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