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