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