xref: /reactos/dll/win32/msi/registry.c (revision f4be6dc3)
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2005 Mike McCormack for CodeWeavers
5  * Copyright 2005 Aric Stewart for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include <stdarg.h>
23 
24 #define COBJMACROS
25 
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "shlwapi.h"
31 #include "wine/debug.h"
32 #include "msi.h"
33 #include "msipriv.h"
34 #include "wincrypt.h"
35 #include "winver.h"
36 #include "winuser.h"
37 #include "sddl.h"
38 
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
40 
unsquash_guid(LPCWSTR in,LPWSTR out)41 BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
42 {
43     DWORD i,n=0;
44 
45     if (lstrlenW(in) != 32)
46         return FALSE;
47 
48     out[n++]='{';
49     for(i=0; i<8; i++)
50         out[n++] = in[7-i];
51     out[n++]='-';
52     for(i=0; i<4; i++)
53         out[n++] = in[11-i];
54     out[n++]='-';
55     for(i=0; i<4; i++)
56         out[n++] = in[15-i];
57     out[n++]='-';
58     for(i=0; i<2; i++)
59     {
60         out[n++] = in[17+i*2];
61         out[n++] = in[16+i*2];
62     }
63     out[n++]='-';
64     for( ; i<8; i++)
65     {
66         out[n++] = in[17+i*2];
67         out[n++] = in[16+i*2];
68     }
69     out[n++]='}';
70     out[n]=0;
71     return TRUE;
72 }
73 
squash_guid(LPCWSTR in,LPWSTR out)74 BOOL squash_guid(LPCWSTR in, LPWSTR out)
75 {
76     DWORD i,n=1;
77     GUID guid;
78 
79     out[0] = 0;
80 
81     if (FAILED(CLSIDFromString((LPCOLESTR)in, &guid)))
82         return FALSE;
83 
84     for(i=0; i<8; i++)
85         out[7-i] = in[n++];
86     n++;
87     for(i=0; i<4; i++)
88         out[11-i] = in[n++];
89     n++;
90     for(i=0; i<4; i++)
91         out[15-i] = in[n++];
92     n++;
93     for(i=0; i<2; i++)
94     {
95         out[17+i*2] = in[n++];
96         out[16+i*2] = in[n++];
97     }
98     n++;
99     for( ; i<8; i++)
100     {
101         out[17+i*2] = in[n++];
102         out[16+i*2] = in[n++];
103     }
104     out[32]=0;
105     return TRUE;
106 }
107 
108 
109 /* tables for encoding and decoding base85 */
110 static const unsigned char table_dec85[0x80] = {
111 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
112 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
113 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
114 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
115 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
116 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
117 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
118 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
119 };
120 
121 static const char table_enc85[] =
122 "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
123 "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
124 "yz{}~";
125 
126 /*
127  *  Converts a base85 encoded guid into a GUID pointer
128  *  Base85 encoded GUIDs should be 20 characters long.
129  *
130  *  returns TRUE if successful, FALSE if not
131  */
decode_base85_guid(LPCWSTR str,GUID * guid)132 BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
133 {
134     DWORD i, val = 0, base = 1, *p;
135 
136     if (!str)
137         return FALSE;
138 
139     p = (DWORD*) guid;
140     for( i=0; i<20; i++ )
141     {
142         if( (i%5) == 0 )
143         {
144             val = 0;
145             base = 1;
146         }
147         val += table_dec85[str[i]] * base;
148         if( str[i] >= 0x80 )
149             return FALSE;
150         if( table_dec85[str[i]] == 0xff )
151             return FALSE;
152         if( (i%5) == 4 )
153             p[i/5] = val;
154         base *= 85;
155     }
156     return TRUE;
157 }
158 
159 /*
160  *  Encodes a base85 guid given a GUID pointer
161  *  Caller should provide a 21 character buffer for the encoded string.
162  *
163  *  returns TRUE if successful, FALSE if not
164  */
encode_base85_guid(GUID * guid,LPWSTR str)165 BOOL encode_base85_guid( GUID *guid, LPWSTR str )
166 {
167     unsigned int x, *p, i;
168 
169     p = (unsigned int*) guid;
170     for( i=0; i<4; i++ )
171     {
172         x = p[i];
173         *str++ = table_enc85[x%85];
174         x = x/85;
175         *str++ = table_enc85[x%85];
176         x = x/85;
177         *str++ = table_enc85[x%85];
178         x = x/85;
179         *str++ = table_enc85[x%85];
180         x = x/85;
181         *str++ = table_enc85[x%85];
182     }
183     *str = 0;
184 
185     return TRUE;
186 }
187 
msi_version_str_to_dword(LPCWSTR p)188 DWORD msi_version_str_to_dword(LPCWSTR p)
189 {
190     DWORD major, minor = 0, build = 0, version = 0;
191 
192     if (!p)
193         return version;
194 
195     major = wcstol(p, NULL, 10);
196 
197     p = wcschr(p, '.');
198     if (p)
199     {
200         minor = wcstol(p+1, NULL, 10);
201         p = wcschr(p+1, '.');
202         if (p)
203             build = wcstol(p+1, NULL, 10);
204     }
205 
206     return MAKELONG(build, MAKEWORD(minor, major));
207 }
208 
msi_reg_set_val_str(HKEY hkey,LPCWSTR name,LPCWSTR value)209 LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
210 {
211     DWORD len;
212     if (!value) value = L"";
213     len = (lstrlenW(value) + 1) * sizeof (WCHAR);
214     return RegSetValueExW( hkey, name, 0, REG_SZ, (const BYTE *)value, len );
215 }
216 
msi_reg_set_val_multi_str(HKEY hkey,LPCWSTR name,LPCWSTR value)217 LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
218 {
219     LPCWSTR p = value;
220     while (*p) p += lstrlenW(p) + 1;
221     return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
222                            (const BYTE *)value, (p + 1 - value) * sizeof(WCHAR) );
223 }
224 
msi_reg_set_val_dword(HKEY hkey,LPCWSTR name,DWORD val)225 LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
226 {
227     return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
228 }
229 
msi_reg_set_subkey_val(HKEY hkey,LPCWSTR path,LPCWSTR name,LPCWSTR val)230 LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
231 {
232     HKEY hsubkey = 0;
233     LONG r;
234 
235     r = RegCreateKeyW( hkey, path, &hsubkey );
236     if (r != ERROR_SUCCESS)
237         return r;
238     r = msi_reg_set_val_str( hsubkey, name, val );
239     RegCloseKey( hsubkey );
240     return r;
241 }
242 
msi_reg_get_val_str(HKEY hkey,LPCWSTR name)243 LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name )
244 {
245     DWORD len = 0;
246     LPWSTR val;
247     LONG r;
248 
249     r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len);
250     if (r != ERROR_SUCCESS)
251         return NULL;
252 
253     len += sizeof (WCHAR);
254     val = malloc( len );
255     if (!val)
256         return NULL;
257     val[0] = 0;
258     RegQueryValueExW(hkey, name, NULL, NULL, (LPBYTE) val, &len);
259     return val;
260 }
261 
msi_reg_get_val_dword(HKEY hkey,LPCWSTR name,DWORD * val)262 BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val)
263 {
264     DWORD type, len = sizeof (DWORD);
265     LONG r = RegQueryValueExW(hkey, name, NULL, &type, (LPBYTE) val, &len);
266     return r == ERROR_SUCCESS && type == REG_DWORD;
267 }
268 
get_user_sid(void)269 static WCHAR *get_user_sid(void)
270 {
271     HANDLE token;
272     DWORD size = 256;
273     TOKEN_USER *user;
274     WCHAR *ret;
275 
276     if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token )) return NULL;
277     if (!(user = malloc( size )))
278     {
279         CloseHandle( token );
280         return NULL;
281     }
282     if (!GetTokenInformation( token, TokenUser, user, size, &size ))
283     {
284         free( user );
285         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || !(user = malloc( size )))
286         {
287             CloseHandle( token );
288             return NULL;
289         }
290         GetTokenInformation( token, TokenUser, user, size, &size );
291     }
292     CloseHandle( token );
293     if (!ConvertSidToStringSidW( user->User.Sid, &ret ))
294     {
295         free( user );
296         return NULL;
297     }
298     free( user );
299     return ret;
300 }
301 
MSIREG_OpenUninstallKey(const WCHAR * product,enum platform platform,HKEY * key,BOOL create)302 UINT MSIREG_OpenUninstallKey(const WCHAR *product, enum platform platform, HKEY *key, BOOL create)
303 {
304     REGSAM access = KEY_ALL_ACCESS;
305     WCHAR keypath[0x200];
306 
307     TRACE("%s\n", debugstr_w(product));
308 
309     if (platform == PLATFORM_INTEL)
310         access |= KEY_WOW64_32KEY;
311     else
312         access |= KEY_WOW64_64KEY;
313     lstrcpyW(keypath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\");
314     lstrcatW(keypath, product);
315     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
316     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
317 }
318 
MSIREG_DeleteUninstallKey(const WCHAR * product,enum platform platform)319 UINT MSIREG_DeleteUninstallKey(const WCHAR *product, enum platform platform)
320 {
321     REGSAM access = KEY_ALL_ACCESS;
322     HKEY parent;
323     LONG r;
324 
325     TRACE("%s\n", debugstr_w(product));
326 
327     if (platform == PLATFORM_INTEL)
328         access |= KEY_WOW64_32KEY;
329     else
330         access |= KEY_WOW64_64KEY;
331     if ((r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\",
332                            0, access, &parent))) return r;
333     r = RegDeleteTreeW(parent, product);
334     RegCloseKey(parent);
335     return r;
336 }
337 
MSIREG_OpenProductKey(LPCWSTR szProduct,LPCWSTR szUserSid,MSIINSTALLCONTEXT context,HKEY * key,BOOL create)338 UINT MSIREG_OpenProductKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
339 {
340     HKEY root = HKEY_LOCAL_MACHINE;
341     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
342     WCHAR *usersid = NULL, squashed_pc[SQUASHED_GUID_SIZE], keypath[MAX_PATH];
343 
344     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
345     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
346 
347     if (context == MSIINSTALLCONTEXT_MACHINE)
348     {
349         lstrcpyW(keypath, L"Software\\Classes\\Installer\\Products\\");
350         lstrcatW( keypath, squashed_pc );
351     }
352     else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
353     {
354         root = HKEY_CURRENT_USER;
355         lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Products\\" );
356         lstrcatW( keypath, squashed_pc );
357     }
358     else
359     {
360         if (!szUserSid)
361         {
362             if (!(usersid = get_user_sid()))
363             {
364                 ERR("Failed to retrieve user SID\n");
365                 return ERROR_FUNCTION_FAILED;
366             }
367             szUserSid = usersid;
368         }
369         swprintf( keypath, ARRAY_SIZE(keypath),
370                   L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\%s\\Installer\\Products\\%s",
371                   szUserSid, squashed_pc );
372         LocalFree(usersid);
373     }
374     if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL);
375     return RegOpenKeyExW(root, keypath, 0, access, key);
376 }
377 
MSIREG_DeleteUserProductKey(LPCWSTR szProduct)378 UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
379 {
380     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
381 
382     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
383     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
384 
385     lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Products\\" );
386     lstrcatW( keypath, squashed_pc );
387     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
388 }
389 
MSIREG_OpenUserPatchesKey(LPCWSTR szPatch,HKEY * key,BOOL create)390 UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
391 {
392     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
393 
394     if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED;
395     TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc));
396 
397     lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Patches\\" );
398     lstrcatW( keypath, squashed_pc );
399 
400     if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
401     return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
402 }
403 
MSIREG_OpenFeaturesKey(LPCWSTR szProduct,LPCWSTR szUserSid,MSIINSTALLCONTEXT context,HKEY * key,BOOL create)404 UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context,
405                             HKEY *key, BOOL create)
406 {
407     HKEY root = HKEY_LOCAL_MACHINE;
408     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
409     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[MAX_PATH], *usersid = NULL;
410 
411     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
412     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
413 
414     if (context == MSIINSTALLCONTEXT_MACHINE)
415     {
416         lstrcpyW(keypath, L"Software\\Classes\\Installer\\Features\\");
417         lstrcatW( keypath, squashed_pc );
418     }
419     else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
420     {
421         root = HKEY_CURRENT_USER;
422         lstrcpyW(keypath, L"Software\\Microsoft\\Installer\\Features\\");
423         lstrcatW( keypath, squashed_pc );
424     }
425     else
426     {
427         if (!szUserSid)
428         {
429             if (!(usersid = get_user_sid()))
430             {
431                 ERR("Failed to retrieve user SID\n");
432                 return ERROR_FUNCTION_FAILED;
433             }
434             szUserSid = usersid;
435         }
436         swprintf( keypath, ARRAY_SIZE(keypath),
437                   L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\%s\\Installer\\Features\\%s",
438                   szUserSid, squashed_pc );
439         LocalFree(usersid);
440     }
441     if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL);
442     return RegOpenKeyExW(root, keypath, 0, access, key);
443 }
444 
MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)445 UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
446 {
447     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
448 
449     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
450     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
451 
452     lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Features\\" );
453     lstrcatW( keypath, squashed_pc );
454     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
455 }
456 
MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct,HKEY * key,BOOL create)457 static UINT MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
458 {
459     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
460     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
461 
462     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
463     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
464 
465     lstrcpyW(keypath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Features\\");
466     lstrcatW( keypath, squashed_pc );
467 
468     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
469     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
470 }
471 
MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct,LPCWSTR szUserSid,MSIINSTALLCONTEXT context,HKEY * key,BOOL create)472 UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context,
473                                     HKEY *key, BOOL create)
474 {
475     static const WCHAR fmtW[] =
476         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Products\\%s\\Features";
477     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
478     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200], *usersid = NULL;
479 
480     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
481     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
482 
483     if (context == MSIINSTALLCONTEXT_MACHINE)
484     {
485         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_pc );
486     }
487     else
488     {
489         if (!szUserSid)
490         {
491             if (!(usersid = get_user_sid()))
492             {
493                 ERR("Failed to retrieve user SID\n");
494                 return ERROR_FUNCTION_FAILED;
495             }
496             szUserSid = usersid;
497         }
498         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, szUserSid, squashed_pc );
499         LocalFree(usersid);
500     }
501     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
502     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
503 }
504 
MSIREG_OpenUserComponentsKey(LPCWSTR szComponent,HKEY * key,BOOL create)505 UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY *key, BOOL create)
506 {
507     WCHAR squashed_cc[SQUASHED_GUID_SIZE], keypath[0x200];
508     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
509     UINT ret;
510 
511     if (!squash_guid( szComponent, squashed_cc)) return ERROR_FUNCTION_FAILED;
512     TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_cc));
513 
514     lstrcpyW(keypath, L"Software\\Microsoft\\Installer\\Components\\");
515     lstrcatW( keypath, squashed_cc );
516 
517     if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
518     ret = RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
519     if (ret != ERROR_FILE_NOT_FOUND) return ret;
520 
521     lstrcpyW(keypath, L"Software\\Classes\\Installer\\Components\\");
522     lstrcatW( keypath, squashed_cc );
523     return RegOpenKeyExW( HKEY_LOCAL_MACHINE, keypath, 0, access, key );
524 }
525 
MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent,LPCWSTR szUserSid,HKEY * key,BOOL create)526 UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid, HKEY *key, BOOL create)
527 {
528     static const WCHAR fmtW[] =
529         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Components\\%s";
530     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
531     WCHAR *usersid, squashed_comp[SQUASHED_GUID_SIZE], keypath[0x200];
532 
533     if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED;
534     TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp));
535 
536     if (!szUserSid)
537     {
538         if (!(usersid = get_user_sid()))
539         {
540             ERR("Failed to retrieve user SID\n");
541             return ERROR_FUNCTION_FAILED;
542         }
543         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_comp );
544         LocalFree(usersid);
545     }
546     else swprintf( keypath, ARRAY_SIZE(keypath), fmtW, szUserSid, squashed_comp );
547 
548     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
549     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
550 }
551 
MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent,LPCWSTR szUserSid)552 UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid)
553 {
554     static const WCHAR fmtW[] =
555         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Components";
556     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
557     WCHAR *usersid, squashed_comp[SQUASHED_GUID_SIZE], keypath[0x200];
558     HKEY hkey;
559     LONG r;
560 
561     if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED;
562     TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp));
563 
564     if (!szUserSid)
565     {
566         if (!(usersid = get_user_sid()))
567         {
568             ERR("Failed to retrieve user SID\n");
569             return ERROR_FUNCTION_FAILED;
570         }
571         swprintf(keypath, ARRAY_SIZE(keypath), fmtW, usersid);
572         LocalFree(usersid);
573     }
574     else swprintf(keypath, ARRAY_SIZE(keypath), fmtW, szUserSid);
575 
576     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
577     r = RegDeleteTreeW( hkey, squashed_comp );
578     RegCloseKey(hkey);
579     return r;
580 }
581 
MSIREG_OpenUserDataProductKey(LPCWSTR szProduct,MSIINSTALLCONTEXT dwContext,LPCWSTR szUserSid,HKEY * key,BOOL create)582 UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create)
583 {
584     static const WCHAR fmtW[] =
585         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Products\\%s";
586     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
587     WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
588 
589     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
590     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
591 
592     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
593         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_pc );
594     else if (szUserSid)
595         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, szUserSid, squashed_pc );
596     else
597     {
598         if (!(usersid = get_user_sid()))
599         {
600             ERR("Failed to retrieve user SID\n");
601             return ERROR_FUNCTION_FAILED;
602         }
603         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_pc );
604         LocalFree(usersid);
605     }
606     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
607     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
608 }
609 
MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch,MSIINSTALLCONTEXT dwContext,HKEY * key,BOOL create)610 UINT MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch, MSIINSTALLCONTEXT dwContext, HKEY *key, BOOL create)
611 {
612     static const WCHAR fmtW[] =
613         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Patches\\%s";
614     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
615     WCHAR *usersid, squashed_patch[SQUASHED_GUID_SIZE], keypath[0x200];
616 
617     if (!squash_guid( szPatch, squashed_patch )) return ERROR_FUNCTION_FAILED;
618     TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_patch));
619 
620     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
621         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_patch );
622     else
623     {
624         if (!(usersid = get_user_sid()))
625         {
626             ERR("Failed to retrieve user SID\n");
627             return ERROR_FUNCTION_FAILED;
628         }
629         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_patch );
630         LocalFree(usersid);
631     }
632     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
633     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
634 }
635 
MSIREG_DeleteUserDataPatchKey(LPCWSTR patch,MSIINSTALLCONTEXT context)636 UINT MSIREG_DeleteUserDataPatchKey(LPCWSTR patch, MSIINSTALLCONTEXT context)
637 {
638     static const WCHAR fmtW[] =
639         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Patches";
640     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
641     WCHAR *usersid, squashed_patch[SQUASHED_GUID_SIZE], keypath[0x200];
642     HKEY hkey;
643     LONG r;
644 
645     if (!squash_guid( patch, squashed_patch )) return ERROR_FUNCTION_FAILED;
646     TRACE("%s squashed %s\n", debugstr_w(patch), debugstr_w(squashed_patch));
647 
648     if (context == MSIINSTALLCONTEXT_MACHINE)
649         swprintf(keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18");
650     else
651     {
652         if (!(usersid = get_user_sid()))
653         {
654             ERR("Failed to retrieve user SID\n");
655             return ERROR_FUNCTION_FAILED;
656         }
657         swprintf(keypath, ARRAY_SIZE(keypath), fmtW, usersid);
658         LocalFree(usersid);
659     }
660     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
661     r = RegDeleteTreeW( hkey, squashed_patch );
662     RegCloseKey(hkey);
663     return r;
664 }
665 
MSIREG_OpenUserDataProductPatchesKey(LPCWSTR product,MSIINSTALLCONTEXT context,HKEY * key,BOOL create)666 UINT MSIREG_OpenUserDataProductPatchesKey(LPCWSTR product, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
667 {
668     static const WCHAR fmtW[] =
669         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Products\\%s\\Patches";
670     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
671     WCHAR *usersid, squashed_product[SQUASHED_GUID_SIZE], keypath[0x200];
672 
673     if (!squash_guid( product, squashed_product )) return ERROR_FUNCTION_FAILED;
674     TRACE("%s squashed %s\n", debugstr_w(product), debugstr_w(squashed_product));
675 
676     if (context == MSIINSTALLCONTEXT_MACHINE)
677         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_product );
678     else
679     {
680         if (!(usersid = get_user_sid()))
681         {
682             ERR("Failed to retrieve user SID\n");
683             return ERROR_FUNCTION_FAILED;
684         }
685         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_product );
686         LocalFree(usersid);
687     }
688     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
689     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
690 }
691 
MSIREG_OpenInstallProps(LPCWSTR szProduct,MSIINSTALLCONTEXT dwContext,LPCWSTR szUserSid,HKEY * key,BOOL create)692 UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create)
693 {
694     static const WCHAR fmtW[] =
695         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Products\\%s\\InstallProperties";
696     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
697     WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
698 
699     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
700     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
701 
702     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
703         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_pc );
704     else if (szUserSid)
705         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, szUserSid, squashed_pc );
706     else
707     {
708         if (!(usersid = get_user_sid()))
709         {
710             ERR("Failed to retrieve user SID\n");
711             return ERROR_FUNCTION_FAILED;
712         }
713         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_pc );
714         LocalFree(usersid);
715     }
716     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
717     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
718 }
719 
MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct,MSIINSTALLCONTEXT context)720 UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context)
721 {
722     static const WCHAR fmtW[] =
723         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Products";
724     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
725     WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
726     HKEY hkey;
727     LONG r;
728 
729     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
730     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
731 
732     if (context == MSIINSTALLCONTEXT_MACHINE)
733         swprintf(keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18");
734     else
735     {
736         if (!(usersid = get_user_sid()))
737         {
738             ERR("Failed to retrieve user SID\n");
739             return ERROR_FUNCTION_FAILED;
740         }
741         swprintf(keypath, ARRAY_SIZE(keypath), fmtW, usersid);
742         LocalFree(usersid);
743     }
744 
745     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
746     r = RegDeleteTreeW( hkey, squashed_pc );
747     RegCloseKey(hkey);
748     return r;
749 }
750 
MSIREG_DeleteProductKey(LPCWSTR szProduct)751 UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
752 {
753     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
754     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
755     HKEY hkey;
756     LONG r;
757 
758     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
759     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
760 
761     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products",
762                       0, access, &hkey)) return ERROR_SUCCESS;
763     r = RegDeleteTreeW( hkey, squashed_pc );
764     RegCloseKey(hkey);
765     return r;
766 }
767 
MSIREG_OpenPatchesKey(LPCWSTR szPatch,HKEY * key,BOOL create)768 UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
769 {
770     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
771     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
772 
773     if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED;
774     TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc));
775 
776     lstrcpyW( keypath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Patches\\" );
777     lstrcatW( keypath, squashed_pc );
778 
779     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
780     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
781 }
782 
MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode,HKEY * key,BOOL create)783 UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create)
784 {
785     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
786     WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
787 
788     if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
789     TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
790 
791     lstrcpyW( keypath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\" );
792     lstrcatW( keypath, squashed_uc );
793 
794     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
795     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
796 }
797 
MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode,HKEY * key,BOOL create)798 UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
799 {
800     WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
801 
802     if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
803     TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
804 
805     lstrcpyW(keypath, L"Software\\Microsoft\\Installer\\UpgradeCodes\\");
806     lstrcatW( keypath, squashed_uc );
807 
808     if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
809     return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
810 }
811 
MSIREG_DeleteUpgradeCodesKey(const WCHAR * code)812 UINT MSIREG_DeleteUpgradeCodesKey( const WCHAR *code )
813 {
814     WCHAR squashed_code[SQUASHED_GUID_SIZE];
815     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
816     HKEY hkey;
817     LONG ret;
818 
819     if (!squash_guid( code, squashed_code )) return ERROR_FUNCTION_FAILED;
820     TRACE( "%s squashed %s\n", debugstr_w(code), debugstr_w(squashed_code) );
821 
822     if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\",
823                        0, access, &hkey )) return ERROR_SUCCESS;
824     ret = RegDeleteTreeW( hkey, squashed_code );
825     RegCloseKey( hkey );
826     return ret;
827 }
828 
MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode)829 UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode)
830 {
831     WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
832 
833     if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
834     TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
835 
836     lstrcpyW(keypath, L"Software\\Microsoft\\Installer\\UpgradeCodes\\");
837     lstrcatW( keypath, squashed_uc );
838     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
839 }
840 
MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode)841 UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode)
842 {
843     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
844     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
845     HKEY hkey;
846     LONG r;
847 
848     if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED;
849     TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc));
850 
851     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Classes\\Installer\\Products", 0, access, &hkey))
852         return ERROR_SUCCESS;
853     r = RegDeleteTreeW( hkey, squashed_pc );
854     RegCloseKey(hkey);
855     return r;
856 }
857 
MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode)858 UINT MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode)
859 {
860     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
861     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
862     HKEY hkey;
863     LONG r;
864 
865     if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED;
866     TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc));
867 
868     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Classes\\Installer\\Features", 0, access, &hkey))
869         return ERROR_SUCCESS;
870     r = RegDeleteTreeW( hkey, squashed_pc );
871     RegCloseKey(hkey);
872     return r;
873 }
874 
MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode,HKEY * key,BOOL create)875 UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create)
876 {
877     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
878     WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
879 
880     if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
881     TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
882 
883     lstrcpyW(keypath, L"Software\\Classes\\Installer\\UpgradeCodes\\");
884     lstrcatW( keypath, squashed_uc );
885 
886     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
887     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
888 }
889 
MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode)890 UINT MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode)
891 {
892     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
893     WCHAR squashed_uc[SQUASHED_GUID_SIZE];
894     HKEY hkey;
895     LONG r;
896 
897     if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
898     TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
899 
900     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Classes\\Installer\\UpgradeCodes", 0, access, &hkey))
901         return ERROR_SUCCESS;
902     r = RegDeleteTreeW( hkey, squashed_uc );
903     RegCloseKey(hkey);
904     return r;
905 }
906 
907 /*************************************************************************
908  *  MsiDecomposeDescriptorW   [MSI.@]
909  *
910  * Decomposes an MSI descriptor into product, feature and component parts.
911  * An MSI descriptor is a string of the form:
912  *   [base 85 guid] [feature code] '>' [base 85 guid] or
913  *   [base 85 guid] [feature code] '<'
914  *
915  * PARAMS
916  *   szDescriptor  [I]  the descriptor to decompose
917  *   szProduct     [O]  buffer of MAX_FEATURE_CHARS+1 for the product guid
918  *   szFeature     [O]  buffer of MAX_FEATURE_CHARS+1 for the feature code
919  *   szComponent   [O]  buffer of MAX_FEATURE_CHARS+1 for the component guid
920  *   pUsed         [O]  the length of the descriptor
921  *
922  * RETURNS
923  *   ERROR_SUCCESS             if everything worked correctly
924  *   ERROR_INVALID_PARAMETER   if the descriptor was invalid
925  *
926  */
MsiDecomposeDescriptorW(LPCWSTR szDescriptor,LPWSTR szProduct,LPWSTR szFeature,LPWSTR szComponent,LPDWORD pUsed)927 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
928                 LPWSTR szFeature, LPWSTR szComponent, LPDWORD pUsed )
929 {
930     UINT len;
931     const WCHAR *p;
932     GUID product, component;
933 
934     TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
935           szFeature, szComponent, pUsed);
936 
937     if (!decode_base85_guid( szDescriptor, &product ))
938         return ERROR_INVALID_PARAMETER;
939 
940     TRACE("product %s\n", debugstr_guid( &product ));
941 
942     if (!(p = wcschr( &szDescriptor[20], '>' )))
943         p = wcschr( &szDescriptor[20], '<' );
944     if (!p)
945         return ERROR_INVALID_PARAMETER;
946 
947     len = (p - &szDescriptor[20]);
948     if( len > MAX_FEATURE_CHARS )
949         return ERROR_INVALID_PARAMETER;
950 
951     TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
952 
953     if (*p == '>')
954     {
955         if (!decode_base85_guid( p+1, &component ))
956             return ERROR_INVALID_PARAMETER;
957         TRACE( "component %s\n", debugstr_guid(&component) );
958     }
959 
960     if (szProduct)
961         StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
962     if (szComponent)
963     {
964         if (*p == '>')
965             StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
966         else
967             szComponent[0] = 0;
968     }
969     if (szFeature)
970     {
971         memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
972         szFeature[len] = 0;
973     }
974 
975     len = p - szDescriptor + 1;
976     if (*p == '>') len += 20;
977 
978     TRACE("length = %d\n", len);
979     if (pUsed) *pUsed = len;
980 
981     return ERROR_SUCCESS;
982 }
983 
MsiDecomposeDescriptorA(LPCSTR szDescriptor,LPSTR szProduct,LPSTR szFeature,LPSTR szComponent,LPDWORD pUsed)984 UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
985                 LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed )
986 {
987     WCHAR product[MAX_FEATURE_CHARS+1];
988     WCHAR feature[MAX_FEATURE_CHARS+1];
989     WCHAR component[MAX_FEATURE_CHARS+1];
990     LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
991     UINT r;
992 
993     TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
994           szFeature, szComponent, pUsed);
995 
996     str = strdupAtoW( szDescriptor );
997     if( szDescriptor && !str )
998         return ERROR_OUTOFMEMORY;
999 
1000     if (szProduct)
1001         p = product;
1002     if (szFeature)
1003         f = feature;
1004     if (szComponent)
1005         c = component;
1006 
1007     r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
1008 
1009     if (r == ERROR_SUCCESS)
1010     {
1011         WideCharToMultiByte( CP_ACP, 0, p, -1,
1012                              szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
1013         WideCharToMultiByte( CP_ACP, 0, f, -1,
1014                              szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
1015         WideCharToMultiByte( CP_ACP, 0, c, -1,
1016                              szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
1017     }
1018 
1019     free( str );
1020 
1021     return r;
1022 }
1023 
MsiEnumProductsA(DWORD index,char * lpguid)1024 UINT WINAPI MsiEnumProductsA( DWORD index, char *lpguid )
1025 {
1026     DWORD r;
1027     WCHAR szwGuid[GUID_SIZE];
1028 
1029     TRACE( "%lu, %p\n", index, lpguid );
1030 
1031     if (NULL == lpguid)
1032         return ERROR_INVALID_PARAMETER;
1033     r = MsiEnumProductsW(index, szwGuid);
1034     if( r == ERROR_SUCCESS )
1035         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1036 
1037     return r;
1038 }
1039 
MsiEnumProductsW(DWORD index,WCHAR * lpguid)1040 UINT WINAPI MsiEnumProductsW( DWORD index, WCHAR *lpguid )
1041 {
1042     TRACE("%lu, %p\n", index, lpguid );
1043 
1044     if (NULL == lpguid)
1045         return ERROR_INVALID_PARAMETER;
1046 
1047     return MsiEnumProductsExW( NULL, L"S-1-1-0", MSIINSTALLCONTEXT_ALL, index, lpguid,
1048                                NULL, NULL, NULL );
1049 }
1050 
MsiEnumFeaturesA(const char * szProduct,DWORD index,char * szFeature,char * szParent)1051 UINT WINAPI MsiEnumFeaturesA( const char *szProduct, DWORD index, char *szFeature, char *szParent )
1052 {
1053     DWORD r;
1054     WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
1055     WCHAR *szwProduct = NULL;
1056 
1057     TRACE( "%s, %lu, %p, %p\n", debugstr_a(szProduct), index, szFeature, szParent );
1058 
1059     if( szProduct )
1060     {
1061         szwProduct = strdupAtoW( szProduct );
1062         if( !szwProduct )
1063             return ERROR_OUTOFMEMORY;
1064     }
1065 
1066     r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
1067     if( r == ERROR_SUCCESS )
1068     {
1069         WideCharToMultiByte(CP_ACP, 0, szwFeature, -1, szFeature, GUID_SIZE, NULL, NULL);
1070         WideCharToMultiByte(CP_ACP, 0, szwParent, -1, szParent, GUID_SIZE, NULL, NULL);
1071     }
1072 
1073     free(szwProduct);
1074 
1075     return r;
1076 }
1077 
MsiEnumFeaturesW(const WCHAR * szProduct,DWORD index,WCHAR * szFeature,WCHAR * szParent)1078 UINT WINAPI MsiEnumFeaturesW( const WCHAR *szProduct, DWORD index, WCHAR *szFeature, WCHAR *szParent )
1079 {
1080     HKEY hkeyProduct = 0;
1081     DWORD r, sz;
1082 
1083     TRACE( "%s, %lu, %p, %p\n", debugstr_w(szProduct), index, szFeature, szParent );
1084 
1085     if( !szProduct )
1086         return ERROR_INVALID_PARAMETER;
1087 
1088     r = MSIREG_OpenInstallerFeaturesKey(szProduct,&hkeyProduct,FALSE);
1089     if( r != ERROR_SUCCESS )
1090         return ERROR_NO_MORE_ITEMS;
1091 
1092     sz = GUID_SIZE;
1093     r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
1094     RegCloseKey(hkeyProduct);
1095 
1096     return r;
1097 }
1098 
MsiEnumComponentsA(DWORD index,char * lpguid)1099 UINT WINAPI MsiEnumComponentsA( DWORD index, char *lpguid )
1100 {
1101     DWORD r;
1102     WCHAR szwGuid[GUID_SIZE];
1103 
1104     TRACE( "%lu, %p\n", index, lpguid );
1105 
1106     if (!lpguid) return ERROR_INVALID_PARAMETER;
1107 
1108     r = MsiEnumComponentsW(index, szwGuid);
1109     if( r == ERROR_SUCCESS )
1110         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1111 
1112     return r;
1113 }
1114 
MsiEnumComponentsW(DWORD index,WCHAR * lpguid)1115 UINT WINAPI MsiEnumComponentsW( DWORD index, WCHAR *lpguid )
1116 {
1117     TRACE( "%lu, %p\n", index, lpguid );
1118 
1119     if (!lpguid) return ERROR_INVALID_PARAMETER;
1120 
1121     return MsiEnumComponentsExW( L"S-1-1-0", MSIINSTALLCONTEXT_ALL, index, lpguid, NULL, NULL, NULL );
1122 }
1123 
MsiEnumComponentsExA(const char * user_sid,DWORD ctx,DWORD index,CHAR guid[39],MSIINSTALLCONTEXT * installed_ctx,char * sid,DWORD * sid_len)1124 UINT WINAPI MsiEnumComponentsExA( const char *user_sid, DWORD ctx, DWORD index, CHAR guid[39],
1125                                   MSIINSTALLCONTEXT *installed_ctx, char *sid, DWORD *sid_len )
1126 {
1127     UINT r;
1128     WCHAR *user_sidW = NULL, *sidW = NULL, guidW[GUID_SIZE];
1129 
1130     TRACE( "%s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_a(user_sid), ctx, index, guid, installed_ctx,
1131            sid, sid_len );
1132 
1133     if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
1134     if (user_sid && !(user_sidW = strdupAtoW( user_sid ))) return ERROR_OUTOFMEMORY;
1135     if (sid && !(sidW = malloc( *sid_len * sizeof(WCHAR) )))
1136     {
1137         free( user_sidW );
1138         return ERROR_OUTOFMEMORY;
1139     }
1140     r = MsiEnumComponentsExW( user_sidW, ctx, index, guidW, installed_ctx, sidW, sid_len );
1141     if (r == ERROR_SUCCESS)
1142     {
1143         if (guid) WideCharToMultiByte( CP_ACP, 0, guidW, GUID_SIZE, guid, GUID_SIZE, NULL, NULL );
1144         if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
1145     }
1146     free( user_sidW );
1147     free( sidW );
1148     return r;
1149 }
1150 
fetch_machine_component(DWORD ctx,DWORD index,DWORD * idx,WCHAR guid[39],MSIINSTALLCONTEXT * installed_ctx,LPWSTR sid,LPDWORD sid_len)1151 static UINT fetch_machine_component( DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
1152                                      MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1153 {
1154     UINT r = ERROR_SUCCESS;
1155     WCHAR component[SQUASHED_GUID_SIZE];
1156     DWORD i = 0, len_component;
1157     REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
1158     HKEY key_components;
1159 
1160     if (RegOpenKeyExW( HKEY_LOCAL_MACHINE,
1161                        L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Components",
1162                        0, access, &key_components ))
1163         return ERROR_NO_MORE_ITEMS;
1164 
1165     len_component = ARRAY_SIZE( component );
1166     while (!RegEnumKeyExW( key_components, i, component, &len_component, NULL, NULL, NULL, NULL ))
1167     {
1168         if (*idx == index) goto found;
1169         (*idx)++;
1170         len_component = ARRAY_SIZE( component );
1171         i++;
1172     }
1173     RegCloseKey( key_components );
1174     return ERROR_NO_MORE_ITEMS;
1175 
1176 found:
1177     if (sid_len)
1178     {
1179         if (*sid_len < 1)
1180         {
1181             *sid_len = 1;
1182             r = ERROR_MORE_DATA;
1183         }
1184         else if (sid)
1185         {
1186             *sid_len = 0;
1187             sid[0] = 0;
1188         }
1189     }
1190     if (guid) unsquash_guid( component, guid );
1191     if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
1192     RegCloseKey( key_components );
1193     return r;
1194 }
1195 
fetch_user_component(const WCHAR * usersid,DWORD ctx,DWORD index,DWORD * idx,WCHAR guid[39],MSIINSTALLCONTEXT * installed_ctx,LPWSTR sid,LPDWORD sid_len)1196 static UINT fetch_user_component( const WCHAR *usersid, DWORD ctx, DWORD index, DWORD *idx,
1197                                   WCHAR guid[39], MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid,
1198                                   LPDWORD sid_len )
1199 {
1200     UINT r = ERROR_SUCCESS;
1201     WCHAR path[MAX_PATH], component[SQUASHED_GUID_SIZE], user[128];
1202     DWORD i = 0, j = 0, len_component, len_user;
1203     REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
1204     HKEY key_users, key_components;
1205 
1206     if (ctx == MSIINSTALLCONTEXT_USERMANAGED) /* FIXME: where to find these? */
1207         return ERROR_NO_MORE_ITEMS;
1208 
1209     if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData",
1210                        0, access, &key_users )) return ERROR_NO_MORE_ITEMS;
1211 
1212     len_user = ARRAY_SIZE( user );
1213     while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
1214     {
1215         if ((wcscmp( usersid, L"S-1-1-0" ) && wcscmp( usersid, user )) ||
1216             !wcscmp( L"S-1-5-18", user ))
1217         {
1218             i++;
1219             len_user = ARRAY_SIZE( user );
1220             continue;
1221         }
1222         lstrcpyW( path, user );
1223         lstrcatW( path, L"\\Components" );
1224         if (RegOpenKeyExW( key_users, path, 0, access, &key_components ))
1225         {
1226             i++;
1227             len_user = ARRAY_SIZE( user );
1228             continue;
1229         }
1230         len_component = ARRAY_SIZE( component );
1231         while (!RegEnumKeyExW( key_components, j, component, &len_component, NULL, NULL, NULL, NULL ))
1232         {
1233             if (*idx == index) goto found;
1234             (*idx)++;
1235             len_component = ARRAY_SIZE( component );
1236             j++;
1237         }
1238         RegCloseKey( key_components );
1239         len_user = ARRAY_SIZE( user );
1240         i++;
1241     }
1242     RegCloseKey( key_users );
1243     return ERROR_NO_MORE_ITEMS;
1244 
1245 found:
1246     if (sid_len)
1247     {
1248         if (*sid_len < len_user + 1)
1249         {
1250             *sid_len = len_user + 1;
1251             r = ERROR_MORE_DATA;
1252         }
1253         else if (sid)
1254         {
1255             *sid_len = len_user;
1256             lstrcpyW( sid, user );
1257         }
1258     }
1259     if (guid) unsquash_guid( component, guid );
1260     if (installed_ctx) *installed_ctx = ctx;
1261     RegCloseKey( key_components );
1262     RegCloseKey( key_users );
1263     return r;
1264 }
1265 
enum_components(const WCHAR * usersid,DWORD ctx,DWORD index,DWORD * idx,WCHAR guid[39],MSIINSTALLCONTEXT * installed_ctx,LPWSTR sid,LPDWORD sid_len)1266 static UINT enum_components( const WCHAR *usersid, DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
1267                              MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1268 {
1269     UINT r = ERROR_NO_MORE_ITEMS;
1270     WCHAR *user = NULL;
1271 
1272     if (!usersid)
1273     {
1274         usersid = user = get_user_sid();
1275         if (!user) return ERROR_FUNCTION_FAILED;
1276     }
1277     if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
1278     {
1279         r = fetch_user_component( usersid, MSIINSTALLCONTEXT_USERMANAGED, index, idx, guid,
1280                                   installed_ctx, sid, sid_len );
1281         if (r != ERROR_NO_MORE_ITEMS) goto done;
1282     }
1283     if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
1284     {
1285         r = fetch_user_component( usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index, idx, guid,
1286                                   installed_ctx, sid, sid_len );
1287         if (r != ERROR_NO_MORE_ITEMS) goto done;
1288     }
1289     if (ctx & MSIINSTALLCONTEXT_MACHINE)
1290     {
1291         r = fetch_machine_component( MSIINSTALLCONTEXT_MACHINE, index, idx, guid, installed_ctx,
1292                                      sid, sid_len );
1293         if (r != ERROR_NO_MORE_ITEMS) goto done;
1294     }
1295 
1296 done:
1297     LocalFree( user );
1298     return r;
1299 }
1300 
MsiEnumComponentsExW(const WCHAR * user_sid,DWORD ctx,DWORD index,WCHAR guid[39],MSIINSTALLCONTEXT * installed_ctx,WCHAR * sid,DWORD * sid_len)1301 UINT WINAPI MsiEnumComponentsExW( const WCHAR *user_sid, DWORD ctx, DWORD index, WCHAR guid[39],
1302                                   MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
1303 {
1304     UINT r;
1305     DWORD idx = 0;
1306     static DWORD last_index;
1307 
1308     TRACE( "%s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(user_sid), ctx, index, guid, installed_ctx,
1309           sid, sid_len );
1310 
1311     if ((sid && !sid_len) || !ctx || (user_sid && ctx == MSIINSTALLCONTEXT_MACHINE))
1312         return ERROR_INVALID_PARAMETER;
1313 
1314     if (index && index - last_index != 1)
1315         return ERROR_INVALID_PARAMETER;
1316 
1317     if (!index) last_index = 0;
1318 
1319     r = enum_components( user_sid, ctx, index, &idx, guid, installed_ctx, sid, sid_len );
1320     if (r == ERROR_SUCCESS)
1321         last_index = index;
1322     else
1323         last_index = 0;
1324 
1325     return r;
1326 }
1327 
MsiEnumClientsA(const char * szComponent,DWORD index,char * szProduct)1328 UINT WINAPI MsiEnumClientsA( const char *szComponent, DWORD index, char *szProduct )
1329 {
1330     DWORD r;
1331     WCHAR szwProduct[GUID_SIZE];
1332     WCHAR *szwComponent = NULL;
1333 
1334     TRACE( "%s, %lu, %p\n", debugstr_a(szComponent), index, szProduct );
1335 
1336     if ( !szProduct )
1337         return ERROR_INVALID_PARAMETER;
1338 
1339     if( szComponent )
1340     {
1341         szwComponent = strdupAtoW( szComponent );
1342         if( !szwComponent )
1343             return ERROR_OUTOFMEMORY;
1344     }
1345 
1346     r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
1347     if( r == ERROR_SUCCESS )
1348         WideCharToMultiByte(CP_ACP, 0, szwProduct, -1, szProduct, GUID_SIZE, NULL, NULL);
1349 
1350     free(szwComponent);
1351 
1352     return r;
1353 }
1354 
MsiEnumClientsW(const WCHAR * szComponent,DWORD index,WCHAR * szProduct)1355 UINT WINAPI MsiEnumClientsW( const WCHAR *szComponent, DWORD index, WCHAR *szProduct )
1356 {
1357     HKEY hkeyComp = 0;
1358     DWORD r, sz;
1359     WCHAR szValName[SQUASHED_GUID_SIZE];
1360 
1361     TRACE( "%s, %lu, %p\n", debugstr_w(szComponent), index, szProduct );
1362 
1363     if (!szComponent || !*szComponent || !szProduct)
1364         return ERROR_INVALID_PARAMETER;
1365 
1366     if (MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkeyComp, FALSE) != ERROR_SUCCESS &&
1367         MSIREG_OpenUserDataComponentKey(szComponent, L"S-1-5-18", &hkeyComp, FALSE) != ERROR_SUCCESS)
1368         return ERROR_UNKNOWN_COMPONENT;
1369 
1370     /* see if there are any products at all */
1371     sz = SQUASHED_GUID_SIZE;
1372     r = RegEnumValueW(hkeyComp, 0, szValName, &sz, NULL, NULL, NULL, NULL);
1373     if (r != ERROR_SUCCESS)
1374     {
1375         RegCloseKey(hkeyComp);
1376 
1377         if (index != 0)
1378             return ERROR_INVALID_PARAMETER;
1379 
1380         return ERROR_UNKNOWN_COMPONENT;
1381     }
1382 
1383     sz = SQUASHED_GUID_SIZE;
1384     r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
1385     if( r == ERROR_SUCCESS )
1386     {
1387         unsquash_guid(szValName, szProduct);
1388         TRACE("-> %s\n", debugstr_w(szProduct));
1389     }
1390     RegCloseKey(hkeyComp);
1391     return r;
1392 }
1393 
MsiEnumClientsExA(const char * component,const char * usersid,DWORD ctx,DWORD index,char installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,char * sid,DWORD * sid_len)1394 UINT WINAPI MsiEnumClientsExA( const char *component, const char *usersid, DWORD ctx, DWORD index,
1395                                char installed_product[GUID_SIZE], MSIINSTALLCONTEXT *installed_ctx, char *sid,
1396                                DWORD *sid_len )
1397 {
1398     FIXME( "%s, %s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_a(component), debugstr_a(usersid), ctx, index,
1399            installed_product, installed_ctx, sid, sid_len );
1400     return ERROR_ACCESS_DENIED;
1401 }
1402 
MsiEnumClientsExW(const WCHAR * component,const WCHAR * usersid,DWORD ctx,DWORD index,WCHAR installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,WCHAR * sid,DWORD * sid_len)1403 UINT WINAPI MsiEnumClientsExW( const WCHAR *component, const WCHAR *usersid, DWORD ctx, DWORD index,
1404                                WCHAR installed_product[GUID_SIZE], MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid,
1405                                DWORD *sid_len )
1406 {
1407     FIXME( "%s, %s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(component), debugstr_w(usersid), ctx, index,
1408            installed_product, installed_ctx, sid, sid_len );
1409     return ERROR_ACCESS_DENIED;
1410 }
1411 
MSI_EnumComponentQualifiers(const WCHAR * szComponent,DWORD iIndex,awstring * lpQualBuf,DWORD * pcchQual,awstring * lpAppBuf,DWORD * pcchAppBuf)1412 static UINT MSI_EnumComponentQualifiers( const WCHAR *szComponent, DWORD iIndex, awstring *lpQualBuf,
1413                                          DWORD *pcchQual, awstring *lpAppBuf, DWORD *pcchAppBuf )
1414 {
1415     DWORD name_sz, val_sz, name_max, val_max, type, ofs;
1416     WCHAR *name = NULL, *val = NULL;
1417     UINT r, r2;
1418     HKEY key;
1419 
1420     TRACE( "%s, %lu, %p, %p, %p, %p\n", debugstr_w(szComponent), iIndex, lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf );
1421 
1422     if (!szComponent)
1423         return ERROR_INVALID_PARAMETER;
1424 
1425     r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1426     if (r != ERROR_SUCCESS)
1427         return ERROR_UNKNOWN_COMPONENT;
1428 
1429     /* figure out how big the name is we want to return */
1430     name_max = 0x10;
1431     r = ERROR_OUTOFMEMORY;
1432     name = malloc( name_max * sizeof(WCHAR) );
1433     if (!name)
1434         goto end;
1435 
1436     val_max = 0x10;
1437     r = ERROR_OUTOFMEMORY;
1438     val = malloc( val_max );
1439     if (!val)
1440         goto end;
1441 
1442     /* loop until we allocate enough memory */
1443     while (1)
1444     {
1445         name_sz = name_max;
1446         val_sz = val_max;
1447         r = RegEnumValueW( key, iIndex, name, &name_sz, NULL, &type, (BYTE *)val, &val_sz );
1448         if (r == ERROR_SUCCESS)
1449             break;
1450         if (r != ERROR_MORE_DATA)
1451             goto end;
1452 
1453         if (type != REG_MULTI_SZ)
1454         {
1455             ERR( "component data has wrong type (%lu)\n", type );
1456             goto end;
1457         }
1458 
1459         r = ERROR_OUTOFMEMORY;
1460         if (name_sz + 1 >= name_max)
1461         {
1462             name_max *= 2;
1463             free( name );
1464             name = malloc( name_max * sizeof (WCHAR) );
1465             if (!name)
1466                 goto end;
1467             continue;
1468         }
1469         if (val_sz > val_max)
1470         {
1471             val_max = val_sz + sizeof (WCHAR);
1472             free( val );
1473             val = malloc( val_max * sizeof (WCHAR) );
1474             if (!val)
1475                 goto end;
1476             continue;
1477         }
1478         ERR( "should be enough data, but isn't %lu %lu\n", name_sz, val_sz );
1479         goto end;
1480     }
1481 
1482     ofs = 0;
1483     r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1484     if (r != ERROR_SUCCESS)
1485         goto end;
1486 
1487     TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1488 
1489     r = msi_strcpy_to_awstring( name, -1, lpQualBuf, pcchQual );
1490     r2 = msi_strcpy_to_awstring( val+ofs, -1, lpAppBuf, pcchAppBuf );
1491 
1492     if (r2 != ERROR_SUCCESS)
1493         r = r2;
1494 
1495 end:
1496     free(val);
1497     free(name);
1498     RegCloseKey(key);
1499     return r;
1500 }
1501 
1502 /*************************************************************************
1503  *  MsiEnumComponentQualifiersA [MSI.@]
1504  */
MsiEnumComponentQualifiersA(const char * szComponent,DWORD iIndex,char * lpQualifierBuf,DWORD * pcchQualifierBuf,char * lpApplicationDataBuf,DWORD * pcchApplicationDataBuf)1505 UINT WINAPI MsiEnumComponentQualifiersA( const char *szComponent, DWORD iIndex, char *lpQualifierBuf,
1506                                          DWORD *pcchQualifierBuf, char *lpApplicationDataBuf,
1507                                          DWORD *pcchApplicationDataBuf )
1508 {
1509     awstring qual, appdata;
1510     WCHAR *comp;
1511     UINT r;
1512 
1513     TRACE( "%s, %lu, %p, %p, %p, %p\n", debugstr_a(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf,
1514            lpApplicationDataBuf, pcchApplicationDataBuf );
1515 
1516     comp = strdupAtoW( szComponent );
1517     if (szComponent && !comp)
1518         return ERROR_OUTOFMEMORY;
1519 
1520     qual.unicode = FALSE;
1521     qual.str.a = lpQualifierBuf;
1522 
1523     appdata.unicode = FALSE;
1524     appdata.str.a = lpApplicationDataBuf;
1525 
1526     r = MSI_EnumComponentQualifiers( comp, iIndex,
1527               &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1528     free( comp );
1529     return r;
1530 }
1531 
1532 /*************************************************************************
1533  *  MsiEnumComponentQualifiersW [MSI.@]
1534  */
MsiEnumComponentQualifiersW(const WCHAR * szComponent,DWORD iIndex,WCHAR * lpQualifierBuf,DWORD * pcchQualifierBuf,WCHAR * lpApplicationDataBuf,DWORD * pcchApplicationDataBuf)1535 UINT WINAPI MsiEnumComponentQualifiersW( const WCHAR *szComponent, DWORD iIndex, WCHAR *lpQualifierBuf,
1536                                          DWORD *pcchQualifierBuf, WCHAR *lpApplicationDataBuf,
1537                                          DWORD *pcchApplicationDataBuf )
1538 {
1539     awstring qual, appdata;
1540 
1541     TRACE( "%s, %lu, %p, %p, %p, %p\n", debugstr_w(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf,
1542            lpApplicationDataBuf, pcchApplicationDataBuf );
1543 
1544     qual.unicode = TRUE;
1545     qual.str.w = lpQualifierBuf;
1546 
1547     appdata.unicode = TRUE;
1548     appdata.str.w = lpApplicationDataBuf;
1549 
1550     return MSI_EnumComponentQualifiers( szComponent, iIndex, &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1551 }
1552 
1553 /*************************************************************************
1554  *  MsiEnumRelatedProductsW   [MSI.@]
1555  *
1556  */
MsiEnumRelatedProductsW(const WCHAR * szUpgradeCode,DWORD dwReserved,DWORD iProductIndex,WCHAR * lpProductBuf)1557 UINT WINAPI MsiEnumRelatedProductsW( const WCHAR *szUpgradeCode, DWORD dwReserved, DWORD iProductIndex,
1558                                      WCHAR *lpProductBuf )
1559 {
1560     UINT r;
1561     HKEY hkey;
1562     WCHAR szKeyName[SQUASHED_GUID_SIZE];
1563     DWORD dwSize = ARRAY_SIZE(szKeyName);
1564 
1565     TRACE( "%s, %#lx, %lu, %p\n", debugstr_w(szUpgradeCode), dwReserved, iProductIndex, lpProductBuf );
1566 
1567     if (NULL == szUpgradeCode)
1568         return ERROR_INVALID_PARAMETER;
1569     if (NULL == lpProductBuf)
1570         return ERROR_INVALID_PARAMETER;
1571 
1572     r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1573     if (r != ERROR_SUCCESS)
1574         return ERROR_NO_MORE_ITEMS;
1575 
1576     r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1577     if( r == ERROR_SUCCESS )
1578         unsquash_guid(szKeyName, lpProductBuf);
1579     RegCloseKey(hkey);
1580 
1581     return r;
1582 }
1583 
1584 /*************************************************************************
1585  *  MsiEnumRelatedProductsA   [MSI.@]
1586  *
1587  */
MsiEnumRelatedProductsA(const char * szUpgradeCode,DWORD dwReserved,DWORD iProductIndex,char * lpProductBuf)1588 UINT WINAPI MsiEnumRelatedProductsA( const char *szUpgradeCode, DWORD dwReserved, DWORD iProductIndex,
1589                                      char *lpProductBuf )
1590 {
1591     WCHAR *szwUpgradeCode = NULL;
1592     WCHAR productW[GUID_SIZE];
1593     UINT r;
1594 
1595     TRACE( "%s, %#lx, %lu, %p\n", debugstr_a(szUpgradeCode), dwReserved, iProductIndex, lpProductBuf );
1596 
1597     if (szUpgradeCode)
1598     {
1599         szwUpgradeCode = strdupAtoW( szUpgradeCode );
1600         if( !szwUpgradeCode )
1601             return ERROR_OUTOFMEMORY;
1602     }
1603 
1604     r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1605                                  iProductIndex, productW );
1606     if (r == ERROR_SUCCESS)
1607     {
1608         WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1609                              lpProductBuf, GUID_SIZE, NULL, NULL );
1610     }
1611     free( szwUpgradeCode );
1612     return r;
1613 }
1614 
1615 /***********************************************************************
1616  * MsiEnumPatchesExA            [MSI.@]
1617  */
MsiEnumPatchesExA(const char * szProductCode,const char * szUserSid,DWORD dwContext,DWORD dwFilter,DWORD dwIndex,char * szPatchCode,char * szTargetProductCode,MSIINSTALLCONTEXT * pdwTargetProductContext,char * szTargetUserSid,DWORD * pcchTargetUserSid)1618 UINT WINAPI MsiEnumPatchesExA( const char *szProductCode, const char *szUserSid, DWORD dwContext, DWORD dwFilter,
1619                                DWORD dwIndex, char *szPatchCode, char *szTargetProductCode,
1620                                MSIINSTALLCONTEXT *pdwTargetProductContext, char *szTargetUserSid,
1621                                DWORD *pcchTargetUserSid )
1622 {
1623     WCHAR *prodcode = NULL, *usersid = NULL, *targsid = NULL;
1624     WCHAR patch[GUID_SIZE], targprod[GUID_SIZE];
1625     DWORD len;
1626     UINT r;
1627 
1628     TRACE( "%s, %s, %#lx, %lu, %lu, %p, %p, %p, %p, %p\n", debugstr_a(szProductCode), debugstr_a(szUserSid),
1629            dwContext, dwFilter, dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
1630            pcchTargetUserSid );
1631 
1632     if (szTargetUserSid && !pcchTargetUserSid)
1633         return ERROR_INVALID_PARAMETER;
1634 
1635     if (szProductCode) prodcode = strdupAtoW(szProductCode);
1636     if (szUserSid) usersid = strdupAtoW(szUserSid);
1637 
1638     r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1639                           patch, targprod, pdwTargetProductContext,
1640                           NULL, &len);
1641     if (r != ERROR_SUCCESS)
1642         goto done;
1643 
1644     WideCharToMultiByte(CP_ACP, 0, patch, -1, szPatchCode,
1645                         GUID_SIZE, NULL, NULL);
1646     WideCharToMultiByte(CP_ACP, 0, targprod, -1, szTargetProductCode,
1647                         GUID_SIZE, NULL, NULL);
1648 
1649     if (!szTargetUserSid)
1650     {
1651         if (pcchTargetUserSid)
1652             *pcchTargetUserSid = len;
1653 
1654         goto done;
1655     }
1656 
1657     targsid = malloc(++len * sizeof(WCHAR));
1658     if (!targsid)
1659     {
1660         r = ERROR_OUTOFMEMORY;
1661         goto done;
1662     }
1663 
1664     r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1665                           patch, targprod, pdwTargetProductContext,
1666                           targsid, &len);
1667     if (r != ERROR_SUCCESS || !szTargetUserSid)
1668         goto done;
1669 
1670     WideCharToMultiByte(CP_ACP, 0, targsid, -1, szTargetUserSid,
1671                         *pcchTargetUserSid, NULL, NULL);
1672 
1673     len = lstrlenW(targsid);
1674     if (*pcchTargetUserSid < len + 1)
1675     {
1676         r = ERROR_MORE_DATA;
1677         *pcchTargetUserSid = len * sizeof(WCHAR);
1678     }
1679     else
1680         *pcchTargetUserSid = len;
1681 
1682 done:
1683     free(prodcode);
1684     free(usersid);
1685     free(targsid);
1686 
1687     return r;
1688 }
1689 
get_patch_state(const WCHAR * prodcode,const WCHAR * usersid,MSIINSTALLCONTEXT context,WCHAR * patch,MSIPATCHSTATE * state)1690 static UINT get_patch_state(const WCHAR *prodcode, const WCHAR *usersid, MSIINSTALLCONTEXT context,
1691                             WCHAR *patch, MSIPATCHSTATE *state)
1692 {
1693     DWORD type, val, size;
1694     HKEY prod, hkey = 0;
1695     HKEY udpatch = 0;
1696     LONG res;
1697     UINT r = ERROR_NO_MORE_ITEMS;
1698 
1699     *state = MSIPATCHSTATE_INVALID;
1700 
1701     r = MSIREG_OpenUserDataProductKey(prodcode, context,
1702                                       usersid, &prod, FALSE);
1703     if (r != ERROR_SUCCESS)
1704         return ERROR_NO_MORE_ITEMS;
1705 
1706     res = RegOpenKeyExW(prod, L"Patches", 0, KEY_READ, &hkey);
1707     if (res != ERROR_SUCCESS)
1708         goto done;
1709 
1710     res = RegOpenKeyExW(hkey, patch, 0, KEY_READ, &udpatch);
1711     if (res != ERROR_SUCCESS)
1712         goto done;
1713 
1714     size = sizeof(DWORD);
1715     res = RegGetValueW(udpatch, NULL, L"State", RRF_RT_DWORD, &type, &val, &size);
1716     if (res != ERROR_SUCCESS ||
1717         val < MSIPATCHSTATE_APPLIED || val > MSIPATCHSTATE_REGISTERED)
1718     {
1719         r = ERROR_BAD_CONFIGURATION;
1720         goto done;
1721     }
1722 
1723     *state = val;
1724     r = ERROR_SUCCESS;
1725 
1726 done:
1727     RegCloseKey(udpatch);
1728     RegCloseKey(hkey);
1729     RegCloseKey(prod);
1730 
1731     return r;
1732 }
1733 
check_product_patches(const WCHAR * prodcode,const WCHAR * usersid,MSIINSTALLCONTEXT context,DWORD filter,DWORD index,DWORD * idx,WCHAR * patch,WCHAR * targetprod,MSIINSTALLCONTEXT * targetctx,WCHAR * targetsid,DWORD * sidsize,WCHAR ** transforms)1734 static UINT check_product_patches(const WCHAR *prodcode, const WCHAR *usersid, MSIINSTALLCONTEXT context,
1735                                   DWORD filter, DWORD index, DWORD *idx, WCHAR *patch, WCHAR *targetprod,
1736                                   MSIINSTALLCONTEXT *targetctx, WCHAR *targetsid, DWORD *sidsize, WCHAR **transforms)
1737 {
1738     MSIPATCHSTATE state = MSIPATCHSTATE_INVALID;
1739     LPWSTR ptr, patches = NULL;
1740     HKEY prod, patchkey = 0;
1741     HKEY localprod = 0, localpatch = 0;
1742     DWORD type, size;
1743     LONG res;
1744     UINT temp, r = ERROR_NO_MORE_ITEMS;
1745 
1746     if (MSIREG_OpenProductKey(prodcode, usersid, context,
1747                               &prod, FALSE) != ERROR_SUCCESS)
1748         return ERROR_NO_MORE_ITEMS;
1749 
1750     size = 0;
1751     res = RegGetValueW(prod, L"Patches", L"Patches", RRF_RT_ANY, &type, NULL,
1752                        &size);
1753     if (res != ERROR_SUCCESS)
1754         goto done;
1755 
1756     if (type != REG_MULTI_SZ)
1757     {
1758         r = ERROR_BAD_CONFIGURATION;
1759         goto done;
1760     }
1761 
1762     patches = malloc(size);
1763     if (!patches)
1764     {
1765         r = ERROR_OUTOFMEMORY;
1766         goto done;
1767     }
1768 
1769     res = RegGetValueW(prod, L"Patches", L"Patches", RRF_RT_ANY, &type,
1770                        patches, &size);
1771     if (res != ERROR_SUCCESS)
1772         goto done;
1773 
1774     for (ptr = patches; *ptr && r == ERROR_NO_MORE_ITEMS; ptr += lstrlenW(ptr) + 1)
1775     {
1776         if (!unsquash_guid(ptr, patch))
1777         {
1778             r = ERROR_BAD_CONFIGURATION;
1779             goto done;
1780         }
1781 
1782         size = 0;
1783         res = RegGetValueW(prod, L"Patches", ptr, RRF_RT_REG_SZ,
1784                            &type, NULL, &size);
1785         if (res != ERROR_SUCCESS)
1786             continue;
1787 
1788         if (transforms)
1789         {
1790             *transforms = malloc(size);
1791             if (!*transforms)
1792             {
1793                 r = ERROR_OUTOFMEMORY;
1794                 goto done;
1795             }
1796 
1797             res = RegGetValueW(prod, L"Patches", ptr, RRF_RT_REG_SZ,
1798                                &type, *transforms, &size);
1799             if (res != ERROR_SUCCESS)
1800                 continue;
1801         }
1802 
1803         if (context == MSIINSTALLCONTEXT_USERMANAGED)
1804         {
1805             if (!(filter & MSIPATCHSTATE_APPLIED))
1806             {
1807                 temp = get_patch_state(prodcode, usersid, context, ptr, &state);
1808                 if (temp == ERROR_BAD_CONFIGURATION)
1809                 {
1810                     r = ERROR_BAD_CONFIGURATION;
1811                     goto done;
1812                 }
1813 
1814                 if (temp != ERROR_SUCCESS || !(filter & state))
1815                     continue;
1816             }
1817         }
1818         else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
1819         {
1820             if (!(filter & MSIPATCHSTATE_APPLIED))
1821             {
1822                 temp = get_patch_state(prodcode, usersid, context, ptr, &state);
1823                 if (temp == ERROR_BAD_CONFIGURATION)
1824                 {
1825                     r = ERROR_BAD_CONFIGURATION;
1826                     goto done;
1827                 }
1828 
1829                 if (temp != ERROR_SUCCESS || !(filter & state))
1830                     continue;
1831             }
1832             else
1833             {
1834                 temp = MSIREG_OpenUserDataPatchKey(patch, context,
1835                                                    &patchkey, FALSE);
1836                 RegCloseKey(patchkey);
1837                 if (temp != ERROR_SUCCESS)
1838                     continue;
1839             }
1840         }
1841         else if (context == MSIINSTALLCONTEXT_MACHINE)
1842         {
1843             usersid = L"";
1844 
1845             if (MSIREG_OpenUserDataProductKey(prodcode, context, NULL, &localprod, FALSE) == ERROR_SUCCESS &&
1846                 RegOpenKeyExW(localprod, L"Patches", 0, KEY_READ, &localpatch) == ERROR_SUCCESS &&
1847                 RegOpenKeyExW(localpatch, ptr, 0, KEY_READ, &patchkey) == ERROR_SUCCESS)
1848             {
1849                 res = RegGetValueW(patchkey, NULL, L"State", RRF_RT_REG_DWORD,
1850                                    &type, &state, &size);
1851 
1852                 if (!(filter & state))
1853                     res = ERROR_NO_MORE_ITEMS;
1854 
1855                 RegCloseKey(patchkey);
1856             }
1857 
1858             RegCloseKey(localpatch);
1859             RegCloseKey(localprod);
1860 
1861             if (res != ERROR_SUCCESS)
1862                 continue;
1863         }
1864 
1865         if (*idx < index)
1866         {
1867             (*idx)++;
1868             continue;
1869         }
1870 
1871         r = ERROR_SUCCESS;
1872         if (targetprod)
1873             lstrcpyW(targetprod, prodcode);
1874 
1875         if (targetctx)
1876             *targetctx = context;
1877 
1878         if (targetsid)
1879         {
1880             lstrcpynW(targetsid, usersid, *sidsize);
1881             if (lstrlenW(usersid) >= *sidsize)
1882                 r = ERROR_MORE_DATA;
1883         }
1884 
1885         if (sidsize)
1886         {
1887             *sidsize = lstrlenW(usersid);
1888             if (!targetsid)
1889                 *sidsize *= sizeof(WCHAR);
1890         }
1891     }
1892 
1893 done:
1894     RegCloseKey(prod);
1895     free(patches);
1896 
1897     return r;
1898 }
1899 
enum_patches(const WCHAR * szProductCode,const WCHAR * szUserSid,DWORD dwContext,DWORD dwFilter,DWORD dwIndex,DWORD * idx,WCHAR * szPatchCode,WCHAR * szTargetProductCode,MSIINSTALLCONTEXT * pdwTargetProductContext,WCHAR * szTargetUserSid,DWORD * pcchTargetUserSid,WCHAR ** szTransforms)1900 static UINT enum_patches(const WCHAR *szProductCode, const WCHAR *szUserSid, DWORD dwContext, DWORD dwFilter,
1901                          DWORD dwIndex, DWORD *idx, WCHAR *szPatchCode, WCHAR *szTargetProductCode,
1902                          MSIINSTALLCONTEXT *pdwTargetProductContext, WCHAR *szTargetUserSid, DWORD *pcchTargetUserSid,
1903                          WCHAR **szTransforms)
1904 {
1905     LPWSTR usersid = NULL;
1906     UINT r = ERROR_INVALID_PARAMETER;
1907 
1908     if (!szUserSid)
1909     {
1910         szUserSid = usersid = get_user_sid();
1911         if (!usersid) return ERROR_FUNCTION_FAILED;
1912     }
1913 
1914     if (dwContext & MSIINSTALLCONTEXT_USERMANAGED)
1915     {
1916         r = check_product_patches(szProductCode, szUserSid, MSIINSTALLCONTEXT_USERMANAGED, dwFilter, dwIndex, idx,
1917                                   szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
1918                                   pcchTargetUserSid, szTransforms);
1919         if (r != ERROR_NO_MORE_ITEMS)
1920             goto done;
1921     }
1922 
1923     if (dwContext & MSIINSTALLCONTEXT_USERUNMANAGED)
1924     {
1925         r = check_product_patches(szProductCode, szUserSid, MSIINSTALLCONTEXT_USERUNMANAGED, dwFilter, dwIndex, idx,
1926                                   szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
1927                                   pcchTargetUserSid, szTransforms);
1928         if (r != ERROR_NO_MORE_ITEMS)
1929             goto done;
1930     }
1931 
1932     if (dwContext & MSIINSTALLCONTEXT_MACHINE)
1933     {
1934         r = check_product_patches(szProductCode, szUserSid, MSIINSTALLCONTEXT_MACHINE, dwFilter, dwIndex, idx,
1935                                   szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
1936                                   pcchTargetUserSid, szTransforms);
1937         if (r != ERROR_NO_MORE_ITEMS)
1938             goto done;
1939     }
1940 
1941 done:
1942     LocalFree(usersid);
1943     return r;
1944 }
1945 
1946 /***********************************************************************
1947  * MsiEnumPatchesExW            [MSI.@]
1948  */
MsiEnumPatchesExW(const WCHAR * szProductCode,const WCHAR * szUserSid,DWORD dwContext,DWORD dwFilter,DWORD dwIndex,WCHAR * szPatchCode,WCHAR * szTargetProductCode,MSIINSTALLCONTEXT * pdwTargetProductContext,WCHAR * szTargetUserSid,DWORD * pcchTargetUserSid)1949 UINT WINAPI MsiEnumPatchesExW( const WCHAR *szProductCode, const WCHAR *szUserSid, DWORD dwContext, DWORD dwFilter,
1950                                DWORD dwIndex, WCHAR *szPatchCode, WCHAR *szTargetProductCode,
1951                                MSIINSTALLCONTEXT *pdwTargetProductContext, WCHAR *szTargetUserSid,
1952                                DWORD *pcchTargetUserSid )
1953 {
1954     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
1955     DWORD idx = 0;
1956     UINT r;
1957 
1958     static DWORD last_index;
1959 
1960     TRACE( "%s, %s, %#lx, %lu, %lu, %p, %p, %p, %p, %p)\n", debugstr_w(szProductCode), debugstr_w(szUserSid),
1961            dwContext, dwFilter, dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
1962            pcchTargetUserSid );
1963 
1964     if (!szProductCode || !squash_guid( szProductCode, squashed_pc ))
1965         return ERROR_INVALID_PARAMETER;
1966 
1967     if (szUserSid && !wcscmp( szUserSid, L"S-1-5-18" ))
1968         return ERROR_INVALID_PARAMETER;
1969 
1970     if (dwContext & MSIINSTALLCONTEXT_MACHINE && szUserSid)
1971         return ERROR_INVALID_PARAMETER;
1972 
1973     if (dwContext <= MSIINSTALLCONTEXT_NONE ||
1974         dwContext > MSIINSTALLCONTEXT_ALL)
1975         return ERROR_INVALID_PARAMETER;
1976 
1977     if (dwFilter <= MSIPATCHSTATE_INVALID || dwFilter > MSIPATCHSTATE_ALL)
1978         return ERROR_INVALID_PARAMETER;
1979 
1980     if (dwIndex && dwIndex - last_index != 1)
1981         return ERROR_INVALID_PARAMETER;
1982 
1983     if (dwIndex == 0)
1984         last_index = 0;
1985 
1986     r = enum_patches(szProductCode, szUserSid, dwContext, dwFilter, dwIndex, &idx, szPatchCode, szTargetProductCode,
1987                      pdwTargetProductContext, szTargetUserSid, pcchTargetUserSid, NULL);
1988 
1989     if (r == ERROR_SUCCESS)
1990         last_index = dwIndex;
1991     else
1992         last_index = 0;
1993 
1994     return r;
1995 }
1996 
1997 /***********************************************************************
1998  * MsiEnumPatchesA            [MSI.@]
1999  */
MsiEnumPatchesA(const char * szProduct,DWORD iPatchIndex,char * lpPatchBuf,char * lpTransformsBuf,DWORD * pcchTransformsBuf)2000 UINT WINAPI MsiEnumPatchesA( const char *szProduct, DWORD iPatchIndex, char *lpPatchBuf, char *lpTransformsBuf,
2001                              DWORD *pcchTransformsBuf )
2002 {
2003     WCHAR *product, *transforms, patch[GUID_SIZE];
2004     DWORD len;
2005     UINT r;
2006 
2007     TRACE( "%s, %lu, %p, %p, %p\n", debugstr_a(szProduct), iPatchIndex, lpPatchBuf, lpTransformsBuf,
2008            pcchTransformsBuf );
2009 
2010     if (!szProduct || !lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2011         return ERROR_INVALID_PARAMETER;
2012 
2013     product = strdupAtoW(szProduct);
2014     if (!product)
2015         return ERROR_OUTOFMEMORY;
2016 
2017     len = *pcchTransformsBuf;
2018     transforms = malloc(len * sizeof(WCHAR));
2019     if (!transforms)
2020     {
2021         r = ERROR_OUTOFMEMORY;
2022         goto done;
2023     }
2024 
2025     r = MsiEnumPatchesW(product, iPatchIndex, patch, transforms, &len);
2026     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2027         goto done;
2028 
2029     WideCharToMultiByte(CP_ACP, 0, patch, -1, lpPatchBuf,
2030                         GUID_SIZE, NULL, NULL);
2031 
2032     if (!WideCharToMultiByte(CP_ACP, 0, transforms, -1, lpTransformsBuf,
2033                              *pcchTransformsBuf, NULL, NULL))
2034         r = ERROR_MORE_DATA;
2035 
2036     if (r == ERROR_MORE_DATA)
2037     {
2038         lpTransformsBuf[*pcchTransformsBuf - 1] = '\0';
2039         *pcchTransformsBuf = len * 2;
2040     }
2041     else
2042         *pcchTransformsBuf = strlen( lpTransformsBuf );
2043 
2044 done:
2045     free(transforms);
2046     free(product);
2047 
2048     return r;
2049 }
2050 
2051 /***********************************************************************
2052  * MsiEnumPatchesW            [MSI.@]
2053  */
MsiEnumPatchesW(const WCHAR * szProduct,DWORD iPatchIndex,WCHAR * lpPatchBuf,WCHAR * lpTransformsBuf,DWORD * pcchTransformsBuf)2054 UINT WINAPI MsiEnumPatchesW( const WCHAR *szProduct, DWORD iPatchIndex, WCHAR *lpPatchBuf, WCHAR *lpTransformsBuf,
2055                              DWORD *pcchTransformsBuf )
2056 {
2057     WCHAR *transforms = NULL, squashed_pc[SQUASHED_GUID_SIZE];
2058     HKEY prod;
2059     DWORD idx = 0;
2060     UINT r;
2061 
2062     TRACE( "%s, %lu, %p, %p, %p)\n", debugstr_w(szProduct), iPatchIndex, lpPatchBuf, lpTransformsBuf,
2063            pcchTransformsBuf );
2064 
2065     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
2066         return ERROR_INVALID_PARAMETER;
2067 
2068     if (!lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2069         return ERROR_INVALID_PARAMETER;
2070 
2071     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2072                               &prod, FALSE) != ERROR_SUCCESS &&
2073         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2074                               &prod, FALSE) != ERROR_SUCCESS &&
2075         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2076                               &prod, FALSE) != ERROR_SUCCESS)
2077         return ERROR_UNKNOWN_PRODUCT;
2078 
2079     RegCloseKey(prod);
2080 
2081     r = enum_patches(szProduct, NULL, MSIINSTALLCONTEXT_ALL, MSIPATCHSTATE_ALL, iPatchIndex, &idx, lpPatchBuf, NULL,
2082                      NULL, NULL, NULL, &transforms);
2083     if (r != ERROR_SUCCESS)
2084         goto done;
2085 
2086     lstrcpynW(lpTransformsBuf, transforms, *pcchTransformsBuf);
2087     if (*pcchTransformsBuf <= lstrlenW(transforms))
2088     {
2089         r = ERROR_MORE_DATA;
2090         *pcchTransformsBuf = lstrlenW(transforms);
2091     }
2092     else
2093         *pcchTransformsBuf = lstrlenW(transforms);
2094 
2095 done:
2096     free(transforms);
2097     return r;
2098 }
2099 
MsiEnumProductsExA(const char * product,const char * usersid,DWORD ctx,DWORD index,char installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,char * sid,DWORD * sid_len)2100 UINT WINAPI MsiEnumProductsExA( const char *product, const char *usersid, DWORD ctx, DWORD index,
2101                                 char installed_product[GUID_SIZE], MSIINSTALLCONTEXT *installed_ctx, char *sid,
2102                                 DWORD *sid_len )
2103 {
2104     UINT r;
2105     WCHAR installed_productW[GUID_SIZE], *productW = NULL, *usersidW = NULL, *sidW = NULL;
2106 
2107     TRACE( "%s, %s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_a(product), debugstr_a(usersid), ctx, index,
2108            installed_product, installed_ctx, sid, sid_len );
2109 
2110     if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
2111     if (product && !(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
2112     if (usersid && !(usersidW = strdupAtoW( usersid )))
2113     {
2114         free( productW );
2115         return ERROR_OUTOFMEMORY;
2116     }
2117     if (sid && !(sidW = malloc( *sid_len * sizeof(WCHAR) )))
2118     {
2119         free( usersidW );
2120         free( productW );
2121         return ERROR_OUTOFMEMORY;
2122     }
2123     r = MsiEnumProductsExW( productW, usersidW, ctx, index, installed_productW,
2124                             installed_ctx, sidW, sid_len );
2125     if (r == ERROR_SUCCESS)
2126     {
2127         if (installed_product) WideCharToMultiByte( CP_ACP, 0, installed_productW, GUID_SIZE,
2128                                                     installed_product, GUID_SIZE, NULL, NULL );
2129         if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
2130     }
2131     free( productW );
2132     free( usersidW );
2133     free( sidW );
2134     return r;
2135 }
2136 
fetch_machine_product(const WCHAR * match,DWORD index,DWORD * idx,WCHAR installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,WCHAR * sid,DWORD * sid_len)2137 static UINT fetch_machine_product( const WCHAR *match, DWORD index, DWORD *idx,
2138                                    WCHAR installed_product[GUID_SIZE],
2139                                    MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2140 {
2141     UINT r;
2142     WCHAR product[SQUASHED_GUID_SIZE];
2143     DWORD i = 0, len;
2144     REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
2145     HKEY key;
2146 
2147     if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Classes\\Installer\\Products", 0, access, &key ))
2148         return ERROR_NO_MORE_ITEMS;
2149 
2150     len = ARRAY_SIZE( product );
2151     while (!RegEnumKeyExW( key, i, product, &len, NULL, NULL, NULL, NULL ))
2152     {
2153         if (match && wcscmp( match, product ))
2154         {
2155             i++;
2156             len = ARRAY_SIZE( product );
2157             continue;
2158         }
2159         if (*idx == index) goto found;
2160         (*idx)++;
2161         len = ARRAY_SIZE( product );
2162         i++;
2163     }
2164     RegCloseKey( key );
2165     return ERROR_NO_MORE_ITEMS;
2166 
2167 found:
2168     if (sid_len && *sid_len < 1)
2169     {
2170         *sid_len = 1;
2171         r = ERROR_MORE_DATA;
2172     }
2173     else
2174     {
2175         if (installed_product) unsquash_guid( product, installed_product );
2176         if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
2177         if (sid)
2178         {
2179             sid[0] = 0;
2180             *sid_len = 0;
2181         }
2182         r = ERROR_SUCCESS;
2183     }
2184     RegCloseKey( key );
2185     return r;
2186 }
2187 
fetch_user_product(const WCHAR * match,const WCHAR * usersid,DWORD ctx,DWORD index,DWORD * idx,WCHAR installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,WCHAR * sid,DWORD * sid_len)2188 static UINT fetch_user_product( const WCHAR *match, const WCHAR *usersid, DWORD ctx, DWORD index,
2189                                 DWORD *idx, WCHAR installed_product[GUID_SIZE],
2190                                 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2191 {
2192     UINT r;
2193     const WCHAR *subkey;
2194     WCHAR path[MAX_PATH], product[SQUASHED_GUID_SIZE], user[128];
2195     DWORD i = 0, j = 0, len_product, len_user;
2196     REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
2197     HKEY key_users, key_products;
2198 
2199     if (ctx == MSIINSTALLCONTEXT_USERMANAGED)
2200     {
2201         subkey = L"\\Installer\\Products";
2202         if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed",
2203                            0, access, &key_users )) return ERROR_NO_MORE_ITEMS;
2204     }
2205     else if (ctx == MSIINSTALLCONTEXT_USERUNMANAGED)
2206     {
2207         subkey = L"\\Software\\Microsoft\\Installer\\Products";
2208         if (RegOpenKeyExW( HKEY_USERS, NULL, 0, access, &key_users ))
2209             return ERROR_NO_MORE_ITEMS;
2210     }
2211     else return ERROR_INVALID_PARAMETER;
2212 
2213     len_user = ARRAY_SIZE( user );
2214     while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
2215     {
2216         if (wcscmp( usersid, user ) && wcscmp( usersid, L"S-1-1-0" ))
2217         {
2218             i++;
2219             len_user = ARRAY_SIZE( user );
2220             continue;
2221         }
2222         lstrcpyW( path, user );
2223         lstrcatW( path, subkey );
2224         if (RegOpenKeyExW( key_users, path, 0, access, &key_products ))
2225         {
2226             i++;
2227             len_user = ARRAY_SIZE( user );
2228             continue;
2229         }
2230         len_product = ARRAY_SIZE( product );
2231         while (!RegEnumKeyExW( key_products, j, product, &len_product, NULL, NULL, NULL, NULL ))
2232         {
2233             if (match && wcscmp( match, product ))
2234             {
2235                 j++;
2236                 len_product = ARRAY_SIZE( product );
2237                 continue;
2238             }
2239             if (*idx == index) goto found;
2240             (*idx)++;
2241             len_product = ARRAY_SIZE( product );
2242             j++;
2243         }
2244         RegCloseKey( key_products );
2245         len_user = ARRAY_SIZE( user );
2246         i++;
2247     }
2248     RegCloseKey( key_users );
2249     return ERROR_NO_MORE_ITEMS;
2250 
2251 found:
2252     if (sid_len && *sid_len <= len_user)
2253     {
2254         *sid_len = len_user;
2255         r = ERROR_MORE_DATA;
2256     }
2257     else
2258     {
2259         if (installed_product) unsquash_guid( product, installed_product );
2260         if (installed_ctx) *installed_ctx = ctx;
2261         if (sid)
2262         {
2263             lstrcpyW( sid, user );
2264             *sid_len = len_user;
2265         }
2266         r = ERROR_SUCCESS;
2267     }
2268     RegCloseKey( key_products );
2269     RegCloseKey( key_users );
2270     return r;
2271 }
2272 
enum_products(const WCHAR * product,const WCHAR * usersid,DWORD ctx,DWORD index,DWORD * idx,WCHAR installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,WCHAR * sid,DWORD * sid_len)2273 static UINT enum_products( const WCHAR *product, const WCHAR *usersid, DWORD ctx, DWORD index,
2274                            DWORD *idx, WCHAR installed_product[GUID_SIZE],
2275                            MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2276 {
2277     UINT r = ERROR_NO_MORE_ITEMS;
2278     WCHAR *user = NULL;
2279 
2280     if (!usersid)
2281     {
2282         usersid = user = get_user_sid();
2283         if (!user) return ERROR_FUNCTION_FAILED;
2284     }
2285     if (ctx & MSIINSTALLCONTEXT_MACHINE)
2286     {
2287         r = fetch_machine_product( product, index, idx, installed_product, installed_ctx,
2288                                    sid, sid_len );
2289         if (r != ERROR_NO_MORE_ITEMS) goto done;
2290     }
2291     if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
2292     {
2293         r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index,
2294                                 idx, installed_product, installed_ctx, sid, sid_len );
2295         if (r != ERROR_NO_MORE_ITEMS) goto done;
2296     }
2297     if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
2298     {
2299         r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERMANAGED, index,
2300                                 idx, installed_product, installed_ctx, sid, sid_len );
2301         if (r != ERROR_NO_MORE_ITEMS) goto done;
2302     }
2303 
2304 done:
2305     LocalFree( user );
2306     return r;
2307 }
2308 
MsiEnumProductsExW(const WCHAR * product,const WCHAR * usersid,DWORD ctx,DWORD index,WCHAR installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,WCHAR * sid,DWORD * sid_len)2309 UINT WINAPI MsiEnumProductsExW( const WCHAR *product, const WCHAR *usersid, DWORD ctx, DWORD index,
2310                                 WCHAR installed_product[GUID_SIZE], MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid,
2311                                 DWORD *sid_len )
2312 {
2313     UINT r;
2314     DWORD idx = 0;
2315     static DWORD last_index;
2316 
2317     TRACE( "%s, %s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(product), debugstr_w(usersid), ctx, index,
2318            installed_product, installed_ctx, sid, sid_len );
2319 
2320     if ((sid && !sid_len) || !ctx || (usersid && ctx == MSIINSTALLCONTEXT_MACHINE))
2321         return ERROR_INVALID_PARAMETER;
2322 
2323     if (index && index - last_index != 1)
2324         return ERROR_INVALID_PARAMETER;
2325 
2326     if (!index) last_index = 0;
2327 
2328     r = enum_products( product, usersid, ctx, index, &idx, installed_product, installed_ctx,
2329                        sid, sid_len );
2330     if (r == ERROR_SUCCESS)
2331         last_index = index;
2332     else
2333         last_index = 0;
2334 
2335     return r;
2336 }
2337