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