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