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
);
254 val
= msi_alloc( len
);
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
= msi_alloc( size
)))
279 CloseHandle( token
);
282 if (!GetTokenInformation( token
, TokenUser
, user
, size
, &size
))
285 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
|| !(user
= msi_alloc( 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 swprintf( keypath
, ARRAY_SIZE(keypath
), L
"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Patches",
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
, LPSTR lpguid
)
1027 WCHAR szwGuid
[GUID_SIZE
];
1029 TRACE("%d %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
, LPWSTR lpguid
)
1042 TRACE("%d %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(LPCSTR szProduct
, DWORD index
, LPSTR szFeature
, LPSTR szParent
)
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
);
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,
1070 szFeature
, GUID_SIZE
, NULL
, NULL
);
1071 WideCharToMultiByte(CP_ACP
, 0, szwParent
, -1,
1072 szParent
, GUID_SIZE
, NULL
, NULL
);
1075 msi_free( szwProduct
);
1080 UINT WINAPI
MsiEnumFeaturesW(LPCWSTR szProduct
, DWORD index
, LPWSTR szFeature
, LPWSTR szParent
)
1082 HKEY hkeyProduct
= 0;
1085 TRACE("%s %d %p %p\n", debugstr_w(szProduct
), index
, szFeature
, szParent
);
1088 return ERROR_INVALID_PARAMETER
;
1090 r
= MSIREG_OpenInstallerFeaturesKey(szProduct
,&hkeyProduct
,FALSE
);
1091 if( r
!= ERROR_SUCCESS
)
1092 return ERROR_NO_MORE_ITEMS
;
1095 r
= RegEnumValueW(hkeyProduct
, index
, szFeature
, &sz
, NULL
, NULL
, NULL
, NULL
);
1096 RegCloseKey(hkeyProduct
);
1101 UINT WINAPI
MsiEnumComponentsA(DWORD index
, LPSTR lpguid
)
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
);
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
)
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
,
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
);
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
;
1172 len_component
= ARRAY_SIZE( component
);
1175 RegCloseKey( key_components
);
1176 return ERROR_NO_MORE_ITEMS
;
1184 r
= ERROR_MORE_DATA
;
1192 if (guid
) unsquash_guid( component
, guid
);
1193 if (installed_ctx
) *installed_ctx
= MSIINSTALLCONTEXT_MACHINE
;
1194 RegCloseKey( key_components
);
1198 static UINT
fetch_user_component( const WCHAR
*usersid
, DWORD ctx
, DWORD index
, DWORD
*idx
,
1199 WCHAR guid
[39], MSIINSTALLCONTEXT
*installed_ctx
, LPWSTR sid
,
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
))
1221 len_user
= ARRAY_SIZE( user
);
1224 lstrcpyW( path
, user
);
1225 lstrcatW( path
, L
"\\Components" );
1226 if (RegOpenKeyExW( key_users
, path
, 0, access
, &key_components
))
1229 len_user
= ARRAY_SIZE( user
);
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
;
1237 len_component
= ARRAY_SIZE( component
);
1240 RegCloseKey( key_components
);
1241 len_user
= ARRAY_SIZE( user
);
1244 RegCloseKey( key_users
);
1245 return ERROR_NO_MORE_ITEMS
;
1250 if (*sid_len
< len_user
+ 1)
1252 *sid_len
= len_user
+ 1;
1253 r
= ERROR_MORE_DATA
;
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
);
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
;
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
,
1295 if (r
!= ERROR_NO_MORE_ITEMS
) goto done
;
1303 UINT WINAPI
MsiEnumComponentsExW( LPCWSTR user_sid
, DWORD ctx
, DWORD index
, WCHAR guid
[39],
1304 MSIINSTALLCONTEXT
*installed_ctx
, LPWSTR sid
, LPDWORD sid_len
)
1308 static DWORD last_index
;
1310 TRACE("%s, %u, %u, %p, %p, %p, %p\n", debugstr_w(user_sid
), ctx
, index
, guid
, installed_ctx
,
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
)
1330 UINT WINAPI
MsiEnumClientsA(LPCSTR szComponent
, DWORD index
, LPSTR szProduct
)
1333 WCHAR szwProduct
[GUID_SIZE
];
1334 LPWSTR szwComponent
= NULL
;
1336 TRACE("%s %d %p\n", debugstr_a(szComponent
), index
, szProduct
);
1339 return ERROR_INVALID_PARAMETER
;
1343 szwComponent
= strdupAtoW( szComponent
);
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
);
1360 UINT WINAPI
MsiEnumClientsW(LPCWSTR szComponent
, DWORD index
, LPWSTR szProduct
)
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
);
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
);
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
;
1426 TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent
), iIndex
,
1427 lpQualBuf
, pcchQual
, lpAppBuf
, pcchAppBuf
);
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 */
1438 r
= ERROR_OUTOFMEMORY
;
1439 name
= msi_alloc( name_max
* sizeof(WCHAR
) );
1444 r
= ERROR_OUTOFMEMORY
;
1445 val
= msi_alloc( val_max
);
1449 /* loop until we allocate enough memory */
1454 r
= RegEnumValueW( key
, iIndex
, name
, &name_sz
,
1455 NULL
, &type
, (LPBYTE
)val
, &val_sz
);
1456 if (r
== ERROR_SUCCESS
)
1458 if (r
!= ERROR_MORE_DATA
)
1461 if (type
!= REG_MULTI_SZ
)
1463 ERR("component data has wrong type (%d)\n", type
);
1467 r
= ERROR_OUTOFMEMORY
;
1468 if (name_sz
+ 1 >= name_max
)
1472 name
= msi_alloc( name_max
* sizeof (WCHAR
) );
1477 if (val_sz
> val_max
)
1479 val_max
= val_sz
+ sizeof (WCHAR
);
1481 val
= msi_alloc( val_max
* sizeof (WCHAR
) );
1486 ERR("should be enough data, but isn't %d %d\n", name_sz
, val_sz
);
1491 r
= MsiDecomposeDescriptorW( val
, NULL
, NULL
, NULL
, &ofs
);
1492 if (r
!= ERROR_SUCCESS
)
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
)
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
;
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
);
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
)
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
);
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
];
1607 TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode
), dwReserved
,
1608 iProductIndex
, lpProductBuf
);
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
);
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
];
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
,
1658 if (r
!= ERROR_SUCCESS
)
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
;
1674 targsid
= msi_alloc(++len
* sizeof(WCHAR
));
1677 r
= ERROR_OUTOFMEMORY
;
1681 r
= MsiEnumPatchesExW(prodcode
, usersid
, dwContext
, dwFilter
, dwIndex
,
1682 patch
, targprod
, pdwTargetProductContext
,
1684 if (r
!= ERROR_SUCCESS
|| !szTargetUserSid
)
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
);
1697 *pcchTargetUserSid
= len
;
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;
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
)
1728 res
= RegOpenKeyExW(hkey
, patch
, 0, KEY_READ
, &udpatch
);
1729 if (res
!= ERROR_SUCCESS
)
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
;
1745 RegCloseKey(udpatch
);
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;
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
;
1770 res
= RegGetValueW(prod
, L
"Patches", L
"Patches", RRF_RT_ANY
, &type
, NULL
,
1772 if (res
!= ERROR_SUCCESS
)
1775 if (type
!= REG_MULTI_SZ
)
1777 r
= ERROR_BAD_CONFIGURATION
;
1781 patches
= msi_alloc(size
);
1784 r
= ERROR_OUTOFMEMORY
;
1788 res
= RegGetValueW(prod
, L
"Patches", L
"Patches", RRF_RT_ANY
, &type
,
1790 if (res
!= ERROR_SUCCESS
)
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
;
1802 res
= RegGetValueW(prod
, L
"Patches", ptr
, RRF_RT_REG_SZ
,
1803 &type
, NULL
, &size
);
1804 if (res
!= ERROR_SUCCESS
)
1809 *transforms
= msi_alloc(size
);
1812 r
= ERROR_OUTOFMEMORY
;
1816 res
= RegGetValueW(prod
, L
"Patches", ptr
, RRF_RT_REG_SZ
,
1817 &type
, *transforms
, &size
);
1818 if (res
!= ERROR_SUCCESS
)
1822 if (context
== MSIINSTALLCONTEXT_USERMANAGED
)
1824 if (!(filter
& MSIPATCHSTATE_APPLIED
))
1826 temp
= msi_get_patch_state(prodcode
, usersid
, context
,
1828 if (temp
== ERROR_BAD_CONFIGURATION
)
1830 r
= ERROR_BAD_CONFIGURATION
;
1834 if (temp
!= ERROR_SUCCESS
|| !(filter
& state
))
1838 else if (context
== MSIINSTALLCONTEXT_USERUNMANAGED
)
1840 if (!(filter
& MSIPATCHSTATE_APPLIED
))
1842 temp
= msi_get_patch_state(prodcode
, usersid
, context
,
1844 if (temp
== ERROR_BAD_CONFIGURATION
)
1846 r
= ERROR_BAD_CONFIGURATION
;
1850 if (temp
!= ERROR_SUCCESS
|| !(filter
& state
))
1855 temp
= MSIREG_OpenUserDataPatchKey(patch
, context
,
1857 RegCloseKey(patchkey
);
1858 if (temp
!= ERROR_SUCCESS
)
1862 else if (context
== MSIINSTALLCONTEXT_MACHINE
)
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
)
1894 lstrcpyW(targetprod
, prodcode
);
1897 *targetctx
= context
;
1901 lstrcpynW(targetsid
, usersid
, *sidsize
);
1902 if (lstrlenW(usersid
) >= *sidsize
)
1903 r
= ERROR_MORE_DATA
;
1908 *sidsize
= lstrlenW(usersid
);
1910 *sidsize
*= sizeof(WCHAR
);
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
;
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
)
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
)
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
)
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
];
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
;
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
;
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
];
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
);
2050 return ERROR_OUTOFMEMORY
;
2052 len
= *pcchTransformsBuf
;
2053 transforms
= msi_alloc( len
* sizeof(WCHAR
) );
2056 r
= ERROR_OUTOFMEMORY
;
2060 r
= MsiEnumPatchesW(product
, iPatchIndex
, patch
, transforms
, &len
);
2061 if (r
!= ERROR_SUCCESS
&& r
!= ERROR_MORE_DATA
)
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;
2077 *pcchTransformsBuf
= strlen( lpTransformsBuf
);
2080 msi_free(transforms
);
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
];
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
;
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
)
2122 lstrcpynW(lpTransformsBuf
, transforms
, *pcchTransformsBuf
);
2123 if (*pcchTransformsBuf
<= lstrlenW(transforms
))
2125 r
= ERROR_MORE_DATA
;
2126 *pcchTransformsBuf
= lstrlenW(transforms
);
2129 *pcchTransformsBuf
= lstrlenW(transforms
);
2132 msi_free(transforms
);
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
)
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
);
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
)
2178 WCHAR product
[SQUASHED_GUID_SIZE
];
2180 REGSAM access
= KEY_ENUMERATE_SUB_KEYS
| KEY_WOW64_64KEY
;
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
))
2192 len
= ARRAY_SIZE( product
);
2195 if (*idx
== index
) goto found
;
2197 len
= ARRAY_SIZE( product
);
2201 return ERROR_NO_MORE_ITEMS
;
2204 if (sid_len
&& *sid_len
< 1)
2207 r
= ERROR_MORE_DATA
;
2211 if (installed_product
) unsquash_guid( product
, installed_product
);
2212 if (installed_ctx
) *installed_ctx
= MSIINSTALLCONTEXT_MACHINE
;
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
)
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" ))
2255 len_user
= ARRAY_SIZE( user
);
2258 lstrcpyW( path
, user
);
2259 lstrcatW( path
, subkey
);
2260 if (RegOpenKeyExW( key_users
, path
, 0, access
, &key_products
))
2263 len_user
= ARRAY_SIZE( user
);
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
))
2272 len_product
= ARRAY_SIZE( product
);
2275 if (*idx
== index
) goto found
;
2277 len_product
= ARRAY_SIZE( product
);
2280 RegCloseKey( key_products
);
2281 len_user
= ARRAY_SIZE( user
);
2284 RegCloseKey( key_users
);
2285 return ERROR_NO_MORE_ITEMS
;
2288 if (sid_len
&& *sid_len
<= len_user
)
2290 *sid_len
= len_user
;
2291 r
= ERROR_MORE_DATA
;
2295 if (installed_product
) unsquash_guid( product
, installed_product
);
2296 if (installed_ctx
) *installed_ctx
= ctx
;
2299 lstrcpyW( sid
, user
);
2300 *sid_len
= len_user
;
2304 RegCloseKey( key_products
);
2305 RegCloseKey( key_users
);
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
;
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
,
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
;
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
)
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
,
2366 if (r
== ERROR_SUCCESS
)