[RAPPS] listview refactor (#2970)

This makes it easier to maintain the listview, and better separates the application list and listview.

* [RAPPS] fix memory leak when cleanup. some renaming are also done
* [RAPPS] move the code adding apps info inside class CAppsListView
* [RAPPS] add table view, create listview and AppInfoDisplay inside it
* [RAPPS] rename INSTALLED_INFO as CInstalledApplicationInfo
now it corresponds with CAvailableApplicationInfo
* [RAPPS] add CInstalledApps
* [RAPPS] optimize the speed when refreshing listview
* [RAPPS] correctly handle Enum for InstalledApps
* [RAPPS] make check all working properly (this also fixes some bugs)
the old version has some bugs when check all items after switching tags in tree-view
* [RAPPS] add handling for wow64
* [RAPPS] use an inline function to replace INSERT_TEXT macro
* [RAPPS] fix the bug that StatusBar won't update when switching tags
* [RAPPS] now TableView always reset bIsAscending in SetDisplayMode
* [RAPPS] rename TableView to ApplicationView
* [RAPPS] now bIsAscending would be reset when switching column in listview
This commit is contained in:
He Yang 2020-07-21 22:13:39 +08:00 committed by Mark Jansen
parent 4482d0f455
commit 10c0ff7416
No known key found for this signature in database
GPG key ID: B39240EE84BEAE8B
8 changed files with 1147 additions and 653 deletions

View file

@ -19,7 +19,7 @@
// CAvailableApplicationInfo // CAvailableApplicationInfo
CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam, AvailableStrings& AvlbStrings) CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam, AvailableStrings& AvlbStrings)
: m_IsSelected(FALSE), m_LicenseType(LICENSE_NONE), m_SizeBytes(0), m_sFileName(sFileNameParam), : m_LicenseType(LICENSE_NONE), m_SizeBytes(0), m_sFileName(sFileNameParam),
m_IsInstalled(FALSE), m_HasLanguageInfo(FALSE), m_HasInstalledVersion(FALSE) m_IsInstalled(FALSE), m_HasLanguageInfo(FALSE), m_HasInstalledVersion(FALSE)
{ {
RetrieveGeneralInfo(AvlbStrings); RetrieveGeneralInfo(AvlbStrings);
@ -400,71 +400,127 @@ BOOL CAvailableApps::ForceUpdateAppsDB()
BOOL CAvailableApps::Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param) BOOL CAvailableApps::Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param)
{ {
if (EnumType == ENUM_CAT_SELECTED)
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAW FindFileData;
hFind = FindFirstFileW(m_Strings.szSearchPath.GetString(), &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{ {
//no db yet CAvailableApplicationInfo *EnumAvlbInfo = NULL;
return FALSE;
}
do // enum all object in m_SelectedList and invoke callback
{ for(POSITION CurrentPosition = m_SelectedList.GetHeadPosition();
// loop for all the cached entries CurrentPosition && (EnumAvlbInfo = m_SelectedList.GetAt(CurrentPosition));
POSITION CurrentListPosition = m_InfoList.GetHeadPosition(); m_SelectedList.GetNext(CurrentPosition))
CAvailableApplicationInfo* Info = NULL;
while (CurrentListPosition != NULL)
{ {
POSITION LastListPosition = CurrentListPosition; EnumAvlbInfo->RefreshAppInfo(m_Strings);
Info = m_InfoList.GetNext(CurrentListPosition);
// do we already have this entry in cache?
if (Info->m_sFileName == FindFileData.cFileName)
{
// is it current enough, or the file has been modified since our last time here?
if (CompareFileTime(&FindFileData.ftLastWriteTime, &Info->m_ftCacheStamp) == 1)
{
// recreate our cache, this is the slow path
m_InfoList.RemoveAt(LastListPosition);
delete Info;
Info = NULL;
break;
}
else
{
// speedy path, compare directly, we already have the data
goto skip_if_cached;
}
}
}
// create a new entry
Info = new CAvailableApplicationInfo(FindFileData.cFileName, m_Strings);
// set a timestamp for the next time
Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
m_InfoList.AddTail(Info);
skip_if_cached:
if (EnumType == Info->m_Category
|| EnumType == ENUM_ALL_AVAILABLE
|| (EnumType == ENUM_CAT_SELECTED && Info->m_IsSelected))
{
Info->RefreshAppInfo(m_Strings);
if (lpEnumProc) if (lpEnumProc)
lpEnumProc(Info, m_Strings.szAppsPath.GetString(), param); lpEnumProc(EnumAvlbInfo, TRUE, param);
} }
} while (FindNextFileW(hFind, &FindFileData) != 0); return TRUE;
}
else
{
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAW FindFileData;
FindClose(hFind); hFind = FindFirstFileW(m_Strings.szSearchPath.GetString(), &FindFileData);
return TRUE;
if (hFind == INVALID_HANDLE_VALUE)
{
//no db yet
return FALSE;
}
do
{
// loop for all the cached entries
POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
CAvailableApplicationInfo *Info = NULL;
while (CurrentListPosition != NULL)
{
POSITION LastListPosition = CurrentListPosition;
Info = m_InfoList.GetNext(CurrentListPosition);
// do we already have this entry in cache?
if (Info->m_sFileName == FindFileData.cFileName)
{
// is it current enough, or the file has been modified since our last time here?
if (CompareFileTime(&FindFileData.ftLastWriteTime, &Info->m_ftCacheStamp) == 1)
{
// recreate our cache, this is the slow path
m_InfoList.RemoveAt(LastListPosition);
// also remove this in selected list (if exist)
RemoveSelected(Info);
delete Info;
Info = NULL;
break;
}
else
{
// speedy path, compare directly, we already have the data
goto skip_if_cached;
}
}
}
// create a new entry
Info = new CAvailableApplicationInfo(FindFileData.cFileName, m_Strings);
// set a timestamp for the next time
Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
m_InfoList.AddTail(Info);
skip_if_cached:
if (EnumType == Info->m_Category
|| EnumType == ENUM_ALL_AVAILABLE)
{
Info->RefreshAppInfo(m_Strings);
if (lpEnumProc)
{
if (m_SelectedList.Find(Info))
{
lpEnumProc(Info, TRUE, param);
}
else
{
lpEnumProc(Info, FALSE, param);
}
}
}
} while (FindNextFileW(hFind, &FindFileData));
FindClose(hFind);
return TRUE;
}
}
BOOL CAvailableApps::AddSelected(CAvailableApplicationInfo *AvlbInfo)
{
return m_SelectedList.AddTail(AvlbInfo) != 0;
}
BOOL CAvailableApps::RemoveSelected(CAvailableApplicationInfo *AvlbInfo)
{
POSITION Position = m_SelectedList.Find(AvlbInfo);
if (Position)
{
m_SelectedList.RemoveAt(Position);
return TRUE;
}
return FALSE;
}
VOID CAvailableApps::RemoveAllSelected()
{
m_SelectedList.RemoveAll();
return;
}
int CAvailableApps::GetSelectedCount()
{
return m_SelectedList.GetCount();
} }
CAvailableApplicationInfo* CAvailableApps::FindInfo(const ATL::CStringW& szAppName) const CAvailableApplicationInfo* CAvailableApps::FindInfo(const ATL::CStringW& szAppName) const
@ -502,23 +558,6 @@ ATL::CSimpleArray<CAvailableApplicationInfo> CAvailableApps::FindInfoList(const
return result; return result;
} }
ATL::CSimpleArray<CAvailableApplicationInfo> CAvailableApps::GetSelected() const
{
ATL::CSimpleArray<CAvailableApplicationInfo> result;
POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
CAvailableApplicationInfo* Info;
while (CurrentListPosition != NULL)
{
Info = m_InfoList.GetNext(CurrentListPosition);
if (Info->m_IsSelected)
{
result.Add(*Info);
}
}
return result;
}
const ATL::CStringW& CAvailableApps::GetFolderPath() const const ATL::CStringW& CAvailableApps::GetFolderPath() const
{ {
return m_Strings.szPath; return m_Strings.szPath;

File diff suppressed because it is too large Load diff

View file

@ -37,10 +37,11 @@ struct AvailableStrings
AvailableStrings(); AvailableStrings();
}; };
struct CAvailableApplicationInfo class CAvailableApplicationInfo
{ {
public:
INT m_Category; INT m_Category;
BOOL m_IsSelected; //BOOL m_IsSelected;
LicenseType m_LicenseType; LicenseType m_LicenseType;
ATL::CStringW m_szName; ATL::CStringW m_szName;
ATL::CStringW m_szRegName; ATL::CStringW m_szRegName;
@ -98,11 +99,12 @@ private:
inline BOOL FindInLanguages(LCID what) const; inline BOOL FindInLanguages(LCID what) const;
}; };
typedef BOOL(CALLBACK *AVAILENUMPROC)(CAvailableApplicationInfo *Info, LPCWSTR szFolderPath, PVOID param); typedef BOOL(CALLBACK *AVAILENUMPROC)(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param);
class CAvailableApps class CAvailableApps
{ {
ATL::CAtlList<CAvailableApplicationInfo*> m_InfoList; ATL::CAtlList<CAvailableApplicationInfo*> m_InfoList;
ATL::CAtlList< CAvailableApplicationInfo*> m_SelectedList;
public: public:
static AvailableStrings m_Strings; static AvailableStrings m_Strings;
@ -116,9 +118,15 @@ public:
VOID FreeCachedEntries(); VOID FreeCachedEntries();
BOOL Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param); BOOL Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param);
BOOL AddSelected(CAvailableApplicationInfo *AvlbInfo);
BOOL RemoveSelected(CAvailableApplicationInfo *AvlbInfo);
VOID RemoveAllSelected();
int GetSelectedCount();
CAvailableApplicationInfo* FindInfo(const ATL::CStringW& szAppName) const; CAvailableApplicationInfo* FindInfo(const ATL::CStringW& szAppName) const;
ATL::CSimpleArray<CAvailableApplicationInfo> FindInfoList(const ATL::CSimpleArray<ATL::CStringW> &arrAppsNames) const; ATL::CSimpleArray<CAvailableApplicationInfo> FindInfoList(const ATL::CSimpleArray<ATL::CStringW> &arrAppsNames) const;
ATL::CSimpleArray<CAvailableApplicationInfo> GetSelected() const; //ATL::CSimpleArray<CAvailableApplicationInfo> GetSelected() const;
const ATL::CStringW& GetFolderPath() const; const ATL::CStringW& GetFolderPath() const;
const ATL::CStringW& GetAppPath() const; const ATL::CStringW& GetAppPath() const;

