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