msi: Components with INSTALLSTATE_NOTUSED are considered present.
[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  * MsiProvideQualifiedComponentExW [MSI.@]
1553  */
1554 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
1555                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
1556                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
1557                 DWORD* pcchPathBuf)
1558 {
1559     HKEY hkey;
1560     UINT rc;
1561     LPWSTR info;
1562     DWORD sz;
1563     WCHAR product[MAX_FEATURE_CHARS+1];
1564     WCHAR component[MAX_FEATURE_CHARS+1];
1565     WCHAR feature[MAX_FEATURE_CHARS+1];
1566
1567     TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent),
1568           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
1569           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1570
1571     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
1572     if (rc != ERROR_SUCCESS)
1573         return ERROR_INDEX_ABSENT;
1574
1575     sz = 0;
1576     rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, NULL, &sz);
1577     if (sz <= 0)
1578     {
1579         RegCloseKey(hkey);
1580         return ERROR_INDEX_ABSENT;
1581     }
1582
1583     info = msi_alloc(sz);
1584     rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, (LPBYTE)info, &sz);
1585     if (rc != ERROR_SUCCESS)
1586     {
1587         RegCloseKey(hkey);
1588         msi_free(info);
1589         return ERROR_INDEX_ABSENT;
1590     }
1591
1592     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
1593
1594     if (!szProduct)
1595         rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf);
1596     else
1597         rc = MsiGetComponentPathW(szProduct, component, lpPathBuf, pcchPathBuf);
1598
1599     RegCloseKey(hkey);
1600     msi_free(info);
1601
1602     if (rc == INSTALLSTATE_LOCAL)
1603         return ERROR_SUCCESS;
1604     else
1605         return ERROR_FILE_NOT_FOUND;
1606 }
1607
1608 /***********************************************************************
1609  * MsiProvideQualifiedComponentW [MSI.@]
1610  */
1611 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
1612                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
1613                 DWORD* pcchPathBuf)
1614 {
1615     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
1616                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1617 }
1618
1619 /***********************************************************************
1620  * MsiProvideQualifiedComponentA [MSI.@]
1621  */
1622 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
1623                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
1624                 DWORD* pcchPathBuf)
1625 {
1626     LPWSTR szwComponent, szwQualifier, lpwPathBuf;
1627     DWORD cchwPathBuf;
1628     UINT rc;
1629
1630     TRACE("%s %s %li %p %p\n",szComponent, szQualifier,
1631                     dwInstallMode, lpPathBuf, pcchPathBuf);
1632
1633     szwComponent= strdupAtoW( szComponent);
1634     szwQualifier= strdupAtoW( szQualifier);
1635
1636     lpwPathBuf = msi_alloc(*pcchPathBuf * sizeof(WCHAR));
1637
1638     cchwPathBuf = *pcchPathBuf;
1639
1640     rc = MsiProvideQualifiedComponentW(szwComponent, szwQualifier, 
1641                     dwInstallMode, lpwPathBuf, &cchwPathBuf);
1642
1643     msi_free(szwComponent);
1644     msi_free(szwQualifier);
1645
1646     if (rc == ERROR_SUCCESS)
1647         *pcchPathBuf = WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, cchwPathBuf + 1,
1648                                            lpPathBuf, *pcchPathBuf, NULL, NULL);
1649
1650     msi_free(lpwPathBuf);
1651     return rc;
1652 }
1653
1654 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf,
1655                 DWORD* pcchUserNameBuf, LPWSTR lpOrgNameBuf,
1656                 DWORD* pcchOrgNameBuf, LPWSTR lpSerialBuf, DWORD* pcchSerialBuf)
1657 {
1658     HKEY hkey;
1659     DWORD sz;
1660     UINT rc = ERROR_SUCCESS,rc2 = ERROR_SUCCESS;
1661
1662     TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf,
1663           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1664           pcchSerialBuf);
1665
1666     rc = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
1667     if (rc != ERROR_SUCCESS)
1668         return USERINFOSTATE_UNKNOWN;
1669
1670     if (lpUserNameBuf)
1671     {
1672         sz = *lpUserNameBuf * sizeof(WCHAR);
1673         rc = RegQueryValueExW( hkey, INSTALLPROPERTY_REGOWNERW, NULL,
1674                 NULL, (LPBYTE)lpUserNameBuf,
1675                                &sz);
1676     }
1677     if (!lpUserNameBuf && pcchUserNameBuf)
1678     {
1679         sz = 0;
1680         rc = RegQueryValueExW( hkey, INSTALLPROPERTY_REGOWNERW, NULL,
1681                 NULL, NULL, &sz);
1682     }
1683
1684     if (pcchUserNameBuf)
1685         *pcchUserNameBuf = sz / sizeof(WCHAR);
1686
1687     if (lpOrgNameBuf)
1688     {
1689         sz = *pcchOrgNameBuf * sizeof(WCHAR);
1690         rc2 = RegQueryValueExW( hkey, INSTALLPROPERTY_REGCOMPANYW, NULL,
1691                 NULL, (LPBYTE)lpOrgNameBuf, &sz);
1692     }
1693     if (!lpOrgNameBuf && pcchOrgNameBuf)
1694     {
1695         sz = 0;
1696         rc2 = RegQueryValueExW( hkey, INSTALLPROPERTY_REGCOMPANYW, NULL,
1697                 NULL, NULL, &sz);
1698     }
1699
1700     if (pcchOrgNameBuf)
1701         *pcchOrgNameBuf = sz / sizeof(WCHAR);
1702
1703     if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA && 
1704         rc2 != ERROR_SUCCESS && rc2 != ERROR_MORE_DATA)
1705     {
1706         RegCloseKey(hkey);
1707         return USERINFOSTATE_ABSENT;
1708     }
1709
1710     if (lpSerialBuf)
1711     {
1712         sz = *pcchSerialBuf * sizeof(WCHAR);
1713         RegQueryValueExW( hkey, INSTALLPROPERTY_PRODUCTIDW, NULL, NULL,
1714                 (LPBYTE)lpSerialBuf, &sz);
1715     }
1716     if (!lpSerialBuf && pcchSerialBuf)
1717     {
1718         sz = 0;
1719         rc = RegQueryValueExW( hkey, INSTALLPROPERTY_PRODUCTIDW, NULL,
1720                 NULL, NULL, &sz);
1721     }
1722     if (pcchSerialBuf)
1723         *pcchSerialBuf = sz / sizeof(WCHAR);
1724
1725     RegCloseKey(hkey);
1726     return USERINFOSTATE_PRESENT;
1727 }
1728
1729 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct, LPSTR lpUserNameBuf,
1730                 DWORD* pcchUserNameBuf, LPSTR lpOrgNameBuf,
1731                 DWORD* pcchOrgNameBuf, LPSTR lpSerialBuf, DWORD* pcchSerialBuf)
1732 {
1733     FIXME("%s %p %p %p %p %p %p\n",debugstr_a(szProduct), lpUserNameBuf,
1734           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1735           pcchSerialBuf);
1736
1737     return USERINFOSTATE_UNKNOWN;
1738 }
1739
1740 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
1741 {
1742     MSIHANDLE handle;
1743     UINT rc;
1744     MSIPACKAGE *package;
1745     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1746
1747     TRACE("(%s)\n",debugstr_w(szProduct));
1748
1749     rc = MsiOpenProductW(szProduct,&handle);
1750     if (rc != ERROR_SUCCESS)
1751         return ERROR_INVALID_PARAMETER;
1752
1753     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1754     rc = ACTION_PerformUIAction(package, szFirstRun);
1755     msiobj_release( &package->hdr );
1756
1757     MsiCloseHandle(handle);
1758
1759     return rc;
1760 }
1761
1762 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
1763 {
1764     MSIHANDLE handle;
1765     UINT rc;
1766     MSIPACKAGE *package;
1767     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1768
1769     TRACE("(%s)\n",debugstr_a(szProduct));
1770
1771     rc = MsiOpenProductA(szProduct,&handle);
1772     if (rc != ERROR_SUCCESS)
1773         return ERROR_INVALID_PARAMETER;
1774
1775     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1776     rc = ACTION_PerformUIAction(package, szFirstRun);
1777     msiobj_release( &package->hdr );
1778
1779     MsiCloseHandle(handle);
1780
1781     return rc;
1782 }
1783
1784 /***********************************************************************
1785  * MsiConfigureFeatureA            [MSI.@]
1786  */
1787 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
1788 {
1789     LPWSTR prod, feat = NULL;
1790     UINT r = ERROR_OUTOFMEMORY;
1791
1792     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
1793
1794     prod = strdupAtoW( szProduct );
1795     if (szProduct && !prod)
1796         goto end;
1797
1798     feat = strdupAtoW( szFeature );
1799     if (szFeature && !feat)
1800         goto end;
1801
1802     r = MsiConfigureFeatureW(prod, feat, eInstallState);
1803
1804 end:
1805     msi_free(feat);
1806     msi_free(prod);
1807
1808     return r;
1809 }
1810
1811 /***********************************************************************
1812  * MsiConfigureFeatureW            [MSI.@]
1813  */
1814 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
1815 {
1816     static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1817     MSIPACKAGE *package = NULL;
1818     UINT r;
1819     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
1820     DWORD sz;
1821
1822     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
1823
1824     if (!szProduct || !szFeature)
1825         return ERROR_INVALID_PARAMETER;
1826
1827     r = MSI_OpenProductW( szProduct, &package );
1828     if (r != ERROR_SUCCESS)
1829         return r;
1830
1831     sz = sizeof(sourcepath);
1832     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
1833                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
1834
1835     sz = sizeof(filename);
1836     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
1837                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
1838
1839     lstrcatW( sourcepath, filename );
1840
1841     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
1842
1843     /* FIXME: how do we figure out the default location? */
1844     if (eInstallState == INSTALLSTATE_DEFAULT)
1845         eInstallState = INSTALLSTATE_LOCAL;
1846
1847     r = ACTION_PerformUIAction( package, szCostInit );
1848     if (r != ERROR_SUCCESS)
1849         goto end;
1850
1851     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
1852     if (r != ERROR_SUCCESS)
1853         goto end;
1854
1855     r = MSI_InstallPackage( package, sourcepath, NULL );
1856
1857 end:
1858     msiobj_release( &package->hdr );
1859
1860     return r;
1861 }
1862
1863 /***********************************************************************
1864  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
1865  *
1866  * Notes: undocumented
1867  */
1868 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
1869 {
1870     WCHAR path[MAX_PATH];
1871
1872     TRACE("%ld\n", dwReserved);
1873
1874     if (dwReserved)
1875     {
1876         FIXME("dwReserved=%ld\n", dwReserved);
1877         return ERROR_INVALID_PARAMETER;
1878     }
1879
1880     if (!GetWindowsDirectoryW(path, MAX_PATH))
1881         return ERROR_FUNCTION_FAILED;
1882
1883     lstrcatW(path, installerW);
1884
1885     if (!CreateDirectoryW(path, NULL))
1886         return ERROR_FUNCTION_FAILED;
1887
1888     return ERROR_SUCCESS;
1889 }
1890
1891 /***********************************************************************
1892  * MsiGetShortcutTargetA           [MSI.@]
1893  */
1894 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
1895                                    LPSTR szProductCode, LPSTR szFeatureId,
1896                                    LPSTR szComponentCode )
1897 {
1898     LPWSTR target;
1899     const int len = MAX_FEATURE_CHARS+1;
1900     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
1901     UINT r;
1902
1903     target = strdupAtoW( szShortcutTarget );
1904     if (szShortcutTarget && !target )
1905         return ERROR_OUTOFMEMORY;
1906     product[0] = 0;
1907     feature[0] = 0;
1908     component[0] = 0;
1909     r = MsiGetShortcutTargetW( target, product, feature, component );
1910     msi_free( target );
1911     if (r == ERROR_SUCCESS)
1912     {
1913         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
1914         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
1915         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
1916     }
1917     return r;
1918 }
1919
1920 /***********************************************************************
1921  * MsiGetShortcutTargetW           [MSI.@]
1922  */
1923 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
1924                                    LPWSTR szProductCode, LPWSTR szFeatureId,
1925                                    LPWSTR szComponentCode )
1926 {
1927     IShellLinkDataList *dl = NULL;
1928     IPersistFile *pf = NULL;
1929     LPEXP_DARWIN_LINK darwin = NULL;
1930     HRESULT r, init;
1931
1932     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
1933           szProductCode, szFeatureId, szComponentCode );
1934
1935     init = CoInitialize(NULL);
1936
1937     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1938                           &IID_IPersistFile, (LPVOID*) &pf );
1939     if( SUCCEEDED( r ) )
1940     {
1941         r = IPersistFile_Load( pf, szShortcutTarget,
1942                                STGM_READ | STGM_SHARE_DENY_WRITE );
1943         if( SUCCEEDED( r ) )
1944         {
1945             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
1946                                              (LPVOID*) &dl );
1947             if( SUCCEEDED( r ) )
1948             {
1949                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
1950                                                   (LPVOID) &darwin );
1951                 IShellLinkDataList_Release( dl );
1952             }
1953         }
1954         IPersistFile_Release( pf );
1955     }
1956
1957     if (SUCCEEDED(init))
1958         CoUninitialize();
1959
1960     TRACE("darwin = %p\n", darwin);
1961
1962     if (darwin)
1963     {
1964         DWORD sz;
1965         UINT ret;
1966
1967         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
1968                   szProductCode, szFeatureId, szComponentCode, &sz );
1969         LocalFree( darwin );
1970         return ret;
1971     }
1972
1973     return ERROR_FUNCTION_FAILED;
1974 }
1975
1976 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
1977                                   DWORD dwReinstallMode )
1978 {
1979     MSIPACKAGE* package = NULL;
1980     UINT r;
1981     WCHAR sourcepath[MAX_PATH];
1982     WCHAR filename[MAX_PATH];
1983     static const WCHAR szLogVerbose[] = {
1984         ' ','L','O','G','V','E','R','B','O','S','E',0 };
1985     static const WCHAR szInstalled[] = { 'I','n','s','t','a','l','l','e','d',0};
1986     static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0};
1987     static const WCHAR szReinstallMode[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
1988     static const WCHAR szOne[] = {'1',0};
1989     WCHAR reinstallmode[11];
1990     LPWSTR ptr;
1991     DWORD sz;
1992
1993     FIXME("%s %s %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
1994                            dwReinstallMode);
1995
1996     ptr = reinstallmode;
1997
1998     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
1999         *ptr++ = 'p';
2000     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
2001         *ptr++ = 'o';
2002     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
2003         *ptr++ = 'w';
2004     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
2005         *ptr++ = 'd';
2006     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
2007         *ptr++ = 'c';
2008     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
2009         *ptr++ = 'a';
2010     if (dwReinstallMode & REINSTALLMODE_USERDATA)
2011         *ptr++ = 'u';
2012     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
2013         *ptr++ = 'm';
2014     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
2015         *ptr++ = 's';
2016     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2017         *ptr++ = 'v';
2018     *ptr = 0;
2019     
2020     sz = sizeof(sourcepath);
2021     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
2022             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
2023
2024     sz = sizeof(filename);
2025     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
2026             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
2027
2028     lstrcatW( sourcepath, filename );
2029
2030     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2031         r = MSI_OpenPackageW( sourcepath, &package );
2032     else
2033         r = MSI_OpenProductW( szProduct, &package );
2034
2035     if (r != ERROR_SUCCESS)
2036         return r;
2037
2038     MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
2039     MSI_SetPropertyW( package, szInstalled, szOne );
2040     MSI_SetPropertyW( package, szLogVerbose, szOne );
2041     MSI_SetPropertyW( package, szReinstall, szFeature );
2042
2043     r = MSI_InstallPackage( package, sourcepath, NULL );
2044
2045     msiobj_release( &package->hdr );
2046
2047     return r;
2048 }
2049
2050 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
2051                                   DWORD dwReinstallMode )
2052 {
2053     LPWSTR wszProduct;
2054     LPWSTR wszFeature;
2055     UINT rc;
2056
2057     TRACE("%s %s %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
2058                            dwReinstallMode);
2059
2060     wszProduct = strdupAtoW(szProduct);
2061     wszFeature = strdupAtoW(szFeature);
2062
2063     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
2064
2065     msi_free(wszProduct);
2066     msi_free(wszFeature);
2067     return rc;
2068 }
2069
2070 /***********************************************************************
2071  * MsiEnumPatchesA            [MSI.@]
2072  */
2073 UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex, 
2074         LPSTR lpPatchBuf, LPSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
2075 {
2076     FIXME("%s %ld %p %p %p\n", debugstr_a(szProduct),
2077           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
2078     return ERROR_NO_MORE_ITEMS;
2079 }
2080
2081 /***********************************************************************
2082  * MsiEnumPatchesW            [MSI.@]
2083  */
2084 UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex, 
2085         LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
2086 {
2087     FIXME("%s %ld %p %p %p\n", debugstr_w(szProduct),
2088           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
2089     return ERROR_NO_MORE_ITEMS;
2090 }
2091
2092 /***********************************************************************
2093  * MsiGetFileHashW            [MSI.@]
2094  */
2095 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
2096                              PMSIFILEHASHINFO pHash )
2097 {
2098     FIXME("%s %08lx %p\n", debugstr_w(szFilePath), dwOptions, pHash );
2099     return ERROR_CALL_NOT_IMPLEMENTED;
2100 }
2101
2102 /***********************************************************************
2103  * MsiGetFileHashA            [MSI.@]
2104  */
2105 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
2106                              PMSIFILEHASHINFO pHash )
2107 {
2108     FIXME("%s %08lx %p\n", debugstr_a(szFilePath), dwOptions, pHash );
2109     return ERROR_CALL_NOT_IMPLEMENTED;
2110 }
2111
2112 /***********************************************************************
2113  * MsiAdvertiseScriptW        [MSI.@]
2114  */
2115 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
2116                                  PHKEY phRegData, BOOL fRemoveItems )
2117 {
2118     FIXME("%s %08lx %p %d\n",
2119           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2120     return ERROR_CALL_NOT_IMPLEMENTED;
2121 }
2122
2123 /***********************************************************************
2124  * MsiAdvertiseScriptA        [MSI.@]
2125  */
2126 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
2127                                  PHKEY phRegData, BOOL fRemoveItems )
2128 {
2129     FIXME("%s %08lx %p %d\n",
2130           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2131     return ERROR_CALL_NOT_IMPLEMENTED;
2132 }