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
31 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
41 BOOL
unsquash_guid(LPCWSTR in
, LPWSTR out
)
45 if (lstrlenW(in
) != 32)
60 out
[n
++] = in
[17+i
*2];
61 out
[n
++] = in
[16+i
*2];
66 out
[n
++] = in
[17+i
*2];
67 out
[n
++] = in
[16+i
*2];
74 BOOL
squash_guid(LPCWSTR in
, LPWSTR out
)
81 if (FAILED(CLSIDFromString((LPCOLESTR
)in
, &guid
)))
95 out
[17+i
*2] = in
[n
++];
96 out
[16+i
*2] = in
[n
++];
101 out
[17+i
*2] = in
[n
++];
102 out
[16+i
*2] = in
[n
++];
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"
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
;
140 for( i
=0; i
<20; i
++ )
147 val
+= table_dec85
[str
[i
]] * base
;
150 if( table_dec85
[str
[i
]] == 0xff )
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
;
173 *str
++ = table_enc85
[x
%85];
175 *str
++ = table_enc85
[x
%85];
177 *str
++ = table_enc85
[x
%85];
179 *str
++ = table_enc85
[x
%85];
181 *str
++ = table_enc85
[x
%85];
188 DWORD
msi_version_str_to_dword(LPCWSTR p
)
190 DWORD major
, minor
= 0, build
= 0, version
= 0;
195 major
= wcstol(p
, NULL
, 10);
200 minor
= wcstol(p
+1, NULL
, 10);
201 p
= wcschr(p
+1, '.');
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
)
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
)
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
)
235 r
= RegCreateKeyW( hkey
, path
, &hsubkey
);
236 if (r
!= ERROR_SUCCESS
)
238 r
= msi_reg_set_val_str( hsubkey
, name
, val
);
239 RegCloseKey( hsubkey
);
243 LPWSTR
msi_reg_get_val_str( HKEY hkey
, LPCWSTR name
)
249 r
= RegQueryValueExW(hkey
, name
, NULL
, NULL
, NULL
, &len
);
250 if (r
!= ERROR_SUCCESS
)
253 len
+= sizeof (WCHAR
);
258 RegQueryValueExW(hkey
, name
, NULL
, NULL
, (LPBYTE
) val
, &len
);
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)
276 if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY
, &token
)) return NULL
;
277 if (!(user
= malloc( size
)))
279 CloseHandle( token
);
282 if (!GetTokenInformation( token
, TokenUser
, user
, size
, &size
))
285 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
|| !(user
= malloc( size
)))
287 CloseHandle( token
);
290 GetTokenInformation( token
, TokenUser
, user
, size
, &size
);
292 CloseHandle( token
);
293 if (!ConvertSidToStringSidW( user
->User
.Sid
, &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
;
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
;
325 TRACE("%s\n", debugstr_w(product
));
327 if (platform
== PLATFORM_INTEL
)
328 access
|= KEY_WOW64_32KEY
;
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
);
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
);
362 if (!(usersid
= get_user_sid()))
364 ERR("Failed to retrieve user SID\n");
365 return ERROR_FUNCTION_FAILED
;
369 swprintf( keypath
, ARRAY_SIZE(keypath
),
370 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\%s\\Installer\\Products\\%s",
371 szUserSid
, squashed_pc
);
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
);
429 if (!(usersid
= get_user_sid()))
431 ERR("Failed to retrieve user SID\n");
432 return ERROR_FUNCTION_FAILED
;
436 swprintf( keypath
, ARRAY_SIZE(keypath
),
437 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\%s\\Installer\\Features\\%s",
438 szUserSid
, squashed_pc
);
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
);
491 if (!(usersid
= get_user_sid()))
493 ERR("Failed to retrieve user SID\n");
494 return ERROR_FUNCTION_FAILED
;
498 swprintf( keypath
, ARRAY_SIZE(keypath
), fmtW
, szUserSid
, squashed_pc
);
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
;
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
));
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
);
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];
561 if (!squash_guid( szComponent
, squashed_comp
)) return ERROR_FUNCTION_FAILED
;
562 TRACE("%s squashed %s\n", debugstr_w(szComponent
), debugstr_w(squashed_comp
));
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
);
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
);
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
);
595 swprintf( keypath
, ARRAY_SIZE(keypath
), fmtW
, szUserSid
, squashed_pc
);
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
);
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
);
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
);
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];
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");
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
);
660 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, keypath
, 0, access
, &hkey
)) return ERROR_SUCCESS
;
661 r
= RegDeleteTreeW( hkey
, squashed_patch
);
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
);
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
);
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
);
705 swprintf( keypath
, ARRAY_SIZE(keypath
), fmtW
, szUserSid
, squashed_pc
);
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
);
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];
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");
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
);
745 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, keypath
, 0, access
, &hkey
)) return ERROR_SUCCESS
;
746 r
= RegDeleteTreeW( hkey
, squashed_pc
);
751 UINT
MSIREG_DeleteProductKey(LPCWSTR szProduct
)
753 REGSAM access
= KEY_WOW64_64KEY
| KEY_ALL_ACCESS
;
754 WCHAR squashed_pc
[SQUASHED_GUID_SIZE
];
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
);
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
;
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
);
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
];
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
);
858 UINT
MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode
)
860 REGSAM access
= KEY_WOW64_64KEY
| KEY_ALL_ACCESS
;
861 WCHAR squashed_pc
[SQUASHED_GUID_SIZE
];
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
);
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
];
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
);
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] '<'
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
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
)
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], '<' );
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
));
955 if (!decode_base85_guid( p
+1, &component
))
956 return ERROR_INVALID_PARAMETER
;
957 TRACE( "component %s\n", debugstr_guid(&component
) );
961 StringFromGUID2( &product
, szProduct
, MAX_FEATURE_CHARS
+1 );
965 StringFromGUID2( &component
, szComponent
, MAX_FEATURE_CHARS
+1 );
971 memcpy( szFeature
, &szDescriptor
[20], len
*sizeof(WCHAR
) );
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
;
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
;
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
);
1024 UINT WINAPI
MsiEnumProductsA( DWORD index
, char *lpguid
)
1027 WCHAR szwGuid
[GUID_SIZE
];
1029 TRACE( "%lu, %p\n", index
, 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
);
1040 UINT WINAPI
MsiEnumProductsW( DWORD index
, WCHAR
*lpguid
)
1042 TRACE("%lu, %p\n", index
, lpguid
);
1045 return ERROR_INVALID_PARAMETER
;
1047 return MsiEnumProductsExW( NULL
, L
"S-1-1-0", MSIINSTALLCONTEXT_ALL
, index
, lpguid
,
1051 UINT WINAPI
MsiEnumFeaturesA( const char *szProduct
, DWORD index
, char *szFeature
, char *szParent
)
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
);
1061 szwProduct
= strdupAtoW( szProduct
);
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
);
1078 UINT WINAPI
MsiEnumFeaturesW( const WCHAR
*szProduct
, DWORD index
, WCHAR
*szFeature
, WCHAR
*szParent
)
1080 HKEY hkeyProduct
= 0;
1083 TRACE( "%s, %lu, %p, %p\n", debugstr_w(szProduct
), index
, szFeature
, szParent
);
1086 return ERROR_INVALID_PARAMETER
;
1088 r
= MSIREG_OpenInstallerFeaturesKey(szProduct
,&hkeyProduct
,FALSE
);
1089 if( r
!= ERROR_SUCCESS
)
1090 return ERROR_NO_MORE_ITEMS
;
1093 r
= RegEnumValueW(hkeyProduct
, index
, szFeature
, &sz
, NULL
, NULL
, NULL
, NULL
);
1094 RegCloseKey(hkeyProduct
);
1099 UINT WINAPI
MsiEnumComponentsA( DWORD index
, char *lpguid
)
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
);
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
)
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
,
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
) )))
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
);
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
;
1170 len_component
= ARRAY_SIZE( component
);
1173 RegCloseKey( key_components
);
1174 return ERROR_NO_MORE_ITEMS
;
1182 r
= ERROR_MORE_DATA
;
1190 if (guid
) unsquash_guid( component
, guid
);
1191 if (installed_ctx
) *installed_ctx
= MSIINSTALLCONTEXT_MACHINE
;
1192 RegCloseKey( key_components
);
1196 static UINT
fetch_user_component( const WCHAR
*usersid
, DWORD ctx
, DWORD index
, DWORD
*idx
,
1197 WCHAR guid
[39], MSIINSTALLCONTEXT
*installed_ctx
, LPWSTR sid
,
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
))
1219 len_user
= ARRAY_SIZE( user
);
1222 lstrcpyW( path
, user
);
1223 lstrcatW( path
, L
"\\Components" );
1224 if (RegOpenKeyExW( key_users
, path
, 0, access
, &key_components
))
1227 len_user
= ARRAY_SIZE( user
);
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
;
1235 len_component
= ARRAY_SIZE( component
);
1238 RegCloseKey( key_components
);
1239 len_user
= ARRAY_SIZE( user
);
1242 RegCloseKey( key_users
);
1243 return ERROR_NO_MORE_ITEMS
;
1248 if (*sid_len
< len_user
+ 1)
1250 *sid_len
= len_user
+ 1;
1251 r
= ERROR_MORE_DATA
;
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
);
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
;
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
,
1293 if (r
!= ERROR_NO_MORE_ITEMS
) goto done
;
1301 UINT WINAPI
MsiEnumComponentsExW( const WCHAR
*user_sid
, DWORD ctx
, DWORD index
, WCHAR guid
[39],
1302 MSIINSTALLCONTEXT
*installed_ctx
, WCHAR
*sid
, DWORD
*sid_len
)
1306 static DWORD last_index
;
1308 TRACE( "%s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(user_sid
), ctx
, index
, guid
, installed_ctx
,
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
)
1328 UINT WINAPI
MsiEnumClientsA( const char *szComponent
, DWORD index
, char *szProduct
)
1331 WCHAR szwProduct
[GUID_SIZE
];
1332 WCHAR
*szwComponent
= NULL
;
1334 TRACE( "%s, %lu, %p\n", debugstr_a(szComponent
), index
, szProduct
);
1337 return ERROR_INVALID_PARAMETER
;
1341 szwComponent
= strdupAtoW( szComponent
);
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
);
1355 UINT WINAPI
MsiEnumClientsW( const WCHAR
*szComponent
, DWORD index
, WCHAR
*szProduct
)
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
);
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
);
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
,
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
,
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
;
1420 TRACE( "%s, %lu, %p, %p, %p, %p\n", debugstr_w(szComponent
), iIndex
, lpQualBuf
, pcchQual
, lpAppBuf
, pcchAppBuf
);
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 */
1431 r
= ERROR_OUTOFMEMORY
;
1432 name
= malloc( name_max
* sizeof(WCHAR
) );
1437 r
= ERROR_OUTOFMEMORY
;
1438 val
= malloc( val_max
);
1442 /* loop until we allocate enough memory */
1447 r
= RegEnumValueW( key
, iIndex
, name
, &name_sz
, NULL
, &type
, (BYTE
*)val
, &val_sz
);
1448 if (r
== ERROR_SUCCESS
)
1450 if (r
!= ERROR_MORE_DATA
)
1453 if (type
!= REG_MULTI_SZ
)
1455 ERR( "component data has wrong type (%lu)\n", type
);
1459 r
= ERROR_OUTOFMEMORY
;
1460 if (name_sz
+ 1 >= name_max
)
1464 name
= malloc( name_max
* sizeof (WCHAR
) );
1469 if (val_sz
> val_max
)
1471 val_max
= val_sz
+ sizeof (WCHAR
);
1473 val
= malloc( val_max
* sizeof (WCHAR
) );
1478 ERR( "should be enough data, but isn't %lu %lu\n", name_sz
, val_sz
);
1483 r
= MsiDecomposeDescriptorW( val
, NULL
, NULL
, NULL
, &ofs
);
1484 if (r
!= ERROR_SUCCESS
)
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
)
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
;
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
);
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
)
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
);
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
];
1595 TRACE( "%s, %#lx, %lu, %p\n", debugstr_a(szUpgradeCode
), dwReserved
, iProductIndex
, lpProductBuf
);
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
);
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
];
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
,
1641 if (r
!= ERROR_SUCCESS
)
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
;
1657 targsid
= malloc(++len
* sizeof(WCHAR
));
1660 r
= ERROR_OUTOFMEMORY
;
1664 r
= MsiEnumPatchesExW(prodcode
, usersid
, dwContext
, dwFilter
, dwIndex
,
1665 patch
, targprod
, pdwTargetProductContext
,
1667 if (r
!= ERROR_SUCCESS
|| !szTargetUserSid
)
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
);
1680 *pcchTargetUserSid
= len
;
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;
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
)
1710 res
= RegOpenKeyExW(hkey
, patch
, 0, KEY_READ
, &udpatch
);
1711 if (res
!= ERROR_SUCCESS
)
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
;
1727 RegCloseKey(udpatch
);
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;
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
;
1751 res
= RegGetValueW(prod
, L
"Patches", L
"Patches", RRF_RT_ANY
, &type
, NULL
,
1753 if (res
!= ERROR_SUCCESS
)
1756 if (type
!= REG_MULTI_SZ
)
1758 r
= ERROR_BAD_CONFIGURATION
;
1762 patches
= malloc(size
);
1765 r
= ERROR_OUTOFMEMORY
;
1769 res
= RegGetValueW(prod
, L
"Patches", L
"Patches", RRF_RT_ANY
, &type
,
1771 if (res
!= ERROR_SUCCESS
)
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
;
1783 res
= RegGetValueW(prod
, L
"Patches", ptr
, RRF_RT_REG_SZ
,
1784 &type
, NULL
, &size
);
1785 if (res
!= ERROR_SUCCESS
)
1790 *transforms
= malloc(size
);
1793 r
= ERROR_OUTOFMEMORY
;
1797 res
= RegGetValueW(prod
, L
"Patches", ptr
, RRF_RT_REG_SZ
,
1798 &type
, *transforms
, &size
);
1799 if (res
!= ERROR_SUCCESS
)
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
;
1814 if (temp
!= ERROR_SUCCESS
|| !(filter
& state
))
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
;
1829 if (temp
!= ERROR_SUCCESS
|| !(filter
& state
))
1834 temp
= MSIREG_OpenUserDataPatchKey(patch
, context
,
1836 RegCloseKey(patchkey
);
1837 if (temp
!= ERROR_SUCCESS
)
1841 else if (context
== MSIINSTALLCONTEXT_MACHINE
)
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 res
= RegGetValueW(patchkey
, NULL
, L
"State", RRF_RT_REG_DWORD
,
1850 &type
, &state
, &size
);
1852 if (!(filter
& state
))
1853 res
= ERROR_NO_MORE_ITEMS
;
1855 RegCloseKey(patchkey
);
1858 RegCloseKey(localpatch
);
1859 RegCloseKey(localprod
);
1861 if (res
!= ERROR_SUCCESS
)
1873 lstrcpyW(targetprod
, prodcode
);
1876 *targetctx
= context
;
1880 lstrcpynW(targetsid
, usersid
, *sidsize
);
1881 if (lstrlenW(usersid
) >= *sidsize
)
1882 r
= ERROR_MORE_DATA
;
1887 *sidsize
= lstrlenW(usersid
);
1889 *sidsize
*= sizeof(WCHAR
);
1900 static UINT
enum_patches(const WCHAR
*szProductCode
, const WCHAR
*szUserSid
, DWORD dwContext
, DWORD dwFilter
,
1901 DWORD dwIndex
, DWORD
*idx
, WCHAR
*szPatchCode
, WCHAR
*szTargetProductCode
,
1902 MSIINSTALLCONTEXT
*pdwTargetProductContext
, WCHAR
*szTargetUserSid
, DWORD
*pcchTargetUserSid
,
1903 WCHAR
**szTransforms
)
1905 LPWSTR usersid
= NULL
;
1906 UINT r
= ERROR_INVALID_PARAMETER
;
1910 szUserSid
= usersid
= get_user_sid();
1911 if (!usersid
) return ERROR_FUNCTION_FAILED
;
1914 if (dwContext
& MSIINSTALLCONTEXT_USERMANAGED
)
1916 r
= check_product_patches(szProductCode
, szUserSid
, MSIINSTALLCONTEXT_USERMANAGED
, dwFilter
, dwIndex
, idx
,
1917 szPatchCode
, szTargetProductCode
, pdwTargetProductContext
, szTargetUserSid
,
1918 pcchTargetUserSid
, szTransforms
);
1919 if (r
!= ERROR_NO_MORE_ITEMS
)
1923 if (dwContext
& MSIINSTALLCONTEXT_USERUNMANAGED
)
1925 r
= check_product_patches(szProductCode
, szUserSid
, MSIINSTALLCONTEXT_USERUNMANAGED
, dwFilter
, dwIndex
, idx
,
1926 szPatchCode
, szTargetProductCode
, pdwTargetProductContext
, szTargetUserSid
,
1927 pcchTargetUserSid
, szTransforms
);
1928 if (r
!= ERROR_NO_MORE_ITEMS
)
1932 if (dwContext
& MSIINSTALLCONTEXT_MACHINE
)
1934 r
= check_product_patches(szProductCode
, szUserSid
, MSIINSTALLCONTEXT_MACHINE
, dwFilter
, dwIndex
, idx
,
1935 szPatchCode
, szTargetProductCode
, pdwTargetProductContext
, szTargetUserSid
,
1936 pcchTargetUserSid
, szTransforms
);
1937 if (r
!= ERROR_NO_MORE_ITEMS
)
1946 /***********************************************************************
1947 * MsiEnumPatchesExW [MSI.@]
1949 UINT WINAPI
MsiEnumPatchesExW( const WCHAR
*szProductCode
, const WCHAR
*szUserSid
, DWORD dwContext
, DWORD dwFilter
,
1950 DWORD dwIndex
, WCHAR
*szPatchCode
, WCHAR
*szTargetProductCode
,
1951 MSIINSTALLCONTEXT
*pdwTargetProductContext
, WCHAR
*szTargetUserSid
,
1952 DWORD
*pcchTargetUserSid
)
1954 WCHAR squashed_pc
[SQUASHED_GUID_SIZE
];
1958 static DWORD last_index
;
1960 TRACE( "%s, %s, %#lx, %lu, %lu, %p, %p, %p, %p, %p)\n", debugstr_w(szProductCode
), debugstr_w(szUserSid
),
1961 dwContext
, dwFilter
, dwIndex
, szPatchCode
, szTargetProductCode
, pdwTargetProductContext
, szTargetUserSid
,
1962 pcchTargetUserSid
);
1964 if (!szProductCode
|| !squash_guid( szProductCode
, squashed_pc
))
1965 return ERROR_INVALID_PARAMETER
;
1967 if (szUserSid
&& !wcscmp( szUserSid
, L
"S-1-5-18" ))
1968 return ERROR_INVALID_PARAMETER
;
1970 if (dwContext
& MSIINSTALLCONTEXT_MACHINE
&& szUserSid
)
1971 return ERROR_INVALID_PARAMETER
;
1973 if (dwContext
<= MSIINSTALLCONTEXT_NONE
||
1974 dwContext
> MSIINSTALLCONTEXT_ALL
)
1975 return ERROR_INVALID_PARAMETER
;
1977 if (dwFilter
<= MSIPATCHSTATE_INVALID
|| dwFilter
> MSIPATCHSTATE_ALL
)
1978 return ERROR_INVALID_PARAMETER
;
1980 if (dwIndex
&& dwIndex
- last_index
!= 1)
1981 return ERROR_INVALID_PARAMETER
;
1986 r
= enum_patches(szProductCode
, szUserSid
, dwContext
, dwFilter
, dwIndex
, &idx
, szPatchCode
, szTargetProductCode
,
1987 pdwTargetProductContext
, szTargetUserSid
, pcchTargetUserSid
, NULL
);
1989 if (r
== ERROR_SUCCESS
)
1990 last_index
= dwIndex
;
1997 /***********************************************************************
1998 * MsiEnumPatchesA [MSI.@]
2000 UINT WINAPI
MsiEnumPatchesA( const char *szProduct
, DWORD iPatchIndex
, char *lpPatchBuf
, char *lpTransformsBuf
,
2001 DWORD
*pcchTransformsBuf
)
2003 WCHAR
*product
, *transforms
, patch
[GUID_SIZE
];
2007 TRACE( "%s, %lu, %p, %p, %p\n", debugstr_a(szProduct
), iPatchIndex
, lpPatchBuf
, lpTransformsBuf
,
2008 pcchTransformsBuf
);
2010 if (!szProduct
|| !lpPatchBuf
|| !lpTransformsBuf
|| !pcchTransformsBuf
)
2011 return ERROR_INVALID_PARAMETER
;
2013 product
= strdupAtoW(szProduct
);
2015 return ERROR_OUTOFMEMORY
;
2017 len
= *pcchTransformsBuf
;
2018 transforms
= malloc(len
* sizeof(WCHAR
));
2021 r
= ERROR_OUTOFMEMORY
;
2025 r
= MsiEnumPatchesW(product
, iPatchIndex
, patch
, transforms
, &len
);
2026 if (r
!= ERROR_SUCCESS
&& r
!= ERROR_MORE_DATA
)
2029 WideCharToMultiByte(CP_ACP
, 0, patch
, -1, lpPatchBuf
,
2030 GUID_SIZE
, NULL
, NULL
);
2032 if (!WideCharToMultiByte(CP_ACP
, 0, transforms
, -1, lpTransformsBuf
,
2033 *pcchTransformsBuf
, NULL
, NULL
))
2034 r
= ERROR_MORE_DATA
;
2036 if (r
== ERROR_MORE_DATA
)
2038 lpTransformsBuf
[*pcchTransformsBuf
- 1] = '\0';
2039 *pcchTransformsBuf
= len
* 2;
2042 *pcchTransformsBuf
= strlen( lpTransformsBuf
);
2051 /***********************************************************************
2052 * MsiEnumPatchesW [MSI.@]
2054 UINT WINAPI
MsiEnumPatchesW( const WCHAR
*szProduct
, DWORD iPatchIndex
, WCHAR
*lpPatchBuf
, WCHAR
*lpTransformsBuf
,
2055 DWORD
*pcchTransformsBuf
)
2057 WCHAR
*transforms
= NULL
, squashed_pc
[SQUASHED_GUID_SIZE
];
2062 TRACE( "%s, %lu, %p, %p, %p)\n", debugstr_w(szProduct
), iPatchIndex
, lpPatchBuf
, lpTransformsBuf
,
2063 pcchTransformsBuf
);
2065 if (!szProduct
|| !squash_guid( szProduct
, squashed_pc
))
2066 return ERROR_INVALID_PARAMETER
;
2068 if (!lpPatchBuf
|| !lpTransformsBuf
|| !pcchTransformsBuf
)
2069 return ERROR_INVALID_PARAMETER
;
2071 if (MSIREG_OpenProductKey(szProduct
, NULL
, MSIINSTALLCONTEXT_USERMANAGED
,
2072 &prod
, FALSE
) != ERROR_SUCCESS
&&
2073 MSIREG_OpenProductKey(szProduct
, NULL
, MSIINSTALLCONTEXT_USERUNMANAGED
,
2074 &prod
, FALSE
) != ERROR_SUCCESS
&&
2075 MSIREG_OpenProductKey(szProduct
, NULL
, MSIINSTALLCONTEXT_MACHINE
,
2076 &prod
, FALSE
) != ERROR_SUCCESS
)
2077 return ERROR_UNKNOWN_PRODUCT
;
2081 r
= enum_patches(szProduct
, NULL
, MSIINSTALLCONTEXT_ALL
, MSIPATCHSTATE_ALL
, iPatchIndex
, &idx
, lpPatchBuf
, NULL
,
2082 NULL
, NULL
, NULL
, &transforms
);
2083 if (r
!= ERROR_SUCCESS
)
2086 lstrcpynW(lpTransformsBuf
, transforms
, *pcchTransformsBuf
);
2087 if (*pcchTransformsBuf
<= lstrlenW(transforms
))
2089 r
= ERROR_MORE_DATA
;
2090 *pcchTransformsBuf
= lstrlenW(transforms
);
2093 *pcchTransformsBuf
= lstrlenW(transforms
);
2100 UINT WINAPI
MsiEnumProductsExA( const char *product
, const char *usersid
, DWORD ctx
, DWORD index
,
2101 char installed_product
[GUID_SIZE
], MSIINSTALLCONTEXT
*installed_ctx
, char *sid
,
2105 WCHAR installed_productW
[GUID_SIZE
], *productW
= NULL
, *usersidW
= NULL
, *sidW
= NULL
;
2107 TRACE( "%s, %s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_a(product
), debugstr_a(usersid
), ctx
, index
,
2108 installed_product
, installed_ctx
, sid
, sid_len
);
2110 if (sid
&& !sid_len
) return ERROR_INVALID_PARAMETER
;
2111 if (product
&& !(productW
= strdupAtoW( product
))) return ERROR_OUTOFMEMORY
;
2112 if (usersid
&& !(usersidW
= strdupAtoW( usersid
)))
2115 return ERROR_OUTOFMEMORY
;
2117 if (sid
&& !(sidW
= malloc( *sid_len
* sizeof(WCHAR
) )))
2121 return ERROR_OUTOFMEMORY
;
2123 r
= MsiEnumProductsExW( productW
, usersidW
, ctx
, index
, installed_productW
,
2124 installed_ctx
, sidW
, sid_len
);
2125 if (r
== ERROR_SUCCESS
)
2127 if (installed_product
) WideCharToMultiByte( CP_ACP
, 0, installed_productW
, GUID_SIZE
,
2128 installed_product
, GUID_SIZE
, NULL
, NULL
);
2129 if (sid
) WideCharToMultiByte( CP_ACP
, 0, sidW
, *sid_len
+ 1, sid
, *sid_len
+ 1, NULL
, NULL
);
2137 static UINT
fetch_machine_product( const WCHAR
*match
, DWORD index
, DWORD
*idx
,
2138 WCHAR installed_product
[GUID_SIZE
],
2139 MSIINSTALLCONTEXT
*installed_ctx
, WCHAR
*sid
, DWORD
*sid_len
)
2142 WCHAR product
[SQUASHED_GUID_SIZE
];
2144 REGSAM access
= KEY_ENUMERATE_SUB_KEYS
| KEY_WOW64_64KEY
;
2147 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE
, L
"Software\\Classes\\Installer\\Products", 0, access
, &key
))
2148 return ERROR_NO_MORE_ITEMS
;
2150 len
= ARRAY_SIZE( product
);
2151 while (!RegEnumKeyExW( key
, i
, product
, &len
, NULL
, NULL
, NULL
, NULL
))
2153 if (match
&& wcscmp( match
, product
))
2156 len
= ARRAY_SIZE( product
);
2159 if (*idx
== index
) goto found
;
2161 len
= ARRAY_SIZE( product
);
2165 return ERROR_NO_MORE_ITEMS
;
2168 if (sid_len
&& *sid_len
< 1)
2171 r
= ERROR_MORE_DATA
;
2175 if (installed_product
) unsquash_guid( product
, installed_product
);
2176 if (installed_ctx
) *installed_ctx
= MSIINSTALLCONTEXT_MACHINE
;
2188 static UINT
fetch_user_product( const WCHAR
*match
, const WCHAR
*usersid
, DWORD ctx
, DWORD index
,
2189 DWORD
*idx
, WCHAR installed_product
[GUID_SIZE
],
2190 MSIINSTALLCONTEXT
*installed_ctx
, WCHAR
*sid
, DWORD
*sid_len
)
2193 const WCHAR
*subkey
;
2194 WCHAR path
[MAX_PATH
], product
[SQUASHED_GUID_SIZE
], user
[128];
2195 DWORD i
= 0, j
= 0, len_product
, len_user
;
2196 REGSAM access
= KEY_ENUMERATE_SUB_KEYS
| KEY_WOW64_64KEY
;
2197 HKEY key_users
, key_products
;
2199 if (ctx
== MSIINSTALLCONTEXT_USERMANAGED
)
2201 subkey
= L
"\\Installer\\Products";
2202 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed",
2203 0, access
, &key_users
)) return ERROR_NO_MORE_ITEMS
;
2205 else if (ctx
== MSIINSTALLCONTEXT_USERUNMANAGED
)
2207 subkey
= L
"\\Software\\Microsoft\\Installer\\Products";
2208 if (RegOpenKeyExW( HKEY_USERS
, NULL
, 0, access
, &key_users
))
2209 return ERROR_NO_MORE_ITEMS
;
2211 else return ERROR_INVALID_PARAMETER
;
2213 len_user
= ARRAY_SIZE( user
);
2214 while (!RegEnumKeyExW( key_users
, i
, user
, &len_user
, NULL
, NULL
, NULL
, NULL
))
2216 if (wcscmp( usersid
, user
) && wcscmp( usersid
, L
"S-1-1-0" ))
2219 len_user
= ARRAY_SIZE( user
);
2222 lstrcpyW( path
, user
);
2223 lstrcatW( path
, subkey
);
2224 if (RegOpenKeyExW( key_users
, path
, 0, access
, &key_products
))
2227 len_user
= ARRAY_SIZE( user
);
2230 len_product
= ARRAY_SIZE( product
);
2231 while (!RegEnumKeyExW( key_products
, j
, product
, &len_product
, NULL
, NULL
, NULL
, NULL
))
2233 if (match
&& wcscmp( match
, product
))
2236 len_product
= ARRAY_SIZE( product
);
2239 if (*idx
== index
) goto found
;
2241 len_product
= ARRAY_SIZE( product
);
2244 RegCloseKey( key_products
);
2245 len_user
= ARRAY_SIZE( user
);
2248 RegCloseKey( key_users
);
2249 return ERROR_NO_MORE_ITEMS
;
2252 if (sid_len
&& *sid_len
<= len_user
)
2254 *sid_len
= len_user
;
2255 r
= ERROR_MORE_DATA
;
2259 if (installed_product
) unsquash_guid( product
, installed_product
);
2260 if (installed_ctx
) *installed_ctx
= ctx
;
2263 lstrcpyW( sid
, user
);
2264 *sid_len
= len_user
;
2268 RegCloseKey( key_products
);
2269 RegCloseKey( key_users
);
2273 static UINT
enum_products( const WCHAR
*product
, const WCHAR
*usersid
, DWORD ctx
, DWORD index
,
2274 DWORD
*idx
, WCHAR installed_product
[GUID_SIZE
],
2275 MSIINSTALLCONTEXT
*installed_ctx
, WCHAR
*sid
, DWORD
*sid_len
)
2277 UINT r
= ERROR_NO_MORE_ITEMS
;
2282 usersid
= user
= get_user_sid();
2283 if (!user
) return ERROR_FUNCTION_FAILED
;
2285 if (ctx
& MSIINSTALLCONTEXT_MACHINE
)
2287 r
= fetch_machine_product( product
, index
, idx
, installed_product
, installed_ctx
,
2289 if (r
!= ERROR_NO_MORE_ITEMS
) goto done
;
2291 if (ctx
& MSIINSTALLCONTEXT_USERUNMANAGED
)
2293 r
= fetch_user_product( product
, usersid
, MSIINSTALLCONTEXT_USERUNMANAGED
, index
,
2294 idx
, installed_product
, installed_ctx
, sid
, sid_len
);
2295 if (r
!= ERROR_NO_MORE_ITEMS
) goto done
;
2297 if (ctx
& MSIINSTALLCONTEXT_USERMANAGED
)
2299 r
= fetch_user_product( product
, usersid
, MSIINSTALLCONTEXT_USERMANAGED
, index
,
2300 idx
, installed_product
, installed_ctx
, sid
, sid_len
);
2301 if (r
!= ERROR_NO_MORE_ITEMS
) goto done
;
2309 UINT WINAPI
MsiEnumProductsExW( const WCHAR
*product
, const WCHAR
*usersid
, DWORD ctx
, DWORD index
,
2310 WCHAR installed_product
[GUID_SIZE
], MSIINSTALLCONTEXT
*installed_ctx
, WCHAR
*sid
,
2315 static DWORD last_index
;
2317 TRACE( "%s, %s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(product
), debugstr_w(usersid
), ctx
, index
,
2318 installed_product
, installed_ctx
, sid
, sid_len
);
2320 if ((sid
&& !sid_len
) || !ctx
|| (usersid
&& ctx
== MSIINSTALLCONTEXT_MACHINE
))
2321 return ERROR_INVALID_PARAMETER
;
2323 if (index
&& index
- last_index
!= 1)
2324 return ERROR_INVALID_PARAMETER
;
2326 if (!index
) last_index
= 0;
2328 r
= enum_products( product
, usersid
, ctx
, index
, &idx
, installed_product
, installed_ctx
,
2330 if (r
== ERROR_SUCCESS
)