xref: /reactos/dll/win32/msi/registry.c (revision f4be6dc3)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Implementation of the Microsoft Installer (msi.dll)
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Copyright 2005 Mike McCormack for CodeWeavers
5c2c66affSColin Finck  * Copyright 2005 Aric Stewart for CodeWeavers
6c2c66affSColin Finck  *
7c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
8c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
9c2c66affSColin Finck  * License as published by the Free Software Foundation; either
10c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
11c2c66affSColin Finck  *
12c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
13c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15c2c66affSColin Finck  * Lesser General Public License for more details.
16c2c66affSColin Finck  *
17c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
18c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
19c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20c2c66affSColin Finck  */
21c2c66affSColin Finck 
22c42b133eSAmine Khaldi #include <stdarg.h>
23c42b133eSAmine Khaldi 
24c42b133eSAmine Khaldi #define COBJMACROS
25c42b133eSAmine Khaldi 
26c42b133eSAmine Khaldi #include "windef.h"
27c42b133eSAmine Khaldi #include "winbase.h"
28c42b133eSAmine Khaldi #include "winreg.h"
29c42b133eSAmine Khaldi #include "winnls.h"
30c42b133eSAmine Khaldi #include "shlwapi.h"
31c42b133eSAmine Khaldi #include "wine/debug.h"
32c42b133eSAmine Khaldi #include "msi.h"
33c2c66affSColin Finck #include "msipriv.h"
34c42b133eSAmine Khaldi #include "wincrypt.h"
35c42b133eSAmine Khaldi #include "winver.h"
36c42b133eSAmine Khaldi #include "winuser.h"
37c42b133eSAmine Khaldi #include "sddl.h"
38c2c66affSColin Finck 
39c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(msi);
40c2c66affSColin Finck 
unsquash_guid(LPCWSTR in,LPWSTR out)41c2c66affSColin Finck BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
42c2c66affSColin Finck {
43c2c66affSColin Finck     DWORD i,n=0;
44c2c66affSColin Finck 
45c2c66affSColin Finck     if (lstrlenW(in) != 32)
46c2c66affSColin Finck         return FALSE;
47c2c66affSColin Finck 
48c2c66affSColin Finck     out[n++]='{';
49c2c66affSColin Finck     for(i=0; i<8; i++)
50c2c66affSColin Finck         out[n++] = in[7-i];
51c2c66affSColin Finck     out[n++]='-';
52c2c66affSColin Finck     for(i=0; i<4; i++)
53c2c66affSColin Finck         out[n++] = in[11-i];
54c2c66affSColin Finck     out[n++]='-';
55c2c66affSColin Finck     for(i=0; i<4; i++)
56c2c66affSColin Finck         out[n++] = in[15-i];
57c2c66affSColin Finck     out[n++]='-';
58c2c66affSColin Finck     for(i=0; i<2; i++)
59c2c66affSColin Finck     {
60c2c66affSColin Finck         out[n++] = in[17+i*2];
61c2c66affSColin Finck         out[n++] = in[16+i*2];
62c2c66affSColin Finck     }
63c2c66affSColin Finck     out[n++]='-';
64c2c66affSColin Finck     for( ; i<8; i++)
65c2c66affSColin Finck     {
66c2c66affSColin Finck         out[n++] = in[17+i*2];
67c2c66affSColin Finck         out[n++] = in[16+i*2];
68c2c66affSColin Finck     }
69c2c66affSColin Finck     out[n++]='}';
70c2c66affSColin Finck     out[n]=0;
71c2c66affSColin Finck     return TRUE;
72c2c66affSColin Finck }
73c2c66affSColin Finck 
squash_guid(LPCWSTR in,LPWSTR out)74c2c66affSColin Finck BOOL squash_guid(LPCWSTR in, LPWSTR out)
75c2c66affSColin Finck {
76c2c66affSColin Finck     DWORD i,n=1;
77c2c66affSColin Finck     GUID guid;
78c2c66affSColin Finck 
79c2c66affSColin Finck     out[0] = 0;
80c2c66affSColin Finck 
81c2c66affSColin Finck     if (FAILED(CLSIDFromString((LPCOLESTR)in, &guid)))
82c2c66affSColin Finck         return FALSE;
83c2c66affSColin Finck 
84c2c66affSColin Finck     for(i=0; i<8; i++)
85c2c66affSColin Finck         out[7-i] = in[n++];
86c2c66affSColin Finck     n++;
87c2c66affSColin Finck     for(i=0; i<4; i++)
88c2c66affSColin Finck         out[11-i] = in[n++];
89c2c66affSColin Finck     n++;
90c2c66affSColin Finck     for(i=0; i<4; i++)
91c2c66affSColin Finck         out[15-i] = in[n++];
92c2c66affSColin Finck     n++;
93c2c66affSColin Finck     for(i=0; i<2; i++)
94c2c66affSColin Finck     {
95c2c66affSColin Finck         out[17+i*2] = in[n++];
96c2c66affSColin Finck         out[16+i*2] = in[n++];
97c2c66affSColin Finck     }
98c2c66affSColin Finck     n++;
99c2c66affSColin Finck     for( ; i<8; i++)
100c2c66affSColin Finck     {
101c2c66affSColin Finck         out[17+i*2] = in[n++];
102c2c66affSColin Finck         out[16+i*2] = in[n++];
103c2c66affSColin Finck     }
104c2c66affSColin Finck     out[32]=0;
105c2c66affSColin Finck     return TRUE;
106c2c66affSColin Finck }
107c2c66affSColin Finck 
108c2c66affSColin Finck 
109c2c66affSColin Finck /* tables for encoding and decoding base85 */
110c2c66affSColin Finck static const unsigned char table_dec85[0x80] = {
111c2c66affSColin Finck 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
112c2c66affSColin Finck 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
113c2c66affSColin Finck 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
114c2c66affSColin Finck 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
115c2c66affSColin Finck 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
116c2c66affSColin Finck 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
117c2c66affSColin Finck 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
118c2c66affSColin Finck 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
119c2c66affSColin Finck };
120c2c66affSColin Finck 
121c2c66affSColin Finck static const char table_enc85[] =
122c2c66affSColin Finck "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
123c2c66affSColin Finck "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
124c2c66affSColin Finck "yz{}~";
125c2c66affSColin Finck 
126c2c66affSColin Finck /*
127c2c66affSColin Finck  *  Converts a base85 encoded guid into a GUID pointer
128c2c66affSColin Finck  *  Base85 encoded GUIDs should be 20 characters long.
129c2c66affSColin Finck  *
130c2c66affSColin Finck  *  returns TRUE if successful, FALSE if not
131c2c66affSColin Finck  */
decode_base85_guid(LPCWSTR str,GUID * guid)132c2c66affSColin Finck BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
133c2c66affSColin Finck {
134c2c66affSColin Finck     DWORD i, val = 0, base = 1, *p;
135c2c66affSColin Finck 
136c2c66affSColin Finck     if (!str)
137c2c66affSColin Finck         return FALSE;
138c2c66affSColin Finck 
139c2c66affSColin Finck     p = (DWORD*) guid;
140c2c66affSColin Finck     for( i=0; i<20; i++ )
141c2c66affSColin Finck     {
142c2c66affSColin Finck         if( (i%5) == 0 )
143c2c66affSColin Finck         {
144c2c66affSColin Finck             val = 0;
145c2c66affSColin Finck             base = 1;
146c2c66affSColin Finck         }
147c2c66affSColin Finck         val += table_dec85[str[i]] * base;
148c2c66affSColin Finck         if( str[i] >= 0x80 )
149c2c66affSColin Finck             return FALSE;
150c2c66affSColin Finck         if( table_dec85[str[i]] == 0xff )
151c2c66affSColin Finck             return FALSE;
152c2c66affSColin Finck         if( (i%5) == 4 )
153c2c66affSColin Finck             p[i/5] = val;
154c2c66affSColin Finck         base *= 85;
155c2c66affSColin Finck     }
156c2c66affSColin Finck     return TRUE;
157c2c66affSColin Finck }
158c2c66affSColin Finck 
159c2c66affSColin Finck /*
160c2c66affSColin Finck  *  Encodes a base85 guid given a GUID pointer
161c2c66affSColin Finck  *  Caller should provide a 21 character buffer for the encoded string.
162c2c66affSColin Finck  *
163c2c66affSColin Finck  *  returns TRUE if successful, FALSE if not
164c2c66affSColin Finck  */
encode_base85_guid(GUID * guid,LPWSTR str)165c2c66affSColin Finck BOOL encode_base85_guid( GUID *guid, LPWSTR str )
166c2c66affSColin Finck {
167c2c66affSColin Finck     unsigned int x, *p, i;
168c2c66affSColin Finck 
169c2c66affSColin Finck     p = (unsigned int*) guid;
170c2c66affSColin Finck     for( i=0; i<4; i++ )
171c2c66affSColin Finck     {
172c2c66affSColin Finck         x = p[i];
173c2c66affSColin Finck         *str++ = table_enc85[x%85];
174c2c66affSColin Finck         x = x/85;
175c2c66affSColin Finck         *str++ = table_enc85[x%85];
176c2c66affSColin Finck         x = x/85;
177c2c66affSColin Finck         *str++ = table_enc85[x%85];
178c2c66affSColin Finck         x = x/85;
179c2c66affSColin Finck         *str++ = table_enc85[x%85];
180c2c66affSColin Finck         x = x/85;
181c2c66affSColin Finck         *str++ = table_enc85[x%85];
182c2c66affSColin Finck     }
183c2c66affSColin Finck     *str = 0;
184c2c66affSColin Finck 
185c2c66affSColin Finck     return TRUE;
186c2c66affSColin Finck }
187c2c66affSColin Finck 
msi_version_str_to_dword(LPCWSTR p)188c2c66affSColin Finck DWORD msi_version_str_to_dword(LPCWSTR p)
189c2c66affSColin Finck {
190c2c66affSColin Finck     DWORD major, minor = 0, build = 0, version = 0;
191c2c66affSColin Finck 
192c2c66affSColin Finck     if (!p)
193c2c66affSColin Finck         return version;
194c2c66affSColin Finck 
195958f1addSwinesync     major = wcstol(p, NULL, 10);
196c2c66affSColin Finck 
197958f1addSwinesync     p = wcschr(p, '.');
198c2c66affSColin Finck     if (p)
199c2c66affSColin Finck     {
200958f1addSwinesync         minor = wcstol(p+1, NULL, 10);
201958f1addSwinesync         p = wcschr(p+1, '.');
202c2c66affSColin Finck         if (p)
203958f1addSwinesync             build = wcstol(p+1, NULL, 10);
204c2c66affSColin Finck     }
205c2c66affSColin Finck 
206c2c66affSColin Finck     return MAKELONG(build, MAKEWORD(minor, major));
207c2c66affSColin Finck }
208c2c66affSColin Finck 
msi_reg_set_val_str(HKEY hkey,LPCWSTR name,LPCWSTR value)209c2c66affSColin Finck LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
210c2c66affSColin Finck {
211c2c66affSColin Finck     DWORD len;
2120f67ae4bSwinesync     if (!value) value = L"";
213c2c66affSColin Finck     len = (lstrlenW(value) + 1) * sizeof (WCHAR);
214c2c66affSColin Finck     return RegSetValueExW( hkey, name, 0, REG_SZ, (const BYTE *)value, len );
215c2c66affSColin Finck }
216c2c66affSColin Finck 
msi_reg_set_val_multi_str(HKEY hkey,LPCWSTR name,LPCWSTR value)217c2c66affSColin Finck LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
218c2c66affSColin Finck {
219c2c66affSColin Finck     LPCWSTR p = value;
220c2c66affSColin Finck     while (*p) p += lstrlenW(p) + 1;
221c2c66affSColin Finck     return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
222c2c66affSColin Finck                            (const BYTE *)value, (p + 1 - value) * sizeof(WCHAR) );
223c2c66affSColin Finck }
224c2c66affSColin Finck 
msi_reg_set_val_dword(HKEY hkey,LPCWSTR name,DWORD val)225c2c66affSColin Finck LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
226c2c66affSColin Finck {
227c2c66affSColin Finck     return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
228c2c66affSColin Finck }
229c2c66affSColin Finck 
msi_reg_set_subkey_val(HKEY hkey,LPCWSTR path,LPCWSTR name,LPCWSTR val)230c2c66affSColin Finck LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
231c2c66affSColin Finck {
232c2c66affSColin Finck     HKEY hsubkey = 0;
233c2c66affSColin Finck     LONG r;
234c2c66affSColin Finck 
235c2c66affSColin Finck     r = RegCreateKeyW( hkey, path, &hsubkey );
236c2c66affSColin Finck     if (r != ERROR_SUCCESS)
237c2c66affSColin Finck         return r;
238c2c66affSColin Finck     r = msi_reg_set_val_str( hsubkey, name, val );
239c2c66affSColin Finck     RegCloseKey( hsubkey );
240c2c66affSColin Finck     return r;
241c2c66affSColin Finck }
242c2c66affSColin Finck 
msi_reg_get_val_str(HKEY hkey,LPCWSTR name)243c2c66affSColin Finck LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name )
244c2c66affSColin Finck {
245c2c66affSColin Finck     DWORD len = 0;
246c2c66affSColin Finck     LPWSTR val;
247c2c66affSColin Finck     LONG r;
248c2c66affSColin Finck 
249c2c66affSColin Finck     r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len);
250c2c66affSColin Finck     if (r != ERROR_SUCCESS)
251c2c66affSColin Finck         return NULL;
252c2c66affSColin Finck 
253c2c66affSColin Finck     len += sizeof (WCHAR);
254*f4be6dc3SMikhail     val = malloc( len );
255c2c66affSColin Finck     if (!val)
256c2c66affSColin Finck         return NULL;
257c2c66affSColin Finck     val[0] = 0;
258c2c66affSColin Finck     RegQueryValueExW(hkey, name, NULL, NULL, (LPBYTE) val, &len);
259c2c66affSColin Finck     return val;
260c2c66affSColin Finck }
261c2c66affSColin Finck 
msi_reg_get_val_dword(HKEY hkey,LPCWSTR name,DWORD * val)262c2c66affSColin Finck BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val)
263c2c66affSColin Finck {
264c2c66affSColin Finck     DWORD type, len = sizeof (DWORD);
265c2c66affSColin Finck     LONG r = RegQueryValueExW(hkey, name, NULL, &type, (LPBYTE) val, &len);
266c2c66affSColin Finck     return r == ERROR_SUCCESS && type == REG_DWORD;
267c2c66affSColin Finck }
268c2c66affSColin Finck 
get_user_sid(void)269c2c66affSColin Finck static WCHAR *get_user_sid(void)
270c2c66affSColin Finck {
271c2c66affSColin Finck     HANDLE token;
272c2c66affSColin Finck     DWORD size = 256;
273c2c66affSColin Finck     TOKEN_USER *user;
274c2c66affSColin Finck     WCHAR *ret;
275c2c66affSColin Finck 
276c2c66affSColin Finck     if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token )) return NULL;
277*f4be6dc3SMikhail     if (!(user = malloc( size )))
278c2c66affSColin Finck     {
279c2c66affSColin Finck         CloseHandle( token );
280c2c66affSColin Finck         return NULL;
281c2c66affSColin Finck     }
282c2c66affSColin Finck     if (!GetTokenInformation( token, TokenUser, user, size, &size ))
283c2c66affSColin Finck     {
284*f4be6dc3SMikhail         free( user );
285*f4be6dc3SMikhail         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || !(user = malloc( size )))
286c2c66affSColin Finck         {
287c2c66affSColin Finck             CloseHandle( token );
288c2c66affSColin Finck             return NULL;
289c2c66affSColin Finck         }
290c2c66affSColin Finck         GetTokenInformation( token, TokenUser, user, size, &size );
291c2c66affSColin Finck     }
292c2c66affSColin Finck     CloseHandle( token );
293c2c66affSColin Finck     if (!ConvertSidToStringSidW( user->User.Sid, &ret ))
294c2c66affSColin Finck     {
295*f4be6dc3SMikhail         free( user );
296c2c66affSColin Finck         return NULL;
297c2c66affSColin Finck     }
298*f4be6dc3SMikhail     free( user );
299c2c66affSColin Finck     return ret;
300c2c66affSColin Finck }
301c2c66affSColin Finck 
MSIREG_OpenUninstallKey(const WCHAR * product,enum platform platform,HKEY * key,BOOL create)302c2c66affSColin Finck UINT MSIREG_OpenUninstallKey(const WCHAR *product, enum platform platform, HKEY *key, BOOL create)
303c2c66affSColin Finck {
304c3c3655cSwinesync     REGSAM access = KEY_ALL_ACCESS;
305c2c66affSColin Finck     WCHAR keypath[0x200];
306c2c66affSColin Finck 
307c2c66affSColin Finck     TRACE("%s\n", debugstr_w(product));
308c2c66affSColin Finck 
309c3c3655cSwinesync     if (platform == PLATFORM_INTEL)
310c3c3655cSwinesync         access |= KEY_WOW64_32KEY;
311c2c66affSColin Finck     else
312c3c3655cSwinesync         access |= KEY_WOW64_64KEY;
3130f67ae4bSwinesync     lstrcpyW(keypath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\");
314958f1addSwinesync     lstrcatW(keypath, product);
315c3c3655cSwinesync     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
316c3c3655cSwinesync     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
317c2c66affSColin Finck }
318c2c66affSColin Finck 
MSIREG_DeleteUninstallKey(const WCHAR * product,enum platform platform)319c2c66affSColin Finck UINT MSIREG_DeleteUninstallKey(const WCHAR *product, enum platform platform)
320c2c66affSColin Finck {
321c3c3655cSwinesync     REGSAM access = KEY_ALL_ACCESS;
322c3c3655cSwinesync     HKEY parent;
323c3c3655cSwinesync     LONG r;
324c2c66affSColin Finck 
325c2c66affSColin Finck     TRACE("%s\n", debugstr_w(product));
326c2c66affSColin Finck 
327c3c3655cSwinesync     if (platform == PLATFORM_INTEL)
328c3c3655cSwinesync         access |= KEY_WOW64_32KEY;
329c2c66affSColin Finck     else
330c3c3655cSwinesync         access |= KEY_WOW64_64KEY;
3310f67ae4bSwinesync     if ((r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\",
3320f67ae4bSwinesync                            0, access, &parent))) return r;
333c3c3655cSwinesync     r = RegDeleteTreeW(parent, product);
334c3c3655cSwinesync     RegCloseKey(parent);
335c3c3655cSwinesync     return r;
336c2c66affSColin Finck }
337c2c66affSColin Finck 
MSIREG_OpenProductKey(LPCWSTR szProduct,LPCWSTR szUserSid,MSIINSTALLCONTEXT context,HKEY * key,BOOL create)338c2c66affSColin Finck UINT MSIREG_OpenProductKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
339c2c66affSColin Finck {
340c2c66affSColin Finck     HKEY root = HKEY_LOCAL_MACHINE;
341c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
342c2c66affSColin Finck     WCHAR *usersid = NULL, squashed_pc[SQUASHED_GUID_SIZE], keypath[MAX_PATH];
343c2c66affSColin Finck 
344c2c66affSColin Finck     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
345c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
346c2c66affSColin Finck 
347c2c66affSColin Finck     if (context == MSIINSTALLCONTEXT_MACHINE)
348c2c66affSColin Finck     {
3490f67ae4bSwinesync         lstrcpyW(keypath, L"Software\\Classes\\Installer\\Products\\");
350958f1addSwinesync         lstrcatW( keypath, squashed_pc );
351c2c66affSColin Finck     }
352c2c66affSColin Finck     else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
353c2c66affSColin Finck     {
354c2c66affSColin Finck         root = HKEY_CURRENT_USER;
3550f67ae4bSwinesync         lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Products\\" );
356958f1addSwinesync         lstrcatW( keypath, squashed_pc );
357c2c66affSColin Finck     }
358c2c66affSColin Finck     else
359c2c66affSColin Finck     {
360c2c66affSColin Finck         if (!szUserSid)
361c2c66affSColin Finck         {
362c2c66affSColin Finck             if (!(usersid = get_user_sid()))
363c2c66affSColin Finck             {
364c2c66affSColin Finck                 ERR("Failed to retrieve user SID\n");
365c2c66affSColin Finck                 return ERROR_FUNCTION_FAILED;
366c2c66affSColin Finck             }
367c2c66affSColin Finck             szUserSid = usersid;
368c2c66affSColin Finck         }
3690f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath),
3700f67ae4bSwinesync                   L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\%s\\Installer\\Products\\%s",
3710f67ae4bSwinesync                   szUserSid, squashed_pc );
372c2c66affSColin Finck         LocalFree(usersid);
373c2c66affSColin Finck     }
374c2c66affSColin Finck     if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL);
375c2c66affSColin Finck     return RegOpenKeyExW(root, keypath, 0, access, key);
376c2c66affSColin Finck }
377c2c66affSColin Finck 
MSIREG_DeleteUserProductKey(LPCWSTR szProduct)378c2c66affSColin Finck UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
379c2c66affSColin Finck {
380c2c66affSColin Finck     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
381c2c66affSColin Finck 
382c2c66affSColin Finck     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
383c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
384c2c66affSColin Finck 
3850f67ae4bSwinesync     lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Products\\" );
386958f1addSwinesync     lstrcatW( keypath, squashed_pc );
387c2c66affSColin Finck     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
388c2c66affSColin Finck }
389c2c66affSColin Finck 
MSIREG_OpenUserPatchesKey(LPCWSTR szPatch,HKEY * key,BOOL create)390c2c66affSColin Finck UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
391c2c66affSColin Finck {
392c2c66affSColin Finck     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
393c2c66affSColin Finck 
394c2c66affSColin Finck     if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED;
395c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc));
396c2c66affSColin Finck 
3970f67ae4bSwinesync     lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Patches\\" );
398958f1addSwinesync     lstrcatW( keypath, squashed_pc );
399c2c66affSColin Finck 
400c2c66affSColin Finck     if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
401c2c66affSColin Finck     return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
402c2c66affSColin Finck }
403c2c66affSColin Finck 
MSIREG_OpenFeaturesKey(LPCWSTR szProduct,LPCWSTR szUserSid,MSIINSTALLCONTEXT context,HKEY * key,BOOL create)404c2c66affSColin Finck UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context,
405c2c66affSColin Finck                             HKEY *key, BOOL create)
406c2c66affSColin Finck {
407c2c66affSColin Finck     HKEY root = HKEY_LOCAL_MACHINE;
408c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
409c2c66affSColin Finck     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[MAX_PATH], *usersid = NULL;
410c2c66affSColin Finck 
411c2c66affSColin Finck     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
412c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
413c2c66affSColin Finck 
414c2c66affSColin Finck     if (context == MSIINSTALLCONTEXT_MACHINE)
415c2c66affSColin Finck     {
4160f67ae4bSwinesync         lstrcpyW(keypath, L"Software\\Classes\\Installer\\Features\\");
417958f1addSwinesync         lstrcatW( keypath, squashed_pc );
418c2c66affSColin Finck     }
419c2c66affSColin Finck     else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
420c2c66affSColin Finck     {
421c2c66affSColin Finck         root = HKEY_CURRENT_USER;
4220f67ae4bSwinesync         lstrcpyW(keypath, L"Software\\Microsoft\\Installer\\Features\\");
423958f1addSwinesync         lstrcatW( keypath, squashed_pc );
424c2c66affSColin Finck     }
425c2c66affSColin Finck     else
426c2c66affSColin Finck     {
427c2c66affSColin Finck         if (!szUserSid)
428c2c66affSColin Finck         {
429c2c66affSColin Finck             if (!(usersid = get_user_sid()))
430c2c66affSColin Finck             {
431c2c66affSColin Finck                 ERR("Failed to retrieve user SID\n");
432c2c66affSColin Finck                 return ERROR_FUNCTION_FAILED;
433c2c66affSColin Finck             }
434c2c66affSColin Finck             szUserSid = usersid;
435c2c66affSColin Finck         }
4360f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath),
4370f67ae4bSwinesync                   L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\%s\\Installer\\Features\\%s",
4380f67ae4bSwinesync                   szUserSid, squashed_pc );
439c2c66affSColin Finck         LocalFree(usersid);
440c2c66affSColin Finck     }
441c2c66affSColin Finck     if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL);
442c2c66affSColin Finck     return RegOpenKeyExW(root, keypath, 0, access, key);
443c2c66affSColin Finck }
444c2c66affSColin Finck 
MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)445c2c66affSColin Finck UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
446c2c66affSColin Finck {
447c2c66affSColin Finck     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
448c2c66affSColin Finck 
449c2c66affSColin Finck     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
450c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
451c2c66affSColin Finck 
4520f67ae4bSwinesync     lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Features\\" );
453958f1addSwinesync     lstrcatW( keypath, squashed_pc );
454c2c66affSColin Finck     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
455c2c66affSColin Finck }
456c2c66affSColin Finck 
MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct,HKEY * key,BOOL create)457c2c66affSColin Finck static UINT MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
458c2c66affSColin Finck {
459c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
460c2c66affSColin Finck     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
461c2c66affSColin Finck 
462c2c66affSColin Finck     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
463c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
464c2c66affSColin Finck 
4650f67ae4bSwinesync     lstrcpyW(keypath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Features\\");
466958f1addSwinesync     lstrcatW( keypath, squashed_pc );
467c2c66affSColin Finck 
468c2c66affSColin Finck     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
469c2c66affSColin Finck     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
470c2c66affSColin Finck }
471c2c66affSColin Finck 
MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct,LPCWSTR szUserSid,MSIINSTALLCONTEXT context,HKEY * key,BOOL create)472c2c66affSColin Finck UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context,
473c2c66affSColin Finck                                     HKEY *key, BOOL create)
474c2c66affSColin Finck {
4750f67ae4bSwinesync     static const WCHAR fmtW[] =
4760f67ae4bSwinesync         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Products\\%s\\Features";
477c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
478c2c66affSColin Finck     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200], *usersid = NULL;
479c2c66affSColin Finck 
480c2c66affSColin Finck     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
481c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
482c2c66affSColin Finck 
483c2c66affSColin Finck     if (context == MSIINSTALLCONTEXT_MACHINE)
484c2c66affSColin Finck     {
4850f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_pc );
486c2c66affSColin Finck     }
487c2c66affSColin Finck     else
488c2c66affSColin Finck     {
489c2c66affSColin Finck         if (!szUserSid)
490c2c66affSColin Finck         {
491c2c66affSColin Finck             if (!(usersid = get_user_sid()))
492c2c66affSColin Finck             {
493c2c66affSColin Finck                 ERR("Failed to retrieve user SID\n");
494c2c66affSColin Finck                 return ERROR_FUNCTION_FAILED;
495c2c66affSColin Finck             }
496c2c66affSColin Finck             szUserSid = usersid;
497c2c66affSColin Finck         }
4980f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, szUserSid, squashed_pc );
499c2c66affSColin Finck         LocalFree(usersid);
500c2c66affSColin Finck     }
501c2c66affSColin Finck     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
502c2c66affSColin Finck     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
503c2c66affSColin Finck }
504c2c66affSColin Finck 
MSIREG_OpenUserComponentsKey(LPCWSTR szComponent,HKEY * key,BOOL create)505c2c66affSColin Finck UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY *key, BOOL create)
506c2c66affSColin Finck {
507c2c66affSColin Finck     WCHAR squashed_cc[SQUASHED_GUID_SIZE], keypath[0x200];
508c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
509c2c66affSColin Finck     UINT ret;
510c2c66affSColin Finck 
511c2c66affSColin Finck     if (!squash_guid( szComponent, squashed_cc)) return ERROR_FUNCTION_FAILED;
512c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_cc));
513c2c66affSColin Finck 
5140f67ae4bSwinesync     lstrcpyW(keypath, L"Software\\Microsoft\\Installer\\Components\\");
515958f1addSwinesync     lstrcatW( keypath, squashed_cc );
516c2c66affSColin Finck 
517c2c66affSColin Finck     if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
518c2c66affSColin Finck     ret = RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
519c2c66affSColin Finck     if (ret != ERROR_FILE_NOT_FOUND) return ret;
520c2c66affSColin Finck 
5210f67ae4bSwinesync     lstrcpyW(keypath, L"Software\\Classes\\Installer\\Components\\");
522958f1addSwinesync     lstrcatW( keypath, squashed_cc );
523c2c66affSColin Finck     return RegOpenKeyExW( HKEY_LOCAL_MACHINE, keypath, 0, access, key );
524c2c66affSColin Finck }
525c2c66affSColin Finck 
MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent,LPCWSTR szUserSid,HKEY * key,BOOL create)526c2c66affSColin Finck UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid, HKEY *key, BOOL create)
527c2c66affSColin Finck {
5280f67ae4bSwinesync     static const WCHAR fmtW[] =
5290f67ae4bSwinesync         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Components\\%s";
530c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
531c2c66affSColin Finck     WCHAR *usersid, squashed_comp[SQUASHED_GUID_SIZE], keypath[0x200];
532c2c66affSColin Finck 
533c2c66affSColin Finck     if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED;
534c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp));
535c2c66affSColin Finck 
536c2c66affSColin Finck     if (!szUserSid)
537c2c66affSColin Finck     {
538c2c66affSColin Finck         if (!(usersid = get_user_sid()))
539c2c66affSColin Finck         {
540c2c66affSColin Finck             ERR("Failed to retrieve user SID\n");
541c2c66affSColin Finck             return ERROR_FUNCTION_FAILED;
542c2c66affSColin Finck         }
5430f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_comp );
544c2c66affSColin Finck         LocalFree(usersid);
545c2c66affSColin Finck     }
5460f67ae4bSwinesync     else swprintf( keypath, ARRAY_SIZE(keypath), fmtW, szUserSid, squashed_comp );
547c2c66affSColin Finck 
548c2c66affSColin Finck     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
549c2c66affSColin Finck     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
550c2c66affSColin Finck }
551c2c66affSColin Finck 
MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent,LPCWSTR szUserSid)552c2c66affSColin Finck UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid)
553c2c66affSColin Finck {
5540f67ae4bSwinesync     static const WCHAR fmtW[] =
5550f67ae4bSwinesync         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Components";
556c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
557c2c66affSColin Finck     WCHAR *usersid, squashed_comp[SQUASHED_GUID_SIZE], keypath[0x200];
558c2c66affSColin Finck     HKEY hkey;
559c2c66affSColin Finck     LONG r;
560c2c66affSColin Finck 
561c2c66affSColin Finck     if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED;
562c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp));
563c2c66affSColin Finck 
564c2c66affSColin Finck     if (!szUserSid)
565c2c66affSColin Finck     {
566c2c66affSColin Finck         if (!(usersid = get_user_sid()))
567c2c66affSColin Finck         {
568c2c66affSColin Finck             ERR("Failed to retrieve user SID\n");
569c2c66affSColin Finck             return ERROR_FUNCTION_FAILED;
570c2c66affSColin Finck         }
5710f67ae4bSwinesync         swprintf(keypath, ARRAY_SIZE(keypath), fmtW, usersid);
572c2c66affSColin Finck         LocalFree(usersid);
573c2c66affSColin Finck     }
5740f67ae4bSwinesync     else swprintf(keypath, ARRAY_SIZE(keypath), fmtW, szUserSid);
575c2c66affSColin Finck 
576c2c66affSColin Finck     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
577c2c66affSColin Finck     r = RegDeleteTreeW( hkey, squashed_comp );
578c2c66affSColin Finck     RegCloseKey(hkey);
579c2c66affSColin Finck     return r;
580c2c66affSColin Finck }
581c2c66affSColin Finck 
MSIREG_OpenUserDataProductKey(LPCWSTR szProduct,MSIINSTALLCONTEXT dwContext,LPCWSTR szUserSid,HKEY * key,BOOL create)582c2c66affSColin Finck UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create)
583c2c66affSColin Finck {
5840f67ae4bSwinesync     static const WCHAR fmtW[] =
5850f67ae4bSwinesync         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Products\\%s";
586c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
587c2c66affSColin Finck     WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
588c2c66affSColin Finck 
589c2c66affSColin Finck     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
590c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
591c2c66affSColin Finck 
592c2c66affSColin Finck     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
5930f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_pc );
594c2c66affSColin Finck     else if (szUserSid)
5950f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, szUserSid, squashed_pc );
596c2c66affSColin Finck     else
597c2c66affSColin Finck     {
598c2c66affSColin Finck         if (!(usersid = get_user_sid()))
599c2c66affSColin Finck         {
600c2c66affSColin Finck             ERR("Failed to retrieve user SID\n");
601c2c66affSColin Finck             return ERROR_FUNCTION_FAILED;
602c2c66affSColin Finck         }
6030f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_pc );
604c2c66affSColin Finck         LocalFree(usersid);
605c2c66affSColin Finck     }
606c2c66affSColin Finck     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
607c2c66affSColin Finck     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
608c2c66affSColin Finck }
609c2c66affSColin Finck 
MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch,MSIINSTALLCONTEXT dwContext,HKEY * key,BOOL create)610c2c66affSColin Finck UINT MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch, MSIINSTALLCONTEXT dwContext, HKEY *key, BOOL create)
611c2c66affSColin Finck {
6120f67ae4bSwinesync     static const WCHAR fmtW[] =
6130f67ae4bSwinesync         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Patches\\%s";
614c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
615c2c66affSColin Finck     WCHAR *usersid, squashed_patch[SQUASHED_GUID_SIZE], keypath[0x200];
616c2c66affSColin Finck 
617c2c66affSColin Finck     if (!squash_guid( szPatch, squashed_patch )) return ERROR_FUNCTION_FAILED;
618c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_patch));
619c2c66affSColin Finck 
620c2c66affSColin Finck     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
6210f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_patch );
622c2c66affSColin Finck     else
623c2c66affSColin Finck     {
624c2c66affSColin Finck         if (!(usersid = get_user_sid()))
625c2c66affSColin Finck         {
626c2c66affSColin Finck             ERR("Failed to retrieve user SID\n");
627c2c66affSColin Finck             return ERROR_FUNCTION_FAILED;
628c2c66affSColin Finck         }
6290f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_patch );
630c2c66affSColin Finck         LocalFree(usersid);
631c2c66affSColin Finck     }
632c2c66affSColin Finck     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
633c2c66affSColin Finck     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
634c2c66affSColin Finck }
635c2c66affSColin Finck 
MSIREG_DeleteUserDataPatchKey(LPCWSTR patch,MSIINSTALLCONTEXT context)636c2c66affSColin Finck UINT MSIREG_DeleteUserDataPatchKey(LPCWSTR patch, MSIINSTALLCONTEXT context)
637c2c66affSColin Finck {
6380f67ae4bSwinesync     static const WCHAR fmtW[] =
6390f67ae4bSwinesync         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Patches";
640c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
641c2c66affSColin Finck     WCHAR *usersid, squashed_patch[SQUASHED_GUID_SIZE], keypath[0x200];
642c2c66affSColin Finck     HKEY hkey;
643c2c66affSColin Finck     LONG r;
644c2c66affSColin Finck 
645c2c66affSColin Finck     if (!squash_guid( patch, squashed_patch )) return ERROR_FUNCTION_FAILED;
646c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(patch), debugstr_w(squashed_patch));
647c2c66affSColin Finck 
648c2c66affSColin Finck     if (context == MSIINSTALLCONTEXT_MACHINE)
6490f67ae4bSwinesync         swprintf(keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18");
650c2c66affSColin Finck     else
651c2c66affSColin Finck     {
652c2c66affSColin Finck         if (!(usersid = get_user_sid()))
653c2c66affSColin Finck         {
654c2c66affSColin Finck             ERR("Failed to retrieve user SID\n");
655c2c66affSColin Finck             return ERROR_FUNCTION_FAILED;
656c2c66affSColin Finck         }
6570f67ae4bSwinesync         swprintf(keypath, ARRAY_SIZE(keypath), fmtW, usersid);
658c2c66affSColin Finck         LocalFree(usersid);
659c2c66affSColin Finck     }
660c2c66affSColin Finck     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
661c2c66affSColin Finck     r = RegDeleteTreeW( hkey, squashed_patch );
662c2c66affSColin Finck     RegCloseKey(hkey);
663c2c66affSColin Finck     return r;
664c2c66affSColin Finck }
665c2c66affSColin Finck 
MSIREG_OpenUserDataProductPatchesKey(LPCWSTR product,MSIINSTALLCONTEXT context,HKEY * key,BOOL create)666c2c66affSColin Finck UINT MSIREG_OpenUserDataProductPatchesKey(LPCWSTR product, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
667c2c66affSColin Finck {
6680f67ae4bSwinesync     static const WCHAR fmtW[] =
6690f67ae4bSwinesync         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Products\\%s\\Patches";
670c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
671c2c66affSColin Finck     WCHAR *usersid, squashed_product[SQUASHED_GUID_SIZE], keypath[0x200];
672c2c66affSColin Finck 
673c2c66affSColin Finck     if (!squash_guid( product, squashed_product )) return ERROR_FUNCTION_FAILED;
674c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(product), debugstr_w(squashed_product));
675c2c66affSColin Finck 
676c2c66affSColin Finck     if (context == MSIINSTALLCONTEXT_MACHINE)
6770f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_product );
678c2c66affSColin Finck     else
679c2c66affSColin Finck     {
680c2c66affSColin Finck         if (!(usersid = get_user_sid()))
681c2c66affSColin Finck         {
682c2c66affSColin Finck             ERR("Failed to retrieve user SID\n");
683c2c66affSColin Finck             return ERROR_FUNCTION_FAILED;
684c2c66affSColin Finck         }
6850f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_product );
686c2c66affSColin Finck         LocalFree(usersid);
687c2c66affSColin Finck     }
688c2c66affSColin Finck     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
689c2c66affSColin Finck     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
690c2c66affSColin Finck }
691c2c66affSColin Finck 
MSIREG_OpenInstallProps(LPCWSTR szProduct,MSIINSTALLCONTEXT dwContext,LPCWSTR szUserSid,HKEY * key,BOOL create)692c2c66affSColin Finck UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create)
693c2c66affSColin Finck {
6940f67ae4bSwinesync     static const WCHAR fmtW[] =
6950f67ae4bSwinesync         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Products\\%s\\InstallProperties";
696c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
697c2c66affSColin Finck     WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
698c2c66affSColin Finck 
699c2c66affSColin Finck     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
700c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
701c2c66affSColin Finck 
702c2c66affSColin Finck     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
7030f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18", squashed_pc );
704c2c66affSColin Finck     else if (szUserSid)
7050f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, szUserSid, squashed_pc );
706c2c66affSColin Finck     else
707c2c66affSColin Finck     {
708c2c66affSColin Finck         if (!(usersid = get_user_sid()))
709c2c66affSColin Finck         {
710c2c66affSColin Finck             ERR("Failed to retrieve user SID\n");
711c2c66affSColin Finck             return ERROR_FUNCTION_FAILED;
712c2c66affSColin Finck         }
7130f67ae4bSwinesync         swprintf( keypath, ARRAY_SIZE(keypath), fmtW, usersid, squashed_pc );
714c2c66affSColin Finck         LocalFree(usersid);
715c2c66affSColin Finck     }
716c2c66affSColin Finck     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
717c2c66affSColin Finck     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
718c2c66affSColin Finck }
719c2c66affSColin Finck 
MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct,MSIINSTALLCONTEXT context)720c2c66affSColin Finck UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context)
721c2c66affSColin Finck {
7220f67ae4bSwinesync     static const WCHAR fmtW[] =
7230f67ae4bSwinesync         L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\%s\\Products";
724c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
725c2c66affSColin Finck     WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
726c2c66affSColin Finck     HKEY hkey;
727c2c66affSColin Finck     LONG r;
728c2c66affSColin Finck 
729c2c66affSColin Finck     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
730c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
731c2c66affSColin Finck 
732c2c66affSColin Finck     if (context == MSIINSTALLCONTEXT_MACHINE)
7330f67ae4bSwinesync         swprintf(keypath, ARRAY_SIZE(keypath), fmtW, L"S-1-5-18");
734c2c66affSColin Finck     else
735c2c66affSColin Finck     {
736c2c66affSColin Finck         if (!(usersid = get_user_sid()))
737c2c66affSColin Finck         {
738c2c66affSColin Finck             ERR("Failed to retrieve user SID\n");
739c2c66affSColin Finck             return ERROR_FUNCTION_FAILED;
740c2c66affSColin Finck         }
7410f67ae4bSwinesync         swprintf(keypath, ARRAY_SIZE(keypath), fmtW, usersid);
742c2c66affSColin Finck         LocalFree(usersid);
743c2c66affSColin Finck     }
744c2c66affSColin Finck 
745c2c66affSColin Finck     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
746c2c66affSColin Finck     r = RegDeleteTreeW( hkey, squashed_pc );
747c2c66affSColin Finck     RegCloseKey(hkey);
748c2c66affSColin Finck     return r;
749c2c66affSColin Finck }
750c2c66affSColin Finck 
MSIREG_DeleteProductKey(LPCWSTR szProduct)751c2c66affSColin Finck UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
752c2c66affSColin Finck {
753c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
754c2c66affSColin Finck     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
755c2c66affSColin Finck     HKEY hkey;
756c2c66affSColin Finck     LONG r;
757c2c66affSColin Finck 
758c2c66affSColin Finck     if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
759c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
760c2c66affSColin Finck 
7610f67ae4bSwinesync     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products",
7620f67ae4bSwinesync                       0, access, &hkey)) return ERROR_SUCCESS;
763c2c66affSColin Finck     r = RegDeleteTreeW( hkey, squashed_pc );
764c2c66affSColin Finck     RegCloseKey(hkey);
765c2c66affSColin Finck     return r;
766c2c66affSColin Finck }
767c2c66affSColin Finck 
MSIREG_OpenPatchesKey(LPCWSTR szPatch,HKEY * key,BOOL create)768c2c66affSColin Finck UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
769c2c66affSColin Finck {
770c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
771c2c66affSColin Finck     WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
772c2c66affSColin Finck 
773c2c66affSColin Finck     if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED;
774c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc));
775c2c66affSColin Finck 
77674f53b4bSwinesync     lstrcpyW( keypath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Patches\\" );
77774f53b4bSwinesync     lstrcatW( keypath, squashed_pc );
778c2c66affSColin Finck 
779c2c66affSColin Finck     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
780c2c66affSColin Finck     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
781c2c66affSColin Finck }
782c2c66affSColin Finck 
MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode,HKEY * key,BOOL create)783c2c66affSColin Finck UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create)
784c2c66affSColin Finck {
785c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
786c2c66affSColin Finck     WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
787c2c66affSColin Finck 
788c2c66affSColin Finck     if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
789c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
790c2c66affSColin Finck 
7910f67ae4bSwinesync     lstrcpyW( keypath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\" );
792958f1addSwinesync     lstrcatW( keypath, squashed_uc );
793c2c66affSColin Finck 
794c2c66affSColin Finck     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
795c2c66affSColin Finck     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
796c2c66affSColin Finck }
797c2c66affSColin Finck 
MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode,HKEY * key,BOOL create)798c2c66affSColin Finck UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
799c2c66affSColin Finck {
800c2c66affSColin Finck     WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
801c2c66affSColin Finck 
802c2c66affSColin Finck     if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
803c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
804c2c66affSColin Finck 
8050f67ae4bSwinesync     lstrcpyW(keypath, L"Software\\Microsoft\\Installer\\UpgradeCodes\\");
806958f1addSwinesync     lstrcatW( keypath, squashed_uc );
807c2c66affSColin Finck 
808c2c66affSColin Finck     if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
809c2c66affSColin Finck     return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
810c2c66affSColin Finck }
811c2c66affSColin Finck 
MSIREG_DeleteUpgradeCodesKey(const WCHAR * code)812c2c66affSColin Finck UINT MSIREG_DeleteUpgradeCodesKey( const WCHAR *code )
813c2c66affSColin Finck {
814c2c66affSColin Finck     WCHAR squashed_code[SQUASHED_GUID_SIZE];
815c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
816c2c66affSColin Finck     HKEY hkey;
817c2c66affSColin Finck     LONG ret;
818c2c66affSColin Finck 
819c2c66affSColin Finck     if (!squash_guid( code, squashed_code )) return ERROR_FUNCTION_FAILED;
820c2c66affSColin Finck     TRACE( "%s squashed %s\n", debugstr_w(code), debugstr_w(squashed_code) );
821c2c66affSColin Finck 
8220f67ae4bSwinesync     if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\",
8230f67ae4bSwinesync                        0, access, &hkey )) return ERROR_SUCCESS;
824c2c66affSColin Finck     ret = RegDeleteTreeW( hkey, squashed_code );
825c2c66affSColin Finck     RegCloseKey( hkey );
826c2c66affSColin Finck     return ret;
827c2c66affSColin Finck }
828c2c66affSColin Finck 
MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode)829c2c66affSColin Finck UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode)
830c2c66affSColin Finck {
831c2c66affSColin Finck     WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
832c2c66affSColin Finck 
833c2c66affSColin Finck     if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
834c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
835c2c66affSColin Finck 
8360f67ae4bSwinesync     lstrcpyW(keypath, L"Software\\Microsoft\\Installer\\UpgradeCodes\\");
837958f1addSwinesync     lstrcatW( keypath, squashed_uc );
838c2c66affSColin Finck     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
839c2c66affSColin Finck }
840c2c66affSColin Finck 
MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode)841c2c66affSColin Finck UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode)
842c2c66affSColin Finck {
843c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
844c2c66affSColin Finck     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
845c2c66affSColin Finck     HKEY hkey;
846c2c66affSColin Finck     LONG r;
847c2c66affSColin Finck 
848c2c66affSColin Finck     if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED;
849c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc));
850c2c66affSColin Finck 
8510f67ae4bSwinesync     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Classes\\Installer\\Products", 0, access, &hkey))
8520f67ae4bSwinesync         return ERROR_SUCCESS;
853c2c66affSColin Finck     r = RegDeleteTreeW( hkey, squashed_pc );
854c2c66affSColin Finck     RegCloseKey(hkey);
855c2c66affSColin Finck     return r;
856c2c66affSColin Finck }
857c2c66affSColin Finck 
MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode)858c2c66affSColin Finck UINT MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode)
859c2c66affSColin Finck {
860c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
861c2c66affSColin Finck     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
862c2c66affSColin Finck     HKEY hkey;
863c2c66affSColin Finck     LONG r;
864c2c66affSColin Finck 
865c2c66affSColin Finck     if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED;
866c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc));
867c2c66affSColin Finck 
8680f67ae4bSwinesync     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Classes\\Installer\\Features", 0, access, &hkey))
8690f67ae4bSwinesync         return ERROR_SUCCESS;
870c2c66affSColin Finck     r = RegDeleteTreeW( hkey, squashed_pc );
871c2c66affSColin Finck     RegCloseKey(hkey);
872c2c66affSColin Finck     return r;
873c2c66affSColin Finck }
874c2c66affSColin Finck 
MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode,HKEY * key,BOOL create)875c2c66affSColin Finck UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create)
876c2c66affSColin Finck {
877c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
878c2c66affSColin Finck     WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
879c2c66affSColin Finck 
880c2c66affSColin Finck     if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
881c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
882c2c66affSColin Finck 
8830f67ae4bSwinesync     lstrcpyW(keypath, L"Software\\Classes\\Installer\\UpgradeCodes\\");
884958f1addSwinesync     lstrcatW( keypath, squashed_uc );
885c2c66affSColin Finck 
886c2c66affSColin Finck     if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
887c2c66affSColin Finck     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
888c2c66affSColin Finck }
889c2c66affSColin Finck 
MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode)890c2c66affSColin Finck UINT MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode)
891c2c66affSColin Finck {
892c2c66affSColin Finck     REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
893c2c66affSColin Finck     WCHAR squashed_uc[SQUASHED_GUID_SIZE];
894c2c66affSColin Finck     HKEY hkey;
895c2c66affSColin Finck     LONG r;
896c2c66affSColin Finck 
897c2c66affSColin Finck     if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
898c2c66affSColin Finck     TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
899c2c66affSColin Finck 
9000f67ae4bSwinesync     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Classes\\Installer\\UpgradeCodes", 0, access, &hkey))
9010f67ae4bSwinesync         return ERROR_SUCCESS;
902c2c66affSColin Finck     r = RegDeleteTreeW( hkey, squashed_uc );
903c2c66affSColin Finck     RegCloseKey(hkey);
904c2c66affSColin Finck     return r;
905c2c66affSColin Finck }
906c2c66affSColin Finck 
907c2c66affSColin Finck /*************************************************************************
908c2c66affSColin Finck  *  MsiDecomposeDescriptorW   [MSI.@]
909c2c66affSColin Finck  *
910c2c66affSColin Finck  * Decomposes an MSI descriptor into product, feature and component parts.
911c2c66affSColin Finck  * An MSI descriptor is a string of the form:
912c2c66affSColin Finck  *   [base 85 guid] [feature code] '>' [base 85 guid] or
913c2c66affSColin Finck  *   [base 85 guid] [feature code] '<'
914c2c66affSColin Finck  *
915c2c66affSColin Finck  * PARAMS
916c2c66affSColin Finck  *   szDescriptor  [I]  the descriptor to decompose
917c2c66affSColin Finck  *   szProduct     [O]  buffer of MAX_FEATURE_CHARS+1 for the product guid
918c2c66affSColin Finck  *   szFeature     [O]  buffer of MAX_FEATURE_CHARS+1 for the feature code
919c2c66affSColin Finck  *   szComponent   [O]  buffer of MAX_FEATURE_CHARS+1 for the component guid
920c2c66affSColin Finck  *   pUsed         [O]  the length of the descriptor
921c2c66affSColin Finck  *
922c2c66affSColin Finck  * RETURNS
923c2c66affSColin Finck  *   ERROR_SUCCESS             if everything worked correctly
924c2c66affSColin Finck  *   ERROR_INVALID_PARAMETER   if the descriptor was invalid
925c2c66affSColin Finck  *
926c2c66affSColin Finck  */
MsiDecomposeDescriptorW(LPCWSTR szDescriptor,LPWSTR szProduct,LPWSTR szFeature,LPWSTR szComponent,LPDWORD pUsed)927c2c66affSColin Finck UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
928c2c66affSColin Finck                 LPWSTR szFeature, LPWSTR szComponent, LPDWORD pUsed )
929c2c66affSColin Finck {
930c2c66affSColin Finck     UINT len;
931c2c66affSColin Finck     const WCHAR *p;
932c2c66affSColin Finck     GUID product, component;
933c2c66affSColin Finck 
934c2c66affSColin Finck     TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
935c2c66affSColin Finck           szFeature, szComponent, pUsed);
936c2c66affSColin Finck 
937c2c66affSColin Finck     if (!decode_base85_guid( szDescriptor, &product ))
938c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
939c2c66affSColin Finck 
940c2c66affSColin Finck     TRACE("product %s\n", debugstr_guid( &product ));
941c2c66affSColin Finck 
942958f1addSwinesync     if (!(p = wcschr( &szDescriptor[20], '>' )))
943958f1addSwinesync         p = wcschr( &szDescriptor[20], '<' );
944c2c66affSColin Finck     if (!p)
945c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
946c2c66affSColin Finck 
947c2c66affSColin Finck     len = (p - &szDescriptor[20]);
948c2c66affSColin Finck     if( len > MAX_FEATURE_CHARS )
949c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
950c2c66affSColin Finck 
951c2c66affSColin Finck     TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
952c2c66affSColin Finck 
953c2c66affSColin Finck     if (*p == '>')
954c2c66affSColin Finck     {
955c2c66affSColin Finck         if (!decode_base85_guid( p+1, &component ))
956c2c66affSColin Finck             return ERROR_INVALID_PARAMETER;
957c2c66affSColin Finck         TRACE( "component %s\n", debugstr_guid(&component) );
958c2c66affSColin Finck     }
959c2c66affSColin Finck 
960c2c66affSColin Finck     if (szProduct)
961c2c66affSColin Finck         StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
962c2c66affSColin Finck     if (szComponent)
963c2c66affSColin Finck     {
964c2c66affSColin Finck         if (*p == '>')
965c2c66affSColin Finck             StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
966c2c66affSColin Finck         else
967c2c66affSColin Finck             szComponent[0] = 0;
968c2c66affSColin Finck     }
969c2c66affSColin Finck     if (szFeature)
970c2c66affSColin Finck     {
971c2c66affSColin Finck         memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
972c2c66affSColin Finck         szFeature[len] = 0;
973c2c66affSColin Finck     }
974c2c66affSColin Finck 
975c2c66affSColin Finck     len = p - szDescriptor + 1;
976c2c66affSColin Finck     if (*p == '>') len += 20;
977c2c66affSColin Finck 
978c2c66affSColin Finck     TRACE("length = %d\n", len);
979c2c66affSColin Finck     if (pUsed) *pUsed = len;
980c2c66affSColin Finck 
981c2c66affSColin Finck     return ERROR_SUCCESS;
982c2c66affSColin Finck }
983c2c66affSColin Finck 
MsiDecomposeDescriptorA(LPCSTR szDescriptor,LPSTR szProduct,LPSTR szFeature,LPSTR szComponent,LPDWORD pUsed)984c2c66affSColin Finck UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
985c2c66affSColin Finck                 LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed )
986c2c66affSColin Finck {
987c2c66affSColin Finck     WCHAR product[MAX_FEATURE_CHARS+1];
988c2c66affSColin Finck     WCHAR feature[MAX_FEATURE_CHARS+1];
989c2c66affSColin Finck     WCHAR component[MAX_FEATURE_CHARS+1];
990c2c66affSColin Finck     LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
991c2c66affSColin Finck     UINT r;
992c2c66affSColin Finck 
993c2c66affSColin Finck     TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
994c2c66affSColin Finck           szFeature, szComponent, pUsed);
995c2c66affSColin Finck 
996c2c66affSColin Finck     str = strdupAtoW( szDescriptor );
997c2c66affSColin Finck     if( szDescriptor && !str )
998c2c66affSColin Finck         return ERROR_OUTOFMEMORY;
999c2c66affSColin Finck 
1000c2c66affSColin Finck     if (szProduct)
1001c2c66affSColin Finck         p = product;
1002c2c66affSColin Finck     if (szFeature)
1003c2c66affSColin Finck         f = feature;
1004c2c66affSColin Finck     if (szComponent)
1005c2c66affSColin Finck         c = component;
1006c2c66affSColin Finck 
1007c2c66affSColin Finck     r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
1008c2c66affSColin Finck 
1009c2c66affSColin Finck     if (r == ERROR_SUCCESS)
1010c2c66affSColin Finck     {
1011c2c66affSColin Finck         WideCharToMultiByte( CP_ACP, 0, p, -1,
1012c2c66affSColin Finck                              szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
1013c2c66affSColin Finck         WideCharToMultiByte( CP_ACP, 0, f, -1,
1014c2c66affSColin Finck                              szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
1015c2c66affSColin Finck         WideCharToMultiByte( CP_ACP, 0, c, -1,
1016c2c66affSColin Finck                              szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
1017c2c66affSColin Finck     }
1018c2c66affSColin Finck 
1019*f4be6dc3SMikhail     free( str );
1020c2c66affSColin Finck 
1021c2c66affSColin Finck     return r;
1022c2c66affSColin Finck }
1023c2c66affSColin Finck 
MsiEnumProductsA(DWORD index,char * lpguid)102402f995b2Swinesync UINT WINAPI MsiEnumProductsA( DWORD index, char *lpguid )
1025c2c66affSColin Finck {
1026c2c66affSColin Finck     DWORD r;
1027c2c66affSColin Finck     WCHAR szwGuid[GUID_SIZE];
1028c2c66affSColin Finck 
102902f995b2Swinesync     TRACE( "%lu, %p\n", index, lpguid );
1030c2c66affSColin Finck 
1031c2c66affSColin Finck     if (NULL == lpguid)
1032c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1033c2c66affSColin Finck     r = MsiEnumProductsW(index, szwGuid);
1034c2c66affSColin Finck     if( r == ERROR_SUCCESS )
1035c2c66affSColin Finck         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1036c2c66affSColin Finck 
1037c2c66affSColin Finck     return r;
1038c2c66affSColin Finck }
1039c2c66affSColin Finck 
MsiEnumProductsW(DWORD index,WCHAR * lpguid)104002f995b2Swinesync UINT WINAPI MsiEnumProductsW( DWORD index, WCHAR *lpguid )
1041c2c66affSColin Finck {
104202f995b2Swinesync     TRACE("%lu, %p\n", index, lpguid );
1043c2c66affSColin Finck 
1044c2c66affSColin Finck     if (NULL == lpguid)
1045c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1046c2c66affSColin Finck 
10470f67ae4bSwinesync     return MsiEnumProductsExW( NULL, L"S-1-1-0", MSIINSTALLCONTEXT_ALL, index, lpguid,
1048c2c66affSColin Finck                                NULL, NULL, NULL );
1049c2c66affSColin Finck }
1050c2c66affSColin Finck 
MsiEnumFeaturesA(const char * szProduct,DWORD index,char * szFeature,char * szParent)105102f995b2Swinesync UINT WINAPI MsiEnumFeaturesA( const char *szProduct, DWORD index, char *szFeature, char *szParent )
1052c2c66affSColin Finck {
1053c2c66affSColin Finck     DWORD r;
1054c2c66affSColin Finck     WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
105502f995b2Swinesync     WCHAR *szwProduct = NULL;
1056c2c66affSColin Finck 
105702f995b2Swinesync     TRACE( "%s, %lu, %p, %p\n", debugstr_a(szProduct), index, szFeature, szParent );
1058c2c66affSColin Finck 
1059c2c66affSColin Finck     if( szProduct )
1060c2c66affSColin Finck     {
1061c2c66affSColin Finck         szwProduct = strdupAtoW( szProduct );
1062c2c66affSColin Finck         if( !szwProduct )
1063c2c66affSColin Finck             return ERROR_OUTOFMEMORY;
1064c2c66affSColin Finck     }
1065c2c66affSColin Finck 
1066c2c66affSColin Finck     r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
1067c2c66affSColin Finck     if( r == ERROR_SUCCESS )
1068c2c66affSColin Finck     {
106902f995b2Swinesync         WideCharToMultiByte(CP_ACP, 0, szwFeature, -1, szFeature, GUID_SIZE, NULL, NULL);
107002f995b2Swinesync         WideCharToMultiByte(CP_ACP, 0, szwParent, -1, szParent, GUID_SIZE, NULL, NULL);
1071c2c66affSColin Finck     }
1072c2c66affSColin Finck 
1073*f4be6dc3SMikhail     free(szwProduct);
1074c2c66affSColin Finck 
1075c2c66affSColin Finck     return r;
1076c2c66affSColin Finck }
1077c2c66affSColin Finck 
MsiEnumFeaturesW(const WCHAR * szProduct,DWORD index,WCHAR * szFeature,WCHAR * szParent)107802f995b2Swinesync UINT WINAPI MsiEnumFeaturesW( const WCHAR *szProduct, DWORD index, WCHAR *szFeature, WCHAR *szParent )
1079c2c66affSColin Finck {
1080c2c66affSColin Finck     HKEY hkeyProduct = 0;
1081c2c66affSColin Finck     DWORD r, sz;
1082c2c66affSColin Finck 
108302f995b2Swinesync     TRACE( "%s, %lu, %p, %p\n", debugstr_w(szProduct), index, szFeature, szParent );
1084c2c66affSColin Finck 
1085c2c66affSColin Finck     if( !szProduct )
1086c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1087c2c66affSColin Finck 
1088c2c66affSColin Finck     r = MSIREG_OpenInstallerFeaturesKey(szProduct,&hkeyProduct,FALSE);
1089c2c66affSColin Finck     if( r != ERROR_SUCCESS )
1090c2c66affSColin Finck         return ERROR_NO_MORE_ITEMS;
1091c2c66affSColin Finck 
1092c2c66affSColin Finck     sz = GUID_SIZE;
1093c2c66affSColin Finck     r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
1094c2c66affSColin Finck     RegCloseKey(hkeyProduct);
1095c2c66affSColin Finck 
1096c2c66affSColin Finck     return r;
1097c2c66affSColin Finck }
1098c2c66affSColin Finck 
MsiEnumComponentsA(DWORD index,char * lpguid)109902f995b2Swinesync UINT WINAPI MsiEnumComponentsA( DWORD index, char *lpguid )
1100c2c66affSColin Finck {
1101c2c66affSColin Finck     DWORD r;
1102c2c66affSColin Finck     WCHAR szwGuid[GUID_SIZE];
1103c2c66affSColin Finck 
110402f995b2Swinesync     TRACE( "%lu, %p\n", index, lpguid );
1105c2c66affSColin Finck 
1106c2c66affSColin Finck     if (!lpguid) return ERROR_INVALID_PARAMETER;
1107c2c66affSColin Finck 
1108c2c66affSColin Finck     r = MsiEnumComponentsW(index, szwGuid);
1109c2c66affSColin Finck     if( r == ERROR_SUCCESS )
1110c2c66affSColin Finck         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1111c2c66affSColin Finck 
1112c2c66affSColin Finck     return r;
1113c2c66affSColin Finck }
1114c2c66affSColin Finck 
MsiEnumComponentsW(DWORD index,WCHAR * lpguid)111502f995b2Swinesync UINT WINAPI MsiEnumComponentsW( DWORD index, WCHAR *lpguid )
1116c2c66affSColin Finck {
111702f995b2Swinesync     TRACE( "%lu, %p\n", index, lpguid );
1118c2c66affSColin Finck 
1119c2c66affSColin Finck     if (!lpguid) return ERROR_INVALID_PARAMETER;
1120c2c66affSColin Finck 
11210f67ae4bSwinesync     return MsiEnumComponentsExW( L"S-1-1-0", MSIINSTALLCONTEXT_ALL, index, lpguid, NULL, NULL, NULL );
1122c2c66affSColin Finck }
1123c2c66affSColin Finck 
MsiEnumComponentsExA(const char * user_sid,DWORD ctx,DWORD index,CHAR guid[39],MSIINSTALLCONTEXT * installed_ctx,char * sid,DWORD * sid_len)112402f995b2Swinesync UINT WINAPI MsiEnumComponentsExA( const char *user_sid, DWORD ctx, DWORD index, CHAR guid[39],
112502f995b2Swinesync                                   MSIINSTALLCONTEXT *installed_ctx, char *sid, DWORD *sid_len )
1126c2c66affSColin Finck {
1127c2c66affSColin Finck     UINT r;
1128c2c66affSColin Finck     WCHAR *user_sidW = NULL, *sidW = NULL, guidW[GUID_SIZE];
1129c2c66affSColin Finck 
113002f995b2Swinesync     TRACE( "%s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_a(user_sid), ctx, index, guid, installed_ctx,
1131c2c66affSColin Finck            sid, sid_len );
1132c2c66affSColin Finck 
1133c2c66affSColin Finck     if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
1134c2c66affSColin Finck     if (user_sid && !(user_sidW = strdupAtoW( user_sid ))) return ERROR_OUTOFMEMORY;
1135*f4be6dc3SMikhail     if (sid && !(sidW = malloc( *sid_len * sizeof(WCHAR) )))
1136c2c66affSColin Finck     {
1137*f4be6dc3SMikhail         free( user_sidW );
1138c2c66affSColin Finck         return ERROR_OUTOFMEMORY;
1139c2c66affSColin Finck     }
1140c2c66affSColin Finck     r = MsiEnumComponentsExW( user_sidW, ctx, index, guidW, installed_ctx, sidW, sid_len );
1141c2c66affSColin Finck     if (r == ERROR_SUCCESS)
1142c2c66affSColin Finck     {
1143c2c66affSColin Finck         if (guid) WideCharToMultiByte( CP_ACP, 0, guidW, GUID_SIZE, guid, GUID_SIZE, NULL, NULL );
1144c2c66affSColin Finck         if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
1145c2c66affSColin Finck     }
1146*f4be6dc3SMikhail     free( user_sidW );
1147*f4be6dc3SMikhail     free( sidW );
1148c2c66affSColin Finck     return r;
1149c2c66affSColin Finck }
1150c2c66affSColin Finck 
fetch_machine_component(DWORD ctx,DWORD index,DWORD * idx,WCHAR guid[39],MSIINSTALLCONTEXT * installed_ctx,LPWSTR sid,LPDWORD sid_len)1151c2c66affSColin Finck static UINT fetch_machine_component( DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
1152c2c66affSColin Finck                                      MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1153c2c66affSColin Finck {
1154c2c66affSColin Finck     UINT r = ERROR_SUCCESS;
1155c2c66affSColin Finck     WCHAR component[SQUASHED_GUID_SIZE];
1156c2c66affSColin Finck     DWORD i = 0, len_component;
1157c2c66affSColin Finck     REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
1158c2c66affSColin Finck     HKEY key_components;
1159c2c66affSColin Finck 
11600f67ae4bSwinesync     if (RegOpenKeyExW( HKEY_LOCAL_MACHINE,
11610f67ae4bSwinesync                        L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Components",
11620f67ae4bSwinesync                        0, access, &key_components ))
1163c2c66affSColin Finck         return ERROR_NO_MORE_ITEMS;
1164c2c66affSColin Finck 
11659792c08fSwinesync     len_component = ARRAY_SIZE( component );
1166c2c66affSColin Finck     while (!RegEnumKeyExW( key_components, i, component, &len_component, NULL, NULL, NULL, NULL ))
1167c2c66affSColin Finck     {
1168c2c66affSColin Finck         if (*idx == index) goto found;
1169c2c66affSColin Finck         (*idx)++;
11709792c08fSwinesync         len_component = ARRAY_SIZE( component );
1171c2c66affSColin Finck         i++;
1172c2c66affSColin Finck     }
1173c2c66affSColin Finck     RegCloseKey( key_components );
1174c2c66affSColin Finck     return ERROR_NO_MORE_ITEMS;
1175c2c66affSColin Finck 
1176c2c66affSColin Finck found:
1177c2c66affSColin Finck     if (sid_len)
1178c2c66affSColin Finck     {
1179c2c66affSColin Finck         if (*sid_len < 1)
1180c2c66affSColin Finck         {
1181c2c66affSColin Finck             *sid_len = 1;
1182c2c66affSColin Finck             r = ERROR_MORE_DATA;
1183c2c66affSColin Finck         }
1184c2c66affSColin Finck         else if (sid)
1185c2c66affSColin Finck         {
1186c2c66affSColin Finck             *sid_len = 0;
1187c2c66affSColin Finck             sid[0] = 0;
1188c2c66affSColin Finck         }
1189c2c66affSColin Finck     }
1190c2c66affSColin Finck     if (guid) unsquash_guid( component, guid );
1191c2c66affSColin Finck     if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
1192c2c66affSColin Finck     RegCloseKey( key_components );
1193c2c66affSColin Finck     return r;
1194c2c66affSColin Finck }
1195c2c66affSColin Finck 
fetch_user_component(const WCHAR * usersid,DWORD ctx,DWORD index,DWORD * idx,WCHAR guid[39],MSIINSTALLCONTEXT * installed_ctx,LPWSTR sid,LPDWORD sid_len)1196c2c66affSColin Finck static UINT fetch_user_component( const WCHAR *usersid, DWORD ctx, DWORD index, DWORD *idx,
1197c2c66affSColin Finck                                   WCHAR guid[39], MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid,
1198c2c66affSColin Finck                                   LPDWORD sid_len )
1199c2c66affSColin Finck {
1200c2c66affSColin Finck     UINT r = ERROR_SUCCESS;
1201c2c66affSColin Finck     WCHAR path[MAX_PATH], component[SQUASHED_GUID_SIZE], user[128];
1202c2c66affSColin Finck     DWORD i = 0, j = 0, len_component, len_user;
1203c2c66affSColin Finck     REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
1204c2c66affSColin Finck     HKEY key_users, key_components;
1205c2c66affSColin Finck 
1206c2c66affSColin Finck     if (ctx == MSIINSTALLCONTEXT_USERMANAGED) /* FIXME: where to find these? */
1207c2c66affSColin Finck         return ERROR_NO_MORE_ITEMS;
1208c2c66affSColin Finck 
12090f67ae4bSwinesync     if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData",
12100f67ae4bSwinesync                        0, access, &key_users )) return ERROR_NO_MORE_ITEMS;
1211c2c66affSColin Finck 
12129792c08fSwinesync     len_user = ARRAY_SIZE( user );
1213c2c66affSColin Finck     while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
1214c2c66affSColin Finck     {
12150f67ae4bSwinesync         if ((wcscmp( usersid, L"S-1-1-0" ) && wcscmp( usersid, user )) ||
12160f67ae4bSwinesync             !wcscmp( L"S-1-5-18", user ))
1217c2c66affSColin Finck         {
1218c2c66affSColin Finck             i++;
12199792c08fSwinesync             len_user = ARRAY_SIZE( user );
1220c2c66affSColin Finck             continue;
1221c2c66affSColin Finck         }
1222958f1addSwinesync         lstrcpyW( path, user );
12230f67ae4bSwinesync         lstrcatW( path, L"\\Components" );
1224c2c66affSColin Finck         if (RegOpenKeyExW( key_users, path, 0, access, &key_components ))
1225c2c66affSColin Finck         {
1226c2c66affSColin Finck             i++;
12279792c08fSwinesync             len_user = ARRAY_SIZE( user );
1228c2c66affSColin Finck             continue;
1229c2c66affSColin Finck         }
12309792c08fSwinesync         len_component = ARRAY_SIZE( component );
1231c2c66affSColin Finck         while (!RegEnumKeyExW( key_components, j, component, &len_component, NULL, NULL, NULL, NULL ))
1232c2c66affSColin Finck         {
1233c2c66affSColin Finck             if (*idx == index) goto found;
1234c2c66affSColin Finck             (*idx)++;
12359792c08fSwinesync             len_component = ARRAY_SIZE( component );
1236c2c66affSColin Finck             j++;
1237c2c66affSColin Finck         }
1238c2c66affSColin Finck         RegCloseKey( key_components );
12399792c08fSwinesync         len_user = ARRAY_SIZE( user );
1240c2c66affSColin Finck         i++;
1241c2c66affSColin Finck     }
1242c2c66affSColin Finck     RegCloseKey( key_users );
1243c2c66affSColin Finck     return ERROR_NO_MORE_ITEMS;
1244c2c66affSColin Finck 
1245c2c66affSColin Finck found:
1246c2c66affSColin Finck     if (sid_len)
1247c2c66affSColin Finck     {
1248c2c66affSColin Finck         if (*sid_len < len_user + 1)
1249c2c66affSColin Finck         {
1250c2c66affSColin Finck             *sid_len = len_user + 1;
1251c2c66affSColin Finck             r = ERROR_MORE_DATA;
1252c2c66affSColin Finck         }
1253c2c66affSColin Finck         else if (sid)
1254c2c66affSColin Finck         {
1255c2c66affSColin Finck             *sid_len = len_user;
1256958f1addSwinesync             lstrcpyW( sid, user );
1257c2c66affSColin Finck         }
1258c2c66affSColin Finck     }
1259c2c66affSColin Finck     if (guid) unsquash_guid( component, guid );
1260c2c66affSColin Finck     if (installed_ctx) *installed_ctx = ctx;
1261c2c66affSColin Finck     RegCloseKey( key_components );
1262c2c66affSColin Finck     RegCloseKey( key_users );
1263c2c66affSColin Finck     return r;
1264c2c66affSColin Finck }
1265c2c66affSColin Finck 
enum_components(const WCHAR * usersid,DWORD ctx,DWORD index,DWORD * idx,WCHAR guid[39],MSIINSTALLCONTEXT * installed_ctx,LPWSTR sid,LPDWORD sid_len)1266c2c66affSColin Finck static UINT enum_components( const WCHAR *usersid, DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
1267c2c66affSColin Finck                              MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1268c2c66affSColin Finck {
1269c2c66affSColin Finck     UINT r = ERROR_NO_MORE_ITEMS;
1270c2c66affSColin Finck     WCHAR *user = NULL;
1271c2c66affSColin Finck 
1272c2c66affSColin Finck     if (!usersid)
1273c2c66affSColin Finck     {
1274c2c66affSColin Finck         usersid = user = get_user_sid();
1275c2c66affSColin Finck         if (!user) return ERROR_FUNCTION_FAILED;
1276c2c66affSColin Finck     }
1277c2c66affSColin Finck     if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
1278c2c66affSColin Finck     {
1279c2c66affSColin Finck         r = fetch_user_component( usersid, MSIINSTALLCONTEXT_USERMANAGED, index, idx, guid,
1280c2c66affSColin Finck                                   installed_ctx, sid, sid_len );
1281c2c66affSColin Finck         if (r != ERROR_NO_MORE_ITEMS) goto done;
1282c2c66affSColin Finck     }
1283c2c66affSColin Finck     if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
1284c2c66affSColin Finck     {
1285c2c66affSColin Finck         r = fetch_user_component( usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index, idx, guid,
1286c2c66affSColin Finck                                   installed_ctx, sid, sid_len );
1287c2c66affSColin Finck         if (r != ERROR_NO_MORE_ITEMS) goto done;
1288c2c66affSColin Finck     }
1289c2c66affSColin Finck     if (ctx & MSIINSTALLCONTEXT_MACHINE)
1290c2c66affSColin Finck     {
1291c2c66affSColin Finck         r = fetch_machine_component( MSIINSTALLCONTEXT_MACHINE, index, idx, guid, installed_ctx,
1292c2c66affSColin Finck                                      sid, sid_len );
1293c2c66affSColin Finck         if (r != ERROR_NO_MORE_ITEMS) goto done;
1294c2c66affSColin Finck     }
1295c2c66affSColin Finck 
1296c2c66affSColin Finck done:
1297c2c66affSColin Finck     LocalFree( user );
1298c2c66affSColin Finck     return r;
1299c2c66affSColin Finck }
1300c2c66affSColin Finck 
MsiEnumComponentsExW(const WCHAR * user_sid,DWORD ctx,DWORD index,WCHAR guid[39],MSIINSTALLCONTEXT * installed_ctx,WCHAR * sid,DWORD * sid_len)130102f995b2Swinesync UINT WINAPI MsiEnumComponentsExW( const WCHAR *user_sid, DWORD ctx, DWORD index, WCHAR guid[39],
130202f995b2Swinesync                                   MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
1303c2c66affSColin Finck {
1304c2c66affSColin Finck     UINT r;
1305c2c66affSColin Finck     DWORD idx = 0;
1306c2c66affSColin Finck     static DWORD last_index;
1307c2c66affSColin Finck 
130802f995b2Swinesync     TRACE( "%s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(user_sid), ctx, index, guid, installed_ctx,
1309c2c66affSColin Finck           sid, sid_len );
1310c2c66affSColin Finck 
1311c2c66affSColin Finck     if ((sid && !sid_len) || !ctx || (user_sid && ctx == MSIINSTALLCONTEXT_MACHINE))
1312c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1313c2c66affSColin Finck 
1314c2c66affSColin Finck     if (index && index - last_index != 1)
1315c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1316c2c66affSColin Finck 
1317c2c66affSColin Finck     if (!index) last_index = 0;
1318c2c66affSColin Finck 
1319c2c66affSColin Finck     r = enum_components( user_sid, ctx, index, &idx, guid, installed_ctx, sid, sid_len );
1320c2c66affSColin Finck     if (r == ERROR_SUCCESS)
1321c2c66affSColin Finck         last_index = index;
1322c2c66affSColin Finck     else
1323c2c66affSColin Finck         last_index = 0;
1324c2c66affSColin Finck 
1325c2c66affSColin Finck     return r;
1326c2c66affSColin Finck }
1327c2c66affSColin Finck 
MsiEnumClientsA(const char * szComponent,DWORD index,char * szProduct)132802f995b2Swinesync UINT WINAPI MsiEnumClientsA( const char *szComponent, DWORD index, char *szProduct )
1329c2c66affSColin Finck {
1330c2c66affSColin Finck     DWORD r;
1331c2c66affSColin Finck     WCHAR szwProduct[GUID_SIZE];
133202f995b2Swinesync     WCHAR *szwComponent = NULL;
1333c2c66affSColin Finck 
133402f995b2Swinesync     TRACE( "%s, %lu, %p\n", debugstr_a(szComponent), index, szProduct );
1335c2c66affSColin Finck 
1336c2c66affSColin Finck     if ( !szProduct )
1337c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1338c2c66affSColin Finck 
1339c2c66affSColin Finck     if( szComponent )
1340c2c66affSColin Finck     {
1341c2c66affSColin Finck         szwComponent = strdupAtoW( szComponent );
1342c2c66affSColin Finck         if( !szwComponent )
1343c2c66affSColin Finck             return ERROR_OUTOFMEMORY;
1344c2c66affSColin Finck     }
1345c2c66affSColin Finck 
1346c2c66affSColin Finck     r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
1347c2c66affSColin Finck     if( r == ERROR_SUCCESS )
134802f995b2Swinesync         WideCharToMultiByte(CP_ACP, 0, szwProduct, -1, szProduct, GUID_SIZE, NULL, NULL);
1349c2c66affSColin Finck 
1350*f4be6dc3SMikhail     free(szwComponent);
1351c2c66affSColin Finck 
1352c2c66affSColin Finck     return r;
1353c2c66affSColin Finck }
1354c2c66affSColin Finck 
MsiEnumClientsW(const WCHAR * szComponent,DWORD index,WCHAR * szProduct)135502f995b2Swinesync UINT WINAPI MsiEnumClientsW( const WCHAR *szComponent, DWORD index, WCHAR *szProduct )
1356c2c66affSColin Finck {
1357c2c66affSColin Finck     HKEY hkeyComp = 0;
1358c2c66affSColin Finck     DWORD r, sz;
1359c2c66affSColin Finck     WCHAR szValName[SQUASHED_GUID_SIZE];
1360c2c66affSColin Finck 
136102f995b2Swinesync     TRACE( "%s, %lu, %p\n", debugstr_w(szComponent), index, szProduct );
1362c2c66affSColin Finck 
1363c2c66affSColin Finck     if (!szComponent || !*szComponent || !szProduct)
1364c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1365c2c66affSColin Finck 
1366c2c66affSColin Finck     if (MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkeyComp, FALSE) != ERROR_SUCCESS &&
13670f67ae4bSwinesync         MSIREG_OpenUserDataComponentKey(szComponent, L"S-1-5-18", &hkeyComp, FALSE) != ERROR_SUCCESS)
1368c2c66affSColin Finck         return ERROR_UNKNOWN_COMPONENT;
1369c2c66affSColin Finck 
1370c2c66affSColin Finck     /* see if there are any products at all */
1371c2c66affSColin Finck     sz = SQUASHED_GUID_SIZE;
1372c2c66affSColin Finck     r = RegEnumValueW(hkeyComp, 0, szValName, &sz, NULL, NULL, NULL, NULL);
1373c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1374c2c66affSColin Finck     {
1375c2c66affSColin Finck         RegCloseKey(hkeyComp);
1376c2c66affSColin Finck 
1377c2c66affSColin Finck         if (index != 0)
1378c2c66affSColin Finck             return ERROR_INVALID_PARAMETER;
1379c2c66affSColin Finck 
1380c2c66affSColin Finck         return ERROR_UNKNOWN_COMPONENT;
1381c2c66affSColin Finck     }
1382c2c66affSColin Finck 
1383c2c66affSColin Finck     sz = SQUASHED_GUID_SIZE;
1384c2c66affSColin Finck     r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
1385c2c66affSColin Finck     if( r == ERROR_SUCCESS )
1386c2c66affSColin Finck     {
1387c2c66affSColin Finck         unsquash_guid(szValName, szProduct);
1388c2c66affSColin Finck         TRACE("-> %s\n", debugstr_w(szProduct));
1389c2c66affSColin Finck     }
1390c2c66affSColin Finck     RegCloseKey(hkeyComp);
1391c2c66affSColin Finck     return r;
1392c2c66affSColin Finck }
1393c2c66affSColin Finck 
MsiEnumClientsExA(const char * component,const char * usersid,DWORD ctx,DWORD index,char installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,char * sid,DWORD * sid_len)139402f995b2Swinesync UINT WINAPI MsiEnumClientsExA( const char *component, const char *usersid, DWORD ctx, DWORD index,
139502f995b2Swinesync                                char installed_product[GUID_SIZE], MSIINSTALLCONTEXT *installed_ctx, char *sid,
139602f995b2Swinesync                                DWORD *sid_len )
1397c2c66affSColin Finck {
139802f995b2Swinesync     FIXME( "%s, %s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_a(component), debugstr_a(usersid), ctx, index,
139902f995b2Swinesync            installed_product, installed_ctx, sid, sid_len );
1400c2c66affSColin Finck     return ERROR_ACCESS_DENIED;
1401c2c66affSColin Finck }
1402c2c66affSColin Finck 
MsiEnumClientsExW(const WCHAR * component,const WCHAR * usersid,DWORD ctx,DWORD index,WCHAR installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,WCHAR * sid,DWORD * sid_len)140302f995b2Swinesync UINT WINAPI MsiEnumClientsExW( const WCHAR *component, const WCHAR *usersid, DWORD ctx, DWORD index,
140402f995b2Swinesync                                WCHAR installed_product[GUID_SIZE], MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid,
140502f995b2Swinesync                                DWORD *sid_len )
1406c2c66affSColin Finck {
140702f995b2Swinesync     FIXME( "%s, %s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(component), debugstr_w(usersid), ctx, index,
140802f995b2Swinesync            installed_product, installed_ctx, sid, sid_len );
1409c2c66affSColin Finck     return ERROR_ACCESS_DENIED;
1410c2c66affSColin Finck }
1411c2c66affSColin Finck 
MSI_EnumComponentQualifiers(const WCHAR * szComponent,DWORD iIndex,awstring * lpQualBuf,DWORD * pcchQual,awstring * lpAppBuf,DWORD * pcchAppBuf)141202f995b2Swinesync static UINT MSI_EnumComponentQualifiers( const WCHAR *szComponent, DWORD iIndex, awstring *lpQualBuf,
141302f995b2Swinesync                                          DWORD *pcchQual, awstring *lpAppBuf, DWORD *pcchAppBuf )
1414c2c66affSColin Finck {
1415c2c66affSColin Finck     DWORD name_sz, val_sz, name_max, val_max, type, ofs;
141602f995b2Swinesync     WCHAR *name = NULL, *val = NULL;
1417c2c66affSColin Finck     UINT r, r2;
1418c2c66affSColin Finck     HKEY key;
1419c2c66affSColin Finck 
142002f995b2Swinesync     TRACE( "%s, %lu, %p, %p, %p, %p\n", debugstr_w(szComponent), iIndex, lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf );
1421c2c66affSColin Finck 
1422c2c66affSColin Finck     if (!szComponent)
1423c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1424c2c66affSColin Finck 
1425c2c66affSColin Finck     r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1426c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1427c2c66affSColin Finck         return ERROR_UNKNOWN_COMPONENT;
1428c2c66affSColin Finck 
1429c2c66affSColin Finck     /* figure out how big the name is we want to return */
1430c2c66affSColin Finck     name_max = 0x10;
1431c2c66affSColin Finck     r = ERROR_OUTOFMEMORY;
1432*f4be6dc3SMikhail     name = malloc( name_max * sizeof(WCHAR) );
1433c2c66affSColin Finck     if (!name)
1434c2c66affSColin Finck         goto end;
1435c2c66affSColin Finck 
1436c2c66affSColin Finck     val_max = 0x10;
1437c2c66affSColin Finck     r = ERROR_OUTOFMEMORY;
1438*f4be6dc3SMikhail     val = malloc( val_max );
1439c2c66affSColin Finck     if (!val)
1440c2c66affSColin Finck         goto end;
1441c2c66affSColin Finck 
1442c2c66affSColin Finck     /* loop until we allocate enough memory */
1443c2c66affSColin Finck     while (1)
1444c2c66affSColin Finck     {
1445c2c66affSColin Finck         name_sz = name_max;
1446c2c66affSColin Finck         val_sz = val_max;
144702f995b2Swinesync         r = RegEnumValueW( key, iIndex, name, &name_sz, NULL, &type, (BYTE *)val, &val_sz );
1448c2c66affSColin Finck         if (r == ERROR_SUCCESS)
1449c2c66affSColin Finck             break;
1450c2c66affSColin Finck         if (r != ERROR_MORE_DATA)
1451c2c66affSColin Finck             goto end;
1452c2c66affSColin Finck 
1453c2c66affSColin Finck         if (type != REG_MULTI_SZ)
1454c2c66affSColin Finck         {
145502f995b2Swinesync             ERR( "component data has wrong type (%lu)\n", type );
1456c2c66affSColin Finck             goto end;
1457c2c66affSColin Finck         }
1458c2c66affSColin Finck 
1459c2c66affSColin Finck         r = ERROR_OUTOFMEMORY;
1460c2c66affSColin Finck         if (name_sz + 1 >= name_max)
1461c2c66affSColin Finck         {
1462c2c66affSColin Finck             name_max *= 2;
1463*f4be6dc3SMikhail             free( name );
1464*f4be6dc3SMikhail             name = malloc( name_max * sizeof (WCHAR) );
1465c2c66affSColin Finck             if (!name)
1466c2c66affSColin Finck                 goto end;
1467c2c66affSColin Finck             continue;
1468c2c66affSColin Finck         }
1469c2c66affSColin Finck         if (val_sz > val_max)
1470c2c66affSColin Finck         {
1471c2c66affSColin Finck             val_max = val_sz + sizeof (WCHAR);
1472*f4be6dc3SMikhail             free( val );
1473*f4be6dc3SMikhail             val = malloc( val_max * sizeof (WCHAR) );
1474c2c66affSColin Finck             if (!val)
1475c2c66affSColin Finck                 goto end;
1476c2c66affSColin Finck             continue;
1477c2c66affSColin Finck         }
147802f995b2Swinesync         ERR( "should be enough data, but isn't %lu %lu\n", name_sz, val_sz );
1479c2c66affSColin Finck         goto end;
1480c2c66affSColin Finck     }
1481c2c66affSColin Finck 
1482c2c66affSColin Finck     ofs = 0;
1483c2c66affSColin Finck     r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1484c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1485c2c66affSColin Finck         goto end;
1486c2c66affSColin Finck 
1487c2c66affSColin Finck     TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1488c2c66affSColin Finck 
1489c2c66affSColin Finck     r = msi_strcpy_to_awstring( name, -1, lpQualBuf, pcchQual );
1490c2c66affSColin Finck     r2 = msi_strcpy_to_awstring( val+ofs, -1, lpAppBuf, pcchAppBuf );
1491c2c66affSColin Finck 
1492c2c66affSColin Finck     if (r2 != ERROR_SUCCESS)
1493c2c66affSColin Finck         r = r2;
1494c2c66affSColin Finck 
1495c2c66affSColin Finck end:
1496*f4be6dc3SMikhail     free(val);
1497*f4be6dc3SMikhail     free(name);
1498c2c66affSColin Finck     RegCloseKey(key);
1499c2c66affSColin Finck     return r;
1500c2c66affSColin Finck }
1501c2c66affSColin Finck 
1502c2c66affSColin Finck /*************************************************************************
1503c2c66affSColin Finck  *  MsiEnumComponentQualifiersA [MSI.@]
1504c2c66affSColin Finck  */
MsiEnumComponentQualifiersA(const char * szComponent,DWORD iIndex,char * lpQualifierBuf,DWORD * pcchQualifierBuf,char * lpApplicationDataBuf,DWORD * pcchApplicationDataBuf)150502f995b2Swinesync UINT WINAPI MsiEnumComponentQualifiersA( const char *szComponent, DWORD iIndex, char *lpQualifierBuf,
150602f995b2Swinesync                                          DWORD *pcchQualifierBuf, char *lpApplicationDataBuf,
150702f995b2Swinesync                                          DWORD *pcchApplicationDataBuf )
1508c2c66affSColin Finck {
1509c2c66affSColin Finck     awstring qual, appdata;
151002f995b2Swinesync     WCHAR *comp;
1511c2c66affSColin Finck     UINT r;
1512c2c66affSColin Finck 
151302f995b2Swinesync     TRACE( "%s, %lu, %p, %p, %p, %p\n", debugstr_a(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf,
151402f995b2Swinesync            lpApplicationDataBuf, pcchApplicationDataBuf );
1515c2c66affSColin Finck 
1516c2c66affSColin Finck     comp = strdupAtoW( szComponent );
1517c2c66affSColin Finck     if (szComponent && !comp)
1518c2c66affSColin Finck         return ERROR_OUTOFMEMORY;
1519c2c66affSColin Finck 
1520c2c66affSColin Finck     qual.unicode = FALSE;
1521c2c66affSColin Finck     qual.str.a = lpQualifierBuf;
1522c2c66affSColin Finck 
1523c2c66affSColin Finck     appdata.unicode = FALSE;
1524c2c66affSColin Finck     appdata.str.a = lpApplicationDataBuf;
1525c2c66affSColin Finck 
1526c2c66affSColin Finck     r = MSI_EnumComponentQualifiers( comp, iIndex,
1527c2c66affSColin Finck               &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1528*f4be6dc3SMikhail     free( comp );
1529c2c66affSColin Finck     return r;
1530c2c66affSColin Finck }
1531c2c66affSColin Finck 
1532c2c66affSColin Finck /*************************************************************************
1533c2c66affSColin Finck  *  MsiEnumComponentQualifiersW [MSI.@]
1534c2c66affSColin Finck  */
MsiEnumComponentQualifiersW(const WCHAR * szComponent,DWORD iIndex,WCHAR * lpQualifierBuf,DWORD * pcchQualifierBuf,WCHAR * lpApplicationDataBuf,DWORD * pcchApplicationDataBuf)153502f995b2Swinesync UINT WINAPI MsiEnumComponentQualifiersW( const WCHAR *szComponent, DWORD iIndex, WCHAR *lpQualifierBuf,
153602f995b2Swinesync                                          DWORD *pcchQualifierBuf, WCHAR *lpApplicationDataBuf,
153702f995b2Swinesync                                          DWORD *pcchApplicationDataBuf )
1538c2c66affSColin Finck {
1539c2c66affSColin Finck     awstring qual, appdata;
1540c2c66affSColin Finck 
154102f995b2Swinesync     TRACE( "%s, %lu, %p, %p, %p, %p\n", debugstr_w(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf,
154202f995b2Swinesync            lpApplicationDataBuf, pcchApplicationDataBuf );
1543c2c66affSColin Finck 
1544c2c66affSColin Finck     qual.unicode = TRUE;
1545c2c66affSColin Finck     qual.str.w = lpQualifierBuf;
1546c2c66affSColin Finck 
1547c2c66affSColin Finck     appdata.unicode = TRUE;
1548c2c66affSColin Finck     appdata.str.w = lpApplicationDataBuf;
1549c2c66affSColin Finck 
155002f995b2Swinesync     return MSI_EnumComponentQualifiers( szComponent, iIndex, &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1551c2c66affSColin Finck }
1552c2c66affSColin Finck 
1553c2c66affSColin Finck /*************************************************************************
1554c2c66affSColin Finck  *  MsiEnumRelatedProductsW   [MSI.@]
1555c2c66affSColin Finck  *
1556c2c66affSColin Finck  */
MsiEnumRelatedProductsW(const WCHAR * szUpgradeCode,DWORD dwReserved,DWORD iProductIndex,WCHAR * lpProductBuf)155702f995b2Swinesync UINT WINAPI MsiEnumRelatedProductsW( const WCHAR *szUpgradeCode, DWORD dwReserved, DWORD iProductIndex,
155802f995b2Swinesync                                      WCHAR *lpProductBuf )
1559c2c66affSColin Finck {
1560c2c66affSColin Finck     UINT r;
1561c2c66affSColin Finck     HKEY hkey;
1562c2c66affSColin Finck     WCHAR szKeyName[SQUASHED_GUID_SIZE];
15639792c08fSwinesync     DWORD dwSize = ARRAY_SIZE(szKeyName);
1564c2c66affSColin Finck 
156502f995b2Swinesync     TRACE( "%s, %#lx, %lu, %p\n", debugstr_w(szUpgradeCode), dwReserved, iProductIndex, lpProductBuf );
1566c2c66affSColin Finck 
1567c2c66affSColin Finck     if (NULL == szUpgradeCode)
1568c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1569c2c66affSColin Finck     if (NULL == lpProductBuf)
1570c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1571c2c66affSColin Finck 
1572c2c66affSColin Finck     r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1573c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1574c2c66affSColin Finck         return ERROR_NO_MORE_ITEMS;
1575c2c66affSColin Finck 
1576c2c66affSColin Finck     r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1577c2c66affSColin Finck     if( r == ERROR_SUCCESS )
1578c2c66affSColin Finck         unsquash_guid(szKeyName, lpProductBuf);
1579c2c66affSColin Finck     RegCloseKey(hkey);
1580c2c66affSColin Finck 
1581c2c66affSColin Finck     return r;
1582c2c66affSColin Finck }
1583c2c66affSColin Finck 
1584c2c66affSColin Finck /*************************************************************************
1585c2c66affSColin Finck  *  MsiEnumRelatedProductsA   [MSI.@]
1586c2c66affSColin Finck  *
1587c2c66affSColin Finck  */
MsiEnumRelatedProductsA(const char * szUpgradeCode,DWORD dwReserved,DWORD iProductIndex,char * lpProductBuf)158802f995b2Swinesync UINT WINAPI MsiEnumRelatedProductsA( const char *szUpgradeCode, DWORD dwReserved, DWORD iProductIndex,
158902f995b2Swinesync                                      char *lpProductBuf )
1590c2c66affSColin Finck {
159102f995b2Swinesync     WCHAR *szwUpgradeCode = NULL;
1592c2c66affSColin Finck     WCHAR productW[GUID_SIZE];
1593c2c66affSColin Finck     UINT r;
1594c2c66affSColin Finck 
159502f995b2Swinesync     TRACE( "%s, %#lx, %lu, %p\n", debugstr_a(szUpgradeCode), dwReserved, iProductIndex, lpProductBuf );
1596c2c66affSColin Finck 
1597c2c66affSColin Finck     if (szUpgradeCode)
1598c2c66affSColin Finck     {
1599c2c66affSColin Finck         szwUpgradeCode = strdupAtoW( szUpgradeCode );
1600c2c66affSColin Finck         if( !szwUpgradeCode )
1601c2c66affSColin Finck             return ERROR_OUTOFMEMORY;
1602c2c66affSColin Finck     }
1603c2c66affSColin Finck 
1604c2c66affSColin Finck     r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1605c2c66affSColin Finck                                  iProductIndex, productW );
1606c2c66affSColin Finck     if (r == ERROR_SUCCESS)
1607c2c66affSColin Finck     {
1608c2c66affSColin Finck         WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1609c2c66affSColin Finck                              lpProductBuf, GUID_SIZE, NULL, NULL );
1610c2c66affSColin Finck     }
1611*f4be6dc3SMikhail     free( szwUpgradeCode );
1612c2c66affSColin Finck     return r;
1613c2c66affSColin Finck }
1614c2c66affSColin Finck 
1615c2c66affSColin Finck /***********************************************************************
1616c2c66affSColin Finck  * MsiEnumPatchesExA            [MSI.@]
1617c2c66affSColin Finck  */
MsiEnumPatchesExA(const char * szProductCode,const char * szUserSid,DWORD dwContext,DWORD dwFilter,DWORD dwIndex,char * szPatchCode,char * szTargetProductCode,MSIINSTALLCONTEXT * pdwTargetProductContext,char * szTargetUserSid,DWORD * pcchTargetUserSid)161802f995b2Swinesync UINT WINAPI MsiEnumPatchesExA( const char *szProductCode, const char *szUserSid, DWORD dwContext, DWORD dwFilter,
161902f995b2Swinesync                                DWORD dwIndex, char *szPatchCode, char *szTargetProductCode,
162002f995b2Swinesync                                MSIINSTALLCONTEXT *pdwTargetProductContext, char *szTargetUserSid,
162102f995b2Swinesync                                DWORD *pcchTargetUserSid )
1622c2c66affSColin Finck {
162302f995b2Swinesync     WCHAR *prodcode = NULL, *usersid = NULL, *targsid = NULL;
162402f995b2Swinesync     WCHAR patch[GUID_SIZE], targprod[GUID_SIZE];
1625c2c66affSColin Finck     DWORD len;
1626c2c66affSColin Finck     UINT r;
1627c2c66affSColin Finck 
162802f995b2Swinesync     TRACE( "%s, %s, %#lx, %lu, %lu, %p, %p, %p, %p, %p\n", debugstr_a(szProductCode), debugstr_a(szUserSid),
162902f995b2Swinesync            dwContext, dwFilter, dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
163002f995b2Swinesync            pcchTargetUserSid );
1631c2c66affSColin Finck 
1632c2c66affSColin Finck     if (szTargetUserSid && !pcchTargetUserSid)
1633c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1634c2c66affSColin Finck 
1635c2c66affSColin Finck     if (szProductCode) prodcode = strdupAtoW(szProductCode);
1636c2c66affSColin Finck     if (szUserSid) usersid = strdupAtoW(szUserSid);
1637c2c66affSColin Finck 
1638c2c66affSColin Finck     r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1639c2c66affSColin Finck                           patch, targprod, pdwTargetProductContext,
1640c2c66affSColin Finck                           NULL, &len);
1641c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1642c2c66affSColin Finck         goto done;
1643c2c66affSColin Finck 
1644c2c66affSColin Finck     WideCharToMultiByte(CP_ACP, 0, patch, -1, szPatchCode,
1645c2c66affSColin Finck                         GUID_SIZE, NULL, NULL);
1646c2c66affSColin Finck     WideCharToMultiByte(CP_ACP, 0, targprod, -1, szTargetProductCode,
1647c2c66affSColin Finck                         GUID_SIZE, NULL, NULL);
1648c2c66affSColin Finck 
1649c2c66affSColin Finck     if (!szTargetUserSid)
1650c2c66affSColin Finck     {
1651c2c66affSColin Finck         if (pcchTargetUserSid)
1652c2c66affSColin Finck             *pcchTargetUserSid = len;
1653c2c66affSColin Finck 
1654c2c66affSColin Finck         goto done;
1655c2c66affSColin Finck     }
1656c2c66affSColin Finck 
1657*f4be6dc3SMikhail     targsid = malloc(++len * sizeof(WCHAR));
1658c2c66affSColin Finck     if (!targsid)
1659c2c66affSColin Finck     {
1660c2c66affSColin Finck         r = ERROR_OUTOFMEMORY;
1661c2c66affSColin Finck         goto done;
1662c2c66affSColin Finck     }
1663c2c66affSColin Finck 
1664c2c66affSColin Finck     r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1665c2c66affSColin Finck                           patch, targprod, pdwTargetProductContext,
1666c2c66affSColin Finck                           targsid, &len);
1667c2c66affSColin Finck     if (r != ERROR_SUCCESS || !szTargetUserSid)
1668c2c66affSColin Finck         goto done;
1669c2c66affSColin Finck 
1670c2c66affSColin Finck     WideCharToMultiByte(CP_ACP, 0, targsid, -1, szTargetUserSid,
1671c2c66affSColin Finck                         *pcchTargetUserSid, NULL, NULL);
1672c2c66affSColin Finck 
1673c2c66affSColin Finck     len = lstrlenW(targsid);
1674c2c66affSColin Finck     if (*pcchTargetUserSid < len + 1)
1675c2c66affSColin Finck     {
1676c2c66affSColin Finck         r = ERROR_MORE_DATA;
1677c2c66affSColin Finck         *pcchTargetUserSid = len * sizeof(WCHAR);
1678c2c66affSColin Finck     }
1679c2c66affSColin Finck     else
1680c2c66affSColin Finck         *pcchTargetUserSid = len;
1681c2c66affSColin Finck 
1682c2c66affSColin Finck done:
1683*f4be6dc3SMikhail     free(prodcode);
1684*f4be6dc3SMikhail     free(usersid);
1685*f4be6dc3SMikhail     free(targsid);
1686c2c66affSColin Finck 
1687c2c66affSColin Finck     return r;
1688c2c66affSColin Finck }
1689c2c66affSColin Finck 
get_patch_state(const WCHAR * prodcode,const WCHAR * usersid,MSIINSTALLCONTEXT context,WCHAR * patch,MSIPATCHSTATE * state)1690*f4be6dc3SMikhail static UINT get_patch_state(const WCHAR *prodcode, const WCHAR *usersid, MSIINSTALLCONTEXT context,
1691*f4be6dc3SMikhail                             WCHAR *patch, MSIPATCHSTATE *state)
1692c2c66affSColin Finck {
1693c2c66affSColin Finck     DWORD type, val, size;
1694c2c66affSColin Finck     HKEY prod, hkey = 0;
1695c2c66affSColin Finck     HKEY udpatch = 0;
1696c2c66affSColin Finck     LONG res;
1697c2c66affSColin Finck     UINT r = ERROR_NO_MORE_ITEMS;
1698c2c66affSColin Finck 
1699c2c66affSColin Finck     *state = MSIPATCHSTATE_INVALID;
1700c2c66affSColin Finck 
1701c2c66affSColin Finck     r = MSIREG_OpenUserDataProductKey(prodcode, context,
1702c2c66affSColin Finck                                       usersid, &prod, FALSE);
1703c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1704c2c66affSColin Finck         return ERROR_NO_MORE_ITEMS;
1705c2c66affSColin Finck 
17060f67ae4bSwinesync     res = RegOpenKeyExW(prod, L"Patches", 0, KEY_READ, &hkey);
1707c2c66affSColin Finck     if (res != ERROR_SUCCESS)
1708c2c66affSColin Finck         goto done;
1709c2c66affSColin Finck 
1710c2c66affSColin Finck     res = RegOpenKeyExW(hkey, patch, 0, KEY_READ, &udpatch);
1711c2c66affSColin Finck     if (res != ERROR_SUCCESS)
1712c2c66affSColin Finck         goto done;
1713c2c66affSColin Finck 
1714c2c66affSColin Finck     size = sizeof(DWORD);
17150f67ae4bSwinesync     res = RegGetValueW(udpatch, NULL, L"State", RRF_RT_DWORD, &type, &val, &size);
1716c2c66affSColin Finck     if (res != ERROR_SUCCESS ||
1717c2c66affSColin Finck         val < MSIPATCHSTATE_APPLIED || val > MSIPATCHSTATE_REGISTERED)
1718c2c66affSColin Finck     {
1719c2c66affSColin Finck         r = ERROR_BAD_CONFIGURATION;
1720c2c66affSColin Finck         goto done;
1721c2c66affSColin Finck     }
1722c2c66affSColin Finck 
1723c2c66affSColin Finck     *state = val;
1724c2c66affSColin Finck     r = ERROR_SUCCESS;
1725c2c66affSColin Finck 
1726c2c66affSColin Finck done:
1727c2c66affSColin Finck     RegCloseKey(udpatch);
1728c2c66affSColin Finck     RegCloseKey(hkey);
1729c2c66affSColin Finck     RegCloseKey(prod);
1730c2c66affSColin Finck 
1731c2c66affSColin Finck     return r;
1732c2c66affSColin Finck }
1733c2c66affSColin Finck 
check_product_patches(const WCHAR * prodcode,const WCHAR * usersid,MSIINSTALLCONTEXT context,DWORD filter,DWORD index,DWORD * idx,WCHAR * patch,WCHAR * targetprod,MSIINSTALLCONTEXT * targetctx,WCHAR * targetsid,DWORD * sidsize,WCHAR ** transforms)1734*f4be6dc3SMikhail static UINT check_product_patches(const WCHAR *prodcode, const WCHAR *usersid, MSIINSTALLCONTEXT context,
1735*f4be6dc3SMikhail                                   DWORD filter, DWORD index, DWORD *idx, WCHAR *patch, WCHAR *targetprod,
1736*f4be6dc3SMikhail                                   MSIINSTALLCONTEXT *targetctx, WCHAR *targetsid, DWORD *sidsize, WCHAR **transforms)
1737c2c66affSColin Finck {
1738c2c66affSColin Finck     MSIPATCHSTATE state = MSIPATCHSTATE_INVALID;
1739c2c66affSColin Finck     LPWSTR ptr, patches = NULL;
1740c2c66affSColin Finck     HKEY prod, patchkey = 0;
1741c2c66affSColin Finck     HKEY localprod = 0, localpatch = 0;
1742c2c66affSColin Finck     DWORD type, size;
1743c2c66affSColin Finck     LONG res;
1744c2c66affSColin Finck     UINT temp, r = ERROR_NO_MORE_ITEMS;
1745c2c66affSColin Finck 
1746c2c66affSColin Finck     if (MSIREG_OpenProductKey(prodcode, usersid, context,
1747c2c66affSColin Finck                               &prod, FALSE) != ERROR_SUCCESS)
1748c2c66affSColin Finck         return ERROR_NO_MORE_ITEMS;
1749c2c66affSColin Finck 
1750c2c66affSColin Finck     size = 0;
17510f67ae4bSwinesync     res = RegGetValueW(prod, L"Patches", L"Patches", RRF_RT_ANY, &type, NULL,
1752c2c66affSColin Finck                        &size);
1753c2c66affSColin Finck     if (res != ERROR_SUCCESS)
1754c2c66affSColin Finck         goto done;
1755c2c66affSColin Finck 
1756c2c66affSColin Finck     if (type != REG_MULTI_SZ)
1757c2c66affSColin Finck     {
1758c2c66affSColin Finck         r = ERROR_BAD_CONFIGURATION;
1759c2c66affSColin Finck         goto done;
1760c2c66affSColin Finck     }
1761c2c66affSColin Finck 
1762*f4be6dc3SMikhail     patches = malloc(size);
1763c2c66affSColin Finck     if (!patches)
1764c2c66affSColin Finck     {
1765c2c66affSColin Finck         r = ERROR_OUTOFMEMORY;
1766c2c66affSColin Finck         goto done;
1767c2c66affSColin Finck     }
1768c2c66affSColin Finck 
17690f67ae4bSwinesync     res = RegGetValueW(prod, L"Patches", L"Patches", RRF_RT_ANY, &type,
1770c2c66affSColin Finck                        patches, &size);
1771c2c66affSColin Finck     if (res != ERROR_SUCCESS)
1772c2c66affSColin Finck         goto done;
1773c2c66affSColin Finck 
1774c2c66affSColin Finck     for (ptr = patches; *ptr && r == ERROR_NO_MORE_ITEMS; ptr += lstrlenW(ptr) + 1)
1775c2c66affSColin Finck     {
1776c2c66affSColin Finck         if (!unsquash_guid(ptr, patch))
1777c2c66affSColin Finck         {
1778c2c66affSColin Finck             r = ERROR_BAD_CONFIGURATION;
1779c2c66affSColin Finck             goto done;
1780c2c66affSColin Finck         }
1781c2c66affSColin Finck 
1782c2c66affSColin Finck         size = 0;
17830f67ae4bSwinesync         res = RegGetValueW(prod, L"Patches", ptr, RRF_RT_REG_SZ,
1784c2c66affSColin Finck                            &type, NULL, &size);
1785c2c66affSColin Finck         if (res != ERROR_SUCCESS)
1786c2c66affSColin Finck             continue;
1787c2c66affSColin Finck 
1788c2c66affSColin Finck         if (transforms)
1789c2c66affSColin Finck         {
1790*f4be6dc3SMikhail             *transforms = malloc(size);
1791c2c66affSColin Finck             if (!*transforms)
1792c2c66affSColin Finck             {
1793c2c66affSColin Finck                 r = ERROR_OUTOFMEMORY;
1794c2c66affSColin Finck                 goto done;
1795c2c66affSColin Finck             }
1796c2c66affSColin Finck 
17970f67ae4bSwinesync             res = RegGetValueW(prod, L"Patches", ptr, RRF_RT_REG_SZ,
1798c2c66affSColin Finck                                &type, *transforms, &size);
1799c2c66affSColin Finck             if (res != ERROR_SUCCESS)
1800c2c66affSColin Finck                 continue;
1801c2c66affSColin Finck         }
1802c2c66affSColin Finck 
1803c2c66affSColin Finck         if (context == MSIINSTALLCONTEXT_USERMANAGED)
1804c2c66affSColin Finck         {
1805c2c66affSColin Finck             if (!(filter & MSIPATCHSTATE_APPLIED))
1806c2c66affSColin Finck             {
1807*f4be6dc3SMikhail                 temp = get_patch_state(prodcode, usersid, context, ptr, &state);
1808c2c66affSColin Finck                 if (temp == ERROR_BAD_CONFIGURATION)
1809c2c66affSColin Finck                 {
1810c2c66affSColin Finck                     r = ERROR_BAD_CONFIGURATION;
1811c2c66affSColin Finck                     goto done;
1812c2c66affSColin Finck                 }
1813c2c66affSColin Finck 
1814c2c66affSColin Finck                 if (temp != ERROR_SUCCESS || !(filter & state))
1815c2c66affSColin Finck                     continue;
1816c2c66affSColin Finck             }
1817c2c66affSColin Finck         }
1818c2c66affSColin Finck         else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
1819c2c66affSColin Finck         {
1820c2c66affSColin Finck             if (!(filter & MSIPATCHSTATE_APPLIED))
1821c2c66affSColin Finck             {
1822*f4be6dc3SMikhail                 temp = get_patch_state(prodcode, usersid, context, ptr, &state);
1823c2c66affSColin Finck                 if (temp == ERROR_BAD_CONFIGURATION)
1824c2c66affSColin Finck                 {
1825c2c66affSColin Finck                     r = ERROR_BAD_CONFIGURATION;
1826c2c66affSColin Finck                     goto done;
1827c2c66affSColin Finck                 }
1828c2c66affSColin Finck 
1829c2c66affSColin Finck                 if (temp != ERROR_SUCCESS || !(filter & state))
1830c2c66affSColin Finck                     continue;
1831c2c66affSColin Finck             }
1832c2c66affSColin Finck             else
1833c2c66affSColin Finck             {
1834c2c66affSColin Finck                 temp = MSIREG_OpenUserDataPatchKey(patch, context,
1835c2c66affSColin Finck                                                    &patchkey, FALSE);
1836c2c66affSColin Finck                 RegCloseKey(patchkey);
1837c2c66affSColin Finck                 if (temp != ERROR_SUCCESS)
1838c2c66affSColin Finck                     continue;
1839c2c66affSColin Finck             }
1840c2c66affSColin Finck         }
1841c2c66affSColin Finck         else if (context == MSIINSTALLCONTEXT_MACHINE)
1842c2c66affSColin Finck         {
18430f67ae4bSwinesync             usersid = L"";
1844c2c66affSColin Finck 
1845c2c66affSColin Finck             if (MSIREG_OpenUserDataProductKey(prodcode, context, NULL, &localprod, FALSE) == ERROR_SUCCESS &&
18460f67ae4bSwinesync                 RegOpenKeyExW(localprod, L"Patches", 0, KEY_READ, &localpatch) == ERROR_SUCCESS &&
1847c2c66affSColin Finck                 RegOpenKeyExW(localpatch, ptr, 0, KEY_READ, &patchkey) == ERROR_SUCCESS)
1848c2c66affSColin Finck             {
18490f67ae4bSwinesync                 res = RegGetValueW(patchkey, NULL, L"State", RRF_RT_REG_DWORD,
1850c2c66affSColin Finck                                    &type, &state, &size);
1851c2c66affSColin Finck 
1852c2c66affSColin Finck                 if (!(filter & state))
1853c2c66affSColin Finck                     res = ERROR_NO_MORE_ITEMS;
1854c2c66affSColin Finck 
1855c2c66affSColin Finck                 RegCloseKey(patchkey);
1856c2c66affSColin Finck             }
1857c2c66affSColin Finck 
1858c2c66affSColin Finck             RegCloseKey(localpatch);
1859c2c66affSColin Finck             RegCloseKey(localprod);
1860c2c66affSColin Finck 
1861c2c66affSColin Finck             if (res != ERROR_SUCCESS)
1862c2c66affSColin Finck                 continue;
1863c2c66affSColin Finck         }
1864c2c66affSColin Finck 
1865c2c66affSColin Finck         if (*idx < index)
1866c2c66affSColin Finck         {
1867c2c66affSColin Finck             (*idx)++;
1868c2c66affSColin Finck             continue;
1869c2c66affSColin Finck         }
1870c2c66affSColin Finck 
1871c2c66affSColin Finck         r = ERROR_SUCCESS;
1872c2c66affSColin Finck         if (targetprod)
1873c2c66affSColin Finck             lstrcpyW(targetprod, prodcode);
1874c2c66affSColin Finck 
1875c2c66affSColin Finck         if (targetctx)
1876c2c66affSColin Finck             *targetctx = context;
1877c2c66affSColin Finck 
1878c2c66affSColin Finck         if (targetsid)
1879c2c66affSColin Finck         {
1880c2c66affSColin Finck             lstrcpynW(targetsid, usersid, *sidsize);
1881c2c66affSColin Finck             if (lstrlenW(usersid) >= *sidsize)
1882c2c66affSColin Finck                 r = ERROR_MORE_DATA;
1883c2c66affSColin Finck         }
1884c2c66affSColin Finck 
1885c2c66affSColin Finck         if (sidsize)
1886c2c66affSColin Finck         {
1887c2c66affSColin Finck             *sidsize = lstrlenW(usersid);
1888c2c66affSColin Finck             if (!targetsid)
1889c2c66affSColin Finck                 *sidsize *= sizeof(WCHAR);
1890c2c66affSColin Finck         }
1891c2c66affSColin Finck     }
1892c2c66affSColin Finck 
1893c2c66affSColin Finck done:
1894c2c66affSColin Finck     RegCloseKey(prod);
1895*f4be6dc3SMikhail     free(patches);
1896c2c66affSColin Finck 
1897c2c66affSColin Finck     return r;
1898c2c66affSColin Finck }
1899c2c66affSColin Finck 
enum_patches(const WCHAR * szProductCode,const WCHAR * szUserSid,DWORD dwContext,DWORD dwFilter,DWORD dwIndex,DWORD * idx,WCHAR * szPatchCode,WCHAR * szTargetProductCode,MSIINSTALLCONTEXT * pdwTargetProductContext,WCHAR * szTargetUserSid,DWORD * pcchTargetUserSid,WCHAR ** szTransforms)1900*f4be6dc3SMikhail static UINT enum_patches(const WCHAR *szProductCode, const WCHAR *szUserSid, DWORD dwContext, DWORD dwFilter,
1901*f4be6dc3SMikhail                          DWORD dwIndex, DWORD *idx, WCHAR *szPatchCode, WCHAR *szTargetProductCode,
1902*f4be6dc3SMikhail                          MSIINSTALLCONTEXT *pdwTargetProductContext, WCHAR *szTargetUserSid, DWORD *pcchTargetUserSid,
1903*f4be6dc3SMikhail                          WCHAR **szTransforms)
1904c2c66affSColin Finck {
1905c2c66affSColin Finck     LPWSTR usersid = NULL;
1906c2c66affSColin Finck     UINT r = ERROR_INVALID_PARAMETER;
1907c2c66affSColin Finck 
1908c2c66affSColin Finck     if (!szUserSid)
1909c2c66affSColin Finck     {
1910c2c66affSColin Finck         szUserSid = usersid = get_user_sid();
1911c2c66affSColin Finck         if (!usersid) return ERROR_FUNCTION_FAILED;
1912c2c66affSColin Finck     }
1913c2c66affSColin Finck 
1914c2c66affSColin Finck     if (dwContext & MSIINSTALLCONTEXT_USERMANAGED)
1915c2c66affSColin Finck     {
1916*f4be6dc3SMikhail         r = check_product_patches(szProductCode, szUserSid, MSIINSTALLCONTEXT_USERMANAGED, dwFilter, dwIndex, idx,
1917*f4be6dc3SMikhail                                   szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
1918c2c66affSColin Finck                                   pcchTargetUserSid, szTransforms);
1919c2c66affSColin Finck         if (r != ERROR_NO_MORE_ITEMS)
1920c2c66affSColin Finck             goto done;
1921c2c66affSColin Finck     }
1922c2c66affSColin Finck 
1923c2c66affSColin Finck     if (dwContext & MSIINSTALLCONTEXT_USERUNMANAGED)
1924c2c66affSColin Finck     {
1925*f4be6dc3SMikhail         r = check_product_patches(szProductCode, szUserSid, MSIINSTALLCONTEXT_USERUNMANAGED, dwFilter, dwIndex, idx,
1926*f4be6dc3SMikhail                                   szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
1927c2c66affSColin Finck                                   pcchTargetUserSid, szTransforms);
1928c2c66affSColin Finck         if (r != ERROR_NO_MORE_ITEMS)
1929c2c66affSColin Finck             goto done;
1930c2c66affSColin Finck     }
1931c2c66affSColin Finck 
1932c2c66affSColin Finck     if (dwContext & MSIINSTALLCONTEXT_MACHINE)
1933c2c66affSColin Finck     {
1934*f4be6dc3SMikhail         r = check_product_patches(szProductCode, szUserSid, MSIINSTALLCONTEXT_MACHINE, dwFilter, dwIndex, idx,
1935*f4be6dc3SMikhail                                   szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
1936c2c66affSColin Finck                                   pcchTargetUserSid, szTransforms);
1937c2c66affSColin Finck         if (r != ERROR_NO_MORE_ITEMS)
1938c2c66affSColin Finck             goto done;
1939c2c66affSColin Finck     }
1940c2c66affSColin Finck 
1941c2c66affSColin Finck done:
1942c2c66affSColin Finck     LocalFree(usersid);
1943c2c66affSColin Finck     return r;
1944c2c66affSColin Finck }
1945c2c66affSColin Finck 
1946c2c66affSColin Finck /***********************************************************************
1947c2c66affSColin Finck  * MsiEnumPatchesExW            [MSI.@]
1948c2c66affSColin Finck  */
MsiEnumPatchesExW(const WCHAR * szProductCode,const WCHAR * szUserSid,DWORD dwContext,DWORD dwFilter,DWORD dwIndex,WCHAR * szPatchCode,WCHAR * szTargetProductCode,MSIINSTALLCONTEXT * pdwTargetProductContext,WCHAR * szTargetUserSid,DWORD * pcchTargetUserSid)194902f995b2Swinesync UINT WINAPI MsiEnumPatchesExW( const WCHAR *szProductCode, const WCHAR *szUserSid, DWORD dwContext, DWORD dwFilter,
195002f995b2Swinesync                                DWORD dwIndex, WCHAR *szPatchCode, WCHAR *szTargetProductCode,
195102f995b2Swinesync                                MSIINSTALLCONTEXT *pdwTargetProductContext, WCHAR *szTargetUserSid,
195202f995b2Swinesync                                DWORD *pcchTargetUserSid )
1953c2c66affSColin Finck {
1954c2c66affSColin Finck     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
1955c2c66affSColin Finck     DWORD idx = 0;
1956c2c66affSColin Finck     UINT r;
1957c2c66affSColin Finck 
1958c2c66affSColin Finck     static DWORD last_index;
1959c2c66affSColin Finck 
196002f995b2Swinesync     TRACE( "%s, %s, %#lx, %lu, %lu, %p, %p, %p, %p, %p)\n", debugstr_w(szProductCode), debugstr_w(szUserSid),
196102f995b2Swinesync            dwContext, dwFilter, dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext, szTargetUserSid,
196202f995b2Swinesync            pcchTargetUserSid );
1963c2c66affSColin Finck 
1964c2c66affSColin Finck     if (!szProductCode || !squash_guid( szProductCode, squashed_pc ))
1965c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1966c2c66affSColin Finck 
19670f67ae4bSwinesync     if (szUserSid && !wcscmp( szUserSid, L"S-1-5-18" ))
1968c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1969c2c66affSColin Finck 
1970c2c66affSColin Finck     if (dwContext & MSIINSTALLCONTEXT_MACHINE && szUserSid)
1971c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1972c2c66affSColin Finck 
1973c2c66affSColin Finck     if (dwContext <= MSIINSTALLCONTEXT_NONE ||
1974c2c66affSColin Finck         dwContext > MSIINSTALLCONTEXT_ALL)
1975c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1976c2c66affSColin Finck 
1977c2c66affSColin Finck     if (dwFilter <= MSIPATCHSTATE_INVALID || dwFilter > MSIPATCHSTATE_ALL)
1978c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1979c2c66affSColin Finck 
1980c2c66affSColin Finck     if (dwIndex && dwIndex - last_index != 1)
1981c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1982c2c66affSColin Finck 
1983c2c66affSColin Finck     if (dwIndex == 0)
1984c2c66affSColin Finck         last_index = 0;
1985c2c66affSColin Finck 
1986*f4be6dc3SMikhail     r = enum_patches(szProductCode, szUserSid, dwContext, dwFilter, dwIndex, &idx, szPatchCode, szTargetProductCode,
1987*f4be6dc3SMikhail                      pdwTargetProductContext, szTargetUserSid, pcchTargetUserSid, NULL);
1988c2c66affSColin Finck 
1989c2c66affSColin Finck     if (r == ERROR_SUCCESS)
1990c2c66affSColin Finck         last_index = dwIndex;
1991c2c66affSColin Finck     else
1992c2c66affSColin Finck         last_index = 0;
1993c2c66affSColin Finck 
1994c2c66affSColin Finck     return r;
1995c2c66affSColin Finck }
1996c2c66affSColin Finck 
1997c2c66affSColin Finck /***********************************************************************
1998c2c66affSColin Finck  * MsiEnumPatchesA            [MSI.@]
1999c2c66affSColin Finck  */
MsiEnumPatchesA(const char * szProduct,DWORD iPatchIndex,char * lpPatchBuf,char * lpTransformsBuf,DWORD * pcchTransformsBuf)200002f995b2Swinesync UINT WINAPI MsiEnumPatchesA( const char *szProduct, DWORD iPatchIndex, char *lpPatchBuf, char *lpTransformsBuf,
200102f995b2Swinesync                              DWORD *pcchTransformsBuf )
2002c2c66affSColin Finck {
200302f995b2Swinesync     WCHAR *product, *transforms, patch[GUID_SIZE];
2004c2c66affSColin Finck     DWORD len;
2005c2c66affSColin Finck     UINT r;
2006c2c66affSColin Finck 
200702f995b2Swinesync     TRACE( "%s, %lu, %p, %p, %p\n", debugstr_a(szProduct), iPatchIndex, lpPatchBuf, lpTransformsBuf,
200802f995b2Swinesync            pcchTransformsBuf );
2009c2c66affSColin Finck 
2010c2c66affSColin Finck     if (!szProduct || !lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2011c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
2012c2c66affSColin Finck 
2013c2c66affSColin Finck     product = strdupAtoW(szProduct);
2014c2c66affSColin Finck     if (!product)
2015c2c66affSColin Finck         return ERROR_OUTOFMEMORY;
2016c2c66affSColin Finck 
2017c2c66affSColin Finck     len = *pcchTransformsBuf;
2018*f4be6dc3SMikhail     transforms = malloc(len * sizeof(WCHAR));
2019c2c66affSColin Finck     if (!transforms)
2020c2c66affSColin Finck     {
2021c2c66affSColin Finck         r = ERROR_OUTOFMEMORY;
2022c2c66affSColin Finck         goto done;
2023c2c66affSColin Finck     }
2024c2c66affSColin Finck 
2025c2c66affSColin Finck     r = MsiEnumPatchesW(product, iPatchIndex, patch, transforms, &len);
2026c2c66affSColin Finck     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2027c2c66affSColin Finck         goto done;
2028c2c66affSColin Finck 
2029c2c66affSColin Finck     WideCharToMultiByte(CP_ACP, 0, patch, -1, lpPatchBuf,
2030c2c66affSColin Finck                         GUID_SIZE, NULL, NULL);
2031c2c66affSColin Finck 
2032c2c66affSColin Finck     if (!WideCharToMultiByte(CP_ACP, 0, transforms, -1, lpTransformsBuf,
2033c2c66affSColin Finck                              *pcchTransformsBuf, NULL, NULL))
2034c2c66affSColin Finck         r = ERROR_MORE_DATA;
2035c2c66affSColin Finck 
2036c2c66affSColin Finck     if (r == ERROR_MORE_DATA)
2037c2c66affSColin Finck     {
2038c2c66affSColin Finck         lpTransformsBuf[*pcchTransformsBuf - 1] = '\0';
2039c2c66affSColin Finck         *pcchTransformsBuf = len * 2;
2040c2c66affSColin Finck     }
2041c2c66affSColin Finck     else
2042c2c66affSColin Finck         *pcchTransformsBuf = strlen( lpTransformsBuf );
2043c2c66affSColin Finck 
2044c2c66affSColin Finck done:
2045*f4be6dc3SMikhail     free(transforms);
2046*f4be6dc3SMikhail     free(product);
2047c2c66affSColin Finck 
2048c2c66affSColin Finck     return r;
2049c2c66affSColin Finck }
2050c2c66affSColin Finck 
2051c2c66affSColin Finck /***********************************************************************
2052c2c66affSColin Finck  * MsiEnumPatchesW            [MSI.@]
2053c2c66affSColin Finck  */
MsiEnumPatchesW(const WCHAR * szProduct,DWORD iPatchIndex,WCHAR * lpPatchBuf,WCHAR * lpTransformsBuf,DWORD * pcchTransformsBuf)205402f995b2Swinesync UINT WINAPI MsiEnumPatchesW( const WCHAR *szProduct, DWORD iPatchIndex, WCHAR *lpPatchBuf, WCHAR *lpTransformsBuf,
205502f995b2Swinesync                              DWORD *pcchTransformsBuf )
2056c2c66affSColin Finck {
2057c2c66affSColin Finck     WCHAR *transforms = NULL, squashed_pc[SQUASHED_GUID_SIZE];
2058c2c66affSColin Finck     HKEY prod;
2059c2c66affSColin Finck     DWORD idx = 0;
2060c2c66affSColin Finck     UINT r;
2061c2c66affSColin Finck 
206202f995b2Swinesync     TRACE( "%s, %lu, %p, %p, %p)\n", debugstr_w(szProduct), iPatchIndex, lpPatchBuf, lpTransformsBuf,
206302f995b2Swinesync            pcchTransformsBuf );
2064c2c66affSColin Finck 
2065c2c66affSColin Finck     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
2066c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
2067c2c66affSColin Finck 
2068c2c66affSColin Finck     if (!lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2069c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
2070c2c66affSColin Finck 
2071c2c66affSColin Finck     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2072c2c66affSColin Finck                               &prod, FALSE) != ERROR_SUCCESS &&
2073c2c66affSColin Finck         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2074c2c66affSColin Finck                               &prod, FALSE) != ERROR_SUCCESS &&
2075c2c66affSColin Finck         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2076c2c66affSColin Finck                               &prod, FALSE) != ERROR_SUCCESS)
2077c2c66affSColin Finck         return ERROR_UNKNOWN_PRODUCT;
2078c2c66affSColin Finck 
2079c2c66affSColin Finck     RegCloseKey(prod);
2080c2c66affSColin Finck 
2081*f4be6dc3SMikhail     r = enum_patches(szProduct, NULL, MSIINSTALLCONTEXT_ALL, MSIPATCHSTATE_ALL, iPatchIndex, &idx, lpPatchBuf, NULL,
2082*f4be6dc3SMikhail                      NULL, NULL, NULL, &transforms);
2083c2c66affSColin Finck     if (r != ERROR_SUCCESS)
2084c2c66affSColin Finck         goto done;
2085c2c66affSColin Finck 
2086c2c66affSColin Finck     lstrcpynW(lpTransformsBuf, transforms, *pcchTransformsBuf);
2087c2c66affSColin Finck     if (*pcchTransformsBuf <= lstrlenW(transforms))
2088c2c66affSColin Finck     {
2089c2c66affSColin Finck         r = ERROR_MORE_DATA;
2090c2c66affSColin Finck         *pcchTransformsBuf = lstrlenW(transforms);
2091c2c66affSColin Finck     }
2092c2c66affSColin Finck     else
2093c2c66affSColin Finck         *pcchTransformsBuf = lstrlenW(transforms);
2094c2c66affSColin Finck 
2095c2c66affSColin Finck done:
2096*f4be6dc3SMikhail     free(transforms);
2097c2c66affSColin Finck     return r;
2098c2c66affSColin Finck }
2099c2c66affSColin Finck 
MsiEnumProductsExA(const char * product,const char * usersid,DWORD ctx,DWORD index,char installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,char * sid,DWORD * sid_len)210002f995b2Swinesync UINT WINAPI MsiEnumProductsExA( const char *product, const char *usersid, DWORD ctx, DWORD index,
210102f995b2Swinesync                                 char installed_product[GUID_SIZE], MSIINSTALLCONTEXT *installed_ctx, char *sid,
210202f995b2Swinesync                                 DWORD *sid_len )
2103c2c66affSColin Finck {
2104c2c66affSColin Finck     UINT r;
2105c2c66affSColin Finck     WCHAR installed_productW[GUID_SIZE], *productW = NULL, *usersidW = NULL, *sidW = NULL;
2106c2c66affSColin Finck 
210702f995b2Swinesync     TRACE( "%s, %s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_a(product), debugstr_a(usersid), ctx, index,
210802f995b2Swinesync            installed_product, installed_ctx, sid, sid_len );
2109c2c66affSColin Finck 
2110c2c66affSColin Finck     if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
2111c2c66affSColin Finck     if (product && !(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
2112c2c66affSColin Finck     if (usersid && !(usersidW = strdupAtoW( usersid )))
2113c2c66affSColin Finck     {
2114*f4be6dc3SMikhail         free( productW );
2115c2c66affSColin Finck         return ERROR_OUTOFMEMORY;
2116c2c66affSColin Finck     }
2117*f4be6dc3SMikhail     if (sid && !(sidW = malloc( *sid_len * sizeof(WCHAR) )))
2118c2c66affSColin Finck     {
2119*f4be6dc3SMikhail         free( usersidW );
2120*f4be6dc3SMikhail         free( productW );
2121c2c66affSColin Finck         return ERROR_OUTOFMEMORY;
2122c2c66affSColin Finck     }
2123c2c66affSColin Finck     r = MsiEnumProductsExW( productW, usersidW, ctx, index, installed_productW,
2124c2c66affSColin Finck                             installed_ctx, sidW, sid_len );
2125c2c66affSColin Finck     if (r == ERROR_SUCCESS)
2126c2c66affSColin Finck     {
2127c2c66affSColin Finck         if (installed_product) WideCharToMultiByte( CP_ACP, 0, installed_productW, GUID_SIZE,
2128c2c66affSColin Finck                                                     installed_product, GUID_SIZE, NULL, NULL );
2129c2c66affSColin Finck         if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
2130c2c66affSColin Finck     }
2131*f4be6dc3SMikhail     free( productW );
2132*f4be6dc3SMikhail     free( usersidW );
2133*f4be6dc3SMikhail     free( sidW );
2134c2c66affSColin Finck     return r;
2135c2c66affSColin Finck }
2136c2c66affSColin Finck 
fetch_machine_product(const WCHAR * match,DWORD index,DWORD * idx,WCHAR installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,WCHAR * sid,DWORD * sid_len)2137c2c66affSColin Finck static UINT fetch_machine_product( const WCHAR *match, DWORD index, DWORD *idx,
2138c2c66affSColin Finck                                    WCHAR installed_product[GUID_SIZE],
2139c2c66affSColin Finck                                    MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2140c2c66affSColin Finck {
2141c2c66affSColin Finck     UINT r;
2142c2c66affSColin Finck     WCHAR product[SQUASHED_GUID_SIZE];
2143c2c66affSColin Finck     DWORD i = 0, len;
2144c2c66affSColin Finck     REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
2145c2c66affSColin Finck     HKEY key;
2146c2c66affSColin Finck 
21470f67ae4bSwinesync     if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Classes\\Installer\\Products", 0, access, &key ))
2148c2c66affSColin Finck         return ERROR_NO_MORE_ITEMS;
2149c2c66affSColin Finck 
21509792c08fSwinesync     len = ARRAY_SIZE( product );
2151c2c66affSColin Finck     while (!RegEnumKeyExW( key, i, product, &len, NULL, NULL, NULL, NULL ))
2152c2c66affSColin Finck     {
2153958f1addSwinesync         if (match && wcscmp( match, product ))
2154c2c66affSColin Finck         {
2155c2c66affSColin Finck             i++;
21569792c08fSwinesync             len = ARRAY_SIZE( product );
2157c2c66affSColin Finck             continue;
2158c2c66affSColin Finck         }
2159c2c66affSColin Finck         if (*idx == index) goto found;
2160c2c66affSColin Finck         (*idx)++;
21619792c08fSwinesync         len = ARRAY_SIZE( product );
2162c2c66affSColin Finck         i++;
2163c2c66affSColin Finck     }
2164c2c66affSColin Finck     RegCloseKey( key );
2165c2c66affSColin Finck     return ERROR_NO_MORE_ITEMS;
2166c2c66affSColin Finck 
2167c2c66affSColin Finck found:
2168c2c66affSColin Finck     if (sid_len && *sid_len < 1)
2169c2c66affSColin Finck     {
2170c2c66affSColin Finck         *sid_len = 1;
2171c2c66affSColin Finck         r = ERROR_MORE_DATA;
2172c2c66affSColin Finck     }
2173c2c66affSColin Finck     else
2174c2c66affSColin Finck     {
2175c2c66affSColin Finck         if (installed_product) unsquash_guid( product, installed_product );
2176c2c66affSColin Finck         if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
2177c2c66affSColin Finck         if (sid)
2178c2c66affSColin Finck         {
2179c2c66affSColin Finck             sid[0] = 0;
2180c2c66affSColin Finck             *sid_len = 0;
2181c2c66affSColin Finck         }
2182c2c66affSColin Finck         r = ERROR_SUCCESS;
2183c2c66affSColin Finck     }
2184c2c66affSColin Finck     RegCloseKey( key );
2185c2c66affSColin Finck     return r;
2186c2c66affSColin Finck }
2187c2c66affSColin Finck 
fetch_user_product(const WCHAR * match,const WCHAR * usersid,DWORD ctx,DWORD index,DWORD * idx,WCHAR installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,WCHAR * sid,DWORD * sid_len)2188c2c66affSColin Finck static UINT fetch_user_product( const WCHAR *match, const WCHAR *usersid, DWORD ctx, DWORD index,
2189c2c66affSColin Finck                                 DWORD *idx, WCHAR installed_product[GUID_SIZE],
2190c2c66affSColin Finck                                 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2191c2c66affSColin Finck {
2192c2c66affSColin Finck     UINT r;
2193c2c66affSColin Finck     const WCHAR *subkey;
2194c2c66affSColin Finck     WCHAR path[MAX_PATH], product[SQUASHED_GUID_SIZE], user[128];
2195c2c66affSColin Finck     DWORD i = 0, j = 0, len_product, len_user;
2196c2c66affSColin Finck     REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
2197c2c66affSColin Finck     HKEY key_users, key_products;
2198c2c66affSColin Finck 
2199c2c66affSColin Finck     if (ctx == MSIINSTALLCONTEXT_USERMANAGED)
2200c2c66affSColin Finck     {
22010f67ae4bSwinesync         subkey = L"\\Installer\\Products";
22020f67ae4bSwinesync         if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed",
22030f67ae4bSwinesync                            0, access, &key_users )) return ERROR_NO_MORE_ITEMS;
2204c2c66affSColin Finck     }
2205c2c66affSColin Finck     else if (ctx == MSIINSTALLCONTEXT_USERUNMANAGED)
2206c2c66affSColin Finck     {
22070f67ae4bSwinesync         subkey = L"\\Software\\Microsoft\\Installer\\Products";
2208c2c66affSColin Finck         if (RegOpenKeyExW( HKEY_USERS, NULL, 0, access, &key_users ))
2209c2c66affSColin Finck             return ERROR_NO_MORE_ITEMS;
2210c2c66affSColin Finck     }
2211c2c66affSColin Finck     else return ERROR_INVALID_PARAMETER;
2212c2c66affSColin Finck 
22139792c08fSwinesync     len_user = ARRAY_SIZE( user );
2214c2c66affSColin Finck     while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
2215c2c66affSColin Finck     {
22160f67ae4bSwinesync         if (wcscmp( usersid, user ) && wcscmp( usersid, L"S-1-1-0" ))
2217c2c66affSColin Finck         {
2218c2c66affSColin Finck             i++;
22199792c08fSwinesync             len_user = ARRAY_SIZE( user );
2220c2c66affSColin Finck             continue;
2221c2c66affSColin Finck         }
2222958f1addSwinesync         lstrcpyW( path, user );
2223958f1addSwinesync         lstrcatW( path, subkey );
2224c2c66affSColin Finck         if (RegOpenKeyExW( key_users, path, 0, access, &key_products ))
2225c2c66affSColin Finck         {
2226c2c66affSColin Finck             i++;
22279792c08fSwinesync             len_user = ARRAY_SIZE( user );
2228c2c66affSColin Finck             continue;
2229c2c66affSColin Finck         }
22309792c08fSwinesync         len_product = ARRAY_SIZE( product );
2231c2c66affSColin Finck         while (!RegEnumKeyExW( key_products, j, product, &len_product, NULL, NULL, NULL, NULL ))
2232c2c66affSColin Finck         {
2233958f1addSwinesync             if (match && wcscmp( match, product ))
2234c2c66affSColin Finck             {
2235c2c66affSColin Finck                 j++;
22369792c08fSwinesync                 len_product = ARRAY_SIZE( product );
2237c2c66affSColin Finck                 continue;
2238c2c66affSColin Finck             }
2239c2c66affSColin Finck             if (*idx == index) goto found;
2240c2c66affSColin Finck             (*idx)++;
22419792c08fSwinesync             len_product = ARRAY_SIZE( product );
2242c2c66affSColin Finck             j++;
2243c2c66affSColin Finck         }
2244c2c66affSColin Finck         RegCloseKey( key_products );
22459792c08fSwinesync         len_user = ARRAY_SIZE( user );
2246c2c66affSColin Finck         i++;
2247c2c66affSColin Finck     }
2248c2c66affSColin Finck     RegCloseKey( key_users );
2249c2c66affSColin Finck     return ERROR_NO_MORE_ITEMS;
2250c2c66affSColin Finck 
2251c2c66affSColin Finck found:
2252c2c66affSColin Finck     if (sid_len && *sid_len <= len_user)
2253c2c66affSColin Finck     {
2254c2c66affSColin Finck         *sid_len = len_user;
2255c2c66affSColin Finck         r = ERROR_MORE_DATA;
2256c2c66affSColin Finck     }
2257c2c66affSColin Finck     else
2258c2c66affSColin Finck     {
2259c2c66affSColin Finck         if (installed_product) unsquash_guid( product, installed_product );
2260c2c66affSColin Finck         if (installed_ctx) *installed_ctx = ctx;
2261c2c66affSColin Finck         if (sid)
2262c2c66affSColin Finck         {
2263958f1addSwinesync             lstrcpyW( sid, user );
2264c2c66affSColin Finck             *sid_len = len_user;
2265c2c66affSColin Finck         }
2266c2c66affSColin Finck         r = ERROR_SUCCESS;
2267c2c66affSColin Finck     }
2268c2c66affSColin Finck     RegCloseKey( key_products );
2269c2c66affSColin Finck     RegCloseKey( key_users );
2270c2c66affSColin Finck     return r;
2271c2c66affSColin Finck }
2272c2c66affSColin Finck 
enum_products(const WCHAR * product,const WCHAR * usersid,DWORD ctx,DWORD index,DWORD * idx,WCHAR installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,WCHAR * sid,DWORD * sid_len)2273c2c66affSColin Finck static UINT enum_products( const WCHAR *product, const WCHAR *usersid, DWORD ctx, DWORD index,
2274c2c66affSColin Finck                            DWORD *idx, WCHAR installed_product[GUID_SIZE],
2275c2c66affSColin Finck                            MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2276c2c66affSColin Finck {
2277c2c66affSColin Finck     UINT r = ERROR_NO_MORE_ITEMS;
2278c2c66affSColin Finck     WCHAR *user = NULL;
2279c2c66affSColin Finck 
2280c2c66affSColin Finck     if (!usersid)
2281c2c66affSColin Finck     {
2282c2c66affSColin Finck         usersid = user = get_user_sid();
2283c2c66affSColin Finck         if (!user) return ERROR_FUNCTION_FAILED;
2284c2c66affSColin Finck     }
2285c2c66affSColin Finck     if (ctx & MSIINSTALLCONTEXT_MACHINE)
2286c2c66affSColin Finck     {
2287c2c66affSColin Finck         r = fetch_machine_product( product, index, idx, installed_product, installed_ctx,
2288c2c66affSColin Finck                                    sid, sid_len );
2289c2c66affSColin Finck         if (r != ERROR_NO_MORE_ITEMS) goto done;
2290c2c66affSColin Finck     }
2291c2c66affSColin Finck     if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
2292c2c66affSColin Finck     {
2293c2c66affSColin Finck         r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index,
2294c2c66affSColin Finck                                 idx, installed_product, installed_ctx, sid, sid_len );
2295c2c66affSColin Finck         if (r != ERROR_NO_MORE_ITEMS) goto done;
2296c2c66affSColin Finck     }
2297c2c66affSColin Finck     if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
2298c2c66affSColin Finck     {
2299c2c66affSColin Finck         r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERMANAGED, index,
2300c2c66affSColin Finck                                 idx, installed_product, installed_ctx, sid, sid_len );
2301c2c66affSColin Finck         if (r != ERROR_NO_MORE_ITEMS) goto done;
2302c2c66affSColin Finck     }
2303c2c66affSColin Finck 
2304c2c66affSColin Finck done:
2305c2c66affSColin Finck     LocalFree( user );
2306c2c66affSColin Finck     return r;
2307c2c66affSColin Finck }
2308c2c66affSColin Finck 
MsiEnumProductsExW(const WCHAR * product,const WCHAR * usersid,DWORD ctx,DWORD index,WCHAR installed_product[GUID_SIZE],MSIINSTALLCONTEXT * installed_ctx,WCHAR * sid,DWORD * sid_len)230902f995b2Swinesync UINT WINAPI MsiEnumProductsExW( const WCHAR *product, const WCHAR *usersid, DWORD ctx, DWORD index,
231002f995b2Swinesync                                 WCHAR installed_product[GUID_SIZE], MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid,
231102f995b2Swinesync                                 DWORD *sid_len )
2312c2c66affSColin Finck {
2313c2c66affSColin Finck     UINT r;
2314c2c66affSColin Finck     DWORD idx = 0;
2315c2c66affSColin Finck     static DWORD last_index;
2316c2c66affSColin Finck 
231702f995b2Swinesync     TRACE( "%s, %s, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(product), debugstr_w(usersid), ctx, index,
231802f995b2Swinesync            installed_product, installed_ctx, sid, sid_len );
2319c2c66affSColin Finck 
2320c2c66affSColin Finck     if ((sid && !sid_len) || !ctx || (usersid && ctx == MSIINSTALLCONTEXT_MACHINE))
2321c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
2322c2c66affSColin Finck 
2323c2c66affSColin Finck     if (index && index - last_index != 1)
2324c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
2325c2c66affSColin Finck 
2326c2c66affSColin Finck     if (!index) last_index = 0;
2327c2c66affSColin Finck 
2328c2c66affSColin Finck     r = enum_products( product, usersid, ctx, index, &idx, installed_product, installed_ctx,
2329c2c66affSColin Finck                        sid, sid_len );
2330c2c66affSColin Finck     if (r == ERROR_SUCCESS)
2331c2c66affSColin Finck         last_index = index;
2332c2c66affSColin Finck     else
2333c2c66affSColin Finck         last_index = 0;
2334c2c66affSColin Finck 
2335c2c66affSColin Finck     return r;
2336c2c66affSColin Finck }
2337