View file

@ -3,19 +3,51 @@
#include <windef.h> #include <windef.h>
#include <atlstr.h> #include <atlstr.h>
struct INSTALLED_INFO class CInstalledApplicationInfo
{ {
HKEY hRootKey; public:
BOOL IsUserKey;
REGSAM WowKey;
HKEY hSubKey; HKEY hSubKey;
BOOL bIsUpdate = FALSE;
ATL::CStringW szKeyName; ATL::CStringW szKeyName;
CInstalledApplicationInfo(BOOL bIsUserKey, REGSAM RegWowKey, HKEY hKey);
BOOL GetApplicationString(LPCWSTR lpKeyName, ATL::CStringW& String); BOOL GetApplicationString(LPCWSTR lpKeyName, ATL::CStringW& String);
BOOL UninstallApplication(BOOL bModify);
LSTATUS RemoveFromRegistry();
ATL::CStringW szDisplayName;
ATL::CStringW szDisplayVersion;
ATL::CStringW szPublisher;
ATL::CStringW szRegOwner;
ATL::CStringW szProductID;
ATL::CStringW szHelpLink;
ATL::CStringW szHelpTelephone;
ATL::CStringW szReadme;
ATL::CStringW szContact;
ATL::CStringW szURLUpdateInfo;
ATL::CStringW szURLInfoAbout;
ATL::CStringW szComments;
ATL::CStringW szInstallDate;
ATL::CStringW szInstallLocation;
ATL::CStringW szInstallSource;
ATL::CStringW szUninstallString;
ATL::CStringW szModifyPath;
~CInstalledApplicationInfo();
}; };
typedef INSTALLED_INFO *PINSTALLED_INFO; typedef BOOL(CALLBACK *APPENUMPROC)(CInstalledApplicationInfo * Info, PVOID param);
typedef BOOL(CALLBACK *APPENUMPROC)(INT ItemIndex, ATL::CStringW &Name, PINSTALLED_INFO Info, PVOID param);
BOOL EnumInstalledApplications(INT EnumType, BOOL IsUserKey, APPENUMPROC lpEnumProc, PVOID param); class CInstalledApps
BOOL GetApplicationString(HKEY hKey, LPCWSTR lpKeyName, LPWSTR szString); {
ATL::CAtlList<CInstalledApplicationInfo *> m_InfoList;
public:
BOOL Enum(INT EnumType, APPENUMPROC lpEnumProc, PVOID param);
VOID FreeCachedEntries();
};
BOOL UninstallApplication(PINSTALLED_INFO ItemInfo, BOOL bModify);

