kernel32/tests: Fix the BindIoCompletionCallback test on Vista.
[wine] / dlls / msi / msi.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002,2003,2004,2005 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "shlwapi.h"
31 #include "wine/debug.h"
32 #include "msi.h"
33 #include "msidefs.h"
34 #include "msiquery.h"
35 #include "msipriv.h"
36 #include "wincrypt.h"
37 #include "winver.h"
38 #include "winuser.h"
39 #include "shlobj.h"
40 #include "shobjidl.h"
41 #include "objidl.h"
42 #include "wine/unicode.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(msi);
45
46 static const WCHAR installerW[] = {'\\','I','n','s','t','a','l','l','e','r',0};
47
48 static UINT msi_locate_product(LPCWSTR szProduct, MSIINSTALLCONTEXT *context)
49 {
50     HKEY hkey = NULL;
51
52     *context = MSIINSTALLCONTEXT_NONE;
53
54     if (MSIREG_OpenLocalManagedProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS)
55         *context = MSIINSTALLCONTEXT_USERMANAGED;
56     else if (MSIREG_OpenLocalClassesProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS)
57         *context = MSIINSTALLCONTEXT_MACHINE;
58     else if (MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS)
59         *context = MSIINSTALLCONTEXT_USERUNMANAGED;
60
61     RegCloseKey(hkey);
62
63     if (*context == MSIINSTALLCONTEXT_NONE)
64         return ERROR_UNKNOWN_PRODUCT;
65
66     return ERROR_SUCCESS;
67 }
68
69 UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
70 {
71     UINT r;
72     LPWSTR szwProd = NULL;
73
74     TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
75
76     if( szProduct )
77     {
78         szwProd = strdupAtoW( szProduct );
79         if( !szwProd )
80             return ERROR_OUTOFMEMORY;
81     }
82
83     r = MsiOpenProductW( szwProd, phProduct );
84
85     msi_free( szwProd );
86
87     return r;
88 }
89
90 static UINT MSI_OpenProductW(LPCWSTR szProduct, MSIPACKAGE **package)
91 {
92     UINT r;
93     HKEY props;
94     LPWSTR path;
95     MSIINSTALLCONTEXT context;
96
97     static const WCHAR managed[] = {
98         'M','a','n','a','g','e','d','L','o','c','a','l','P','a','c','k','a','g','e',0};
99     static const WCHAR local[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
100
101     TRACE("%s %p\n", debugstr_w(szProduct), package);
102
103     r = msi_locate_product(szProduct, &context);
104     if (r != ERROR_SUCCESS)
105         return r;
106
107     if (context == MSIINSTALLCONTEXT_MACHINE)
108         r = MSIREG_OpenLocalSystemInstallProps(szProduct, &props, FALSE);
109     else if (context == MSIINSTALLCONTEXT_USERMANAGED ||
110              context == MSIINSTALLCONTEXT_USERUNMANAGED)
111         r = MSIREG_OpenCurrentUserInstallProps(szProduct, &props, FALSE);
112
113     if (r != ERROR_SUCCESS)
114         return ERROR_UNKNOWN_PRODUCT;
115
116     if (context == MSIINSTALLCONTEXT_USERMANAGED)
117         path = msi_reg_get_val_str(props, managed);
118     else
119         path = msi_reg_get_val_str(props, local);
120
121     r = ERROR_UNKNOWN_PRODUCT;
122
123     if (!path || GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
124         goto done;
125
126     if (PathIsRelativeW(path))
127     {
128         r = ERROR_INSTALL_PACKAGE_OPEN_FAILED;
129         goto done;
130     }
131
132     r = MSI_OpenPackageW(path, package);
133
134 done:
135     RegCloseKey(props);
136     msi_free(path);
137     return r;
138 }
139
140 UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct)
141 {
142     MSIPACKAGE *package = NULL;
143     WCHAR squished_pc[GUID_SIZE];
144     UINT r;
145
146     if (!szProduct || !squash_guid(szProduct, squished_pc))
147         return ERROR_INVALID_PARAMETER;
148
149     if (!phProduct)
150         return ERROR_INVALID_PARAMETER;
151
152     r = MSI_OpenProductW(szProduct, &package);
153     if (r != ERROR_SUCCESS)
154         return r;
155
156     *phProduct = alloc_msihandle(&package->hdr);
157     if (!*phProduct)
158         r = ERROR_NOT_ENOUGH_MEMORY;
159
160     msiobj_release(&package->hdr);
161     return r;
162 }
163
164 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
165                 LPCSTR szTransforms, LANGID lgidLanguage)
166 {
167     FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath),
168           debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
169     return ERROR_CALL_NOT_IMPLEMENTED;
170 }
171
172 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
173                 LPCWSTR szTransforms, LANGID lgidLanguage)
174 {
175     FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath),
176           debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
177     return ERROR_CALL_NOT_IMPLEMENTED;
178 }
179
180 UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
181       LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
182 {
183     FIXME("%s %s %s %08x %08x %08x\n", debugstr_a(szPackagePath),
184           debugstr_a(szScriptfilePath), debugstr_a(szTransforms),
185           lgidLanguage, dwPlatform, dwOptions);
186     return ERROR_CALL_NOT_IMPLEMENTED;
187 }
188
189 UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
190       LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
191 {
192     FIXME("%s %s %s %08x %08x %08x\n", debugstr_w(szPackagePath),
193           debugstr_w(szScriptfilePath), debugstr_w(szTransforms),
194           lgidLanguage, dwPlatform, dwOptions);
195     return ERROR_CALL_NOT_IMPLEMENTED;
196 }
197
198 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
199 {
200     LPWSTR szwPath = NULL, szwCommand = NULL;
201     UINT r = ERROR_OUTOFMEMORY;
202
203     TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
204
205     if( szPackagePath )
206     {
207         szwPath = strdupAtoW( szPackagePath );
208         if( !szwPath )
209             goto end;
210     }
211
212     if( szCommandLine )
213     {
214         szwCommand = strdupAtoW( szCommandLine );
215         if( !szwCommand )
216             goto end;
217     }
218
219     r = MsiInstallProductW( szwPath, szwCommand );
220
221 end:
222     msi_free( szwPath );
223     msi_free( szwCommand );
224
225     return r;
226 }
227
228 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
229 {
230     MSIPACKAGE *package = NULL;
231     UINT r;
232
233     TRACE("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
234
235     r = MSI_OpenPackageW( szPackagePath, &package );
236     if (r == ERROR_SUCCESS)
237     {
238         r = MSI_InstallPackage( package, szPackagePath, szCommandLine );
239         msiobj_release( &package->hdr );
240     }
241
242     return r;
243 }
244
245 UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode)
246 {
247     FIXME("%s %08x\n", debugstr_a(szProduct), dwReinstallMode);
248     return ERROR_CALL_NOT_IMPLEMENTED;
249 }
250
251 UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode)
252 {
253     FIXME("%s %08x\n", debugstr_w(szProduct), dwReinstallMode);
254     return ERROR_CALL_NOT_IMPLEMENTED;
255 }
256
257 UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage,
258         INSTALLTYPE eInstallType, LPCSTR szCommandLine)
259 {
260     LPWSTR patch_package = NULL;
261     LPWSTR install_package = NULL;
262     LPWSTR command_line = NULL;
263     UINT r = ERROR_OUTOFMEMORY;
264
265     TRACE("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage),
266           eInstallType, debugstr_a(szCommandLine));
267
268     if (szPatchPackage && !(patch_package = strdupAtoW(szPatchPackage)))
269         goto done;
270
271     if (szInstallPackage && !(install_package = strdupAtoW(szInstallPackage)))
272         goto done;
273
274     if (szCommandLine && !(command_line = strdupAtoW(szCommandLine)))
275         goto done;
276
277     r = MsiApplyPatchW(patch_package, install_package, eInstallType, command_line);
278
279 done:
280     msi_free(patch_package);
281     msi_free(install_package);
282     msi_free(command_line);
283
284     return r;
285 }
286
287 UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
288          INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
289 {
290     MSIHANDLE patch, info;
291     UINT r, type;
292     DWORD size = 0;
293     LPCWSTR cmd_ptr = szCommandLine;
294     LPWSTR beg, end;
295     LPWSTR cmd = NULL, codes = NULL;
296
297     static const WCHAR space[] = {' ',0};
298     static const WCHAR patcheq[] = {'P','A','T','C','H','=',0};
299     static WCHAR empty[] = {0};
300
301     TRACE("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage),
302           eInstallType, debugstr_w(szCommandLine));
303
304     if (szInstallPackage || eInstallType == INSTALLTYPE_NETWORK_IMAGE ||
305         eInstallType == INSTALLTYPE_SINGLE_INSTANCE)
306     {
307         FIXME("Only reading target products from patch\n");
308         return ERROR_CALL_NOT_IMPLEMENTED;
309     }
310
311     r = MsiOpenDatabaseW(szPatchPackage, MSIDBOPEN_READONLY, &patch);
312     if (r != ERROR_SUCCESS)
313         return r;
314
315     r = MsiGetSummaryInformationW(patch, NULL, 0, &info);
316     if (r != ERROR_SUCCESS)
317         goto done;
318
319     r = MsiSummaryInfoGetPropertyW(info, PID_TEMPLATE, &type, NULL, NULL, empty, &size);
320     if (r != ERROR_MORE_DATA || !size || type != VT_LPSTR)
321     {
322         ERR("Failed to read product codes from patch\n");
323         goto done;
324     }
325
326     codes = msi_alloc(++size * sizeof(WCHAR));
327     if (!codes)
328     {
329         r = ERROR_OUTOFMEMORY;
330         goto done;
331     }
332
333     r = MsiSummaryInfoGetPropertyW(info, PID_TEMPLATE, &type, NULL, NULL, codes, &size);
334     if (r != ERROR_SUCCESS)
335         goto done;
336
337     if (!szCommandLine)
338         cmd_ptr = empty;
339
340     size = lstrlenW(cmd_ptr) + lstrlenW(patcheq) + lstrlenW(szPatchPackage) + 1;
341     cmd = msi_alloc(size * sizeof(WCHAR));
342     if (!cmd)
343     {
344         r = ERROR_OUTOFMEMORY;
345         goto done;
346     }
347
348     lstrcpyW(cmd, cmd_ptr);
349     if (szCommandLine) lstrcatW(cmd, space);
350     lstrcatW(cmd, patcheq);
351     lstrcatW(cmd, szPatchPackage);
352
353     beg = codes;
354     while ((end = strchrW(beg, '}')))
355     {
356         *(end + 1) = '\0';
357
358         r = MsiConfigureProductExW(beg, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
359         if (r != ERROR_SUCCESS)
360             goto done;
361
362         beg = end + 2;
363     }
364
365 done:
366     msi_free(cmd);
367     msi_free(codes);
368
369     MsiCloseHandle(info);
370     MsiCloseHandle(patch);
371
372     return r;
373 }
374
375 static UINT msi_open_package(LPCWSTR product, MSIINSTALLCONTEXT context,
376                              MSIPACKAGE **package)
377 {
378     UINT r;
379     DWORD sz;
380     HKEY props;
381     LPWSTR localpack;
382     WCHAR sourcepath[MAX_PATH];
383     WCHAR filename[MAX_PATH];
384
385     static const WCHAR szLocalPackage[] = {
386         'L','o','c','a','l','P','a','c','k','a','g','e',0};
387
388     if (context == MSIINSTALLCONTEXT_MACHINE)
389         r = MSIREG_OpenLocalSystemInstallProps(product, &props, FALSE);
390     else
391         r = MSIREG_OpenCurrentUserInstallProps(product, &props, FALSE);
392
393     if (r != ERROR_SUCCESS)
394         return ERROR_BAD_CONFIGURATION;
395
396     localpack = msi_reg_get_val_str(props, szLocalPackage);
397     if (localpack)
398     {
399         lstrcpyW(sourcepath, localpack);
400         msi_free(localpack);
401     }
402
403     if (!localpack || GetFileAttributesW(sourcepath) == INVALID_FILE_ATTRIBUTES)
404     {
405         sz = sizeof(sourcepath);
406         MsiSourceListGetInfoW(product, NULL, context, MSICODE_PRODUCT,
407                               INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
408
409         sz = sizeof(filename);
410         MsiSourceListGetInfoW(product, NULL, context, MSICODE_PRODUCT,
411                               INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
412
413         lstrcatW(sourcepath, filename);
414     }
415
416     if (GetFileAttributesW(sourcepath) == INVALID_FILE_ATTRIBUTES)
417         return ERROR_INSTALL_SOURCE_ABSENT;
418
419     return MSI_OpenPackageW(sourcepath, package);
420 }
421
422 UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
423                         INSTALLSTATE eInstallState, LPCWSTR szCommandLine)
424 {
425     MSIPACKAGE* package = NULL;
426     MSIINSTALLCONTEXT context;
427     UINT r;
428     DWORD sz;
429     WCHAR sourcepath[MAX_PATH];
430     LPWSTR commandline;
431
432     static const WCHAR szInstalled[] = {
433         ' ','I','n','s','t','a','l','l','e','d','=','1',0};
434     static const WCHAR szRemoveAll[] = {
435         ' ','R','E','M','O','V','E','=','A','L','L',0};
436     static const WCHAR szMachine[] = {
437         ' ','A','L','L','U','S','E','R','S','=','1',0};
438
439     TRACE("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState,
440           debugstr_w(szCommandLine));
441
442     if (!szProduct || lstrlenW(szProduct) != GUID_SIZE - 1)
443         return ERROR_INVALID_PARAMETER;
444
445     if (eInstallState == INSTALLSTATE_ADVERTISED ||
446         eInstallState == INSTALLSTATE_SOURCE)
447     {
448         FIXME("State %d not implemented\n", eInstallState);
449         return ERROR_CALL_NOT_IMPLEMENTED;
450     }
451
452     r = msi_locate_product(szProduct, &context);
453     if (r != ERROR_SUCCESS)
454         return r;
455
456     r = msi_open_package(szProduct, context, &package);
457     if (r != ERROR_SUCCESS)
458         return r;
459
460     sz = lstrlenW(szInstalled) + 1;
461
462     if (szCommandLine)
463         sz += lstrlenW(szCommandLine);
464
465     if (eInstallState == INSTALLSTATE_ABSENT)
466         sz += lstrlenW(szRemoveAll);
467
468     if (context == MSIINSTALLCONTEXT_MACHINE)
469         sz += lstrlenW(szMachine);
470
471     commandline = msi_alloc(sz * sizeof(WCHAR));
472     if (!commandline)
473     {
474         r = ERROR_OUTOFMEMORY;
475         goto end;
476     }
477
478     commandline[0] = 0;
479     if (szCommandLine)
480         lstrcpyW(commandline,szCommandLine);
481
482     if (MsiQueryProductStateW(szProduct) != INSTALLSTATE_UNKNOWN)
483         lstrcatW(commandline,szInstalled);
484
485     if (eInstallState == INSTALLSTATE_ABSENT)
486         lstrcatW(commandline, szRemoveAll);
487
488     if (context == MSIINSTALLCONTEXT_MACHINE)
489         lstrcatW(commandline, szMachine);
490
491     r = MSI_InstallPackage( package, sourcepath, commandline );
492
493     msi_free(commandline);
494
495 end:
496     msiobj_release( &package->hdr );
497
498     return r;
499 }
500
501 UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel,
502                         INSTALLSTATE eInstallState, LPCSTR szCommandLine)
503 {
504     LPWSTR szwProduct = NULL;
505     LPWSTR szwCommandLine = NULL;
506     UINT r = ERROR_OUTOFMEMORY;
507
508     if( szProduct )
509     {
510         szwProduct = strdupAtoW( szProduct );
511         if( !szwProduct )
512             goto end;
513     }
514
515     if( szCommandLine)
516     {
517         szwCommandLine = strdupAtoW( szCommandLine );
518         if( !szwCommandLine)
519             goto end;
520     }
521
522     r = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState,
523                                 szwCommandLine );
524 end:
525     msi_free( szwProduct );
526     msi_free( szwCommandLine);
527
528     return r;
529 }
530
531 UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel,
532                                  INSTALLSTATE eInstallState)
533 {
534     LPWSTR szwProduct = NULL;
535     UINT r;
536
537     TRACE("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
538
539     if( szProduct )
540     {
541         szwProduct = strdupAtoW( szProduct );
542         if( !szwProduct )
543             return ERROR_OUTOFMEMORY;
544     }
545
546     r = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState );
547     msi_free( szwProduct );
548
549     return r;
550 }
551
552 UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel,
553                                  INSTALLSTATE eInstallState)
554 {
555     return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL);
556 }
557
558 UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
559 {
560     LPWSTR szwComponent = NULL;
561     UINT r;
562     WCHAR szwBuffer[GUID_SIZE];
563
564     TRACE("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer));
565
566     if( szComponent )
567     {
568         szwComponent = strdupAtoW( szComponent );
569         if( !szwComponent )
570             return ERROR_OUTOFMEMORY;
571     }
572
573     *szwBuffer = '\0';
574     r = MsiGetProductCodeW( szwComponent, szwBuffer );
575
576     if(*szwBuffer)
577         WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL);
578
579     msi_free( szwComponent );
580
581     return r;
582 }
583
584 UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
585 {
586     UINT rc, index;
587     HKEY compkey, prodkey;
588     WCHAR squished_comp[GUID_SIZE];
589     WCHAR squished_prod[GUID_SIZE];
590     DWORD sz = GUID_SIZE;
591
592     TRACE("%s %p\n", debugstr_w(szComponent), szBuffer);
593
594     if (!szComponent || !*szComponent)
595         return ERROR_INVALID_PARAMETER;
596
597     if (!squash_guid(szComponent, squished_comp))
598         return ERROR_INVALID_PARAMETER;
599
600     if (MSIREG_OpenUserDataComponentKey(szComponent, &compkey, FALSE) != ERROR_SUCCESS &&
601         MSIREG_OpenLocalSystemComponentKey(szComponent, &compkey, FALSE) != ERROR_SUCCESS)
602     {
603         return ERROR_UNKNOWN_COMPONENT;
604     }
605
606     rc = RegEnumValueW(compkey, 0, squished_prod, &sz, NULL, NULL, NULL, NULL);
607     if (rc != ERROR_SUCCESS)
608     {
609         RegCloseKey(compkey);
610         return ERROR_UNKNOWN_COMPONENT;
611     }
612
613     /* check simple case, only one product */
614     rc = RegEnumValueW(compkey, 1, squished_prod, &sz, NULL, NULL, NULL, NULL);
615     if (rc == ERROR_NO_MORE_ITEMS)
616     {
617         rc = ERROR_SUCCESS;
618         goto done;
619     }
620
621     index = 0;
622     while ((rc = RegEnumValueW(compkey, index, squished_prod, &sz,
623            NULL, NULL, NULL, NULL)) != ERROR_NO_MORE_ITEMS)
624     {
625         index++;
626         sz = GUID_SIZE;
627         unsquash_guid(squished_prod, szBuffer);
628
629         if (MSIREG_OpenLocalManagedProductKey(szBuffer, &prodkey, FALSE) == ERROR_SUCCESS ||
630             MSIREG_OpenUserProductsKey(szBuffer, &prodkey, FALSE) == ERROR_SUCCESS ||
631             MSIREG_OpenLocalClassesProductKey(szBuffer, &prodkey, FALSE) == ERROR_SUCCESS)
632         {
633             RegCloseKey(prodkey);
634             rc = ERROR_SUCCESS;
635             goto done;
636         }
637     }
638
639     rc = ERROR_INSTALL_FAILURE;
640
641 done:
642     RegCloseKey(compkey);
643     unsquash_guid(squished_prod, szBuffer);
644     return rc;
645 }
646
647 static LPWSTR msi_reg_get_value(HKEY hkey, LPCWSTR name, DWORD *type)
648 {
649     DWORD dval;
650     LONG res;
651     WCHAR temp[20];
652
653     static const WCHAR format[] = {'%','d',0};
654
655     res = RegQueryValueExW(hkey, name, NULL, type, NULL, NULL);
656     if (res != ERROR_SUCCESS)
657         return NULL;
658
659     if (*type == REG_SZ)
660         return msi_reg_get_val_str(hkey, name);
661
662     if (!msi_reg_get_val_dword(hkey, name, &dval))
663         return NULL;
664
665     sprintfW(temp, format, dval);
666     return strdupW(temp);
667 }
668
669 static UINT WINAPI MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
670                                       awstring *szValue, LPDWORD pcchValueBuf)
671 {
672     UINT r = ERROR_UNKNOWN_PROPERTY;
673     HKEY prodkey, userdata, source;
674     LPWSTR val = NULL;
675     WCHAR squished_pc[GUID_SIZE];
676     WCHAR packagecode[GUID_SIZE];
677     BOOL classes = FALSE;
678     BOOL badconfig = FALSE;
679     LONG res;
680     DWORD save, type = REG_NONE;
681
682     static WCHAR empty[] = {0};
683     static const WCHAR sourcelist[] = {
684         'S','o','u','r','c','e','L','i','s','t',0};
685     static const WCHAR display_name[] = {
686         'D','i','s','p','l','a','y','N','a','m','e',0};
687     static const WCHAR display_version[] = {
688         'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
689     static const WCHAR assignment[] = {
690         'A','s','s','i','g','n','m','e','n','t',0};
691
692     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
693           debugstr_w(szAttribute), szValue, pcchValueBuf);
694
695     if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szAttribute)
696         return ERROR_INVALID_PARAMETER;
697
698     if (!squash_guid(szProduct, squished_pc))
699         return ERROR_INVALID_PARAMETER;
700
701     r = MSIREG_OpenLocalManagedProductKey(szProduct, &prodkey, FALSE);
702     if (r != ERROR_SUCCESS)
703     {
704         r = MSIREG_OpenUserProductsKey(szProduct, &prodkey, FALSE);
705         if (r != ERROR_SUCCESS)
706         {
707             r = MSIREG_OpenLocalClassesProductKey(szProduct, &prodkey, FALSE);
708             if (r == ERROR_SUCCESS)
709                 classes = TRUE;
710         }
711     }
712
713     if (classes)
714         MSIREG_OpenLocalSystemProductKey(szProduct, &userdata, FALSE);
715     else
716         MSIREG_OpenCurrentUserInstallProps(szProduct, &userdata, FALSE);
717
718     if (!lstrcmpW(szAttribute, INSTALLPROPERTY_HELPLINKW) ||
719         !lstrcmpW(szAttribute, INSTALLPROPERTY_HELPTELEPHONEW) ||
720         !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLDATEW) ||
721         !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW) ||
722         !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLLOCATIONW) ||
723         !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLSOURCEW) ||
724         !lstrcmpW(szAttribute, INSTALLPROPERTY_LOCALPACKAGEW) ||
725         !lstrcmpW(szAttribute, INSTALLPROPERTY_PUBLISHERW) ||
726         !lstrcmpW(szAttribute, INSTALLPROPERTY_URLINFOABOUTW) ||
727         !lstrcmpW(szAttribute, INSTALLPROPERTY_URLUPDATEINFOW) ||
728         !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONMINORW) ||
729         !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONMAJORW) ||
730         !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW) ||
731         !lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTIDW) ||
732         !lstrcmpW(szAttribute, INSTALLPROPERTY_REGCOMPANYW) ||
733         !lstrcmpW(szAttribute, INSTALLPROPERTY_REGOWNERW))
734     {
735         if (!prodkey)
736         {
737             r = ERROR_UNKNOWN_PRODUCT;
738             goto done;
739         }
740
741         if (!userdata)
742             return ERROR_UNKNOWN_PROPERTY;
743
744         if (!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW))
745             szAttribute = display_name;
746         else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW))
747             szAttribute = display_version;
748
749         val = msi_reg_get_value(userdata, szAttribute, &type);
750         if (!val)
751             val = empty;
752     }
753     else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTANCETYPEW) ||
754              !lstrcmpW(szAttribute, INSTALLPROPERTY_TRANSFORMSW) ||
755              !lstrcmpW(szAttribute, INSTALLPROPERTY_LANGUAGEW) ||
756              !lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTNAMEW) ||
757              !lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW) ||
758              !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW) ||
759              !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONW) ||
760              !lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTICONW) ||
761              !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGENAMEW) ||
762              !lstrcmpW(szAttribute, INSTALLPROPERTY_AUTHORIZED_LUA_APPW))
763     {
764         if (!prodkey)
765         {
766             r = ERROR_UNKNOWN_PRODUCT;
767             goto done;
768         }
769
770         if (!lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW))
771             szAttribute = assignment;
772
773         if (!lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGENAMEW))
774         {
775             res = RegOpenKeyW(prodkey, sourcelist, &source);
776             if (res == ERROR_SUCCESS)
777                 val = msi_reg_get_value(source, szAttribute, &type);
778
779             RegCloseKey(source);
780         }
781         else
782         {
783             val = msi_reg_get_value(prodkey, szAttribute, &type);
784             if (!val)
785                 val = empty;
786         }
787
788         if (val != empty && type != REG_DWORD &&
789             !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW))
790         {
791             if (lstrlenW(val) != SQUISH_GUID_SIZE - 1)
792                 badconfig = TRUE;
793             else
794             {
795                 unsquash_guid(val, packagecode);
796                 msi_free(val);
797                 val = strdupW(packagecode);
798             }
799         }
800     }
801
802     if (!val)
803     {
804         r = ERROR_UNKNOWN_PROPERTY;
805         goto done;
806     }
807
808     if (pcchValueBuf)
809     {
810         save = *pcchValueBuf;
811
812         if (lstrlenW(val) < *pcchValueBuf)
813             r = msi_strcpy_to_awstring(val, szValue, pcchValueBuf);
814         else if (szValue->str.a || szValue->str.w)
815             r = ERROR_MORE_DATA;
816
817         if (!badconfig)
818             *pcchValueBuf = lstrlenW(val);
819         else if (r == ERROR_SUCCESS)
820         {
821             *pcchValueBuf = save;
822             r = ERROR_BAD_CONFIGURATION;
823         }
824     }
825     else if (badconfig)
826         r = ERROR_BAD_CONFIGURATION;
827
828     if (val != empty)
829         msi_free(val);
830
831 done:
832     RegCloseKey(prodkey);
833     RegCloseKey(userdata);
834     return r;
835 }
836
837 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
838                                LPSTR szBuffer, LPDWORD pcchValueBuf)
839 {
840     LPWSTR szwProduct, szwAttribute = NULL;
841     UINT r = ERROR_OUTOFMEMORY;
842     awstring buffer;
843
844     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
845           szBuffer, pcchValueBuf);
846
847     szwProduct = strdupAtoW( szProduct );
848     if( szProduct && !szwProduct )
849         goto end;
850
851     szwAttribute = strdupAtoW( szAttribute );
852     if( szAttribute && !szwAttribute )
853         goto end;
854
855     buffer.unicode = FALSE;
856     buffer.str.a = szBuffer;
857
858     r = MSI_GetProductInfo( szwProduct, szwAttribute,
859                             &buffer, pcchValueBuf );
860
861 end:
862     msi_free( szwProduct );
863     msi_free( szwAttribute );
864
865     return r;
866 }
867
868 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
869                                LPWSTR szBuffer, LPDWORD pcchValueBuf)
870 {
871     awstring buffer;
872
873     TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szAttribute),
874           szBuffer, pcchValueBuf);
875
876     buffer.unicode = TRUE;
877     buffer.str.w = szBuffer;
878
879     return MSI_GetProductInfo( szProduct, szAttribute,
880                                &buffer, pcchValueBuf );
881 }
882
883 UINT WINAPI MsiGetProductInfoExA(LPCSTR szProductCode, LPCSTR szUserSid,
884                                  MSIINSTALLCONTEXT dwContext, LPCSTR szProperty,
885                                  LPSTR szValue, LPDWORD pcchValue)
886 {
887     LPWSTR product = NULL;
888     LPWSTR usersid = NULL;
889     LPWSTR property = NULL;
890     LPWSTR value = NULL;
891     DWORD len = 0;
892     UINT r;
893
894     TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_a(szProductCode),
895           debugstr_a(szUserSid), dwContext, debugstr_a(szProperty),
896            szValue, pcchValue);
897
898     if (szValue && !pcchValue)
899         return ERROR_INVALID_PARAMETER;
900
901     if (szProductCode) product = strdupAtoW(szProductCode);
902     if (szUserSid) usersid = strdupAtoW(szUserSid);
903     if (szProperty) property = strdupAtoW(szProperty);
904
905     r = MsiGetProductInfoExW(product, usersid, dwContext, property,
906                              NULL, &len);
907     if (r != ERROR_SUCCESS)
908         goto done;
909
910     value = msi_alloc(++len * sizeof(WCHAR));
911     if (!value)
912     {
913         r = ERROR_OUTOFMEMORY;
914         goto done;
915     }
916
917     r = MsiGetProductInfoExW(product, usersid, dwContext, property,
918                              value, &len);
919     if (r != ERROR_SUCCESS)
920         goto done;
921
922     if (!pcchValue)
923         goto done;
924
925     len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
926     if (*pcchValue >= len)
927         WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
928     else if (szValue)
929     {
930         r = ERROR_MORE_DATA;
931         if (*pcchValue > 0)
932             *szValue = '\0';
933     }
934
935     if (*pcchValue <= len || !szValue)
936         len = len * sizeof(WCHAR) - 1;
937
938     *pcchValue = len - 1;
939
940 done:
941     msi_free(product);
942     msi_free(usersid);
943     msi_free(property);
944     msi_free(value);
945
946     return r;
947 }
948
949 static UINT msi_copy_outval(LPWSTR val, LPWSTR out, LPDWORD size)
950 {
951     UINT r;
952
953     if (!val)
954         return ERROR_UNKNOWN_PROPERTY;
955
956     if (out)
957     {
958         if (lstrlenW(val) >= *size)
959         {
960             r = ERROR_MORE_DATA;
961             if (*size > 0)
962                 *out = '\0';
963         }
964         else
965             lstrcpyW(out, val);
966     }
967
968     if (size)
969         *size = lstrlenW(val);
970
971     return ERROR_SUCCESS;
972 }
973
974 UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
975                                  MSIINSTALLCONTEXT dwContext, LPCWSTR szProperty,
976                                  LPWSTR szValue, LPDWORD pcchValue)
977 {
978     WCHAR squished_pc[GUID_SIZE];
979     LPWSTR val = NULL;
980     LPCWSTR package = NULL;
981     HKEY props = NULL, prod;
982     HKEY classes = NULL, managed;
983     HKEY hkey = NULL;
984     DWORD type;
985     UINT r = ERROR_UNKNOWN_PRODUCT;
986
987     static const WCHAR one[] = {'1',0};
988     static const WCHAR five[] = {'5',0};
989     static const WCHAR empty[] = {0};
990     static const WCHAR displayname[] = {
991         'D','i','s','p','l','a','y','N','a','m','e',0};
992     static const WCHAR displayversion[] = {
993         'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
994     static const WCHAR managed_local_package[] = {
995         'M','a','n','a','g','e','d','L','o','c','a','l',
996         'P','a','c','k','a','g','e',0};
997
998     TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_w(szProductCode),
999           debugstr_w(szUserSid), dwContext, debugstr_w(szProperty),
1000            szValue, pcchValue);
1001
1002     if (!szProductCode || !squash_guid(szProductCode, squished_pc))
1003         return ERROR_INVALID_PARAMETER;
1004
1005     if (szValue && !pcchValue)
1006         return ERROR_INVALID_PARAMETER;
1007
1008     if (dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
1009         dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
1010         dwContext != MSIINSTALLCONTEXT_MACHINE)
1011         return ERROR_INVALID_PARAMETER;
1012
1013     if (!szProperty || !*szProperty)
1014         return ERROR_INVALID_PARAMETER;
1015
1016     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
1017         return ERROR_INVALID_PARAMETER;
1018
1019     MSIREG_OpenLocalManagedProductKey(szProductCode, &managed, FALSE);
1020     MSIREG_OpenUserProductsKey(szProductCode, &prod, FALSE);
1021
1022     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
1023     {
1024         package = INSTALLPROPERTY_LOCALPACKAGEW;
1025         MSIREG_OpenCurrentUserInstallProps(szProductCode, &props, FALSE);
1026
1027         if (!props && !prod)
1028             goto done;
1029     }
1030     else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1031     {
1032         package = managed_local_package;
1033         MSIREG_OpenCurrentUserInstallProps(szProductCode, &props, FALSE);
1034
1035         if (!props && !managed)
1036             goto done;
1037     }
1038     else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1039     {
1040         package = INSTALLPROPERTY_LOCALPACKAGEW;
1041         MSIREG_OpenLocalSystemProductKey(szProductCode, &props, FALSE);
1042         MSIREG_OpenLocalClassesProductKey(szProductCode, &classes, FALSE);
1043
1044         if (!props && !classes)
1045             goto done;
1046     }
1047
1048     if (!lstrcmpW(szProperty, INSTALLPROPERTY_HELPLINKW) ||
1049         !lstrcmpW(szProperty, INSTALLPROPERTY_HELPTELEPHONEW) ||
1050         !lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLDATEW) ||
1051         !lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW) ||
1052         !lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLLOCATIONW) ||
1053         !lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLSOURCEW) ||
1054         !lstrcmpW(szProperty, INSTALLPROPERTY_LOCALPACKAGEW) ||
1055         !lstrcmpW(szProperty, INSTALLPROPERTY_PUBLISHERW) ||
1056         !lstrcmpW(szProperty, INSTALLPROPERTY_URLINFOABOUTW) ||
1057         !lstrcmpW(szProperty, INSTALLPROPERTY_URLUPDATEINFOW) ||
1058         !lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONMINORW) ||
1059         !lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONMAJORW) ||
1060         !lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONSTRINGW) ||
1061         !lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTIDW) ||
1062         !lstrcmpW(szProperty, INSTALLPROPERTY_REGCOMPANYW) ||
1063         !lstrcmpW(szProperty, INSTALLPROPERTY_REGOWNERW) ||
1064         !lstrcmpW(szProperty, INSTALLPROPERTY_INSTANCETYPEW))
1065     {
1066         val = msi_reg_get_value(props, package, &type);
1067         if (!val)
1068         {
1069             if (prod || classes)
1070                 r = ERROR_UNKNOWN_PROPERTY;
1071
1072             goto done;
1073         }
1074
1075         msi_free(val);
1076
1077         if (!lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW))
1078             szProperty = displayname;
1079         else if (!lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONSTRINGW))
1080             szProperty = displayversion;
1081
1082         val = msi_reg_get_value(props, szProperty, &type);
1083         if (!val)
1084             val = strdupW(empty);
1085
1086         r = msi_copy_outval(val, szValue, pcchValue);
1087     }
1088     else if (!lstrcmpW(szProperty, INSTALLPROPERTY_TRANSFORMSW) ||
1089              !lstrcmpW(szProperty, INSTALLPROPERTY_LANGUAGEW) ||
1090              !lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTNAMEW) ||
1091              !lstrcmpW(szProperty, INSTALLPROPERTY_PACKAGECODEW) ||
1092              !lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONW) ||
1093              !lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTICONW) ||
1094              !lstrcmpW(szProperty, INSTALLPROPERTY_PACKAGENAMEW) ||
1095              !lstrcmpW(szProperty, INSTALLPROPERTY_AUTHORIZED_LUA_APPW))
1096     {
1097         if (!prod && !classes)
1098             goto done;
1099
1100         if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
1101             hkey = prod;
1102         else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1103             hkey = managed;
1104         else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1105             hkey = classes;
1106
1107         val = msi_reg_get_value(hkey, szProperty, &type);
1108         if (!val)
1109             val = strdupW(empty);
1110
1111         r = msi_copy_outval(val, szValue, pcchValue);
1112     }
1113     else if (!lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTSTATEW))
1114     {
1115         if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1116         {
1117             if (props)
1118             {
1119                 val = msi_reg_get_value(props, package, &type);
1120                 if (!val)
1121                     goto done;
1122
1123                 msi_free(val);
1124                 val = strdupW(five);
1125             }
1126             else
1127                 val = strdupW(one);
1128
1129             r = msi_copy_outval(val, szValue, pcchValue);
1130             goto done;
1131         }
1132         else if (props && (val = msi_reg_get_value(props, package, &type)))
1133         {
1134             msi_free(val);
1135             val = strdupW(five);
1136             r = msi_copy_outval(val, szValue, pcchValue);
1137             goto done;
1138         }
1139
1140         if (prod || managed)
1141             val = strdupW(one);
1142         else
1143             goto done;
1144
1145         r = msi_copy_outval(val, szValue, pcchValue);
1146     }
1147     else if (!lstrcmpW(szProperty, INSTALLPROPERTY_ASSIGNMENTTYPEW))
1148     {
1149         if (!prod && !classes)
1150             goto done;
1151
1152         /* FIXME */
1153         val = strdupW(empty);
1154         r = msi_copy_outval(val, szValue, pcchValue);
1155     }
1156     else
1157         r = ERROR_UNKNOWN_PROPERTY;
1158
1159 done:
1160     RegCloseKey(props);
1161     RegCloseKey(prod);
1162     RegCloseKey(managed);
1163     RegCloseKey(classes);
1164     msi_free(val);
1165
1166     return r;
1167 }
1168
1169 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
1170 {
1171     LPWSTR szwLogFile = NULL;
1172     UINT r;
1173
1174     TRACE("%08x %s %08x\n", dwLogMode, debugstr_a(szLogFile), attributes);
1175
1176     if( szLogFile )
1177     {
1178         szwLogFile = strdupAtoW( szLogFile );
1179         if( !szwLogFile )
1180             return ERROR_OUTOFMEMORY;
1181     }
1182     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
1183     msi_free( szwLogFile );
1184     return r;
1185 }
1186
1187 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
1188 {
1189     HANDLE file = INVALID_HANDLE_VALUE;
1190
1191     TRACE("%08x %s %08x\n", dwLogMode, debugstr_w(szLogFile), attributes);
1192
1193     if (szLogFile)
1194     {
1195         lstrcpyW(gszLogFile,szLogFile);
1196         if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
1197             DeleteFileW(szLogFile);
1198         file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
1199                                FILE_ATTRIBUTE_NORMAL, NULL);
1200         if (file != INVALID_HANDLE_VALUE)
1201             CloseHandle(file);
1202         else
1203             ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
1204     }
1205     else
1206         gszLogFile[0] = '\0';
1207
1208     return ERROR_SUCCESS;
1209 }
1210
1211 UINT WINAPI MsiEnumComponentCostsW(MSIHANDLE hInstall, LPCWSTR szComponent,
1212                                    DWORD dwIndex, INSTALLSTATE iState,
1213                                    LPWSTR lpDriveBuf, DWORD *pcchDriveBuf,
1214                                    int *piCost, int *pTempCost)
1215 {
1216     FIXME("(%ld, %s, %d, %d, %p, %p, %p %p): stub!\n", hInstall,
1217           debugstr_w(szComponent), dwIndex, iState, lpDriveBuf,
1218           pcchDriveBuf, piCost, pTempCost);
1219
1220     return ERROR_NO_MORE_ITEMS;
1221 }
1222
1223 UINT WINAPI MsiQueryComponentStateA(LPCSTR szProductCode,
1224                                     LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1225                                     LPCSTR szComponent, INSTALLSTATE *pdwState)
1226 {
1227     LPWSTR prodcode = NULL, usersid = NULL, comp = NULL;
1228     UINT r;
1229
1230     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_a(szProductCode),
1231           debugstr_a(szUserSid), dwContext, debugstr_a(szComponent), pdwState);
1232
1233     if (szProductCode && !(prodcode = strdupAtoW(szProductCode)))
1234         return ERROR_OUTOFMEMORY;
1235
1236     if (szUserSid && !(usersid = strdupAtoW(szUserSid)))
1237             return ERROR_OUTOFMEMORY;
1238
1239     if (szComponent && !(comp = strdupAtoW(szComponent)))
1240             return ERROR_OUTOFMEMORY;
1241
1242     r = MsiQueryComponentStateW(prodcode, usersid, dwContext, comp, pdwState);
1243
1244     msi_free(prodcode);
1245     msi_free(usersid);
1246     msi_free(comp);
1247
1248     return r;
1249 }
1250
1251 static BOOL msi_comp_find_prod_key(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
1252 {
1253     UINT r;
1254     HKEY hkey;
1255
1256     if (context == MSIINSTALLCONTEXT_MACHINE)
1257         r = MSIREG_OpenLocalClassesProductKey(prodcode, &hkey, FALSE);
1258     else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
1259         r = MSIREG_OpenUserProductsKey(prodcode, &hkey, FALSE);
1260     else
1261         r = MSIREG_OpenLocalManagedProductKey(prodcode, &hkey, FALSE);
1262
1263     RegCloseKey(hkey);
1264     return (r == ERROR_SUCCESS);
1265 }
1266
1267 static BOOL msi_comp_find_package(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
1268 {
1269     LPCWSTR package;
1270     HKEY hkey;
1271     DWORD sz;
1272     LONG res;
1273     UINT r;
1274
1275     static const WCHAR local_package[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
1276     static const WCHAR managed_local_package[] = {
1277         'M','a','n','a','g','e','d','L','o','c','a','l','P','a','c','k','a','g','e',0
1278     };
1279
1280     if (context == MSIINSTALLCONTEXT_MACHINE)
1281         r = MSIREG_OpenLocalSystemProductKey(prodcode, &hkey, FALSE);
1282     else
1283         r = MSIREG_OpenCurrentUserInstallProps(prodcode, &hkey, FALSE);
1284
1285     if (r != ERROR_SUCCESS)
1286         return FALSE;
1287
1288     if (context == MSIINSTALLCONTEXT_USERMANAGED)
1289         package = managed_local_package;
1290     else
1291         package = local_package;
1292
1293     sz = 0;
1294     res = RegQueryValueExW(hkey, package, NULL, NULL, NULL, &sz);
1295     RegCloseKey(hkey);
1296
1297     return (res == ERROR_SUCCESS);
1298 }
1299
1300 static BOOL msi_comp_find_prodcode(LPWSTR squished_pc,
1301                                    MSIINSTALLCONTEXT context,
1302                                    LPCWSTR comp, LPWSTR val, DWORD *sz)
1303 {
1304     HKEY hkey;
1305     LONG res;
1306     UINT r;
1307
1308     if (context == MSIINSTALLCONTEXT_MACHINE)
1309         r = MSIREG_OpenLocalSystemComponentKey(comp, &hkey, FALSE);
1310     else
1311         r = MSIREG_OpenUserDataComponentKey(comp, &hkey, FALSE);
1312
1313     if (r != ERROR_SUCCESS)
1314         return FALSE;
1315
1316     res = RegQueryValueExW(hkey, squished_pc, NULL, NULL, (BYTE *)val, sz);
1317     if (res != ERROR_SUCCESS)
1318         return FALSE;
1319
1320     RegCloseKey(hkey);
1321     return TRUE;
1322 }
1323
1324 UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode,
1325                                     LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1326                                     LPCWSTR szComponent, INSTALLSTATE *pdwState)
1327 {
1328     WCHAR squished_pc[GUID_SIZE];
1329     WCHAR val[MAX_PATH];
1330     BOOL found;
1331     DWORD sz;
1332
1333     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_w(szProductCode),
1334           debugstr_w(szUserSid), dwContext, debugstr_w(szComponent), pdwState);
1335
1336     if (!pdwState)
1337         return ERROR_INVALID_PARAMETER;
1338
1339     if (!szProductCode || !*szProductCode || lstrlenW(szProductCode) != GUID_SIZE - 1)
1340         return ERROR_INVALID_PARAMETER;
1341
1342     if (!squash_guid(szProductCode, squished_pc))
1343         return ERROR_INVALID_PARAMETER;
1344
1345     found = msi_comp_find_prod_key(szProductCode, dwContext);
1346
1347     if (!msi_comp_find_package(szProductCode, dwContext))
1348     {
1349         if (found)
1350         {
1351             *pdwState = INSTALLSTATE_UNKNOWN;
1352             return ERROR_UNKNOWN_COMPONENT;
1353         }
1354
1355         return ERROR_UNKNOWN_PRODUCT;
1356     }
1357
1358     *pdwState = INSTALLSTATE_UNKNOWN;
1359
1360     sz = MAX_PATH;
1361     if (!msi_comp_find_prodcode(squished_pc, dwContext, szComponent, val, &sz))
1362         return ERROR_UNKNOWN_COMPONENT;
1363
1364     if (sz == 0)
1365         *pdwState = INSTALLSTATE_NOTUSED;
1366     else
1367     {
1368         if (lstrlenW(val) > 2 &&
1369             val[0] >= '0' && val[0] <= '9' && val[1] >= '0' && val[1] <= '9')
1370         {
1371             *pdwState = INSTALLSTATE_SOURCE;
1372         }
1373         else
1374             *pdwState = INSTALLSTATE_LOCAL;
1375     }
1376
1377     return ERROR_SUCCESS;
1378 }
1379
1380 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
1381 {
1382     LPWSTR szwProduct = NULL;
1383     INSTALLSTATE r;
1384
1385     if( szProduct )
1386     {
1387          szwProduct = strdupAtoW( szProduct );
1388          if( !szwProduct )
1389              return ERROR_OUTOFMEMORY;
1390     }
1391     r = MsiQueryProductStateW( szwProduct );
1392     msi_free( szwProduct );
1393     return r;
1394 }
1395
1396 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
1397 {
1398     INSTALLSTATE state = INSTALLSTATE_ADVERTISED;
1399     HKEY prodkey = 0, userdata = 0;
1400     BOOL user = TRUE;
1401     DWORD val;
1402     UINT r;
1403
1404     static const WCHAR szWindowsInstaller[] = {
1405         'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
1406
1407     TRACE("%s\n", debugstr_w(szProduct));
1408
1409     if (!szProduct || !*szProduct)
1410         return INSTALLSTATE_INVALIDARG;
1411
1412     if (lstrlenW(szProduct) != GUID_SIZE - 1)
1413         return INSTALLSTATE_INVALIDARG;
1414
1415     r = MSIREG_OpenLocalManagedProductKey(szProduct, &prodkey, FALSE);
1416     if (r != ERROR_SUCCESS)
1417     {
1418         r = MSIREG_OpenUserProductsKey(szProduct, &prodkey, FALSE);
1419         if (r != ERROR_SUCCESS)
1420         {
1421             r = MSIREG_OpenLocalClassesProductKey(szProduct, &prodkey, FALSE);
1422             if (r == ERROR_SUCCESS)
1423                user = FALSE;
1424         }
1425     }
1426
1427     if (user)
1428     {
1429         r = MSIREG_OpenCurrentUserInstallProps(szProduct, &userdata, FALSE);
1430         if (r != ERROR_SUCCESS)
1431             goto done;
1432     }
1433     else
1434     {
1435         r = MSIREG_OpenLocalSystemInstallProps(szProduct, &userdata, FALSE);
1436         if (r != ERROR_SUCCESS)
1437             goto done;
1438     }
1439
1440     if (!msi_reg_get_val_dword(userdata, szWindowsInstaller, &val))
1441         goto done;
1442
1443     if (val)
1444         state = INSTALLSTATE_DEFAULT;
1445     else
1446         state = INSTALLSTATE_UNKNOWN;
1447
1448 done:
1449     if (!prodkey)
1450     {
1451         state = INSTALLSTATE_UNKNOWN;
1452
1453         if (userdata)
1454             state = INSTALLSTATE_ABSENT;
1455     }
1456
1457     RegCloseKey(prodkey);
1458     RegCloseKey(userdata);
1459     return state;
1460 }
1461
1462 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
1463 {
1464     INSTALLUILEVEL old = gUILevel;
1465     HWND oldwnd = gUIhwnd;
1466
1467     TRACE("%08x %p\n", dwUILevel, phWnd);
1468
1469     gUILevel = dwUILevel;
1470     if (phWnd)
1471     {
1472         gUIhwnd = *phWnd;
1473         *phWnd = oldwnd;
1474     }
1475     return old;
1476 }
1477
1478 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
1479                                   DWORD dwMessageFilter, LPVOID pvContext)
1480 {
1481     INSTALLUI_HANDLERA prev = gUIHandlerA;
1482
1483     TRACE("%p %x %p\n",puiHandler, dwMessageFilter,pvContext);
1484     gUIHandlerA = puiHandler;
1485     gUIFilter = dwMessageFilter;
1486     gUIContext = pvContext;
1487
1488     return prev;
1489 }
1490
1491 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
1492                                   DWORD dwMessageFilter, LPVOID pvContext)
1493 {
1494     INSTALLUI_HANDLERW prev = gUIHandlerW;
1495
1496     TRACE("%p %x %p\n",puiHandler,dwMessageFilter,pvContext);
1497     gUIHandlerW = puiHandler;
1498     gUIFilter = dwMessageFilter;
1499     gUIContext = pvContext;
1500
1501     return prev;
1502 }
1503
1504 /******************************************************************
1505  *  MsiLoadStringW            [MSI.@]
1506  *
1507  * Loads a string from MSI's string resources.
1508  *
1509  * PARAMS
1510  *
1511  *   handle        [I]  only -1 is handled currently
1512  *   id            [I]  id of the string to be loaded
1513  *   lpBuffer      [O]  buffer for the string to be written to
1514  *   nBufferMax    [I]  maximum size of the buffer in characters
1515  *   lang          [I]  the preferred language for the string
1516  *
1517  * RETURNS
1518  *
1519  *   If successful, this function returns the language id of the string loaded
1520  *   If the function fails, the function returns zero.
1521  *
1522  * NOTES
1523  *
1524  *   The type of the first parameter is unknown.  LoadString's prototype
1525  *  suggests that it might be a module handle.  I have made it an MSI handle
1526  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
1527  *  handle.  Maybe strings can be stored in an MSI database somehow.
1528  */
1529 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
1530                 int nBufferMax, LANGID lang )
1531 {
1532     HRSRC hres;
1533     HGLOBAL hResData;
1534     LPWSTR p;
1535     DWORD i, len;
1536
1537     TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
1538
1539     if( handle != -1 )
1540         FIXME("don't know how to deal with handle = %08lx\n", handle);
1541
1542     if( !lang )
1543         lang = GetUserDefaultLangID();
1544
1545     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
1546                             (LPWSTR)1, lang );
1547     if( !hres )
1548         return 0;
1549     hResData = LoadResource( msi_hInstance, hres );
1550     if( !hResData )
1551         return 0;
1552     p = LockResource( hResData );
1553     if( !p )
1554         return 0;
1555
1556     for (i = 0; i < (id&0xf); i++)
1557         p += *p + 1;
1558     len = *p;
1559
1560     if( nBufferMax <= len )
1561         return 0;
1562
1563     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
1564     lpBuffer[ len ] = 0;
1565
1566     TRACE("found -> %s\n", debugstr_w(lpBuffer));
1567
1568     return lang;
1569 }
1570
1571 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
1572                 int nBufferMax, LANGID lang )
1573 {
1574     LPWSTR bufW;
1575     LANGID r;
1576     DWORD len;
1577
1578     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
1579     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
1580     if( r )
1581     {
1582         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
1583         if( len <= nBufferMax )
1584             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
1585                                  lpBuffer, nBufferMax, NULL, NULL );
1586         else
1587             r = 0;
1588     }
1589     msi_free(bufW);
1590     return r;
1591 }
1592
1593 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
1594                 LPDWORD pcchBuf)
1595 {
1596     char szProduct[GUID_SIZE];
1597
1598     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
1599
1600     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
1601         return INSTALLSTATE_UNKNOWN;
1602
1603     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
1604 }
1605
1606 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
1607                 LPDWORD pcchBuf)
1608 {
1609     WCHAR szProduct[GUID_SIZE];
1610
1611     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
1612
1613     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
1614         return INSTALLSTATE_UNKNOWN;
1615
1616     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
1617 }
1618
1619 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
1620                 WORD wLanguageId, DWORD f)
1621 {
1622     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption),
1623           uType, wLanguageId, f);
1624     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
1625 }
1626
1627 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
1628                 WORD wLanguageId, DWORD f)
1629 {
1630     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption),
1631           uType, wLanguageId, f);
1632     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
1633 }
1634
1635 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
1636                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
1637                 LPDWORD pcchPathBuf )
1638 {
1639     FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
1640           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
1641           pcchPathBuf);
1642     return ERROR_CALL_NOT_IMPLEMENTED;
1643 }
1644
1645 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
1646                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
1647                 LPDWORD pcchPathBuf )
1648 {
1649     FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
1650           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
1651           pcchPathBuf);
1652     return ERROR_CALL_NOT_IMPLEMENTED;
1653 }
1654
1655 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
1656                 LPSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
1657 {
1658     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
1659     return ERROR_CALL_NOT_IMPLEMENTED;
1660 }
1661
1662 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
1663                 LPWSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
1664 {
1665     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
1666     return ERROR_CALL_NOT_IMPLEMENTED;
1667 }
1668
1669 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
1670                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
1671                 LPDWORD pcbHashData)
1672 {
1673     FIXME("%s %08x %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
1674           ppcCertContext, pbHashData, pcbHashData);
1675     return ERROR_CALL_NOT_IMPLEMENTED;
1676 }
1677
1678 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
1679                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
1680                 LPDWORD pcbHashData)
1681 {
1682     FIXME("%s %08x %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
1683           ppcCertContext, pbHashData, pcbHashData);
1684     return ERROR_CALL_NOT_IMPLEMENTED;
1685 }
1686
1687 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
1688                                     LPSTR szValue, LPDWORD pccbValue )
1689 {
1690     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
1691     return ERROR_CALL_NOT_IMPLEMENTED;
1692 }
1693
1694 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
1695                                     LPWSTR szValue, LPDWORD pccbValue )
1696 {
1697     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
1698     return ERROR_CALL_NOT_IMPLEMENTED;
1699 }
1700
1701 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
1702 {
1703     UINT r;
1704     LPWSTR szPack = NULL;
1705
1706     TRACE("%s\n", debugstr_a(szPackage) );
1707
1708     if( szPackage )
1709     {
1710         szPack = strdupAtoW( szPackage );
1711         if( !szPack )
1712             return ERROR_OUTOFMEMORY;
1713     }
1714
1715     r = MsiVerifyPackageW( szPack );
1716
1717     msi_free( szPack );
1718
1719     return r;
1720 }
1721
1722 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
1723 {
1724     MSIHANDLE handle;
1725     UINT r;
1726
1727     TRACE("%s\n", debugstr_w(szPackage) );
1728
1729     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
1730     MsiCloseHandle( handle );
1731
1732     return r;
1733 }
1734
1735 static INSTALLSTATE WINAPI MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent,
1736                                                 awstring* lpPathBuf, LPDWORD pcchBuf)
1737 {
1738     WCHAR squished_pc[GUID_SIZE];
1739     WCHAR squished_comp[GUID_SIZE];
1740     HKEY hkey;
1741     LPWSTR path = NULL;
1742     INSTALLSTATE state;
1743     DWORD version;
1744
1745     static const WCHAR wininstaller[] = {
1746         'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
1747
1748     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1749            debugstr_w(szComponent), lpPathBuf->str.w, pcchBuf);
1750
1751     if (!szProduct || !szComponent)
1752         return INSTALLSTATE_INVALIDARG;
1753
1754     if (lpPathBuf->str.w && !pcchBuf)
1755         return INSTALLSTATE_INVALIDARG;
1756
1757     if (!squash_guid(szProduct, squished_pc) ||
1758         !squash_guid(szComponent, squished_comp))
1759         return INSTALLSTATE_INVALIDARG;
1760
1761     state = INSTALLSTATE_UNKNOWN;
1762
1763     if (MSIREG_OpenLocalSystemComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS ||
1764         MSIREG_OpenUserDataComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS)
1765     {
1766         path = msi_reg_get_val_str(hkey, squished_pc);
1767         RegCloseKey(hkey);
1768
1769         state = INSTALLSTATE_ABSENT;
1770
1771         if ((MSIREG_OpenLocalSystemProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS ||
1772             MSIREG_OpenUserDataProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS) &&
1773             msi_reg_get_val_dword(hkey, wininstaller, &version) &&
1774             GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
1775         {
1776             RegCloseKey(hkey);
1777             state = INSTALLSTATE_LOCAL;
1778         }
1779     }
1780
1781     if (state != INSTALLSTATE_LOCAL &&
1782         (MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS ||
1783          MSIREG_OpenLocalClassesProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS))
1784     {
1785         RegCloseKey(hkey);
1786
1787         if (MSIREG_OpenLocalSystemComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS ||
1788             MSIREG_OpenUserDataComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS)
1789         {
1790             msi_free(path);
1791             path = msi_reg_get_val_str(hkey, squished_pc);
1792             RegCloseKey(hkey);
1793
1794             state = INSTALLSTATE_ABSENT;
1795
1796             if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
1797                 state = INSTALLSTATE_LOCAL;
1798         }
1799     }
1800
1801     if (!path)
1802         return INSTALLSTATE_UNKNOWN;
1803
1804     if (state == INSTALLSTATE_LOCAL && !*path)
1805         state = INSTALLSTATE_NOTUSED;
1806
1807     msi_strcpy_to_awstring(path, lpPathBuf, pcchBuf);
1808     msi_free(path);
1809     return state;
1810 }
1811
1812 /******************************************************************
1813  * MsiGetComponentPathW      [MSI.@]
1814  */
1815 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
1816                                          LPWSTR lpPathBuf, LPDWORD pcchBuf)
1817 {
1818     awstring path;
1819
1820     path.unicode = TRUE;
1821     path.str.w = lpPathBuf;
1822
1823     return MSI_GetComponentPath( szProduct, szComponent, &path, pcchBuf );
1824 }
1825
1826 /******************************************************************
1827  * MsiGetComponentPathA      [MSI.@]
1828  */
1829 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
1830                                          LPSTR lpPathBuf, LPDWORD pcchBuf)
1831 {
1832     LPWSTR szwProduct, szwComponent = NULL;
1833     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
1834     awstring path;
1835
1836     szwProduct = strdupAtoW( szProduct );
1837     if( szProduct && !szwProduct)
1838         goto end;
1839
1840     szwComponent = strdupAtoW( szComponent );
1841     if( szComponent && !szwComponent )
1842         goto end;
1843
1844     path.unicode = FALSE;
1845     path.str.a = lpPathBuf;
1846
1847     r = MSI_GetComponentPath( szwProduct, szwComponent, &path, pcchBuf );
1848
1849 end:
1850     msi_free( szwProduct );
1851     msi_free( szwComponent );
1852
1853     return r;
1854 }
1855
1856 /******************************************************************
1857  * MsiQueryFeatureStateA      [MSI.@]
1858  */
1859 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
1860 {
1861     LPWSTR szwProduct = NULL, szwFeature= NULL;
1862     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
1863
1864     szwProduct = strdupAtoW( szProduct );
1865     if ( szProduct && !szwProduct )
1866         goto end;
1867
1868     szwFeature = strdupAtoW( szFeature );
1869     if ( szFeature && !szwFeature )
1870         goto end;
1871
1872     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
1873
1874 end:
1875     msi_free( szwProduct);
1876     msi_free( szwFeature);
1877
1878     return rc;
1879 }
1880
1881 /******************************************************************
1882  * MsiQueryFeatureStateW      [MSI.@]
1883  *
1884  * Checks the state of a feature
1885  *
1886  * PARAMS
1887  *   szProduct     [I]  Product's GUID string
1888  *   szFeature     [I]  Feature's GUID string
1889  *
1890  * RETURNS
1891  *   INSTALLSTATE_LOCAL        Feature is installed and usable
1892  *   INSTALLSTATE_ABSENT       Feature is absent
1893  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
1894  *   INSTALLSTATE_UNKNOWN      An error occurred
1895  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
1896  *
1897  */
1898 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
1899 {
1900     WCHAR squishProduct[33], comp[GUID_SIZE];
1901     GUID guid;
1902     LPWSTR components, p, parent_feature, path;
1903     UINT rc;
1904     HKEY hkey;
1905     INSTALLSTATE r;
1906     BOOL missing = FALSE;
1907     BOOL machine = FALSE;
1908     BOOL source = FALSE;
1909
1910     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1911
1912     if (!szProduct || !szFeature)
1913         return INSTALLSTATE_INVALIDARG;
1914
1915     if (!squash_guid( szProduct, squishProduct ))
1916         return INSTALLSTATE_INVALIDARG;
1917
1918     if (MSIREG_OpenManagedFeaturesKey(szProduct, &hkey, FALSE) != ERROR_SUCCESS &&
1919         MSIREG_OpenUserFeaturesKey(szProduct, &hkey, FALSE) != ERROR_SUCCESS)
1920     {
1921         rc = MSIREG_OpenLocalClassesFeaturesKey(szProduct, &hkey, FALSE);
1922         if (rc != ERROR_SUCCESS)
1923             return INSTALLSTATE_UNKNOWN;
1924
1925         machine = TRUE;
1926     }
1927
1928     parent_feature = msi_reg_get_val_str( hkey, szFeature );
1929     RegCloseKey(hkey);
1930
1931     if (!parent_feature)
1932         return INSTALLSTATE_UNKNOWN;
1933
1934     r = (parent_feature[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
1935     msi_free(parent_feature);
1936     if (r == INSTALLSTATE_ABSENT)
1937         return r;
1938
1939     if (machine)
1940         rc = MSIREG_OpenLocalUserDataFeaturesKey(szProduct, &hkey, FALSE);
1941     else
1942         rc = MSIREG_OpenUserDataFeaturesKey(szProduct, &hkey, FALSE);
1943
1944     if (rc != ERROR_SUCCESS)
1945         return INSTALLSTATE_ADVERTISED;
1946
1947     components = msi_reg_get_val_str( hkey, szFeature );
1948     RegCloseKey(hkey);
1949
1950     TRACE("rc = %d buffer = %s\n", rc, debugstr_w(components));
1951
1952     if (!components)
1953         return INSTALLSTATE_ADVERTISED;
1954
1955     for( p = components; *p && *p != 2 ; p += 20)
1956     {
1957         if (!decode_base85_guid( p, &guid ))
1958         {
1959             if (p != components)
1960                 break;
1961
1962             msi_free(components);
1963             return INSTALLSTATE_BADCONFIG;
1964         }
1965
1966         StringFromGUID2(&guid, comp, GUID_SIZE);
1967
1968         if (machine)
1969             rc = MSIREG_OpenLocalUserDataComponentKey(comp, &hkey, FALSE);
1970         else
1971             rc = MSIREG_OpenUserDataComponentKey(comp, &hkey, FALSE);
1972
1973         if (rc != ERROR_SUCCESS)
1974         {
1975             msi_free(components);
1976             return INSTALLSTATE_ADVERTISED;
1977         }
1978
1979         path = msi_reg_get_val_str(hkey, squishProduct);
1980         if (!path)
1981             missing = TRUE;
1982         else if (lstrlenW(path) > 2 &&
1983                  path[0] >= '0' && path[0] <= '9' &&
1984                  path[1] >= '0' && path[1] <= '9')
1985         {
1986             source = TRUE;
1987         }
1988
1989         msi_free(path);
1990     }
1991
1992     TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
1993     msi_free(components);
1994
1995     if (missing)
1996         return INSTALLSTATE_ADVERTISED;
1997
1998     if (source)
1999         return INSTALLSTATE_SOURCE;
2000
2001     return INSTALLSTATE_LOCAL;
2002 }
2003
2004 /******************************************************************
2005  * MsiGetFileVersionA         [MSI.@]
2006  */
2007 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
2008                 LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf)
2009 {
2010     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
2011     UINT ret = ERROR_OUTOFMEMORY;
2012
2013     if ((lpVersionBuf && !pcchVersionBuf) ||
2014         (lpLangBuf && !pcchLangBuf))
2015         return ERROR_INVALID_PARAMETER;
2016
2017     if( szFilePath )
2018     {
2019         szwFilePath = strdupAtoW( szFilePath );
2020         if( !szwFilePath )
2021             goto end;
2022     }
2023
2024     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
2025     {
2026         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
2027         if( !lpwVersionBuff )
2028             goto end;
2029     }
2030
2031     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
2032     {
2033         lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
2034         if( !lpwLangBuff )
2035             goto end;
2036     }
2037
2038     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
2039                              lpwLangBuff, pcchLangBuf);
2040
2041     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff )
2042         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
2043                             lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL);
2044     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff )
2045         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
2046                             lpLangBuf, *pcchLangBuf + 1, NULL, NULL);
2047
2048 end:
2049     msi_free(szwFilePath);
2050     msi_free(lpwVersionBuff);
2051     msi_free(lpwLangBuff);
2052
2053     return ret;
2054 }
2055
2056 /******************************************************************
2057  * MsiGetFileVersionW         [MSI.@]
2058  */
2059 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
2060                 LPDWORD pcchVersionBuf, LPWSTR lpLangBuf, LPDWORD pcchLangBuf)
2061 {
2062     static const WCHAR szVersionResource[] = {'\\',0};
2063     static const WCHAR szVersionFormat[] = {
2064         '%','d','.','%','d','.','%','d','.','%','d',0};
2065     static const WCHAR szLangResource[] = {
2066         '\\','V','a','r','F','i','l','e','I','n','f','o','\\',
2067         'T','r','a','n','s','l','a','t','i','o','n',0};
2068     static const WCHAR szLangFormat[] = {'%','d',0};
2069     UINT ret = 0;
2070     DWORD dwVerLen, gle;
2071     LPVOID lpVer = NULL;
2072     VS_FIXEDFILEINFO *ffi;
2073     USHORT *lang;
2074     UINT puLen;
2075     WCHAR tmp[32];
2076
2077     TRACE("%s %p %d %p %d\n", debugstr_w(szFilePath),
2078           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
2079           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
2080
2081     if ((lpVersionBuf && !pcchVersionBuf) ||
2082         (lpLangBuf && !pcchLangBuf))
2083         return ERROR_INVALID_PARAMETER;
2084
2085     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
2086     if( !dwVerLen )
2087     {
2088         gle = GetLastError();
2089         if (gle == ERROR_BAD_PATHNAME)
2090             return ERROR_FILE_NOT_FOUND;
2091         else if (gle == ERROR_RESOURCE_DATA_NOT_FOUND)
2092             return ERROR_FILE_INVALID;
2093
2094         return gle;
2095     }
2096
2097     lpVer = msi_alloc(dwVerLen);
2098     if( !lpVer )
2099     {
2100         ret = ERROR_OUTOFMEMORY;
2101         goto end;
2102     }
2103
2104     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
2105     {
2106         ret = GetLastError();
2107         goto end;
2108     }
2109
2110     if (pcchVersionBuf)
2111     {
2112         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
2113             (puLen > 0) )
2114         {
2115             wsprintfW(tmp, szVersionFormat,
2116                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
2117                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
2118             if (lpVersionBuf) lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
2119
2120             if (lstrlenW(tmp) >= *pcchVersionBuf)
2121                 ret = ERROR_MORE_DATA;
2122
2123             *pcchVersionBuf = lstrlenW(tmp);
2124         }
2125         else
2126         {
2127             if (lpVersionBuf) *lpVersionBuf = 0;
2128             *pcchVersionBuf = 0;
2129         }
2130     }
2131
2132     if (pcchLangBuf)
2133     {
2134         if (VerQueryValueW(lpVer, szLangResource, (LPVOID*)&lang, &puLen) &&
2135             (puLen > 0))
2136         {
2137             wsprintfW(tmp, szLangFormat, *lang);
2138             if (lpLangBuf) lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
2139
2140             if (lstrlenW(tmp) >= *pcchLangBuf)
2141                 ret = ERROR_MORE_DATA;
2142
2143             *pcchLangBuf = lstrlenW(tmp);
2144         }
2145         else
2146         {
2147             if (lpLangBuf) *lpLangBuf = 0;
2148             *pcchLangBuf = 0;
2149         }
2150     }
2151
2152 end:
2153     msi_free(lpVer);
2154     return ret;
2155 }
2156
2157 /***********************************************************************
2158  * MsiGetFeatureUsageW           [MSI.@]
2159  */
2160 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
2161                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
2162 {
2163     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
2164           pdwUseCount, pwDateUsed);
2165     return ERROR_CALL_NOT_IMPLEMENTED;
2166 }
2167
2168 /***********************************************************************
2169  * MsiGetFeatureUsageA           [MSI.@]
2170  */
2171 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
2172                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
2173 {
2174     LPWSTR prod = NULL, feat = NULL;
2175     UINT ret = ERROR_OUTOFMEMORY;
2176
2177     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
2178           pdwUseCount, pwDateUsed);
2179
2180     prod = strdupAtoW( szProduct );
2181     if (szProduct && !prod)
2182         goto end;
2183
2184     feat = strdupAtoW( szFeature );
2185     if (szFeature && !feat)
2186         goto end;
2187
2188     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
2189
2190 end:
2191     msi_free( prod );
2192     msi_free( feat );
2193
2194     return ret;
2195 }
2196
2197 /***********************************************************************
2198  * MsiUseFeatureExW           [MSI.@]
2199  */
2200 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
2201                                       DWORD dwInstallMode, DWORD dwReserved )
2202 {
2203     INSTALLSTATE state;
2204
2205     TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
2206           dwInstallMode, dwReserved);
2207
2208     state = MsiQueryFeatureStateW( szProduct, szFeature );
2209
2210     if (dwReserved)
2211         return INSTALLSTATE_INVALIDARG;
2212
2213     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
2214     {
2215         FIXME("mark product %s feature %s as used\n",
2216               debugstr_w(szProduct), debugstr_w(szFeature) );
2217     }
2218
2219     return state;
2220 }
2221
2222 /***********************************************************************
2223  * MsiUseFeatureExA           [MSI.@]
2224  */
2225 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
2226                                       DWORD dwInstallMode, DWORD dwReserved )
2227 {
2228     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
2229     LPWSTR prod = NULL, feat = NULL;
2230
2231     TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
2232           dwInstallMode, dwReserved);
2233
2234     prod = strdupAtoW( szProduct );
2235     if (szProduct && !prod)
2236         goto end;
2237
2238     feat = strdupAtoW( szFeature );
2239     if (szFeature && !feat)
2240         goto end;
2241
2242     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
2243
2244 end:
2245     msi_free( prod );
2246     msi_free( feat );
2247
2248     return ret;
2249 }
2250
2251 /***********************************************************************
2252  * MsiUseFeatureW             [MSI.@]
2253  */
2254 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
2255 {
2256     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
2257 }
2258
2259 /***********************************************************************
2260  * MsiUseFeatureA             [MSI.@]
2261  */
2262 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
2263 {
2264     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
2265 }
2266
2267 /***********************************************************************
2268  * MSI_ProvideQualifiedComponentEx [internal]
2269  */
2270 static UINT WINAPI MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
2271                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
2272                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
2273                 LPDWORD pcchPathBuf)
2274 {
2275     WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
2276           feature[MAX_FEATURE_CHARS+1];
2277     LPWSTR info;
2278     HKEY hkey;
2279     DWORD sz;
2280     UINT rc;
2281
2282     TRACE("%s %s %i %s %i %i %p %p\n", debugstr_w(szComponent),
2283           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
2284           Unused1, Unused2, lpPathBuf, pcchPathBuf);
2285
2286     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
2287     if (rc != ERROR_SUCCESS)
2288         return ERROR_INDEX_ABSENT;
2289
2290     info = msi_reg_get_val_str( hkey, szQualifier );
2291     RegCloseKey(hkey);
2292
2293     if (!info)
2294         return ERROR_INDEX_ABSENT;
2295
2296     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
2297
2298     if (!szProduct)
2299         rc = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
2300     else
2301         rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
2302
2303     msi_free( info );
2304
2305     if (rc != INSTALLSTATE_LOCAL)
2306         return ERROR_FILE_NOT_FOUND;
2307
2308     return ERROR_SUCCESS;
2309 }
2310
2311 /***********************************************************************
2312  * MsiProvideQualifiedComponentExW [MSI.@]
2313  */
2314 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
2315                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
2316                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
2317                 LPDWORD pcchPathBuf)
2318 {
2319     awstring path;
2320
2321     path.unicode = TRUE;
2322     path.str.w = lpPathBuf;
2323
2324     return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
2325             dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
2326 }
2327
2328 /***********************************************************************
2329  * MsiProvideQualifiedComponentExA [MSI.@]
2330  */
2331 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
2332                 LPCSTR szQualifier, DWORD dwInstallMode, LPCSTR szProduct,
2333                 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
2334                 LPDWORD pcchPathBuf)
2335 {
2336     LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
2337     UINT r = ERROR_OUTOFMEMORY;
2338     awstring path;
2339
2340     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
2341           debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
2342           Unused1, Unused2, lpPathBuf, pcchPathBuf);
2343
2344     szwComponent = strdupAtoW( szComponent );
2345     if (szComponent && !szwComponent)
2346         goto end;
2347
2348     szwQualifier = strdupAtoW( szQualifier );
2349     if (szQualifier && !szwQualifier)
2350         goto end;
2351
2352     szwProduct = strdupAtoW( szProduct );
2353     if (szProduct && !szwProduct)
2354         goto end;
2355
2356     path.unicode = FALSE;
2357     path.str.a = lpPathBuf;
2358
2359     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
2360                               dwInstallMode, szwProduct, Unused1,
2361                               Unused2, &path, pcchPathBuf);
2362 end:
2363     msi_free(szwProduct);
2364     msi_free(szwComponent);
2365     msi_free(szwQualifier);
2366
2367     return r;
2368 }
2369
2370 /***********************************************************************
2371  * MsiProvideQualifiedComponentW [MSI.@]
2372  */
2373 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
2374                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
2375                 LPDWORD pcchPathBuf)
2376 {
2377     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
2378                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
2379 }
2380
2381 /***********************************************************************
2382  * MsiProvideQualifiedComponentA [MSI.@]
2383  */
2384 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
2385                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
2386                 LPDWORD pcchPathBuf)
2387 {
2388     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
2389                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
2390 }
2391
2392 /***********************************************************************
2393  * MSI_GetUserInfo [internal]
2394  */
2395 static USERINFOSTATE WINAPI MSI_GetUserInfo(LPCWSTR szProduct,
2396                 awstring *lpUserNameBuf, LPDWORD pcchUserNameBuf,
2397                 awstring *lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
2398                 awstring *lpSerialBuf, LPDWORD pcchSerialBuf)
2399 {
2400     WCHAR squished_pc[SQUISH_GUID_SIZE];
2401     LPWSTR user, org, serial;
2402     USERINFOSTATE state;
2403     HKEY hkey, props;
2404     LPCWSTR orgptr;
2405     UINT r;
2406
2407     static const WCHAR szEmpty[] = {0};
2408
2409     TRACE("%s %p %p %p %p %p %p\n", debugstr_w(szProduct), lpUserNameBuf,
2410           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
2411           pcchSerialBuf);
2412
2413     if (!szProduct || !squash_guid(szProduct, squished_pc))
2414         return USERINFOSTATE_INVALIDARG;
2415
2416     if (MSIREG_OpenLocalManagedProductKey(szProduct, &hkey, FALSE) != ERROR_SUCCESS &&
2417         MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE) != ERROR_SUCCESS &&
2418         MSIREG_OpenLocalClassesProductKey(szProduct, &hkey, FALSE) != ERROR_SUCCESS)
2419     {
2420         return USERINFOSTATE_UNKNOWN;
2421     }
2422
2423     if (MSIREG_OpenCurrentUserInstallProps(szProduct, &props, FALSE) != ERROR_SUCCESS &&
2424         MSIREG_OpenLocalSystemInstallProps(szProduct, &props, FALSE) != ERROR_SUCCESS)
2425     {
2426         RegCloseKey(hkey);
2427         return USERINFOSTATE_ABSENT;
2428     }
2429
2430     user = msi_reg_get_val_str(props, INSTALLPROPERTY_REGOWNERW);
2431     org = msi_reg_get_val_str(props, INSTALLPROPERTY_REGCOMPANYW);
2432     serial = msi_reg_get_val_str(props, INSTALLPROPERTY_PRODUCTIDW);
2433     state = USERINFOSTATE_ABSENT;
2434
2435     RegCloseKey(hkey);
2436     RegCloseKey(props);
2437
2438     if (user && serial)
2439         state = USERINFOSTATE_PRESENT;
2440
2441     if (pcchUserNameBuf)
2442     {
2443         if (lpUserNameBuf && !user)
2444         {
2445             (*pcchUserNameBuf)--;
2446             goto done;
2447         }
2448
2449         r = msi_strcpy_to_awstring(user, lpUserNameBuf, pcchUserNameBuf);
2450         if (r == ERROR_MORE_DATA)
2451         {
2452             state = USERINFOSTATE_MOREDATA;
2453             goto done;
2454         }
2455     }
2456
2457     if (pcchOrgNameBuf)
2458     {
2459         orgptr = org;
2460         if (!orgptr) orgptr = szEmpty;
2461
2462         r = msi_strcpy_to_awstring(orgptr, lpOrgNameBuf, pcchOrgNameBuf);
2463         if (r == ERROR_MORE_DATA)
2464         {
2465             state = USERINFOSTATE_MOREDATA;
2466             goto done;
2467         }
2468     }
2469
2470     if (pcchSerialBuf)
2471     {
2472         if (!serial)
2473         {
2474             (*pcchSerialBuf)--;
2475             goto done;
2476         }
2477
2478         r = msi_strcpy_to_awstring(serial, lpSerialBuf, pcchSerialBuf);
2479         if (r == ERROR_MORE_DATA)
2480             state = USERINFOSTATE_MOREDATA;
2481     }
2482
2483 done:
2484     msi_free(user);
2485     msi_free(org);
2486     msi_free(serial);
2487
2488     return state;
2489 }
2490
2491 /***********************************************************************
2492  * MsiGetUserInfoW [MSI.@]
2493  */
2494 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
2495                 LPWSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
2496                 LPWSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
2497                 LPWSTR lpSerialBuf, LPDWORD pcchSerialBuf)
2498 {
2499     awstring user, org, serial;
2500
2501     if ((lpUserNameBuf && !pcchUserNameBuf) ||
2502         (lpOrgNameBuf && !pcchOrgNameBuf) ||
2503         (lpSerialBuf && !pcchSerialBuf))
2504         return USERINFOSTATE_INVALIDARG;
2505
2506     user.unicode = TRUE;
2507     user.str.w = lpUserNameBuf;
2508     org.unicode = TRUE;
2509     org.str.w = lpOrgNameBuf;
2510     serial.unicode = TRUE;
2511     serial.str.w = lpSerialBuf;
2512
2513     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
2514                             &org, pcchOrgNameBuf,
2515                             &serial, pcchSerialBuf );
2516 }
2517
2518 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
2519                 LPSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
2520                 LPSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
2521                 LPSTR lpSerialBuf, LPDWORD pcchSerialBuf)
2522 {
2523     awstring user, org, serial;
2524     LPWSTR prod;
2525     UINT r;
2526
2527     if ((lpUserNameBuf && !pcchUserNameBuf) ||
2528         (lpOrgNameBuf && !pcchOrgNameBuf) ||
2529         (lpSerialBuf && !pcchSerialBuf))
2530         return USERINFOSTATE_INVALIDARG;
2531
2532     prod = strdupAtoW( szProduct );
2533     if (szProduct && !prod)
2534         return ERROR_OUTOFMEMORY;
2535
2536     user.unicode = FALSE;
2537     user.str.a = lpUserNameBuf;
2538     org.unicode = FALSE;
2539     org.str.a = lpOrgNameBuf;
2540     serial.unicode = FALSE;
2541     serial.str.a = lpSerialBuf;
2542
2543     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
2544                          &org, pcchOrgNameBuf,
2545                          &serial, pcchSerialBuf );
2546
2547     msi_free( prod );
2548
2549     return r;
2550 }
2551
2552 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
2553 {
2554     MSIHANDLE handle;
2555     UINT rc;
2556     MSIPACKAGE *package;
2557     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
2558
2559     TRACE("(%s)\n",debugstr_w(szProduct));
2560
2561     rc = MsiOpenProductW(szProduct,&handle);
2562     if (rc != ERROR_SUCCESS)
2563         return ERROR_INVALID_PARAMETER;
2564
2565     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
2566     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
2567     msiobj_release( &package->hdr );
2568
2569     MsiCloseHandle(handle);
2570
2571     return rc;
2572 }
2573
2574 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
2575 {
2576     MSIHANDLE handle;
2577     UINT rc;
2578     MSIPACKAGE *package;
2579     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
2580
2581     TRACE("(%s)\n",debugstr_a(szProduct));
2582
2583     rc = MsiOpenProductA(szProduct,&handle);
2584     if (rc != ERROR_SUCCESS)
2585         return ERROR_INVALID_PARAMETER;
2586
2587     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
2588     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
2589     msiobj_release( &package->hdr );
2590
2591     MsiCloseHandle(handle);
2592
2593     return rc;
2594 }
2595
2596 /***********************************************************************
2597  * MsiConfigureFeatureA            [MSI.@]
2598  */
2599 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
2600 {
2601     LPWSTR prod, feat = NULL;
2602     UINT r = ERROR_OUTOFMEMORY;
2603
2604     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
2605
2606     prod = strdupAtoW( szProduct );
2607     if (szProduct && !prod)
2608         goto end;
2609
2610     feat = strdupAtoW( szFeature );
2611     if (szFeature && !feat)
2612         goto end;
2613
2614     r = MsiConfigureFeatureW(prod, feat, eInstallState);
2615
2616 end:
2617     msi_free(feat);
2618     msi_free(prod);
2619
2620     return r;
2621 }
2622
2623 /***********************************************************************
2624  * MsiConfigureFeatureW            [MSI.@]
2625  */
2626 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
2627 {
2628     static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
2629     MSIPACKAGE *package = NULL;
2630     UINT r;
2631     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
2632     DWORD sz;
2633
2634     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
2635
2636     if (!szProduct || !szFeature)
2637         return ERROR_INVALID_PARAMETER;
2638
2639     switch (eInstallState)
2640     {
2641     case INSTALLSTATE_DEFAULT:
2642         /* FIXME: how do we figure out the default location? */
2643         eInstallState = INSTALLSTATE_LOCAL;
2644         break;
2645     case INSTALLSTATE_LOCAL:
2646     case INSTALLSTATE_SOURCE:
2647     case INSTALLSTATE_ABSENT:
2648     case INSTALLSTATE_ADVERTISED:
2649         break;
2650     default:
2651         return ERROR_INVALID_PARAMETER;
2652     }
2653
2654     r = MSI_OpenProductW( szProduct, &package );
2655     if (r != ERROR_SUCCESS)
2656         return r;
2657
2658     sz = sizeof(sourcepath);
2659     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2660                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
2661
2662     sz = sizeof(filename);
2663     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2664                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
2665
2666     lstrcatW( sourcepath, filename );
2667
2668     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
2669
2670     r = ACTION_PerformUIAction( package, szCostInit, -1 );
2671     if (r != ERROR_SUCCESS)
2672         goto end;
2673
2674     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
2675     if (r != ERROR_SUCCESS)
2676         goto end;
2677
2678     r = MSI_InstallPackage( package, sourcepath, NULL );
2679
2680 end:
2681     msiobj_release( &package->hdr );
2682
2683     return r;
2684 }
2685
2686 /***********************************************************************
2687  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
2688  *
2689  * Notes: undocumented
2690  */
2691 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
2692 {
2693     WCHAR path[MAX_PATH];
2694
2695     TRACE("%d\n", dwReserved);
2696
2697     if (dwReserved)
2698     {
2699         FIXME("dwReserved=%d\n", dwReserved);
2700         return ERROR_INVALID_PARAMETER;
2701     }
2702
2703     if (!GetWindowsDirectoryW(path, MAX_PATH))
2704         return ERROR_FUNCTION_FAILED;
2705
2706     lstrcatW(path, installerW);
2707
2708     if (!CreateDirectoryW(path, NULL))
2709         return ERROR_FUNCTION_FAILED;
2710
2711     return ERROR_SUCCESS;
2712 }
2713
2714 /***********************************************************************
2715  * MsiGetShortcutTargetA           [MSI.@]
2716  */
2717 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
2718                                    LPSTR szProductCode, LPSTR szFeatureId,
2719                                    LPSTR szComponentCode )
2720 {
2721     LPWSTR target;
2722     const int len = MAX_FEATURE_CHARS+1;
2723     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
2724     UINT r;
2725
2726     target = strdupAtoW( szShortcutTarget );
2727     if (szShortcutTarget && !target )
2728         return ERROR_OUTOFMEMORY;
2729     product[0] = 0;
2730     feature[0] = 0;
2731     component[0] = 0;
2732     r = MsiGetShortcutTargetW( target, product, feature, component );
2733     msi_free( target );
2734     if (r == ERROR_SUCCESS)
2735     {
2736         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
2737         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
2738         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
2739     }
2740     return r;
2741 }
2742
2743 /***********************************************************************
2744  * MsiGetShortcutTargetW           [MSI.@]
2745  */
2746 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
2747                                    LPWSTR szProductCode, LPWSTR szFeatureId,
2748                                    LPWSTR szComponentCode )
2749 {
2750     IShellLinkDataList *dl = NULL;
2751     IPersistFile *pf = NULL;
2752     LPEXP_DARWIN_LINK darwin = NULL;
2753     HRESULT r, init;
2754
2755     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
2756           szProductCode, szFeatureId, szComponentCode );
2757
2758     init = CoInitialize(NULL);
2759
2760     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2761                           &IID_IPersistFile, (LPVOID*) &pf );
2762     if( SUCCEEDED( r ) )
2763     {
2764         r = IPersistFile_Load( pf, szShortcutTarget,
2765                                STGM_READ | STGM_SHARE_DENY_WRITE );
2766         if( SUCCEEDED( r ) )
2767         {
2768             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
2769                                              (LPVOID*) &dl );
2770             if( SUCCEEDED( r ) )
2771             {
2772                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
2773                                                   (LPVOID) &darwin );
2774                 IShellLinkDataList_Release( dl );
2775             }
2776         }
2777         IPersistFile_Release( pf );
2778     }
2779
2780     if (SUCCEEDED(init))
2781         CoUninitialize();
2782
2783     TRACE("darwin = %p\n", darwin);
2784
2785     if (darwin)
2786     {
2787         DWORD sz;
2788         UINT ret;
2789
2790         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
2791                   szProductCode, szFeatureId, szComponentCode, &sz );
2792         LocalFree( darwin );
2793         return ret;
2794     }
2795
2796     return ERROR_FUNCTION_FAILED;
2797 }
2798
2799 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
2800                                   DWORD dwReinstallMode )
2801 {
2802     MSIPACKAGE* package = NULL;
2803     UINT r;
2804     WCHAR sourcepath[MAX_PATH];
2805     WCHAR filename[MAX_PATH];
2806     static const WCHAR szLogVerbose[] = {
2807         ' ','L','O','G','V','E','R','B','O','S','E',0 };
2808     static const WCHAR szInstalled[] = { 'I','n','s','t','a','l','l','e','d',0};
2809     static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0};
2810     static const WCHAR szReinstallMode[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
2811     static const WCHAR szOne[] = {'1',0};
2812     WCHAR reinstallmode[11];
2813     LPWSTR ptr;
2814     DWORD sz;
2815
2816     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
2817                            dwReinstallMode);
2818
2819     ptr = reinstallmode;
2820
2821     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
2822         *ptr++ = 'p';
2823     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
2824         *ptr++ = 'o';
2825     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
2826         *ptr++ = 'w';
2827     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
2828         *ptr++ = 'd';
2829     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
2830         *ptr++ = 'c';
2831     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
2832         *ptr++ = 'a';
2833     if (dwReinstallMode & REINSTALLMODE_USERDATA)
2834         *ptr++ = 'u';
2835     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
2836         *ptr++ = 'm';
2837     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
2838         *ptr++ = 's';
2839     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2840         *ptr++ = 'v';
2841     *ptr = 0;
2842     
2843     sz = sizeof(sourcepath);
2844     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2845             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
2846
2847     sz = sizeof(filename);
2848     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2849             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
2850
2851     lstrcatW( sourcepath, filename );
2852
2853     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2854         r = MSI_OpenPackageW( sourcepath, &package );
2855     else
2856         r = MSI_OpenProductW( szProduct, &package );
2857
2858     if (r != ERROR_SUCCESS)
2859         return r;
2860
2861     MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
2862     MSI_SetPropertyW( package, szInstalled, szOne );
2863     MSI_SetPropertyW( package, szLogVerbose, szOne );
2864     MSI_SetPropertyW( package, szReinstall, szFeature );
2865
2866     r = MSI_InstallPackage( package, sourcepath, NULL );
2867
2868     msiobj_release( &package->hdr );
2869
2870     return r;
2871 }
2872
2873 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
2874                                   DWORD dwReinstallMode )
2875 {
2876     LPWSTR wszProduct;
2877     LPWSTR wszFeature;
2878     UINT rc;
2879
2880     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
2881                            dwReinstallMode);
2882
2883     wszProduct = strdupAtoW(szProduct);
2884     wszFeature = strdupAtoW(szFeature);
2885
2886     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
2887
2888     msi_free(wszProduct);
2889     msi_free(wszFeature);
2890     return rc;
2891 }
2892
2893 typedef struct
2894 {
2895     unsigned int i[2];
2896     unsigned int buf[4];
2897     unsigned char in[64];
2898     unsigned char digest[16];
2899 } MD5_CTX;
2900
2901 extern VOID WINAPI MD5Init( MD5_CTX *);
2902 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
2903 extern VOID WINAPI MD5Final( MD5_CTX *);
2904
2905 /***********************************************************************
2906  * MsiGetFileHashW            [MSI.@]
2907  */
2908 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
2909                              PMSIFILEHASHINFO pHash )
2910 {
2911     HANDLE handle, mapping;
2912     void *p;
2913     DWORD length;
2914     UINT r = ERROR_FUNCTION_FAILED;
2915
2916     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
2917
2918     if (!szFilePath)
2919         return ERROR_INVALID_PARAMETER;
2920
2921     if (!*szFilePath)
2922         return ERROR_PATH_NOT_FOUND;
2923
2924     if (dwOptions)
2925         return ERROR_INVALID_PARAMETER;
2926     if (!pHash)
2927         return ERROR_INVALID_PARAMETER;
2928     if (pHash->dwFileHashInfoSize < sizeof *pHash)
2929         return ERROR_INVALID_PARAMETER;
2930
2931     handle = CreateFileW( szFilePath, GENERIC_READ,
2932                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
2933     if (handle == INVALID_HANDLE_VALUE)
2934         return ERROR_FILE_NOT_FOUND;
2935
2936     length = GetFileSize( handle, NULL );
2937
2938     mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
2939     if (mapping)
2940     {
2941         p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
2942         if (p)
2943         {
2944             MD5_CTX ctx;
2945
2946             MD5Init( &ctx );
2947             MD5Update( &ctx, p, length );
2948             MD5Final( &ctx );
2949             UnmapViewOfFile( p );
2950
2951             memcpy( pHash->dwData, ctx.digest, sizeof pHash->dwData );
2952             r = ERROR_SUCCESS;
2953         }
2954         CloseHandle( mapping );
2955     }
2956     CloseHandle( handle );
2957
2958     return r;
2959 }
2960
2961 /***********************************************************************
2962  * MsiGetFileHashA            [MSI.@]
2963  */
2964 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
2965                              PMSIFILEHASHINFO pHash )
2966 {
2967     LPWSTR file;
2968     UINT r;
2969
2970     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
2971
2972     file = strdupAtoW( szFilePath );
2973     if (szFilePath && !file)
2974         return ERROR_OUTOFMEMORY;
2975
2976     r = MsiGetFileHashW( file, dwOptions, pHash );
2977     msi_free( file );
2978     return r;
2979 }
2980
2981 /***********************************************************************
2982  * MsiAdvertiseScriptW        [MSI.@]
2983  */
2984 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
2985                                  PHKEY phRegData, BOOL fRemoveItems )
2986 {
2987     FIXME("%s %08x %p %d\n",
2988           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2989     return ERROR_CALL_NOT_IMPLEMENTED;
2990 }
2991
2992 /***********************************************************************
2993  * MsiAdvertiseScriptA        [MSI.@]
2994  */
2995 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
2996                                  PHKEY phRegData, BOOL fRemoveItems )
2997 {
2998     FIXME("%s %08x %p %d\n",
2999           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
3000     return ERROR_CALL_NOT_IMPLEMENTED;
3001 }
3002
3003 /***********************************************************************
3004  * MsiIsProductElevatedW        [MSI.@]
3005  */
3006 UINT WINAPI MsiIsProductElevatedW( LPCWSTR szProduct, BOOL *pfElevated )
3007 {
3008     FIXME("%s %p - stub\n",
3009           debugstr_w( szProduct ), pfElevated );
3010     *pfElevated = TRUE;
3011     return ERROR_SUCCESS;
3012 }
3013
3014 /***********************************************************************
3015  * MsiIsProductElevatedA        [MSI.@]
3016  */
3017 UINT WINAPI MsiIsProductElevatedA( LPCSTR szProduct, BOOL *pfElevated )
3018 {
3019     FIXME("%s %p - stub\n",
3020           debugstr_a( szProduct ), pfElevated );
3021     *pfElevated = TRUE;
3022     return ERROR_SUCCESS;
3023 }