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