View file

@ -46,3 +46,5 @@ public:
}; };
BOOL PathAppendNoDirEscapeW(LPWSTR pszPath, LPCWSTR pszMore); BOOL PathAppendNoDirEscapeW(LPWSTR pszPath, LPCWSTR pszMore);
BOOL IsSystem64Bit();

View file

@ -495,7 +495,10 @@ public:
virtual ~CUiWindow() virtual ~CUiWindow()
{ {
T::DestroyWindow(); if (T::IsWindow())
{
T::DestroyWindow();
}
} }
VOID GetWindowTextW(ATL::CStringW& szText) VOID GetWindowTextW(ATL::CStringW& szText)

View file

@ -12,149 +12,253 @@
#include "misc.h" #include "misc.h"
BOOL INSTALLED_INFO::GetApplicationString(LPCWSTR lpKeyName, ATL::CStringW& String) CInstalledApplicationInfo::CInstalledApplicationInfo(BOOL bIsUserKey, REGSAM RegWowKey, HKEY hKey)
: IsUserKey(bIsUserKey), WowKey(RegWowKey), hSubKey(hKey)
{ {
BOOL result = ::GetApplicationString(hSubKey, lpKeyName, String.GetBuffer(MAX_PATH)); // if Initialize failed, hSubKey will be closed automatically and set to zero
String.ReleaseBuffer();
return result;
}
BOOL GetApplicationString(HKEY hKey, LPCWSTR lpKeyName, LPWSTR szString) DWORD dwSize = MAX_PATH, dwType, dwValue;
{ BOOL bIsSystemComponent;
DWORD dwSize = MAX_PATH * sizeof(WCHAR); ATL::CStringW szParentKeyName;
if (RegQueryValueExW(hKey, dwType = REG_DWORD;
lpKeyName, dwSize = sizeof(DWORD);
NULL,
NULL, if (RegQueryValueExW(hSubKey,
(LPBYTE) szString, L"SystemComponent",
&dwSize) == ERROR_SUCCESS) NULL,
&dwType,
(LPBYTE)&dwValue,
&dwSize) == ERROR_SUCCESS)
{ {
return TRUE; bIsSystemComponent = (dwValue == 0x1);
}
else
{
bIsSystemComponent = FALSE;
} }
StringCchCopyW(szString, MAX_PATH, L"---");
return FALSE;
}
BOOL UninstallApplication(PINSTALLED_INFO ItemInfo, BOOL bModify)
{
LPCWSTR szModify = L"ModifyPath";
LPCWSTR szUninstall = L"UninstallString";
DWORD dwType, dwSize;
WCHAR szPath[MAX_PATH];
dwType = REG_SZ; dwType = REG_SZ;
dwSize = MAX_PATH * sizeof(WCHAR); dwSize = MAX_PATH * sizeof(WCHAR);
if (RegQueryValueExW(ItemInfo->hSubKey, bIsUpdate = (RegQueryValueExW(hSubKey,
bModify ? szModify : szUninstall, L"ParentKeyName",
NULL, NULL,
&dwType, &dwType,
(LPBYTE) szPath, (LPBYTE)szParentKeyName.GetBuffer(MAX_PATH),
&dwSize) != ERROR_SUCCESS) &dwSize) == ERROR_SUCCESS);
szParentKeyName.ReleaseBuffer();
if (bIsSystemComponent)
{ {
return FALSE; CloseHandle(hSubKey);
hSubKey = NULL;
} }
return StartProcess(szPath, TRUE);
} }
BOOL EnumInstalledApplications(INT EnumType, BOOL IsUserKey, APPENUMPROC lpEnumProc, PVOID param) CInstalledApplicationInfo::~CInstalledApplicationInfo()
{ {
DWORD dwSize = MAX_PATH, dwType, dwValue; if (hSubKey)
BOOL bIsSystemComponent, bIsUpdate; {
ATL::CStringW szParentKeyName; CloseHandle(hSubKey);
ATL::CStringW szDisplayName; hSubKey = NULL;
INSTALLED_INFO Info; }
HKEY hKey; }
LONG ItemIndex = 0;
Info.hRootKey = IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; BOOL CInstalledApplicationInfo::GetApplicationString(LPCWSTR lpKeyName, ATL::CStringW& String)
{
DWORD dwSize = 0;
String.Empty();
DWORD dwType;
if (RegOpenKeyW(Info.hRootKey, // retrieve the size of value first.
L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall", if (RegQueryValueExW(hSubKey,
&hKey) != ERROR_SUCCESS) lpKeyName,
NULL,
&dwType,
NULL,
&dwSize) != ERROR_SUCCESS)
{ {
return FALSE; return FALSE;
} }
while (RegEnumKeyExW(hKey, ItemIndex, Info.szKeyName.GetBuffer(MAX_PATH), &dwSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) // TODO: I assume the type as REG_SZ. but I think REG_EXPAND_SZ should be handled correctly too.
if (dwType != REG_SZ)
{ {
Info.szKeyName.ReleaseBuffer(); return FALSE;
if (RegOpenKeyW(hKey, Info.szKeyName.GetString(), &Info.hSubKey) == ERROR_SUCCESS) }
// allocate buffer.
// attention: dwSize is size in bytes, and RegQueryValueExW does not guarantee the terminating null character.
String.GetBuffer(dwSize + sizeof(WCHAR));
// query the value
if (RegQueryValueExW(hSubKey,
lpKeyName,
NULL,
NULL,
(LPBYTE)String.GetBuffer(),
&dwSize) != ERROR_SUCCESS)
{
String.ReleaseBuffer();
String.Empty();
return FALSE;
}
String.GetBuffer()[dwSize / sizeof(WCHAR)] = L'\0'; // ensure zero terminated
String.ReleaseBuffer();
return TRUE;
}
BOOL CInstalledApplicationInfo::UninstallApplication(BOOL bModify)
{
return StartProcess(bModify ? szModifyPath : szUninstallString, TRUE);
}
LSTATUS CInstalledApplicationInfo::RemoveFromRegistry()
{
ATL::CStringW szFullName = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + szKeyName;
// TODO: if there are subkeys inside, simply RegDeleteKeyExW will fail
// we don't have RegDeleteTree for ReactOS now. (It's a WinVista API)
// write a function to delete all subkeys recursively to solve this
// or consider letting ReactOS having this API
return RegDeleteKeyExW(IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, szFullName, WowKey, 0);
}
BOOL CInstalledApps::Enum(INT EnumType, APPENUMPROC lpEnumProc, PVOID param)
{
FreeCachedEntries();
HKEY RootKeyEnum[3] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE };
REGSAM RegSamEnum[3] = { KEY_WOW64_32KEY, KEY_WOW64_32KEY, KEY_WOW64_64KEY };
int LoopTime;
// test if the OS is 64 bit.
if (IsSystem64Bit())
{
// loop for all 3 combination.
// note that HKEY_CURRENT_USER\Software don't have a redirect
// https://docs.microsoft.com/en-us/windows/win32/winprog64/shared-registry-keys#redirected-shared-and-reflected-keys-under-wow64
LoopTime = 3;
}
else
{
// loop for 2 combination for KEY_WOW64_32KEY only
LoopTime = 2;
}
// loop for all combination
for (int i = 0; i < LoopTime; i++)
{
DWORD dwSize = MAX_PATH;
HKEY hKey, hSubKey;
LONG ItemIndex = 0;
ATL::CStringW szKeyName;
if (RegOpenKeyExW(RootKeyEnum[i],
L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
NULL,
KEY_READ | RegSamEnum[i],
&hKey) != ERROR_SUCCESS)
{ {
dwType = REG_DWORD; return FALSE;
dwSize = sizeof(DWORD); }
if (RegQueryValueExW(Info.hSubKey, while (1)
L"SystemComponent", {
NULL, dwSize = MAX_PATH;
&dwType, if (RegEnumKeyExW(hKey, ItemIndex, szKeyName.GetBuffer(MAX_PATH), &dwSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
(LPBYTE) &dwValue,
&dwSize) == ERROR_SUCCESS)
{ {
bIsSystemComponent = (dwValue == 0x1); break;
}
else
{
bIsSystemComponent = FALSE;
} }
dwType = REG_SZ; ItemIndex++;
dwSize = MAX_PATH * sizeof(WCHAR);
bIsUpdate = (RegQueryValueExW(Info.hSubKey,
L"ParentKeyName",
NULL,
&dwType,
(LPBYTE) szParentKeyName.GetBuffer(MAX_PATH),
&dwSize) == ERROR_SUCCESS);
szParentKeyName.ReleaseBuffer();
dwType = REG_SZ; szKeyName.ReleaseBuffer();
dwSize = MAX_PATH * sizeof(WCHAR); if (RegOpenKeyW(hKey, szKeyName.GetString(), &hSubKey) == ERROR_SUCCESS)
if (RegQueryValueExW(Info.hSubKey,
L"DisplayName",
NULL,
&dwType,
(LPBYTE) szDisplayName.GetBuffer(MAX_PATH),
&dwSize) == ERROR_SUCCESS)
{ {
szDisplayName.ReleaseBuffer(); BOOL bSuccess = FALSE;
if (EnumType < ENUM_ALL_INSTALLED || EnumType > ENUM_UPDATES) CInstalledApplicationInfo *Info = new CInstalledApplicationInfo(RootKeyEnum[i] == HKEY_CURRENT_USER, RegSamEnum[i], hSubKey);
EnumType = ENUM_ALL_INSTALLED; Info->szKeyName = szKeyName;
if (!bIsSystemComponent) // check for failure. if failed to init, Info->hSubKey will be set to NULL
if (Info->hSubKey)
{ {
if ((EnumType == ENUM_ALL_INSTALLED) || /* All components */ // those items without display name are ignored
((EnumType == ENUM_INSTALLED_APPLICATIONS) && (!bIsUpdate)) || /* Applications only */ if (Info->GetApplicationString(L"DisplayName", Info->szDisplayName))
((EnumType == ENUM_UPDATES) && (bIsUpdate))) /* Updates only */
{ {
if (!lpEnumProc(ItemIndex, szDisplayName, &Info, param)) Info->GetApplicationString(L"DisplayVersion", Info->szDisplayVersion);
break; Info->GetApplicationString(L"Publisher", Info->szPublisher);
Info->GetApplicationString(L"RegOwner", Info->szRegOwner);
Info->GetApplicationString(L"ProductID", Info->szProductID);
Info->GetApplicationString(L"HelpLink", Info->szHelpLink);
Info->GetApplicationString(L"HelpTelephone", Info->szHelpTelephone);
Info->GetApplicationString(L"Readme", Info->szReadme);
Info->GetApplicationString(L"Contact", Info->szContact);
Info->GetApplicationString(L"URLUpdateInfo", Info->szURLUpdateInfo);
Info->GetApplicationString(L"URLInfoAbout", Info->szURLInfoAbout);
Info->GetApplicationString(L"Comments", Info->szComments);
Info->GetApplicationString(L"InstallDate", Info->szInstallDate);
Info->GetApplicationString(L"InstallLocation", Info->szInstallLocation);
Info->GetApplicationString(L"InstallSource", Info->szInstallSource);
Info->GetApplicationString(L"UninstallString", Info->szUninstallString);
Info->GetApplicationString(L"ModifyPath", Info->szModifyPath);
bSuccess = TRUE;
} }
else }
// close handle
if (Info->hSubKey)
{
CloseHandle(Info->hSubKey);
Info->hSubKey = NULL;
}
if (bSuccess)
{
// add to InfoList.
m_InfoList.AddTail(Info);
// invoke callback
if (lpEnumProc)
{ {
RegCloseKey(Info.hSubKey); if ((EnumType == ENUM_ALL_INSTALLED) || /* All components */
((EnumType == ENUM_INSTALLED_APPLICATIONS) && (!Info->bIsUpdate)) || /* Applications only */
((EnumType == ENUM_UPDATES) && (Info->bIsUpdate))) /* Updates only */
{
lpEnumProc(Info, param);
}
} }
} }
else else
{ {
RegCloseKey(Info.hSubKey); // destory object
delete Info;
} }
} }
else
{
szDisplayName.ReleaseBuffer();
RegCloseKey(Info.hSubKey);
}
} }
dwSize = MAX_PATH; szKeyName.ReleaseBuffer();
ItemIndex++; RegCloseKey(hKey);
} }
Info.szKeyName.ReleaseBuffer();
RegCloseKey(hKey);
return TRUE; return TRUE;
} }
VOID CInstalledApps::FreeCachedEntries()
{
POSITION InfoListPosition = m_InfoList.GetHeadPosition();
/* loop and deallocate all the cached app infos in the list */
while (InfoListPosition)
{
CInstalledApplicationInfo *Info = m_InfoList.GetNext(InfoListPosition);
delete Info;
}
m_InfoList.RemoveAll();
}

View file

@ -13,6 +13,9 @@
static HANDLE hLog = NULL; static HANDLE hLog = NULL;
static BOOL bIsSys64ResultCached = FALSE;
static BOOL bIsSys64Result = FALSE;
INT GetWindowWidth(HWND hwnd) INT GetWindowWidth(HWND hwnd)
{ {
RECT Rect; RECT Rect;
@ -453,3 +456,33 @@ BOOL PathAppendNoDirEscapeW(LPWSTR pszPath, LPCWSTR pszMore)
return TRUE; return TRUE;
} }
BOOL IsSystem64Bit()
{
if (bIsSys64ResultCached)
{
// just return cached result
return bIsSys64Result;
}
SYSTEM_INFO si;
typedef void (WINAPI *LPFN_PGNSI)(LPSYSTEM_INFO);
LPFN_PGNSI pGetNativeSystemInfo = (LPFN_PGNSI)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetNativeSystemInfo");
if (pGetNativeSystemInfo)
{
pGetNativeSystemInfo(&si);
if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
{
bIsSys64Result = TRUE;
}
}
else
{
bIsSys64Result = FALSE;
}
bIsSys64ResultCached = TRUE; // next time calling this function, it will directly return bIsSys64Result
return bIsSys64Result;
}