include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / msi / registry.c
blobad220eaa7566a03d27f5d73f80bba81b1a7c37e7
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2005 Mike McCormack for CodeWeavers
5 * Copyright 2005 Aric Stewart for CodeWeavers
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.
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.
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
22 #include <stdarg.h>
24 #define COBJMACROS
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"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41 BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
43 DWORD i,n=0;
45 if (lstrlenW(in) != 32)
46 return FALSE;
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++)
60 out[n++] = in[17+i*2];
61 out[n++] = in[16+i*2];
63 out[n++]='-';
64 for( ; i<8; i++)
66 out[n++] = in[17+i*2];
67 out[n++] = in[16+i*2];
69 out[n++]='}';
70 out[n]=0;
71 return TRUE;
74 BOOL squash_guid(LPCWSTR in, LPWSTR out)
76 DWORD i,n=1;
77 GUID guid;
79 out[0] = 0;
81 if (FAILED(CLSIDFromString((LPCOLESTR)in, &guid)))
82 return FALSE;
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++)
95 out[17+i*2] = in[n++];
96 out[16+i*2] = in[n++];
98 n++;
99 for( ; i<8; i++)
101 out[17+i*2] = in[n++];
102 out[16+i*2] = in[n++];
104 out[32]=0;
105 return TRUE;
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,
121 static const char table_enc85[] =
122 "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
123 "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
124 "yz{}~";
127 * Converts a base85 encoded guid into a GUID pointer
128 * Base85 encoded GUIDs should be 20 characters long.
130 * returns TRUE if successful, FALSE if not
132 BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
134 DWORD i, val = 0, base = 1, *p;
136 if (!str)
137 return FALSE;
139 p = (DWORD*) guid;
140 for( i=0; i<20; i++ )
142 if( (i%5) == 0 )
144 val = 0;
145 base = 1;
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;
156 return TRUE;
160 * Encodes a base85 guid given a GUID pointer
161 * Caller should provide a 21 character buffer for the encoded string.
163 * returns TRUE if successful, FALSE if not
165 BOOL encode_base85_guid( GUID *guid, LPWSTR str )
167 unsigned int x, *p, i;
169 p = (unsigned int*) guid;
170 for( i=0; i<4; i++ )
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];
183 *str = 0;
185 return TRUE;
188 DWORD msi_version_str_to_dword(LPCWSTR p)
190 DWORD major, minor = 0, build = 0, version = 0;
192 if (!p)
193 return version;
195 major = wcstol(p, NULL, 10);
197 p = wcschr(p, '.');
198 if (p)
200 minor = wcstol(p+1, NULL, 10);
201 p = wcschr(p+1, '.');
202 if (p)
203 build = wcstol(p+1, NULL, 10);
206 return MAKELONG(build, MAKEWORD(minor, major));
209 LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
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 );
217 LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
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) );
225 LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
227 return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
230 LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
232 HKEY hsubkey = 0;
233 LONG r;
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;
243 LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name )
245 DWORD len = 0;
246 LPWSTR val;
247 LONG r;
249 r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len);
250 if (r != ERROR_SUCCESS)
251 return NULL;
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;
262 BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val)
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;
269 static WCHAR *get_user_sid(void)
271 HANDLE token;
272 DWORD size = 256;
273 TOKEN_USER *user;
274 WCHAR *ret;
276 if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token )) return NULL;
277 if (!(user = malloc( size )))
279 CloseHandle( token );
280 return NULL;
282 if (!GetTokenInformation( token, TokenUser, user, size, &size ))
284 free( user );
285 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || !(user = malloc( size )))
287 CloseHandle( token );
288 return NULL;
290 GetTokenInformation( token, TokenUser, user, size, &size );
292 CloseHandle( token );
293 if (!ConvertSidToStringSidW( user->User.Sid, &ret ))
295 free( user );
296 return NULL;
298 free( user );
299 return ret;
302 UINT MSIREG_OpenUninstallKey(const WCHAR *product, enum platform platform, HKEY *key, BOOL create)
304 REGSAM access = KEY_ALL_ACCESS;
305 WCHAR keypath[0x200];
307 TRACE("%s\n", debugstr_w(product));
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);
319 UINT MSIREG_DeleteUninstallKey(const WCHAR *product, enum platform platform)
321 REGSAM access = KEY_ALL_ACCESS;
322 HKEY parent;
323 LONG r;
325 TRACE("%s\n", debugstr_w(product));
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;
338 UINT MSIREG_OpenProductKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
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];
344 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
345 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
347 if (context == MSIINSTALLCONTEXT_MACHINE)
349 lstrcpyW(keypath, L"Software\\Classes\\Installer\\Products\\");
350 lstrcatW( keypath, squashed_pc );
352 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
354 root = HKEY_CURRENT_USER;
355 lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Products\\" );
356 lstrcatW( keypath, squashed_pc );
358 else
360 if (!szUserSid)
362 if (!(usersid = get_user_sid()))
364 ERR("Failed to retrieve user SID\n");
365 return ERROR_FUNCTION_FAILED;
367 szUserSid = usersid;
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);
374 if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL);
375 return RegOpenKeyExW(root, keypath, 0, access, key);
378 UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
380 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
382 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
383 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
385 lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Products\\" );
386 lstrcatW( keypath, squashed_pc );
387 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
390 UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
392 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
394 if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED;
395 TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc));
397 lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Patches\\" );
398 lstrcatW( keypath, squashed_pc );
400 if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
401 return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
404 UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context,
405 HKEY *key, BOOL create)
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;
411 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
412 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
414 if (context == MSIINSTALLCONTEXT_MACHINE)
416 lstrcpyW(keypath, L"Software\\Classes\\Installer\\Features\\");
417 lstrcatW( keypath, squashed_pc );
419 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
421 root = HKEY_CURRENT_USER;
422 lstrcpyW(keypath, L"Software\\Microsoft\\Installer\\Features\\");
423 lstrcatW( keypath, squashed_pc );
425 else
427 if (!szUserSid)
429 if (!(usersid = get_user_sid()))
431 ERR("Failed to retrieve user SID\n");
432 return ERROR_FUNCTION_FAILED;
434 szUserSid = usersid;
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);
441 if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL);
442 return RegOpenKeyExW(root, keypath, 0, access, key);
445 UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
447 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
449 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
450 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
452 lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Features\\" );
453 lstrcatW( keypath, squashed_pc );
454 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
457 static UINT MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
459 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
460 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
462 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
463 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
465 lstrcpyW(keypath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Features\\");
466 lstrcatW( keypath, squashed_pc );
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);
472 UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context,
473 HKEY *key, BOOL create)
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;
480 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
481 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
483 if (context == MSIINSTALLCONTEXT_MACHINE)
485 swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_pc );
487 else
489 if (!szUserSid)
491 if (!(usersid = get_user_sid()))
493 ERR("Failed to retrieve user SID\n");
494 return ERROR_FUNCTION_FAILED;
496 szUserSid = usersid;
498 swprintf( keypath, ARRAY_SIZE(keypath), fmtW, szUserSid, squashed_pc );
499 LocalFree(usersid);
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);
505 UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY *key, BOOL create)
507 WCHAR squashed_cc[SQUASHED_GUID_SIZE], keypath[0x200];
508 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
509 UINT ret;
511 if (!squash_guid( szComponent, squashed_cc)) return ERROR_FUNCTION_FAILED;
512 TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_cc));
514 lstrcpyW(keypath, L"Software\\Microsoft\\Installer\\Components\\");
515 lstrcatW( keypath, squashed_cc );
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;
521 lstrcpyW(keypath, L"Software\\Classes\\Installer\\Components\\");
522 lstrcatW( keypath, squashed_cc );
523 return RegOpenKeyExW( HKEY_LOCAL_MACHINE, keypath, 0, access, key );
526 UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid, HKEY *key, BOOL create)
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];
533 if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED;
534 TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp));
536 if (!szUserSid)
538 if (!(usersid = get_user_sid()))
540 ERR("Failed to retrieve user SID\n");
541 return ERROR_FUNCTION_FAILED;
543 swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_comp );
544 LocalFree(usersid);
546 else swprintf( keypath, ARRAY_SIZE(keypath), fmtW, szUserSid, squashed_comp );
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);
552 UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid)
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;
561 if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED;
562 TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp));
564 if (!szUserSid)
566 if (!(usersid = get_user_sid()))
568 ERR("Failed to retrieve user SID\n");
569 return ERROR_FUNCTION_FAILED;
571 swprintf(keypath, ARRAY_SIZE(keypath), fmtW, usersid);
572 LocalFree(usersid);
574 else swprintf(keypath, ARRAY_SIZE(keypath), fmtW, szUserSid);
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;
582 UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create)
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];
589 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
590 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
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
598 if (!(usersid = get_user_sid()))
600 ERR("Failed to retrieve user SID\n");
601 return ERROR_FUNCTION_FAILED;
603 swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_pc );
604 LocalFree(usersid);
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);
610 UINT MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch, MSIINSTALLCONTEXT dwContext, HKEY *key, BOOL create)
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];
617 if (!squash_guid( szPatch, squashed_patch )) return ERROR_FUNCTION_FAILED;
618 TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_patch));
620 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
621 swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_patch );
622 else
624 if (!(usersid = get_user_sid()))
626 ERR("Failed to retrieve user SID\n");
627 return ERROR_FUNCTION_FAILED;
629 swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_patch );
630 LocalFree(usersid);
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);
636 UINT MSIREG_DeleteUserDataPatchKey(LPCWSTR patch, MSIINSTALLCONTEXT context)
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;
645 if (!squash_guid( patch, squashed_patch )) return ERROR_FUNCTION_FAILED;
646 TRACE("%s squashed %s\n", debugstr_w(patch), debugstr_w(squashed_patch));
648 if (context == MSIINSTALLCONTEXT_MACHINE)
649 swprintf(keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18");
650 else
652 if (!(usersid = get_user_sid()))
654 ERR("Failed to retrieve user SID\n");
655 return ERROR_FUNCTION_FAILED;
657 swprintf(keypath, ARRAY_SIZE(keypath), fmtW, usersid);
658 LocalFree(usersid);
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;
666 UINT MSIREG_OpenUserDataProductPatchesKey(LPCWSTR product, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
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];
673 if (!squash_guid( product, squashed_product )) return ERROR_FUNCTION_FAILED;
674 TRACE("%s squashed %s\n", debugstr_w(product), debugstr_w(squashed_product));
676 if (context == MSIINSTALLCONTEXT_MACHINE)
677 swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_product );
678 else
680 if (!(usersid = get_user_sid()))
682 ERR("Failed to retrieve user SID\n");
683 return ERROR_FUNCTION_FAILED;
685 swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_product );
686 LocalFree(usersid);
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);
692 UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create)
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];
699 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
700 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
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
708 if (!(usersid = get_user_sid()))
710 ERR("Failed to retrieve user SID\n");
711 return ERROR_FUNCTION_FAILED;
713 swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_pc );
714 LocalFree(usersid);
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);
720 UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context)
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;
729 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
730 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
732 if (context == MSIINSTALLCONTEXT_MACHINE)
733 swprintf(keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18");
734 else
736 if (!(usersid = get_user_sid()))
738 ERR("Failed to retrieve user SID\n");
739 return ERROR_FUNCTION_FAILED;
741 swprintf(keypath, ARRAY_SIZE(keypath), fmtW, usersid);
742 LocalFree(usersid);
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;
751 UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
753 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
754 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
755 HKEY hkey;
756 LONG r;
758 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
759 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
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;
768 UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
770 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
771 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
773 if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED;
774 TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc));
776 lstrcpyW( keypath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Patches\\" );
777 lstrcatW( keypath, squashed_pc );
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);
783 UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create)
785 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
786 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
788 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
789 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
791 lstrcpyW( keypath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\" );
792 lstrcatW( keypath, squashed_uc );
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);
798 UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
800 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
802 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
803 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
805 lstrcpyW(keypath, L"Software\\Microsoft\\Installer\\UpgradeCodes\\");
806 lstrcatW( keypath, squashed_uc );
808 if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
809 return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
812 UINT MSIREG_DeleteUpgradeCodesKey( const WCHAR *code )
814 WCHAR squashed_code[SQUASHED_GUID_SIZE];
815 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
816 HKEY hkey;
817 LONG ret;
819 if (!squash_guid( code, squashed_code )) return ERROR_FUNCTION_FAILED;
820 TRACE( "%s squashed %s\n", debugstr_w(code), debugstr_w(squashed_code) );
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;
829 UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode)
831 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
833 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
834 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
836 lstrcpyW(keypath, L"Software\\Microsoft\\Installer\\UpgradeCodes\\");
837 lstrcatW( keypath, squashed_uc );
838 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
841 UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode)
843 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
844 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
845 HKEY hkey;
846 LONG r;
848 if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED;
849 TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc));
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;
858 UINT MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode)
860 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
861 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
862 HKEY hkey;
863 LONG r;
865 if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED;
866 TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc));
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;
875 UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create)
877 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
878 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
880 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
881 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
883 lstrcpyW(keypath, L"Software\\Classes\\Installer\\UpgradeCodes\\");
884 lstrcatW( keypath, squashed_uc );
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);
890 UINT MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode)
892 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
893 WCHAR squashed_uc[SQUASHED_GUID_SIZE];
894 HKEY hkey;
895 LONG r;
897 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
898 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
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;
907 /*************************************************************************
908 * MsiDecomposeDescriptorW [MSI.@]
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] '<'
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
922 * RETURNS
923 * ERROR_SUCCESS if everything worked correctly
924 * ERROR_INVALID_PARAMETER if the descriptor was invalid
927 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
928 LPWSTR szFeature, LPWSTR szComponent, LPDWORD pUsed )
930 UINT len;
931 const WCHAR *p;
932 GUID product, component;
934 TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
935 szFeature, szComponent, pUsed);
937 if (!decode_base85_guid( szDescriptor, &product ))
938 return ERROR_INVALID_PARAMETER;
940 TRACE("product %s\n", debugstr_guid( &product ));
942 if (!(p = wcschr( &szDescriptor[20], '>' )))
943 p = wcschr( &szDescriptor[20], '<' );
944 if (!p)
945 return ERROR_INVALID_PARAMETER;
947 len = (p - &szDescriptor[20]);
948 if( len > MAX_FEATURE_CHARS )
949 return ERROR_INVALID_PARAMETER;
951 TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
953 if (*p == '>')
955 if (!decode_base85_guid( p+1, &component ))
956 return ERROR_INVALID_PARAMETER;
957 TRACE( "component %s\n", debugstr_guid(&component) );
960 if (szProduct)
961 StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
962 if (szComponent)
964 if (*p == '>')
965 StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
966 else
967 szComponent[0] = 0;
969 if (szFeature)
971 memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
972 szFeature[len] = 0;
975 len = p - szDescriptor + 1;
976 if (*p == '>') len += 20;
978 TRACE("length = %d\n", len);
979 if (pUsed) *pUsed = len;
981 return ERROR_SUCCESS;
984 UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
985 LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed )
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;
993 TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
994 szFeature, szComponent, pUsed);
996 str = strdupAtoW( szDescriptor );
997 if( szDescriptor && !str )
998 return ERROR_OUTOFMEMORY;
1000 if (szProduct)
1001 p = product;
1002 if (szFeature)
1003 f = feature;
1004 if (szComponent)
1005 c = component;
1007 r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
1009 if (r == ERROR_SUCCESS)
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 );
1019 free( str );
1021 return r;
1024 UINT WINAPI MsiEnumProductsA( DWORD index, char *lpguid )
1026 DWORD r;
1027 WCHAR szwGuid[GUID_SIZE];
1029 TRACE( "%lu, %p\n", index, lpguid );
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);
1037 return r;
1040 UINT WINAPI MsiEnumProductsW( DWORD index, WCHAR *lpguid )
1042 TRACE("%lu, %p\n", index, lpguid );
1044 if (NULL == lpguid)
1045 return ERROR_INVALID_PARAMETER;
1047 return MsiEnumProductsExW( NULL, L"S-1-1-0", MSIINSTALLCONTEXT_ALL, index, lpguid,
1048 NULL, NULL, NULL );
1051 UINT WINAPI MsiEnumFeaturesA( const char *szProduct, DWORD index, char *szFeature, char *szParent )
1053 DWORD r;
1054 WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
1055 WCHAR *szwProduct = NULL;
1057 TRACE( "%s, %lu, %p, %p\n", debugstr_a(szProduct), index, szFeature, szParent );
1059 if( szProduct )
1061 szwProduct = strdupAtoW( szProduct );
1062 if( !szwProduct )
1063 return ERROR_OUTOFMEMORY;
1066 r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
1067 if( r == ERROR_SUCCESS )
1069 WideCharToMultiByte(CP_ACP, 0, szwFeature, -1, szFeature, GUID_SIZE, NULL, NULL);
1070 WideCharToMultiByte(CP_ACP, 0, szwParent, -1, szParent, GUID_SIZE, NULL, NULL);
1073 free(szwProduct);
1075 return r;
1078 UINT WINAPI MsiEnumFeaturesW( const WCHAR *szProduct, DWORD index, WCHAR *szFeature, WCHAR *szParent )
1080 HKEY hkeyProduct = 0;
1081 DWORD r, sz;
1083 TRACE( "%s, %lu, %p, %p\n", debugstr_w(szProduct), index, szFeature, szParent );
1085 if( !szProduct )
1086 return ERROR_INVALID_PARAMETER;
1088 r = MSIREG_OpenInstallerFeaturesKey(szProduct,&hkeyProduct,FALSE);
1089 if( r != ERROR_SUCCESS )
1090 return ERROR_NO_MORE_ITEMS;
1092 sz = GUID_SIZE;
1093 r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
1094 RegCloseKey(hkeyProduct);
1096 return r;
1099 UINT WINAPI MsiEnumComponentsA( DWORD index, char *lpguid )
1101 DWORD r;
1102 WCHAR szwGuid[GUID_SIZE];
1104 TRACE( "%lu, %p\n", index, lpguid );
1106 if (!lpguid) return ERROR_INVALID_PARAMETER;
1108 r = MsiEnumComponentsW(index, szwGuid);
1109 if( r == ERROR_SUCCESS )
1110 WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1112 return r;
1115 UINT WINAPI MsiEnumComponentsW( DWORD index, WCHAR *lpguid )
1117 TRACE( "%lu, %p\n", index, lpguid );
1119 if (!lpguid) return ERROR_INVALID_PARAMETER;
1121 return MsiEnumComponentsExW( L"S-1-1-0", MSIINSTALLCONTEXT_ALL, index, lpguid, NULL, NULL, NULL );
1124 UINT WINAPI MsiEnumComponentsExA( const char *user_sid, DWORD ctx, DWORD index, CHAR guid[39],
1125 MSIINSTALLCONTEXT *installed_ctx, char *sid, DWORD *sid_len )
1127 UINT r;
1128 WCHAR *user_sidW = NULL, *sidW = NULL, guidW[GUID_SIZE];
1130 TRACE( "%s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_a(user_sid), ctx, index, guid, installed_ctx,
1131 sid, sid_len );
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) )))
1137 free( user_sidW );
1138 return ERROR_OUTOFMEMORY;
1140 r = MsiEnumComponentsExW( user_sidW, ctx, index, guidW, installed_ctx, sidW, sid_len );
1141 if (r == ERROR_SUCCESS)
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 );
1146 free( user_sidW );
1147 free( sidW );
1148 return r;
1151 static UINT fetch_machine_component( DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
1152 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
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;
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;
1165 len_component = ARRAY_SIZE( component );
1166 while (!RegEnumKeyExW( key_components, i, component, &len_component, NULL, NULL, NULL, NULL ))
1168 if (*idx == index) goto found;
1169 (*idx)++;
1170 len_component = ARRAY_SIZE( component );
1171 i++;
1173 RegCloseKey( key_components );
1174 return ERROR_NO_MORE_ITEMS;
1176 found:
1177 if (sid_len)
1179 if (*sid_len < 1)
1181 *sid_len = 1;
1182 r = ERROR_MORE_DATA;
1184 else if (sid)
1186 *sid_len = 0;
1187 sid[0] = 0;
1190 if (guid) unsquash_guid( component, guid );
1191 if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
1192 RegCloseKey( key_components );
1193 return r;
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 )
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;
1206 if (ctx == MSIINSTALLCONTEXT_USERMANAGED) /* FIXME: where to find these? */
1207 return ERROR_NO_MORE_ITEMS;
1209 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData",
1210 0, access, &key_users )) return ERROR_NO_MORE_ITEMS;
1212 len_user = ARRAY_SIZE( user );
1213 while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
1215 if ((wcscmp( usersid, L"S-1-1-0" ) && wcscmp( usersid, user )) ||
1216 !wcscmp( L"S-1-5-18", user ))
1218 i++;
1219 len_user = ARRAY_SIZE( user );
1220 continue;
1222 lstrcpyW( path, user );
1223 lstrcatW( path, L"\\Components" );
1224 if (RegOpenKeyExW( key_users, path, 0, access, &key_components ))
1226 i++;
1227 len_user = ARRAY_SIZE( user );
1228 continue;
1230 len_component = ARRAY_SIZE( component );
1231 while (!RegEnumKeyExW( key_components, j, component, &len_component, NULL, NULL, NULL, NULL ))
1233 if (*idx == index) goto found;
1234 (*idx)++;
1235 len_component = ARRAY_SIZE( component );
1236 j++;
1238 RegCloseKey( key_components );
1239 len_user = ARRAY_SIZE( user );
1240 i++;
1242 RegCloseKey( key_users );
1243 return ERROR_NO_MORE_ITEMS;
1245 found:
1246 if (sid_len)
1248 if (*sid_len < len_user + 1)
1250 *sid_len = len_user + 1;
1251 r = ERROR_MORE_DATA;
1253 else if (sid)
1255 *sid_len = len_user;
1256 lstrcpyW( sid, user );
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;
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 )
1269 UINT r = ERROR_NO_MORE_ITEMS;
1270 WCHAR *user = NULL;
1272 if (!usersid)
1274 usersid = user = get_user_sid();
1275 if (!user) return ERROR_FUNCTION_FAILED;
1277 if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
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;
1283 if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
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;
1289 if (ctx & MSIINSTALLCONTEXT_MACHINE)
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;
1296 done:
1297 LocalFree( user );
1298 return r;
1301 UINT WINAPI MsiEnumComponentsExW( const WCHAR *user_sid, DWORD ctx, DWORD index, WCHAR guid[39],
1302 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
1304 UINT r;
1305 DWORD idx = 0;
1306 static DWORD last_index;
1308 TRACE( "%s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(user_sid), ctx, index, guid, installed_ctx,
1309 sid, sid_len );
1311 if ((sid && !sid_len) || !ctx || (user_sid && ctx == MSIINSTALLCONTEXT_MACHINE))
1312 return ERROR_INVALID_PARAMETER;
1314 if (index && index - last_index != 1)
1315 return ERROR_INVALID_PARAMETER;
1317 if (!index) last_index = 0;
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;
1325 return r;
1328 UINT WINAPI MsiEnumClientsA( const char *szComponent, DWORD index, char *szProduct )
1330 DWORD r;
1331 WCHAR szwProduct[GUID_SIZE];
1332 WCHAR *szwComponent = NULL;
1334 TRACE( "%s, %lu, %p\n", debugstr_a(szComponent), index, szProduct );
1336 if ( !szProduct )
1337 return ERROR_INVALID_PARAMETER;
1339 if( szComponent )
1341 szwComponent = strdupAtoW( szComponent );
1342 if( !szwComponent )
1343 return ERROR_OUTOFMEMORY;
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);
1350 free(szwComponent);
1352 return r;
1355 UINT WINAPI MsiEnumClientsW( const WCHAR *szComponent, DWORD index, WCHAR *szProduct )
1357 HKEY hkeyComp = 0;
1358 DWORD r, sz;
1359 WCHAR szValName[SQUASHED_GUID_SIZE];
1361 TRACE( "%s, %lu, %p\n", debugstr_w(szComponent), index, szProduct );
1363 if (!szComponent || !*szComponent || !szProduct)
1364 return ERROR_INVALID_PARAMETER;
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;
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)
1375 RegCloseKey(hkeyComp);
1377 if (index != 0)
1378 return ERROR_INVALID_PARAMETER;
1380 return ERROR_UNKNOWN_COMPONENT;
1383 sz = SQUASHED_GUID_SIZE;
1384 r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
1385 if( r == ERROR_SUCCESS )
1387 unsquash_guid(szValName, szProduct);
1388 TRACE("-> %s\n", debugstr_w(szProduct));
1390 RegCloseKey(hkeyComp);
1391 return r;
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 )
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;
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 )
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;
1412 static UINT MSI_EnumComponentQualifiers( const WCHAR *szComponent, DWORD iIndex, awstring *lpQualBuf,
1413 DWORD *pcchQual, awstring *lpAppBuf, DWORD *pcchAppBuf )
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;
1420 TRACE( "%s, %lu, %p, %p, %p, %p\n", debugstr_w(szComponent), iIndex, lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf );
1422 if (!szComponent)
1423 return ERROR_INVALID_PARAMETER;
1425 r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1426 if (r != ERROR_SUCCESS)
1427 return ERROR_UNKNOWN_COMPONENT;
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;
1436 val_max = 0x10;
1437 r = ERROR_OUTOFMEMORY;
1438 val = malloc( val_max );
1439 if (!val)
1440 goto end;
1442 /* loop until we allocate enough memory */
1443 while (1)
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;
1453 if (type != REG_MULTI_SZ)
1455 ERR( "component data has wrong type (%lu)\n", type );
1456 goto end;
1459 r = ERROR_OUTOFMEMORY;
1460 if (name_sz + 1 >= name_max)
1462 name_max *= 2;
1463 free( name );
1464 name = malloc( name_max * sizeof (WCHAR) );
1465 if (!name)
1466 goto end;
1467 continue;
1469 if (val_sz > val_max)
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;
1478 ERR( "should be enough data, but isn't %lu %lu\n", name_sz, val_sz );
1479 goto end;
1482 ofs = 0;
1483 r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1484 if (r != ERROR_SUCCESS)
1485 goto end;
1487 TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1489 r = msi_strcpy_to_awstring( name, -1, lpQualBuf, pcchQual );
1490 r2 = msi_strcpy_to_awstring( val+ofs, -1, lpAppBuf, pcchAppBuf );
1492 if (r2 != ERROR_SUCCESS)
1493 r = r2;
1495 end:
1496 free(val);
1497 free(name);
1498 RegCloseKey(key);
1499 return r;
1502 /*************************************************************************
1503 * MsiEnumComponentQualifiersA [MSI.@]
1505 UINT WINAPI MsiEnumComponentQualifiersA( const char *szComponent, DWORD iIndex, char *lpQualifierBuf,
1506 DWORD *pcchQualifierBuf, char *lpApplicationDataBuf,
1507 DWORD *pcchApplicationDataBuf )
1509 awstring qual, appdata;
1510 WCHAR *comp;
1511 UINT r;
1513 TRACE( "%s, %lu, %p, %p, %p, %p\n", debugstr_a(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf,
1514 lpApplicationDataBuf, pcchApplicationDataBuf );
1516 comp = strdupAtoW( szComponent );
1517 if (szComponent && !comp)
1518 return ERROR_OUTOFMEMORY;
1520 qual.unicode = FALSE;
1521 qual.str.a = lpQualifierBuf;
1523 appdata.unicode = FALSE;
1524 appdata.str.a = lpApplicationDataBuf;
1526 r = MSI_EnumComponentQualifiers( comp, iIndex,
1527 &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1528 free( comp );
1529 return r;
1532 /*************************************************************************
1533 * MsiEnumComponentQualifiersW [MSI.@]
1535 UINT WINAPI MsiEnumComponentQualifiersW( const WCHAR *szComponent, DWORD iIndex, WCHAR *lpQualifierBuf,
1536 DWORD *pcchQualifierBuf, WCHAR *lpApplicationDataBuf,
1537 DWORD *pcchApplicationDataBuf )
1539 awstring qual, appdata;
1541 TRACE( "%s, %lu, %p, %p, %p, %p\n", debugstr_w(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf,
1542 lpApplicationDataBuf, pcchApplicationDataBuf );
1544 qual.unicode = TRUE;
1545 qual.str.w = lpQualifierBuf;
1547 appdata.unicode = TRUE;
1548 appdata.str.w = lpApplicationDataBuf;
1550 return MSI_EnumComponentQualifiers( szComponent, iIndex, &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1553 /*************************************************************************
1554 * MsiEnumRelatedProductsW [MSI.@]
1557 UINT WINAPI MsiEnumRelatedProductsW( const WCHAR *szUpgradeCode, DWORD dwReserved, DWORD iProductIndex,
1558 WCHAR *lpProductBuf )
1560 UINT r;
1561 HKEY hkey;
1562 WCHAR szKeyName[SQUASHED_GUID_SIZE];
1563 DWORD dwSize = ARRAY_SIZE(szKeyName);
1565 TRACE( "%s, %#lx, %lu, %p\n", debugstr_w(szUpgradeCode), dwReserved, iProductIndex, lpProductBuf );
1567 if (NULL == szUpgradeCode)
1568 return ERROR_INVALID_PARAMETER;
1569 if (NULL == lpProductBuf)
1570 return ERROR_INVALID_PARAMETER;
1572 r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1573 if (r != ERROR_SUCCESS)
1574 return ERROR_NO_MORE_ITEMS;
1576 r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1577 if( r == ERROR_SUCCESS )
1578 unsquash_guid(szKeyName, lpProductBuf);
1579 RegCloseKey(hkey);
1581 return r;
1584 /*************************************************************************
1585 * MsiEnumRelatedProductsA [MSI.@]
1588 UINT WINAPI MsiEnumRelatedProductsA( const char *szUpgradeCode, DWORD dwReserved, DWORD iProductIndex,
1589 char *lpProductBuf )
1591 WCHAR *szwUpgradeCode = NULL;
1592 WCHAR productW[GUID_SIZE];
1593 UINT r;
1595 TRACE( "%s, %#lx, %lu, %p\n", debugstr_a(szUpgradeCode), dwReserved, iProductIndex, lpProductBuf );
1597 if (szUpgradeCode)
1599 szwUpgradeCode = strdupAtoW( szUpgradeCode );
1600 if( !szwUpgradeCode )
1601 return ERROR_OUTOFMEMORY;
1604 r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1605 iProductIndex, productW );
1606 if (r == ERROR_SUCCESS)
1608 WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1609 lpProductBuf, GUID_SIZE, NULL, NULL );
1611 free( szwUpgradeCode );
1612 return r;
1615 /***********************************************************************
1616 * MsiEnumPatchesExA [MSI.@]
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 )
1623 WCHAR *prodcode = NULL, *usersid = NULL, *targsid = NULL;
1624 WCHAR patch[GUID_SIZE], targprod[GUID_SIZE];
1625 DWORD len;
1626 UINT r;
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 );
1632 if (szTargetUserSid && !pcchTargetUserSid)
1633 return ERROR_INVALID_PARAMETER;
1635 if (szProductCode) prodcode = strdupAtoW(szProductCode);
1636 if (szUserSid) usersid = strdupAtoW(szUserSid);
1638 r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1639 patch, targprod, pdwTargetProductContext,
1640 NULL, &len);
1641 if (r != ERROR_SUCCESS)
1642 goto done;
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);
1649 if (!szTargetUserSid)
1651 if (pcchTargetUserSid)
1652 *pcchTargetUserSid = len;
1654 goto done;
1657 targsid = malloc(++len * sizeof(WCHAR));
1658 if (!targsid)
1660 r = ERROR_OUTOFMEMORY;
1661 goto done;
1664 r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1665 patch, targprod, pdwTargetProductContext,
1666 targsid, &len);
1667 if (r != ERROR_SUCCESS || !szTargetUserSid)
1668 goto done;
1670 WideCharToMultiByte(CP_ACP, 0, targsid, -1, szTargetUserSid,
1671 *pcchTargetUserSid, NULL, NULL);
1673 len = lstrlenW(targsid);
1674 if (*pcchTargetUserSid < len + 1)
1676 r = ERROR_MORE_DATA;
1677 *pcchTargetUserSid = len * sizeof(WCHAR);
1679 else
1680 *pcchTargetUserSid = len;
1682 done:
1683 free(prodcode);
1684 free(usersid);
1685 free(targsid);
1687 return r;
1690 static UINT get_patch_state(const WCHAR *prodcode, const WCHAR *usersid, MSIINSTALLCONTEXT context,
1691 WCHAR *patch, MSIPATCHSTATE *state)
1693 DWORD type, val, size;
1694 HKEY prod, hkey = 0;
1695 HKEY udpatch = 0;
1696 LONG res;
1697 UINT r = ERROR_NO_MORE_ITEMS;
1699 *state = MSIPATCHSTATE_INVALID;
1701 r = MSIREG_OpenUserDataProductKey(prodcode, context,
1702 usersid, &prod, FALSE);
1703 if (r != ERROR_SUCCESS)
1704 return ERROR_NO_MORE_ITEMS;
1706 res = RegOpenKeyExW(prod, L"Patches", 0, KEY_READ, &hkey);
1707 if (res != ERROR_SUCCESS)
1708 goto done;
1710 res = RegOpenKeyExW(hkey, patch, 0, KEY_READ, &udpatch);
1711 if (res != ERROR_SUCCESS)
1712 goto done;
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)
1719 r = ERROR_BAD_CONFIGURATION;
1720 goto done;
1723 *state = val;
1724 r = ERROR_SUCCESS;
1726 done:
1727 RegCloseKey(udpatch);
1728 RegCloseKey(hkey);
1729 RegCloseKey(prod);
1731 return r;
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)
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;
1746 if (MSIREG_OpenProductKey(prodcode, usersid, context,
1747 &prod, FALSE) != ERROR_SUCCESS)
1748 return ERROR_NO_MORE_ITEMS;
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;
1756 if (type != REG_MULTI_SZ)
1758 r = ERROR_BAD_CONFIGURATION;
1759 goto done;
1762 patches = malloc(size);
1763 if (!patches)
1765 r = ERROR_OUTOFMEMORY;
1766 goto done;
1769 res = RegGetValueW(prod, L"Patches", L"Patches", RRF_RT_ANY, &type,
1770 patches, &size);
1771 if (res != ERROR_SUCCESS)
1772 goto done;
1774 for (ptr = patches; *ptr && r == ERROR_NO_MORE_ITEMS; ptr += lstrlenW(ptr) + 1)
1776 if (!unsquash_guid(ptr, patch))
1778 r = ERROR_BAD_CONFIGURATION;
1779 goto done;
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;
1788 if (transforms)
1790 *transforms = malloc(size);
1791 if (!*transforms)
1793 r = ERROR_OUTOFMEMORY;
1794 goto done;
1797 res = RegGetValueW(prod, L"Patches", ptr, RRF_RT_REG_SZ,
1798 &type, *transforms, &size);
1799 if (res != ERROR_SUCCESS)
1800 continue;
1803 if (context == MSIINSTALLCONTEXT_USERMANAGED)
1805 if (!(filter & MSIPATCHSTATE_APPLIED))
1807 temp = get_patch_state(prodcode, usersid, context, ptr, &state);
1808 if (temp == ERROR_BAD_CONFIGURATION)
1810 r = ERROR_BAD_CONFIGURATION;
1811 goto done;
1814 if (temp != ERROR_SUCCESS || !(filter & state))
1815 continue;
1818 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
1820 if (!(filter & MSIPATCHSTATE_APPLIED))
1822 temp = get_patch_state(prodcode, usersid, context, ptr, &state);
1823 if (temp == ERROR_BAD_CONFIGURATION)
1825 r = ERROR_BAD_CONFIGURATION;
1826 goto done;
1829 if (temp != ERROR_SUCCESS || !(filter & state))
1830 continue;
1832 else
1834 temp = MSIREG_OpenUserDataPatchKey(patch, context,
1835 &patchkey, FALSE);
1836 RegCloseKey(patchkey);
1837 if (temp != ERROR_SUCCESS)
1838 continue;
1841 else if (context == MSIINSTALLCONTEXT_MACHINE)
1843 usersid = L"";
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)
1849 size = sizeof(state);
1850 res = RegGetValueW(patchkey, NULL, L"State", RRF_RT_REG_DWORD,
1851 &type, &state, &size);
1853 if (!(filter & state))
1854 res = ERROR_NO_MORE_ITEMS;
1856 RegCloseKey(patchkey);
1859 RegCloseKey(localpatch);
1860 RegCloseKey(localprod);
1862 if (res != ERROR_SUCCESS)
1863 continue;
1866 if (*idx < index)
1868 (*idx)++;
1869 continue;
1872 r = ERROR_SUCCESS;
1873 if (targetprod)
1874 lstrcpyW(targetprod, prodcode);
1876 if (targetctx)
1877 *targetctx = context;
1879 if (targetsid)
1881 lstrcpynW(targetsid, usersid, *sidsize);
1882 if (lstrlenW(usersid) >= *sidsize)
1883 r = ERROR_MORE_DATA;
1886 if (sidsize)
1888 *sidsize = lstrlenW(usersid);
1889 if (!targetsid)
1890 *sidsize *= sizeof(WCHAR);
1894 done:
1895 RegCloseKey(prod);
1896 free(patches);
1898 return r;
1901 static UINT enum_patches(const WCHAR *szProductCode, const WCHAR *szUserSid, DWORD dwContext, DWORD dwFilter,
1902 DWORD dwIndex, DWORD *idx, WCHAR *szPatchCode, WCHAR *szTargetProductCode,
1903 MSIINSTALLCONTEXT *pdwTargetProductContext, WCHAR *szTargetUserSid, DWORD *pcchTargetUserSid,
1904 WCHAR **szTransforms)
1906 LPWSTR usersid = NULL;
1907 UINT r = ERROR_INVALID_PARAMETER;
1909 if (!szUserSid)
1911 szUserSid = usersid = get_user_sid();
1912 if (!usersid) return ERROR_FUNCTION_FAILED;
1915 if (dwContext & MSIINSTALLCONTEXT_USERMANAGED)
1917 r = check_product_patches(szProductCode, szUserSid, MSIINSTALLCONTEXT_USERMANAGED, dwFilter, dwIndex, idx,
1918 szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
1919 pcchTargetUserSid, szTransforms);
1920 if (r != ERROR_NO_MORE_ITEMS)
1921 goto done;
1924 if (dwContext & MSIINSTALLCONTEXT_USERUNMANAGED)
1926 r = check_product_patches(szProductCode, szUserSid, MSIINSTALLCONTEXT_USERUNMANAGED, dwFilter, dwIndex, idx,
1927 szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
1928 pcchTargetUserSid, szTransforms);
1929 if (r != ERROR_NO_MORE_ITEMS)
1930 goto done;
1933 if (dwContext & MSIINSTALLCONTEXT_MACHINE)
1935 r = check_product_patches(szProductCode, szUserSid, MSIINSTALLCONTEXT_MACHINE, dwFilter, dwIndex, idx,
1936 szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
1937 pcchTargetUserSid, szTransforms);
1938 if (r != ERROR_NO_MORE_ITEMS)
1939 goto done;
1942 done:
1943 LocalFree(usersid);
1944 return r;
1947 /***********************************************************************
1948 * MsiEnumPatchesExW [MSI.@]
1950 UINT WINAPI MsiEnumPatchesExW( const WCHAR *szProductCode, const WCHAR *szUserSid, DWORD dwContext, DWORD dwFilter,
1951 DWORD dwIndex, WCHAR *szPatchCode, WCHAR *szTargetProductCode,
1952 MSIINSTALLCONTEXT *pdwTargetProductContext, WCHAR *szTargetUserSid,
1953 DWORD *pcchTargetUserSid )
1955 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
1956 DWORD idx = 0;
1957 UINT r;
1959 static DWORD last_index;
1961 TRACE( "%s, %s, %#lx, %lu, %lu, %p, %p, %p, %p, %p)\n", debugstr_w(szProductCode), debugstr_w(szUserSid),
1962 dwContext, dwFilter, dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
1963 pcchTargetUserSid );
1965 if (!szProductCode || !squash_guid( szProductCode, squashed_pc ))
1966 return ERROR_INVALID_PARAMETER;
1968 if (szUserSid && !wcscmp( szUserSid, L"S-1-5-18" ))
1969 return ERROR_INVALID_PARAMETER;
1971 if (dwContext & MSIINSTALLCONTEXT_MACHINE && szUserSid)
1972 return ERROR_INVALID_PARAMETER;
1974 if (dwContext <= MSIINSTALLCONTEXT_NONE ||
1975 dwContext > MSIINSTALLCONTEXT_ALL)
1976 return ERROR_INVALID_PARAMETER;
1978 if (dwFilter <= MSIPATCHSTATE_INVALID || dwFilter > MSIPATCHSTATE_ALL)
1979 return ERROR_INVALID_PARAMETER;
1981 if (dwIndex && dwIndex - last_index != 1)
1982 return ERROR_INVALID_PARAMETER;
1984 if (dwIndex == 0)
1985 last_index = 0;
1987 r = enum_patches(szProductCode, szUserSid, dwContext, dwFilter, dwIndex, &idx, szPatchCode, szTargetProductCode,
1988 pdwTargetProductContext, szTargetUserSid, pcchTargetUserSid, NULL);
1990 if (r == ERROR_SUCCESS)
1991 last_index = dwIndex;
1992 else
1993 last_index = 0;
1995 return r;
1998 /***********************************************************************
1999 * MsiEnumPatchesA [MSI.@]
2001 UINT WINAPI MsiEnumPatchesA( const char *szProduct, DWORD iPatchIndex, char *lpPatchBuf, char *lpTransformsBuf,
2002 DWORD *pcchTransformsBuf )
2004 WCHAR *product, *transforms, patch[GUID_SIZE];
2005 DWORD len;
2006 UINT r;
2008 TRACE( "%s, %lu, %p, %p, %p\n", debugstr_a(szProduct), iPatchIndex, lpPatchBuf, lpTransformsBuf,
2009 pcchTransformsBuf );
2011 if (!szProduct || !lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2012 return ERROR_INVALID_PARAMETER;
2014 product = strdupAtoW(szProduct);
2015 if (!product)
2016 return ERROR_OUTOFMEMORY;
2018 len = *pcchTransformsBuf;
2019 transforms = malloc(len * sizeof(WCHAR));
2020 if (!transforms)
2022 r = ERROR_OUTOFMEMORY;
2023 goto done;
2026 r = MsiEnumPatchesW(product, iPatchIndex, patch, transforms, &len);
2027 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2028 goto done;
2030 WideCharToMultiByte(CP_ACP, 0, patch, -1, lpPatchBuf,
2031 GUID_SIZE, NULL, NULL);
2033 if (!WideCharToMultiByte(CP_ACP, 0, transforms, -1, lpTransformsBuf,
2034 *pcchTransformsBuf, NULL, NULL))
2035 r = ERROR_MORE_DATA;
2037 if (r == ERROR_MORE_DATA)
2039 lpTransformsBuf[*pcchTransformsBuf - 1] = '\0';
2040 *pcchTransformsBuf = len * 2;
2042 else
2043 *pcchTransformsBuf = strlen( lpTransformsBuf );
2045 done:
2046 free(transforms);
2047 free(product);
2049 return r;
2052 /***********************************************************************
2053 * MsiEnumPatchesW [MSI.@]
2055 UINT WINAPI MsiEnumPatchesW( const WCHAR *szProduct, DWORD iPatchIndex, WCHAR *lpPatchBuf, WCHAR *lpTransformsBuf,
2056 DWORD *pcchTransformsBuf )
2058 WCHAR *transforms = NULL, squashed_pc[SQUASHED_GUID_SIZE];
2059 HKEY prod;
2060 DWORD idx = 0;
2061 UINT r;
2063 TRACE( "%s, %lu, %p, %p, %p)\n", debugstr_w(szProduct), iPatchIndex, lpPatchBuf, lpTransformsBuf,
2064 pcchTransformsBuf );
2066 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
2067 return ERROR_INVALID_PARAMETER;
2069 if (!lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2070 return ERROR_INVALID_PARAMETER;
2072 if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2073 &prod, FALSE) != ERROR_SUCCESS &&
2074 MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2075 &prod, FALSE) != ERROR_SUCCESS &&
2076 MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2077 &prod, FALSE) != ERROR_SUCCESS)
2078 return ERROR_UNKNOWN_PRODUCT;
2080 RegCloseKey(prod);
2082 r = enum_patches(szProduct, NULL, MSIINSTALLCONTEXT_ALL, MSIPATCHSTATE_ALL, iPatchIndex, &idx, lpPatchBuf, NULL,
2083 NULL, NULL, NULL, &transforms);
2084 if (r != ERROR_SUCCESS)
2085 goto done;
2087 lstrcpynW(lpTransformsBuf, transforms, *pcchTransformsBuf);
2088 if (*pcchTransformsBuf <= lstrlenW(transforms))
2090 r = ERROR_MORE_DATA;
2091 *pcchTransformsBuf = lstrlenW(transforms);
2093 else
2094 *pcchTransformsBuf = lstrlenW(transforms);
2096 done:
2097 free(transforms);
2098 return r;
2101 UINT WINAPI MsiEnumProductsExA( const char *product, const char *usersid, DWORD ctx, DWORD index,
2102 char installed_product[GUID_SIZE], MSIINSTALLCONTEXT *installed_ctx, char *sid,
2103 DWORD *sid_len )
2105 UINT r;
2106 WCHAR installed_productW[GUID_SIZE], *productW = NULL, *usersidW = NULL, *sidW = NULL;
2108 TRACE( "%s, %s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_a(product), debugstr_a(usersid), ctx, index,
2109 installed_product, installed_ctx, sid, sid_len );
2111 if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
2112 if (product && !(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
2113 if (usersid && !(usersidW = strdupAtoW( usersid )))
2115 free( productW );
2116 return ERROR_OUTOFMEMORY;
2118 if (sid && !(sidW = malloc( *sid_len * sizeof(WCHAR) )))
2120 free( usersidW );
2121 free( productW );
2122 return ERROR_OUTOFMEMORY;
2124 r = MsiEnumProductsExW( productW, usersidW, ctx, index, installed_productW,
2125 installed_ctx, sidW, sid_len );
2126 if (r == ERROR_SUCCESS)
2128 if (installed_product) WideCharToMultiByte( CP_ACP, 0, installed_productW, GUID_SIZE,
2129 installed_product, GUID_SIZE, NULL, NULL );
2130 if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
2132 free( productW );
2133 free( usersidW );
2134 free( sidW );
2135 return r;
2138 static UINT fetch_machine_product( const WCHAR *match, DWORD index, DWORD *idx,
2139 WCHAR installed_product[GUID_SIZE],
2140 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2142 UINT r;
2143 WCHAR product[SQUASHED_GUID_SIZE];
2144 DWORD i = 0, len;
2145 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
2146 HKEY key;
2148 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Classes\\Installer\\Products", 0, access, &key ))
2149 return ERROR_NO_MORE_ITEMS;
2151 len = ARRAY_SIZE( product );
2152 while (!RegEnumKeyExW( key, i, product, &len, NULL, NULL, NULL, NULL ))
2154 if (match && wcscmp( match, product ))
2156 i++;
2157 len = ARRAY_SIZE( product );
2158 continue;
2160 if (*idx == index) goto found;
2161 (*idx)++;
2162 len = ARRAY_SIZE( product );
2163 i++;
2165 RegCloseKey( key );
2166 return ERROR_NO_MORE_ITEMS;
2168 found:
2169 if (sid_len && *sid_len < 1)
2171 *sid_len = 1;
2172 r = ERROR_MORE_DATA;
2174 else
2176 if (installed_product) unsquash_guid( product, installed_product );
2177 if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
2178 if (sid)
2180 sid[0] = 0;
2181 *sid_len = 0;
2183 r = ERROR_SUCCESS;
2185 RegCloseKey( key );
2186 return r;
2189 static UINT fetch_user_product( const WCHAR *match, const WCHAR *usersid, DWORD ctx, DWORD index,
2190 DWORD *idx, WCHAR installed_product[GUID_SIZE],
2191 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2193 UINT r;
2194 const WCHAR *subkey;
2195 WCHAR path[MAX_PATH], product[SQUASHED_GUID_SIZE], user[128];
2196 DWORD i = 0, j = 0, len_product, len_user;
2197 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
2198 HKEY key_users, key_products;
2200 if (ctx == MSIINSTALLCONTEXT_USERMANAGED)
2202 subkey = L"\\Installer\\Products";
2203 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed",
2204 0, access, &key_users )) return ERROR_NO_MORE_ITEMS;
2206 else if (ctx == MSIINSTALLCONTEXT_USERUNMANAGED)
2208 subkey = L"\\Software\\Microsoft\\Installer\\Products";
2209 if (RegOpenKeyExW( HKEY_USERS, NULL, 0, access, &key_users ))
2210 return ERROR_NO_MORE_ITEMS;
2212 else return ERROR_INVALID_PARAMETER;
2214 len_user = ARRAY_SIZE( user );
2215 while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
2217 if (wcscmp( usersid, user ) && wcscmp( usersid, L"S-1-1-0" ))
2219 i++;
2220 len_user = ARRAY_SIZE( user );
2221 continue;
2223 lstrcpyW( path, user );
2224 lstrcatW( path, subkey );
2225 if (RegOpenKeyExW( key_users, path, 0, access, &key_products ))
2227 i++;
2228 len_user = ARRAY_SIZE( user );
2229 continue;
2231 len_product = ARRAY_SIZE( product );
2232 while (!RegEnumKeyExW( key_products, j, product, &len_product, NULL, NULL, NULL, NULL ))
2234 if (match && wcscmp( match, product ))
2236 j++;
2237 len_product = ARRAY_SIZE( product );
2238 continue;
2240 if (*idx == index) goto found;
2241 (*idx)++;
2242 len_product = ARRAY_SIZE( product );
2243 j++;
2245 RegCloseKey( key_products );
2246 len_user = ARRAY_SIZE( user );
2247 i++;
2249 RegCloseKey( key_users );
2250 return ERROR_NO_MORE_ITEMS;
2252 found:
2253 if (sid_len && *sid_len <= len_user)
2255 *sid_len = len_user;
2256 r = ERROR_MORE_DATA;
2258 else
2260 if (installed_product) unsquash_guid( product, installed_product );
2261 if (installed_ctx) *installed_ctx = ctx;
2262 if (sid)
2264 lstrcpyW( sid, user );
2265 *sid_len = len_user;
2267 r = ERROR_SUCCESS;
2269 RegCloseKey( key_products );
2270 RegCloseKey( key_users );
2271 return r;
2274 static UINT enum_products( const WCHAR *product, const WCHAR *usersid, DWORD ctx, DWORD index,
2275 DWORD *idx, WCHAR installed_product[GUID_SIZE],
2276 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2278 UINT r = ERROR_NO_MORE_ITEMS;
2279 WCHAR *user = NULL;
2281 if (!usersid)
2283 usersid = user = get_user_sid();
2284 if (!user) return ERROR_FUNCTION_FAILED;
2286 if (ctx & MSIINSTALLCONTEXT_MACHINE)
2288 r = fetch_machine_product( product, index, idx, installed_product, installed_ctx,
2289 sid, sid_len );
2290 if (r != ERROR_NO_MORE_ITEMS) goto done;
2292 if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
2294 r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index,
2295 idx, installed_product, installed_ctx, sid, sid_len );
2296 if (r != ERROR_NO_MORE_ITEMS) goto done;
2298 if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
2300 r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERMANAGED, index,
2301 idx, installed_product, installed_ctx, sid, sid_len );
2302 if (r != ERROR_NO_MORE_ITEMS) goto done;
2305 done:
2306 LocalFree( user );
2307 return r;
2310 UINT WINAPI MsiEnumProductsExW( const WCHAR *product, const WCHAR *usersid, DWORD ctx, DWORD index,
2311 WCHAR installed_product[GUID_SIZE], MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid,
2312 DWORD *sid_len )
2314 UINT r;
2315 DWORD idx = 0;
2316 static DWORD last_index;
2318 TRACE( "%s, %s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(product), debugstr_w(usersid), ctx, index,
2319 installed_product, installed_ctx, sid, sid_len );
2321 if ((sid && !sid_len) || !ctx || (usersid && ctx == MSIINSTALLCONTEXT_MACHINE))
2322 return ERROR_INVALID_PARAMETER;
2324 if (index && index - last_index != 1)
2325 return ERROR_INVALID_PARAMETER;
2327 if (!index) last_index = 0;
2329 r = enum_products( product, usersid, ctx, index, &idx, installed_product, installed_ctx,
2330 sid, sid_len );
2331 if (r == ERROR_SUCCESS)
2332 last_index = index;
2333 else
2334 last_index = 0;
2336 return r;