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