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