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