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