msi/tests: Cleanup registry after test.
[wine] / dlls / msi / registry.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2005 Mike McCormack for CodeWeavers
5  * Copyright 2005 Aric Stewart for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23
24 #define COBJMACROS
25 #define NONAMELESSUNION
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winreg.h"
30 #include "winnls.h"
31 #include "shlwapi.h"
32 #include "wine/debug.h"
33 #include "msi.h"
34 #include "msipriv.h"
35 #include "wincrypt.h"
36 #include "wine/unicode.h"
37 #include "winver.h"
38 #include "winuser.h"
39 #include "sddl.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42
43
44 /* 
45  * This module will be all the helper functions for registry access by the
46  * installer bits. 
47  */
48 static const WCHAR szUserFeatures_fmt[] = {
49 'S','o','f','t','w','a','r','e','\\',
50 'M','i','c','r','o','s','o','f','t','\\',
51 'I','n','s','t','a','l','l','e','r','\\',
52 'F','e','a','t','u','r','e','s','\\',
53 '%','s',0};
54
55 static const WCHAR szUserDataFeatures_fmt[] = {
56 'S','o','f','t','w','a','r','e','\\',
57 'M','i','c','r','o','s','o','f','t','\\',
58 'W','i','n','d','o','w','s','\\',
59 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
60 'I','n','s','t','a','l','l','e','r','\\',
61 'U','s','e','r','D','a','t','a','\\',
62 '%','s','\\','P','r','o','d','u','c','t','s','\\',
63 '%','s','\\','F','e','a','t','u','r','e','s',0};
64
65 static const WCHAR szInstaller_Features_fmt[] = {
66 'S','o','f','t','w','a','r','e','\\',
67 'M','i','c','r','o','s','o','f','t','\\',
68 'W','i','n','d','o','w','s','\\',
69 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
70 'I','n','s','t','a','l','l','e','r','\\',
71 'F','e','a','t','u','r','e','s','\\',
72 '%','s',0};
73
74 static const WCHAR szInstaller_Components[] = {
75 'S','o','f','t','w','a','r','e','\\',
76 'M','i','c','r','o','s','o','f','t','\\',
77 'W','i','n','d','o','w','s','\\',
78 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
79 'I','n','s','t','a','l','l','e','r','\\',
80 'C','o','m','p','o','n','e','n','t','s',0 };
81
82 static const WCHAR szUser_Components_fmt[] = {
83 'S','o','f','t','w','a','r','e','\\',
84 'M','i','c','r','o','s','o','f','t','\\',
85 'I','n','s','t','a','l','l','e','r','\\',
86 'C','o','m','p','o','n','e','n','t','s','\\',
87 '%','s',0};
88
89 static const WCHAR szUserDataComp_fmt[] = {
90 'S','o','f','t','w','a','r','e','\\',
91 'M','i','c','r','o','s','o','f','t','\\',
92 'W','i','n','d','o','w','s','\\',
93 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
94 'I','n','s','t','a','l','l','e','r','\\',
95 'U','s','e','r','D','a','t','a','\\',
96 '%','s','\\','C','o','m','p','o','n','e','n','t','s','\\','%','s',0};
97
98 static const WCHAR szUninstall_fmt[] = {
99 'S','o','f','t','w','a','r','e','\\',
100 'M','i','c','r','o','s','o','f','t','\\',
101 'W','i','n','d','o','w','s','\\',
102 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
103 'U','n','i','n','s','t','a','l','l','\\',
104 '%','s',0 };
105
106 static const WCHAR szUserProduct_fmt[] = {
107 'S','o','f','t','w','a','r','e','\\',
108 'M','i','c','r','o','s','o','f','t','\\',
109 'I','n','s','t','a','l','l','e','r','\\',
110 'P','r','o','d','u','c','t','s','\\',
111 '%','s',0};
112
113 static const WCHAR szUserPatch_fmt[] = {
114 'S','o','f','t','w','a','r','e','\\',
115 'M','i','c','r','o','s','o','f','t','\\',
116 'I','n','s','t','a','l','l','e','r','\\',
117 'P','a','t','c','h','e','s','\\',
118 '%','s',0};
119
120 static const WCHAR szInstaller_Products[] = {
121 'S','o','f','t','w','a','r','e','\\',
122 'M','i','c','r','o','s','o','f','t','\\',
123 'W','i','n','d','o','w','s','\\',
124 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
125 'I','n','s','t','a','l','l','e','r','\\',
126 'P','r','o','d','u','c','t','s',0};
127
128 static const WCHAR szInstaller_Products_fmt[] = {
129 'S','o','f','t','w','a','r','e','\\',
130 'M','i','c','r','o','s','o','f','t','\\',
131 'W','i','n','d','o','w','s','\\',
132 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
133 'I','n','s','t','a','l','l','e','r','\\',
134 'P','r','o','d','u','c','t','s','\\',
135 '%','s',0};
136
137 static const WCHAR szInstaller_Patches_fmt[] = {
138 'S','o','f','t','w','a','r','e','\\',
139 'M','i','c','r','o','s','o','f','t','\\',
140 'W','i','n','d','o','w','s','\\',
141 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
142 'I','n','s','t','a','l','l','e','r','\\',
143 'P','a','t','c','h','e','s','\\',
144 '%','s',0};
145
146 static const WCHAR szInstaller_UpgradeCodes_fmt[] = {
147 'S','o','f','t','w','a','r','e','\\',
148 'M','i','c','r','o','s','o','f','t','\\',
149 'W','i','n','d','o','w','s','\\',
150 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
151 'I','n','s','t','a','l','l','e','r','\\',
152 'U','p','g','r','a','d','e','C','o','d','e','s','\\',
153 '%','s',0};
154
155 static const WCHAR szInstaller_UserUpgradeCodes_fmt[] = {
156 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'I','n','s','t','a','l','l','e','r','\\',
159 'U','p','g','r','a','d','e','C','o','d','e','s','\\',
160 '%','s',0};
161
162 static const WCHAR szUserDataProd_fmt[] = {
163 'S','o','f','t','w','a','r','e','\\',
164 'M','i','c','r','o','s','o','f','t','\\',
165 'W','i','n','d','o','w','s','\\',
166 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
167 'I','n','s','t','a','l','l','e','r','\\',
168 'U','s','e','r','D','a','t','a','\\',
169 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s',0};
170
171 static const WCHAR szInstallProperties_fmt[] = {
172 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'I','n','s','t','a','l','l','e','r','\\',
177 'U','s','e','r','D','a','t','a','\\',
178 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\',
179 'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
180
181 static const WCHAR szInstaller_LocalSystemProductCodes_fmt[] = {
182 'S','o','f','t','w','a','r','e','\\',
183 'M','i','c','r','o','s','o','f','t','\\',
184 'W','i','n','d','o','w','s','\\',
185 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
186 'I','n','s','t','a','l','l','e','r','\\',
187 'U','s','e','r','D','a','t','a','\\',
188 'S','-','1','-','5','-','1','8','\\','P','r','o','d','u','c','t','s','\\',
189 '%','s','\\','I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
190
191 static const WCHAR szInstaller_LocalSystemComponent_fmt[] = {
192 'S','o','f','t','w','a','r','e','\\',
193 'M','i','c','r','o','s','o','f','t','\\',
194 'W','i','n','d','o','w','s','\\',
195 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
196 'I','n','s','t','a','l','l','e','r','\\',
197 'U','s','e','r','D','a','t','a','\\',
198 'S','-','1','-','5','-','1','8','\\',
199 'C','o','m','p','o','n','e','n','t','s','\\','%','s',0};
200
201 static const WCHAR szInstaller_LocalClassesProd_fmt[] = {
202 'S','o','f','t','w','a','r','e','\\',
203 'C','l','a','s','s','e','s','\\',
204 'I','n','s','t','a','l','l','e','r','\\',
205 'P','r','o','d','u','c','t','s','\\','%','s',0};
206
207 static const WCHAR szInstaller_LocalManagedProd_fmt[] = {
208 'S','o','f','t','w','a','r','e','\\',
209 'M','i','c','r','o','s','o','f','t','\\',
210 'W','i','n','d','o','w','s','\\',
211 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
212 'I','n','s','t','a','l','l','e','r','\\',
213 'M','a','n','a','g','e','d','\\','%','s','\\',
214 'I','n','s','t','a','l','l','e','r','\\',
215 'P','r','o','d','u','c','t','s','\\','%','s',0};
216
217 BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
218 {
219     DWORD i,n=0;
220
221     out[n++]='{';
222     for(i=0; i<8; i++)
223         out[n++] = in[7-i];
224     out[n++]='-';
225     for(i=0; i<4; i++)
226         out[n++] = in[11-i];
227     out[n++]='-';
228     for(i=0; i<4; i++)
229         out[n++] = in[15-i];
230     out[n++]='-';
231     for(i=0; i<2; i++)
232     {
233         out[n++] = in[17+i*2];
234         out[n++] = in[16+i*2];
235     }
236     out[n++]='-';
237     for( ; i<8; i++)
238     {
239         out[n++] = in[17+i*2];
240         out[n++] = in[16+i*2];
241     }
242     out[n++]='}';
243     out[n]=0;
244     return TRUE;
245 }
246
247 BOOL squash_guid(LPCWSTR in, LPWSTR out)
248 {
249     DWORD i,n=1;
250     GUID guid;
251
252     out[0] = 0;
253
254     if (FAILED(CLSIDFromString((LPOLESTR)in, &guid)))
255         return FALSE;
256
257     for(i=0; i<8; i++)
258         out[7-i] = in[n++];
259     n++;
260     for(i=0; i<4; i++)
261         out[11-i] = in[n++];
262     n++;
263     for(i=0; i<4; i++)
264         out[15-i] = in[n++];
265     n++;
266     for(i=0; i<2; i++)
267     {
268         out[17+i*2] = in[n++];
269         out[16+i*2] = in[n++];
270     }
271     n++;
272     for( ; i<8; i++)
273     {
274         out[17+i*2] = in[n++];
275         out[16+i*2] = in[n++];
276     }
277     out[32]=0;
278     return TRUE;
279 }
280
281
282 /* tables for encoding and decoding base85 */
283 static const unsigned char table_dec85[0x80] = {
284 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
285 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
286 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
287 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
288 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
289 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
290 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
291 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
292 };
293
294 static const char table_enc85[] =
295 "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
296 "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
297 "yz{}~";
298
299 /*
300  *  Converts a base85 encoded guid into a GUID pointer
301  *  Base85 encoded GUIDs should be 20 characters long.
302  *
303  *  returns TRUE if successful, FALSE if not
304  */
305 BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
306 {
307     DWORD i, val = 0, base = 1, *p;
308
309     if (!str)
310         return FALSE;
311
312     p = (DWORD*) guid;
313     for( i=0; i<20; i++ )
314     {
315         if( (i%5) == 0 )
316         {
317             val = 0;
318             base = 1;
319         }
320         val += table_dec85[str[i]] * base;
321         if( str[i] >= 0x80 )
322             return FALSE;
323         if( table_dec85[str[i]] == 0xff )
324             return FALSE;
325         if( (i%5) == 4 )
326             p[i/5] = val;
327         base *= 85;
328     }
329     return TRUE;
330 }
331
332 /*
333  *  Encodes a base85 guid given a GUID pointer
334  *  Caller should provide a 21 character buffer for the encoded string.
335  *
336  *  returns TRUE if successful, FALSE if not
337  */
338 BOOL encode_base85_guid( GUID *guid, LPWSTR str )
339 {
340     unsigned int x, *p, i;
341
342     p = (unsigned int*) guid;
343     for( i=0; i<4; i++ )
344     {
345         x = p[i];
346         *str++ = table_enc85[x%85];
347         x = x/85;
348         *str++ = table_enc85[x%85];
349         x = x/85;
350         *str++ = table_enc85[x%85];
351         x = x/85;
352         *str++ = table_enc85[x%85];
353         x = x/85;
354         *str++ = table_enc85[x%85];
355     }
356     *str = 0;
357
358     return TRUE;
359 }
360
361 DWORD msi_version_str_to_dword(LPCWSTR p)
362 {
363     DWORD major, minor = 0, build = 0, version = 0;
364
365     if (!p)
366         return version;
367
368     major = atoiW(p);
369
370     p = strchrW(p, '.');
371     if (p)
372     {
373         minor = atoiW(p+1);
374         p = strchrW(p+1, '.');
375         if (p)
376             build = atoiW(p+1);
377     }
378
379     return MAKELONG(build, MAKEWORD(minor, major));
380 }
381
382 LPWSTR msi_version_dword_to_str(DWORD version)
383 {
384     static const WCHAR fmt[] = { '%','u','.','%','u','.','%','u',0 };
385     LPWSTR str = msi_alloc(20);
386     sprintfW(str, fmt,
387              (version&0xff000000)>>24,
388              (version&0x00ff0000)>>16,
389               version&0x0000ffff);
390     return str;
391 }
392
393 LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
394 {
395     static const WCHAR emptyW[] = {0};
396     DWORD len;
397     if (!value) value = emptyW;
398     len = (lstrlenW(value) + 1) * sizeof (WCHAR);
399     return RegSetValueExW( hkey, name, 0, REG_SZ, (const BYTE *)value, len );
400 }
401
402 LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
403 {
404     LPCWSTR p = value;
405     while (*p) p += lstrlenW(p) + 1;
406     return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
407                            (const BYTE *)value, (p + 1 - value) * sizeof(WCHAR) );
408 }
409
410 LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
411 {
412     return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
413 }
414
415 LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
416 {
417     HKEY hsubkey = 0;
418     LONG r;
419
420     r = RegCreateKeyW( hkey, path, &hsubkey );
421     if (r != ERROR_SUCCESS)
422         return r;
423     r = msi_reg_set_val_str( hsubkey, name, val );
424     RegCloseKey( hsubkey );
425     return r;
426 }
427
428 LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name )
429 {
430     DWORD len = 0;
431     LPWSTR val;
432     LONG r;
433
434     r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len);
435     if (r != ERROR_SUCCESS)
436         return NULL;
437
438     len += sizeof (WCHAR);
439     val = msi_alloc( len );
440     if (!val)
441         return NULL;
442     val[0] = 0;
443     RegQueryValueExW(hkey, name, NULL, NULL, (LPBYTE) val, &len);
444     return val;
445 }
446
447 BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val)
448 {
449     DWORD type, len = sizeof (DWORD);
450     LONG r = RegQueryValueExW(hkey, name, NULL, &type, (LPBYTE) val, &len);
451     return r == ERROR_SUCCESS && type == REG_DWORD;
452 }
453
454 static UINT get_user_sid(LPWSTR *usersid)
455 {
456     HANDLE token;
457     BYTE buf[1024];
458     DWORD size;
459     PTOKEN_USER user;
460
461     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
462         return ERROR_FUNCTION_FAILED;
463
464     size = sizeof(buf);
465     if (!GetTokenInformation(token, TokenUser, (void *)buf, size, &size)) {
466         CloseHandle(token);
467         return ERROR_FUNCTION_FAILED;
468     }
469
470     user = (PTOKEN_USER)buf;
471     if (!ConvertSidToStringSidW(user->User.Sid, usersid)) {
472         CloseHandle(token);
473         return ERROR_FUNCTION_FAILED;
474     }
475     CloseHandle(token);
476     return ERROR_SUCCESS;
477 }
478
479 UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create)
480 {
481     UINT rc;
482     WCHAR keypath[0x200];
483     TRACE("%s\n",debugstr_w(szProduct));
484
485     sprintfW(keypath,szUninstall_fmt,szProduct);
486
487     if (create)
488         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
489     else
490         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
491
492     return rc;
493 }
494
495 UINT MSIREG_DeleteUninstallKey(LPCWSTR szProduct)
496 {
497     WCHAR keypath[0x200];
498     TRACE("%s\n",debugstr_w(szProduct));
499
500     sprintfW(keypath,szUninstall_fmt,szProduct);
501
502     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
503 }
504
505 UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create)
506 {
507     UINT rc;
508     WCHAR squished_pc[GUID_SIZE];
509     WCHAR keypath[0x200];
510
511     TRACE("%s\n",debugstr_w(szProduct));
512     if (!squash_guid(szProduct,squished_pc))
513         return ERROR_FUNCTION_FAILED;
514     TRACE("squished (%s)\n", debugstr_w(squished_pc));
515
516     sprintfW(keypath,szUserProduct_fmt,squished_pc);
517
518     if (create)
519         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
520     else
521         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
522
523     return rc;
524 }
525
526 UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
527 {
528     WCHAR squished_pc[GUID_SIZE];
529     WCHAR keypath[0x200];
530
531     TRACE("%s\n",debugstr_w(szProduct));
532     if (!squash_guid(szProduct,squished_pc))
533         return ERROR_FUNCTION_FAILED;
534     TRACE("squished (%s)\n", debugstr_w(squished_pc));
535
536     sprintfW(keypath,szUserProduct_fmt,squished_pc);
537
538     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
539 }
540
541 UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create)
542 {
543     UINT rc;
544     WCHAR squished_pc[GUID_SIZE];
545     WCHAR keypath[0x200];
546
547     TRACE("%s\n",debugstr_w(szPatch));
548     if (!squash_guid(szPatch,squished_pc))
549         return ERROR_FUNCTION_FAILED;
550     TRACE("squished (%s)\n", debugstr_w(squished_pc));
551
552     sprintfW(keypath,szUserPatch_fmt,squished_pc);
553
554     if (create)
555         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
556     else
557         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
558
559     return rc;
560 }
561
562 UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create)
563 {
564     UINT rc;
565     WCHAR squished_pc[GUID_SIZE];
566     WCHAR keypath[0x200];
567
568     TRACE("%s\n",debugstr_w(szProduct));
569     if (!squash_guid(szProduct,squished_pc))
570         return ERROR_FUNCTION_FAILED;
571     TRACE("squished (%s)\n", debugstr_w(squished_pc));
572
573     sprintfW(keypath,szUserFeatures_fmt,squished_pc);
574
575     if (create)
576         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
577     else
578         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
579
580     return rc;
581 }
582
583 UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
584 {
585     WCHAR squished_pc[GUID_SIZE];
586     WCHAR keypath[0x200];
587
588     TRACE("%s\n",debugstr_w(szProduct));
589     if (!squash_guid(szProduct,squished_pc))
590         return ERROR_FUNCTION_FAILED;
591     TRACE("squished (%s)\n", debugstr_w(squished_pc));
592
593     sprintfW(keypath,szUserFeatures_fmt,squished_pc);
594     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
595 }
596
597 UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create)
598 {
599     UINT rc;
600     WCHAR squished_pc[GUID_SIZE];
601     WCHAR keypath[0x200];
602
603     TRACE("%s\n",debugstr_w(szProduct));
604     if (!squash_guid(szProduct,squished_pc))
605         return ERROR_FUNCTION_FAILED;
606     TRACE("squished (%s)\n", debugstr_w(squished_pc));
607
608     sprintfW(keypath,szInstaller_Features_fmt,squished_pc);
609
610     if (create)
611         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
612     else
613         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
614
615     return rc;
616 }
617
618 UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
619 {
620     UINT rc;
621     WCHAR squished_pc[GUID_SIZE];
622     WCHAR keypath[0x200];
623     LPWSTR usersid;
624
625     TRACE("%s\n", debugstr_w(szProduct));
626     if (!squash_guid(szProduct, squished_pc))
627         return ERROR_FUNCTION_FAILED;
628     TRACE("squished (%s)\n", debugstr_w(squished_pc));
629
630     rc = get_user_sid(&usersid);
631     if (rc != ERROR_SUCCESS || !usersid)
632     {
633         ERR("Failed to retrieve user SID: %d\n", rc);
634         return rc;
635     }
636
637     sprintfW(keypath, szUserDataFeatures_fmt, usersid, squished_pc);
638
639     if (create)
640         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
641     else
642         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
643
644     LocalFree(usersid);
645     return rc;
646 }
647
648 UINT MSIREG_OpenComponents(HKEY* key)
649 {
650     return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Components,key);
651 }
652
653 UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create)
654 {
655     UINT rc;
656     WCHAR squished_cc[GUID_SIZE];
657     WCHAR keypath[0x200];
658
659     TRACE("%s\n",debugstr_w(szComponent));
660     if (!squash_guid(szComponent,squished_cc))
661         return ERROR_FUNCTION_FAILED;
662     TRACE("squished (%s)\n", debugstr_w(squished_cc));
663
664     sprintfW(keypath,szUser_Components_fmt,squished_cc);
665
666     if (create)
667         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
668     else
669         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
670
671     return rc;
672 }
673
674 UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create)
675 {
676     UINT rc;
677     WCHAR comp[GUID_SIZE];
678     WCHAR keypath[0x200];
679     LPWSTR usersid;
680
681     TRACE("%s\n", debugstr_w(szComponent));
682     if (!squash_guid(szComponent, comp))
683         return ERROR_FUNCTION_FAILED;
684     TRACE("squished (%s)\n", debugstr_w(comp));
685
686     rc = get_user_sid(&usersid);
687     if (rc != ERROR_SUCCESS || !usersid)
688     {
689         ERR("Failed to retrieve user SID: %d\n", rc);
690         return rc;
691     }
692
693     sprintfW(keypath, szUserDataComp_fmt, usersid, comp);
694
695     if (create)
696         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
697     else
698         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
699
700     LocalFree(usersid);
701     return rc;
702 }
703
704 UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent)
705 {
706     UINT rc;
707     WCHAR comp[GUID_SIZE];
708     WCHAR keypath[0x200];
709     LPWSTR usersid;
710
711     TRACE("%s\n", debugstr_w(szComponent));
712     if (!squash_guid(szComponent, comp))
713         return ERROR_FUNCTION_FAILED;
714     TRACE("squished (%s)\n", debugstr_w(comp));
715
716     rc = get_user_sid(&usersid);
717     if (rc != ERROR_SUCCESS || !usersid)
718     {
719         ERR("Failed to retrieve user SID: %d\n", rc);
720         return rc;
721     }
722
723     sprintfW(keypath, szUserDataComp_fmt, usersid, comp);
724
725     LocalFree(usersid);
726     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
727 }
728
729 UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, HKEY *key, BOOL create)
730 {
731     UINT rc;
732     WCHAR squished_pc[GUID_SIZE];
733     WCHAR keypath[0x200];
734     LPWSTR usersid;
735
736     TRACE("%s\n", debugstr_w(szProduct));
737     if (!squash_guid(szProduct, squished_pc))
738         return ERROR_FUNCTION_FAILED;
739     TRACE("squished (%s)\n", debugstr_w(squished_pc));
740
741     rc = get_user_sid(&usersid);
742     if (rc != ERROR_SUCCESS || !usersid)
743     {
744         ERR("Failed to retrieve user SID: %d\n", rc);
745         return rc;
746     }
747
748     sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc);
749
750     if (create)
751         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
752     else
753         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
754
755     LocalFree(usersid);
756     return rc;
757 }
758
759 static UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, LPCWSTR szUserSID,
760                                     HKEY *key, BOOL create)
761 {
762     UINT rc;
763     WCHAR squished_pc[GUID_SIZE];
764     WCHAR keypath[0x200];
765
766     TRACE("%s\n", debugstr_w(szProduct));
767     if (!squash_guid(szProduct, squished_pc))
768         return ERROR_FUNCTION_FAILED;
769     TRACE("squished (%s)\n", debugstr_w(squished_pc));
770
771     sprintfW(keypath, szInstallProperties_fmt, szUserSID, squished_pc);
772
773     if (create)
774         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
775     else
776         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
777
778     return rc;
779 }
780
781 UINT MSIREG_OpenCurrentUserInstallProps(LPCWSTR szProduct, HKEY *key,
782                                                BOOL create)
783 {
784     UINT rc;
785     LPWSTR usersid;
786
787     rc = get_user_sid(&usersid);
788     if (rc != ERROR_SUCCESS || !usersid)
789     {
790         ERR("Failed to retrieve user SID: %d\n", rc);
791         return rc;
792     }
793
794     rc = MSIREG_OpenInstallProps(szProduct, usersid, key, create);
795
796     LocalFree(usersid);
797     return rc;
798 }
799
800 UINT MSIREG_OpenLocalSystemInstallProps(LPCWSTR szProduct, HKEY *key,
801                                         BOOL create)
802 {
803     static const WCHAR localsid[] = {'S','-','1','-','5','-','1','8',0};
804
805     return MSIREG_OpenInstallProps(szProduct, localsid, key, create);
806 }
807
808 UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct)
809 {
810     UINT rc;
811     WCHAR squished_pc[GUID_SIZE];
812     WCHAR keypath[0x200];
813     LPWSTR usersid;
814
815     TRACE("%s\n", debugstr_w(szProduct));
816     if (!squash_guid(szProduct, squished_pc))
817         return ERROR_FUNCTION_FAILED;
818     TRACE("squished (%s)\n", debugstr_w(squished_pc));
819
820     rc = get_user_sid(&usersid);
821     if (rc != ERROR_SUCCESS || !usersid)
822     {
823         ERR("Failed to retrieve user SID: %d\n", rc);
824         return rc;
825     }
826
827     sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc);
828
829     LocalFree(usersid);
830     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
831 }
832
833 UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create)
834 {
835     UINT rc;
836     WCHAR squished_pc[GUID_SIZE];
837     WCHAR keypath[0x200];
838
839     TRACE("%s\n",debugstr_w(szProduct));
840     if (!squash_guid(szProduct,squished_pc))
841         return ERROR_FUNCTION_FAILED;
842     TRACE("squished (%s)\n", debugstr_w(squished_pc));
843
844     sprintfW(keypath,szInstaller_Products_fmt,squished_pc);
845
846     if (create)
847         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
848     else
849         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
850
851     return rc;
852 }
853
854 UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
855 {
856     WCHAR squished_pc[GUID_SIZE];
857     WCHAR keypath[0x200];
858
859     TRACE("%s\n", debugstr_w(szProduct));
860     if (!squash_guid(szProduct, squished_pc))
861         return ERROR_FUNCTION_FAILED;
862     TRACE("squished (%s)\n", debugstr_w(squished_pc));
863
864     sprintfW(keypath, szInstaller_Products_fmt, squished_pc);
865
866     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
867 }
868
869 UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create)
870 {
871     UINT rc;
872     WCHAR squished_pc[GUID_SIZE];
873     WCHAR keypath[0x200];
874
875     TRACE("%s\n",debugstr_w(szPatch));
876     if (!squash_guid(szPatch,squished_pc))
877         return ERROR_FUNCTION_FAILED;
878     TRACE("squished (%s)\n", debugstr_w(squished_pc));
879
880     sprintfW(keypath,szInstaller_Patches_fmt,squished_pc);
881
882     if (create)
883         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
884     else
885         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
886
887     return rc;
888 }
889
890 UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
891 {
892     UINT rc;
893     WCHAR squished_pc[GUID_SIZE];
894     WCHAR keypath[0x200];
895
896     TRACE("%s\n",debugstr_w(szUpgradeCode));
897     if (!squash_guid(szUpgradeCode,squished_pc))
898         return ERROR_FUNCTION_FAILED;
899     TRACE("squished (%s)\n", debugstr_w(squished_pc));
900
901     sprintfW(keypath,szInstaller_UpgradeCodes_fmt,squished_pc);
902
903     if (create)
904         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
905     else
906         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
907
908     return rc;
909 }
910
911 UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
912 {
913     UINT rc;
914     WCHAR squished_pc[GUID_SIZE];
915     WCHAR keypath[0x200];
916
917     TRACE("%s\n",debugstr_w(szUpgradeCode));
918     if (!squash_guid(szUpgradeCode,squished_pc))
919         return ERROR_FUNCTION_FAILED;
920     TRACE("squished (%s)\n", debugstr_w(squished_pc));
921
922     sprintfW(keypath,szInstaller_UserUpgradeCodes_fmt,squished_pc);
923
924     if (create)
925         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
926     else
927         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
928
929     return rc;
930 }
931
932 UINT MSIREG_OpenLocalSystemProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
933 {
934     WCHAR squished_pc[GUID_SIZE];
935     WCHAR keypath[0x200];
936
937     TRACE("%s\n", debugstr_w(szProductCode));
938
939     if (!squash_guid(szProductCode, squished_pc))
940         return ERROR_FUNCTION_FAILED;
941
942     TRACE("squished (%s)\n", debugstr_w(squished_pc));
943
944     sprintfW(keypath, szInstaller_LocalSystemProductCodes_fmt, squished_pc);
945
946     if (create)
947         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
948
949     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
950 }
951
952 UINT MSIREG_OpenLocalSystemComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create)
953 {
954     WCHAR squished_pc[GUID_SIZE];
955     WCHAR keypath[0x200];
956
957     TRACE("%s\n", debugstr_w(szComponent));
958
959     if (!squash_guid(szComponent, squished_pc))
960         return ERROR_FUNCTION_FAILED;
961
962     TRACE("squished (%s)\n", debugstr_w(squished_pc));
963
964     sprintfW(keypath, szInstaller_LocalSystemComponent_fmt, squished_pc);
965
966     if (create)
967         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
968
969     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
970 }
971
972 UINT MSIREG_OpenLocalClassesProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
973 {
974     WCHAR squished_pc[GUID_SIZE];
975     WCHAR keypath[0x200];
976
977     TRACE("%s\n", debugstr_w(szProductCode));
978
979     if (!squash_guid(szProductCode, squished_pc))
980         return ERROR_FUNCTION_FAILED;
981
982     TRACE("squished (%s)\n", debugstr_w(squished_pc));
983
984     sprintfW(keypath, szInstaller_LocalClassesProd_fmt, squished_pc);
985
986     if (create)
987         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
988
989     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
990 }
991
992 UINT MSIREG_OpenLocalManagedProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
993 {
994     WCHAR squished_pc[GUID_SIZE];
995     WCHAR keypath[0x200];
996     LPWSTR usersid;
997     UINT r;
998
999     TRACE("%s\n", debugstr_w(szProductCode));
1000
1001     if (!squash_guid(szProductCode, squished_pc))
1002         return ERROR_FUNCTION_FAILED;
1003
1004     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1005
1006     r = get_user_sid(&usersid);
1007     if (r != ERROR_SUCCESS || !usersid)
1008     {
1009         ERR("Failed to retrieve user SID: %d\n", r);
1010         return r;
1011     }
1012
1013     sprintfW(keypath, szInstaller_LocalManagedProd_fmt, usersid, squished_pc);
1014     LocalFree(usersid);
1015
1016     if (create)
1017         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1018
1019     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1020 }
1021
1022 /*************************************************************************
1023  *  MsiDecomposeDescriptorW   [MSI.@]
1024  *
1025  * Decomposes an MSI descriptor into product, feature and component parts.
1026  * An MSI descriptor is a string of the form:
1027  *   [base 85 guid] [feature code] '>' [base 85 guid]
1028  *
1029  * PARAMS
1030  *   szDescriptor  [I]  the descriptor to decompose
1031  *   szProduct     [O]  buffer of MAX_FEATURE_CHARS+1 for the product guid
1032  *   szFeature     [O]  buffer of MAX_FEATURE_CHARS+1 for the feature code
1033  *   szComponent   [O]  buffer of MAX_FEATURE_CHARS+1 for the component guid
1034  *   pUsed         [O]  the length of the descriptor
1035  *
1036  * RETURNS
1037  *   ERROR_SUCCESS             if everything worked correctly
1038  *   ERROR_INVALID_PARAMETER   if the descriptor was invalid
1039  *
1040  */
1041 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
1042                 LPWSTR szFeature, LPWSTR szComponent, LPDWORD pUsed )
1043 {
1044     UINT r, len;
1045     LPWSTR p;
1046     GUID product, component;
1047
1048     TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
1049           szFeature, szComponent, pUsed);
1050
1051     r = decode_base85_guid( szDescriptor, &product );
1052     if( !r )
1053         return ERROR_INVALID_PARAMETER;
1054
1055     TRACE("product %s\n", debugstr_guid( &product ));
1056
1057     p = strchrW(&szDescriptor[20],'>');
1058     if( !p )
1059         return ERROR_INVALID_PARAMETER;
1060
1061     len = (p - &szDescriptor[20]);
1062     if( len > MAX_FEATURE_CHARS )
1063         return ERROR_INVALID_PARAMETER;
1064
1065     TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
1066
1067     r = decode_base85_guid( p+1, &component );
1068     if( !r )
1069         return ERROR_INVALID_PARAMETER;
1070
1071     TRACE("component %s\n", debugstr_guid( &component ));
1072
1073     if (szProduct)
1074         StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
1075     if (szComponent)
1076         StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
1077     if (szFeature)
1078     {
1079         memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
1080         szFeature[len] = 0;
1081     }
1082     len = ( &p[21] - szDescriptor );
1083
1084     TRACE("length = %d\n", len);
1085     *pUsed = len;
1086
1087     return ERROR_SUCCESS;
1088 }
1089
1090 UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
1091                 LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed )
1092 {
1093     WCHAR product[MAX_FEATURE_CHARS+1];
1094     WCHAR feature[MAX_FEATURE_CHARS+1];
1095     WCHAR component[MAX_FEATURE_CHARS+1];
1096     LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
1097     UINT r;
1098
1099     TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
1100           szFeature, szComponent, pUsed);
1101
1102     str = strdupAtoW( szDescriptor );
1103     if( szDescriptor && !str )
1104         return ERROR_OUTOFMEMORY;
1105
1106     if (szProduct)
1107         p = product;
1108     if (szFeature)
1109         f = feature;
1110     if (szComponent)
1111         c = component;
1112
1113     r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
1114
1115     if (r == ERROR_SUCCESS)
1116     {
1117         WideCharToMultiByte( CP_ACP, 0, p, -1,
1118                              szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
1119         WideCharToMultiByte( CP_ACP, 0, f, -1,
1120                              szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
1121         WideCharToMultiByte( CP_ACP, 0, c, -1,
1122                              szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
1123     }
1124
1125     msi_free( str );
1126
1127     return r;
1128 }
1129
1130 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
1131 {
1132     DWORD r;
1133     WCHAR szwGuid[GUID_SIZE];
1134
1135     TRACE("%d %p\n", index, lpguid);
1136
1137     if (NULL == lpguid)
1138         return ERROR_INVALID_PARAMETER;
1139     r = MsiEnumProductsW(index, szwGuid);
1140     if( r == ERROR_SUCCESS )
1141         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1142
1143     return r;
1144 }
1145
1146 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
1147 {
1148     HKEY hkeyProducts = 0;
1149     DWORD r;
1150     WCHAR szKeyName[SQUISH_GUID_SIZE];
1151
1152     TRACE("%d %p\n", index, lpguid);
1153
1154     if (NULL == lpguid)
1155         return ERROR_INVALID_PARAMETER;
1156
1157     r = RegCreateKeyW(HKEY_LOCAL_MACHINE, szInstaller_Products, &hkeyProducts);
1158     if( r != ERROR_SUCCESS )
1159         return ERROR_NO_MORE_ITEMS;
1160
1161     r = RegEnumKeyW(hkeyProducts, index, szKeyName, SQUISH_GUID_SIZE);
1162     if( r == ERROR_SUCCESS )
1163         unsquash_guid(szKeyName, lpguid);
1164     RegCloseKey(hkeyProducts);
1165
1166     return r;
1167 }
1168
1169 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, 
1170       LPSTR szFeature, LPSTR szParent)
1171 {
1172     DWORD r;
1173     WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
1174     LPWSTR szwProduct = NULL;
1175
1176     TRACE("%s %d %p %p\n", debugstr_a(szProduct), index, szFeature, szParent);
1177
1178     if( szProduct )
1179     {
1180         szwProduct = strdupAtoW( szProduct );
1181         if( !szwProduct )
1182             return ERROR_OUTOFMEMORY;
1183     }
1184
1185     r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
1186     if( r == ERROR_SUCCESS )
1187     {
1188         WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
1189                             szFeature, GUID_SIZE, NULL, NULL);
1190         WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
1191                             szParent, GUID_SIZE, NULL, NULL);
1192     }
1193
1194     msi_free( szwProduct);
1195
1196     return r;
1197 }
1198
1199 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, 
1200       LPWSTR szFeature, LPWSTR szParent)
1201 {
1202     HKEY hkeyProduct = 0;
1203     DWORD r, sz;
1204
1205     TRACE("%s %d %p %p\n", debugstr_w(szProduct), index, szFeature, szParent);
1206
1207     if( !szProduct )
1208         return ERROR_INVALID_PARAMETER;
1209
1210     r = MSIREG_OpenFeaturesKey(szProduct,&hkeyProduct,FALSE);
1211     if( r != ERROR_SUCCESS )
1212         return ERROR_NO_MORE_ITEMS;
1213
1214     sz = GUID_SIZE;
1215     r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
1216     RegCloseKey(hkeyProduct);
1217
1218     return r;
1219 }
1220
1221 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
1222 {
1223     DWORD r;
1224     WCHAR szwGuid[GUID_SIZE];
1225
1226     TRACE("%d %p\n", index, lpguid);
1227
1228     r = MsiEnumComponentsW(index, szwGuid);
1229     if( r == ERROR_SUCCESS )
1230         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1231
1232     return r;
1233 }
1234
1235 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
1236 {
1237     HKEY hkeyComponents = 0;
1238     DWORD r;
1239     WCHAR szKeyName[SQUISH_GUID_SIZE];
1240
1241     TRACE("%d %p\n", index, lpguid);
1242
1243     r = MSIREG_OpenComponents(&hkeyComponents);
1244     if( r != ERROR_SUCCESS )
1245         return ERROR_NO_MORE_ITEMS;
1246
1247     r = RegEnumKeyW(hkeyComponents, index, szKeyName, SQUISH_GUID_SIZE);
1248     if( r == ERROR_SUCCESS )
1249         unsquash_guid(szKeyName, lpguid);
1250     RegCloseKey(hkeyComponents);
1251
1252     return r;
1253 }
1254
1255 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
1256 {
1257     DWORD r;
1258     WCHAR szwProduct[GUID_SIZE];
1259     LPWSTR szwComponent = NULL;
1260
1261     TRACE("%s %d %p\n", debugstr_a(szComponent), index, szProduct);
1262
1263     if ( !szProduct )
1264         return ERROR_INVALID_PARAMETER;
1265
1266     if( szComponent )
1267     {
1268         szwComponent = strdupAtoW( szComponent );
1269         if( !szwComponent )
1270             return ERROR_OUTOFMEMORY;
1271     }
1272
1273     r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
1274     if( r == ERROR_SUCCESS )
1275     {
1276         WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
1277                             szProduct, GUID_SIZE, NULL, NULL);
1278     }
1279
1280     msi_free( szwComponent);
1281
1282     return r;
1283 }
1284
1285 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
1286 {
1287     HKEY hkeyComp = 0;
1288     DWORD r, sz;
1289     WCHAR szValName[SQUISH_GUID_SIZE];
1290
1291     TRACE("%s %d %p\n", debugstr_w(szComponent), index, szProduct);
1292
1293     if (!szComponent || !*szComponent || !szProduct)
1294         return ERROR_INVALID_PARAMETER;
1295
1296     if (MSIREG_OpenUserDataComponentKey(szComponent, &hkeyComp, FALSE) != ERROR_SUCCESS &&
1297         MSIREG_OpenLocalSystemComponentKey(szComponent, &hkeyComp, FALSE) != ERROR_SUCCESS)
1298         return ERROR_UNKNOWN_COMPONENT;
1299
1300     /* see if there are any products at all */
1301     sz = SQUISH_GUID_SIZE;
1302     r = RegEnumValueW(hkeyComp, 0, szValName, &sz, NULL, NULL, NULL, NULL);
1303     if (r != ERROR_SUCCESS)
1304     {
1305         RegCloseKey(hkeyComp);
1306
1307         if (index != 0)
1308             return ERROR_INVALID_PARAMETER;
1309
1310         return ERROR_UNKNOWN_COMPONENT;
1311     }
1312
1313     sz = SQUISH_GUID_SIZE;
1314     r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
1315     if( r == ERROR_SUCCESS )
1316         unsquash_guid(szValName, szProduct);
1317
1318     RegCloseKey(hkeyComp);
1319
1320     return r;
1321 }
1322
1323 static UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
1324                 awstring *lpQualBuf, LPDWORD pcchQual,
1325                 awstring *lpAppBuf, LPDWORD pcchAppBuf )
1326 {
1327     DWORD name_sz, val_sz, name_max, val_max, type, ofs;
1328     LPWSTR name = NULL, val = NULL;
1329     UINT r, r2;
1330     HKEY key;
1331
1332     TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1333           lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
1334
1335     if (!szComponent)
1336         return ERROR_INVALID_PARAMETER;
1337
1338     r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1339     if (r != ERROR_SUCCESS)
1340         return ERROR_UNKNOWN_COMPONENT;
1341
1342     /* figure out how big the name is we want to return */
1343     name_max = 0x10;
1344     r = ERROR_OUTOFMEMORY;
1345     name = msi_alloc( name_max * sizeof(WCHAR) );
1346     if (!name)
1347         goto end;
1348
1349     val_max = 0x10;
1350     r = ERROR_OUTOFMEMORY;
1351     val = msi_alloc( val_max );
1352     if (!val)
1353         goto end;
1354
1355     /* loop until we allocate enough memory */
1356     while (1)
1357     {
1358         name_sz = name_max;
1359         val_sz = val_max;
1360         r = RegEnumValueW( key, iIndex, name, &name_sz,
1361                            NULL, &type, (LPBYTE)val, &val_sz );
1362         if (r == ERROR_SUCCESS)
1363             break;
1364         if (r != ERROR_MORE_DATA)
1365             goto end;
1366  
1367         if (type != REG_MULTI_SZ)
1368         {
1369             ERR("component data has wrong type (%d)\n", type);
1370             goto end;
1371         }
1372
1373         r = ERROR_OUTOFMEMORY;
1374         if ((name_sz+1) >= name_max)
1375         {
1376             name_max *= 2;
1377             msi_free( name );
1378             name = msi_alloc( name_max * sizeof (WCHAR) );
1379             if (!name)
1380                 goto end;
1381             continue;
1382         }
1383         if (val_sz > val_max)
1384         {
1385             val_max = val_sz + sizeof (WCHAR);
1386             msi_free( val );
1387             val = msi_alloc( val_max * sizeof (WCHAR) );
1388             if (!val)
1389                 goto end;
1390             continue;
1391         }
1392         ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz );
1393         goto end;
1394     }
1395
1396     ofs = 0;
1397     r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1398     if (r != ERROR_SUCCESS)
1399         goto end;
1400
1401     TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1402
1403     r = msi_strcpy_to_awstring( name, lpQualBuf, pcchQual );
1404     r2 = msi_strcpy_to_awstring( val+ofs, lpAppBuf, pcchAppBuf );
1405
1406     if (r2 != ERROR_SUCCESS)
1407         r = r2;
1408
1409 end:
1410     msi_free(val);
1411     msi_free(name);
1412     RegCloseKey(key);
1413
1414     return r;
1415 }
1416
1417 /*************************************************************************
1418  *  MsiEnumComponentQualifiersA [MSI.@]
1419  */
1420 UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
1421                 LPSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1422                 LPSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1423 {
1424     awstring qual, appdata;
1425     LPWSTR comp;
1426     UINT r;
1427
1428     TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex,
1429           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1430           pcchApplicationDataBuf);
1431
1432     comp = strdupAtoW( szComponent );
1433     if (szComponent && !comp)
1434         return ERROR_OUTOFMEMORY;
1435
1436     qual.unicode = FALSE;
1437     qual.str.a = lpQualifierBuf;
1438
1439     appdata.unicode = FALSE;
1440     appdata.str.a = lpApplicationDataBuf;
1441
1442     r = MSI_EnumComponentQualifiers( comp, iIndex,
1443               &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1444     msi_free( comp );
1445     return r;
1446 }
1447
1448 /*************************************************************************
1449  *  MsiEnumComponentQualifiersW [MSI.@]
1450  */
1451 UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
1452                 LPWSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1453                 LPWSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1454 {
1455     awstring qual, appdata;
1456
1457     TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1458           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1459           pcchApplicationDataBuf);
1460
1461     qual.unicode = TRUE;
1462     qual.str.w = lpQualifierBuf;
1463
1464     appdata.unicode = TRUE;
1465     appdata.str.w = lpApplicationDataBuf;
1466
1467     return MSI_EnumComponentQualifiers( szComponent, iIndex,
1468                  &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1469 }
1470
1471 /*************************************************************************
1472  *  MsiEnumRelatedProductsW   [MSI.@]
1473  *
1474  */
1475 UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,
1476                                     DWORD iProductIndex, LPWSTR lpProductBuf)
1477 {
1478     UINT r;
1479     HKEY hkey;
1480     DWORD dwSize = SQUISH_GUID_SIZE;
1481     WCHAR szKeyName[SQUISH_GUID_SIZE];
1482
1483     TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved,
1484           iProductIndex, lpProductBuf);
1485
1486     if (NULL == szUpgradeCode)
1487         return ERROR_INVALID_PARAMETER;
1488     if (NULL == lpProductBuf)
1489         return ERROR_INVALID_PARAMETER;
1490
1491     r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1492     if (r != ERROR_SUCCESS)
1493         return ERROR_NO_MORE_ITEMS;
1494
1495     r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1496     if( r == ERROR_SUCCESS )
1497         unsquash_guid(szKeyName, lpProductBuf);
1498     RegCloseKey(hkey);
1499
1500     return r;
1501 }
1502
1503 /*************************************************************************
1504  *  MsiEnumRelatedProductsA   [MSI.@]
1505  *
1506  */
1507 UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
1508                                     DWORD iProductIndex, LPSTR lpProductBuf)
1509 {
1510     LPWSTR szwUpgradeCode = NULL;
1511     WCHAR productW[GUID_SIZE];
1512     UINT r;
1513
1514     TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved,
1515           iProductIndex, lpProductBuf);
1516
1517     if (szUpgradeCode)
1518     {
1519         szwUpgradeCode = strdupAtoW( szUpgradeCode );
1520         if( !szwUpgradeCode )
1521             return ERROR_OUTOFMEMORY;
1522     }
1523
1524     r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1525                                  iProductIndex, productW );
1526     if (r == ERROR_SUCCESS)
1527     {
1528         WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1529                              lpProductBuf, GUID_SIZE, NULL, NULL );
1530     }
1531     msi_free( szwUpgradeCode);
1532     return r;
1533 }
1534
1535 /***********************************************************************
1536  * MsiEnumPatchesA            [MSI.@]
1537  */
1538 UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex,
1539         LPSTR lpPatchBuf, LPSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
1540 {
1541     FIXME("%s %d %p %p %p\n", debugstr_a(szProduct),
1542           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1543     return ERROR_NO_MORE_ITEMS;
1544 }
1545
1546 /***********************************************************************
1547  * MsiEnumPatchesW            [MSI.@]
1548  */
1549 UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex,
1550         LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
1551 {
1552     FIXME("%s %d %p %p %p\n", debugstr_w(szProduct),
1553           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1554     return ERROR_NO_MORE_ITEMS;
1555 }
1556
1557 UINT WINAPI MsiEnumProductsExA( LPCSTR szProductCode, LPCSTR szUserSid,
1558         DWORD dwContext, DWORD dwIndex, CHAR szInstalledProductCode[39],
1559         MSIINSTALLCONTEXT* pdwInstalledContext, LPSTR szSid, LPDWORD pcchSid)
1560 {
1561     FIXME("%s %s %d %d %p %p %p %p\n", debugstr_a(szProductCode), debugstr_a(szUserSid),
1562           dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
1563           szSid, pcchSid);
1564     return ERROR_NO_MORE_ITEMS;
1565 }
1566
1567 UINT WINAPI MsiEnumProductsExW( LPCWSTR szProductCode, LPCWSTR szUserSid,
1568         DWORD dwContext, DWORD dwIndex, WCHAR szInstalledProductCode[39],
1569         MSIINSTALLCONTEXT* pdwInstalledContext, LPWSTR szSid, LPDWORD pcchSid)
1570 {
1571     FIXME("%s %s %d %d %p %p %p %p\n", debugstr_w(szProductCode), debugstr_w(szUserSid),
1572           dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
1573           szSid, pcchSid);
1574     return ERROR_NO_MORE_ITEMS;
1575 }