push 4764fdcba48f6a6df3263056e605233f2bb574ff
[wine/hacks.git] / dlls / msi / registry.c
blob6aedc711130b80e0eb95ecb7a3aefa7db576ece0
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2005 Mike McCormack for CodeWeavers
5 * Copyright 2005 Aric Stewart for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
24 #define COBJMACROS
25 #define NONAMELESSUNION
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"
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
44 /*
45 * This module will be all the helper functions for registry access by the
46 * installer bits.
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};
55 static const WCHAR szInstaller_Features[] = {
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 'F','e','a','t','u','r','e','s',0 };
63 static const WCHAR szUserDataFeatures_fmt[] = {
64 'S','o','f','t','w','a','r','e','\\',
65 'M','i','c','r','o','s','o','f','t','\\',
66 'W','i','n','d','o','w','s','\\',
67 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
68 'I','n','s','t','a','l','l','e','r','\\',
69 'U','s','e','r','D','a','t','a','\\',
70 '%','s','\\','P','r','o','d','u','c','t','s','\\',
71 '%','s','\\','F','e','a','t','u','r','e','s',0};
73 static const WCHAR szInstaller_Features_fmt[] = {
74 'S','o','f','t','w','a','r','e','\\',
75 'M','i','c','r','o','s','o','f','t','\\',
76 'W','i','n','d','o','w','s','\\',
77 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
78 'I','n','s','t','a','l','l','e','r','\\',
79 'F','e','a','t','u','r','e','s','\\',
80 '%','s',0};
82 static const WCHAR szInstaller_Components[] = {
83 'S','o','f','t','w','a','r','e','\\',
84 'M','i','c','r','o','s','o','f','t','\\',
85 'W','i','n','d','o','w','s','\\',
86 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
87 'I','n','s','t','a','l','l','e','r','\\',
88 'C','o','m','p','o','n','e','n','t','s',0 };
90 static const WCHAR szInstaller_Components_fmt[] = {
91 'S','o','f','t','w','a','r','e','\\',
92 'M','i','c','r','o','s','o','f','t','\\',
93 'W','i','n','d','o','w','s','\\',
94 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
95 'I','n','s','t','a','l','l','e','r','\\',
96 'C','o','m','p','o','n','e','n','t','s','\\',
97 '%','s',0};
99 static const WCHAR szUser_Components_fmt[] = {
100 'S','o','f','t','w','a','r','e','\\',
101 'M','i','c','r','o','s','o','f','t','\\',
102 'I','n','s','t','a','l','l','e','r','\\',
103 'C','o','m','p','o','n','e','n','t','s','\\',
104 '%','s',0};
106 static const WCHAR szUserDataComp_fmt[] = {
107 'S','o','f','t','w','a','r','e','\\',
108 'M','i','c','r','o','s','o','f','t','\\',
109 'W','i','n','d','o','w','s','\\',
110 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
111 'I','n','s','t','a','l','l','e','r','\\',
112 'U','s','e','r','D','a','t','a','\\',
113 '%','s','\\','C','o','m','p','o','n','e','n','t','s','\\','%','s',0};
115 static const WCHAR szUninstall_fmt[] = {
116 'S','o','f','t','w','a','r','e','\\',
117 'M','i','c','r','o','s','o','f','t','\\',
118 'W','i','n','d','o','w','s','\\',
119 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
120 'U','n','i','n','s','t','a','l','l','\\',
121 '%','s',0 };
123 static const WCHAR szUserProduct_fmt[] = {
124 'S','o','f','t','w','a','r','e','\\',
125 'M','i','c','r','o','s','o','f','t','\\',
126 'I','n','s','t','a','l','l','e','r','\\',
127 'P','r','o','d','u','c','t','s','\\',
128 '%','s',0};
130 static const WCHAR szUserPatch_fmt[] = {
131 'S','o','f','t','w','a','r','e','\\',
132 'M','i','c','r','o','s','o','f','t','\\',
133 'I','n','s','t','a','l','l','e','r','\\',
134 'P','a','t','c','h','e','s','\\',
135 '%','s',0};
137 static const WCHAR szInstaller_Products[] = {
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','r','o','d','u','c','t','s',0};
145 static const WCHAR szInstaller_Products_fmt[] = {
146 'S','o','f','t','w','a','r','e','\\',
147 'M','i','c','r','o','s','o','f','t','\\',
148 'W','i','n','d','o','w','s','\\',
149 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
150 'I','n','s','t','a','l','l','e','r','\\',
151 'P','r','o','d','u','c','t','s','\\',
152 '%','s',0};
154 static const WCHAR szInstaller_Patches_fmt[] = {
155 'S','o','f','t','w','a','r','e','\\',
156 'M','i','c','r','o','s','o','f','t','\\',
157 'W','i','n','d','o','w','s','\\',
158 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
159 'I','n','s','t','a','l','l','e','r','\\',
160 'P','a','t','c','h','e','s','\\',
161 '%','s',0};
163 static const WCHAR szInstaller_UpgradeCodes_fmt[] = {
164 'S','o','f','t','w','a','r','e','\\',
165 'M','i','c','r','o','s','o','f','t','\\',
166 'W','i','n','d','o','w','s','\\',
167 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
168 'I','n','s','t','a','l','l','e','r','\\',
169 'U','p','g','r','a','d','e','C','o','d','e','s','\\',
170 '%','s',0};
172 static const WCHAR szInstaller_UserUpgradeCodes_fmt[] = {
173 'S','o','f','t','w','a','r','e','\\',
174 'M','i','c','r','o','s','o','f','t','\\',
175 'I','n','s','t','a','l','l','e','r','\\',
176 'U','p','g','r','a','d','e','C','o','d','e','s','\\',
177 '%','s',0};
179 static const WCHAR szUserDataProd_fmt[] = {
180 'S','o','f','t','w','a','r','e','\\',
181 'M','i','c','r','o','s','o','f','t','\\',
182 'W','i','n','d','o','w','s','\\',
183 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
184 'I','n','s','t','a','l','l','e','r','\\',
185 'U','s','e','r','D','a','t','a','\\',
186 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s',0};
188 static const WCHAR szInstallProperties_fmt[] = {
189 'S','o','f','t','w','a','r','e','\\',
190 'M','i','c','r','o','s','o','f','t','\\',
191 'W','i','n','d','o','w','s','\\',
192 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
193 'I','n','s','t','a','l','l','e','r','\\',
194 'U','s','e','r','D','a','t','a','\\',
195 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\',
196 'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
199 #define SQUISH_GUID_SIZE 33
201 BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
203 DWORD i,n=0;
205 out[n++]='{';
206 for(i=0; i<8; i++)
207 out[n++] = in[7-i];
208 out[n++]='-';
209 for(i=0; i<4; i++)
210 out[n++] = in[11-i];
211 out[n++]='-';
212 for(i=0; i<4; i++)
213 out[n++] = in[15-i];
214 out[n++]='-';
215 for(i=0; i<2; i++)
217 out[n++] = in[17+i*2];
218 out[n++] = in[16+i*2];
220 out[n++]='-';
221 for( ; i<8; i++)
223 out[n++] = in[17+i*2];
224 out[n++] = in[16+i*2];
226 out[n++]='}';
227 out[n]=0;
228 return TRUE;
231 BOOL squash_guid(LPCWSTR in, LPWSTR out)
233 DWORD i,n=1;
234 GUID guid;
236 out[0] = 0;
238 if (FAILED(CLSIDFromString((LPOLESTR)in, &guid)))
239 return FALSE;
241 for(i=0; i<8; i++)
242 out[7-i] = in[n++];
243 n++;
244 for(i=0; i<4; i++)
245 out[11-i] = in[n++];
246 n++;
247 for(i=0; i<4; i++)
248 out[15-i] = in[n++];
249 n++;
250 for(i=0; i<2; i++)
252 out[17+i*2] = in[n++];
253 out[16+i*2] = in[n++];
255 n++;
256 for( ; i<8; i++)
258 out[17+i*2] = in[n++];
259 out[16+i*2] = in[n++];
261 out[32]=0;
262 return TRUE;
266 /* tables for encoding and decoding base85 */
267 static const unsigned char table_dec85[0x80] = {
268 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
269 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
270 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
271 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
272 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
273 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
274 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
275 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
278 static const char table_enc85[] =
279 "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
280 "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
281 "yz{}~";
284 * Converts a base85 encoded guid into a GUID pointer
285 * Base85 encoded GUIDs should be 20 characters long.
287 * returns TRUE if successful, FALSE if not
289 BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
291 DWORD i, val = 0, base = 1, *p;
293 if (!str)
294 return FALSE;
296 p = (DWORD*) guid;
297 for( i=0; i<20; i++ )
299 if( (i%5) == 0 )
301 val = 0;
302 base = 1;
304 val += table_dec85[str[i]] * base;
305 if( str[i] >= 0x80 )
306 return FALSE;
307 if( table_dec85[str[i]] == 0xff )
308 return FALSE;
309 if( (i%5) == 4 )
310 p[i/5] = val;
311 base *= 85;
313 return TRUE;
317 * Encodes a base85 guid given a GUID pointer
318 * Caller should provide a 21 character buffer for the encoded string.
320 * returns TRUE if successful, FALSE if not
322 BOOL encode_base85_guid( GUID *guid, LPWSTR str )
324 unsigned int x, *p, i;
326 p = (unsigned int*) guid;
327 for( i=0; i<4; i++ )
329 x = p[i];
330 *str++ = table_enc85[x%85];
331 x = x/85;
332 *str++ = table_enc85[x%85];
333 x = x/85;
334 *str++ = table_enc85[x%85];
335 x = x/85;
336 *str++ = table_enc85[x%85];
337 x = x/85;
338 *str++ = table_enc85[x%85];
340 *str = 0;
342 return TRUE;
345 DWORD msi_version_str_to_dword(LPCWSTR p)
347 DWORD major, minor = 0, build = 0, version = 0;
349 if (!p)
350 return version;
352 major = atoiW(p);
354 p = strchrW(p, '.');
355 if (p)
357 minor = atoiW(p+1);
358 p = strchrW(p+1, '.');
359 if (p)
360 build = atoiW(p+1);
363 return MAKELONG(build, MAKEWORD(minor, major));
366 LPWSTR msi_version_dword_to_str(DWORD version)
368 const WCHAR fmt[] = { '%','u','.','%','u','.','%','u',0 };
369 LPWSTR str = msi_alloc(20);
370 sprintfW(str, fmt,
371 (version&0xff000000)>>24,
372 (version&0x00ff0000)>>16,
373 version&0x0000ffff);
374 return str;
377 LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
379 DWORD len = value ? (lstrlenW(value) + 1) * sizeof (WCHAR) : 0;
380 return RegSetValueExW( hkey, name, 0, REG_SZ, (const BYTE *)value, len );
383 LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
385 LPCWSTR p = value;
386 while (*p) p += lstrlenW(p) + 1;
387 return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
388 (const BYTE *)value, (p + 1 - value) * sizeof(WCHAR) );
391 LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
393 return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
396 LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
398 HKEY hsubkey = 0;
399 LONG r;
401 r = RegCreateKeyW( hkey, path, &hsubkey );
402 if (r != ERROR_SUCCESS)
403 return r;
404 r = msi_reg_set_val_str( hsubkey, name, val );
405 RegCloseKey( hsubkey );
406 return r;
409 LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name )
411 DWORD len = 0;
412 LPWSTR val;
413 LONG r;
415 r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len);
416 if (r != ERROR_SUCCESS)
417 return NULL;
419 len += sizeof (WCHAR);
420 val = msi_alloc( len );
421 if (!val)
422 return NULL;
423 val[0] = 0;
424 RegQueryValueExW(hkey, name, NULL, NULL, (LPBYTE) val, &len);
425 return val;
428 BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val)
430 DWORD type, len = sizeof (DWORD);
431 LONG r = RegQueryValueExW(hkey, name, NULL, &type, (LPBYTE) val, &len);
432 return r == ERROR_SUCCESS && type == REG_DWORD;
435 static UINT get_user_sid(LPWSTR *usersid)
437 HANDLE token;
438 BYTE buf[1024];
439 DWORD size;
440 PTOKEN_USER user;
442 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
443 return ERROR_FUNCTION_FAILED;
445 size = sizeof(buf);
446 if (!GetTokenInformation(token, TokenUser, (void *)buf, size, &size))
447 return ERROR_FUNCTION_FAILED;
449 user = (PTOKEN_USER)buf;
450 if (!ConvertSidToStringSidW(user->User.Sid, usersid))
451 return ERROR_FUNCTION_FAILED;
453 return ERROR_SUCCESS;
456 UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create)
458 UINT rc;
459 WCHAR keypath[0x200];
460 TRACE("%s\n",debugstr_w(szProduct));
462 sprintfW(keypath,szUninstall_fmt,szProduct);
464 if (create)
465 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
466 else
467 rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
469 return rc;
472 UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create)
474 UINT rc;
475 WCHAR squished_pc[GUID_SIZE];
476 WCHAR keypath[0x200];
478 TRACE("%s\n",debugstr_w(szProduct));
479 if (!squash_guid(szProduct,squished_pc))
480 return ERROR_FUNCTION_FAILED;
481 TRACE("squished (%s)\n", debugstr_w(squished_pc));
483 sprintfW(keypath,szUserProduct_fmt,squished_pc);
485 if (create)
486 rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
487 else
488 rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
490 return rc;
493 UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
495 WCHAR squished_pc[GUID_SIZE];
496 WCHAR keypath[0x200];
498 TRACE("%s\n",debugstr_w(szProduct));
499 if (!squash_guid(szProduct,squished_pc))
500 return ERROR_FUNCTION_FAILED;
501 TRACE("squished (%s)\n", debugstr_w(squished_pc));
503 sprintfW(keypath,szUserProduct_fmt,squished_pc);
505 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
508 UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create)
510 UINT rc;
511 WCHAR squished_pc[GUID_SIZE];
512 WCHAR keypath[0x200];
514 TRACE("%s\n",debugstr_w(szPatch));
515 if (!squash_guid(szPatch,squished_pc))
516 return ERROR_FUNCTION_FAILED;
517 TRACE("squished (%s)\n", debugstr_w(squished_pc));
519 sprintfW(keypath,szUserPatch_fmt,squished_pc);
521 if (create)
522 rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
523 else
524 rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
526 return rc;
529 UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create)
531 UINT rc;
532 WCHAR squished_pc[GUID_SIZE];
533 WCHAR keypath[0x200];
535 TRACE("%s\n",debugstr_w(szProduct));
536 if (!squash_guid(szProduct,squished_pc))
537 return ERROR_FUNCTION_FAILED;
538 TRACE("squished (%s)\n", debugstr_w(squished_pc));
540 sprintfW(keypath,szUserFeatures_fmt,squished_pc);
542 if (create)
543 rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
544 else
545 rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
547 return rc;
550 UINT MSIREG_OpenFeatures(HKEY* key)
552 return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Features,key);
555 UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create)
557 UINT rc;
558 WCHAR squished_pc[GUID_SIZE];
559 WCHAR keypath[0x200];
561 TRACE("%s\n",debugstr_w(szProduct));
562 if (!squash_guid(szProduct,squished_pc))
563 return ERROR_FUNCTION_FAILED;
564 TRACE("squished (%s)\n", debugstr_w(squished_pc));
566 sprintfW(keypath,szInstaller_Features_fmt,squished_pc);
568 if (create)
569 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
570 else
571 rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
573 return rc;
576 UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
578 UINT rc;
579 WCHAR squished_pc[GUID_SIZE];
580 WCHAR keypath[0x200];
581 LPWSTR usersid;
583 TRACE("%s\n", debugstr_w(szProduct));
584 if (!squash_guid(szProduct, squished_pc))
585 return ERROR_FUNCTION_FAILED;
586 TRACE("squished (%s)\n", debugstr_w(squished_pc));
588 rc = get_user_sid(&usersid);
589 if (rc != ERROR_SUCCESS || !usersid)
591 ERR("Failed to retrieve user SID: %d\n", rc);
592 return rc;
595 sprintfW(keypath, szUserDataFeatures_fmt, usersid, squished_pc);
597 if (create)
598 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
599 else
600 rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
602 msi_free(usersid);
603 return rc;
606 UINT MSIREG_OpenComponents(HKEY* key)
608 return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Components,key);
611 UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create)
613 UINT rc;
614 WCHAR squished_cc[GUID_SIZE];
615 WCHAR keypath[0x200];
617 TRACE("%s\n",debugstr_w(szComponent));
618 if (!squash_guid(szComponent,squished_cc))
619 return ERROR_FUNCTION_FAILED;
620 TRACE("squished (%s)\n", debugstr_w(squished_cc));
622 sprintfW(keypath,szInstaller_Components_fmt,squished_cc);
624 if (create)
625 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
626 else
627 rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
629 return rc;
632 UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create)
634 UINT rc;
635 WCHAR squished_cc[GUID_SIZE];
636 WCHAR keypath[0x200];
638 TRACE("%s\n",debugstr_w(szComponent));
639 if (!squash_guid(szComponent,squished_cc))
640 return ERROR_FUNCTION_FAILED;
641 TRACE("squished (%s)\n", debugstr_w(squished_cc));
643 sprintfW(keypath,szUser_Components_fmt,squished_cc);
645 if (create)
646 rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
647 else
648 rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
650 return rc;
653 UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create)
655 UINT rc;
656 WCHAR comp[GUID_SIZE];
657 WCHAR keypath[0x200];
658 LPWSTR usersid;
660 TRACE("%s\n", debugstr_w(szComponent));
661 if (!squash_guid(szComponent, comp))
662 return ERROR_FUNCTION_FAILED;
663 TRACE("squished (%s)\n", debugstr_w(comp));
665 rc = get_user_sid(&usersid);
666 if (rc != ERROR_SUCCESS || !usersid)
668 ERR("Failed to retrieve user SID: %d\n", rc);
669 return rc;
672 sprintfW(keypath, szUserDataComp_fmt, usersid, comp);
674 if (create)
675 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
676 else
677 rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
679 msi_free(usersid);
680 return rc;
683 UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, HKEY *key, BOOL create)
685 UINT rc;
686 WCHAR squished_pc[GUID_SIZE];
687 WCHAR keypath[0x200];
688 LPWSTR usersid;
690 TRACE("%s\n", debugstr_w(szProduct));
691 if (!squash_guid(szProduct, squished_pc))
692 return ERROR_FUNCTION_FAILED;
693 TRACE("squished (%s)\n", debugstr_w(squished_pc));
695 rc = get_user_sid(&usersid);
696 if (rc != ERROR_SUCCESS || !usersid)
698 ERR("Failed to retrieve user SID: %d\n", rc);
699 return rc;
702 sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc);
704 if (create)
705 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
706 else
707 rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
709 msi_free(usersid);
710 return rc;
713 UINT MSIREG_OpenInstallPropertiesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
715 UINT rc;
716 WCHAR squished_pc[GUID_SIZE];
717 WCHAR keypath[0x200];
718 LPWSTR usersid;
720 TRACE("%s\n", debugstr_w(szProduct));
721 if (!squash_guid(szProduct, squished_pc))
722 return ERROR_FUNCTION_FAILED;
723 TRACE("squished (%s)\n", debugstr_w(squished_pc));
725 rc = get_user_sid(&usersid);
726 if (rc != ERROR_SUCCESS || !usersid)
728 ERR("Failed to retrieve user SID: %d\n", rc);
729 return rc;
732 sprintfW(keypath, szInstallProperties_fmt, usersid, squished_pc);
734 if (create)
735 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
736 else
737 rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
739 msi_free(usersid);
740 return rc;
743 UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct)
745 UINT rc;
746 WCHAR squished_pc[GUID_SIZE];
747 WCHAR keypath[0x200];
748 LPWSTR usersid;
750 TRACE("%s\n", debugstr_w(szProduct));
751 if (!squash_guid(szProduct, squished_pc))
752 return ERROR_FUNCTION_FAILED;
753 TRACE("squished (%s)\n", debugstr_w(squished_pc));
755 rc = get_user_sid(&usersid);
756 if (rc != ERROR_SUCCESS || !usersid)
758 ERR("Failed to retrieve user SID: %d\n", rc);
759 return rc;
762 sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc);
764 msi_free(usersid);
765 return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
768 UINT MSIREG_OpenProducts(HKEY* key)
770 return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Products,key);
773 UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create)
775 UINT rc;
776 WCHAR squished_pc[GUID_SIZE];
777 WCHAR keypath[0x200];
779 TRACE("%s\n",debugstr_w(szProduct));
780 if (!squash_guid(szProduct,squished_pc))
781 return ERROR_FUNCTION_FAILED;
782 TRACE("squished (%s)\n", debugstr_w(squished_pc));
784 sprintfW(keypath,szInstaller_Products_fmt,squished_pc);
786 if (create)
787 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
788 else
789 rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
791 return rc;
794 UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
796 WCHAR squished_pc[GUID_SIZE];
797 WCHAR keypath[0x200];
799 TRACE("%s\n", debugstr_w(szProduct));
800 if (!squash_guid(szProduct, squished_pc))
801 return ERROR_FUNCTION_FAILED;
802 TRACE("squished (%s)\n", debugstr_w(squished_pc));
804 sprintfW(keypath, szInstaller_Products_fmt, squished_pc);
806 return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
809 UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create)
811 UINT rc;
812 WCHAR squished_pc[GUID_SIZE];
813 WCHAR keypath[0x200];
815 TRACE("%s\n",debugstr_w(szPatch));
816 if (!squash_guid(szPatch,squished_pc))
817 return ERROR_FUNCTION_FAILED;
818 TRACE("squished (%s)\n", debugstr_w(squished_pc));
820 sprintfW(keypath,szInstaller_Patches_fmt,squished_pc);
822 if (create)
823 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
824 else
825 rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
827 return rc;
830 UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
832 UINT rc;
833 WCHAR squished_pc[GUID_SIZE];
834 WCHAR keypath[0x200];
836 TRACE("%s\n",debugstr_w(szUpgradeCode));
837 if (!squash_guid(szUpgradeCode,squished_pc))
838 return ERROR_FUNCTION_FAILED;
839 TRACE("squished (%s)\n", debugstr_w(squished_pc));
841 sprintfW(keypath,szInstaller_UpgradeCodes_fmt,squished_pc);
843 if (create)
844 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
845 else
846 rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
848 return rc;
851 UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
853 UINT rc;
854 WCHAR squished_pc[GUID_SIZE];
855 WCHAR keypath[0x200];
857 TRACE("%s\n",debugstr_w(szUpgradeCode));
858 if (!squash_guid(szUpgradeCode,squished_pc))
859 return ERROR_FUNCTION_FAILED;
860 TRACE("squished (%s)\n", debugstr_w(squished_pc));
862 sprintfW(keypath,szInstaller_UserUpgradeCodes_fmt,squished_pc);
864 if (create)
865 rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
866 else
867 rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
869 return rc;
873 /*************************************************************************
874 * MsiDecomposeDescriptorW [MSI.@]
876 * Decomposes an MSI descriptor into product, feature and component parts.
877 * An MSI descriptor is a string of the form:
878 * [base 85 guid] [feature code] '>' [base 85 guid]
880 * PARAMS
881 * szDescriptor [I] the descriptor to decompose
882 * szProduct [O] buffer of MAX_FEATURE_CHARS+1 for the product guid
883 * szFeature [O] buffer of MAX_FEATURE_CHARS+1 for the feature code
884 * szComponent [O] buffer of MAX_FEATURE_CHARS+1 for the component guid
885 * pUsed [O] the length of the descriptor
887 * RETURNS
888 * ERROR_SUCCESS if everything worked correctly
889 * ERROR_INVALID_PARAMETER if the descriptor was invalid
892 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
893 LPWSTR szFeature, LPWSTR szComponent, DWORD *pUsed )
895 UINT r, len;
896 LPWSTR p;
897 GUID product, component;
899 TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
900 szFeature, szComponent, pUsed);
902 r = decode_base85_guid( szDescriptor, &product );
903 if( !r )
904 return ERROR_INVALID_PARAMETER;
906 TRACE("product %s\n", debugstr_guid( &product ));
908 p = strchrW(&szDescriptor[20],'>');
909 if( !p )
910 return ERROR_INVALID_PARAMETER;
912 len = (p - &szDescriptor[20]);
913 if( len > MAX_FEATURE_CHARS )
914 return ERROR_INVALID_PARAMETER;
916 TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
918 r = decode_base85_guid( p+1, &component );
919 if( !r )
920 return ERROR_INVALID_PARAMETER;
922 TRACE("component %s\n", debugstr_guid( &component ));
924 if (szProduct)
925 StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
926 if (szComponent)
927 StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
928 if (szFeature)
930 memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
931 szFeature[len] = 0;
933 len = ( &p[21] - szDescriptor );
935 TRACE("length = %d\n", len);
936 *pUsed = len;
938 return ERROR_SUCCESS;
941 UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
942 LPSTR szFeature, LPSTR szComponent, DWORD *pUsed )
944 WCHAR product[MAX_FEATURE_CHARS+1];
945 WCHAR feature[MAX_FEATURE_CHARS+1];
946 WCHAR component[MAX_FEATURE_CHARS+1];
947 LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
948 UINT r;
950 TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
951 szFeature, szComponent, pUsed);
953 str = strdupAtoW( szDescriptor );
954 if( szDescriptor && !str )
955 return ERROR_OUTOFMEMORY;
957 if (szProduct)
958 p = product;
959 if (szFeature)
960 f = feature;
961 if (szComponent)
962 c = component;
964 r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
966 if (r == ERROR_SUCCESS)
968 WideCharToMultiByte( CP_ACP, 0, p, -1,
969 szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
970 WideCharToMultiByte( CP_ACP, 0, f, -1,
971 szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
972 WideCharToMultiByte( CP_ACP, 0, c, -1,
973 szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
976 msi_free( str );
978 return r;
981 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
983 DWORD r;
984 WCHAR szwGuid[GUID_SIZE];
986 TRACE("%d %p\n", index, lpguid);
988 if (NULL == lpguid)
989 return ERROR_INVALID_PARAMETER;
990 r = MsiEnumProductsW(index, szwGuid);
991 if( r == ERROR_SUCCESS )
992 WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
994 return r;
997 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
999 HKEY hkeyProducts = 0;
1000 DWORD r;
1001 WCHAR szKeyName[SQUISH_GUID_SIZE];
1003 TRACE("%d %p\n", index, lpguid);
1005 if (NULL == lpguid)
1006 return ERROR_INVALID_PARAMETER;
1008 r = MSIREG_OpenProducts(&hkeyProducts);
1009 if( r != ERROR_SUCCESS )
1010 return ERROR_NO_MORE_ITEMS;
1012 r = RegEnumKeyW(hkeyProducts, index, szKeyName, SQUISH_GUID_SIZE);
1013 if( r == ERROR_SUCCESS )
1014 unsquash_guid(szKeyName, lpguid);
1015 RegCloseKey(hkeyProducts);
1017 return r;
1020 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index,
1021 LPSTR szFeature, LPSTR szParent)
1023 DWORD r;
1024 WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
1025 LPWSTR szwProduct = NULL;
1027 TRACE("%s %d %p %p\n", debugstr_a(szProduct), index, szFeature, szParent);
1029 if( szProduct )
1031 szwProduct = strdupAtoW( szProduct );
1032 if( !szwProduct )
1033 return ERROR_OUTOFMEMORY;
1036 r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
1037 if( r == ERROR_SUCCESS )
1039 WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
1040 szFeature, GUID_SIZE, NULL, NULL);
1041 WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
1042 szParent, GUID_SIZE, NULL, NULL);
1045 msi_free( szwProduct);
1047 return r;
1050 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index,
1051 LPWSTR szFeature, LPWSTR szParent)
1053 HKEY hkeyProduct = 0;
1054 DWORD r, sz;
1056 TRACE("%s %d %p %p\n", debugstr_w(szProduct), index, szFeature, szParent);
1058 if( !szProduct )
1059 return ERROR_INVALID_PARAMETER;
1061 r = MSIREG_OpenFeaturesKey(szProduct,&hkeyProduct,FALSE);
1062 if( r != ERROR_SUCCESS )
1063 return ERROR_NO_MORE_ITEMS;
1065 sz = GUID_SIZE;
1066 r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
1067 RegCloseKey(hkeyProduct);
1069 return r;
1072 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
1074 DWORD r;
1075 WCHAR szwGuid[GUID_SIZE];
1077 TRACE("%d %p\n", index, lpguid);
1079 r = MsiEnumComponentsW(index, szwGuid);
1080 if( r == ERROR_SUCCESS )
1081 WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1083 return r;
1086 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
1088 HKEY hkeyComponents = 0;
1089 DWORD r;
1090 WCHAR szKeyName[SQUISH_GUID_SIZE];
1092 TRACE("%d %p\n", index, lpguid);
1094 r = MSIREG_OpenComponents(&hkeyComponents);
1095 if( r != ERROR_SUCCESS )
1096 return ERROR_NO_MORE_ITEMS;
1098 r = RegEnumKeyW(hkeyComponents, index, szKeyName, SQUISH_GUID_SIZE);
1099 if( r == ERROR_SUCCESS )
1100 unsquash_guid(szKeyName, lpguid);
1101 RegCloseKey(hkeyComponents);
1103 return r;
1106 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
1108 DWORD r;
1109 WCHAR szwProduct[GUID_SIZE];
1110 LPWSTR szwComponent = NULL;
1112 TRACE("%s %d %p\n", debugstr_a(szComponent), index, szProduct);
1114 if( szComponent )
1116 szwComponent = strdupAtoW( szComponent );
1117 if( !szwComponent )
1118 return ERROR_OUTOFMEMORY;
1121 r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
1122 if( r == ERROR_SUCCESS )
1124 WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
1125 szProduct, GUID_SIZE, NULL, NULL);
1128 msi_free( szwComponent);
1130 return r;
1133 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
1135 HKEY hkeyComp = 0;
1136 DWORD r, sz;
1137 WCHAR szValName[SQUISH_GUID_SIZE];
1139 TRACE("%s %d %p\n", debugstr_w(szComponent), index, szProduct);
1141 r = MSIREG_OpenComponentsKey(szComponent,&hkeyComp,FALSE);
1142 if( r != ERROR_SUCCESS )
1143 return ERROR_NO_MORE_ITEMS;
1145 sz = SQUISH_GUID_SIZE;
1146 r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
1147 if( r == ERROR_SUCCESS )
1148 unsquash_guid(szValName, szProduct);
1150 RegCloseKey(hkeyComp);
1152 return r;
1155 static UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
1156 awstring *lpQualBuf, DWORD* pcchQual,
1157 awstring *lpAppBuf, DWORD* pcchAppBuf )
1159 DWORD name_sz, val_sz, name_max, val_max, type, ofs;
1160 LPWSTR name = NULL, val = NULL;
1161 UINT r, r2;
1162 HKEY key;
1164 TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1165 lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
1167 if (!szComponent)
1168 return ERROR_INVALID_PARAMETER;
1170 r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1171 if (r != ERROR_SUCCESS)
1172 return ERROR_UNKNOWN_COMPONENT;
1174 /* figure out how big the name is we want to return */
1175 name_max = 0x10;
1176 r = ERROR_OUTOFMEMORY;
1177 name = msi_alloc( name_max * sizeof(WCHAR) );
1178 if (!name)
1179 goto end;
1181 val_max = 0x10;
1182 r = ERROR_OUTOFMEMORY;
1183 val = msi_alloc( val_max );
1184 if (!val)
1185 goto end;
1187 /* loop until we allocate enough memory */
1188 while (1)
1190 name_sz = name_max;
1191 val_sz = val_max;
1192 r = RegEnumValueW( key, iIndex, name, &name_sz,
1193 NULL, &type, (LPBYTE)val, &val_sz );
1194 if (r == ERROR_SUCCESS)
1195 break;
1196 if (r != ERROR_MORE_DATA)
1197 goto end;
1199 if (type != REG_MULTI_SZ)
1201 ERR("component data has wrong type (%d)\n", type);
1202 goto end;
1205 r = ERROR_OUTOFMEMORY;
1206 if ((name_sz+1) >= name_max)
1208 name_max *= 2;
1209 msi_free( name );
1210 name = msi_alloc( name_max * sizeof (WCHAR) );
1211 if (!name)
1212 goto end;
1213 continue;
1215 if (val_sz > val_max)
1217 val_max = val_sz + sizeof (WCHAR);
1218 msi_free( val );
1219 val = msi_alloc( val_max * sizeof (WCHAR) );
1220 if (!val)
1221 goto end;
1222 continue;
1224 ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz );
1225 goto end;
1228 ofs = 0;
1229 r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1230 if (r != ERROR_SUCCESS)
1231 goto end;
1233 TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1235 r = msi_strcpy_to_awstring( name, lpQualBuf, pcchQual );
1236 r2 = msi_strcpy_to_awstring( val+ofs, lpAppBuf, pcchAppBuf );
1238 if (r2 != ERROR_SUCCESS)
1239 r = r2;
1241 end:
1242 msi_free(val);
1243 msi_free(name);
1244 RegCloseKey(key);
1246 return r;
1249 /*************************************************************************
1250 * MsiEnumComponentQualifiersA [MSI.@]
1252 UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
1253 LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf,
1254 LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf )
1256 awstring qual, appdata;
1257 LPWSTR comp;
1258 UINT r;
1260 TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex,
1261 lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1262 pcchApplicationDataBuf);
1264 comp = strdupAtoW( szComponent );
1265 if (szComponent && !comp)
1266 return ERROR_OUTOFMEMORY;
1268 qual.unicode = FALSE;
1269 qual.str.a = lpQualifierBuf;
1271 appdata.unicode = FALSE;
1272 appdata.str.a = lpApplicationDataBuf;
1274 r = MSI_EnumComponentQualifiers( comp, iIndex,
1275 &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1276 msi_free( comp );
1277 return r;
1280 /*************************************************************************
1281 * MsiEnumComponentQualifiersW [MSI.@]
1283 UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
1284 LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf,
1285 LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf )
1287 awstring qual, appdata;
1289 TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1290 lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1291 pcchApplicationDataBuf);
1293 qual.unicode = TRUE;
1294 qual.str.w = lpQualifierBuf;
1296 appdata.unicode = TRUE;
1297 appdata.str.w = lpApplicationDataBuf;
1299 return MSI_EnumComponentQualifiers( szComponent, iIndex,
1300 &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1303 /*************************************************************************
1304 * MsiEnumRelatedProductsW [MSI.@]
1307 UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,
1308 DWORD iProductIndex, LPWSTR lpProductBuf)
1310 UINT r;
1311 HKEY hkey;
1312 DWORD dwSize = SQUISH_GUID_SIZE;
1313 WCHAR szKeyName[SQUISH_GUID_SIZE];
1315 TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved,
1316 iProductIndex, lpProductBuf);
1318 if (NULL == szUpgradeCode)
1319 return ERROR_INVALID_PARAMETER;
1320 if (NULL == lpProductBuf)
1321 return ERROR_INVALID_PARAMETER;
1323 r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1324 if (r != ERROR_SUCCESS)
1325 return ERROR_NO_MORE_ITEMS;
1327 r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1328 if( r == ERROR_SUCCESS )
1329 unsquash_guid(szKeyName, lpProductBuf);
1330 RegCloseKey(hkey);
1332 return r;
1335 /*************************************************************************
1336 * MsiEnumRelatedProductsA [MSI.@]
1339 UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
1340 DWORD iProductIndex, LPSTR lpProductBuf)
1342 LPWSTR szwUpgradeCode = NULL;
1343 WCHAR productW[GUID_SIZE];
1344 UINT r;
1346 TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved,
1347 iProductIndex, lpProductBuf);
1349 if (szUpgradeCode)
1351 szwUpgradeCode = strdupAtoW( szUpgradeCode );
1352 if( !szwUpgradeCode )
1353 return ERROR_OUTOFMEMORY;
1356 r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1357 iProductIndex, productW );
1358 if (r == ERROR_SUCCESS)
1360 WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1361 lpProductBuf, GUID_SIZE, NULL, NULL );
1363 msi_free( szwUpgradeCode);
1364 return r;
1367 /***********************************************************************
1368 * MsiEnumPatchesA [MSI.@]
1370 UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex,
1371 LPSTR lpPatchBuf, LPSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
1373 FIXME("%s %d %p %p %p\n", debugstr_a(szProduct),
1374 iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1375 return ERROR_NO_MORE_ITEMS;
1378 /***********************************************************************
1379 * MsiEnumPatchesW [MSI.@]
1381 UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex,
1382 LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
1384 FIXME("%s %d %p %p %p\n", debugstr_w(szProduct),
1385 iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1386 return ERROR_NO_MORE_ITEMS;
1389 UINT WINAPI MsiEnumProductsExA( LPCSTR szProductCode, LPCSTR szUserSid,
1390 DWORD dwContext, DWORD dwIndex, CHAR szInstalledProductCode[39],
1391 MSIINSTALLCONTEXT* pdwInstalledContext, LPSTR szSid, LPDWORD pcchSid)
1393 FIXME("%s %s %d %d %p %p %p %p\n", debugstr_a(szProductCode), debugstr_a(szUserSid),
1394 dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
1395 szSid, pcchSid);
1396 return ERROR_NO_MORE_ITEMS;
1399 UINT WINAPI MsiEnumProductsExW( LPCWSTR szProductCode, LPCWSTR szUserSid,
1400 DWORD dwContext, DWORD dwIndex, WCHAR szInstalledProductCode[39],
1401 MSIINSTALLCONTEXT* pdwInstalledContext, LPWSTR szSid, LPDWORD pcchSid)
1403 FIXME("%s %s %d %d %p %p %p %p\n", debugstr_w(szProductCode), debugstr_w(szUserSid),
1404 dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
1405 szSid, pcchSid);
1406 return ERROR_NO_MORE_ITEMS;