crypt32: Use CMS messages rather than PKCS messages internally.
[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, 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     *sz = 0;
1317     res = RegQueryValueExW(hkey, squished_pc, NULL, NULL, NULL, sz);
1318     if (res != ERROR_SUCCESS)
1319         return FALSE;
1320
1321     RegCloseKey(hkey);
1322     return TRUE;
1323 }
1324
1325 UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode,
1326                                     LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1327                                     LPCWSTR szComponent, INSTALLSTATE *pdwState)
1328 {
1329     WCHAR squished_pc[GUID_SIZE];
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     if (!msi_comp_find_prodcode(squished_pc, dwContext, szComponent, &sz))
1361         return ERROR_UNKNOWN_COMPONENT;
1362
1363     if (sz == 0)
1364         *pdwState = INSTALLSTATE_NOTUSED;
1365     else
1366         *pdwState = INSTALLSTATE_LOCAL;
1367
1368     return ERROR_SUCCESS;
1369 }
1370
1371 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
1372 {
1373     LPWSTR szwProduct = NULL;
1374     INSTALLSTATE r;
1375
1376     if( szProduct )
1377     {
1378          szwProduct = strdupAtoW( szProduct );
1379          if( !szwProduct )
1380              return ERROR_OUTOFMEMORY;
1381     }
1382     r = MsiQueryProductStateW( szwProduct );
1383     msi_free( szwProduct );
1384     return r;
1385 }
1386
1387 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
1388 {
1389     INSTALLSTATE state = INSTALLSTATE_ADVERTISED;
1390     HKEY prodkey = 0, userdata = 0;
1391     BOOL user = TRUE;
1392     DWORD val;
1393     UINT r;
1394
1395     static const WCHAR szWindowsInstaller[] = {
1396         'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
1397
1398     TRACE("%s\n", debugstr_w(szProduct));
1399
1400     if (!szProduct || !*szProduct)
1401         return INSTALLSTATE_INVALIDARG;
1402
1403     if (lstrlenW(szProduct) != GUID_SIZE - 1)
1404         return INSTALLSTATE_INVALIDARG;
1405
1406     r = MSIREG_OpenLocalManagedProductKey(szProduct, &prodkey, FALSE);
1407     if (r != ERROR_SUCCESS)
1408     {
1409         r = MSIREG_OpenUserProductsKey(szProduct, &prodkey, FALSE);
1410         if (r != ERROR_SUCCESS)
1411         {
1412             r = MSIREG_OpenLocalClassesProductKey(szProduct, &prodkey, FALSE);
1413             if (r == ERROR_SUCCESS)
1414                user = FALSE;
1415         }
1416     }
1417
1418     if (user)
1419     {
1420         r = MSIREG_OpenCurrentUserInstallProps(szProduct, &userdata, FALSE);
1421         if (r != ERROR_SUCCESS)
1422             goto done;
1423     }
1424     else
1425     {
1426         r = MSIREG_OpenLocalSystemInstallProps(szProduct, &userdata, FALSE);
1427         if (r != ERROR_SUCCESS)
1428             goto done;
1429     }
1430
1431     if (!msi_reg_get_val_dword(userdata, szWindowsInstaller, &val))
1432         goto done;
1433
1434     if (val)
1435         state = INSTALLSTATE_DEFAULT;
1436     else
1437         state = INSTALLSTATE_UNKNOWN;
1438
1439 done:
1440     if (!prodkey)
1441     {
1442         state = INSTALLSTATE_UNKNOWN;
1443
1444         if (userdata)
1445             state = INSTALLSTATE_ABSENT;
1446     }
1447
1448     RegCloseKey(prodkey);
1449     RegCloseKey(userdata);
1450     return state;
1451 }
1452
1453 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
1454 {
1455     INSTALLUILEVEL old = gUILevel;
1456     HWND oldwnd = gUIhwnd;
1457
1458     TRACE("%08x %p\n", dwUILevel, phWnd);
1459
1460     gUILevel = dwUILevel;
1461     if (phWnd)
1462     {
1463         gUIhwnd = *phWnd;
1464         *phWnd = oldwnd;
1465     }
1466     return old;
1467 }
1468
1469 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
1470                                   DWORD dwMessageFilter, LPVOID pvContext)
1471 {
1472     INSTALLUI_HANDLERA prev = gUIHandlerA;
1473
1474     TRACE("%p %x %p\n",puiHandler, dwMessageFilter,pvContext);
1475     gUIHandlerA = puiHandler;
1476     gUIFilter = dwMessageFilter;
1477     gUIContext = pvContext;
1478
1479     return prev;
1480 }
1481
1482 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
1483                                   DWORD dwMessageFilter, LPVOID pvContext)
1484 {
1485     INSTALLUI_HANDLERW prev = gUIHandlerW;
1486
1487     TRACE("%p %x %p\n",puiHandler,dwMessageFilter,pvContext);
1488     gUIHandlerW = puiHandler;
1489     gUIFilter = dwMessageFilter;
1490     gUIContext = pvContext;
1491
1492     return prev;
1493 }
1494
1495 /******************************************************************
1496  *  MsiLoadStringW            [MSI.@]
1497  *
1498  * Loads a string from MSI's string resources.
1499  *
1500  * PARAMS
1501  *
1502  *   handle        [I]  only -1 is handled currently
1503  *   id            [I]  id of the string to be loaded
1504  *   lpBuffer      [O]  buffer for the string to be written to
1505  *   nBufferMax    [I]  maximum size of the buffer in characters
1506  *   lang          [I]  the preferred language for the string
1507  *
1508  * RETURNS
1509  *
1510  *   If successful, this function returns the language id of the string loaded
1511  *   If the function fails, the function returns zero.
1512  *
1513  * NOTES
1514  *
1515  *   The type of the first parameter is unknown.  LoadString's prototype
1516  *  suggests that it might be a module handle.  I have made it an MSI handle
1517  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
1518  *  handle.  Maybe strings can be stored in an MSI database somehow.
1519  */
1520 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
1521                 int nBufferMax, LANGID lang )
1522 {
1523     HRSRC hres;
1524     HGLOBAL hResData;
1525     LPWSTR p;
1526     DWORD i, len;
1527
1528     TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
1529
1530     if( handle != -1 )
1531         FIXME("don't know how to deal with handle = %08lx\n", handle);
1532
1533     if( !lang )
1534         lang = GetUserDefaultLangID();
1535
1536     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
1537                             (LPWSTR)1, lang );
1538     if( !hres )
1539         return 0;
1540     hResData = LoadResource( msi_hInstance, hres );
1541     if( !hResData )
1542         return 0;
1543     p = LockResource( hResData );
1544     if( !p )
1545         return 0;
1546
1547     for (i = 0; i < (id&0xf); i++)
1548         p += *p + 1;
1549     len = *p;
1550
1551     if( nBufferMax <= len )
1552         return 0;
1553
1554     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
1555     lpBuffer[ len ] = 0;
1556
1557     TRACE("found -> %s\n", debugstr_w(lpBuffer));
1558
1559     return lang;
1560 }
1561
1562 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
1563                 int nBufferMax, LANGID lang )
1564 {
1565     LPWSTR bufW;
1566     LANGID r;
1567     DWORD len;
1568
1569     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
1570     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
1571     if( r )
1572     {
1573         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
1574         if( len <= nBufferMax )
1575             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
1576                                  lpBuffer, nBufferMax, NULL, NULL );
1577         else
1578             r = 0;
1579     }
1580     msi_free(bufW);
1581     return r;
1582 }
1583
1584 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
1585                 LPDWORD pcchBuf)
1586 {
1587     char szProduct[GUID_SIZE];
1588
1589     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
1590
1591     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
1592         return INSTALLSTATE_UNKNOWN;
1593
1594     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
1595 }
1596
1597 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
1598                 LPDWORD pcchBuf)
1599 {
1600     WCHAR szProduct[GUID_SIZE];
1601
1602     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
1603
1604     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
1605         return INSTALLSTATE_UNKNOWN;
1606
1607     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
1608 }
1609
1610 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
1611                 WORD wLanguageId, DWORD f)
1612 {
1613     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption),
1614           uType, wLanguageId, f);
1615     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
1616 }
1617
1618 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
1619                 WORD wLanguageId, DWORD f)
1620 {
1621     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption),
1622           uType, wLanguageId, f);
1623     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
1624 }
1625
1626 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
1627                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
1628                 LPDWORD pcchPathBuf )
1629 {
1630     FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
1631           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
1632           pcchPathBuf);
1633     return ERROR_CALL_NOT_IMPLEMENTED;
1634 }
1635
1636 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
1637                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
1638                 LPDWORD pcchPathBuf )
1639 {
1640     FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
1641           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
1642           pcchPathBuf);
1643     return ERROR_CALL_NOT_IMPLEMENTED;
1644 }
1645
1646 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
1647                 LPSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
1648 {
1649     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
1650     return ERROR_CALL_NOT_IMPLEMENTED;
1651 }
1652
1653 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
1654                 LPWSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
1655 {
1656     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
1657     return ERROR_CALL_NOT_IMPLEMENTED;
1658 }
1659
1660 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
1661                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
1662                 LPDWORD pcbHashData)
1663 {
1664     FIXME("%s %08x %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
1665           ppcCertContext, pbHashData, pcbHashData);
1666     return ERROR_CALL_NOT_IMPLEMENTED;
1667 }
1668
1669 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
1670                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
1671                 LPDWORD pcbHashData)
1672 {
1673     FIXME("%s %08x %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
1674           ppcCertContext, pbHashData, pcbHashData);
1675     return ERROR_CALL_NOT_IMPLEMENTED;
1676 }
1677
1678 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
1679                                     LPSTR szValue, LPDWORD pccbValue )
1680 {
1681     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
1682     return ERROR_CALL_NOT_IMPLEMENTED;
1683 }
1684
1685 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
1686                                     LPWSTR szValue, LPDWORD pccbValue )
1687 {
1688     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
1689     return ERROR_CALL_NOT_IMPLEMENTED;
1690 }
1691
1692 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
1693 {
1694     UINT r;
1695     LPWSTR szPack = NULL;
1696
1697     TRACE("%s\n", debugstr_a(szPackage) );
1698
1699     if( szPackage )
1700     {
1701         szPack = strdupAtoW( szPackage );
1702         if( !szPack )
1703             return ERROR_OUTOFMEMORY;
1704     }
1705
1706     r = MsiVerifyPackageW( szPack );
1707
1708     msi_free( szPack );
1709
1710     return r;
1711 }
1712
1713 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
1714 {
1715     MSIHANDLE handle;
1716     UINT r;
1717
1718     TRACE("%s\n", debugstr_w(szPackage) );
1719
1720     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
1721     MsiCloseHandle( handle );
1722
1723     return r;
1724 }
1725
1726 static INSTALLSTATE WINAPI MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent,
1727                                                 awstring* lpPathBuf, LPDWORD pcchBuf)
1728 {
1729     WCHAR squished_pc[GUID_SIZE];
1730     WCHAR squished_comp[GUID_SIZE];
1731     HKEY hkey;
1732     LPWSTR path = NULL;
1733     INSTALLSTATE state;
1734     DWORD version;
1735
1736     static const WCHAR wininstaller[] = {
1737         'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
1738
1739     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1740            debugstr_w(szComponent), lpPathBuf->str.w, pcchBuf);
1741
1742     if (!szProduct || !szComponent)
1743         return INSTALLSTATE_INVALIDARG;
1744
1745     if (lpPathBuf->str.w && !pcchBuf)
1746         return INSTALLSTATE_INVALIDARG;
1747
1748     if (!squash_guid(szProduct, squished_pc) ||
1749         !squash_guid(szComponent, squished_comp))
1750         return INSTALLSTATE_INVALIDARG;
1751
1752     state = INSTALLSTATE_UNKNOWN;
1753
1754     if (MSIREG_OpenLocalSystemComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS ||
1755         MSIREG_OpenUserDataComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS)
1756     {
1757         path = msi_reg_get_val_str(hkey, squished_pc);
1758         RegCloseKey(hkey);
1759
1760         state = INSTALLSTATE_ABSENT;
1761
1762         if ((MSIREG_OpenLocalSystemProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS ||
1763             MSIREG_OpenUserDataProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS) &&
1764             msi_reg_get_val_dword(hkey, wininstaller, &version) &&
1765             GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
1766         {
1767             RegCloseKey(hkey);
1768             state = INSTALLSTATE_LOCAL;
1769         }
1770     }
1771
1772     if (state != INSTALLSTATE_LOCAL &&
1773         (MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS ||
1774          MSIREG_OpenLocalClassesProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS))
1775     {
1776         RegCloseKey(hkey);
1777
1778         if (MSIREG_OpenLocalSystemComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS ||
1779             MSIREG_OpenUserDataComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS)
1780         {
1781             msi_free(path);
1782             path = msi_reg_get_val_str(hkey, squished_pc);
1783             RegCloseKey(hkey);
1784
1785             state = INSTALLSTATE_ABSENT;
1786
1787             if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
1788                 state = INSTALLSTATE_LOCAL;
1789         }
1790     }
1791
1792     if (!path)
1793         return INSTALLSTATE_UNKNOWN;
1794
1795     if (state == INSTALLSTATE_LOCAL && !*path)
1796         state = INSTALLSTATE_NOTUSED;
1797
1798     msi_strcpy_to_awstring(path, lpPathBuf, pcchBuf);
1799     msi_free(path);
1800     return state;
1801 }
1802
1803 /******************************************************************
1804  * MsiGetComponentPathW      [MSI.@]
1805  */
1806 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
1807                                          LPWSTR lpPathBuf, LPDWORD pcchBuf)
1808 {
1809     awstring path;
1810
1811     path.unicode = TRUE;
1812     path.str.w = lpPathBuf;
1813
1814     return MSI_GetComponentPath( szProduct, szComponent, &path, pcchBuf );
1815 }
1816
1817 /******************************************************************
1818  * MsiGetComponentPathA      [MSI.@]
1819  */
1820 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
1821                                          LPSTR lpPathBuf, LPDWORD pcchBuf)
1822 {
1823     LPWSTR szwProduct, szwComponent = NULL;
1824     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
1825     awstring path;
1826
1827     szwProduct = strdupAtoW( szProduct );
1828     if( szProduct && !szwProduct)
1829         goto end;
1830
1831     szwComponent = strdupAtoW( szComponent );
1832     if( szComponent && !szwComponent )
1833         goto end;
1834
1835     path.unicode = FALSE;
1836     path.str.a = lpPathBuf;
1837
1838     r = MSI_GetComponentPath( szwProduct, szwComponent, &path, pcchBuf );
1839
1840 end:
1841     msi_free( szwProduct );
1842     msi_free( szwComponent );
1843
1844     return r;
1845 }
1846
1847 /******************************************************************
1848  * MsiQueryFeatureStateA      [MSI.@]
1849  */
1850 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
1851 {
1852     LPWSTR szwProduct = NULL, szwFeature= NULL;
1853     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
1854
1855     szwProduct = strdupAtoW( szProduct );
1856     if ( szProduct && !szwProduct )
1857         goto end;
1858
1859     szwFeature = strdupAtoW( szFeature );
1860     if ( szFeature && !szwFeature )
1861         goto end;
1862
1863     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
1864
1865 end:
1866     msi_free( szwProduct);
1867     msi_free( szwFeature);
1868
1869     return rc;
1870 }
1871
1872 /******************************************************************
1873  * MsiQueryFeatureStateW      [MSI.@]
1874  *
1875  * Checks the state of a feature
1876  *
1877  * PARAMS
1878  *   szProduct     [I]  Product's GUID string
1879  *   szFeature     [I]  Feature's GUID string
1880  *
1881  * RETURNS
1882  *   INSTALLSTATE_LOCAL        Feature is installed and usable
1883  *   INSTALLSTATE_ABSENT       Feature is absent
1884  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
1885  *   INSTALLSTATE_UNKNOWN      An error occurred
1886  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
1887  *
1888  */
1889 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
1890 {
1891     WCHAR squishProduct[33], comp[GUID_SIZE];
1892     GUID guid;
1893     LPWSTR components, p, parent_feature, path;
1894     UINT rc;
1895     HKEY hkey;
1896     INSTALLSTATE r;
1897     BOOL missing = FALSE;
1898     BOOL machine = FALSE;
1899
1900     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1901
1902     if (!szProduct || !szFeature)
1903         return INSTALLSTATE_INVALIDARG;
1904
1905     if (!squash_guid( szProduct, squishProduct ))
1906         return INSTALLSTATE_INVALIDARG;
1907
1908     if (MSIREG_OpenManagedFeaturesKey(szProduct, &hkey, FALSE) != ERROR_SUCCESS &&
1909         MSIREG_OpenUserFeaturesKey(szProduct, &hkey, FALSE) != ERROR_SUCCESS)
1910     {
1911         rc = MSIREG_OpenLocalClassesFeaturesKey(szProduct, &hkey, FALSE);
1912         if (rc != ERROR_SUCCESS)
1913             return INSTALLSTATE_UNKNOWN;
1914
1915         machine = TRUE;
1916     }
1917
1918     parent_feature = msi_reg_get_val_str( hkey, szFeature );
1919     RegCloseKey(hkey);
1920
1921     if (!parent_feature)
1922         return INSTALLSTATE_UNKNOWN;
1923
1924     r = (parent_feature[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
1925     msi_free(parent_feature);
1926     if (r == INSTALLSTATE_ABSENT)
1927         return r;
1928
1929     if (machine)
1930         rc = MSIREG_OpenLocalUserDataFeaturesKey(szProduct, &hkey, FALSE);
1931     else
1932         rc = MSIREG_OpenUserDataFeaturesKey(szProduct, &hkey, FALSE);
1933
1934     if (rc != ERROR_SUCCESS)
1935         return INSTALLSTATE_ADVERTISED;
1936
1937     components = msi_reg_get_val_str( hkey, szFeature );
1938     RegCloseKey(hkey);
1939
1940     TRACE("rc = %d buffer = %s\n", rc, debugstr_w(components));
1941
1942     if (!components)
1943         return INSTALLSTATE_ADVERTISED;
1944
1945     for( p = components; *p && *p != 2 ; p += 20)
1946     {
1947         if (!decode_base85_guid( p, &guid ))
1948         {
1949             if (p != components)
1950                 break;
1951
1952             msi_free(components);
1953             return INSTALLSTATE_BADCONFIG;
1954         }
1955
1956         StringFromGUID2(&guid, comp, GUID_SIZE);
1957
1958         if (machine)
1959             rc = MSIREG_OpenLocalUserDataComponentKey(comp, &hkey, FALSE);
1960         else
1961             rc = MSIREG_OpenUserDataComponentKey(comp, &hkey, FALSE);
1962
1963         if (rc != ERROR_SUCCESS)
1964         {
1965             msi_free(components);
1966             return INSTALLSTATE_ADVERTISED;
1967         }
1968
1969         path = msi_reg_get_val_str(hkey, squishProduct);
1970         if (!path)
1971             missing = TRUE;
1972
1973         msi_free(path);
1974     }
1975
1976     TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
1977     msi_free(components);
1978
1979     if (missing)
1980         return INSTALLSTATE_ADVERTISED;
1981
1982     return INSTALLSTATE_LOCAL;
1983 }
1984
1985 /******************************************************************
1986  * MsiGetFileVersionA         [MSI.@]
1987  */
1988 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
1989                 LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf)
1990 {
1991     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
1992     UINT ret = ERROR_OUTOFMEMORY;
1993
1994     if ((lpVersionBuf && !pcchVersionBuf) ||
1995         (lpLangBuf && !pcchLangBuf))
1996         return ERROR_INVALID_PARAMETER;
1997
1998     if( szFilePath )
1999     {
2000         szwFilePath = strdupAtoW( szFilePath );
2001         if( !szwFilePath )
2002             goto end;
2003     }
2004
2005     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
2006     {
2007         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
2008         if( !lpwVersionBuff )
2009             goto end;
2010     }
2011
2012     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
2013     {
2014         lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
2015         if( !lpwLangBuff )
2016             goto end;
2017     }
2018
2019     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
2020                              lpwLangBuff, pcchLangBuf);
2021
2022     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff )
2023         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
2024                             lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL);
2025     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff )
2026         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
2027                             lpLangBuf, *pcchLangBuf + 1, NULL, NULL);
2028
2029 end:
2030     msi_free(szwFilePath);
2031     msi_free(lpwVersionBuff);
2032     msi_free(lpwLangBuff);
2033
2034     return ret;
2035 }
2036
2037 /******************************************************************
2038  * MsiGetFileVersionW         [MSI.@]
2039  */
2040 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
2041                 LPDWORD pcchVersionBuf, LPWSTR lpLangBuf, LPDWORD pcchLangBuf)
2042 {
2043     static const WCHAR szVersionResource[] = {'\\',0};
2044     static const WCHAR szVersionFormat[] = {
2045         '%','d','.','%','d','.','%','d','.','%','d',0};
2046     static const WCHAR szLangResource[] = {
2047         '\\','V','a','r','F','i','l','e','I','n','f','o','\\',
2048         'T','r','a','n','s','l','a','t','i','o','n',0};
2049     static const WCHAR szLangFormat[] = {'%','d',0};
2050     UINT ret = 0;
2051     DWORD dwVerLen, gle;
2052     LPVOID lpVer = NULL;
2053     VS_FIXEDFILEINFO *ffi;
2054     USHORT *lang;
2055     UINT puLen;
2056     WCHAR tmp[32];
2057
2058     TRACE("%s %p %d %p %d\n", debugstr_w(szFilePath),
2059           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
2060           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
2061
2062     if ((lpVersionBuf && !pcchVersionBuf) ||
2063         (lpLangBuf && !pcchLangBuf))
2064         return ERROR_INVALID_PARAMETER;
2065
2066     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
2067     if( !dwVerLen )
2068     {
2069         gle = GetLastError();
2070         if (gle == ERROR_BAD_PATHNAME)
2071             return ERROR_FILE_NOT_FOUND;
2072         else if (gle == ERROR_RESOURCE_DATA_NOT_FOUND)
2073             return ERROR_FILE_INVALID;
2074
2075         return gle;
2076     }
2077
2078     lpVer = msi_alloc(dwVerLen);
2079     if( !lpVer )
2080     {
2081         ret = ERROR_OUTOFMEMORY;
2082         goto end;
2083     }
2084
2085     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
2086     {
2087         ret = GetLastError();
2088         goto end;
2089     }
2090
2091     if (pcchVersionBuf)
2092     {
2093         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
2094             (puLen > 0) )
2095         {
2096             wsprintfW(tmp, szVersionFormat,
2097                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
2098                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
2099             if (lpVersionBuf) lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
2100
2101             if (lstrlenW(tmp) >= *pcchVersionBuf)
2102                 ret = ERROR_MORE_DATA;
2103
2104             *pcchVersionBuf = lstrlenW(tmp);
2105         }
2106         else
2107         {
2108             if (lpVersionBuf) *lpVersionBuf = 0;
2109             *pcchVersionBuf = 0;
2110         }
2111     }
2112
2113     if (pcchLangBuf)
2114     {
2115         if (VerQueryValueW(lpVer, szLangResource, (LPVOID*)&lang, &puLen) &&
2116             (puLen > 0))
2117         {
2118             wsprintfW(tmp, szLangFormat, *lang);
2119             if (lpLangBuf) lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
2120
2121             if (lstrlenW(tmp) >= *pcchLangBuf)
2122                 ret = ERROR_MORE_DATA;
2123
2124             *pcchLangBuf = lstrlenW(tmp);
2125         }
2126         else
2127         {
2128             if (lpLangBuf) *lpLangBuf = 0;
2129             *pcchLangBuf = 0;
2130         }
2131     }
2132
2133 end:
2134     msi_free(lpVer);
2135     return ret;
2136 }
2137
2138 /***********************************************************************
2139  * MsiGetFeatureUsageW           [MSI.@]
2140  */
2141 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
2142                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
2143 {
2144     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
2145           pdwUseCount, pwDateUsed);
2146     return ERROR_CALL_NOT_IMPLEMENTED;
2147 }
2148
2149 /***********************************************************************
2150  * MsiGetFeatureUsageA           [MSI.@]
2151  */
2152 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
2153                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
2154 {
2155     LPWSTR prod = NULL, feat = NULL;
2156     UINT ret = ERROR_OUTOFMEMORY;
2157
2158     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
2159           pdwUseCount, pwDateUsed);
2160
2161     prod = strdupAtoW( szProduct );
2162     if (szProduct && !prod)
2163         goto end;
2164
2165     feat = strdupAtoW( szFeature );
2166     if (szFeature && !feat)
2167         goto end;
2168
2169     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
2170
2171 end:
2172     msi_free( prod );
2173     msi_free( feat );
2174
2175     return ret;
2176 }
2177
2178 /***********************************************************************
2179  * MsiUseFeatureExW           [MSI.@]
2180  */
2181 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
2182                                       DWORD dwInstallMode, DWORD dwReserved )
2183 {
2184     INSTALLSTATE state;
2185
2186     TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
2187           dwInstallMode, dwReserved);
2188
2189     state = MsiQueryFeatureStateW( szProduct, szFeature );
2190
2191     if (dwReserved)
2192         return INSTALLSTATE_INVALIDARG;
2193
2194     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
2195     {
2196         FIXME("mark product %s feature %s as used\n",
2197               debugstr_w(szProduct), debugstr_w(szFeature) );
2198     }
2199
2200     return state;
2201 }
2202
2203 /***********************************************************************
2204  * MsiUseFeatureExA           [MSI.@]
2205  */
2206 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
2207                                       DWORD dwInstallMode, DWORD dwReserved )
2208 {
2209     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
2210     LPWSTR prod = NULL, feat = NULL;
2211
2212     TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
2213           dwInstallMode, dwReserved);
2214
2215     prod = strdupAtoW( szProduct );
2216     if (szProduct && !prod)
2217         goto end;
2218
2219     feat = strdupAtoW( szFeature );
2220     if (szFeature && !feat)
2221         goto end;
2222
2223     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
2224
2225 end:
2226     msi_free( prod );
2227     msi_free( feat );
2228
2229     return ret;
2230 }
2231
2232 /***********************************************************************
2233  * MsiUseFeatureW             [MSI.@]
2234  */
2235 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
2236 {
2237     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
2238 }
2239
2240 /***********************************************************************
2241  * MsiUseFeatureA             [MSI.@]
2242  */
2243 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
2244 {
2245     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
2246 }
2247
2248 /***********************************************************************
2249  * MSI_ProvideQualifiedComponentEx [internal]
2250  */
2251 static UINT WINAPI MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
2252                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
2253                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
2254                 LPDWORD pcchPathBuf)
2255 {
2256     WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
2257           feature[MAX_FEATURE_CHARS+1];
2258     LPWSTR info;
2259     HKEY hkey;
2260     DWORD sz;
2261     UINT rc;
2262
2263     TRACE("%s %s %i %s %i %i %p %p\n", debugstr_w(szComponent),
2264           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
2265           Unused1, Unused2, lpPathBuf, pcchPathBuf);
2266
2267     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
2268     if (rc != ERROR_SUCCESS)
2269         return ERROR_INDEX_ABSENT;
2270
2271     info = msi_reg_get_val_str( hkey, szQualifier );
2272     RegCloseKey(hkey);
2273
2274     if (!info)
2275         return ERROR_INDEX_ABSENT;
2276
2277     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
2278
2279     if (!szProduct)
2280         rc = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
2281     else
2282         rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
2283
2284     msi_free( info );
2285
2286     if (rc != INSTALLSTATE_LOCAL)
2287         return ERROR_FILE_NOT_FOUND;
2288
2289     return ERROR_SUCCESS;
2290 }
2291
2292 /***********************************************************************
2293  * MsiProvideQualifiedComponentExW [MSI.@]
2294  */
2295 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
2296                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
2297                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
2298                 LPDWORD pcchPathBuf)
2299 {
2300     awstring path;
2301
2302     path.unicode = TRUE;
2303     path.str.w = lpPathBuf;
2304
2305     return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
2306             dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
2307 }
2308
2309 /***********************************************************************
2310  * MsiProvideQualifiedComponentExA [MSI.@]
2311  */
2312 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
2313                 LPCSTR szQualifier, DWORD dwInstallMode, LPCSTR szProduct,
2314                 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
2315                 LPDWORD pcchPathBuf)
2316 {
2317     LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
2318     UINT r = ERROR_OUTOFMEMORY;
2319     awstring path;
2320
2321     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
2322           debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
2323           Unused1, Unused2, lpPathBuf, pcchPathBuf);
2324
2325     szwComponent = strdupAtoW( szComponent );
2326     if (szComponent && !szwComponent)
2327         goto end;
2328
2329     szwQualifier = strdupAtoW( szQualifier );
2330     if (szQualifier && !szwQualifier)
2331         goto end;
2332
2333     szwProduct = strdupAtoW( szProduct );
2334     if (szProduct && !szwProduct)
2335         goto end;
2336
2337     path.unicode = FALSE;
2338     path.str.a = lpPathBuf;
2339
2340     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
2341                               dwInstallMode, szwProduct, Unused1,
2342                               Unused2, &path, pcchPathBuf);
2343 end:
2344     msi_free(szwProduct);
2345     msi_free(szwComponent);
2346     msi_free(szwQualifier);
2347
2348     return r;
2349 }
2350
2351 /***********************************************************************
2352  * MsiProvideQualifiedComponentW [MSI.@]
2353  */
2354 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
2355                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
2356                 LPDWORD pcchPathBuf)
2357 {
2358     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
2359                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
2360 }
2361
2362 /***********************************************************************
2363  * MsiProvideQualifiedComponentA [MSI.@]
2364  */
2365 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
2366                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
2367                 LPDWORD pcchPathBuf)
2368 {
2369     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
2370                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
2371 }
2372
2373 /***********************************************************************
2374  * MSI_GetUserInfo [internal]
2375  */
2376 static USERINFOSTATE WINAPI MSI_GetUserInfo(LPCWSTR szProduct,
2377                 awstring *lpUserNameBuf, LPDWORD pcchUserNameBuf,
2378                 awstring *lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
2379                 awstring *lpSerialBuf, LPDWORD pcchSerialBuf)
2380 {
2381     WCHAR squished_pc[SQUISH_GUID_SIZE];
2382     LPWSTR user, org, serial;
2383     USERINFOSTATE state;
2384     HKEY hkey, props;
2385     LPCWSTR orgptr;
2386     UINT r;
2387
2388     static const WCHAR szEmpty[] = {0};
2389
2390     TRACE("%s %p %p %p %p %p %p\n", debugstr_w(szProduct), lpUserNameBuf,
2391           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
2392           pcchSerialBuf);
2393
2394     if (!szProduct || !squash_guid(szProduct, squished_pc))
2395         return USERINFOSTATE_INVALIDARG;
2396
2397     if (MSIREG_OpenLocalManagedProductKey(szProduct, &hkey, FALSE) != ERROR_SUCCESS &&
2398         MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE) != ERROR_SUCCESS &&
2399         MSIREG_OpenLocalClassesProductKey(szProduct, &hkey, FALSE) != ERROR_SUCCESS)
2400     {
2401         return USERINFOSTATE_UNKNOWN;
2402     }
2403
2404     if (MSIREG_OpenCurrentUserInstallProps(szProduct, &props, FALSE) != ERROR_SUCCESS &&
2405         MSIREG_OpenLocalSystemInstallProps(szProduct, &props, FALSE) != ERROR_SUCCESS)
2406     {
2407         RegCloseKey(hkey);
2408         return USERINFOSTATE_ABSENT;
2409     }
2410
2411     user = msi_reg_get_val_str(props, INSTALLPROPERTY_REGOWNERW);
2412     org = msi_reg_get_val_str(props, INSTALLPROPERTY_REGCOMPANYW);
2413     serial = msi_reg_get_val_str(props, INSTALLPROPERTY_PRODUCTIDW);
2414     state = USERINFOSTATE_ABSENT;
2415
2416     RegCloseKey(hkey);
2417     RegCloseKey(props);
2418
2419     if (user && serial)
2420         state = USERINFOSTATE_PRESENT;
2421
2422     if (pcchUserNameBuf)
2423     {
2424         if (lpUserNameBuf && !user)
2425         {
2426             (*pcchUserNameBuf)--;
2427             goto done;
2428         }
2429
2430         r = msi_strcpy_to_awstring(user, lpUserNameBuf, pcchUserNameBuf);
2431         if (r == ERROR_MORE_DATA)
2432         {
2433             state = USERINFOSTATE_MOREDATA;
2434             goto done;
2435         }
2436     }
2437
2438     if (pcchOrgNameBuf)
2439     {
2440         orgptr = org;
2441         if (!orgptr) orgptr = szEmpty;
2442
2443         r = msi_strcpy_to_awstring(orgptr, lpOrgNameBuf, pcchOrgNameBuf);
2444         if (r == ERROR_MORE_DATA)
2445         {
2446             state = USERINFOSTATE_MOREDATA;
2447             goto done;
2448         }
2449     }
2450
2451     if (pcchSerialBuf)
2452     {
2453         if (!serial)
2454         {
2455             (*pcchSerialBuf)--;
2456             goto done;
2457         }
2458
2459         r = msi_strcpy_to_awstring(serial, lpSerialBuf, pcchSerialBuf);
2460         if (r == ERROR_MORE_DATA)
2461             state = USERINFOSTATE_MOREDATA;
2462     }
2463
2464 done:
2465     msi_free(user);
2466     msi_free(org);
2467     msi_free(serial);
2468
2469     return state;
2470 }
2471
2472 /***********************************************************************
2473  * MsiGetUserInfoW [MSI.@]
2474  */
2475 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
2476                 LPWSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
2477                 LPWSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
2478                 LPWSTR lpSerialBuf, LPDWORD pcchSerialBuf)
2479 {
2480     awstring user, org, serial;
2481
2482     if ((lpUserNameBuf && !pcchUserNameBuf) ||
2483         (lpOrgNameBuf && !pcchOrgNameBuf) ||
2484         (lpSerialBuf && !pcchSerialBuf))
2485         return USERINFOSTATE_INVALIDARG;
2486
2487     user.unicode = TRUE;
2488     user.str.w = lpUserNameBuf;
2489     org.unicode = TRUE;
2490     org.str.w = lpOrgNameBuf;
2491     serial.unicode = TRUE;
2492     serial.str.w = lpSerialBuf;
2493
2494     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
2495                             &org, pcchOrgNameBuf,
2496                             &serial, pcchSerialBuf );
2497 }
2498
2499 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
2500                 LPSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
2501                 LPSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
2502                 LPSTR lpSerialBuf, LPDWORD pcchSerialBuf)
2503 {
2504     awstring user, org, serial;
2505     LPWSTR prod;
2506     UINT r;
2507
2508     if ((lpUserNameBuf && !pcchUserNameBuf) ||
2509         (lpOrgNameBuf && !pcchOrgNameBuf) ||
2510         (lpSerialBuf && !pcchSerialBuf))
2511         return USERINFOSTATE_INVALIDARG;
2512
2513     prod = strdupAtoW( szProduct );
2514     if (szProduct && !prod)
2515         return ERROR_OUTOFMEMORY;
2516
2517     user.unicode = FALSE;
2518     user.str.a = lpUserNameBuf;
2519     org.unicode = FALSE;
2520     org.str.a = lpOrgNameBuf;
2521     serial.unicode = FALSE;
2522     serial.str.a = lpSerialBuf;
2523
2524     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
2525                          &org, pcchOrgNameBuf,
2526                          &serial, pcchSerialBuf );
2527
2528     msi_free( prod );
2529
2530     return r;
2531 }
2532
2533 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
2534 {
2535     MSIHANDLE handle;
2536     UINT rc;
2537     MSIPACKAGE *package;
2538     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
2539
2540     TRACE("(%s)\n",debugstr_w(szProduct));
2541
2542     rc = MsiOpenProductW(szProduct,&handle);
2543     if (rc != ERROR_SUCCESS)
2544         return ERROR_INVALID_PARAMETER;
2545
2546     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
2547     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
2548     msiobj_release( &package->hdr );
2549
2550     MsiCloseHandle(handle);
2551
2552     return rc;
2553 }
2554
2555 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
2556 {
2557     MSIHANDLE handle;
2558     UINT rc;
2559     MSIPACKAGE *package;
2560     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
2561
2562     TRACE("(%s)\n",debugstr_a(szProduct));
2563
2564     rc = MsiOpenProductA(szProduct,&handle);
2565     if (rc != ERROR_SUCCESS)
2566         return ERROR_INVALID_PARAMETER;
2567
2568     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
2569     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
2570     msiobj_release( &package->hdr );
2571
2572     MsiCloseHandle(handle);
2573
2574     return rc;
2575 }
2576
2577 /***********************************************************************
2578  * MsiConfigureFeatureA            [MSI.@]
2579  */
2580 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
2581 {
2582     LPWSTR prod, feat = NULL;
2583     UINT r = ERROR_OUTOFMEMORY;
2584
2585     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
2586
2587     prod = strdupAtoW( szProduct );
2588     if (szProduct && !prod)
2589         goto end;
2590
2591     feat = strdupAtoW( szFeature );
2592     if (szFeature && !feat)
2593         goto end;
2594
2595     r = MsiConfigureFeatureW(prod, feat, eInstallState);
2596
2597 end:
2598     msi_free(feat);
2599     msi_free(prod);
2600
2601     return r;
2602 }
2603
2604 /***********************************************************************
2605  * MsiConfigureFeatureW            [MSI.@]
2606  */
2607 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
2608 {
2609     static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
2610     MSIPACKAGE *package = NULL;
2611     UINT r;
2612     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
2613     DWORD sz;
2614
2615     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
2616
2617     if (!szProduct || !szFeature)
2618         return ERROR_INVALID_PARAMETER;
2619
2620     switch (eInstallState)
2621     {
2622     case INSTALLSTATE_DEFAULT:
2623         /* FIXME: how do we figure out the default location? */
2624         eInstallState = INSTALLSTATE_LOCAL;
2625         break;
2626     case INSTALLSTATE_LOCAL:
2627     case INSTALLSTATE_SOURCE:
2628     case INSTALLSTATE_ABSENT:
2629     case INSTALLSTATE_ADVERTISED:
2630         break;
2631     default:
2632         return ERROR_INVALID_PARAMETER;
2633     }
2634
2635     r = MSI_OpenProductW( szProduct, &package );
2636     if (r != ERROR_SUCCESS)
2637         return r;
2638
2639     sz = sizeof(sourcepath);
2640     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2641                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
2642
2643     sz = sizeof(filename);
2644     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2645                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
2646
2647     lstrcatW( sourcepath, filename );
2648
2649     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
2650
2651     r = ACTION_PerformUIAction( package, szCostInit, -1 );
2652     if (r != ERROR_SUCCESS)
2653         goto end;
2654
2655     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
2656     if (r != ERROR_SUCCESS)
2657         goto end;
2658
2659     r = MSI_InstallPackage( package, sourcepath, NULL );
2660
2661 end:
2662     msiobj_release( &package->hdr );
2663
2664     return r;
2665 }
2666
2667 /***********************************************************************
2668  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
2669  *
2670  * Notes: undocumented
2671  */
2672 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
2673 {
2674     WCHAR path[MAX_PATH];
2675
2676     TRACE("%d\n", dwReserved);
2677
2678     if (dwReserved)
2679     {
2680         FIXME("dwReserved=%d\n", dwReserved);
2681         return ERROR_INVALID_PARAMETER;
2682     }
2683
2684     if (!GetWindowsDirectoryW(path, MAX_PATH))
2685         return ERROR_FUNCTION_FAILED;
2686
2687     lstrcatW(path, installerW);
2688
2689     if (!CreateDirectoryW(path, NULL))
2690         return ERROR_FUNCTION_FAILED;
2691
2692     return ERROR_SUCCESS;
2693 }
2694
2695 /***********************************************************************
2696  * MsiGetShortcutTargetA           [MSI.@]
2697  */
2698 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
2699                                    LPSTR szProductCode, LPSTR szFeatureId,
2700                                    LPSTR szComponentCode )
2701 {
2702     LPWSTR target;
2703     const int len = MAX_FEATURE_CHARS+1;
2704     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
2705     UINT r;
2706
2707     target = strdupAtoW( szShortcutTarget );
2708     if (szShortcutTarget && !target )
2709         return ERROR_OUTOFMEMORY;
2710     product[0] = 0;
2711     feature[0] = 0;
2712     component[0] = 0;
2713     r = MsiGetShortcutTargetW( target, product, feature, component );
2714     msi_free( target );
2715     if (r == ERROR_SUCCESS)
2716     {
2717         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
2718         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
2719         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
2720     }
2721     return r;
2722 }
2723
2724 /***********************************************************************
2725  * MsiGetShortcutTargetW           [MSI.@]
2726  */
2727 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
2728                                    LPWSTR szProductCode, LPWSTR szFeatureId,
2729                                    LPWSTR szComponentCode )
2730 {
2731     IShellLinkDataList *dl = NULL;
2732     IPersistFile *pf = NULL;
2733     LPEXP_DARWIN_LINK darwin = NULL;
2734     HRESULT r, init;
2735
2736     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
2737           szProductCode, szFeatureId, szComponentCode );
2738
2739     init = CoInitialize(NULL);
2740
2741     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2742                           &IID_IPersistFile, (LPVOID*) &pf );
2743     if( SUCCEEDED( r ) )
2744     {
2745         r = IPersistFile_Load( pf, szShortcutTarget,
2746                                STGM_READ | STGM_SHARE_DENY_WRITE );
2747         if( SUCCEEDED( r ) )
2748         {
2749             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
2750                                              (LPVOID*) &dl );
2751             if( SUCCEEDED( r ) )
2752             {
2753                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
2754                                                   (LPVOID) &darwin );
2755                 IShellLinkDataList_Release( dl );
2756             }
2757         }
2758         IPersistFile_Release( pf );
2759     }
2760
2761     if (SUCCEEDED(init))
2762         CoUninitialize();
2763
2764     TRACE("darwin = %p\n", darwin);
2765
2766     if (darwin)
2767     {
2768         DWORD sz;
2769         UINT ret;
2770
2771         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
2772                   szProductCode, szFeatureId, szComponentCode, &sz );
2773         LocalFree( darwin );
2774         return ret;
2775     }
2776
2777     return ERROR_FUNCTION_FAILED;
2778 }
2779
2780 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
2781                                   DWORD dwReinstallMode )
2782 {
2783     MSIPACKAGE* package = NULL;
2784     UINT r;
2785     WCHAR sourcepath[MAX_PATH];
2786     WCHAR filename[MAX_PATH];
2787     static const WCHAR szLogVerbose[] = {
2788         ' ','L','O','G','V','E','R','B','O','S','E',0 };
2789     static const WCHAR szInstalled[] = { 'I','n','s','t','a','l','l','e','d',0};
2790     static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0};
2791     static const WCHAR szReinstallMode[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
2792     static const WCHAR szOne[] = {'1',0};
2793     WCHAR reinstallmode[11];
2794     LPWSTR ptr;
2795     DWORD sz;
2796
2797     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
2798                            dwReinstallMode);
2799
2800     ptr = reinstallmode;
2801
2802     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
2803         *ptr++ = 'p';
2804     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
2805         *ptr++ = 'o';
2806     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
2807         *ptr++ = 'w';
2808     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
2809         *ptr++ = 'd';
2810     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
2811         *ptr++ = 'c';
2812     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
2813         *ptr++ = 'a';
2814     if (dwReinstallMode & REINSTALLMODE_USERDATA)
2815         *ptr++ = 'u';
2816     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
2817         *ptr++ = 'm';
2818     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
2819         *ptr++ = 's';
2820     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2821         *ptr++ = 'v';
2822     *ptr = 0;
2823     
2824     sz = sizeof(sourcepath);
2825     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2826             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
2827
2828     sz = sizeof(filename);
2829     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2830             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
2831
2832     lstrcatW( sourcepath, filename );
2833
2834     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2835         r = MSI_OpenPackageW( sourcepath, &package );
2836     else
2837         r = MSI_OpenProductW( szProduct, &package );
2838
2839     if (r != ERROR_SUCCESS)
2840         return r;
2841
2842     MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
2843     MSI_SetPropertyW( package, szInstalled, szOne );
2844     MSI_SetPropertyW( package, szLogVerbose, szOne );
2845     MSI_SetPropertyW( package, szReinstall, szFeature );
2846
2847     r = MSI_InstallPackage( package, sourcepath, NULL );
2848
2849     msiobj_release( &package->hdr );
2850
2851     return r;
2852 }
2853
2854 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
2855                                   DWORD dwReinstallMode )
2856 {
2857     LPWSTR wszProduct;
2858     LPWSTR wszFeature;
2859     UINT rc;
2860
2861     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
2862                            dwReinstallMode);
2863
2864     wszProduct = strdupAtoW(szProduct);
2865     wszFeature = strdupAtoW(szFeature);
2866
2867     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
2868
2869     msi_free(wszProduct);
2870     msi_free(wszFeature);
2871     return rc;
2872 }
2873
2874 typedef struct
2875 {
2876     unsigned int i[2];
2877     unsigned int buf[4];
2878     unsigned char in[64];
2879     unsigned char digest[16];
2880 } MD5_CTX;
2881
2882 extern VOID WINAPI MD5Init( MD5_CTX *);
2883 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
2884 extern VOID WINAPI MD5Final( MD5_CTX *);
2885
2886 /***********************************************************************
2887  * MsiGetFileHashW            [MSI.@]
2888  */
2889 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
2890                              PMSIFILEHASHINFO pHash )
2891 {
2892     HANDLE handle, mapping;
2893     void *p;
2894     DWORD length;
2895     UINT r = ERROR_FUNCTION_FAILED;
2896
2897     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
2898
2899     if (!szFilePath)
2900         return ERROR_INVALID_PARAMETER;
2901
2902     if (!*szFilePath)
2903         return ERROR_PATH_NOT_FOUND;
2904
2905     if (dwOptions)
2906         return ERROR_INVALID_PARAMETER;
2907     if (!pHash)
2908         return ERROR_INVALID_PARAMETER;
2909     if (pHash->dwFileHashInfoSize < sizeof *pHash)
2910         return ERROR_INVALID_PARAMETER;
2911
2912     handle = CreateFileW( szFilePath, GENERIC_READ,
2913                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
2914     if (handle == INVALID_HANDLE_VALUE)
2915         return ERROR_FILE_NOT_FOUND;
2916
2917     length = GetFileSize( handle, NULL );
2918
2919     mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
2920     if (mapping)
2921     {
2922         p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
2923         if (p)
2924         {
2925             MD5_CTX ctx;
2926
2927             MD5Init( &ctx );
2928             MD5Update( &ctx, p, length );
2929             MD5Final( &ctx );
2930             UnmapViewOfFile( p );
2931
2932             memcpy( pHash->dwData, ctx.digest, sizeof pHash->dwData );
2933             r = ERROR_SUCCESS;
2934         }
2935         CloseHandle( mapping );
2936     }
2937     CloseHandle( handle );
2938
2939     return r;
2940 }
2941
2942 /***********************************************************************
2943  * MsiGetFileHashA            [MSI.@]
2944  */
2945 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
2946                              PMSIFILEHASHINFO pHash )
2947 {
2948     LPWSTR file;
2949     UINT r;
2950
2951     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
2952
2953     file = strdupAtoW( szFilePath );
2954     if (szFilePath && !file)
2955         return ERROR_OUTOFMEMORY;
2956
2957     r = MsiGetFileHashW( file, dwOptions, pHash );
2958     msi_free( file );
2959     return r;
2960 }
2961
2962 /***********************************************************************
2963  * MsiAdvertiseScriptW        [MSI.@]
2964  */
2965 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
2966                                  PHKEY phRegData, BOOL fRemoveItems )
2967 {
2968     FIXME("%s %08x %p %d\n",
2969           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2970     return ERROR_CALL_NOT_IMPLEMENTED;
2971 }
2972
2973 /***********************************************************************
2974  * MsiAdvertiseScriptA        [MSI.@]
2975  */
2976 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
2977                                  PHKEY phRegData, BOOL fRemoveItems )
2978 {
2979     FIXME("%s %08x %p %d\n",
2980           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2981     return ERROR_CALL_NOT_IMPLEMENTED;
2982 }
2983
2984 /***********************************************************************
2985  * MsiIsProductElevatedW        [MSI.@]
2986  */
2987 UINT WINAPI MsiIsProductElevatedW( LPCWSTR szProduct, BOOL *pfElevated )
2988 {
2989     FIXME("%s %p - stub\n",
2990           debugstr_w( szProduct ), pfElevated );
2991     *pfElevated = TRUE;
2992     return ERROR_SUCCESS;
2993 }
2994
2995 /***********************************************************************
2996  * MsiIsProductElevatedA        [MSI.@]
2997  */
2998 UINT WINAPI MsiIsProductElevatedA( LPCSTR szProduct, BOOL *pfElevated )
2999 {
3000     FIXME("%s %p - stub\n",
3001           debugstr_a( szProduct ), pfElevated );
3002     *pfElevated = TRUE;
3003     return ERROR_SUCCESS;
3004 }