crypt32: Introduce function to encode an array of items as a set.
[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 UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
49 {
50     UINT r;
51     LPWSTR szwProd = NULL;
52
53     TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
54
55     if( szProduct )
56     {
57         szwProd = strdupAtoW( szProduct );
58         if( !szwProd )
59             return ERROR_OUTOFMEMORY;
60     }
61
62     r = MsiOpenProductW( szwProd, phProduct );
63
64     msi_free( szwProd );
65
66     return r;
67 }
68
69 static UINT MSI_OpenProductW( LPCWSTR szProduct, MSIPACKAGE **ppackage )
70 {
71     LPWSTR path = NULL;
72     UINT r;
73     HKEY hKeyProduct = NULL;
74     DWORD count, type;
75
76     TRACE("%s %p\n", debugstr_w(szProduct), ppackage );
77
78     r = MSIREG_OpenUninstallKey(szProduct,&hKeyProduct,FALSE);
79     if( r != ERROR_SUCCESS )
80     {
81         r = ERROR_UNKNOWN_PRODUCT;
82         goto end;
83     }
84
85     /* find the size of the path */
86     type = count = 0;
87     r = RegQueryValueExW( hKeyProduct, INSTALLPROPERTY_LOCALPACKAGEW,
88                           NULL, &type, NULL, &count );
89     if( r != ERROR_SUCCESS )
90     {
91         r = ERROR_UNKNOWN_PRODUCT;
92         goto end;
93     }
94
95     /* now alloc and fetch the path of the database to open */
96     path = msi_alloc( count );
97     if( !path )
98         goto end;
99
100     r = RegQueryValueExW( hKeyProduct, INSTALLPROPERTY_LOCALPACKAGEW,
101                           NULL, &type, (LPBYTE) path, &count );
102     if( r != ERROR_SUCCESS )
103     {
104         r = ERROR_UNKNOWN_PRODUCT;
105         goto end;
106     }
107
108     r = MSI_OpenPackageW( path, ppackage );
109
110 end:
111     msi_free( path );
112     if( hKeyProduct )
113         RegCloseKey( hKeyProduct );
114
115     return r;
116 }
117
118 UINT WINAPI MsiOpenProductW( LPCWSTR szProduct, MSIHANDLE *phProduct )
119 {
120    MSIPACKAGE *package = NULL;
121    UINT r;
122
123    r = MSI_OpenProductW( szProduct, &package );
124    if( r == ERROR_SUCCESS )
125    {
126        *phProduct = alloc_msihandle( &package->hdr );
127        if (! *phProduct)
128            r = ERROR_NOT_ENOUGH_MEMORY;
129        msiobj_release( &package->hdr );
130    }
131    return r;
132 }
133
134 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
135                 LPCSTR szTransforms, LANGID lgidLanguage)
136 {
137     FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath),
138           debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
139     return ERROR_CALL_NOT_IMPLEMENTED;
140 }
141
142 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
143                 LPCWSTR szTransforms, LANGID lgidLanguage)
144 {
145     FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath),
146           debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
147     return ERROR_CALL_NOT_IMPLEMENTED;
148 }
149
150 UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
151       LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
152 {
153     FIXME("%s %s %s %08x %08x %08x\n", debugstr_a(szPackagePath),
154           debugstr_a(szScriptfilePath), debugstr_a(szTransforms),
155           lgidLanguage, dwPlatform, dwOptions);
156     return ERROR_CALL_NOT_IMPLEMENTED;
157 }
158
159 UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
160       LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
161 {
162     FIXME("%s %s %s %08x %08x %08x\n", debugstr_w(szPackagePath),
163           debugstr_w(szScriptfilePath), debugstr_w(szTransforms),
164           lgidLanguage, dwPlatform, dwOptions);
165     return ERROR_CALL_NOT_IMPLEMENTED;
166 }
167
168 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
169 {
170     LPWSTR szwPath = NULL, szwCommand = NULL;
171     UINT r = ERROR_OUTOFMEMORY;
172
173     TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
174
175     if( szPackagePath )
176     {
177         szwPath = strdupAtoW( szPackagePath );
178         if( !szwPath )
179             goto end;
180     }
181
182     if( szCommandLine )
183     {
184         szwCommand = strdupAtoW( szCommandLine );
185         if( !szwCommand )
186             goto end;
187     }
188
189     r = MsiInstallProductW( szwPath, szwCommand );
190
191 end:
192     msi_free( szwPath );
193     msi_free( szwCommand );
194
195     return r;
196 }
197
198 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
199 {
200     MSIPACKAGE *package = NULL;
201     UINT r;
202
203     TRACE("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
204
205     r = MSI_OpenPackageW( szPackagePath, &package );
206     if (r == ERROR_SUCCESS)
207     {
208         r = MSI_InstallPackage( package, szPackagePath, szCommandLine );
209         msiobj_release( &package->hdr );
210     }
211
212     return r;
213 }
214
215 UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode)
216 {
217     FIXME("%s %08x\n", debugstr_a(szProduct), dwReinstallMode);
218     return ERROR_CALL_NOT_IMPLEMENTED;
219 }
220
221 UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode)
222 {
223     FIXME("%s %08x\n", debugstr_w(szProduct), dwReinstallMode);
224     return ERROR_CALL_NOT_IMPLEMENTED;
225 }
226
227 UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage,
228         INSTALLTYPE eInstallType, LPCSTR szCommandLine)
229 {
230     LPWSTR patch_package = NULL;
231     LPWSTR install_package = NULL;
232     LPWSTR command_line = NULL;
233     UINT r = ERROR_OUTOFMEMORY;
234
235     TRACE("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage),
236           eInstallType, debugstr_a(szCommandLine));
237
238     if (szPatchPackage && !(patch_package = strdupAtoW(szPatchPackage)))
239         goto done;
240
241     if (szInstallPackage && !(install_package = strdupAtoW(szInstallPackage)))
242         goto done;
243
244     if (szCommandLine && !(command_line = strdupAtoW(szCommandLine)))
245         goto done;
246
247     r = MsiApplyPatchW(patch_package, install_package, eInstallType, command_line);
248
249 done:
250     msi_free(patch_package);
251     msi_free(install_package);
252     msi_free(command_line);
253
254     return r;
255 }
256
257 UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
258          INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
259 {
260     MSIHANDLE patch, info;
261     UINT r, type;
262     DWORD size = 0;
263     LPCWSTR cmd_ptr = szCommandLine;
264     LPWSTR beg, end;
265     LPWSTR cmd = NULL, codes = NULL;
266
267     static const WCHAR space[] = {' ',0};
268     static const WCHAR patcheq[] = {'P','A','T','C','H','=',0};
269     static WCHAR empty[] = {0};
270
271     TRACE("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage),
272           eInstallType, debugstr_w(szCommandLine));
273
274     if (szInstallPackage || eInstallType == INSTALLTYPE_NETWORK_IMAGE ||
275         eInstallType == INSTALLTYPE_SINGLE_INSTANCE)
276     {
277         FIXME("Only reading target products from patch\n");
278         return ERROR_CALL_NOT_IMPLEMENTED;
279     }
280
281     r = MsiOpenDatabaseW(szPatchPackage, MSIDBOPEN_READONLY, &patch);
282     if (r != ERROR_SUCCESS)
283         return r;
284
285     r = MsiGetSummaryInformationW(patch, NULL, 0, &info);
286     if (r != ERROR_SUCCESS)
287         goto done;
288
289     r = MsiSummaryInfoGetPropertyW(info, PID_TEMPLATE, &type, NULL, NULL, empty, &size);
290     if (r != ERROR_MORE_DATA || !size || type != VT_LPSTR)
291     {
292         ERR("Failed to read product codes from patch\n");
293         goto done;
294     }
295
296     codes = msi_alloc(++size * sizeof(WCHAR));
297     if (!codes)
298     {
299         r = ERROR_OUTOFMEMORY;
300         goto done;
301     }
302
303     r = MsiSummaryInfoGetPropertyW(info, PID_TEMPLATE, &type, NULL, NULL, codes, &size);
304     if (r != ERROR_SUCCESS)
305         goto done;
306
307     if (!szCommandLine)
308         cmd_ptr = empty;
309
310     size = lstrlenW(cmd_ptr) + lstrlenW(patcheq) + lstrlenW(szPatchPackage) + 1;
311     cmd = msi_alloc(size * sizeof(WCHAR));
312     if (!cmd)
313     {
314         r = ERROR_OUTOFMEMORY;
315         goto done;
316     }
317
318     lstrcpyW(cmd, cmd_ptr);
319     if (szCommandLine) lstrcatW(cmd, space);
320     lstrcatW(cmd, patcheq);
321     lstrcatW(cmd, szPatchPackage);
322
323     beg = codes;
324     while ((end = strchrW(beg, '}')))
325     {
326         *(end + 1) = '\0';
327
328         r = MsiConfigureProductExW(beg, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
329         if (r != ERROR_SUCCESS)
330             goto done;
331
332         beg = end + 2;
333     }
334
335 done:
336     msi_free(cmd);
337     msi_free(codes);
338
339     MsiCloseHandle(info);
340     MsiCloseHandle(patch);
341
342     return r;
343 }
344
345 UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
346                         INSTALLSTATE eInstallState, LPCWSTR szCommandLine)
347 {
348     MSIPACKAGE* package = NULL;
349     UINT r;
350     DWORD sz;
351     WCHAR sourcepath[MAX_PATH];
352     WCHAR filename[MAX_PATH];
353     static const WCHAR szInstalled[] = {
354         ' ','I','n','s','t','a','l','l','e','d','=','1',0};
355     LPWSTR commandline;
356
357     TRACE("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState,
358           debugstr_w(szCommandLine));
359
360     if (eInstallState != INSTALLSTATE_LOCAL &&
361         eInstallState != INSTALLSTATE_DEFAULT)
362     {
363         FIXME("Not implemented for anything other than local installs\n");
364         return ERROR_CALL_NOT_IMPLEMENTED;
365     }
366
367     sz = sizeof(sourcepath);
368     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
369             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath,
370             &sz);
371
372     sz = sizeof(filename);
373     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
374             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
375
376     lstrcatW(sourcepath,filename);
377
378     /*
379      * ok 1, we need to find the msi file for this product.
380      *    2, find the source dir for the files
381      *    3, do the configure/install.
382      *    4, cleanupany runonce entry.
383      */
384
385     r = MSI_OpenProductW( szProduct, &package );
386     if (r != ERROR_SUCCESS)
387         return r;
388
389     sz = lstrlenW(szInstalled) + 1;
390
391     if (szCommandLine)
392         sz += lstrlenW(szCommandLine);
393
394     commandline = msi_alloc(sz * sizeof(WCHAR));
395     if (!commandline )
396     {
397         r = ERROR_OUTOFMEMORY;
398         goto end;
399     }
400
401     commandline[0] = 0;
402     if (szCommandLine)
403         lstrcpyW(commandline,szCommandLine);
404
405     if (MsiQueryProductStateW(szProduct) != INSTALLSTATE_UNKNOWN)
406         lstrcatW(commandline,szInstalled);
407
408     r = MSI_InstallPackage( package, sourcepath, commandline );
409
410     msi_free(commandline);
411
412 end:
413     msiobj_release( &package->hdr );
414
415     return r;
416 }
417
418 UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel,
419                         INSTALLSTATE eInstallState, LPCSTR szCommandLine)
420 {
421     LPWSTR szwProduct = NULL;
422     LPWSTR szwCommandLine = NULL;
423     UINT r = ERROR_OUTOFMEMORY;
424
425     if( szProduct )
426     {
427         szwProduct = strdupAtoW( szProduct );
428         if( !szwProduct )
429             goto end;
430     }
431
432     if( szCommandLine)
433     {
434         szwCommandLine = strdupAtoW( szCommandLine );
435         if( !szwCommandLine)
436             goto end;
437     }
438
439     r = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState,
440                                 szwCommandLine );
441 end:
442     msi_free( szwProduct );
443     msi_free( szwCommandLine);
444
445     return r;
446 }
447
448 UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel,
449                                  INSTALLSTATE eInstallState)
450 {
451     LPWSTR szwProduct = NULL;
452     UINT r;
453
454     TRACE("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
455
456     if( szProduct )
457     {
458         szwProduct = strdupAtoW( szProduct );
459         if( !szwProduct )
460             return ERROR_OUTOFMEMORY;
461     }
462
463     r = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState );
464     msi_free( szwProduct );
465
466     return r;
467 }
468
469 UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel,
470                                  INSTALLSTATE eInstallState)
471 {
472     return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL);
473 }
474
475 UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
476 {
477     LPWSTR szwComponent = NULL;
478     UINT r;
479     WCHAR szwBuffer[GUID_SIZE];
480
481     TRACE("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer));
482
483     if( szComponent )
484     {
485         szwComponent = strdupAtoW( szComponent );
486         if( !szwComponent )
487             return ERROR_OUTOFMEMORY;
488     }
489
490     r = MsiGetProductCodeW( szwComponent, szwBuffer );
491
492     if( ERROR_SUCCESS == r )
493         WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL);
494
495     msi_free( szwComponent );
496
497     return r;
498 }
499
500 UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
501 {
502     UINT rc;
503     HKEY hkey;
504     WCHAR szSquished[GUID_SIZE];
505     DWORD sz = GUID_SIZE;
506     static const WCHAR szPermKey[] =
507         { '0','0','0','0','0','0','0','0','0','0','0','0',
508           '0','0','0','0','0','0','0','0','0','0','0','0',
509           '0','0','0','0','0','0','0','0',0};
510
511     TRACE("%s %p\n",debugstr_w(szComponent), szBuffer);
512
513     if (NULL == szComponent)
514         return ERROR_INVALID_PARAMETER;
515
516     rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE);
517     if (rc != ERROR_SUCCESS)
518         return ERROR_UNKNOWN_COMPONENT;
519
520     rc = RegEnumValueW(hkey, 0, szSquished, &sz, NULL, NULL, NULL, NULL);
521     if (rc == ERROR_SUCCESS && strcmpW(szSquished,szPermKey)==0)
522     {
523         sz = GUID_SIZE;
524         rc = RegEnumValueW(hkey, 1, szSquished, &sz, NULL, NULL, NULL, NULL);
525     }
526
527     RegCloseKey(hkey);
528
529     if (rc != ERROR_SUCCESS)
530         return ERROR_INSTALL_FAILURE;
531
532     unsquash_guid(szSquished, szBuffer);
533     return ERROR_SUCCESS;
534 }
535
536 static UINT WINAPI MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
537                                       awstring *szValue, DWORD *pcchValueBuf)
538 {
539     UINT r;
540     HKEY hkey;
541     LPWSTR val = NULL;
542
543     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
544           debugstr_w(szAttribute), szValue, pcchValueBuf);
545
546     /*
547      * FIXME: Values seem scattered/duplicated in the registry. Is there a system?
548      */
549
550     if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szProduct[0] || !szAttribute)
551         return ERROR_INVALID_PARAMETER;
552
553     /* check for special properties */
554     if (!lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW))
555     {
556         LPWSTR regval;
557         WCHAR packagecode[35];
558
559         r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE);
560         if (r != ERROR_SUCCESS)
561             return ERROR_UNKNOWN_PRODUCT;
562
563         regval = msi_reg_get_val_str( hkey, szAttribute );
564         if (regval)
565         {
566             if (unsquash_guid(regval, packagecode))
567                 val = strdupW(packagecode);
568             msi_free(regval);
569         }
570
571         RegCloseKey(hkey);
572     }
573     else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW))
574     {
575         static const WCHAR one[] = { '1',0 };
576         /*
577          * FIXME: should be in the Product key (user or system?)
578          *        but isn't written yet...
579          */
580         val = strdupW( one );
581     }
582     else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_LANGUAGEW) ||
583              !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONW))
584     {
585         static const WCHAR fmt[] = { '%','u',0 };
586         WCHAR szVal[16];
587         DWORD regval;
588
589         r = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
590         if (r != ERROR_SUCCESS)
591             return ERROR_UNKNOWN_PRODUCT;
592
593         if (msi_reg_get_val_dword( hkey, szAttribute, &regval))
594         {
595             sprintfW(szVal, fmt, regval);
596             val = strdupW( szVal );
597         }
598
599         RegCloseKey(hkey);
600     }
601     else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTNAMEW))
602     {
603         r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE);
604         if (r != ERROR_SUCCESS)
605             return ERROR_UNKNOWN_PRODUCT;
606
607         val = msi_reg_get_val_str( hkey, szAttribute );
608
609         RegCloseKey(hkey);
610     }
611     else if (!szAttribute[0])
612     {
613         return ERROR_UNKNOWN_PROPERTY;
614     }
615     else
616     {
617         static const WCHAR szDisplayVersion[] = {
618             'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0 };
619
620         FIXME("%s\n", debugstr_w(szAttribute));
621         /* FIXME: some attribute values not tested... */
622
623         if (!lstrcmpW( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ))
624             szAttribute = szDisplayVersion;
625
626         r = MSIREG_OpenUninstallKey( szProduct, &hkey, FALSE );
627         if (r != ERROR_SUCCESS)
628             return ERROR_UNKNOWN_PRODUCT;
629
630         val = msi_reg_get_val_str( hkey, szAttribute );
631
632         RegCloseKey(hkey);
633     }
634
635     TRACE("returning %s\n", debugstr_w(val));
636
637     if (!val)
638         return ERROR_UNKNOWN_PROPERTY;
639
640     r = msi_strcpy_to_awstring( val, szValue, pcchValueBuf );
641
642     msi_free(val);
643
644     return r;
645 }
646
647 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
648                                LPSTR szBuffer, DWORD *pcchValueBuf)
649 {
650     LPWSTR szwProduct, szwAttribute = NULL;
651     UINT r = ERROR_OUTOFMEMORY;
652     awstring buffer;
653
654     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
655           szBuffer, pcchValueBuf);
656
657     szwProduct = strdupAtoW( szProduct );
658     if( szProduct && !szwProduct )
659         goto end;
660
661     szwAttribute = strdupAtoW( szAttribute );
662     if( szAttribute && !szwAttribute )
663         goto end;
664
665     buffer.unicode = FALSE;
666     buffer.str.a = szBuffer;
667
668     r = MSI_GetProductInfo( szwProduct, szwAttribute,
669                             &buffer, pcchValueBuf );
670
671 end:
672     msi_free( szwProduct );
673     msi_free( szwAttribute );
674
675     return r;
676 }
677
678 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
679                                LPWSTR szBuffer, DWORD *pcchValueBuf)
680 {
681     awstring buffer;
682
683     TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szAttribute),
684           szBuffer, pcchValueBuf);
685
686     buffer.unicode = TRUE;
687     buffer.str.w = szBuffer;
688
689     return MSI_GetProductInfo( szProduct, szAttribute,
690                                &buffer, pcchValueBuf );
691 }
692
693 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
694 {
695     LPWSTR szwLogFile = NULL;
696     UINT r;
697
698     TRACE("%08x %s %08x\n", dwLogMode, debugstr_a(szLogFile), attributes);
699
700     if( szLogFile )
701     {
702         szwLogFile = strdupAtoW( szLogFile );
703         if( !szwLogFile )
704             return ERROR_OUTOFMEMORY;
705     }
706     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
707     msi_free( szwLogFile );
708     return r;
709 }
710
711 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
712 {
713     HANDLE file = INVALID_HANDLE_VALUE;
714
715     TRACE("%08x %s %08x\n", dwLogMode, debugstr_w(szLogFile), attributes);
716
717     if (szLogFile)
718     {
719         lstrcpyW(gszLogFile,szLogFile);
720         if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
721             DeleteFileW(szLogFile);
722         file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
723                                FILE_ATTRIBUTE_NORMAL, NULL);
724         if (file != INVALID_HANDLE_VALUE)
725             CloseHandle(file);
726         else
727             ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
728     }
729     else
730         gszLogFile[0] = '\0';
731
732     return ERROR_SUCCESS;
733 }
734
735 UINT WINAPI MsiQueryComponentStateA(LPSTR szProductCode, LPSTR szUserSid, MSIINSTALLCONTEXT dwContext, LPCSTR szComponent, INSTALLSTATE *pdwState)
736 {
737     FIXME("(%s, %s, %d, %s, %p): stub!\n", debugstr_a(szProductCode), debugstr_a(szUserSid), dwContext, debugstr_a(szComponent), pdwState);
738
739     if (!pdwState)
740         return ERROR_INVALID_PARAMETER;
741
742     *pdwState = INSTALLSTATE_UNKNOWN;
743     return ERROR_UNKNOWN_PRODUCT;
744 }
745
746 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
747 {
748     LPWSTR szwProduct = NULL;
749     INSTALLSTATE r;
750
751     if( szProduct )
752     {
753          szwProduct = strdupAtoW( szProduct );
754          if( !szwProduct )
755              return ERROR_OUTOFMEMORY;
756     }
757     r = MsiQueryProductStateW( szwProduct );
758     msi_free( szwProduct );
759     return r;
760 }
761
762 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
763 {
764     UINT rc;
765     INSTALLSTATE state = INSTALLSTATE_UNKNOWN;
766     HKEY hkey = 0, props = 0;
767     DWORD sz;
768     BOOL userkey_exists = FALSE;
769
770     static const int GUID_LEN = 38;
771     static const WCHAR szInstallProperties[] = {
772             'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0
773     };
774     static const WCHAR szWindowsInstaller[] = {
775             'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0
776     };
777
778     TRACE("%s\n", debugstr_w(szProduct));
779
780     if (!szProduct || !*szProduct || lstrlenW(szProduct) != GUID_LEN)
781         return INSTALLSTATE_INVALIDARG;
782
783     rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE);
784     if (rc == ERROR_SUCCESS)
785     {
786         userkey_exists = TRUE;
787         state = INSTALLSTATE_ADVERTISED;
788         RegCloseKey(hkey);
789     }
790
791     rc = MSIREG_OpenUserDataProductKey(szProduct,&hkey,FALSE);
792     if (rc != ERROR_SUCCESS)
793         goto end;
794
795     rc = RegOpenKeyW(hkey, szInstallProperties, &props);
796     if (rc != ERROR_SUCCESS)
797         goto end;
798
799     sz = sizeof(state);
800     rc = RegQueryValueExW(props,szWindowsInstaller,NULL,NULL,(LPVOID)&state, &sz);
801     if (rc != ERROR_SUCCESS)
802         goto end;
803
804     if (state)
805         state = INSTALLSTATE_DEFAULT;
806     else
807         state = INSTALLSTATE_UNKNOWN;
808
809     if (state == INSTALLSTATE_DEFAULT && !userkey_exists)
810         state = INSTALLSTATE_ABSENT;
811
812 end:
813     RegCloseKey(props);
814     RegCloseKey(hkey);
815     return state;
816 }
817
818 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
819 {
820     INSTALLUILEVEL old = gUILevel;
821     HWND oldwnd = gUIhwnd;
822
823     TRACE("%08x %p\n", dwUILevel, phWnd);
824
825     gUILevel = dwUILevel;
826     if (phWnd)
827     {
828         gUIhwnd = *phWnd;
829         *phWnd = oldwnd;
830     }
831     return old;
832 }
833
834 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
835                                   DWORD dwMessageFilter, LPVOID pvContext)
836 {
837     INSTALLUI_HANDLERA prev = gUIHandlerA;
838
839     TRACE("%p %x %p\n",puiHandler, dwMessageFilter,pvContext);
840     gUIHandlerA = puiHandler;
841     gUIFilter = dwMessageFilter;
842     gUIContext = pvContext;
843
844     return prev;
845 }
846
847 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
848                                   DWORD dwMessageFilter, LPVOID pvContext)
849 {
850     INSTALLUI_HANDLERW prev = gUIHandlerW;
851
852     TRACE("%p %x %p\n",puiHandler,dwMessageFilter,pvContext);
853     gUIHandlerW = puiHandler;
854     gUIFilter = dwMessageFilter;
855     gUIContext = pvContext;
856
857     return prev;
858 }
859
860 /******************************************************************
861  *  MsiLoadStringW            [MSI.@]
862  *
863  * Loads a string from MSI's string resources.
864  *
865  * PARAMS
866  *
867  *   handle        [I]  only -1 is handled currently
868  *   id            [I]  id of the string to be loaded
869  *   lpBuffer      [O]  buffer for the string to be written to
870  *   nBufferMax    [I]  maximum size of the buffer in characters
871  *   lang          [I]  the preferred language for the string
872  *
873  * RETURNS
874  *
875  *   If successful, this function returns the language id of the string loaded
876  *   If the function fails, the function returns zero.
877  *
878  * NOTES
879  *
880  *   The type of the first parameter is unknown.  LoadString's prototype
881  *  suggests that it might be a module handle.  I have made it an MSI handle
882  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
883  *  handle.  Maybe strings can be stored in an MSI database somehow.
884  */
885 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
886                 int nBufferMax, LANGID lang )
887 {
888     HRSRC hres;
889     HGLOBAL hResData;
890     LPWSTR p;
891     DWORD i, len;
892
893     TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
894
895     if( handle != -1 )
896         FIXME("don't know how to deal with handle = %08lx\n", handle);
897
898     if( !lang )
899         lang = GetUserDefaultLangID();
900
901     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
902                             (LPWSTR)1, lang );
903     if( !hres )
904         return 0;
905     hResData = LoadResource( msi_hInstance, hres );
906     if( !hResData )
907         return 0;
908     p = LockResource( hResData );
909     if( !p )
910         return 0;
911
912     for (i = 0; i < (id&0xf); i++)
913         p += *p + 1;
914     len = *p;
915
916     if( nBufferMax <= len )
917         return 0;
918
919     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
920     lpBuffer[ len ] = 0;
921
922     TRACE("found -> %s\n", debugstr_w(lpBuffer));
923
924     return lang;
925 }
926
927 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
928                 int nBufferMax, LANGID lang )
929 {
930     LPWSTR bufW;
931     LANGID r;
932     DWORD len;
933
934     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
935     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
936     if( r )
937     {
938         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
939         if( len <= nBufferMax )
940             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
941                                  lpBuffer, nBufferMax, NULL, NULL );
942         else
943             r = 0;
944     }
945     msi_free(bufW);
946     return r;
947 }
948
949 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
950                 DWORD *pcchBuf)
951 {
952     char szProduct[GUID_SIZE];
953
954     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
955
956     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
957         return INSTALLSTATE_UNKNOWN;
958
959     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
960 }
961
962 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
963                 DWORD *pcchBuf)
964 {
965     WCHAR szProduct[GUID_SIZE];
966
967     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
968
969     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
970         return INSTALLSTATE_UNKNOWN;
971
972     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
973 }
974
975 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
976                 WORD wLanguageId, DWORD f)
977 {
978     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption),
979           uType, wLanguageId, f);
980     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
981 }
982
983 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
984                 WORD wLanguageId, DWORD f)
985 {
986     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption),
987           uType, wLanguageId, f);
988     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
989 }
990
991 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
992                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
993                 DWORD* pcchPathBuf )
994 {
995     FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
996           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
997           pcchPathBuf);
998     return ERROR_CALL_NOT_IMPLEMENTED;
999 }
1000
1001 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
1002                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
1003                 DWORD* pcchPathBuf )
1004 {
1005     FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
1006           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
1007           pcchPathBuf);
1008     return ERROR_CALL_NOT_IMPLEMENTED;
1009 }
1010
1011 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
1012                 LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
1013 {
1014     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
1015     return ERROR_CALL_NOT_IMPLEMENTED;
1016 }
1017
1018 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
1019                 LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
1020 {
1021     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
1022     return ERROR_CALL_NOT_IMPLEMENTED;
1023 }
1024
1025 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
1026                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
1027                 DWORD* pcbHashData)
1028 {
1029     FIXME("%s %08x %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
1030           ppcCertContext, pbHashData, pcbHashData);
1031     return ERROR_CALL_NOT_IMPLEMENTED;
1032 }
1033
1034 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
1035                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
1036                 DWORD* pcbHashData)
1037 {
1038     FIXME("%s %08x %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
1039           ppcCertContext, pbHashData, pcbHashData);
1040     return ERROR_CALL_NOT_IMPLEMENTED;
1041 }
1042
1043 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
1044                                     LPSTR szValue, DWORD *pccbValue )
1045 {
1046     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
1047     return ERROR_CALL_NOT_IMPLEMENTED;
1048 }
1049
1050 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
1051                                     LPWSTR szValue, DWORD *pccbValue )
1052 {
1053     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
1054     return ERROR_CALL_NOT_IMPLEMENTED;
1055 }
1056
1057 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
1058 {
1059     UINT r;
1060     LPWSTR szPack = NULL;
1061
1062     TRACE("%s\n", debugstr_a(szPackage) );
1063
1064     if( szPackage )
1065     {
1066         szPack = strdupAtoW( szPackage );
1067         if( !szPack )
1068             return ERROR_OUTOFMEMORY;
1069     }
1070
1071     r = MsiVerifyPackageW( szPack );
1072
1073     msi_free( szPack );
1074
1075     return r;
1076 }
1077
1078 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
1079 {
1080     MSIHANDLE handle;
1081     UINT r;
1082
1083     TRACE("%s\n", debugstr_w(szPackage) );
1084
1085     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
1086     MsiCloseHandle( handle );
1087
1088     return r;
1089 }
1090
1091 static INSTALLSTATE WINAPI MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent,
1092                                                 awstring* lpPathBuf, DWORD* pcchBuf)
1093 {
1094     WCHAR squished_pc[GUID_SIZE], squished_comp[GUID_SIZE];
1095     UINT rc;
1096     HKEY hkey = 0;
1097     LPWSTR path = NULL;
1098     INSTALLSTATE r;
1099
1100     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1101            debugstr_w(szComponent), lpPathBuf->str.w, pcchBuf);
1102
1103     if( !szProduct || !szComponent )
1104         return INSTALLSTATE_INVALIDARG;
1105     if( lpPathBuf->str.w && !pcchBuf )
1106         return INSTALLSTATE_INVALIDARG;
1107
1108     if (!squash_guid( szProduct, squished_pc ) ||
1109         !squash_guid( szComponent, squished_comp ))
1110         return INSTALLSTATE_INVALIDARG;
1111
1112     rc = MSIREG_OpenProductsKey( szProduct, &hkey, FALSE);
1113     if( rc != ERROR_SUCCESS )
1114         return INSTALLSTATE_UNKNOWN;
1115
1116     RegCloseKey(hkey);
1117
1118     rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE);
1119     if( rc != ERROR_SUCCESS )
1120         return INSTALLSTATE_UNKNOWN;
1121
1122     path = msi_reg_get_val_str( hkey, squished_pc );
1123     RegCloseKey(hkey);
1124
1125     TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent),
1126            debugstr_w(szProduct), debugstr_w(path));
1127
1128     if (!path)
1129         return INSTALLSTATE_UNKNOWN;
1130
1131     if (path[0])
1132         r = INSTALLSTATE_LOCAL;
1133     else
1134         r = INSTALLSTATE_NOTUSED;
1135
1136     msi_strcpy_to_awstring( path, lpPathBuf, pcchBuf );
1137
1138     msi_free( path );
1139     return r;
1140 }
1141
1142 /******************************************************************
1143  * MsiGetComponentPathW      [MSI.@]
1144  */
1145 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
1146                                          LPWSTR lpPathBuf, DWORD* pcchBuf)
1147 {
1148     awstring path;
1149
1150     path.unicode = TRUE;
1151     path.str.w = lpPathBuf;
1152
1153     return MSI_GetComponentPath( szProduct, szComponent, &path, pcchBuf );
1154 }
1155
1156 /******************************************************************
1157  * MsiGetComponentPathA      [MSI.@]
1158  */
1159 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
1160                                          LPSTR lpPathBuf, DWORD* pcchBuf)
1161 {
1162     LPWSTR szwProduct, szwComponent = NULL;
1163     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
1164     awstring path;
1165
1166     szwProduct = strdupAtoW( szProduct );
1167     if( szProduct && !szwProduct)
1168         goto end;
1169
1170     szwComponent = strdupAtoW( szComponent );
1171     if( szComponent && !szwComponent )
1172         goto end;
1173
1174     path.unicode = FALSE;
1175     path.str.a = lpPathBuf;
1176
1177     r = MSI_GetComponentPath( szwProduct, szwComponent, &path, pcchBuf );
1178
1179 end:
1180     msi_free( szwProduct );
1181     msi_free( szwComponent );
1182
1183     return r;
1184 }
1185
1186 /******************************************************************
1187  * MsiQueryFeatureStateA      [MSI.@]
1188  */
1189 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
1190 {
1191     LPWSTR szwProduct = NULL, szwFeature= NULL;
1192     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
1193
1194     szwProduct = strdupAtoW( szProduct );
1195     if ( szProduct && !szwProduct )
1196         goto end;
1197
1198     szwFeature = strdupAtoW( szFeature );
1199     if ( szFeature && !szwFeature )
1200         goto end;
1201
1202     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
1203
1204 end:
1205     msi_free( szwProduct);
1206     msi_free( szwFeature);
1207
1208     return rc;
1209 }
1210
1211 /******************************************************************
1212  * MsiQueryFeatureStateW      [MSI.@]
1213  *
1214  * Checks the state of a feature
1215  *
1216  * PARAMS
1217  *   szProduct     [I]  Product's GUID string
1218  *   szFeature     [I]  Feature's GUID string
1219  *
1220  * RETURNS
1221  *   INSTALLSTATE_LOCAL        Feature is installed and useable
1222  *   INSTALLSTATE_ABSENT       Feature is absent
1223  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
1224  *   INSTALLSTATE_UNKNOWN      An error occurred
1225  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
1226  *
1227  */
1228 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
1229 {
1230     WCHAR squishProduct[33], comp[GUID_SIZE];
1231     GUID guid;
1232     LPWSTR components, p, parent_feature, path;
1233     UINT rc;
1234     HKEY hkey;
1235     INSTALLSTATE r;
1236     BOOL missing = FALSE;
1237
1238     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1239
1240     if (!szProduct || !szFeature)
1241         return INSTALLSTATE_INVALIDARG;
1242
1243     if (!squash_guid( szProduct, squishProduct ))
1244         return INSTALLSTATE_INVALIDARG;
1245
1246     /* check that it's installed at all */
1247     rc = MSIREG_OpenUserFeaturesKey(szProduct, &hkey, FALSE);
1248     if (rc != ERROR_SUCCESS)
1249         return INSTALLSTATE_UNKNOWN;
1250
1251     parent_feature = msi_reg_get_val_str( hkey, szFeature );
1252     RegCloseKey(hkey);
1253
1254     if (!parent_feature)
1255         return INSTALLSTATE_UNKNOWN;
1256
1257     r = (parent_feature[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
1258     msi_free(parent_feature);
1259     if (r == INSTALLSTATE_ABSENT)
1260         return r;
1261
1262     /* now check if it's complete or advertised */
1263     rc = MSIREG_OpenUserDataFeaturesKey(szProduct, &hkey, FALSE);
1264     if (rc != ERROR_SUCCESS)
1265         return INSTALLSTATE_ADVERTISED;
1266
1267     components = msi_reg_get_val_str( hkey, szFeature );
1268     RegCloseKey(hkey);
1269
1270     TRACE("rc = %d buffer = %s\n", rc, debugstr_w(components));
1271
1272     if (!components)
1273         return INSTALLSTATE_ADVERTISED;
1274
1275     for( p = components; *p && *p != 2 ; p += 20)
1276     {
1277         if (!decode_base85_guid( p, &guid ))
1278         {
1279             if (p != components)
1280                 break;
1281
1282             msi_free(components);
1283             return INSTALLSTATE_BADCONFIG;
1284         }
1285
1286         StringFromGUID2(&guid, comp, GUID_SIZE);
1287         rc = MSIREG_OpenUserDataComponentKey(comp, &hkey, FALSE);
1288         if (rc != ERROR_SUCCESS)
1289         {
1290             msi_free(components);
1291             return INSTALLSTATE_ADVERTISED;
1292         }
1293
1294         path = msi_reg_get_val_str(hkey, squishProduct);
1295         if (!path)
1296             missing = TRUE;
1297
1298         msi_free(path);
1299     }
1300
1301     TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
1302     msi_free(components);
1303
1304     if (missing)
1305         return INSTALLSTATE_ADVERTISED;
1306
1307     return INSTALLSTATE_LOCAL;
1308 }
1309
1310 /******************************************************************
1311  * MsiGetFileVersionA         [MSI.@]
1312  */
1313 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
1314                 DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf)
1315 {
1316     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
1317     UINT ret = ERROR_OUTOFMEMORY;
1318
1319     if( szFilePath )
1320     {
1321         szwFilePath = strdupAtoW( szFilePath );
1322         if( !szwFilePath )
1323             goto end;
1324     }
1325
1326     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1327     {
1328         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
1329         if( !lpwVersionBuff )
1330             goto end;
1331     }
1332
1333     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1334     {
1335         lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
1336         if( !lpwLangBuff )
1337             goto end;
1338     }
1339
1340     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
1341                              lpwLangBuff, pcchLangBuf);
1342
1343     if( lpwVersionBuff )
1344         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
1345                             lpVersionBuf, *pcchVersionBuf, NULL, NULL);
1346     if( lpwLangBuff )
1347         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
1348                             lpLangBuf, *pcchLangBuf, NULL, NULL);
1349
1350 end:
1351     msi_free(szwFilePath);
1352     msi_free(lpwVersionBuff);
1353     msi_free(lpwLangBuff);
1354
1355     return ret;
1356 }
1357
1358 /******************************************************************
1359  * MsiGetFileVersionW         [MSI.@]
1360  */
1361 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
1362                 DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf)
1363 {
1364     static const WCHAR szVersionResource[] = {'\\',0};
1365     static const WCHAR szVersionFormat[] = {
1366         '%','d','.','%','d','.','%','d','.','%','d',0};
1367     static const WCHAR szLangFormat[] = {'%','d',0};
1368     UINT ret = 0;
1369     DWORD dwVerLen;
1370     LPVOID lpVer = NULL;
1371     VS_FIXEDFILEINFO *ffi;
1372     UINT puLen;
1373     WCHAR tmp[32];
1374
1375     TRACE("%s %p %d %p %d\n", debugstr_w(szFilePath),
1376           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
1377           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
1378
1379     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
1380     if( !dwVerLen )
1381         return GetLastError();
1382
1383     lpVer = msi_alloc(dwVerLen);
1384     if( !lpVer )
1385     {
1386         ret = ERROR_OUTOFMEMORY;
1387         goto end;
1388     }
1389
1390     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
1391     {
1392         ret = GetLastError();
1393         goto end;
1394     }
1395     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1396     {
1397         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
1398             (puLen > 0) )
1399         {
1400             wsprintfW(tmp, szVersionFormat,
1401                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
1402                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
1403             lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
1404             *pcchVersionBuf = lstrlenW(lpVersionBuf);
1405         }
1406         else
1407         {
1408             *lpVersionBuf = 0;
1409             *pcchVersionBuf = 0;
1410         }
1411     }
1412
1413     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1414     {
1415         DWORD lang = GetUserDefaultLangID();
1416
1417         FIXME("Retrieve language from file\n");
1418         wsprintfW(tmp, szLangFormat, lang);
1419         lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
1420         *pcchLangBuf = lstrlenW(lpLangBuf);
1421     }
1422
1423 end:
1424     msi_free(lpVer);
1425     return ret;
1426 }
1427
1428 /***********************************************************************
1429  * MsiGetFeatureUsageW           [MSI.@]
1430  */
1431 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
1432                                  DWORD* pdwUseCount, WORD* pwDateUsed )
1433 {
1434     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
1435           pdwUseCount, pwDateUsed);
1436     return ERROR_CALL_NOT_IMPLEMENTED;
1437 }
1438
1439 /***********************************************************************
1440  * MsiGetFeatureUsageA           [MSI.@]
1441  */
1442 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
1443                                  DWORD* pdwUseCount, WORD* pwDateUsed )
1444 {
1445     LPWSTR prod = NULL, feat = NULL;
1446     UINT ret = ERROR_OUTOFMEMORY;
1447
1448     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
1449           pdwUseCount, pwDateUsed);
1450
1451     prod = strdupAtoW( szProduct );
1452     if (szProduct && !prod)
1453         goto end;
1454
1455     feat = strdupAtoW( szFeature );
1456     if (szFeature && !feat)
1457         goto end;
1458
1459     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
1460
1461 end:
1462     msi_free( prod );
1463     msi_free( feat );
1464
1465     return ret;
1466 }
1467
1468 /***********************************************************************
1469  * MsiUseFeatureExW           [MSI.@]
1470  */
1471 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
1472                                       DWORD dwInstallMode, DWORD dwReserved )
1473 {
1474     INSTALLSTATE state;
1475
1476     TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
1477           dwInstallMode, dwReserved);
1478
1479     state = MsiQueryFeatureStateW( szProduct, szFeature );
1480
1481     if (dwReserved)
1482         return INSTALLSTATE_INVALIDARG;
1483
1484     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
1485     {
1486         FIXME("mark product %s feature %s as used\n",
1487               debugstr_w(szProduct), debugstr_w(szFeature) );
1488     }
1489
1490     return state;
1491 }
1492
1493 /***********************************************************************
1494  * MsiUseFeatureExA           [MSI.@]
1495  */
1496 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
1497                                       DWORD dwInstallMode, DWORD dwReserved )
1498 {
1499     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
1500     LPWSTR prod = NULL, feat = NULL;
1501
1502     TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
1503           dwInstallMode, dwReserved);
1504
1505     prod = strdupAtoW( szProduct );
1506     if (szProduct && !prod)
1507         goto end;
1508
1509     feat = strdupAtoW( szFeature );
1510     if (szFeature && !feat)
1511         goto end;
1512
1513     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
1514
1515 end:
1516     msi_free( prod );
1517     msi_free( feat );
1518
1519     return ret;
1520 }
1521
1522 /***********************************************************************
1523  * MsiUseFeatureW             [MSI.@]
1524  */
1525 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
1526 {
1527     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
1528 }
1529
1530 /***********************************************************************
1531  * MsiUseFeatureA             [MSI.@]
1532  */
1533 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
1534 {
1535     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
1536 }
1537
1538 /***********************************************************************
1539  * MSI_ProvideQualifiedComponentEx [internal]
1540  */
1541 static UINT WINAPI MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
1542                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
1543                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
1544                 DWORD* pcchPathBuf)
1545 {
1546     WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
1547           feature[MAX_FEATURE_CHARS+1];
1548     LPWSTR info;
1549     HKEY hkey;
1550     DWORD sz;
1551     UINT rc;
1552
1553     TRACE("%s %s %i %s %i %i %p %p\n", debugstr_w(szComponent),
1554           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
1555           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1556
1557     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
1558     if (rc != ERROR_SUCCESS)
1559         return ERROR_INDEX_ABSENT;
1560
1561     info = msi_reg_get_val_str( hkey, szQualifier );
1562     RegCloseKey(hkey);
1563
1564     if (!info)
1565         return ERROR_INDEX_ABSENT;
1566
1567     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
1568
1569     if (!szProduct)
1570         rc = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
1571     else
1572         rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
1573
1574     msi_free( info );
1575
1576     if (rc != INSTALLSTATE_LOCAL)
1577         return ERROR_FILE_NOT_FOUND;
1578
1579     return ERROR_SUCCESS;
1580 }
1581
1582 /***********************************************************************
1583  * MsiProvideQualifiedComponentExW [MSI.@]
1584  */
1585 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
1586                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
1587                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
1588                 DWORD* pcchPathBuf)
1589 {
1590     awstring path;
1591
1592     path.unicode = TRUE;
1593     path.str.w = lpPathBuf;
1594
1595     return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
1596             dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
1597 }
1598
1599 /***********************************************************************
1600  * MsiProvideQualifiedComponentExA [MSI.@]
1601  */
1602 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
1603                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR szProduct,
1604                 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
1605                 DWORD* pcchPathBuf)
1606 {
1607     LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
1608     UINT r = ERROR_OUTOFMEMORY;
1609     awstring path;
1610
1611     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
1612           debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
1613           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1614
1615     szwComponent = strdupAtoW( szComponent );
1616     if (szComponent && !szwComponent)
1617         goto end;
1618
1619     szwQualifier = strdupAtoW( szQualifier );
1620     if (szQualifier && !szwQualifier)
1621         goto end;
1622
1623     szwProduct = strdupAtoW( szProduct );
1624     if (szProduct && !szwProduct)
1625         goto end;
1626
1627     path.unicode = FALSE;
1628     path.str.a = lpPathBuf;
1629
1630     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
1631                               dwInstallMode, szwProduct, Unused1,
1632                               Unused2, &path, pcchPathBuf);
1633 end:
1634     msi_free(szwProduct);
1635     msi_free(szwComponent);
1636     msi_free(szwQualifier);
1637
1638     return r;
1639 }
1640
1641 /***********************************************************************
1642  * MsiProvideQualifiedComponentW [MSI.@]
1643  */
1644 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
1645                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
1646                 DWORD* pcchPathBuf)
1647 {
1648     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
1649                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1650 }
1651
1652 /***********************************************************************
1653  * MsiProvideQualifiedComponentA [MSI.@]
1654  */
1655 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
1656                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
1657                 DWORD* pcchPathBuf)
1658 {
1659     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
1660                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1661 }
1662
1663 /***********************************************************************
1664  * MSI_GetUserInfo [internal]
1665  */
1666 static USERINFOSTATE WINAPI MSI_GetUserInfo(LPCWSTR szProduct,
1667                 awstring *lpUserNameBuf, DWORD* pcchUserNameBuf,
1668                 awstring *lpOrgNameBuf, DWORD* pcchOrgNameBuf,
1669                 awstring *lpSerialBuf, DWORD* pcchSerialBuf)
1670 {
1671     HKEY hkey;
1672     LPWSTR user, org, serial;
1673     UINT r;
1674     USERINFOSTATE state;
1675
1676     TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf,
1677           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1678           pcchSerialBuf);
1679
1680     if (!szProduct)
1681         return USERINFOSTATE_INVALIDARG;
1682
1683     r = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
1684     if (r != ERROR_SUCCESS)
1685         return USERINFOSTATE_UNKNOWN;
1686
1687     user = msi_reg_get_val_str( hkey, INSTALLPROPERTY_REGOWNERW );
1688     org = msi_reg_get_val_str( hkey, INSTALLPROPERTY_REGCOMPANYW );
1689     serial = msi_reg_get_val_str( hkey, INSTALLPROPERTY_PRODUCTIDW );
1690
1691     RegCloseKey(hkey);
1692
1693     state = USERINFOSTATE_PRESENT;
1694
1695     if (user)
1696     {
1697         r = msi_strcpy_to_awstring( user, lpUserNameBuf, pcchUserNameBuf );
1698         if (r == ERROR_MORE_DATA)
1699             state = USERINFOSTATE_MOREDATA;
1700     }
1701     else
1702         state = USERINFOSTATE_ABSENT;
1703     if (org)
1704     {
1705         r = msi_strcpy_to_awstring( org, lpOrgNameBuf, pcchOrgNameBuf );
1706         if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT)
1707             state = USERINFOSTATE_MOREDATA;
1708     }
1709     /* msdn states: The user information is considered to be present even in the absence of a company name. */
1710     if (serial)
1711     {
1712         r = msi_strcpy_to_awstring( serial, lpSerialBuf, pcchSerialBuf );
1713         if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT)
1714             state = USERINFOSTATE_MOREDATA;
1715     }
1716     else
1717         state = USERINFOSTATE_ABSENT;
1718
1719     msi_free( user );
1720     msi_free( org );
1721     msi_free( serial );
1722
1723     return state;
1724 }
1725
1726 /***********************************************************************
1727  * MsiGetUserInfoW [MSI.@]
1728  */
1729 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
1730                 LPWSTR lpUserNameBuf, DWORD* pcchUserNameBuf,
1731                 LPWSTR lpOrgNameBuf, DWORD* pcchOrgNameBuf,
1732                 LPWSTR lpSerialBuf, DWORD* pcchSerialBuf)
1733 {
1734     awstring user, org, serial;
1735
1736     user.unicode = TRUE;
1737     user.str.w = lpUserNameBuf;
1738     org.unicode = TRUE;
1739     org.str.w = lpOrgNameBuf;
1740     serial.unicode = TRUE;
1741     serial.str.w = lpSerialBuf;
1742
1743     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
1744                             &org, pcchOrgNameBuf,
1745                             &serial, pcchSerialBuf );
1746 }
1747
1748 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
1749                 LPSTR lpUserNameBuf, DWORD* pcchUserNameBuf,
1750                 LPSTR lpOrgNameBuf, DWORD* pcchOrgNameBuf,
1751                 LPSTR lpSerialBuf, DWORD* pcchSerialBuf)
1752 {
1753     awstring user, org, serial;
1754     LPWSTR prod;
1755     UINT r;
1756
1757     prod = strdupAtoW( szProduct );
1758     if (szProduct && !prod)
1759         return ERROR_OUTOFMEMORY;
1760
1761     user.unicode = FALSE;
1762     user.str.a = lpUserNameBuf;
1763     org.unicode = FALSE;
1764     org.str.a = lpOrgNameBuf;
1765     serial.unicode = FALSE;
1766     serial.str.a = lpSerialBuf;
1767
1768     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
1769                          &org, pcchOrgNameBuf,
1770                          &serial, pcchSerialBuf );
1771
1772     msi_free( prod );
1773
1774     return r;
1775 }
1776
1777 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
1778 {
1779     MSIHANDLE handle;
1780     UINT rc;
1781     MSIPACKAGE *package;
1782     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1783
1784     TRACE("(%s)\n",debugstr_w(szProduct));
1785
1786     rc = MsiOpenProductW(szProduct,&handle);
1787     if (rc != ERROR_SUCCESS)
1788         return ERROR_INVALID_PARAMETER;
1789
1790     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1791     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
1792     msiobj_release( &package->hdr );
1793
1794     MsiCloseHandle(handle);
1795
1796     return rc;
1797 }
1798
1799 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
1800 {
1801     MSIHANDLE handle;
1802     UINT rc;
1803     MSIPACKAGE *package;
1804     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1805
1806     TRACE("(%s)\n",debugstr_a(szProduct));
1807
1808     rc = MsiOpenProductA(szProduct,&handle);
1809     if (rc != ERROR_SUCCESS)
1810         return ERROR_INVALID_PARAMETER;
1811
1812     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1813     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
1814     msiobj_release( &package->hdr );
1815
1816     MsiCloseHandle(handle);
1817
1818     return rc;
1819 }
1820
1821 /***********************************************************************
1822  * MsiConfigureFeatureA            [MSI.@]
1823  */
1824 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
1825 {
1826     LPWSTR prod, feat = NULL;
1827     UINT r = ERROR_OUTOFMEMORY;
1828
1829     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
1830
1831     prod = strdupAtoW( szProduct );
1832     if (szProduct && !prod)
1833         goto end;
1834
1835     feat = strdupAtoW( szFeature );
1836     if (szFeature && !feat)
1837         goto end;
1838
1839     r = MsiConfigureFeatureW(prod, feat, eInstallState);
1840
1841 end:
1842     msi_free(feat);
1843     msi_free(prod);
1844
1845     return r;
1846 }
1847
1848 /***********************************************************************
1849  * MsiConfigureFeatureW            [MSI.@]
1850  */
1851 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
1852 {
1853     static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1854     MSIPACKAGE *package = NULL;
1855     UINT r;
1856     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
1857     DWORD sz;
1858
1859     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
1860
1861     if (!szProduct || !szFeature)
1862         return ERROR_INVALID_PARAMETER;
1863
1864     switch (eInstallState)
1865     {
1866     case INSTALLSTATE_DEFAULT:
1867         /* FIXME: how do we figure out the default location? */
1868         eInstallState = INSTALLSTATE_LOCAL;
1869         break;
1870     case INSTALLSTATE_LOCAL:
1871     case INSTALLSTATE_SOURCE:
1872     case INSTALLSTATE_ABSENT:
1873     case INSTALLSTATE_ADVERTISED:
1874         break;
1875     default:
1876         return ERROR_INVALID_PARAMETER;
1877     }
1878
1879     r = MSI_OpenProductW( szProduct, &package );
1880     if (r != ERROR_SUCCESS)
1881         return r;
1882
1883     sz = sizeof(sourcepath);
1884     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
1885                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
1886
1887     sz = sizeof(filename);
1888     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
1889                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
1890
1891     lstrcatW( sourcepath, filename );
1892
1893     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
1894
1895     r = ACTION_PerformUIAction( package, szCostInit, -1 );
1896     if (r != ERROR_SUCCESS)
1897         goto end;
1898
1899     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
1900     if (r != ERROR_SUCCESS)
1901         goto end;
1902
1903     r = MSI_InstallPackage( package, sourcepath, NULL );
1904
1905 end:
1906     msiobj_release( &package->hdr );
1907
1908     return r;
1909 }
1910
1911 /***********************************************************************
1912  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
1913  *
1914  * Notes: undocumented
1915  */
1916 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
1917 {
1918     WCHAR path[MAX_PATH];
1919
1920     TRACE("%d\n", dwReserved);
1921
1922     if (dwReserved)
1923     {
1924         FIXME("dwReserved=%d\n", dwReserved);
1925         return ERROR_INVALID_PARAMETER;
1926     }
1927
1928     if (!GetWindowsDirectoryW(path, MAX_PATH))
1929         return ERROR_FUNCTION_FAILED;
1930
1931     lstrcatW(path, installerW);
1932
1933     if (!CreateDirectoryW(path, NULL))
1934         return ERROR_FUNCTION_FAILED;
1935
1936     return ERROR_SUCCESS;
1937 }
1938
1939 /***********************************************************************
1940  * MsiGetShortcutTargetA           [MSI.@]
1941  */
1942 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
1943                                    LPSTR szProductCode, LPSTR szFeatureId,
1944                                    LPSTR szComponentCode )
1945 {
1946     LPWSTR target;
1947     const int len = MAX_FEATURE_CHARS+1;
1948     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
1949     UINT r;
1950
1951     target = strdupAtoW( szShortcutTarget );
1952     if (szShortcutTarget && !target )
1953         return ERROR_OUTOFMEMORY;
1954     product[0] = 0;
1955     feature[0] = 0;
1956     component[0] = 0;
1957     r = MsiGetShortcutTargetW( target, product, feature, component );
1958     msi_free( target );
1959     if (r == ERROR_SUCCESS)
1960     {
1961         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
1962         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
1963         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
1964     }
1965     return r;
1966 }
1967
1968 /***********************************************************************
1969  * MsiGetShortcutTargetW           [MSI.@]
1970  */
1971 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
1972                                    LPWSTR szProductCode, LPWSTR szFeatureId,
1973                                    LPWSTR szComponentCode )
1974 {
1975     IShellLinkDataList *dl = NULL;
1976     IPersistFile *pf = NULL;
1977     LPEXP_DARWIN_LINK darwin = NULL;
1978     HRESULT r, init;
1979
1980     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
1981           szProductCode, szFeatureId, szComponentCode );
1982
1983     init = CoInitialize(NULL);
1984
1985     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1986                           &IID_IPersistFile, (LPVOID*) &pf );
1987     if( SUCCEEDED( r ) )
1988     {
1989         r = IPersistFile_Load( pf, szShortcutTarget,
1990                                STGM_READ | STGM_SHARE_DENY_WRITE );
1991         if( SUCCEEDED( r ) )
1992         {
1993             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
1994                                              (LPVOID*) &dl );
1995             if( SUCCEEDED( r ) )
1996             {
1997                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
1998                                                   (LPVOID) &darwin );
1999                 IShellLinkDataList_Release( dl );
2000             }
2001         }
2002         IPersistFile_Release( pf );
2003     }
2004
2005     if (SUCCEEDED(init))
2006         CoUninitialize();
2007
2008     TRACE("darwin = %p\n", darwin);
2009
2010     if (darwin)
2011     {
2012         DWORD sz;
2013         UINT ret;
2014
2015         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
2016                   szProductCode, szFeatureId, szComponentCode, &sz );
2017         LocalFree( darwin );
2018         return ret;
2019     }
2020
2021     return ERROR_FUNCTION_FAILED;
2022 }
2023
2024 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
2025                                   DWORD dwReinstallMode )
2026 {
2027     MSIPACKAGE* package = NULL;
2028     UINT r;
2029     WCHAR sourcepath[MAX_PATH];
2030     WCHAR filename[MAX_PATH];
2031     static const WCHAR szLogVerbose[] = {
2032         ' ','L','O','G','V','E','R','B','O','S','E',0 };
2033     static const WCHAR szInstalled[] = { 'I','n','s','t','a','l','l','e','d',0};
2034     static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0};
2035     static const WCHAR szReinstallMode[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
2036     static const WCHAR szOne[] = {'1',0};
2037     WCHAR reinstallmode[11];
2038     LPWSTR ptr;
2039     DWORD sz;
2040
2041     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
2042                            dwReinstallMode);
2043
2044     ptr = reinstallmode;
2045
2046     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
2047         *ptr++ = 'p';
2048     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
2049         *ptr++ = 'o';
2050     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
2051         *ptr++ = 'w';
2052     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
2053         *ptr++ = 'd';
2054     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
2055         *ptr++ = 'c';
2056     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
2057         *ptr++ = 'a';
2058     if (dwReinstallMode & REINSTALLMODE_USERDATA)
2059         *ptr++ = 'u';
2060     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
2061         *ptr++ = 'm';
2062     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
2063         *ptr++ = 's';
2064     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2065         *ptr++ = 'v';
2066     *ptr = 0;
2067     
2068     sz = sizeof(sourcepath);
2069     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
2070             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
2071
2072     sz = sizeof(filename);
2073     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
2074             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
2075
2076     lstrcatW( sourcepath, filename );
2077
2078     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2079         r = MSI_OpenPackageW( sourcepath, &package );
2080     else
2081         r = MSI_OpenProductW( szProduct, &package );
2082
2083     if (r != ERROR_SUCCESS)
2084         return r;
2085
2086     MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
2087     MSI_SetPropertyW( package, szInstalled, szOne );
2088     MSI_SetPropertyW( package, szLogVerbose, szOne );
2089     MSI_SetPropertyW( package, szReinstall, szFeature );
2090
2091     r = MSI_InstallPackage( package, sourcepath, NULL );
2092
2093     msiobj_release( &package->hdr );
2094
2095     return r;
2096 }
2097
2098 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
2099                                   DWORD dwReinstallMode )
2100 {
2101     LPWSTR wszProduct;
2102     LPWSTR wszFeature;
2103     UINT rc;
2104
2105     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
2106                            dwReinstallMode);
2107
2108     wszProduct = strdupAtoW(szProduct);
2109     wszFeature = strdupAtoW(szFeature);
2110
2111     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
2112
2113     msi_free(wszProduct);
2114     msi_free(wszFeature);
2115     return rc;
2116 }
2117
2118 typedef struct
2119 {
2120     unsigned int i[2];
2121     unsigned int buf[4];
2122     unsigned char in[64];
2123     unsigned char digest[16];
2124 } MD5_CTX;
2125
2126 extern VOID WINAPI MD5Init( MD5_CTX *);
2127 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
2128 extern VOID WINAPI MD5Final( MD5_CTX *);
2129
2130 /***********************************************************************
2131  * MsiGetFileHashW            [MSI.@]
2132  */
2133 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
2134                              PMSIFILEHASHINFO pHash )
2135 {
2136     HANDLE handle, mapping;
2137     void *p;
2138     DWORD length;
2139     UINT r = ERROR_FUNCTION_FAILED;
2140
2141     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
2142
2143     if (dwOptions)
2144         return ERROR_INVALID_PARAMETER;
2145     if (!pHash)
2146         return ERROR_INVALID_PARAMETER;
2147     if (pHash->dwFileHashInfoSize < sizeof *pHash)
2148         return ERROR_INVALID_PARAMETER;
2149
2150     handle = CreateFileW( szFilePath, GENERIC_READ,
2151                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
2152     if (handle == INVALID_HANDLE_VALUE)
2153         return ERROR_FILE_NOT_FOUND;
2154
2155     length = GetFileSize( handle, NULL );
2156
2157     mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
2158     if (mapping)
2159     {
2160         p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
2161         if (p)
2162         {
2163             MD5_CTX ctx;
2164
2165             MD5Init( &ctx );
2166             MD5Update( &ctx, p, length );
2167             MD5Final( &ctx );
2168             UnmapViewOfFile( p );
2169
2170             memcpy( pHash->dwData, &ctx.digest, sizeof pHash->dwData );
2171             r = ERROR_SUCCESS;
2172         }
2173         CloseHandle( mapping );
2174     }
2175     CloseHandle( handle );
2176
2177     return r;
2178 }
2179
2180 /***********************************************************************
2181  * MsiGetFileHashA            [MSI.@]
2182  */
2183 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
2184                              PMSIFILEHASHINFO pHash )
2185 {
2186     LPWSTR file;
2187     UINT r;
2188
2189     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
2190
2191     file = strdupAtoW( szFilePath );
2192     if (szFilePath && !file)
2193         return ERROR_OUTOFMEMORY;
2194
2195     r = MsiGetFileHashW( file, dwOptions, pHash );
2196     msi_free( file );
2197     return r;
2198 }
2199
2200 /***********************************************************************
2201  * MsiAdvertiseScriptW        [MSI.@]
2202  */
2203 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
2204                                  PHKEY phRegData, BOOL fRemoveItems )
2205 {
2206     FIXME("%s %08x %p %d\n",
2207           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2208     return ERROR_CALL_NOT_IMPLEMENTED;
2209 }
2210
2211 /***********************************************************************
2212  * MsiAdvertiseScriptA        [MSI.@]
2213  */
2214 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
2215                                  PHKEY phRegData, BOOL fRemoveItems )
2216 {
2217     FIXME("%s %08x %p %d\n",
2218           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2219     return ERROR_CALL_NOT_IMPLEMENTED;
2220 }