xref: /reactos/base/applications/rapps/appdb.cpp (revision 57b775ef)
1a9b1e059SJoachim Henze /*
2a9b1e059SJoachim Henze  * PROJECT:     ReactOS Applications Manager
3a9b1e059SJoachim Henze  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4a9b1e059SJoachim Henze  * PURPOSE:     Classes for working with available applications
5a9b1e059SJoachim Henze  * COPYRIGHT:   Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org)
6a9b1e059SJoachim Henze  *              Copyright 2020 He Yang (1160386205@qq.com)
7a9b1e059SJoachim Henze  *              Copyright 2021-2023 Mark Jansen <mark.jansen@reactos.org>
8a9b1e059SJoachim Henze  */
9a9b1e059SJoachim Henze 
10a9b1e059SJoachim Henze #include "rapps.h"
11a9b1e059SJoachim Henze #include "appdb.h"
12a9b1e059SJoachim Henze #include "configparser.h"
13a9b1e059SJoachim Henze #include "settings.h"
14a9b1e059SJoachim Henze 
15a9b1e059SJoachim Henze 
16a9b1e059SJoachim Henze static HKEY g_RootKeyEnum[3] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE};
17*57b775efSWhindmar Saksit static REGSAM g_RegSamEnum[3] = {0, KEY_WOW64_32KEY, KEY_WOW64_64KEY};
18a9b1e059SJoachim Henze #define UNINSTALL_SUBKEY L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
19a9b1e059SJoachim Henze 
20a9b1e059SJoachim Henze static VOID
ClearList(CAtlList<CAppInfo * > & list)21a9b1e059SJoachim Henze ClearList(CAtlList<CAppInfo *> &list)
22a9b1e059SJoachim Henze {
23a9b1e059SJoachim Henze     POSITION InfoListPosition = list.GetHeadPosition();
24a9b1e059SJoachim Henze     while (InfoListPosition)
25a9b1e059SJoachim Henze     {
26a9b1e059SJoachim Henze         CAppInfo *Info = list.GetNext(InfoListPosition);
27a9b1e059SJoachim Henze         delete Info;
28a9b1e059SJoachim Henze     }
29a9b1e059SJoachim Henze     list.RemoveAll();
30a9b1e059SJoachim Henze }
31a9b1e059SJoachim Henze 
CAppDB(const CStringW & path)32a9b1e059SJoachim Henze CAppDB::CAppDB(const CStringW &path) : m_BasePath(path)
33a9b1e059SJoachim Henze {
34a9b1e059SJoachim Henze     m_BasePath.Canonicalize();
35a9b1e059SJoachim Henze }
36a9b1e059SJoachim Henze 
37*57b775efSWhindmar Saksit CAvailableApplicationInfo *
FindAvailableByPackageName(const CStringW & name)38*57b775efSWhindmar Saksit CAppDB::FindAvailableByPackageName(const CStringW &name)
39a9b1e059SJoachim Henze {
40a9b1e059SJoachim Henze     POSITION CurrentListPosition = m_Available.GetHeadPosition();
41a9b1e059SJoachim Henze     while (CurrentListPosition)
42a9b1e059SJoachim Henze     {
43a9b1e059SJoachim Henze         CAppInfo *Info = m_Available.GetNext(CurrentListPosition);
44a9b1e059SJoachim Henze         if (Info->szIdentifier == name)
45a9b1e059SJoachim Henze         {
46*57b775efSWhindmar Saksit             return static_cast<CAvailableApplicationInfo *>(Info);
47a9b1e059SJoachim Henze         }
48a9b1e059SJoachim Henze     }
49a9b1e059SJoachim Henze     return NULL;
50a9b1e059SJoachim Henze }
51a9b1e059SJoachim Henze 
52a9b1e059SJoachim Henze void
GetApps(CAtlList<CAppInfo * > & List,AppsCategories Type) const53a9b1e059SJoachim Henze CAppDB::GetApps(CAtlList<CAppInfo *> &List, AppsCategories Type) const
54a9b1e059SJoachim Henze {
55a9b1e059SJoachim Henze     const BOOL UseInstalled = IsInstalledEnum(Type);
56a9b1e059SJoachim Henze     const CAtlList<CAppInfo *> &list = UseInstalled ? m_Installed : m_Available;
57a9b1e059SJoachim Henze     const BOOL IncludeAll = UseInstalled ? (Type == ENUM_ALL_INSTALLED) : (Type == ENUM_ALL_AVAILABLE);
58a9b1e059SJoachim Henze 
59a9b1e059SJoachim Henze     POSITION CurrentListPosition = list.GetHeadPosition();
60a9b1e059SJoachim Henze     while (CurrentListPosition)
61a9b1e059SJoachim Henze     {
62a9b1e059SJoachim Henze         CAppInfo *Info = list.GetNext(CurrentListPosition);
63a9b1e059SJoachim Henze 
64a9b1e059SJoachim Henze         if (IncludeAll || Type == Info->iCategory)
65a9b1e059SJoachim Henze         {
66a9b1e059SJoachim Henze             List.AddTail(Info);
67a9b1e059SJoachim Henze         }
68a9b1e059SJoachim Henze     }
69a9b1e059SJoachim Henze }
70a9b1e059SJoachim Henze 
71a9b1e059SJoachim Henze BOOL
EnumerateFiles()72a9b1e059SJoachim Henze CAppDB::EnumerateFiles()
73a9b1e059SJoachim Henze {
74a9b1e059SJoachim Henze     ClearList(m_Available);
75a9b1e059SJoachim Henze 
76a9b1e059SJoachim Henze     CPathW AppsPath = m_BasePath;
77fefc5f48SHermès Bélusca-Maïto     AppsPath += RAPPS_DATABASE_SUBDIR;
78a9b1e059SJoachim Henze     CPathW WildcardPath = AppsPath;
79a9b1e059SJoachim Henze     WildcardPath += L"*.txt";
80a9b1e059SJoachim Henze 
81a9b1e059SJoachim Henze     WIN32_FIND_DATAW FindFileData;
82a9b1e059SJoachim Henze     HANDLE hFind = FindFirstFileW(WildcardPath, &FindFileData);
83a9b1e059SJoachim Henze     if (hFind == INVALID_HANDLE_VALUE)
84a9b1e059SJoachim Henze     {
85a9b1e059SJoachim Henze         return FALSE;
86a9b1e059SJoachim Henze     }
87a9b1e059SJoachim Henze 
88a9b1e059SJoachim Henze     do
89a9b1e059SJoachim Henze     {
90a9b1e059SJoachim Henze         CStringW szPkgName = FindFileData.cFileName;
91a9b1e059SJoachim Henze         PathRemoveExtensionW(szPkgName.GetBuffer(MAX_PATH));
92a9b1e059SJoachim Henze         szPkgName.ReleaseBuffer();
93a9b1e059SJoachim Henze 
94a9b1e059SJoachim Henze         CAppInfo *Info = FindByPackageName(szPkgName);
95a9b1e059SJoachim Henze         ATLASSERT(Info == NULL);
96a9b1e059SJoachim Henze         if (!Info)
97a9b1e059SJoachim Henze         {
98fefc5f48SHermès Bélusca-Maïto             CConfigParser *Parser = new CConfigParser(CPathW(AppsPath) += FindFileData.cFileName);
99a9b1e059SJoachim Henze             int Cat;
100*57b775efSWhindmar Saksit             if (!Parser->GetInt(DB_CATEGORY, Cat))
101a9b1e059SJoachim Henze                 Cat = ENUM_INVALID;
102a9b1e059SJoachim Henze 
103a9b1e059SJoachim Henze             Info = new CAvailableApplicationInfo(Parser, szPkgName, static_cast<AppsCategories>(Cat), AppsPath);
104a9b1e059SJoachim Henze             if (Info->Valid())
105a9b1e059SJoachim Henze             {
106a9b1e059SJoachim Henze                 m_Available.AddTail(Info);
107a9b1e059SJoachim Henze             }
108a9b1e059SJoachim Henze             else
109a9b1e059SJoachim Henze             {
110a9b1e059SJoachim Henze                 delete Info;
111a9b1e059SJoachim Henze             }
112a9b1e059SJoachim Henze         }
113a9b1e059SJoachim Henze 
114a9b1e059SJoachim Henze     } while (FindNextFileW(hFind, &FindFileData));
115a9b1e059SJoachim Henze 
116a9b1e059SJoachim Henze     FindClose(hFind);
117a9b1e059SJoachim Henze     return TRUE;
118a9b1e059SJoachim Henze }
119a9b1e059SJoachim Henze 
120a9b1e059SJoachim Henze VOID
UpdateAvailable()121a9b1e059SJoachim Henze CAppDB::UpdateAvailable()
122a9b1e059SJoachim Henze {
123a9b1e059SJoachim Henze     if (!CreateDirectoryW(m_BasePath, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
124a9b1e059SJoachim Henze         return;
125a9b1e059SJoachim Henze 
126a9b1e059SJoachim Henze     if (EnumerateFiles())
127a9b1e059SJoachim Henze         return;
128a9b1e059SJoachim Henze 
129a9b1e059SJoachim Henze     DownloadApplicationsDB(
130a9b1e059SJoachim Henze         SettingsInfo.bUseSource ? SettingsInfo.szSourceURL : APPLICATION_DATABASE_URL, !SettingsInfo.bUseSource);
131a9b1e059SJoachim Henze 
132a9b1e059SJoachim Henze     CPathW AppsPath = m_BasePath;
133fefc5f48SHermès Bélusca-Maïto     AppsPath += RAPPS_DATABASE_SUBDIR;
134a9b1e059SJoachim Henze     if (!ExtractFilesFromCab(APPLICATION_DATABASE_NAME, m_BasePath, AppsPath))
135a9b1e059SJoachim Henze         return;
136a9b1e059SJoachim Henze 
137a9b1e059SJoachim Henze     CPathW CabFile = m_BasePath;
138a9b1e059SJoachim Henze     CabFile += APPLICATION_DATABASE_NAME;
139a9b1e059SJoachim Henze     DeleteFileW(CabFile);
140a9b1e059SJoachim Henze 
141a9b1e059SJoachim Henze     EnumerateFiles();
142a9b1e059SJoachim Henze }
143a9b1e059SJoachim Henze 
144*57b775efSWhindmar Saksit static inline HKEY
GetRootKeyInfo(UINT Index,REGSAM & RegSam)145*57b775efSWhindmar Saksit GetRootKeyInfo(UINT Index, REGSAM &RegSam)
146*57b775efSWhindmar Saksit {
147*57b775efSWhindmar Saksit     C_ASSERT(_countof(g_RootKeyEnum) == _countof(g_RegSamEnum));
148*57b775efSWhindmar Saksit     if (Index < _countof(g_RootKeyEnum))
149*57b775efSWhindmar Saksit     {
150*57b775efSWhindmar Saksit         RegSam = g_RegSamEnum[Index];
151*57b775efSWhindmar Saksit         return g_RootKeyEnum[Index];
152*57b775efSWhindmar Saksit     }
153*57b775efSWhindmar Saksit     return NULL;
154*57b775efSWhindmar Saksit }
155*57b775efSWhindmar Saksit 
156*57b775efSWhindmar Saksit HKEY
EnumInstalledRootKey(UINT Index,REGSAM & RegSam)157*57b775efSWhindmar Saksit CAppDB::EnumInstalledRootKey(UINT Index, REGSAM &RegSam)
158*57b775efSWhindmar Saksit {
159*57b775efSWhindmar Saksit     // Loop for through all combinations.
160*57b775efSWhindmar Saksit     // Note that HKEY_CURRENT_USER\Software does not have a redirect
161*57b775efSWhindmar Saksit     // https://docs.microsoft.com/en-us/windows/win32/winprog64/shared-registry-keys#redirected-shared-and-reflected-keys-under-wow64
162*57b775efSWhindmar Saksit     if (Index < (IsSystem64Bit() ? 3 : 2))
163*57b775efSWhindmar Saksit         return GetRootKeyInfo(Index, RegSam);
164*57b775efSWhindmar Saksit     else
165*57b775efSWhindmar Saksit         return NULL;
166*57b775efSWhindmar Saksit }
167*57b775efSWhindmar Saksit 
168*57b775efSWhindmar Saksit CInstalledApplicationInfo *
CreateInstalledAppByRegistryKey(LPCWSTR KeyName,HKEY hKeyParent,UINT KeyIndex)169*57b775efSWhindmar Saksit CAppDB::CreateInstalledAppByRegistryKey(LPCWSTR KeyName, HKEY hKeyParent, UINT KeyIndex)
170*57b775efSWhindmar Saksit {
171*57b775efSWhindmar Saksit     CRegKey hSubKey;
172*57b775efSWhindmar Saksit     if (hSubKey.Open(hKeyParent, KeyName, KEY_READ) != ERROR_SUCCESS)
173*57b775efSWhindmar Saksit         return NULL;
174*57b775efSWhindmar Saksit     DWORD value, size;
175*57b775efSWhindmar Saksit 
176*57b775efSWhindmar Saksit     size = sizeof(DWORD);
177*57b775efSWhindmar Saksit     if (!RegQueryValueExW(hSubKey, L"SystemComponent", NULL, NULL, (LPBYTE)&value, &size) && value == 1)
178*57b775efSWhindmar Saksit     {
179*57b775efSWhindmar Saksit         // Ignore system components
180*57b775efSWhindmar Saksit         return NULL;
181*57b775efSWhindmar Saksit     }
182*57b775efSWhindmar Saksit 
183*57b775efSWhindmar Saksit     size = 0;
184*57b775efSWhindmar Saksit     BOOL bIsUpdate = !RegQueryValueExW(hSubKey, L"ParentKeyName", NULL, NULL, NULL, &size);
185*57b775efSWhindmar Saksit 
186*57b775efSWhindmar Saksit     AppsCategories cat = bIsUpdate ? ENUM_UPDATES : ENUM_INSTALLED_APPLICATIONS;
187*57b775efSWhindmar Saksit     CInstalledApplicationInfo *pInfo;
188*57b775efSWhindmar Saksit     pInfo = new CInstalledApplicationInfo(hSubKey.Detach(), KeyName, cat, KeyIndex);
189*57b775efSWhindmar Saksit     if (pInfo && pInfo->Valid())
190*57b775efSWhindmar Saksit     {
191*57b775efSWhindmar Saksit         return pInfo;
192*57b775efSWhindmar Saksit     }
193*57b775efSWhindmar Saksit     delete pInfo;
194*57b775efSWhindmar Saksit     return NULL;
195*57b775efSWhindmar Saksit }
196*57b775efSWhindmar Saksit 
197*57b775efSWhindmar Saksit CInstalledApplicationInfo *
EnumerateRegistry(CAtlList<CAppInfo * > * List,LPCWSTR SearchOnly)198*57b775efSWhindmar Saksit CAppDB::EnumerateRegistry(CAtlList<CAppInfo *> *List, LPCWSTR SearchOnly)
199*57b775efSWhindmar Saksit {
200*57b775efSWhindmar Saksit     ATLASSERT(List || SearchOnly);
201*57b775efSWhindmar Saksit     REGSAM wowsam;
202*57b775efSWhindmar Saksit     HKEY hRootKey;
203*57b775efSWhindmar Saksit     for (UINT rki = 0; (hRootKey = EnumInstalledRootKey(rki, wowsam)); ++rki)
204*57b775efSWhindmar Saksit     {
205*57b775efSWhindmar Saksit         CRegKey hKey;
206*57b775efSWhindmar Saksit         if (hKey.Open(hRootKey, UNINSTALL_SUBKEY, KEY_READ | wowsam) != ERROR_SUCCESS)
207*57b775efSWhindmar Saksit         {
208*57b775efSWhindmar Saksit             continue;
209*57b775efSWhindmar Saksit         }
210*57b775efSWhindmar Saksit         for (DWORD Index = 0;; ++Index)
211*57b775efSWhindmar Saksit         {
212*57b775efSWhindmar Saksit             WCHAR szKeyName[MAX_PATH];
213*57b775efSWhindmar Saksit             DWORD dwSize = _countof(szKeyName);
214*57b775efSWhindmar Saksit             if (hKey.EnumKey(Index, szKeyName, &dwSize) != ERROR_SUCCESS)
215*57b775efSWhindmar Saksit             {
216*57b775efSWhindmar Saksit                 break;
217*57b775efSWhindmar Saksit             }
218*57b775efSWhindmar Saksit             if (List || !StrCmpIW(SearchOnly, szKeyName))
219*57b775efSWhindmar Saksit             {
220*57b775efSWhindmar Saksit                 CInstalledApplicationInfo *Info;
221*57b775efSWhindmar Saksit                 Info = CreateInstalledAppByRegistryKey(szKeyName, hKey, rki);
222*57b775efSWhindmar Saksit                 if (Info)
223*57b775efSWhindmar Saksit                 {
224*57b775efSWhindmar Saksit                     if (List)
225*57b775efSWhindmar Saksit                         List->AddTail(Info);
226*57b775efSWhindmar Saksit                     else
227*57b775efSWhindmar Saksit                         return Info;
228*57b775efSWhindmar Saksit                 }
229*57b775efSWhindmar Saksit             }
230*57b775efSWhindmar Saksit         }
231*57b775efSWhindmar Saksit     }
232*57b775efSWhindmar Saksit     return NULL;
233*57b775efSWhindmar Saksit }
234*57b775efSWhindmar Saksit 
235a9b1e059SJoachim Henze VOID
UpdateInstalled()236a9b1e059SJoachim Henze CAppDB::UpdateInstalled()
237a9b1e059SJoachim Henze {
238a9b1e059SJoachim Henze     // Remove all old entries
239a9b1e059SJoachim Henze     ClearList(m_Installed);
240a9b1e059SJoachim Henze 
241*57b775efSWhindmar Saksit     EnumerateRegistry(&m_Installed, NULL);
242a9b1e059SJoachim Henze }
243a9b1e059SJoachim Henze 
244*57b775efSWhindmar Saksit CInstalledApplicationInfo *
CreateInstalledAppByRegistryKey(LPCWSTR Name)245*57b775efSWhindmar Saksit CAppDB::CreateInstalledAppByRegistryKey(LPCWSTR Name)
246a9b1e059SJoachim Henze {
247*57b775efSWhindmar Saksit     return EnumerateRegistry(NULL, Name);
248*57b775efSWhindmar Saksit }
249a9b1e059SJoachim Henze 
250*57b775efSWhindmar Saksit CInstalledApplicationInfo *
CreateInstalledAppInstance(LPCWSTR KeyName,BOOL User,REGSAM WowSam)251*57b775efSWhindmar Saksit CAppDB::CreateInstalledAppInstance(LPCWSTR KeyName, BOOL User, REGSAM WowSam)
252*57b775efSWhindmar Saksit {
253*57b775efSWhindmar Saksit     HKEY hRootKey = User ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
254*57b775efSWhindmar Saksit     UINT KeyIndex = User ? (0) : ((WowSam & KEY_WOW64_64KEY) ? 2 : 1);
255a9b1e059SJoachim Henze     CRegKey hKey;
256*57b775efSWhindmar Saksit     if (hKey.Open(hRootKey, UNINSTALL_SUBKEY, KEY_READ | WowSam) == ERROR_SUCCESS)
257a9b1e059SJoachim Henze     {
258*57b775efSWhindmar Saksit         return CreateInstalledAppByRegistryKey(KeyName, hKey, KeyIndex);
259a9b1e059SJoachim Henze     }
260*57b775efSWhindmar Saksit     return NULL;
261a9b1e059SJoachim Henze }
262a9b1e059SJoachim Henze 
263a9b1e059SJoachim Henze static void
DeleteWithWildcard(const CPathW & Dir,const CStringW & Filter)264a9b1e059SJoachim Henze DeleteWithWildcard(const CPathW &Dir, const CStringW &Filter)
265a9b1e059SJoachim Henze {
266a9b1e059SJoachim Henze     HANDLE hFind = INVALID_HANDLE_VALUE;
267a9b1e059SJoachim Henze     WIN32_FIND_DATAW FindFileData;
268a9b1e059SJoachim Henze 
269a9b1e059SJoachim Henze     CPathW DirWithFilter = Dir;
270a9b1e059SJoachim Henze     DirWithFilter += Filter;
271a9b1e059SJoachim Henze 
272a9b1e059SJoachim Henze     hFind = FindFirstFileW(DirWithFilter, &FindFileData);
273a9b1e059SJoachim Henze 
274a9b1e059SJoachim Henze     if (hFind == INVALID_HANDLE_VALUE)
275a9b1e059SJoachim Henze         return;
276a9b1e059SJoachim Henze 
277a9b1e059SJoachim Henze     do
278a9b1e059SJoachim Henze     {
279a9b1e059SJoachim Henze         CPathW szTmp = Dir;
280a9b1e059SJoachim Henze         szTmp += FindFileData.cFileName;
281a9b1e059SJoachim Henze 
282a9b1e059SJoachim Henze         if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
283a9b1e059SJoachim Henze         {
284a9b1e059SJoachim Henze             DeleteFileW(szTmp);
285a9b1e059SJoachim Henze         }
286a9b1e059SJoachim Henze     } while (FindNextFileW(hFind, &FindFileData) != 0);
287a9b1e059SJoachim Henze     FindClose(hFind);
288a9b1e059SJoachim Henze }
289a9b1e059SJoachim Henze 
290a9b1e059SJoachim Henze VOID
RemoveCached()291a9b1e059SJoachim Henze CAppDB::RemoveCached()
292a9b1e059SJoachim Henze {
293a9b1e059SJoachim Henze     // Delete icons
294a9b1e059SJoachim Henze     CPathW AppsPath = m_BasePath;
295fefc5f48SHermès Bélusca-Maïto     AppsPath += RAPPS_DATABASE_SUBDIR;
296a9b1e059SJoachim Henze     CPathW IconPath = AppsPath;
297a9b1e059SJoachim Henze     IconPath += L"icons";
298a9b1e059SJoachim Henze     DeleteWithWildcard(IconPath, L"*.ico");
299a9b1e059SJoachim Henze 
300a9b1e059SJoachim Henze     // Delete leftover screenshots
301a9b1e059SJoachim Henze     CPathW ScrnshotFolder = AppsPath;
302a9b1e059SJoachim Henze     ScrnshotFolder += L"screenshots";
303a9b1e059SJoachim Henze     DeleteWithWildcard(ScrnshotFolder, L"*.tmp");
304a9b1e059SJoachim Henze 
305a9b1e059SJoachim Henze     // Delete data base files (*.txt)
306a9b1e059SJoachim Henze     DeleteWithWildcard(AppsPath, L"*.txt");
307a9b1e059SJoachim Henze 
308a9b1e059SJoachim Henze     RemoveDirectoryW(IconPath);
309a9b1e059SJoachim Henze     RemoveDirectoryW(ScrnshotFolder);
310a9b1e059SJoachim Henze     RemoveDirectoryW(AppsPath);
311a9b1e059SJoachim Henze     RemoveDirectoryW(m_BasePath);
312a9b1e059SJoachim Henze }
313a9b1e059SJoachim Henze 
314*57b775efSWhindmar Saksit DWORD
RemoveInstalledAppFromRegistry(const CAppInfo * Info)315a9b1e059SJoachim Henze CAppDB::RemoveInstalledAppFromRegistry(const CAppInfo *Info)
316a9b1e059SJoachim Henze {
317a9b1e059SJoachim Henze     // Validate that this is actually an installed app / update
318a9b1e059SJoachim Henze     ATLASSERT(Info->iCategory == ENUM_INSTALLED_APPLICATIONS || Info->iCategory == ENUM_UPDATES);
319a9b1e059SJoachim Henze     if (Info->iCategory != ENUM_INSTALLED_APPLICATIONS && Info->iCategory != ENUM_UPDATES)
320*57b775efSWhindmar Saksit         return ERROR_INVALID_PARAMETER;
321a9b1e059SJoachim Henze 
322a9b1e059SJoachim Henze     const CInstalledApplicationInfo *InstalledInfo = static_cast<const CInstalledApplicationInfo *>(Info);
323a9b1e059SJoachim Henze 
324a9b1e059SJoachim Henze     CStringW Name = InstalledInfo->szIdentifier;
325*57b775efSWhindmar Saksit     REGSAM wowsam;
326*57b775efSWhindmar Saksit     HKEY hRoot = GetRootKeyInfo(InstalledInfo->m_KeyInfo, wowsam);
327*57b775efSWhindmar Saksit     ATLASSERT(hRoot);
328*57b775efSWhindmar Saksit     if (!hRoot)
329*57b775efSWhindmar Saksit         return ERROR_OPEN_FAILED;
330a9b1e059SJoachim Henze 
331a9b1e059SJoachim Henze     CRegKey Uninstall;
332*57b775efSWhindmar Saksit     LSTATUS err = Uninstall.Open(hRoot, UNINSTALL_SUBKEY, KEY_READ | KEY_WRITE | wowsam);
333*57b775efSWhindmar Saksit     if (err == ERROR_SUCCESS)
334*57b775efSWhindmar Saksit     {
335*57b775efSWhindmar Saksit         err = Uninstall.RecurseDeleteKey(Name);
336*57b775efSWhindmar Saksit     }
337*57b775efSWhindmar Saksit     return err;
338a9b1e059SJoachim Henze }
339