rpcrt4: Try a lot harder to resuse existing connections by comparing inside the RpcQu...
[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 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
736 {
737     LPWSTR szwProduct = NULL;
738     INSTALLSTATE r;
739
740     if( szProduct )
741     {
742          szwProduct = strdupAtoW( szProduct );
743          if( !szwProduct )
744              return ERROR_OUTOFMEMORY;
745     }
746     r = MsiQueryProductStateW( szwProduct );
747     msi_free( szwProduct );
748     return r;
749 }
750
751 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
752 {
753     UINT rc;
754     INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN;
755     HKEY hkey = 0;
756     static const WCHAR szWindowsInstaller[] = {
757          'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0 };
758     DWORD sz;
759
760     TRACE("%s\n", debugstr_w(szProduct));
761
762     if (!szProduct)
763         return INSTALLSTATE_INVALIDARG;
764
765     rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE);
766     if (rc != ERROR_SUCCESS)
767         goto end;
768
769     RegCloseKey(hkey);
770
771     rc = MSIREG_OpenUninstallKey(szProduct,&hkey,FALSE);
772     if (rc != ERROR_SUCCESS)
773         goto end;
774
775     sz = sizeof(rrc);
776     rc = RegQueryValueExW(hkey,szWindowsInstaller,NULL,NULL,(LPVOID)&rrc, &sz);
777     if (rc != ERROR_SUCCESS)
778         goto end;
779
780     switch (rrc)
781     {
782     case 1:
783         /* default */
784         rrc = INSTALLSTATE_DEFAULT;
785         break;
786     default:
787         FIXME("Unknown install state read from registry (%i)\n",rrc);
788         rrc = INSTALLSTATE_UNKNOWN;
789         break;
790     }
791 end:
792     RegCloseKey(hkey);
793     return rrc;
794 }
795
796 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
797 {
798     INSTALLUILEVEL old = gUILevel;
799     HWND oldwnd = gUIhwnd;
800
801     TRACE("%08x %p\n", dwUILevel, phWnd);
802
803     gUILevel = dwUILevel;
804     if (phWnd)
805     {
806         gUIhwnd = *phWnd;
807         *phWnd = oldwnd;
808     }
809     return old;
810 }
811
812 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
813                                   DWORD dwMessageFilter, LPVOID pvContext)
814 {
815     INSTALLUI_HANDLERA prev = gUIHandlerA;
816
817     TRACE("%p %x %p\n",puiHandler, dwMessageFilter,pvContext);
818     gUIHandlerA = puiHandler;
819     gUIFilter = dwMessageFilter;
820     gUIContext = pvContext;
821
822     return prev;
823 }
824
825 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
826                                   DWORD dwMessageFilter, LPVOID pvContext)
827 {
828     INSTALLUI_HANDLERW prev = gUIHandlerW;
829
830     TRACE("%p %x %p\n",puiHandler,dwMessageFilter,pvContext);
831     gUIHandlerW = puiHandler;
832     gUIFilter = dwMessageFilter;
833     gUIContext = pvContext;
834
835     return prev;
836 }
837
838 /******************************************************************
839  *  MsiLoadStringW            [MSI.@]
840  *
841  * Loads a string from MSI's string resources.
842  *
843  * PARAMS
844  *
845  *   handle        [I]  only -1 is handled currently
846  *   id            [I]  id of the string to be loaded
847  *   lpBuffer      [O]  buffer for the string to be written to
848  *   nBufferMax    [I]  maximum size of the buffer in characters
849  *   lang          [I]  the preferred language for the string
850  *
851  * RETURNS
852  *
853  *   If successful, this function returns the language id of the string loaded
854  *   If the function fails, the function returns zero.
855  *
856  * NOTES
857  *
858  *   The type of the first parameter is unknown.  LoadString's prototype
859  *  suggests that it might be a module handle.  I have made it an MSI handle
860  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
861  *  handle.  Maybe strings can be stored in an MSI database somehow.
862  */
863 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
864                 int nBufferMax, LANGID lang )
865 {
866     HRSRC hres;
867     HGLOBAL hResData;
868     LPWSTR p;
869     DWORD i, len;
870
871     TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
872
873     if( handle != -1 )
874         FIXME("don't know how to deal with handle = %08lx\n", handle);
875
876     if( !lang )
877         lang = GetUserDefaultLangID();
878
879     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
880                             (LPWSTR)1, lang );
881     if( !hres )
882         return 0;
883     hResData = LoadResource( msi_hInstance, hres );
884     if( !hResData )
885         return 0;
886     p = LockResource( hResData );
887     if( !p )
888         return 0;
889
890     for (i = 0; i < (id&0xf); i++)
891         p += *p + 1;
892     len = *p;
893
894     if( nBufferMax <= len )
895         return 0;
896
897     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
898     lpBuffer[ len ] = 0;
899
900     TRACE("found -> %s\n", debugstr_w(lpBuffer));
901
902     return lang;
903 }
904
905 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
906                 int nBufferMax, LANGID lang )
907 {
908     LPWSTR bufW;
909     LANGID r;
910     DWORD len;
911
912     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
913     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
914     if( r )
915     {
916         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
917         if( len <= nBufferMax )
918             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
919                                  lpBuffer, nBufferMax, NULL, NULL );
920         else
921             r = 0;
922     }
923     msi_free(bufW);
924     return r;
925 }
926
927 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
928                 DWORD *pcchBuf)
929 {
930     char szProduct[GUID_SIZE];
931
932     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
933
934     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
935         return INSTALLSTATE_UNKNOWN;
936
937     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
938 }
939
940 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
941                 DWORD *pcchBuf)
942 {
943     WCHAR szProduct[GUID_SIZE];
944
945     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
946
947     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
948         return INSTALLSTATE_UNKNOWN;
949
950     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
951 }
952
953 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
954                 WORD wLanguageId, DWORD f)
955 {
956     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption),
957           uType, wLanguageId, f);
958     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
959 }
960
961 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
962                 WORD wLanguageId, DWORD f)
963 {
964     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption),
965           uType, wLanguageId, f);
966     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
967 }
968
969 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
970                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
971                 DWORD* pcchPathBuf )
972 {
973     FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
974           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
975           pcchPathBuf);
976     return ERROR_CALL_NOT_IMPLEMENTED;
977 }
978
979 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
980                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
981                 DWORD* pcchPathBuf )
982 {
983     FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
984           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
985           pcchPathBuf);
986     return ERROR_CALL_NOT_IMPLEMENTED;
987 }
988
989 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
990                 LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
991 {
992     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
993     return ERROR_CALL_NOT_IMPLEMENTED;
994 }
995
996 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
997                 LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
998 {
999     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
1000     return ERROR_CALL_NOT_IMPLEMENTED;
1001 }
1002
1003 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
1004                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
1005                 DWORD* pcbHashData)
1006 {
1007     FIXME("%s %08x %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
1008           ppcCertContext, pbHashData, pcbHashData);
1009     return ERROR_CALL_NOT_IMPLEMENTED;
1010 }
1011
1012 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
1013                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
1014                 DWORD* pcbHashData)
1015 {
1016     FIXME("%s %08x %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
1017           ppcCertContext, pbHashData, pcbHashData);
1018     return ERROR_CALL_NOT_IMPLEMENTED;
1019 }
1020
1021 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
1022                                     LPSTR szValue, DWORD *pccbValue )
1023 {
1024     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
1025     return ERROR_CALL_NOT_IMPLEMENTED;
1026 }
1027
1028 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
1029                                     LPWSTR szValue, DWORD *pccbValue )
1030 {
1031     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
1032     return ERROR_CALL_NOT_IMPLEMENTED;
1033 }
1034
1035 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
1036 {
1037     UINT r;
1038     LPWSTR szPack = NULL;
1039
1040     TRACE("%s\n", debugstr_a(szPackage) );
1041
1042     if( szPackage )
1043     {
1044         szPack = strdupAtoW( szPackage );
1045         if( !szPack )
1046             return ERROR_OUTOFMEMORY;
1047     }
1048
1049     r = MsiVerifyPackageW( szPack );
1050
1051     msi_free( szPack );
1052
1053     return r;
1054 }
1055
1056 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
1057 {
1058     MSIHANDLE handle;
1059     UINT r;
1060
1061     TRACE("%s\n", debugstr_w(szPackage) );
1062
1063     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
1064     MsiCloseHandle( handle );
1065
1066     return r;
1067 }
1068
1069 static INSTALLSTATE WINAPI MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent,
1070                                                 awstring* lpPathBuf, DWORD* pcchBuf)
1071 {
1072     WCHAR squished_pc[GUID_SIZE], squished_comp[GUID_SIZE];
1073     UINT rc;
1074     HKEY hkey = 0;
1075     LPWSTR path = NULL;
1076     INSTALLSTATE r;
1077
1078     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1079            debugstr_w(szComponent), lpPathBuf->str.w, pcchBuf);
1080
1081     if( !szProduct || !szComponent )
1082         return INSTALLSTATE_INVALIDARG;
1083     if( lpPathBuf->str.w && !pcchBuf )
1084         return INSTALLSTATE_INVALIDARG;
1085
1086     if (!squash_guid( szProduct, squished_pc ) ||
1087         !squash_guid( szComponent, squished_comp ))
1088         return INSTALLSTATE_INVALIDARG;
1089
1090     rc = MSIREG_OpenProductsKey( szProduct, &hkey, FALSE);
1091     if( rc != ERROR_SUCCESS )
1092         return INSTALLSTATE_UNKNOWN;
1093
1094     RegCloseKey(hkey);
1095
1096     rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE);
1097     if( rc != ERROR_SUCCESS )
1098         return INSTALLSTATE_UNKNOWN;
1099
1100     path = msi_reg_get_val_str( hkey, squished_pc );
1101     RegCloseKey(hkey);
1102
1103     TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent),
1104            debugstr_w(szProduct), debugstr_w(path));
1105
1106     if (!path)
1107         return INSTALLSTATE_UNKNOWN;
1108
1109     if (path[0])
1110         r = INSTALLSTATE_LOCAL;
1111     else
1112         r = INSTALLSTATE_NOTUSED;
1113
1114     msi_strcpy_to_awstring( path, lpPathBuf, pcchBuf );
1115
1116     msi_free( path );
1117     return r;
1118 }
1119
1120 /******************************************************************
1121  * MsiGetComponentPathW      [MSI.@]
1122  */
1123 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
1124                                          LPWSTR lpPathBuf, DWORD* pcchBuf)
1125 {
1126     awstring path;
1127
1128     path.unicode = TRUE;
1129     path.str.w = lpPathBuf;
1130
1131     return MSI_GetComponentPath( szProduct, szComponent, &path, pcchBuf );
1132 }
1133
1134 /******************************************************************
1135  * MsiGetComponentPathA      [MSI.@]
1136  */
1137 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
1138                                          LPSTR lpPathBuf, DWORD* pcchBuf)
1139 {
1140     LPWSTR szwProduct, szwComponent = NULL;
1141     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
1142     awstring path;
1143
1144     szwProduct = strdupAtoW( szProduct );
1145     if( szProduct && !szwProduct)
1146         goto end;
1147
1148     szwComponent = strdupAtoW( szComponent );
1149     if( szComponent && !szwComponent )
1150         goto end;
1151
1152     path.unicode = FALSE;
1153     path.str.a = lpPathBuf;
1154
1155     r = MSI_GetComponentPath( szwProduct, szwComponent, &path, pcchBuf );
1156
1157 end:
1158     msi_free( szwProduct );
1159     msi_free( szwComponent );
1160
1161     return r;
1162 }
1163
1164 /******************************************************************
1165  * MsiQueryFeatureStateA      [MSI.@]
1166  */
1167 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
1168 {
1169     LPWSTR szwProduct = NULL, szwFeature= NULL;
1170     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
1171
1172     szwProduct = strdupAtoW( szProduct );
1173     if ( szProduct && !szwProduct )
1174         goto end;
1175
1176     szwFeature = strdupAtoW( szFeature );
1177     if ( szFeature && !szwFeature )
1178         goto end;
1179
1180     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
1181
1182 end:
1183     msi_free( szwProduct);
1184     msi_free( szwFeature);
1185
1186     return rc;
1187 }
1188
1189 /******************************************************************
1190  * MsiQueryFeatureStateW      [MSI.@]
1191  *
1192  * Checks the state of a feature
1193  *
1194  * PARAMS
1195  *   szProduct     [I]  Product's GUID string
1196  *   szFeature     [I]  Feature's GUID string
1197  *
1198  * RETURNS
1199  *   INSTALLSTATE_LOCAL        Feature is installed and useable
1200  *   INSTALLSTATE_ABSENT       Feature is absent
1201  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
1202  *   INSTALLSTATE_UNKNOWN      An error occurred
1203  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
1204  *
1205  */
1206 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
1207 {
1208     WCHAR squishProduct[33], comp[GUID_SIZE];
1209     GUID guid;
1210     LPWSTR components, p, parent_feature;
1211     UINT rc;
1212     HKEY hkey;
1213     INSTALLSTATE r;
1214     BOOL missing = FALSE;
1215
1216     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1217
1218     if (!szProduct || !szFeature)
1219         return INSTALLSTATE_INVALIDARG;
1220
1221     if (!squash_guid( szProduct, squishProduct ))
1222         return INSTALLSTATE_INVALIDARG;
1223
1224     /* check that it's installed at all */
1225     rc = MSIREG_OpenUserFeaturesKey(szProduct, &hkey, FALSE);
1226     if (rc != ERROR_SUCCESS)
1227         return INSTALLSTATE_UNKNOWN;
1228
1229     parent_feature = msi_reg_get_val_str( hkey, szFeature );
1230     RegCloseKey(hkey);
1231
1232     if (!parent_feature)
1233         return INSTALLSTATE_UNKNOWN;
1234
1235     r = (parent_feature[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
1236     msi_free(parent_feature);
1237     if (r == INSTALLSTATE_ABSENT)
1238         return r;
1239
1240     /* now check if it's complete or advertised */
1241     rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE);
1242     if (rc != ERROR_SUCCESS)
1243         return INSTALLSTATE_UNKNOWN;
1244
1245     components = msi_reg_get_val_str( hkey, szFeature );
1246     RegCloseKey(hkey);
1247
1248     TRACE("rc = %d buffer = %s\n", rc, debugstr_w(components));
1249
1250     if (!components)
1251     {
1252         ERR("components missing %s %s\n",
1253             debugstr_w(szProduct), debugstr_w(szFeature));
1254         return INSTALLSTATE_UNKNOWN;
1255     }
1256
1257     for( p = components; *p != 2 ; p += 20)
1258     {
1259         if (!decode_base85_guid( p, &guid ))
1260         {
1261             ERR("%s\n", debugstr_w(p));
1262             break;
1263         }
1264         StringFromGUID2(&guid, comp, GUID_SIZE);
1265         r = MsiGetComponentPathW(szProduct, comp, NULL, 0);
1266         TRACE("component %s state %d\n", debugstr_guid(&guid), r);
1267         switch (r)
1268         {
1269         case INSTALLSTATE_NOTUSED:
1270         case INSTALLSTATE_LOCAL:
1271         case INSTALLSTATE_SOURCE:
1272             break;
1273         default:
1274             missing = TRUE;
1275         }
1276     }
1277
1278     TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
1279     msi_free(components);
1280
1281     if (missing)
1282         return INSTALLSTATE_ADVERTISED;
1283
1284     return INSTALLSTATE_LOCAL;
1285 }
1286
1287 /******************************************************************
1288  * MsiGetFileVersionA         [MSI.@]
1289  */
1290 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
1291                 DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf)
1292 {
1293     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
1294     UINT ret = ERROR_OUTOFMEMORY;
1295
1296     if( szFilePath )
1297     {
1298         szwFilePath = strdupAtoW( szFilePath );
1299         if( !szwFilePath )
1300             goto end;
1301     }
1302
1303     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1304     {
1305         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
1306         if( !lpwVersionBuff )
1307             goto end;
1308     }
1309
1310     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1311     {
1312         lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
1313         if( !lpwLangBuff )
1314             goto end;
1315     }
1316
1317     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
1318                              lpwLangBuff, pcchLangBuf);
1319
1320     if( lpwVersionBuff )
1321         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
1322                             lpVersionBuf, *pcchVersionBuf, NULL, NULL);
1323     if( lpwLangBuff )
1324         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
1325                             lpLangBuf, *pcchLangBuf, NULL, NULL);
1326
1327 end:
1328     msi_free(szwFilePath);
1329     msi_free(lpwVersionBuff);
1330     msi_free(lpwLangBuff);
1331
1332     return ret;
1333 }
1334
1335 /******************************************************************
1336  * MsiGetFileVersionW         [MSI.@]
1337  */
1338 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
1339                 DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf)
1340 {
1341     static const WCHAR szVersionResource[] = {'\\',0};
1342     static const WCHAR szVersionFormat[] = {
1343         '%','d','.','%','d','.','%','d','.','%','d',0};
1344     static const WCHAR szLangFormat[] = {'%','d',0};
1345     UINT ret = 0;
1346     DWORD dwVerLen;
1347     LPVOID lpVer = NULL;
1348     VS_FIXEDFILEINFO *ffi;
1349     UINT puLen;
1350     WCHAR tmp[32];
1351
1352     TRACE("%s %p %d %p %d\n", debugstr_w(szFilePath),
1353           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
1354           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
1355
1356     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
1357     if( !dwVerLen )
1358         return GetLastError();
1359
1360     lpVer = msi_alloc(dwVerLen);
1361     if( !lpVer )
1362     {
1363         ret = ERROR_OUTOFMEMORY;
1364         goto end;
1365     }
1366
1367     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
1368     {
1369         ret = GetLastError();
1370         goto end;
1371     }
1372     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1373     {
1374         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
1375             (puLen > 0) )
1376         {
1377             wsprintfW(tmp, szVersionFormat,
1378                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
1379                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
1380             lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
1381             *pcchVersionBuf = lstrlenW(lpVersionBuf);
1382         }
1383         else
1384         {
1385             *lpVersionBuf = 0;
1386             *pcchVersionBuf = 0;
1387         }
1388     }
1389
1390     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1391     {
1392         DWORD lang = GetUserDefaultLangID();
1393
1394         FIXME("Retrieve language from file\n");
1395         wsprintfW(tmp, szLangFormat, lang);
1396         lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
1397         *pcchLangBuf = lstrlenW(lpLangBuf);
1398     }
1399
1400 end:
1401     msi_free(lpVer);
1402     return ret;
1403 }
1404
1405 /***********************************************************************
1406  * MsiGetFeatureUsageW           [MSI.@]
1407  */
1408 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
1409                                  DWORD* pdwUseCount, WORD* pwDateUsed )
1410 {
1411     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
1412           pdwUseCount, pwDateUsed);
1413     return ERROR_CALL_NOT_IMPLEMENTED;
1414 }
1415
1416 /***********************************************************************
1417  * MsiGetFeatureUsageA           [MSI.@]
1418  */
1419 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
1420                                  DWORD* pdwUseCount, WORD* pwDateUsed )
1421 {
1422     LPWSTR prod = NULL, feat = NULL;
1423     UINT ret = ERROR_OUTOFMEMORY;
1424
1425     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
1426           pdwUseCount, pwDateUsed);
1427
1428     prod = strdupAtoW( szProduct );
1429     if (szProduct && !prod)
1430         goto end;
1431
1432     feat = strdupAtoW( szFeature );
1433     if (szFeature && !feat)
1434         goto end;
1435
1436     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
1437
1438 end:
1439     msi_free( prod );
1440     msi_free( feat );
1441
1442     return ret;
1443 }
1444
1445 /***********************************************************************
1446  * MsiUseFeatureExW           [MSI.@]
1447  */
1448 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
1449                                       DWORD dwInstallMode, DWORD dwReserved )
1450 {
1451     INSTALLSTATE state;
1452
1453     TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
1454           dwInstallMode, dwReserved);
1455
1456     state = MsiQueryFeatureStateW( szProduct, szFeature );
1457
1458     if (dwReserved)
1459         return INSTALLSTATE_INVALIDARG;
1460
1461     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
1462     {
1463         FIXME("mark product %s feature %s as used\n",
1464               debugstr_w(szProduct), debugstr_w(szFeature) );
1465     }
1466
1467     return state;
1468 }
1469
1470 /***********************************************************************
1471  * MsiUseFeatureExA           [MSI.@]
1472  */
1473 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
1474                                       DWORD dwInstallMode, DWORD dwReserved )
1475 {
1476     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
1477     LPWSTR prod = NULL, feat = NULL;
1478
1479     TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
1480           dwInstallMode, dwReserved);
1481
1482     prod = strdupAtoW( szProduct );
1483     if (szProduct && !prod)
1484         goto end;
1485
1486     feat = strdupAtoW( szFeature );
1487     if (szFeature && !feat)
1488         goto end;
1489
1490     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
1491
1492 end:
1493     msi_free( prod );
1494     msi_free( feat );
1495
1496     return ret;
1497 }
1498
1499 /***********************************************************************
1500  * MsiUseFeatureW             [MSI.@]
1501  */
1502 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
1503 {
1504     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
1505 }
1506
1507 /***********************************************************************
1508  * MsiUseFeatureA             [MSI.@]
1509  */
1510 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
1511 {
1512     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
1513 }
1514
1515 /***********************************************************************
1516  * MSI_ProvideQualifiedComponentEx [internal]
1517  */
1518 static UINT WINAPI MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
1519                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
1520                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
1521                 DWORD* pcchPathBuf)
1522 {
1523     WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
1524           feature[MAX_FEATURE_CHARS+1];
1525     LPWSTR info;
1526     HKEY hkey;
1527     DWORD sz;
1528     UINT rc;
1529
1530     TRACE("%s %s %i %s %i %i %p %p\n", debugstr_w(szComponent),
1531           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
1532           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1533
1534     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
1535     if (rc != ERROR_SUCCESS)
1536         return ERROR_INDEX_ABSENT;
1537
1538     info = msi_reg_get_val_str( hkey, szQualifier );
1539     RegCloseKey(hkey);
1540
1541     if (!info)
1542         return ERROR_INDEX_ABSENT;
1543
1544     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
1545
1546     if (!szProduct)
1547         rc = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
1548     else
1549         rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
1550
1551     msi_free( info );
1552
1553     if (rc != INSTALLSTATE_LOCAL)
1554         return ERROR_FILE_NOT_FOUND;
1555
1556     return ERROR_SUCCESS;
1557 }
1558
1559 /***********************************************************************
1560  * MsiProvideQualifiedComponentExW [MSI.@]
1561  */
1562 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
1563                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
1564                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
1565                 DWORD* pcchPathBuf)
1566 {
1567     awstring path;
1568
1569     path.unicode = TRUE;
1570     path.str.w = lpPathBuf;
1571
1572     return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
1573             dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
1574 }
1575
1576 /***********************************************************************
1577  * MsiProvideQualifiedComponentExA [MSI.@]
1578  */
1579 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
1580                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR szProduct,
1581                 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
1582                 DWORD* pcchPathBuf)
1583 {
1584     LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
1585     UINT r = ERROR_OUTOFMEMORY;
1586     awstring path;
1587
1588     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
1589           debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
1590           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1591
1592     szwComponent = strdupAtoW( szComponent );
1593     if (szComponent && !szwComponent)
1594         goto end;
1595
1596     szwQualifier = strdupAtoW( szQualifier );
1597     if (szQualifier && !szwQualifier)
1598         goto end;
1599
1600     szwProduct = strdupAtoW( szProduct );
1601     if (szProduct && !szwProduct)
1602         goto end;
1603
1604     path.unicode = FALSE;
1605     path.str.a = lpPathBuf;
1606
1607     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
1608                               dwInstallMode, szwProduct, Unused1,
1609                               Unused2, &path, pcchPathBuf);
1610 end:
1611     msi_free(szwProduct);
1612     msi_free(szwComponent);
1613     msi_free(szwQualifier);
1614
1615     return r;
1616 }
1617
1618 /***********************************************************************
1619  * MsiProvideQualifiedComponentW [MSI.@]
1620  */
1621 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
1622                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
1623                 DWORD* pcchPathBuf)
1624 {
1625     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
1626                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1627 }
1628
1629 /***********************************************************************
1630  * MsiProvideQualifiedComponentA [MSI.@]
1631  */
1632 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
1633                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
1634                 DWORD* pcchPathBuf)
1635 {
1636     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
1637                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1638 }
1639
1640 /***********************************************************************
1641  * MSI_GetUserInfo [internal]
1642  */
1643 static USERINFOSTATE WINAPI MSI_GetUserInfo(LPCWSTR szProduct,
1644                 awstring *lpUserNameBuf, DWORD* pcchUserNameBuf,
1645                 awstring *lpOrgNameBuf, DWORD* pcchOrgNameBuf,
1646                 awstring *lpSerialBuf, DWORD* pcchSerialBuf)
1647 {
1648     HKEY hkey;
1649     LPWSTR user, org, serial;
1650     UINT r;
1651     USERINFOSTATE state;
1652
1653     TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf,
1654           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1655           pcchSerialBuf);
1656
1657     if (!szProduct)
1658         return USERINFOSTATE_INVALIDARG;
1659
1660     r = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
1661     if (r != ERROR_SUCCESS)
1662         return USERINFOSTATE_UNKNOWN;
1663
1664     user = msi_reg_get_val_str( hkey, INSTALLPROPERTY_REGOWNERW );
1665     org = msi_reg_get_val_str( hkey, INSTALLPROPERTY_REGCOMPANYW );
1666     serial = msi_reg_get_val_str( hkey, INSTALLPROPERTY_PRODUCTIDW );
1667
1668     RegCloseKey(hkey);
1669
1670     state = USERINFOSTATE_PRESENT;
1671
1672     if (user)
1673     {
1674         r = msi_strcpy_to_awstring( user, lpUserNameBuf, pcchUserNameBuf );
1675         if (r == ERROR_MORE_DATA)
1676             state = USERINFOSTATE_MOREDATA;
1677     }
1678     else
1679         state = USERINFOSTATE_ABSENT;
1680     if (org)
1681     {
1682         r = msi_strcpy_to_awstring( org, lpOrgNameBuf, pcchOrgNameBuf );
1683         if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT)
1684             state = USERINFOSTATE_MOREDATA;
1685     }
1686     /* msdn states: The user information is considered to be present even in the absence of a company name. */
1687     if (serial)
1688     {
1689         r = msi_strcpy_to_awstring( serial, lpSerialBuf, pcchSerialBuf );
1690         if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT)
1691             state = USERINFOSTATE_MOREDATA;
1692     }
1693     else
1694         state = USERINFOSTATE_ABSENT;
1695
1696     msi_free( user );
1697     msi_free( org );
1698     msi_free( serial );
1699
1700     return state;
1701 }
1702
1703 /***********************************************************************
1704  * MsiGetUserInfoW [MSI.@]
1705  */
1706 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
1707                 LPWSTR lpUserNameBuf, DWORD* pcchUserNameBuf,
1708                 LPWSTR lpOrgNameBuf, DWORD* pcchOrgNameBuf,
1709                 LPWSTR lpSerialBuf, DWORD* pcchSerialBuf)
1710 {
1711     awstring user, org, serial;
1712
1713     user.unicode = TRUE;
1714     user.str.w = lpUserNameBuf;
1715     org.unicode = TRUE;
1716     org.str.w = lpOrgNameBuf;
1717     serial.unicode = TRUE;
1718     serial.str.w = lpSerialBuf;
1719
1720     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
1721                             &org, pcchOrgNameBuf,
1722                             &serial, pcchSerialBuf );
1723 }
1724
1725 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
1726                 LPSTR lpUserNameBuf, DWORD* pcchUserNameBuf,
1727                 LPSTR lpOrgNameBuf, DWORD* pcchOrgNameBuf,
1728                 LPSTR lpSerialBuf, DWORD* pcchSerialBuf)
1729 {
1730     awstring user, org, serial;
1731     LPWSTR prod;
1732     UINT r;
1733
1734     prod = strdupAtoW( szProduct );
1735     if (szProduct && !prod)
1736         return ERROR_OUTOFMEMORY;
1737
1738     user.unicode = FALSE;
1739     user.str.a = lpUserNameBuf;
1740     org.unicode = FALSE;
1741     org.str.a = lpOrgNameBuf;
1742     serial.unicode = FALSE;
1743     serial.str.a = lpSerialBuf;
1744
1745     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
1746                          &org, pcchOrgNameBuf,
1747                          &serial, pcchSerialBuf );
1748
1749     msi_free( prod );
1750
1751     return r;
1752 }
1753
1754 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
1755 {
1756     MSIHANDLE handle;
1757     UINT rc;
1758     MSIPACKAGE *package;
1759     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1760
1761     TRACE("(%s)\n",debugstr_w(szProduct));
1762
1763     rc = MsiOpenProductW(szProduct,&handle);
1764     if (rc != ERROR_SUCCESS)
1765         return ERROR_INVALID_PARAMETER;
1766
1767     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1768     rc = ACTION_PerformUIAction(package, szFirstRun);
1769     msiobj_release( &package->hdr );
1770
1771     MsiCloseHandle(handle);
1772
1773     return rc;
1774 }
1775
1776 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
1777 {
1778     MSIHANDLE handle;
1779     UINT rc;
1780     MSIPACKAGE *package;
1781     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1782
1783     TRACE("(%s)\n",debugstr_a(szProduct));
1784
1785     rc = MsiOpenProductA(szProduct,&handle);
1786     if (rc != ERROR_SUCCESS)
1787         return ERROR_INVALID_PARAMETER;
1788
1789     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1790     rc = ACTION_PerformUIAction(package, szFirstRun);
1791     msiobj_release( &package->hdr );
1792
1793     MsiCloseHandle(handle);
1794
1795     return rc;
1796 }
1797
1798 /***********************************************************************
1799  * MsiConfigureFeatureA            [MSI.@]
1800  */
1801 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
1802 {
1803     LPWSTR prod, feat = NULL;
1804     UINT r = ERROR_OUTOFMEMORY;
1805
1806     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
1807
1808     prod = strdupAtoW( szProduct );
1809     if (szProduct && !prod)
1810         goto end;
1811
1812     feat = strdupAtoW( szFeature );
1813     if (szFeature && !feat)
1814         goto end;
1815
1816     r = MsiConfigureFeatureW(prod, feat, eInstallState);
1817
1818 end:
1819     msi_free(feat);
1820     msi_free(prod);
1821
1822     return r;
1823 }
1824
1825 /***********************************************************************
1826  * MsiConfigureFeatureW            [MSI.@]
1827  */
1828 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
1829 {
1830     static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1831     MSIPACKAGE *package = NULL;
1832     UINT r;
1833     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
1834     DWORD sz;
1835
1836     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
1837
1838     if (!szProduct || !szFeature)
1839         return ERROR_INVALID_PARAMETER;
1840
1841     switch (eInstallState)
1842     {
1843     case INSTALLSTATE_DEFAULT:
1844         /* FIXME: how do we figure out the default location? */
1845         eInstallState = INSTALLSTATE_LOCAL;
1846         break;
1847     case INSTALLSTATE_LOCAL:
1848     case INSTALLSTATE_SOURCE:
1849     case INSTALLSTATE_ABSENT:
1850     case INSTALLSTATE_ADVERTISED:
1851         break;
1852     default:
1853         return ERROR_INVALID_PARAMETER;
1854     }
1855
1856     r = MSI_OpenProductW( szProduct, &package );
1857     if (r != ERROR_SUCCESS)
1858         return r;
1859
1860     sz = sizeof(sourcepath);
1861     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
1862                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
1863
1864     sz = sizeof(filename);
1865     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
1866                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
1867
1868     lstrcatW( sourcepath, filename );
1869
1870     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
1871
1872     r = ACTION_PerformUIAction( package, szCostInit );
1873     if (r != ERROR_SUCCESS)
1874         goto end;
1875
1876     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
1877     if (r != ERROR_SUCCESS)
1878         goto end;
1879
1880     r = MSI_InstallPackage( package, sourcepath, NULL );
1881
1882 end:
1883     msiobj_release( &package->hdr );
1884
1885     return r;
1886 }
1887
1888 /***********************************************************************
1889  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
1890  *
1891  * Notes: undocumented
1892  */
1893 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
1894 {
1895     WCHAR path[MAX_PATH];
1896
1897     TRACE("%d\n", dwReserved);
1898
1899     if (dwReserved)
1900     {
1901         FIXME("dwReserved=%d\n", dwReserved);
1902         return ERROR_INVALID_PARAMETER;
1903     }
1904
1905     if (!GetWindowsDirectoryW(path, MAX_PATH))
1906         return ERROR_FUNCTION_FAILED;
1907
1908     lstrcatW(path, installerW);
1909
1910     if (!CreateDirectoryW(path, NULL))
1911         return ERROR_FUNCTION_FAILED;
1912
1913     return ERROR_SUCCESS;
1914 }
1915
1916 /***********************************************************************
1917  * MsiGetShortcutTargetA           [MSI.@]
1918  */
1919 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
1920                                    LPSTR szProductCode, LPSTR szFeatureId,
1921                                    LPSTR szComponentCode )
1922 {
1923     LPWSTR target;
1924     const int len = MAX_FEATURE_CHARS+1;
1925     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
1926     UINT r;
1927
1928     target = strdupAtoW( szShortcutTarget );
1929     if (szShortcutTarget && !target )
1930         return ERROR_OUTOFMEMORY;
1931     product[0] = 0;
1932     feature[0] = 0;
1933     component[0] = 0;
1934     r = MsiGetShortcutTargetW( target, product, feature, component );
1935     msi_free( target );
1936     if (r == ERROR_SUCCESS)
1937     {
1938         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
1939         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
1940         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
1941     }
1942     return r;
1943 }
1944
1945 /***********************************************************************
1946  * MsiGetShortcutTargetW           [MSI.@]
1947  */
1948 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
1949                                    LPWSTR szProductCode, LPWSTR szFeatureId,
1950                                    LPWSTR szComponentCode )
1951 {
1952     IShellLinkDataList *dl = NULL;
1953     IPersistFile *pf = NULL;
1954     LPEXP_DARWIN_LINK darwin = NULL;
1955     HRESULT r, init;
1956
1957     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
1958           szProductCode, szFeatureId, szComponentCode );
1959
1960     init = CoInitialize(NULL);
1961
1962     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1963                           &IID_IPersistFile, (LPVOID*) &pf );
1964     if( SUCCEEDED( r ) )
1965     {
1966         r = IPersistFile_Load( pf, szShortcutTarget,
1967                                STGM_READ | STGM_SHARE_DENY_WRITE );
1968         if( SUCCEEDED( r ) )
1969         {
1970             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
1971                                              (LPVOID*) &dl );
1972             if( SUCCEEDED( r ) )
1973             {
1974                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
1975                                                   (LPVOID) &darwin );
1976                 IShellLinkDataList_Release( dl );
1977             }
1978         }
1979         IPersistFile_Release( pf );
1980     }
1981
1982     if (SUCCEEDED(init))
1983         CoUninitialize();
1984
1985     TRACE("darwin = %p\n", darwin);
1986
1987     if (darwin)
1988     {
1989         DWORD sz;
1990         UINT ret;
1991
1992         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
1993                   szProductCode, szFeatureId, szComponentCode, &sz );
1994         LocalFree( darwin );
1995         return ret;
1996     }
1997
1998     return ERROR_FUNCTION_FAILED;
1999 }
2000
2001 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
2002                                   DWORD dwReinstallMode )
2003 {
2004     MSIPACKAGE* package = NULL;
2005     UINT r;
2006     WCHAR sourcepath[MAX_PATH];
2007     WCHAR filename[MAX_PATH];
2008     static const WCHAR szLogVerbose[] = {
2009         ' ','L','O','G','V','E','R','B','O','S','E',0 };
2010     static const WCHAR szInstalled[] = { 'I','n','s','t','a','l','l','e','d',0};
2011     static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0};
2012     static const WCHAR szReinstallMode[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
2013     static const WCHAR szOne[] = {'1',0};
2014     WCHAR reinstallmode[11];
2015     LPWSTR ptr;
2016     DWORD sz;
2017
2018     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
2019                            dwReinstallMode);
2020
2021     ptr = reinstallmode;
2022
2023     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
2024         *ptr++ = 'p';
2025     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
2026         *ptr++ = 'o';
2027     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
2028         *ptr++ = 'w';
2029     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
2030         *ptr++ = 'd';
2031     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
2032         *ptr++ = 'c';
2033     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
2034         *ptr++ = 'a';
2035     if (dwReinstallMode & REINSTALLMODE_USERDATA)
2036         *ptr++ = 'u';
2037     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
2038         *ptr++ = 'm';
2039     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
2040         *ptr++ = 's';
2041     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2042         *ptr++ = 'v';
2043     *ptr = 0;
2044     
2045     sz = sizeof(sourcepath);
2046     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
2047             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
2048
2049     sz = sizeof(filename);
2050     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
2051             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
2052
2053     lstrcatW( sourcepath, filename );
2054
2055     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2056         r = MSI_OpenPackageW( sourcepath, &package );
2057     else
2058         r = MSI_OpenProductW( szProduct, &package );
2059
2060     if (r != ERROR_SUCCESS)
2061         return r;
2062
2063     MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
2064     MSI_SetPropertyW( package, szInstalled, szOne );
2065     MSI_SetPropertyW( package, szLogVerbose, szOne );
2066     MSI_SetPropertyW( package, szReinstall, szFeature );
2067
2068     r = MSI_InstallPackage( package, sourcepath, NULL );
2069
2070     msiobj_release( &package->hdr );
2071
2072     return r;
2073 }
2074
2075 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
2076                                   DWORD dwReinstallMode )
2077 {
2078     LPWSTR wszProduct;
2079     LPWSTR wszFeature;
2080     UINT rc;
2081
2082     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
2083                            dwReinstallMode);
2084
2085     wszProduct = strdupAtoW(szProduct);
2086     wszFeature = strdupAtoW(szFeature);
2087
2088     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
2089
2090     msi_free(wszProduct);
2091     msi_free(wszFeature);
2092     return rc;
2093 }
2094
2095 typedef struct
2096 {
2097     unsigned int i[2];
2098     unsigned int buf[4];
2099     unsigned char in[64];
2100     unsigned char digest[16];
2101 } MD5_CTX;
2102
2103 extern VOID WINAPI MD5Init( MD5_CTX *);
2104 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
2105 extern VOID WINAPI MD5Final( MD5_CTX *);
2106
2107 /***********************************************************************
2108  * MsiGetFileHashW            [MSI.@]
2109  */
2110 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
2111                              PMSIFILEHASHINFO pHash )
2112 {
2113     HANDLE handle, mapping;
2114     void *p;
2115     DWORD length;
2116     UINT r = ERROR_FUNCTION_FAILED;
2117
2118     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
2119
2120     if (dwOptions)
2121         return ERROR_INVALID_PARAMETER;
2122     if (!pHash)
2123         return ERROR_INVALID_PARAMETER;
2124     if (pHash->dwFileHashInfoSize < sizeof *pHash)
2125         return ERROR_INVALID_PARAMETER;
2126
2127     handle = CreateFileW( szFilePath, GENERIC_READ,
2128                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
2129     if (handle == INVALID_HANDLE_VALUE)
2130         return ERROR_FILE_NOT_FOUND;
2131
2132     length = GetFileSize( handle, NULL );
2133
2134     mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
2135     if (mapping)
2136     {
2137         p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
2138         if (p)
2139         {
2140             MD5_CTX ctx;
2141
2142             MD5Init( &ctx );
2143             MD5Update( &ctx, p, length );
2144             MD5Final( &ctx );
2145             UnmapViewOfFile( p );
2146
2147             memcpy( pHash->dwData, &ctx.digest, sizeof pHash->dwData );
2148             r = ERROR_SUCCESS;
2149         }
2150         CloseHandle( mapping );
2151     }
2152     CloseHandle( handle );
2153
2154     return r;
2155 }
2156
2157 /***********************************************************************
2158  * MsiGetFileHashA            [MSI.@]
2159  */
2160 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
2161                              PMSIFILEHASHINFO pHash )
2162 {
2163     LPWSTR file;
2164     UINT r;
2165
2166     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
2167
2168     file = strdupAtoW( szFilePath );
2169     if (szFilePath && !file)
2170         return ERROR_OUTOFMEMORY;
2171
2172     r = MsiGetFileHashW( file, dwOptions, pHash );
2173     msi_free( file );
2174     return r;
2175 }
2176
2177 /***********************************************************************
2178  * MsiAdvertiseScriptW        [MSI.@]
2179  */
2180 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
2181                                  PHKEY phRegData, BOOL fRemoveItems )
2182 {
2183     FIXME("%s %08x %p %d\n",
2184           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2185     return ERROR_CALL_NOT_IMPLEMENTED;
2186 }
2187
2188 /***********************************************************************
2189  * MsiAdvertiseScriptA        [MSI.@]
2190  */
2191 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
2192                                  PHKEY phRegData, BOOL fRemoveItems )
2193 {
2194     FIXME("%s %08x %p %d\n",
2195           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2196     return ERROR_CALL_NOT_IMPLEMENTED;
2197 }