user32: Remove _wassert workaround.
[wine.git] / dlls / msi / registry.c
blob5dc3c0a81c3848f185dd632bc6fb268608f8ad92
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 = msi_alloc( 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 = msi_alloc( size )))
279 CloseHandle( token );
280 return NULL;
282 if (!GetTokenInformation( token, TokenUser, user, size, &size ))
284 msi_free( user );
285 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || !(user = msi_alloc( 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 msi_free( user );
296 return NULL;
298 msi_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 msi_free( str );
1021 return r;
1024 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
1026 DWORD r;
1027 WCHAR szwGuid[GUID_SIZE];
1029 TRACE("%d %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, LPWSTR lpguid)
1042 TRACE("%d %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(LPCSTR szProduct, DWORD index, LPSTR szFeature, LPSTR szParent)
1053 DWORD r;
1054 WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
1055 LPWSTR szwProduct = NULL;
1057 TRACE("%s %d %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,
1070 szFeature, GUID_SIZE, NULL, NULL);
1071 WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
1072 szParent, GUID_SIZE, NULL, NULL);
1075 msi_free( szwProduct);
1077 return r;
1080 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, LPWSTR szFeature, LPWSTR szParent)
1082 HKEY hkeyProduct = 0;
1083 DWORD r, sz;
1085 TRACE("%s %d %p %p\n", debugstr_w(szProduct), index, szFeature, szParent);
1087 if( !szProduct )
1088 return ERROR_INVALID_PARAMETER;
1090 r = MSIREG_OpenInstallerFeaturesKey(szProduct,&hkeyProduct,FALSE);
1091 if( r != ERROR_SUCCESS )
1092 return ERROR_NO_MORE_ITEMS;
1094 sz = GUID_SIZE;
1095 r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
1096 RegCloseKey(hkeyProduct);
1098 return r;
1101 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
1103 DWORD r;
1104 WCHAR szwGuid[GUID_SIZE];
1106 TRACE("%u, %p\n", index, lpguid);
1108 if (!lpguid) return ERROR_INVALID_PARAMETER;
1110 r = MsiEnumComponentsW(index, szwGuid);
1111 if( r == ERROR_SUCCESS )
1112 WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1114 return r;
1117 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
1119 TRACE("%u, %p\n", index, lpguid);
1121 if (!lpguid) return ERROR_INVALID_PARAMETER;
1123 return MsiEnumComponentsExW( L"S-1-1-0", MSIINSTALLCONTEXT_ALL, index, lpguid, NULL, NULL, NULL );
1126 UINT WINAPI MsiEnumComponentsExA( LPCSTR user_sid, DWORD ctx, DWORD index, CHAR guid[39],
1127 MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len )
1129 UINT r;
1130 WCHAR *user_sidW = NULL, *sidW = NULL, guidW[GUID_SIZE];
1132 TRACE("%s, %u, %u, %p, %p, %p, %p\n", debugstr_a(user_sid), ctx, index, guid, installed_ctx,
1133 sid, sid_len);
1135 if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
1136 if (user_sid && !(user_sidW = strdupAtoW( user_sid ))) return ERROR_OUTOFMEMORY;
1137 if (sid && !(sidW = msi_alloc( *sid_len * sizeof(WCHAR) )))
1139 msi_free( user_sidW );
1140 return ERROR_OUTOFMEMORY;
1142 r = MsiEnumComponentsExW( user_sidW, ctx, index, guidW, installed_ctx, sidW, sid_len );
1143 if (r == ERROR_SUCCESS)
1145 if (guid) WideCharToMultiByte( CP_ACP, 0, guidW, GUID_SIZE, guid, GUID_SIZE, NULL, NULL );
1146 if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
1148 msi_free( user_sidW );
1149 msi_free( sidW );
1150 return r;
1153 static UINT fetch_machine_component( DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
1154 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1156 UINT r = ERROR_SUCCESS;
1157 WCHAR component[SQUASHED_GUID_SIZE];
1158 DWORD i = 0, len_component;
1159 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
1160 HKEY key_components;
1162 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE,
1163 L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Components",
1164 0, access, &key_components ))
1165 return ERROR_NO_MORE_ITEMS;
1167 len_component = ARRAY_SIZE( component );
1168 while (!RegEnumKeyExW( key_components, i, component, &len_component, NULL, NULL, NULL, NULL ))
1170 if (*idx == index) goto found;
1171 (*idx)++;
1172 len_component = ARRAY_SIZE( component );
1173 i++;
1175 RegCloseKey( key_components );
1176 return ERROR_NO_MORE_ITEMS;
1178 found:
1179 if (sid_len)
1181 if (*sid_len < 1)
1183 *sid_len = 1;
1184 r = ERROR_MORE_DATA;
1186 else if (sid)
1188 *sid_len = 0;
1189 sid[0] = 0;
1192 if (guid) unsquash_guid( component, guid );
1193 if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
1194 RegCloseKey( key_components );
1195 return r;
1198 static UINT fetch_user_component( const WCHAR *usersid, DWORD ctx, DWORD index, DWORD *idx,
1199 WCHAR guid[39], MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid,
1200 LPDWORD sid_len )
1202 UINT r = ERROR_SUCCESS;
1203 WCHAR path[MAX_PATH], component[SQUASHED_GUID_SIZE], user[128];
1204 DWORD i = 0, j = 0, len_component, len_user;
1205 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
1206 HKEY key_users, key_components;
1208 if (ctx == MSIINSTALLCONTEXT_USERMANAGED) /* FIXME: where to find these? */
1209 return ERROR_NO_MORE_ITEMS;
1211 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData",
1212 0, access, &key_users )) return ERROR_NO_MORE_ITEMS;
1214 len_user = ARRAY_SIZE( user );
1215 while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
1217 if ((wcscmp( usersid, L"S-1-1-0" ) && wcscmp( usersid, user )) ||
1218 !wcscmp( L"S-1-5-18", user ))
1220 i++;
1221 len_user = ARRAY_SIZE( user );
1222 continue;
1224 lstrcpyW( path, user );
1225 lstrcatW( path, L"\\Components" );
1226 if (RegOpenKeyExW( key_users, path, 0, access, &key_components ))
1228 i++;
1229 len_user = ARRAY_SIZE( user );
1230 continue;
1232 len_component = ARRAY_SIZE( component );
1233 while (!RegEnumKeyExW( key_components, j, component, &len_component, NULL, NULL, NULL, NULL ))
1235 if (*idx == index) goto found;
1236 (*idx)++;
1237 len_component = ARRAY_SIZE( component );
1238 j++;
1240 RegCloseKey( key_components );
1241 len_user = ARRAY_SIZE( user );
1242 i++;
1244 RegCloseKey( key_users );
1245 return ERROR_NO_MORE_ITEMS;
1247 found:
1248 if (sid_len)
1250 if (*sid_len < len_user + 1)
1252 *sid_len = len_user + 1;
1253 r = ERROR_MORE_DATA;
1255 else if (sid)
1257 *sid_len = len_user;
1258 lstrcpyW( sid, user );
1261 if (guid) unsquash_guid( component, guid );
1262 if (installed_ctx) *installed_ctx = ctx;
1263 RegCloseKey( key_components );
1264 RegCloseKey( key_users );
1265 return r;
1268 static UINT enum_components( const WCHAR *usersid, DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
1269 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1271 UINT r = ERROR_NO_MORE_ITEMS;
1272 WCHAR *user = NULL;
1274 if (!usersid)
1276 usersid = user = get_user_sid();
1277 if (!user) return ERROR_FUNCTION_FAILED;
1279 if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
1281 r = fetch_user_component( usersid, MSIINSTALLCONTEXT_USERMANAGED, index, idx, guid,
1282 installed_ctx, sid, sid_len );
1283 if (r != ERROR_NO_MORE_ITEMS) goto done;
1285 if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
1287 r = fetch_user_component( usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index, idx, guid,
1288 installed_ctx, sid, sid_len );
1289 if (r != ERROR_NO_MORE_ITEMS) goto done;
1291 if (ctx & MSIINSTALLCONTEXT_MACHINE)
1293 r = fetch_machine_component( MSIINSTALLCONTEXT_MACHINE, index, idx, guid, installed_ctx,
1294 sid, sid_len );
1295 if (r != ERROR_NO_MORE_ITEMS) goto done;
1298 done:
1299 LocalFree( user );
1300 return r;
1303 UINT WINAPI MsiEnumComponentsExW( LPCWSTR user_sid, DWORD ctx, DWORD index, WCHAR guid[39],
1304 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1306 UINT r;
1307 DWORD idx = 0;
1308 static DWORD last_index;
1310 TRACE("%s, %u, %u, %p, %p, %p, %p\n", debugstr_w(user_sid), ctx, index, guid, installed_ctx,
1311 sid, sid_len);
1313 if ((sid && !sid_len) || !ctx || (user_sid && ctx == MSIINSTALLCONTEXT_MACHINE))
1314 return ERROR_INVALID_PARAMETER;
1316 if (index && index - last_index != 1)
1317 return ERROR_INVALID_PARAMETER;
1319 if (!index) last_index = 0;
1321 r = enum_components( user_sid, ctx, index, &idx, guid, installed_ctx, sid, sid_len );
1322 if (r == ERROR_SUCCESS)
1323 last_index = index;
1324 else
1325 last_index = 0;
1327 return r;
1330 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
1332 DWORD r;
1333 WCHAR szwProduct[GUID_SIZE];
1334 LPWSTR szwComponent = NULL;
1336 TRACE("%s %d %p\n", debugstr_a(szComponent), index, szProduct);
1338 if ( !szProduct )
1339 return ERROR_INVALID_PARAMETER;
1341 if( szComponent )
1343 szwComponent = strdupAtoW( szComponent );
1344 if( !szwComponent )
1345 return ERROR_OUTOFMEMORY;
1348 r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
1349 if( r == ERROR_SUCCESS )
1351 WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
1352 szProduct, GUID_SIZE, NULL, NULL);
1355 msi_free( szwComponent);
1357 return r;
1360 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
1362 HKEY hkeyComp = 0;
1363 DWORD r, sz;
1364 WCHAR szValName[SQUASHED_GUID_SIZE];
1366 TRACE("%s %d %p\n", debugstr_w(szComponent), index, szProduct);
1368 if (!szComponent || !*szComponent || !szProduct)
1369 return ERROR_INVALID_PARAMETER;
1371 if (MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkeyComp, FALSE) != ERROR_SUCCESS &&
1372 MSIREG_OpenUserDataComponentKey(szComponent, L"S-1-5-18", &hkeyComp, FALSE) != ERROR_SUCCESS)
1373 return ERROR_UNKNOWN_COMPONENT;
1375 /* see if there are any products at all */
1376 sz = SQUASHED_GUID_SIZE;
1377 r = RegEnumValueW(hkeyComp, 0, szValName, &sz, NULL, NULL, NULL, NULL);
1378 if (r != ERROR_SUCCESS)
1380 RegCloseKey(hkeyComp);
1382 if (index != 0)
1383 return ERROR_INVALID_PARAMETER;
1385 return ERROR_UNKNOWN_COMPONENT;
1388 sz = SQUASHED_GUID_SIZE;
1389 r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
1390 if( r == ERROR_SUCCESS )
1392 unsquash_guid(szValName, szProduct);
1393 TRACE("-> %s\n", debugstr_w(szProduct));
1395 RegCloseKey(hkeyComp);
1396 return r;
1399 UINT WINAPI MsiEnumClientsExA(LPCSTR component, LPCSTR usersid, DWORD ctx, DWORD index,
1400 CHAR installed_product[GUID_SIZE],
1401 MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len)
1403 FIXME("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_a(component), debugstr_a(usersid),
1404 ctx, index, installed_product, installed_ctx, sid, sid_len);
1405 return ERROR_ACCESS_DENIED;
1408 UINT WINAPI MsiEnumClientsExW(LPCWSTR component, LPCWSTR usersid, DWORD ctx, DWORD index,
1409 WCHAR installed_product[GUID_SIZE],
1410 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len)
1412 FIXME("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_w(component), debugstr_w(usersid),
1413 ctx, index, installed_product, installed_ctx, sid, sid_len);
1414 return ERROR_ACCESS_DENIED;
1417 static UINT MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
1418 awstring *lpQualBuf, LPDWORD pcchQual,
1419 awstring *lpAppBuf, LPDWORD pcchAppBuf )
1421 DWORD name_sz, val_sz, name_max, val_max, type, ofs;
1422 LPWSTR name = NULL, val = NULL;
1423 UINT r, r2;
1424 HKEY key;
1426 TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1427 lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
1429 if (!szComponent)
1430 return ERROR_INVALID_PARAMETER;
1432 r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1433 if (r != ERROR_SUCCESS)
1434 return ERROR_UNKNOWN_COMPONENT;
1436 /* figure out how big the name is we want to return */
1437 name_max = 0x10;
1438 r = ERROR_OUTOFMEMORY;
1439 name = msi_alloc( name_max * sizeof(WCHAR) );
1440 if (!name)
1441 goto end;
1443 val_max = 0x10;
1444 r = ERROR_OUTOFMEMORY;
1445 val = msi_alloc( val_max );
1446 if (!val)
1447 goto end;
1449 /* loop until we allocate enough memory */
1450 while (1)
1452 name_sz = name_max;
1453 val_sz = val_max;
1454 r = RegEnumValueW( key, iIndex, name, &name_sz,
1455 NULL, &type, (LPBYTE)val, &val_sz );
1456 if (r == ERROR_SUCCESS)
1457 break;
1458 if (r != ERROR_MORE_DATA)
1459 goto end;
1461 if (type != REG_MULTI_SZ)
1463 ERR("component data has wrong type (%d)\n", type);
1464 goto end;
1467 r = ERROR_OUTOFMEMORY;
1468 if (name_sz + 1 >= name_max)
1470 name_max *= 2;
1471 msi_free( name );
1472 name = msi_alloc( name_max * sizeof (WCHAR) );
1473 if (!name)
1474 goto end;
1475 continue;
1477 if (val_sz > val_max)
1479 val_max = val_sz + sizeof (WCHAR);
1480 msi_free( val );
1481 val = msi_alloc( val_max * sizeof (WCHAR) );
1482 if (!val)
1483 goto end;
1484 continue;
1486 ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz );
1487 goto end;
1490 ofs = 0;
1491 r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1492 if (r != ERROR_SUCCESS)
1493 goto end;
1495 TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1497 r = msi_strcpy_to_awstring( name, -1, lpQualBuf, pcchQual );
1498 r2 = msi_strcpy_to_awstring( val+ofs, -1, lpAppBuf, pcchAppBuf );
1500 if (r2 != ERROR_SUCCESS)
1501 r = r2;
1503 end:
1504 msi_free(val);
1505 msi_free(name);
1506 RegCloseKey(key);
1507 return r;
1510 /*************************************************************************
1511 * MsiEnumComponentQualifiersA [MSI.@]
1513 UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
1514 LPSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1515 LPSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1517 awstring qual, appdata;
1518 LPWSTR comp;
1519 UINT r;
1521 TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex,
1522 lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1523 pcchApplicationDataBuf);
1525 comp = strdupAtoW( szComponent );
1526 if (szComponent && !comp)
1527 return ERROR_OUTOFMEMORY;
1529 qual.unicode = FALSE;
1530 qual.str.a = lpQualifierBuf;
1532 appdata.unicode = FALSE;
1533 appdata.str.a = lpApplicationDataBuf;
1535 r = MSI_EnumComponentQualifiers( comp, iIndex,
1536 &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1537 msi_free( comp );
1538 return r;
1541 /*************************************************************************
1542 * MsiEnumComponentQualifiersW [MSI.@]
1544 UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
1545 LPWSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1546 LPWSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1548 awstring qual, appdata;
1550 TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1551 lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1552 pcchApplicationDataBuf);
1554 qual.unicode = TRUE;
1555 qual.str.w = lpQualifierBuf;
1557 appdata.unicode = TRUE;
1558 appdata.str.w = lpApplicationDataBuf;
1560 return MSI_EnumComponentQualifiers( szComponent, iIndex,
1561 &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1564 /*************************************************************************
1565 * MsiEnumRelatedProductsW [MSI.@]
1568 UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,
1569 DWORD iProductIndex, LPWSTR lpProductBuf)
1571 UINT r;
1572 HKEY hkey;
1573 WCHAR szKeyName[SQUASHED_GUID_SIZE];
1574 DWORD dwSize = ARRAY_SIZE(szKeyName);
1576 TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved,
1577 iProductIndex, lpProductBuf);
1579 if (NULL == szUpgradeCode)
1580 return ERROR_INVALID_PARAMETER;
1581 if (NULL == lpProductBuf)
1582 return ERROR_INVALID_PARAMETER;
1584 r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1585 if (r != ERROR_SUCCESS)
1586 return ERROR_NO_MORE_ITEMS;
1588 r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1589 if( r == ERROR_SUCCESS )
1590 unsquash_guid(szKeyName, lpProductBuf);
1591 RegCloseKey(hkey);
1593 return r;
1596 /*************************************************************************
1597 * MsiEnumRelatedProductsA [MSI.@]
1600 UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
1601 DWORD iProductIndex, LPSTR lpProductBuf)
1603 LPWSTR szwUpgradeCode = NULL;
1604 WCHAR productW[GUID_SIZE];
1605 UINT r;
1607 TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved,
1608 iProductIndex, lpProductBuf);
1610 if (szUpgradeCode)
1612 szwUpgradeCode = strdupAtoW( szUpgradeCode );
1613 if( !szwUpgradeCode )
1614 return ERROR_OUTOFMEMORY;
1617 r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1618 iProductIndex, productW );
1619 if (r == ERROR_SUCCESS)
1621 WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1622 lpProductBuf, GUID_SIZE, NULL, NULL );
1624 msi_free( szwUpgradeCode);
1625 return r;
1628 /***********************************************************************
1629 * MsiEnumPatchesExA [MSI.@]
1631 UINT WINAPI MsiEnumPatchesExA(LPCSTR szProductCode, LPCSTR szUserSid,
1632 DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPSTR szPatchCode,
1633 LPSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
1634 LPSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
1636 LPWSTR prodcode = NULL;
1637 LPWSTR usersid = NULL;
1638 LPWSTR targsid = NULL;
1639 WCHAR patch[GUID_SIZE];
1640 WCHAR targprod[GUID_SIZE];
1641 DWORD len;
1642 UINT r;
1644 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
1645 debugstr_a(szProductCode), debugstr_a(szUserSid), dwContext, dwFilter,
1646 dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
1647 szTargetUserSid, pcchTargetUserSid);
1649 if (szTargetUserSid && !pcchTargetUserSid)
1650 return ERROR_INVALID_PARAMETER;
1652 if (szProductCode) prodcode = strdupAtoW(szProductCode);
1653 if (szUserSid) usersid = strdupAtoW(szUserSid);
1655 r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1656 patch, targprod, pdwTargetProductContext,
1657 NULL, &len);
1658 if (r != ERROR_SUCCESS)
1659 goto done;
1661 WideCharToMultiByte(CP_ACP, 0, patch, -1, szPatchCode,
1662 GUID_SIZE, NULL, NULL);
1663 WideCharToMultiByte(CP_ACP, 0, targprod, -1, szTargetProductCode,
1664 GUID_SIZE, NULL, NULL);
1666 if (!szTargetUserSid)
1668 if (pcchTargetUserSid)
1669 *pcchTargetUserSid = len;
1671 goto done;
1674 targsid = msi_alloc(++len * sizeof(WCHAR));
1675 if (!targsid)
1677 r = ERROR_OUTOFMEMORY;
1678 goto done;
1681 r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1682 patch, targprod, pdwTargetProductContext,
1683 targsid, &len);
1684 if (r != ERROR_SUCCESS || !szTargetUserSid)
1685 goto done;
1687 WideCharToMultiByte(CP_ACP, 0, targsid, -1, szTargetUserSid,
1688 *pcchTargetUserSid, NULL, NULL);
1690 len = lstrlenW(targsid);
1691 if (*pcchTargetUserSid < len + 1)
1693 r = ERROR_MORE_DATA;
1694 *pcchTargetUserSid = len * sizeof(WCHAR);
1696 else
1697 *pcchTargetUserSid = len;
1699 done:
1700 msi_free(prodcode);
1701 msi_free(usersid);
1702 msi_free(targsid);
1704 return r;
1707 static UINT msi_get_patch_state(LPCWSTR prodcode, LPCWSTR usersid,
1708 MSIINSTALLCONTEXT context,
1709 LPWSTR patch, MSIPATCHSTATE *state)
1711 DWORD type, val, size;
1712 HKEY prod, hkey = 0;
1713 HKEY udpatch = 0;
1714 LONG res;
1715 UINT r = ERROR_NO_MORE_ITEMS;
1717 *state = MSIPATCHSTATE_INVALID;
1719 r = MSIREG_OpenUserDataProductKey(prodcode, context,
1720 usersid, &prod, FALSE);
1721 if (r != ERROR_SUCCESS)
1722 return ERROR_NO_MORE_ITEMS;
1724 res = RegOpenKeyExW(prod, L"Patches", 0, KEY_READ, &hkey);
1725 if (res != ERROR_SUCCESS)
1726 goto done;
1728 res = RegOpenKeyExW(hkey, patch, 0, KEY_READ, &udpatch);
1729 if (res != ERROR_SUCCESS)
1730 goto done;
1732 size = sizeof(DWORD);
1733 res = RegGetValueW(udpatch, NULL, L"State", RRF_RT_DWORD, &type, &val, &size);
1734 if (res != ERROR_SUCCESS ||
1735 val < MSIPATCHSTATE_APPLIED || val > MSIPATCHSTATE_REGISTERED)
1737 r = ERROR_BAD_CONFIGURATION;
1738 goto done;
1741 *state = val;
1742 r = ERROR_SUCCESS;
1744 done:
1745 RegCloseKey(udpatch);
1746 RegCloseKey(hkey);
1747 RegCloseKey(prod);
1749 return r;
1752 static UINT msi_check_product_patches(LPCWSTR prodcode, LPCWSTR usersid,
1753 MSIINSTALLCONTEXT context, DWORD filter, DWORD index, DWORD *idx,
1754 LPWSTR patch, LPWSTR targetprod, MSIINSTALLCONTEXT *targetctx,
1755 LPWSTR targetsid, DWORD *sidsize, LPWSTR *transforms)
1757 MSIPATCHSTATE state = MSIPATCHSTATE_INVALID;
1758 LPWSTR ptr, patches = NULL;
1759 HKEY prod, patchkey = 0;
1760 HKEY localprod = 0, localpatch = 0;
1761 DWORD type, size;
1762 LONG res;
1763 UINT temp, r = ERROR_NO_MORE_ITEMS;
1765 if (MSIREG_OpenProductKey(prodcode, usersid, context,
1766 &prod, FALSE) != ERROR_SUCCESS)
1767 return ERROR_NO_MORE_ITEMS;
1769 size = 0;
1770 res = RegGetValueW(prod, L"Patches", L"Patches", RRF_RT_ANY, &type, NULL,
1771 &size);
1772 if (res != ERROR_SUCCESS)
1773 goto done;
1775 if (type != REG_MULTI_SZ)
1777 r = ERROR_BAD_CONFIGURATION;
1778 goto done;
1781 patches = msi_alloc(size);
1782 if (!patches)
1784 r = ERROR_OUTOFMEMORY;
1785 goto done;
1788 res = RegGetValueW(prod, L"Patches", L"Patches", RRF_RT_ANY, &type,
1789 patches, &size);
1790 if (res != ERROR_SUCCESS)
1791 goto done;
1793 for (ptr = patches; *ptr && r == ERROR_NO_MORE_ITEMS; ptr += lstrlenW(ptr) + 1)
1795 if (!unsquash_guid(ptr, patch))
1797 r = ERROR_BAD_CONFIGURATION;
1798 goto done;
1801 size = 0;
1802 res = RegGetValueW(prod, L"Patches", ptr, RRF_RT_REG_SZ,
1803 &type, NULL, &size);
1804 if (res != ERROR_SUCCESS)
1805 continue;
1807 if (transforms)
1809 *transforms = msi_alloc(size);
1810 if (!*transforms)
1812 r = ERROR_OUTOFMEMORY;
1813 goto done;
1816 res = RegGetValueW(prod, L"Patches", ptr, RRF_RT_REG_SZ,
1817 &type, *transforms, &size);
1818 if (res != ERROR_SUCCESS)
1819 continue;
1822 if (context == MSIINSTALLCONTEXT_USERMANAGED)
1824 if (!(filter & MSIPATCHSTATE_APPLIED))
1826 temp = msi_get_patch_state(prodcode, usersid, context,
1827 ptr, &state);
1828 if (temp == ERROR_BAD_CONFIGURATION)
1830 r = ERROR_BAD_CONFIGURATION;
1831 goto done;
1834 if (temp != ERROR_SUCCESS || !(filter & state))
1835 continue;
1838 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
1840 if (!(filter & MSIPATCHSTATE_APPLIED))
1842 temp = msi_get_patch_state(prodcode, usersid, context,
1843 ptr, &state);
1844 if (temp == ERROR_BAD_CONFIGURATION)
1846 r = ERROR_BAD_CONFIGURATION;
1847 goto done;
1850 if (temp != ERROR_SUCCESS || !(filter & state))
1851 continue;
1853 else
1855 temp = MSIREG_OpenUserDataPatchKey(patch, context,
1856 &patchkey, FALSE);
1857 RegCloseKey(patchkey);
1858 if (temp != ERROR_SUCCESS)
1859 continue;
1862 else if (context == MSIINSTALLCONTEXT_MACHINE)
1864 usersid = L"";
1866 if (MSIREG_OpenUserDataProductKey(prodcode, context, NULL, &localprod, FALSE) == ERROR_SUCCESS &&
1867 RegOpenKeyExW(localprod, L"Patches", 0, KEY_READ, &localpatch) == ERROR_SUCCESS &&
1868 RegOpenKeyExW(localpatch, ptr, 0, KEY_READ, &patchkey) == ERROR_SUCCESS)
1870 res = RegGetValueW(patchkey, NULL, L"State", RRF_RT_REG_DWORD,
1871 &type, &state, &size);
1873 if (!(filter & state))
1874 res = ERROR_NO_MORE_ITEMS;
1876 RegCloseKey(patchkey);
1879 RegCloseKey(localpatch);
1880 RegCloseKey(localprod);
1882 if (res != ERROR_SUCCESS)
1883 continue;
1886 if (*idx < index)
1888 (*idx)++;
1889 continue;
1892 r = ERROR_SUCCESS;
1893 if (targetprod)
1894 lstrcpyW(targetprod, prodcode);
1896 if (targetctx)
1897 *targetctx = context;
1899 if (targetsid)
1901 lstrcpynW(targetsid, usersid, *sidsize);
1902 if (lstrlenW(usersid) >= *sidsize)
1903 r = ERROR_MORE_DATA;
1906 if (sidsize)
1908 *sidsize = lstrlenW(usersid);
1909 if (!targetsid)
1910 *sidsize *= sizeof(WCHAR);
1914 done:
1915 RegCloseKey(prod);
1916 msi_free(patches);
1918 return r;
1921 static UINT msi_enum_patches(LPCWSTR szProductCode, LPCWSTR szUserSid,
1922 DWORD dwContext, DWORD dwFilter, DWORD dwIndex, DWORD *idx,
1923 LPWSTR szPatchCode, LPWSTR szTargetProductCode,
1924 MSIINSTALLCONTEXT *pdwTargetProductContext, LPWSTR szTargetUserSid,
1925 LPDWORD pcchTargetUserSid, LPWSTR *szTransforms)
1927 LPWSTR usersid = NULL;
1928 UINT r = ERROR_INVALID_PARAMETER;
1930 if (!szUserSid)
1932 szUserSid = usersid = get_user_sid();
1933 if (!usersid) return ERROR_FUNCTION_FAILED;
1936 if (dwContext & MSIINSTALLCONTEXT_USERMANAGED)
1938 r = msi_check_product_patches(szProductCode, szUserSid,
1939 MSIINSTALLCONTEXT_USERMANAGED, dwFilter,
1940 dwIndex, idx, szPatchCode,
1941 szTargetProductCode,
1942 pdwTargetProductContext, szTargetUserSid,
1943 pcchTargetUserSid, szTransforms);
1944 if (r != ERROR_NO_MORE_ITEMS)
1945 goto done;
1948 if (dwContext & MSIINSTALLCONTEXT_USERUNMANAGED)
1950 r = msi_check_product_patches(szProductCode, szUserSid,
1951 MSIINSTALLCONTEXT_USERUNMANAGED, dwFilter,
1952 dwIndex, idx, szPatchCode,
1953 szTargetProductCode,
1954 pdwTargetProductContext, szTargetUserSid,
1955 pcchTargetUserSid, szTransforms);
1956 if (r != ERROR_NO_MORE_ITEMS)
1957 goto done;
1960 if (dwContext & MSIINSTALLCONTEXT_MACHINE)
1962 r = msi_check_product_patches(szProductCode, szUserSid,
1963 MSIINSTALLCONTEXT_MACHINE, dwFilter,
1964 dwIndex, idx, szPatchCode,
1965 szTargetProductCode,
1966 pdwTargetProductContext, szTargetUserSid,
1967 pcchTargetUserSid, szTransforms);
1968 if (r != ERROR_NO_MORE_ITEMS)
1969 goto done;
1972 done:
1973 LocalFree(usersid);
1974 return r;
1977 /***********************************************************************
1978 * MsiEnumPatchesExW [MSI.@]
1980 UINT WINAPI MsiEnumPatchesExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
1981 DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPWSTR szPatchCode,
1982 LPWSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
1983 LPWSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
1985 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
1986 DWORD idx = 0;
1987 UINT r;
1989 static DWORD last_index;
1991 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
1992 debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext, dwFilter,
1993 dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
1994 szTargetUserSid, pcchTargetUserSid);
1996 if (!szProductCode || !squash_guid( szProductCode, squashed_pc ))
1997 return ERROR_INVALID_PARAMETER;
1999 if (szUserSid && !wcscmp( szUserSid, L"S-1-5-18" ))
2000 return ERROR_INVALID_PARAMETER;
2002 if (dwContext & MSIINSTALLCONTEXT_MACHINE && szUserSid)
2003 return ERROR_INVALID_PARAMETER;
2005 if (dwContext <= MSIINSTALLCONTEXT_NONE ||
2006 dwContext > MSIINSTALLCONTEXT_ALL)
2007 return ERROR_INVALID_PARAMETER;
2009 if (dwFilter <= MSIPATCHSTATE_INVALID || dwFilter > MSIPATCHSTATE_ALL)
2010 return ERROR_INVALID_PARAMETER;
2012 if (dwIndex && dwIndex - last_index != 1)
2013 return ERROR_INVALID_PARAMETER;
2015 if (dwIndex == 0)
2016 last_index = 0;
2018 r = msi_enum_patches(szProductCode, szUserSid, dwContext, dwFilter,
2019 dwIndex, &idx, szPatchCode, szTargetProductCode,
2020 pdwTargetProductContext, szTargetUserSid,
2021 pcchTargetUserSid, NULL);
2023 if (r == ERROR_SUCCESS)
2024 last_index = dwIndex;
2025 else
2026 last_index = 0;
2028 return r;
2031 /***********************************************************************
2032 * MsiEnumPatchesA [MSI.@]
2034 UINT WINAPI MsiEnumPatchesA(LPCSTR szProduct, DWORD iPatchIndex,
2035 LPSTR lpPatchBuf, LPSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
2037 LPWSTR product, transforms;
2038 WCHAR patch[GUID_SIZE];
2039 DWORD len;
2040 UINT r;
2042 TRACE("(%s %d %p %p %p)\n", debugstr_a(szProduct), iPatchIndex,
2043 lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
2045 if (!szProduct || !lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2046 return ERROR_INVALID_PARAMETER;
2048 product = strdupAtoW(szProduct);
2049 if (!product)
2050 return ERROR_OUTOFMEMORY;
2052 len = *pcchTransformsBuf;
2053 transforms = msi_alloc( len * sizeof(WCHAR) );
2054 if (!transforms)
2056 r = ERROR_OUTOFMEMORY;
2057 goto done;
2060 r = MsiEnumPatchesW(product, iPatchIndex, patch, transforms, &len);
2061 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2062 goto done;
2064 WideCharToMultiByte(CP_ACP, 0, patch, -1, lpPatchBuf,
2065 GUID_SIZE, NULL, NULL);
2067 if (!WideCharToMultiByte(CP_ACP, 0, transforms, -1, lpTransformsBuf,
2068 *pcchTransformsBuf, NULL, NULL))
2069 r = ERROR_MORE_DATA;
2071 if (r == ERROR_MORE_DATA)
2073 lpTransformsBuf[*pcchTransformsBuf - 1] = '\0';
2074 *pcchTransformsBuf = len * 2;
2076 else
2077 *pcchTransformsBuf = strlen( lpTransformsBuf );
2079 done:
2080 msi_free(transforms);
2081 msi_free(product);
2083 return r;
2086 /***********************************************************************
2087 * MsiEnumPatchesW [MSI.@]
2089 UINT WINAPI MsiEnumPatchesW(LPCWSTR szProduct, DWORD iPatchIndex,
2090 LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
2092 WCHAR *transforms = NULL, squashed_pc[SQUASHED_GUID_SIZE];
2093 HKEY prod;
2094 DWORD idx = 0;
2095 UINT r;
2097 TRACE("(%s %d %p %p %p)\n", debugstr_w(szProduct), iPatchIndex,
2098 lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
2100 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
2101 return ERROR_INVALID_PARAMETER;
2103 if (!lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2104 return ERROR_INVALID_PARAMETER;
2106 if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2107 &prod, FALSE) != ERROR_SUCCESS &&
2108 MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2109 &prod, FALSE) != ERROR_SUCCESS &&
2110 MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2111 &prod, FALSE) != ERROR_SUCCESS)
2112 return ERROR_UNKNOWN_PRODUCT;
2114 RegCloseKey(prod);
2116 r = msi_enum_patches(szProduct, NULL, MSIINSTALLCONTEXT_ALL,
2117 MSIPATCHSTATE_ALL, iPatchIndex, &idx, lpPatchBuf,
2118 NULL, NULL, NULL, NULL, &transforms);
2119 if (r != ERROR_SUCCESS)
2120 goto done;
2122 lstrcpynW(lpTransformsBuf, transforms, *pcchTransformsBuf);
2123 if (*pcchTransformsBuf <= lstrlenW(transforms))
2125 r = ERROR_MORE_DATA;
2126 *pcchTransformsBuf = lstrlenW(transforms);
2128 else
2129 *pcchTransformsBuf = lstrlenW(transforms);
2131 done:
2132 msi_free(transforms);
2133 return r;
2136 UINT WINAPI MsiEnumProductsExA( LPCSTR product, LPCSTR usersid, DWORD ctx, DWORD index,
2137 CHAR installed_product[GUID_SIZE],
2138 MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len )
2140 UINT r;
2141 WCHAR installed_productW[GUID_SIZE], *productW = NULL, *usersidW = NULL, *sidW = NULL;
2143 TRACE("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_a(product), debugstr_a(usersid),
2144 ctx, index, installed_product, installed_ctx, sid, sid_len);
2146 if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
2147 if (product && !(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
2148 if (usersid && !(usersidW = strdupAtoW( usersid )))
2150 msi_free( productW );
2151 return ERROR_OUTOFMEMORY;
2153 if (sid && !(sidW = msi_alloc( *sid_len * sizeof(WCHAR) )))
2155 msi_free( usersidW );
2156 msi_free( productW );
2157 return ERROR_OUTOFMEMORY;
2159 r = MsiEnumProductsExW( productW, usersidW, ctx, index, installed_productW,
2160 installed_ctx, sidW, sid_len );
2161 if (r == ERROR_SUCCESS)
2163 if (installed_product) WideCharToMultiByte( CP_ACP, 0, installed_productW, GUID_SIZE,
2164 installed_product, GUID_SIZE, NULL, NULL );
2165 if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
2167 msi_free( productW );
2168 msi_free( usersidW );
2169 msi_free( sidW );
2170 return r;
2173 static UINT fetch_machine_product( const WCHAR *match, DWORD index, DWORD *idx,
2174 WCHAR installed_product[GUID_SIZE],
2175 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2177 UINT r;
2178 WCHAR product[SQUASHED_GUID_SIZE];
2179 DWORD i = 0, len;
2180 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
2181 HKEY key;
2183 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Classes\\Installer\\Products", 0, access, &key ))
2184 return ERROR_NO_MORE_ITEMS;
2186 len = ARRAY_SIZE( product );
2187 while (!RegEnumKeyExW( key, i, product, &len, NULL, NULL, NULL, NULL ))
2189 if (match && wcscmp( match, product ))
2191 i++;
2192 len = ARRAY_SIZE( product );
2193 continue;
2195 if (*idx == index) goto found;
2196 (*idx)++;
2197 len = ARRAY_SIZE( product );
2198 i++;
2200 RegCloseKey( key );
2201 return ERROR_NO_MORE_ITEMS;
2203 found:
2204 if (sid_len && *sid_len < 1)
2206 *sid_len = 1;
2207 r = ERROR_MORE_DATA;
2209 else
2211 if (installed_product) unsquash_guid( product, installed_product );
2212 if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
2213 if (sid)
2215 sid[0] = 0;
2216 *sid_len = 0;
2218 r = ERROR_SUCCESS;
2220 RegCloseKey( key );
2221 return r;
2224 static UINT fetch_user_product( const WCHAR *match, const WCHAR *usersid, DWORD ctx, DWORD index,
2225 DWORD *idx, WCHAR installed_product[GUID_SIZE],
2226 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2228 UINT r;
2229 const WCHAR *subkey;
2230 WCHAR path[MAX_PATH], product[SQUASHED_GUID_SIZE], user[128];
2231 DWORD i = 0, j = 0, len_product, len_user;
2232 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
2233 HKEY key_users, key_products;
2235 if (ctx == MSIINSTALLCONTEXT_USERMANAGED)
2237 subkey = L"\\Installer\\Products";
2238 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed",
2239 0, access, &key_users )) return ERROR_NO_MORE_ITEMS;
2241 else if (ctx == MSIINSTALLCONTEXT_USERUNMANAGED)
2243 subkey = L"\\Software\\Microsoft\\Installer\\Products";
2244 if (RegOpenKeyExW( HKEY_USERS, NULL, 0, access, &key_users ))
2245 return ERROR_NO_MORE_ITEMS;
2247 else return ERROR_INVALID_PARAMETER;
2249 len_user = ARRAY_SIZE( user );
2250 while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
2252 if (wcscmp( usersid, user ) && wcscmp( usersid, L"S-1-1-0" ))
2254 i++;
2255 len_user = ARRAY_SIZE( user );
2256 continue;
2258 lstrcpyW( path, user );
2259 lstrcatW( path, subkey );
2260 if (RegOpenKeyExW( key_users, path, 0, access, &key_products ))
2262 i++;
2263 len_user = ARRAY_SIZE( user );
2264 continue;
2266 len_product = ARRAY_SIZE( product );
2267 while (!RegEnumKeyExW( key_products, j, product, &len_product, NULL, NULL, NULL, NULL ))
2269 if (match && wcscmp( match, product ))
2271 j++;
2272 len_product = ARRAY_SIZE( product );
2273 continue;
2275 if (*idx == index) goto found;
2276 (*idx)++;
2277 len_product = ARRAY_SIZE( product );
2278 j++;
2280 RegCloseKey( key_products );
2281 len_user = ARRAY_SIZE( user );
2282 i++;
2284 RegCloseKey( key_users );
2285 return ERROR_NO_MORE_ITEMS;
2287 found:
2288 if (sid_len && *sid_len <= len_user)
2290 *sid_len = len_user;
2291 r = ERROR_MORE_DATA;
2293 else
2295 if (installed_product) unsquash_guid( product, installed_product );
2296 if (installed_ctx) *installed_ctx = ctx;
2297 if (sid)
2299 lstrcpyW( sid, user );
2300 *sid_len = len_user;
2302 r = ERROR_SUCCESS;
2304 RegCloseKey( key_products );
2305 RegCloseKey( key_users );
2306 return r;
2309 static UINT enum_products( const WCHAR *product, const WCHAR *usersid, DWORD ctx, DWORD index,
2310 DWORD *idx, WCHAR installed_product[GUID_SIZE],
2311 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2313 UINT r = ERROR_NO_MORE_ITEMS;
2314 WCHAR *user = NULL;
2316 if (!usersid)
2318 usersid = user = get_user_sid();
2319 if (!user) return ERROR_FUNCTION_FAILED;
2321 if (ctx & MSIINSTALLCONTEXT_MACHINE)
2323 r = fetch_machine_product( product, index, idx, installed_product, installed_ctx,
2324 sid, sid_len );
2325 if (r != ERROR_NO_MORE_ITEMS) goto done;
2327 if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
2329 r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index,
2330 idx, installed_product, installed_ctx, sid, sid_len );
2331 if (r != ERROR_NO_MORE_ITEMS) goto done;
2333 if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
2335 r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERMANAGED, index,
2336 idx, installed_product, installed_ctx, sid, sid_len );
2337 if (r != ERROR_NO_MORE_ITEMS) goto done;
2340 done:
2341 LocalFree( user );
2342 return r;
2345 UINT WINAPI MsiEnumProductsExW( LPCWSTR product, LPCWSTR usersid, DWORD ctx, DWORD index,
2346 WCHAR installed_product[GUID_SIZE],
2347 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
2349 UINT r;
2350 DWORD idx = 0;
2351 static DWORD last_index;
2353 TRACE("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_w(product), debugstr_w(usersid),
2354 ctx, index, installed_product, installed_ctx, sid, sid_len);
2356 if ((sid && !sid_len) || !ctx || (usersid && ctx == MSIINSTALLCONTEXT_MACHINE))
2357 return ERROR_INVALID_PARAMETER;
2359 if (index && index - last_index != 1)
2360 return ERROR_INVALID_PARAMETER;
2362 if (!index) last_index = 0;
2364 r = enum_products( product, usersid, ctx, index, &idx, installed_product, installed_ctx,
2365 sid, sid_len );
2366 if (r == ERROR_SUCCESS)
2367 last_index = index;
2368 else
2369 last_index = 0;
2371 return r;