xref: /reactos/dll/win32/msi/msi.c (revision f4be6dc3)
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002,2003,2004,2005 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 
23 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winreg.h"
27 #include "winnls.h"
28 #include "shlwapi.h"
29 #include "msi.h"
30 #include "msidefs.h"
31 #include "msiquery.h"
32 #include "wincrypt.h"
33 #include "winver.h"
34 #include "winuser.h"
35 #include "shlobj.h"
36 #include "shobjidl.h"
37 #include "objidl.h"
38 #include "wintrust.h"
39 #include "softpub.h"
40 
41 #include "msipriv.h"
42 #include "winemsi_s.h"
43 
44 #include "initguid.h"
45 #include "msxml2.h"
46 
47 #include "wine/debug.h"
48 #include "wine/exception.h"
49 
50 WINE_DEFAULT_DEBUG_CHANNEL(msi);
51 
52 BOOL is_wow64;
53 
msi_locate_product(LPCWSTR szProduct,MSIINSTALLCONTEXT * context)54 UINT msi_locate_product(LPCWSTR szProduct, MSIINSTALLCONTEXT *context)
55 {
56     HKEY hkey = NULL;
57 
58     *context = MSIINSTALLCONTEXT_NONE;
59     if (!szProduct) return ERROR_UNKNOWN_PRODUCT;
60 
61     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
62                               &hkey, FALSE) == ERROR_SUCCESS)
63         *context = MSIINSTALLCONTEXT_USERMANAGED;
64     else if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
65                                    &hkey, FALSE) == ERROR_SUCCESS)
66         *context = MSIINSTALLCONTEXT_MACHINE;
67     else if (MSIREG_OpenProductKey(szProduct, NULL,
68                                    MSIINSTALLCONTEXT_USERUNMANAGED,
69                                    &hkey, FALSE) == ERROR_SUCCESS)
70         *context = MSIINSTALLCONTEXT_USERUNMANAGED;
71 
72     RegCloseKey(hkey);
73 
74     if (*context == MSIINSTALLCONTEXT_NONE)
75         return ERROR_UNKNOWN_PRODUCT;
76 
77     return ERROR_SUCCESS;
78 }
79 
MsiOpenProductA(LPCSTR szProduct,MSIHANDLE * phProduct)80 UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
81 {
82     UINT r;
83     LPWSTR szwProd = NULL;
84 
85     TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
86 
87     if( szProduct )
88     {
89         szwProd = strdupAtoW( szProduct );
90         if( !szwProd )
91             return ERROR_OUTOFMEMORY;
92     }
93 
94     r = MsiOpenProductW( szwProd, phProduct );
95 
96     free( szwProd );
97 
98     return r;
99 }
100 
MSI_OpenProductW(LPCWSTR szProduct,MSIPACKAGE ** package)101 static UINT MSI_OpenProductW(LPCWSTR szProduct, MSIPACKAGE **package)
102 {
103     UINT r;
104     HKEY props;
105     LPWSTR path;
106     MSIINSTALLCONTEXT context;
107 
108     TRACE("%s %p\n", debugstr_w(szProduct), package);
109 
110     r = msi_locate_product(szProduct, &context);
111     if (r != ERROR_SUCCESS)
112         return r;
113 
114     r = MSIREG_OpenInstallProps(szProduct, context, NULL, &props, FALSE);
115     if (r != ERROR_SUCCESS)
116         return ERROR_UNKNOWN_PRODUCT;
117 
118     if (context == MSIINSTALLCONTEXT_USERMANAGED)
119         path = msi_reg_get_val_str(props, L"ManagedLocalPackage");
120     else
121         path = msi_reg_get_val_str(props, L"LocalPackage");
122 
123     r = ERROR_UNKNOWN_PRODUCT;
124 
125     if (!path || GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
126         goto done;
127 
128     if (PathIsRelativeW(path))
129     {
130         r = ERROR_INSTALL_PACKAGE_OPEN_FAILED;
131         goto done;
132     }
133 
134     r = MSI_OpenPackageW(path, 0, package);
135 
136 done:
137     RegCloseKey(props);
138     free(path);
139     return r;
140 }
141 
MsiOpenProductW(LPCWSTR szProduct,MSIHANDLE * phProduct)142 UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct)
143 {
144     MSIPACKAGE *package = NULL;
145     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
146     UINT r;
147 
148     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
149         return ERROR_INVALID_PARAMETER;
150 
151     if (!phProduct)
152         return ERROR_INVALID_PARAMETER;
153 
154     r = MSI_OpenProductW(szProduct, &package);
155     if (r != ERROR_SUCCESS)
156         return r;
157 
158     *phProduct = alloc_msihandle(&package->hdr);
159     if (!*phProduct)
160         r = ERROR_NOT_ENOUGH_MEMORY;
161 
162     msiobj_release(&package->hdr);
163     return r;
164 }
165 
MsiAdvertiseProductA(LPCSTR szPackagePath,LPCSTR szScriptfilePath,LPCSTR szTransforms,LANGID lgidLanguage)166 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
167                 LPCSTR szTransforms, LANGID lgidLanguage)
168 {
169     FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath),
170           debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
171     return ERROR_CALL_NOT_IMPLEMENTED;
172 }
173 
MsiAdvertiseProductW(LPCWSTR szPackagePath,LPCWSTR szScriptfilePath,LPCWSTR szTransforms,LANGID lgidLanguage)174 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
175                 LPCWSTR szTransforms, LANGID lgidLanguage)
176 {
177     FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath),
178           debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
179     return ERROR_CALL_NOT_IMPLEMENTED;
180 }
181 
MsiAdvertiseProductExA(const char * szPackagePath,const char * szScriptfilePath,const char * szTransforms,LANGID lgidLanguage,DWORD dwPlatform,DWORD dwOptions)182 UINT WINAPI MsiAdvertiseProductExA( const char *szPackagePath, const char *szScriptfilePath,
183                                     const char *szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions )
184 {
185     FIXME( "%s, %s, %s, %#x, %#lx, %#lx\n", debugstr_a(szPackagePath), debugstr_a(szScriptfilePath),
186            debugstr_a(szTransforms), lgidLanguage, dwPlatform, dwOptions );
187     return ERROR_CALL_NOT_IMPLEMENTED;
188 }
189 
MsiAdvertiseProductExW(const WCHAR * szPackagePath,const WCHAR * szScriptfilePath,const WCHAR * szTransforms,LANGID lgidLanguage,DWORD dwPlatform,DWORD dwOptions)190 UINT WINAPI MsiAdvertiseProductExW( const WCHAR *szPackagePath, const WCHAR *szScriptfilePath,
191                                     const WCHAR *szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions )
192 {
193     FIXME( "%s, %s, %s, %#x %#lx %#lx\n", debugstr_w(szPackagePath), debugstr_w(szScriptfilePath),
194            debugstr_w(szTransforms), lgidLanguage, dwPlatform, dwOptions );
195     return ERROR_CALL_NOT_IMPLEMENTED;
196 }
197 
MsiInstallProductA(LPCSTR szPackagePath,LPCSTR szCommandLine)198 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
199 {
200     LPWSTR szwPath = NULL, szwCommand = NULL;
201     UINT r = ERROR_OUTOFMEMORY;
202 
203     TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
204 
205     if( szPackagePath )
206     {
207         szwPath = strdupAtoW( szPackagePath );
208         if( !szwPath )
209             goto end;
210     }
211 
212     if( szCommandLine )
213     {
214         szwCommand = strdupAtoW( szCommandLine );
215         if( !szwCommand )
216             goto end;
217     }
218 
219     r = MsiInstallProductW( szwPath, szwCommand );
220 
221 end:
222     free( szwPath );
223     free( szwCommand );
224 
225     return r;
226 }
227 
MsiInstallProductW(LPCWSTR szPackagePath,LPCWSTR szCommandLine)228 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
229 {
230     MSIPACKAGE *package = NULL;
231     const WCHAR *reinstallmode;
232     DWORD options = 0;
233     UINT r, len;
234 
235     TRACE("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
236 
237     if (!szPackagePath)
238         return ERROR_INVALID_PARAMETER;
239 
240     if (!*szPackagePath)
241         return ERROR_PATH_NOT_FOUND;
242 
243     reinstallmode = msi_get_command_line_option(szCommandLine, L"REINSTALLMODE", &len);
244     if (reinstallmode)
245     {
246         while (len > 0)
247         {
248             if (reinstallmode[--len] == 'v' || reinstallmode[len] == 'V')
249             {
250                 options |= WINE_OPENPACKAGEFLAGS_RECACHE;
251                 break;
252             }
253         }
254     }
255 
256     r = MSI_OpenPackageW( szPackagePath, options, &package );
257     if (r == ERROR_SUCCESS)
258     {
259         r = MSI_InstallPackage( package, szPackagePath, szCommandLine );
260         msiobj_release( &package->hdr );
261     }
262 
263     return r;
264 }
265 
MsiReinstallProductA(const char * szProduct,DWORD dwReinstallMode)266 UINT WINAPI MsiReinstallProductA( const char *szProduct, DWORD dwReinstallMode )
267 {
268     WCHAR *wszProduct;
269     UINT rc;
270 
271     TRACE( "%s, %#lx\n", debugstr_a(szProduct), dwReinstallMode );
272 
273     wszProduct = strdupAtoW(szProduct);
274     rc = MsiReinstallProductW(wszProduct, dwReinstallMode);
275     free(wszProduct);
276     return rc;
277 }
278 
MsiReinstallProductW(const WCHAR * szProduct,DWORD dwReinstallMode)279 UINT WINAPI MsiReinstallProductW( const WCHAR *szProduct, DWORD dwReinstallMode )
280 {
281     TRACE( "%s, %#lx\n", debugstr_w(szProduct), dwReinstallMode );
282 
283     return MsiReinstallFeatureW(szProduct, L"ALL", dwReinstallMode);
284 }
285 
MsiApplyPatchA(LPCSTR szPatchPackage,LPCSTR szInstallPackage,INSTALLTYPE eInstallType,LPCSTR szCommandLine)286 UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage,
287         INSTALLTYPE eInstallType, LPCSTR szCommandLine)
288 {
289     LPWSTR patch_package = NULL;
290     LPWSTR install_package = NULL;
291     LPWSTR command_line = NULL;
292     UINT r = ERROR_OUTOFMEMORY;
293 
294     TRACE("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage),
295           eInstallType, debugstr_a(szCommandLine));
296 
297     if (szPatchPackage && !(patch_package = strdupAtoW(szPatchPackage)))
298         goto done;
299 
300     if (szInstallPackage && !(install_package = strdupAtoW(szInstallPackage)))
301         goto done;
302 
303     if (szCommandLine && !(command_line = strdupAtoW(szCommandLine)))
304         goto done;
305 
306     r = MsiApplyPatchW(patch_package, install_package, eInstallType, command_line);
307 
308 done:
309     free(patch_package);
310     free(install_package);
311     free(command_line);
312 
313     return r;
314 }
315 
get_patch_product_codes(LPCWSTR szPatchPackage,WCHAR *** product_codes)316 static UINT get_patch_product_codes( LPCWSTR szPatchPackage, WCHAR ***product_codes )
317 {
318     MSIHANDLE patch, info = 0;
319     UINT r, type;
320     DWORD size;
321     static WCHAR empty[] = L"";
322     WCHAR *codes = NULL;
323 
324     r = MsiOpenDatabaseW( szPatchPackage, MSIDBOPEN_READONLY, &patch );
325     if (r != ERROR_SUCCESS)
326         return r;
327 
328     r = MsiGetSummaryInformationW( patch, NULL, 0, &info );
329     if (r != ERROR_SUCCESS)
330         goto done;
331 
332     size = 0;
333     r = MsiSummaryInfoGetPropertyW( info, PID_TEMPLATE, &type, NULL, NULL, empty, &size );
334     if (r != ERROR_MORE_DATA || !size || type != VT_LPSTR)
335     {
336         ERR("Failed to read product codes from patch\n");
337         r = ERROR_FUNCTION_FAILED;
338         goto done;
339     }
340 
341     codes = malloc( ++size * sizeof(WCHAR) );
342     if (!codes)
343     {
344         r = ERROR_OUTOFMEMORY;
345         goto done;
346     }
347 
348     r = MsiSummaryInfoGetPropertyW( info, PID_TEMPLATE, &type, NULL, NULL, codes, &size );
349     if (r == ERROR_SUCCESS)
350         *product_codes = msi_split_string( codes, ';' );
351 
352 done:
353     MsiCloseHandle( info );
354     MsiCloseHandle( patch );
355     free( codes );
356     return r;
357 }
358 
MSI_ApplyPatchW(LPCWSTR szPatchPackage,LPCWSTR szProductCode,LPCWSTR szCommandLine)359 static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWSTR szCommandLine)
360 {
361     UINT i, r = ERROR_FUNCTION_FAILED;
362     DWORD size;
363     LPCWSTR cmd_ptr = szCommandLine;
364     LPWSTR cmd, *codes = NULL;
365     BOOL succeeded = FALSE;
366 
367     if (!szPatchPackage || !szPatchPackage[0])
368         return ERROR_INVALID_PARAMETER;
369 
370     if (!szProductCode && (r = get_patch_product_codes( szPatchPackage, &codes )))
371         return r;
372 
373     if (!szCommandLine)
374         cmd_ptr = L"";
375 
376     size = lstrlenW(cmd_ptr) + lstrlenW(L"%s PATCH=\"%s\"") + lstrlenW(szPatchPackage) + 1;
377     cmd = malloc(size * sizeof(WCHAR));
378     if (!cmd)
379     {
380         free(codes);
381         return ERROR_OUTOFMEMORY;
382     }
383     swprintf(cmd, size, L"%s PATCH=\"%s\"", cmd_ptr, szPatchPackage);
384 
385     if (szProductCode)
386         r = MsiConfigureProductExW(szProductCode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
387     else
388     {
389         for (i = 0; codes[i]; i++)
390         {
391             r = MsiConfigureProductExW(codes[i], INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
392             if (r == ERROR_SUCCESS)
393             {
394                 TRACE("patch applied\n");
395                 succeeded = TRUE;
396             }
397         }
398 
399         if (succeeded)
400             r = ERROR_SUCCESS;
401     }
402 
403     free(cmd);
404     free(codes);
405     return r;
406 }
407 
MsiApplyPatchW(LPCWSTR szPatchPackage,LPCWSTR szInstallPackage,INSTALLTYPE eInstallType,LPCWSTR szCommandLine)408 UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
409          INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
410 {
411     TRACE("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage),
412           eInstallType, debugstr_w(szCommandLine));
413 
414     if (szInstallPackage || eInstallType == INSTALLTYPE_NETWORK_IMAGE ||
415         eInstallType == INSTALLTYPE_SINGLE_INSTANCE)
416     {
417         FIXME("Only reading target products from patch\n");
418         return ERROR_CALL_NOT_IMPLEMENTED;
419     }
420 
421     return MSI_ApplyPatchW(szPatchPackage, NULL, szCommandLine);
422 }
423 
MsiApplyMultiplePatchesA(LPCSTR szPatchPackages,LPCSTR szProductCode,LPCSTR szPropertiesList)424 UINT WINAPI MsiApplyMultiplePatchesA(LPCSTR szPatchPackages,
425         LPCSTR szProductCode, LPCSTR szPropertiesList)
426 {
427     LPWSTR patch_packages = NULL;
428     LPWSTR product_code = NULL;
429     LPWSTR properties_list = NULL;
430     UINT r = ERROR_OUTOFMEMORY;
431 
432     TRACE("%s %s %s\n", debugstr_a(szPatchPackages), debugstr_a(szProductCode),
433           debugstr_a(szPropertiesList));
434 
435     if (!szPatchPackages || !szPatchPackages[0])
436         return ERROR_INVALID_PARAMETER;
437 
438     if (!(patch_packages = strdupAtoW(szPatchPackages)))
439         return ERROR_OUTOFMEMORY;
440 
441     if (szProductCode && !(product_code = strdupAtoW(szProductCode)))
442         goto done;
443 
444     if (szPropertiesList && !(properties_list = strdupAtoW(szPropertiesList)))
445         goto done;
446 
447     r = MsiApplyMultiplePatchesW(patch_packages, product_code, properties_list);
448 
449 done:
450     free(patch_packages);
451     free(product_code);
452     free(properties_list);
453 
454     return r;
455 }
456 
MsiApplyMultiplePatchesW(LPCWSTR szPatchPackages,LPCWSTR szProductCode,LPCWSTR szPropertiesList)457 UINT WINAPI MsiApplyMultiplePatchesW(LPCWSTR szPatchPackages,
458         LPCWSTR szProductCode, LPCWSTR szPropertiesList)
459 {
460     UINT r = ERROR_SUCCESS;
461     LPCWSTR beg, end;
462 
463     TRACE("%s %s %s\n", debugstr_w(szPatchPackages), debugstr_w(szProductCode),
464           debugstr_w(szPropertiesList));
465 
466     if (!szPatchPackages || !szPatchPackages[0])
467         return ERROR_INVALID_PARAMETER;
468 
469     beg = end = szPatchPackages;
470     while (*beg)
471     {
472         DWORD len;
473         LPWSTR patch;
474 
475         while (*beg == ' ') beg++;
476         while (*end && *end != ';') end++;
477 
478         len = end - beg;
479         while (len && beg[len - 1] == ' ') len--;
480 
481         if (!len) return ERROR_INVALID_NAME;
482 
483         patch = malloc((len + 1) * sizeof(WCHAR));
484         if (!patch)
485             return ERROR_OUTOFMEMORY;
486 
487         memcpy(patch, beg, len * sizeof(WCHAR));
488         patch[len] = '\0';
489 
490         r = MSI_ApplyPatchW(patch, szProductCode, szPropertiesList);
491         free(patch);
492 
493         if (r != ERROR_SUCCESS || !*end)
494             break;
495 
496         beg = ++end;
497     }
498     return r;
499 }
500 
free_patchinfo(DWORD count,MSIPATCHSEQUENCEINFOW * info)501 static void free_patchinfo( DWORD count, MSIPATCHSEQUENCEINFOW *info )
502 {
503     DWORD i;
504     for (i = 0; i < count; i++) free( (WCHAR *)info[i].szPatchData );
505     free( info );
506 }
507 
patchinfoAtoW(DWORD count,const MSIPATCHSEQUENCEINFOA * info)508 static MSIPATCHSEQUENCEINFOW *patchinfoAtoW( DWORD count, const MSIPATCHSEQUENCEINFOA *info )
509 {
510     DWORD i;
511     MSIPATCHSEQUENCEINFOW *ret;
512 
513     if (!(ret = malloc( count * sizeof(MSIPATCHSEQUENCEINFOW) ))) return NULL;
514     for (i = 0; i < count; i++)
515     {
516         if (info[i].szPatchData && !(ret[i].szPatchData = strdupAtoW( info[i].szPatchData )))
517         {
518             free_patchinfo( i, ret );
519             return NULL;
520         }
521         ret[i].ePatchDataType = info[i].ePatchDataType;
522         ret[i].dwOrder = info[i].dwOrder;
523         ret[i].uStatus = info[i].uStatus;
524     }
525     return ret;
526 }
527 
MsiDetermineApplicablePatchesA(const char * szProductPackagePath,DWORD cPatchInfo,MSIPATCHSEQUENCEINFOA * pPatchInfo)528 UINT WINAPI MsiDetermineApplicablePatchesA( const char *szProductPackagePath, DWORD cPatchInfo,
529                                             MSIPATCHSEQUENCEINFOA *pPatchInfo )
530 {
531     UINT i, r;
532     WCHAR *package_path = NULL;
533     MSIPATCHSEQUENCEINFOW *psi;
534 
535     TRACE( "%s, %lu, %p\n", debugstr_a(szProductPackagePath), cPatchInfo, pPatchInfo );
536 
537     if (szProductPackagePath && !(package_path = strdupAtoW( szProductPackagePath )))
538         return ERROR_OUTOFMEMORY;
539 
540     if (!(psi = patchinfoAtoW( cPatchInfo, pPatchInfo )))
541     {
542         free( package_path );
543         return ERROR_OUTOFMEMORY;
544     }
545     r = MsiDetermineApplicablePatchesW( package_path, cPatchInfo, psi );
546     if (r == ERROR_SUCCESS)
547     {
548         for (i = 0; i < cPatchInfo; i++)
549         {
550             pPatchInfo[i].dwOrder = psi[i].dwOrder;
551             pPatchInfo[i].uStatus = psi[i].uStatus;
552         }
553     }
554     free( package_path );
555     free_patchinfo( cPatchInfo, psi );
556     return r;
557 }
558 
MSI_ApplicablePatchW(MSIPACKAGE * package,LPCWSTR patch)559 static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch )
560 {
561     MSISUMMARYINFO *si;
562     MSIDATABASE *patch_db;
563     UINT r;
564 
565     r = MSI_OpenDatabaseW( patch, MSIDBOPEN_READONLY, &patch_db );
566     if (r != ERROR_SUCCESS)
567     {
568         WARN("failed to open patch file %s\n", debugstr_w(patch));
569         return r;
570     }
571 
572     r = msi_get_suminfo( patch_db->storage, 0, &si );
573     if (r != ERROR_SUCCESS)
574     {
575         msiobj_release( &patch_db->hdr );
576         return ERROR_FUNCTION_FAILED;
577     }
578 
579     r = msi_check_patch_applicable( package, si );
580     if (r != ERROR_SUCCESS)
581         TRACE("patch not applicable\n");
582 
583     msiobj_release( &patch_db->hdr );
584     msiobj_release( &si->hdr );
585     return r;
586 }
587 
588 /* IXMLDOMDocument should be set to XPath mode already */
MSI_ApplicablePatchXML(MSIPACKAGE * package,IXMLDOMDocument * desc)589 static UINT MSI_ApplicablePatchXML( MSIPACKAGE *package, IXMLDOMDocument *desc )
590 {
591     UINT r = ERROR_FUNCTION_FAILED;
592     IXMLDOMNodeList *list;
593     LPWSTR product_code;
594     IXMLDOMNode *node;
595     HRESULT hr;
596     BSTR s;
597 
598     product_code = msi_dup_property( package->db, L"ProductCode" );
599     if (!product_code)
600     {
601         /* FIXME: the property ProductCode should be written into the DB somewhere */
602         ERR("no product code to check\n");
603         return ERROR_SUCCESS;
604     }
605 
606     s = SysAllocString( L"MsiPatch/TargetProduct/TargetProductCode" );
607     hr = IXMLDOMDocument_selectNodes( desc, s, &list );
608     SysFreeString(s);
609     if (hr != S_OK)
610         return ERROR_INVALID_PATCH_XML;
611 
612     while (IXMLDOMNodeList_nextNode( list, &node ) == S_OK && r != ERROR_SUCCESS)
613     {
614         hr = IXMLDOMNode_get_text( node, &s );
615         IXMLDOMNode_Release( node );
616         if (hr == S_OK)
617         {
618             if (!wcscmp( s, product_code )) r = ERROR_SUCCESS;
619             SysFreeString( s );
620         }
621     }
622     IXMLDOMNodeList_Release( list );
623 
624     if (r != ERROR_SUCCESS)
625         TRACE("patch not applicable\n");
626 
627     free( product_code );
628     return r;
629 }
630 
determine_patch_sequence(MSIPACKAGE * package,DWORD count,MSIPATCHSEQUENCEINFOW * info)631 static UINT determine_patch_sequence( MSIPACKAGE *package, DWORD count, MSIPATCHSEQUENCEINFOW *info )
632 {
633     IXMLDOMDocument *desc = NULL;
634     DWORD i;
635 
636     if (count > 1)
637         FIXME("patch ordering not supported\n");
638 
639     for (i = 0; i < count; i++)
640     {
641         switch (info[i].ePatchDataType)
642         {
643         case MSIPATCH_DATATYPE_PATCHFILE:
644         {
645             if (MSI_ApplicablePatchW( package, info[i].szPatchData ) != ERROR_SUCCESS)
646             {
647                 info[i].dwOrder = ~0u;
648                 info[i].uStatus = ERROR_PATCH_TARGET_NOT_FOUND;
649             }
650             else
651             {
652                 info[i].dwOrder = i;
653                 info[i].uStatus = ERROR_SUCCESS;
654             }
655             break;
656         }
657         case MSIPATCH_DATATYPE_XMLPATH:
658         case MSIPATCH_DATATYPE_XMLBLOB:
659         {
660             VARIANT_BOOL b;
661             HRESULT hr;
662             BSTR s;
663 
664             if (!desc)
665             {
666                 hr = CoCreateInstance( &CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER,
667                     &IID_IXMLDOMDocument, (void**)&desc );
668                 if (hr != S_OK)
669                 {
670                     ERR( "failed to create DOMDocument30 instance, %#lx\n", hr );
671                     return ERROR_FUNCTION_FAILED;
672                 }
673             }
674 
675             s = SysAllocString( info[i].szPatchData );
676             if (info[i].ePatchDataType == MSIPATCH_DATATYPE_XMLPATH)
677             {
678                 VARIANT src;
679 
680                 V_VT(&src) = VT_BSTR;
681                 V_BSTR(&src) = s;
682                 hr = IXMLDOMDocument_load( desc, src, &b );
683             }
684             else
685                 hr = IXMLDOMDocument_loadXML( desc, s, &b );
686             SysFreeString( s );
687             if ( hr != S_OK )
688             {
689                 ERR("failed to parse patch description\n");
690                 IXMLDOMDocument_Release( desc );
691                 break;
692             }
693 
694             if (MSI_ApplicablePatchXML( package, desc ) != ERROR_SUCCESS)
695             {
696                 info[i].dwOrder = ~0u;
697                 info[i].uStatus = ERROR_PATCH_TARGET_NOT_FOUND;
698             }
699             else
700             {
701                 info[i].dwOrder = i;
702                 info[i].uStatus = ERROR_SUCCESS;
703             }
704             break;
705         }
706         default:
707         {
708             FIXME("unknown patch data type %u\n", info[i].ePatchDataType);
709             info[i].dwOrder = i;
710             info[i].uStatus = ERROR_SUCCESS;
711             break;
712         }
713         }
714 
715         TRACE("szPatchData: %s\n", debugstr_w(info[i].szPatchData));
716         TRACE("ePatchDataType: %u\n", info[i].ePatchDataType);
717         TRACE("dwOrder: %lu\n", info[i].dwOrder);
718         TRACE("uStatus: %u\n", info[i].uStatus);
719     }
720 
721     if (desc) IXMLDOMDocument_Release( desc );
722 
723     return ERROR_SUCCESS;
724 }
725 
MsiDetermineApplicablePatchesW(const WCHAR * szProductPackagePath,DWORD cPatchInfo,MSIPATCHSEQUENCEINFOW * pPatchInfo)726 UINT WINAPI MsiDetermineApplicablePatchesW( const WCHAR *szProductPackagePath, DWORD cPatchInfo,
727                                             MSIPATCHSEQUENCEINFOW *pPatchInfo )
728 {
729     UINT r;
730     MSIPACKAGE *package;
731 
732     TRACE( "%s, %lu, %p\n", debugstr_w(szProductPackagePath), cPatchInfo, pPatchInfo );
733 
734     r = MSI_OpenPackageW( szProductPackagePath, 0, &package );
735     if (r != ERROR_SUCCESS)
736     {
737         ERR("failed to open package %u\n", r);
738         return r;
739     }
740     r = determine_patch_sequence( package, cPatchInfo, pPatchInfo );
741     msiobj_release( &package->hdr );
742     return r;
743 }
744 
MsiDeterminePatchSequenceA(const char * product,const char * usersid,MSIINSTALLCONTEXT context,DWORD count,MSIPATCHSEQUENCEINFOA * patchinfo)745 UINT WINAPI MsiDeterminePatchSequenceA( const char *product, const char *usersid, MSIINSTALLCONTEXT context,
746                                         DWORD count, MSIPATCHSEQUENCEINFOA *patchinfo )
747 {
748     UINT i, r;
749     WCHAR *productW, *usersidW = NULL;
750     MSIPATCHSEQUENCEINFOW *patchinfoW;
751 
752     TRACE( "%s, %s, %d, %lu, %p\n", debugstr_a(product), debugstr_a(usersid), context, count, patchinfo );
753 
754     if (!product) return ERROR_INVALID_PARAMETER;
755     if (!(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
756     if (usersid && !(usersidW = strdupAtoW( usersid )))
757     {
758         free( productW );
759         return ERROR_OUTOFMEMORY;
760     }
761     if (!(patchinfoW = patchinfoAtoW( count, patchinfo )))
762     {
763         free( productW );
764         free( usersidW );
765         return ERROR_OUTOFMEMORY;
766     }
767     r = MsiDeterminePatchSequenceW( productW, usersidW, context, count, patchinfoW );
768     if (r == ERROR_SUCCESS)
769     {
770         for (i = 0; i < count; i++)
771         {
772             patchinfo[i].dwOrder = patchinfoW[i].dwOrder;
773             patchinfo[i].uStatus = patchinfoW[i].uStatus;
774         }
775     }
776     free( productW );
777     free( usersidW );
778     free_patchinfo( count, patchinfoW );
779     return r;
780 }
781 
open_package(const WCHAR * product,const WCHAR * usersid,MSIINSTALLCONTEXT context,MSIPACKAGE ** package)782 static UINT open_package( const WCHAR *product, const WCHAR *usersid,
783                           MSIINSTALLCONTEXT context, MSIPACKAGE **package )
784 {
785     UINT r;
786     HKEY props;
787     WCHAR *localpath, sourcepath[MAX_PATH], filename[MAX_PATH];
788 
789     r = MSIREG_OpenInstallProps( product, context, usersid, &props, FALSE );
790     if (r != ERROR_SUCCESS) return ERROR_BAD_CONFIGURATION;
791 
792     if ((localpath = msi_reg_get_val_str( props, L"LocalPackage" )))
793     {
794         lstrcpyW( sourcepath, localpath );
795         free( localpath );
796     }
797     RegCloseKey( props );
798     if (!localpath || GetFileAttributesW( sourcepath ) == INVALID_FILE_ATTRIBUTES)
799     {
800         DWORD sz = sizeof(sourcepath);
801         MsiSourceListGetInfoW( product, usersid, context, MSICODE_PRODUCT,
802                                INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz );
803         sz = sizeof(filename);
804         MsiSourceListGetInfoW( product, usersid, context, MSICODE_PRODUCT,
805                                INSTALLPROPERTY_PACKAGENAMEW, filename, &sz );
806         lstrcatW( sourcepath, filename );
807     }
808     if (GetFileAttributesW( sourcepath ) == INVALID_FILE_ATTRIBUTES)
809         return ERROR_INSTALL_SOURCE_ABSENT;
810 
811     return MSI_OpenPackageW( sourcepath, 0, package );
812 }
813 
MsiDeterminePatchSequenceW(const WCHAR * product,const WCHAR * usersid,MSIINSTALLCONTEXT context,DWORD count,MSIPATCHSEQUENCEINFOW * patchinfo)814 UINT WINAPI MsiDeterminePatchSequenceW( const WCHAR *product, const WCHAR *usersid, MSIINSTALLCONTEXT context,
815                                         DWORD count, MSIPATCHSEQUENCEINFOW *patchinfo )
816 {
817     UINT r;
818     MSIPACKAGE *package;
819 
820     TRACE( "%s, %s, %d, %lu, %p\n", debugstr_w(product), debugstr_w(usersid), context, count, patchinfo );
821 
822     if (!product) return ERROR_INVALID_PARAMETER;
823     r = open_package( product, usersid, context, &package );
824     if (r != ERROR_SUCCESS) return r;
825 
826     r = determine_patch_sequence( package, count, patchinfo );
827     msiobj_release( &package->hdr );
828     return r;
829 }
830 
MsiConfigureProductExW(LPCWSTR szProduct,int iInstallLevel,INSTALLSTATE eInstallState,LPCWSTR szCommandLine)831 UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
832                         INSTALLSTATE eInstallState, LPCWSTR szCommandLine)
833 {
834     MSIPACKAGE* package = NULL;
835     MSIINSTALLCONTEXT context;
836     UINT r;
837     DWORD sz;
838     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
839     LPWSTR commandline;
840 
841     TRACE("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState,
842           debugstr_w(szCommandLine));
843 
844     if (!szProduct || lstrlenW(szProduct) != GUID_SIZE - 1)
845         return ERROR_INVALID_PARAMETER;
846 
847     if (eInstallState == INSTALLSTATE_ADVERTISED ||
848         eInstallState == INSTALLSTATE_SOURCE)
849     {
850         FIXME("State %d not implemented\n", eInstallState);
851         return ERROR_CALL_NOT_IMPLEMENTED;
852     }
853 
854     r = msi_locate_product(szProduct, &context);
855     if (r != ERROR_SUCCESS)
856         return r;
857 
858     r = open_package(szProduct, NULL, context, &package);
859     if (r != ERROR_SUCCESS)
860         return r;
861 
862     sz = lstrlenW(L" Installed=1") + 1;
863 
864     if (szCommandLine)
865         sz += lstrlenW(szCommandLine);
866 
867     if (eInstallState != INSTALLSTATE_DEFAULT)
868         sz += lstrlenW(L" INSTALLLEVEL=32767");
869 
870     if (eInstallState == INSTALLSTATE_ABSENT)
871         sz += lstrlenW(L" REMOVE=ALL");
872 
873     if (context == MSIINSTALLCONTEXT_MACHINE)
874         sz += lstrlenW(L" ALLUSERS=1");
875 
876     commandline = malloc(sz * sizeof(WCHAR));
877     if (!commandline)
878     {
879         r = ERROR_OUTOFMEMORY;
880         goto end;
881     }
882 
883     commandline[0] = 0;
884     if (szCommandLine)
885         lstrcpyW(commandline, szCommandLine);
886 
887     if (eInstallState != INSTALLSTATE_DEFAULT)
888         lstrcatW(commandline, L" INSTALLLEVEL=32767");
889 
890     if (eInstallState == INSTALLSTATE_ABSENT)
891         lstrcatW(commandline, L" REMOVE=ALL");
892 
893     if (context == MSIINSTALLCONTEXT_MACHINE)
894         lstrcatW(commandline, L" ALLUSERS=1");
895 
896     sz = sizeof(sourcepath);
897     MsiSourceListGetInfoW(szProduct, NULL, context, MSICODE_PRODUCT,
898                           INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
899 
900     sz = sizeof(filename);
901     MsiSourceListGetInfoW(szProduct, NULL, context, MSICODE_PRODUCT,
902                           INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
903 
904     lstrcatW(sourcepath, filename);
905 
906     r = MSI_InstallPackage( package, sourcepath, commandline );
907 
908     free(commandline);
909 
910 end:
911     msiobj_release( &package->hdr );
912 
913     return r;
914 }
915 
MsiConfigureProductExA(LPCSTR szProduct,int iInstallLevel,INSTALLSTATE eInstallState,LPCSTR szCommandLine)916 UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel,
917                         INSTALLSTATE eInstallState, LPCSTR szCommandLine)
918 {
919     LPWSTR szwProduct = NULL;
920     LPWSTR szwCommandLine = NULL;
921     UINT r = ERROR_OUTOFMEMORY;
922 
923     if( szProduct )
924     {
925         szwProduct = strdupAtoW( szProduct );
926         if( !szwProduct )
927             goto end;
928     }
929 
930     if( szCommandLine)
931     {
932         szwCommandLine = strdupAtoW( szCommandLine );
933         if( !szwCommandLine)
934             goto end;
935     }
936 
937     r = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState,
938                                 szwCommandLine );
939 end:
940     free( szwProduct );
941     free( szwCommandLine);
942 
943     return r;
944 }
945 
MsiConfigureProductA(LPCSTR szProduct,int iInstallLevel,INSTALLSTATE eInstallState)946 UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel,
947                                  INSTALLSTATE eInstallState)
948 {
949     LPWSTR szwProduct = NULL;
950     UINT r;
951 
952     TRACE("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
953 
954     if( szProduct )
955     {
956         szwProduct = strdupAtoW( szProduct );
957         if( !szwProduct )
958             return ERROR_OUTOFMEMORY;
959     }
960 
961     r = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState );
962     free( szwProduct );
963 
964     return r;
965 }
966 
MsiConfigureProductW(LPCWSTR szProduct,int iInstallLevel,INSTALLSTATE eInstallState)967 UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel,
968                                  INSTALLSTATE eInstallState)
969 {
970     return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL);
971 }
972 
MsiGetProductCodeA(LPCSTR szComponent,LPSTR szBuffer)973 UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
974 {
975     LPWSTR szwComponent = NULL;
976     UINT r;
977     WCHAR szwBuffer[GUID_SIZE];
978 
979     TRACE("%s %p\n", debugstr_a(szComponent), szBuffer);
980 
981     if( szComponent )
982     {
983         szwComponent = strdupAtoW( szComponent );
984         if( !szwComponent )
985             return ERROR_OUTOFMEMORY;
986     }
987 
988     *szwBuffer = '\0';
989     r = MsiGetProductCodeW( szwComponent, szwBuffer );
990 
991     if(*szwBuffer)
992         WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL);
993 
994     free( szwComponent );
995 
996     return r;
997 }
998 
MsiGetProductCodeW(LPCWSTR szComponent,LPWSTR szBuffer)999 UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
1000 {
1001     UINT rc, index;
1002     HKEY compkey, prodkey;
1003     WCHAR squashed_comp[SQUASHED_GUID_SIZE], squashed_prod[SQUASHED_GUID_SIZE];
1004     DWORD sz = ARRAY_SIZE(squashed_prod);
1005 
1006     TRACE("%s %p\n", debugstr_w(szComponent), szBuffer);
1007 
1008     if (!szComponent || !*szComponent)
1009         return ERROR_INVALID_PARAMETER;
1010 
1011     if (!squash_guid( szComponent, squashed_comp ))
1012         return ERROR_INVALID_PARAMETER;
1013 
1014     if (MSIREG_OpenUserDataComponentKey(szComponent, NULL, &compkey, FALSE) != ERROR_SUCCESS &&
1015         MSIREG_OpenUserDataComponentKey(szComponent, L"S-1-5-18", &compkey, FALSE) != ERROR_SUCCESS)
1016     {
1017         return ERROR_UNKNOWN_COMPONENT;
1018     }
1019 
1020     rc = RegEnumValueW( compkey, 0, squashed_prod, &sz, NULL, NULL, NULL, NULL );
1021     if (rc != ERROR_SUCCESS)
1022     {
1023         RegCloseKey(compkey);
1024         return ERROR_UNKNOWN_COMPONENT;
1025     }
1026 
1027     /* check simple case, only one product */
1028     rc = RegEnumValueW( compkey, 1, squashed_prod, &sz, NULL, NULL, NULL, NULL );
1029     if (rc == ERROR_NO_MORE_ITEMS)
1030     {
1031         rc = ERROR_SUCCESS;
1032         goto done;
1033     }
1034 
1035     index = 0;
1036     while ((rc = RegEnumValueW( compkey, index, squashed_prod, &sz, NULL, NULL, NULL, NULL )) !=
1037            ERROR_NO_MORE_ITEMS)
1038     {
1039         index++;
1040         sz = GUID_SIZE;
1041         unsquash_guid( squashed_prod, szBuffer );
1042 
1043         if (MSIREG_OpenProductKey(szBuffer, NULL,
1044                                   MSIINSTALLCONTEXT_USERMANAGED,
1045                                   &prodkey, FALSE) == ERROR_SUCCESS ||
1046             MSIREG_OpenProductKey(szBuffer, NULL,
1047                                   MSIINSTALLCONTEXT_USERUNMANAGED,
1048                                   &prodkey, FALSE) == ERROR_SUCCESS ||
1049             MSIREG_OpenProductKey(szBuffer, NULL,
1050                                   MSIINSTALLCONTEXT_MACHINE,
1051                                   &prodkey, FALSE) == ERROR_SUCCESS)
1052         {
1053             RegCloseKey(prodkey);
1054             rc = ERROR_SUCCESS;
1055             goto done;
1056         }
1057     }
1058 
1059     rc = ERROR_INSTALL_FAILURE;
1060 
1061 done:
1062     RegCloseKey(compkey);
1063     unsquash_guid( squashed_prod, szBuffer );
1064     return rc;
1065 }
1066 
reg_get_value(HKEY hkey,const WCHAR * name,DWORD * type)1067 static WCHAR *reg_get_value( HKEY hkey, const WCHAR *name, DWORD *type )
1068 {
1069     LONG res;
1070 
1071     if ((res = RegQueryValueExW( hkey, name, NULL, type, NULL, NULL )) != ERROR_SUCCESS) return NULL;
1072 
1073     if (*type == REG_SZ) return msi_reg_get_val_str( hkey, name );
1074     if (*type == REG_DWORD)
1075     {
1076         WCHAR temp[11];
1077         DWORD val;
1078 
1079         if (!msi_reg_get_val_dword( hkey, name, &val )) return NULL;
1080         swprintf( temp, ARRAY_SIZE(temp), L"%u", val );
1081         return wcsdup( temp );
1082     }
1083 
1084     ERR( "unhandled value type %lu\n", *type );
1085     return NULL;
1086 }
1087 
MSI_GetProductInfo(LPCWSTR szProduct,LPCWSTR szAttribute,awstring * szValue,LPDWORD pcchValueBuf)1088 static UINT MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
1089                                awstring *szValue, LPDWORD pcchValueBuf)
1090 {
1091     static WCHAR empty[] = L"";
1092     MSIINSTALLCONTEXT context = MSIINSTALLCONTEXT_USERUNMANAGED;
1093     UINT r = ERROR_UNKNOWN_PROPERTY;
1094     HKEY prodkey, userdata, source;
1095     WCHAR *val = NULL, squashed_pc[SQUASHED_GUID_SIZE], packagecode[GUID_SIZE];
1096     BOOL badconfig = FALSE;
1097     LONG res;
1098     DWORD type = REG_NONE;
1099 
1100     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1101           debugstr_w(szAttribute), szValue, pcchValueBuf);
1102 
1103     if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szAttribute)
1104         return ERROR_INVALID_PARAMETER;
1105 
1106     if (!squash_guid( szProduct, squashed_pc ))
1107         return ERROR_INVALID_PARAMETER;
1108 
1109     if ((r = MSIREG_OpenProductKey(szProduct, NULL,
1110                                    MSIINSTALLCONTEXT_USERMANAGED,
1111                                    &prodkey, FALSE)) != ERROR_SUCCESS &&
1112         (r = MSIREG_OpenProductKey(szProduct, NULL,
1113                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1114                                    &prodkey, FALSE)) != ERROR_SUCCESS &&
1115         (r = MSIREG_OpenProductKey(szProduct, NULL,
1116                                    MSIINSTALLCONTEXT_MACHINE,
1117                                     &prodkey, FALSE)) == ERROR_SUCCESS)
1118     {
1119         context = MSIINSTALLCONTEXT_MACHINE;
1120     }
1121 
1122     if (!wcscmp( szAttribute, INSTALLPROPERTY_HELPLINKW ) ||
1123         !wcscmp( szAttribute, INSTALLPROPERTY_HELPTELEPHONEW ) ||
1124         !wcscmp( szAttribute, INSTALLPROPERTY_INSTALLDATEW ) ||
1125         !wcscmp( szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ) ||
1126         !wcscmp( szAttribute, INSTALLPROPERTY_INSTALLLOCATIONW ) ||
1127         !wcscmp( szAttribute, INSTALLPROPERTY_INSTALLSOURCEW ) ||
1128         !wcscmp( szAttribute, INSTALLPROPERTY_LOCALPACKAGEW ) ||
1129         !wcscmp( szAttribute, INSTALLPROPERTY_PUBLISHERW ) ||
1130         !wcscmp( szAttribute, INSTALLPROPERTY_URLINFOABOUTW ) ||
1131         !wcscmp( szAttribute, INSTALLPROPERTY_URLUPDATEINFOW ) ||
1132         !wcscmp( szAttribute, INSTALLPROPERTY_VERSIONMINORW ) ||
1133         !wcscmp( szAttribute, INSTALLPROPERTY_VERSIONMAJORW ) ||
1134         !wcscmp( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ) ||
1135         !wcscmp( szAttribute, INSTALLPROPERTY_PRODUCTIDW ) ||
1136         !wcscmp( szAttribute, INSTALLPROPERTY_REGCOMPANYW ) ||
1137         !wcscmp( szAttribute, INSTALLPROPERTY_REGOWNERW ))
1138     {
1139         if (!prodkey)
1140         {
1141             r = ERROR_UNKNOWN_PRODUCT;
1142             goto done;
1143         }
1144         if (MSIREG_OpenInstallProps(szProduct, context, NULL, &userdata, FALSE))
1145         {
1146             r = ERROR_UNKNOWN_PROPERTY;
1147             goto done;
1148         }
1149 
1150         if (!wcscmp( szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ))
1151             szAttribute = L"DisplayName";
1152         else if (!wcscmp( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ))
1153             szAttribute = L"DisplayVersion";
1154 
1155         val = reg_get_value(userdata, szAttribute, &type);
1156         if (!val)
1157             val = empty;
1158         RegCloseKey(userdata);
1159     }
1160     else if (!wcscmp( szAttribute, INSTALLPROPERTY_INSTANCETYPEW ) ||
1161              !wcscmp( szAttribute, INSTALLPROPERTY_TRANSFORMSW ) ||
1162              !wcscmp( szAttribute, INSTALLPROPERTY_LANGUAGEW ) ||
1163              !wcscmp( szAttribute, INSTALLPROPERTY_PRODUCTNAMEW ) ||
1164              !wcscmp( szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW ) ||
1165              !wcscmp( szAttribute, INSTALLPROPERTY_PACKAGECODEW ) ||
1166              !wcscmp( szAttribute, INSTALLPROPERTY_VERSIONW ) ||
1167              !wcscmp( szAttribute, INSTALLPROPERTY_PRODUCTICONW ) ||
1168              !wcscmp( szAttribute, INSTALLPROPERTY_PACKAGENAMEW ) ||
1169              !wcscmp( szAttribute, INSTALLPROPERTY_AUTHORIZED_LUA_APPW ))
1170     {
1171         if (!prodkey)
1172         {
1173             r = ERROR_UNKNOWN_PRODUCT;
1174             goto done;
1175         }
1176 
1177         if (!wcscmp( szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW ))
1178             szAttribute = L"Assignment";
1179 
1180         if (!wcscmp( szAttribute, INSTALLPROPERTY_PACKAGENAMEW ))
1181         {
1182             res = RegOpenKeyW(prodkey, L"SourceList", &source);
1183             if (res != ERROR_SUCCESS)
1184             {
1185                 r = ERROR_UNKNOWN_PRODUCT;
1186                 goto done;
1187             }
1188 
1189             val = reg_get_value(source, szAttribute, &type);
1190             if (!val)
1191                 val = empty;
1192 
1193             RegCloseKey(source);
1194         }
1195         else
1196         {
1197             val = reg_get_value(prodkey, szAttribute, &type);
1198             if (!val)
1199                 val = empty;
1200         }
1201 
1202         if (val != empty && type != REG_DWORD &&
1203             !wcscmp( szAttribute, INSTALLPROPERTY_PACKAGECODEW ))
1204         {
1205             if (lstrlenW( val ) != SQUASHED_GUID_SIZE - 1)
1206                 badconfig = TRUE;
1207             else
1208             {
1209                 unsquash_guid(val, packagecode);
1210                 free(val);
1211                 val = wcsdup(packagecode);
1212             }
1213         }
1214     }
1215 
1216     if (!val)
1217     {
1218         r = ERROR_UNKNOWN_PROPERTY;
1219         goto done;
1220     }
1221 
1222     if (pcchValueBuf)
1223     {
1224         int len = lstrlenW( val );
1225 
1226         /* If szBuffer (szValue->str) is NULL, there's no need to copy the value
1227          * out.  Also, *pcchValueBuf may be uninitialized in this case, so we
1228          * can't rely on its value.
1229          */
1230         if (szValue->str.a || szValue->str.w)
1231         {
1232             DWORD size = *pcchValueBuf;
1233             if (len < size)
1234                 r = msi_strcpy_to_awstring( val, len, szValue, &size );
1235             else
1236                 r = ERROR_MORE_DATA;
1237         }
1238 
1239         if (!badconfig)
1240             *pcchValueBuf = len;
1241     }
1242 
1243     if (badconfig)
1244         r = ERROR_BAD_CONFIGURATION;
1245 
1246     if (val != empty)
1247         free(val);
1248 
1249 done:
1250     RegCloseKey(prodkey);
1251     return r;
1252 }
1253 
MsiGetProductInfoA(LPCSTR szProduct,LPCSTR szAttribute,LPSTR szBuffer,LPDWORD pcchValueBuf)1254 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
1255                                LPSTR szBuffer, LPDWORD pcchValueBuf)
1256 {
1257     LPWSTR szwProduct, szwAttribute = NULL;
1258     UINT r = ERROR_OUTOFMEMORY;
1259     awstring buffer;
1260 
1261     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
1262           szBuffer, pcchValueBuf);
1263 
1264     szwProduct = strdupAtoW( szProduct );
1265     if( szProduct && !szwProduct )
1266         goto end;
1267 
1268     szwAttribute = strdupAtoW( szAttribute );
1269     if( szAttribute && !szwAttribute )
1270         goto end;
1271 
1272     buffer.unicode = FALSE;
1273     buffer.str.a = szBuffer;
1274 
1275     r = MSI_GetProductInfo( szwProduct, szwAttribute,
1276                             &buffer, pcchValueBuf );
1277 
1278 end:
1279     free( szwProduct );
1280     free( szwAttribute );
1281 
1282     return r;
1283 }
1284 
MsiGetProductInfoW(LPCWSTR szProduct,LPCWSTR szAttribute,LPWSTR szBuffer,LPDWORD pcchValueBuf)1285 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
1286                                LPWSTR szBuffer, LPDWORD pcchValueBuf)
1287 {
1288     awstring buffer;
1289 
1290     TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szAttribute),
1291           szBuffer, pcchValueBuf);
1292 
1293     buffer.unicode = TRUE;
1294     buffer.str.w = szBuffer;
1295 
1296     return MSI_GetProductInfo( szProduct, szAttribute,
1297                                &buffer, pcchValueBuf );
1298 }
1299 
MsiGetProductInfoExA(LPCSTR szProductCode,LPCSTR szUserSid,MSIINSTALLCONTEXT dwContext,LPCSTR szProperty,LPSTR szValue,LPDWORD pcchValue)1300 UINT WINAPI MsiGetProductInfoExA(LPCSTR szProductCode, LPCSTR szUserSid,
1301                                  MSIINSTALLCONTEXT dwContext, LPCSTR szProperty,
1302                                  LPSTR szValue, LPDWORD pcchValue)
1303 {
1304     LPWSTR product = NULL;
1305     LPWSTR usersid = NULL;
1306     LPWSTR property = NULL;
1307     LPWSTR value = NULL;
1308     DWORD len = 0;
1309     UINT r;
1310 
1311     TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_a(szProductCode),
1312           debugstr_a(szUserSid), dwContext, debugstr_a(szProperty),
1313            szValue, pcchValue);
1314 
1315     if (szValue && !pcchValue)
1316         return ERROR_INVALID_PARAMETER;
1317 
1318     if (szProductCode) product = strdupAtoW(szProductCode);
1319     if (szUserSid) usersid = strdupAtoW(szUserSid);
1320     if (szProperty) property = strdupAtoW(szProperty);
1321 
1322     r = MsiGetProductInfoExW(product, usersid, dwContext, property,
1323                              NULL, &len);
1324     if (r != ERROR_SUCCESS)
1325         goto done;
1326 
1327     value = malloc(++len * sizeof(WCHAR));
1328     if (!value)
1329     {
1330         r = ERROR_OUTOFMEMORY;
1331         goto done;
1332     }
1333 
1334     r = MsiGetProductInfoExW(product, usersid, dwContext, property,
1335                              value, &len);
1336     if (r != ERROR_SUCCESS)
1337         goto done;
1338 
1339     if (!pcchValue)
1340         goto done;
1341 
1342     len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
1343     if (*pcchValue >= len)
1344         WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
1345     else if (szValue)
1346     {
1347         r = ERROR_MORE_DATA;
1348         if (*pcchValue > 0)
1349             *szValue = '\0';
1350     }
1351 
1352     if (*pcchValue <= len || !szValue)
1353         len = len * sizeof(WCHAR) - 1;
1354 
1355     *pcchValue = len - 1;
1356 
1357 done:
1358     free(product);
1359     free(usersid);
1360     free(property);
1361     free(value);
1362 
1363     return r;
1364 }
1365 
copy_outval(const WCHAR * val,WCHAR * out,DWORD * size)1366 static UINT copy_outval(const WCHAR *val, WCHAR *out, DWORD *size)
1367 {
1368     UINT r = ERROR_SUCCESS;
1369 
1370     if (!val)
1371         return ERROR_UNKNOWN_PROPERTY;
1372 
1373     if (out)
1374     {
1375         if (lstrlenW(val) >= *size)
1376         {
1377             r = ERROR_MORE_DATA;
1378             if (*size > 0)
1379                 *out = '\0';
1380         }
1381         else
1382             lstrcpyW(out, val);
1383     }
1384 
1385     if (size)
1386         *size = lstrlenW(val);
1387 
1388     return r;
1389 }
1390 
MsiGetProductInfoExW(LPCWSTR szProductCode,LPCWSTR szUserSid,MSIINSTALLCONTEXT dwContext,LPCWSTR szProperty,LPWSTR szValue,LPDWORD pcchValue)1391 UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
1392                                  MSIINSTALLCONTEXT dwContext, LPCWSTR szProperty,
1393                                  LPWSTR szValue, LPDWORD pcchValue)
1394 {
1395     WCHAR *val = NULL, squashed_pc[SQUASHED_GUID_SIZE];
1396     LPCWSTR package = NULL;
1397     HKEY props = NULL, prod, classes = NULL, managed, hkey = NULL;
1398     DWORD type;
1399     UINT r = ERROR_UNKNOWN_PRODUCT;
1400 
1401     TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_w(szProductCode),
1402           debugstr_w(szUserSid), dwContext, debugstr_w(szProperty),
1403            szValue, pcchValue);
1404 
1405     if (!szProductCode || !squash_guid( szProductCode, squashed_pc ))
1406         return ERROR_INVALID_PARAMETER;
1407 
1408     if (szValue && !pcchValue)
1409         return ERROR_INVALID_PARAMETER;
1410 
1411     if (dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
1412         dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
1413         dwContext != MSIINSTALLCONTEXT_MACHINE)
1414         return ERROR_INVALID_PARAMETER;
1415 
1416     if (!szProperty || !*szProperty)
1417         return ERROR_INVALID_PARAMETER;
1418 
1419     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
1420         return ERROR_INVALID_PARAMETER;
1421 
1422     /* FIXME: dwContext is provided, no need to search for it */
1423     MSIREG_OpenProductKey(szProductCode, NULL,MSIINSTALLCONTEXT_USERMANAGED,
1424                           &managed, FALSE);
1425     MSIREG_OpenProductKey(szProductCode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1426                           &prod, FALSE);
1427 
1428     MSIREG_OpenInstallProps(szProductCode, dwContext, NULL, &props, FALSE);
1429 
1430     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
1431     {
1432         package = INSTALLPROPERTY_LOCALPACKAGEW;
1433 
1434         if (!props && !prod)
1435             goto done;
1436     }
1437     else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1438     {
1439         package = L"ManagedLocalPackage";
1440 
1441         if (!props && !managed)
1442             goto done;
1443     }
1444     else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1445     {
1446         package = INSTALLPROPERTY_LOCALPACKAGEW;
1447         MSIREG_OpenProductKey(szProductCode, NULL, dwContext, &classes, FALSE);
1448 
1449         if (!props && !classes)
1450             goto done;
1451     }
1452 
1453     if (!wcscmp( szProperty, INSTALLPROPERTY_HELPLINKW ) ||
1454         !wcscmp( szProperty, INSTALLPROPERTY_HELPTELEPHONEW ) ||
1455         !wcscmp( szProperty, INSTALLPROPERTY_INSTALLDATEW ) ||
1456         !wcscmp( szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ) ||
1457         !wcscmp( szProperty, INSTALLPROPERTY_INSTALLLOCATIONW ) ||
1458         !wcscmp( szProperty, INSTALLPROPERTY_INSTALLSOURCEW ) ||
1459         !wcscmp( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ) ||
1460         !wcscmp( szProperty, INSTALLPROPERTY_PUBLISHERW ) ||
1461         !wcscmp( szProperty, INSTALLPROPERTY_URLINFOABOUTW ) ||
1462         !wcscmp( szProperty, INSTALLPROPERTY_URLUPDATEINFOW ) ||
1463         !wcscmp( szProperty, INSTALLPROPERTY_VERSIONMINORW ) ||
1464         !wcscmp( szProperty, INSTALLPROPERTY_VERSIONMAJORW ) ||
1465         !wcscmp( szProperty, INSTALLPROPERTY_VERSIONSTRINGW ) ||
1466         !wcscmp( szProperty, INSTALLPROPERTY_PRODUCTIDW ) ||
1467         !wcscmp( szProperty, INSTALLPROPERTY_REGCOMPANYW ) ||
1468         !wcscmp( szProperty, INSTALLPROPERTY_REGOWNERW ) ||
1469         !wcscmp( szProperty, INSTALLPROPERTY_INSTANCETYPEW ))
1470     {
1471         val = reg_get_value(props, package, &type);
1472         if (!val)
1473         {
1474             if (prod || classes)
1475                 r = ERROR_UNKNOWN_PROPERTY;
1476 
1477             goto done;
1478         }
1479 
1480         free(val);
1481 
1482         if (!wcscmp( szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ))
1483             szProperty = L"DisplayName";
1484         else if (!wcscmp( szProperty, INSTALLPROPERTY_VERSIONSTRINGW ))
1485             szProperty = L"DisplayVersion";
1486 
1487         val = reg_get_value(props, szProperty, &type);
1488         if (!val)
1489             val = wcsdup(L"");
1490 
1491         r = copy_outval(val, szValue, pcchValue);
1492     }
1493     else if (!wcscmp( szProperty, INSTALLPROPERTY_TRANSFORMSW ) ||
1494              !wcscmp( szProperty, INSTALLPROPERTY_LANGUAGEW ) ||
1495              !wcscmp( szProperty, INSTALLPROPERTY_PRODUCTNAMEW ) ||
1496              !wcscmp( szProperty, INSTALLPROPERTY_PACKAGECODEW ) ||
1497              !wcscmp( szProperty, INSTALLPROPERTY_VERSIONW ) ||
1498              !wcscmp( szProperty, INSTALLPROPERTY_PRODUCTICONW ) ||
1499              !wcscmp( szProperty, INSTALLPROPERTY_PACKAGENAMEW ) ||
1500              !wcscmp( szProperty, INSTALLPROPERTY_AUTHORIZED_LUA_APPW ))
1501     {
1502         if (!prod && !classes)
1503             goto done;
1504 
1505         if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
1506             hkey = prod;
1507         else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1508             hkey = managed;
1509         else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1510             hkey = classes;
1511 
1512         val = reg_get_value(hkey, szProperty, &type);
1513         if (!val)
1514             val = wcsdup(L"");
1515 
1516         r = copy_outval(val, szValue, pcchValue);
1517     }
1518     else if (!wcscmp( szProperty, INSTALLPROPERTY_PRODUCTSTATEW ))
1519     {
1520         if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1521         {
1522             if (props)
1523             {
1524                 val = reg_get_value(props, package, &type);
1525                 if (!val)
1526                     goto done;
1527 
1528                 free(val);
1529                 val = wcsdup(L"5");
1530             }
1531             else
1532                 val = wcsdup(L"1");
1533 
1534             r = copy_outval(val, szValue, pcchValue);
1535             goto done;
1536         }
1537         else if (props && (val = reg_get_value(props, package, &type)))
1538         {
1539             free(val);
1540             val = wcsdup(L"5");
1541             r = copy_outval(val, szValue, pcchValue);
1542             goto done;
1543         }
1544 
1545         if (prod || managed)
1546             val = wcsdup(L"1");
1547         else
1548             goto done;
1549 
1550         r = copy_outval(val, szValue, pcchValue);
1551     }
1552     else if (!wcscmp( szProperty, INSTALLPROPERTY_ASSIGNMENTTYPEW ))
1553     {
1554         if (!prod && !classes)
1555             goto done;
1556 
1557         /* FIXME */
1558         val = wcsdup(L"");
1559         r = copy_outval(val, szValue, pcchValue);
1560     }
1561     else
1562         r = ERROR_UNKNOWN_PROPERTY;
1563 
1564 done:
1565     RegCloseKey(props);
1566     RegCloseKey(prod);
1567     RegCloseKey(managed);
1568     RegCloseKey(classes);
1569     free(val);
1570 
1571     return r;
1572 }
1573 
MsiGetPatchFileListA(LPCSTR szProductCode,LPCSTR szPatchList,LPDWORD pcFiles,MSIHANDLE ** pphFileRecords)1574 UINT WINAPI MsiGetPatchFileListA(LPCSTR szProductCode, LPCSTR szPatchList,
1575                                  LPDWORD pcFiles, MSIHANDLE **pphFileRecords)
1576 {
1577     FIXME("(%s, %s, %p, %p) stub!\n", debugstr_a(szProductCode),
1578           debugstr_a(szPatchList), pcFiles, pphFileRecords);
1579     return ERROR_FUNCTION_FAILED;
1580 }
1581 
MsiGetPatchFileListW(LPCWSTR szProductCode,LPCWSTR szPatchList,LPDWORD pcFiles,MSIHANDLE ** pphFileRecords)1582 UINT WINAPI MsiGetPatchFileListW(LPCWSTR szProductCode, LPCWSTR szPatchList,
1583                                  LPDWORD pcFiles, MSIHANDLE **pphFileRecords)
1584 {
1585     FIXME("(%s, %s, %p, %p) stub!\n", debugstr_w(szProductCode),
1586           debugstr_w(szPatchList), pcFiles, pphFileRecords);
1587     return ERROR_FUNCTION_FAILED;
1588 }
1589 
MsiGetPatchInfoExA(LPCSTR szPatchCode,LPCSTR szProductCode,LPCSTR szUserSid,MSIINSTALLCONTEXT dwContext,LPCSTR szProperty,LPSTR lpValue,DWORD * pcchValue)1590 UINT WINAPI MsiGetPatchInfoExA(LPCSTR szPatchCode, LPCSTR szProductCode,
1591                                LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1592                                LPCSTR szProperty, LPSTR lpValue, DWORD *pcchValue)
1593 {
1594     LPWSTR patch = NULL, product = NULL, usersid = NULL;
1595     LPWSTR property = NULL, val = NULL;
1596     DWORD len;
1597     UINT r;
1598 
1599     TRACE("(%s, %s, %s, %d, %s, %p, %p)\n", debugstr_a(szPatchCode),
1600           debugstr_a(szProductCode), debugstr_a(szUserSid), dwContext,
1601           debugstr_a(szProperty), lpValue, pcchValue);
1602 
1603     if (lpValue && !pcchValue)
1604         return ERROR_INVALID_PARAMETER;
1605 
1606     if (szPatchCode) patch = strdupAtoW(szPatchCode);
1607     if (szProductCode) product = strdupAtoW(szProductCode);
1608     if (szUserSid) usersid = strdupAtoW(szUserSid);
1609     if (szProperty) property = strdupAtoW(szProperty);
1610 
1611     len = 0;
1612     r = MsiGetPatchInfoExW(patch, product, usersid, dwContext, property,
1613                            NULL, &len);
1614     if (r != ERROR_SUCCESS)
1615         goto done;
1616 
1617     val = malloc(++len * sizeof(WCHAR));
1618     if (!val)
1619     {
1620         r = ERROR_OUTOFMEMORY;
1621         goto done;
1622     }
1623 
1624     r = MsiGetPatchInfoExW(patch, product, usersid, dwContext, property,
1625                            val, &len);
1626     if (r != ERROR_SUCCESS || !pcchValue)
1627         goto done;
1628 
1629     if (lpValue)
1630         WideCharToMultiByte(CP_ACP, 0, val, -1, lpValue,
1631                             *pcchValue - 1, NULL, NULL);
1632 
1633     len = lstrlenW(val);
1634     if ((*val && *pcchValue < len + 1) || !lpValue)
1635     {
1636         if (lpValue)
1637         {
1638             r = ERROR_MORE_DATA;
1639             lpValue[*pcchValue - 1] = '\0';
1640         }
1641 
1642         *pcchValue = len * sizeof(WCHAR);
1643     }
1644     else
1645         *pcchValue = len;
1646 
1647 done:
1648     free(val);
1649     free(patch);
1650     free(product);
1651     free(usersid);
1652     free(property);
1653 
1654     return r;
1655 }
1656 
MsiGetPatchInfoExW(LPCWSTR szPatchCode,LPCWSTR szProductCode,LPCWSTR szUserSid,MSIINSTALLCONTEXT dwContext,LPCWSTR szProperty,LPWSTR lpValue,DWORD * pcchValue)1657 UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode,
1658                                LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1659                                LPCWSTR szProperty, LPWSTR lpValue, DWORD *pcchValue)
1660 {
1661     WCHAR *val = NULL, squashed_pc[SQUASHED_GUID_SIZE], squashed_patch[SQUASHED_GUID_SIZE];
1662     HKEY udprod = 0, prod = 0, props = 0;
1663     HKEY patch = 0, patches = 0;
1664     HKEY udpatch = 0, datakey = 0;
1665     HKEY prodpatches = 0;
1666     UINT r = ERROR_UNKNOWN_PRODUCT;
1667     DWORD len, type;
1668     LONG res;
1669 
1670     TRACE("(%s, %s, %s, %d, %s, %p, %p)\n", debugstr_w(szPatchCode),
1671           debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext,
1672           debugstr_w(szProperty), lpValue, pcchValue);
1673 
1674     if (!szProductCode || !squash_guid( szProductCode, squashed_pc ))
1675         return ERROR_INVALID_PARAMETER;
1676 
1677     if (!szPatchCode || !squash_guid( szPatchCode, squashed_patch ))
1678         return ERROR_INVALID_PARAMETER;
1679 
1680     if (!szProperty)
1681         return ERROR_INVALID_PARAMETER;
1682 
1683     if (lpValue && !pcchValue)
1684         return ERROR_INVALID_PARAMETER;
1685 
1686     if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
1687         dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
1688         dwContext != MSIINSTALLCONTEXT_MACHINE)
1689         return ERROR_INVALID_PARAMETER;
1690 
1691     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
1692         return ERROR_INVALID_PARAMETER;
1693 
1694     if (szUserSid && !wcscmp( szUserSid, L"S-1-5-18" ))
1695         return ERROR_INVALID_PARAMETER;
1696 
1697     if (MSIREG_OpenUserDataProductKey(szProductCode, dwContext, NULL,
1698                                       &udprod, FALSE) != ERROR_SUCCESS)
1699         goto done;
1700 
1701     if (MSIREG_OpenInstallProps(szProductCode, dwContext, NULL,
1702                                 &props, FALSE) != ERROR_SUCCESS)
1703         goto done;
1704 
1705     r = ERROR_UNKNOWN_PATCH;
1706 
1707     res = RegOpenKeyExW(udprod, L"Patches", 0, KEY_READ, &patches);
1708     if (res != ERROR_SUCCESS)
1709         goto done;
1710 
1711     res = RegOpenKeyExW( patches, squashed_patch, 0, KEY_READ, &patch );
1712     if (res != ERROR_SUCCESS)
1713         goto done;
1714 
1715     if (!wcscmp( szProperty, INSTALLPROPERTY_TRANSFORMSW ))
1716     {
1717         if (MSIREG_OpenProductKey(szProductCode, NULL, dwContext,
1718                                   &prod, FALSE) != ERROR_SUCCESS)
1719             goto done;
1720 
1721         res = RegOpenKeyExW(prod, L"Patches", 0, KEY_ALL_ACCESS, &prodpatches);
1722         if (res != ERROR_SUCCESS)
1723             goto done;
1724 
1725         datakey = prodpatches;
1726         szProperty = squashed_patch;
1727     }
1728     else
1729     {
1730         if (MSIREG_OpenUserDataPatchKey(szPatchCode, dwContext,
1731                                         &udpatch, FALSE) != ERROR_SUCCESS)
1732             goto done;
1733 
1734         if (!wcscmp( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ))
1735         {
1736             if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1737                 szProperty = L"ManagedLocalPackage";
1738             datakey = udpatch;
1739         }
1740         else if (!wcscmp( szProperty, INSTALLPROPERTY_INSTALLDATEW ))
1741         {
1742             datakey = patch;
1743             szProperty = L"Installed";
1744         }
1745         else if (!wcscmp( szProperty, INSTALLPROPERTY_UNINSTALLABLEW ) ||
1746                  !wcscmp( szProperty, INSTALLPROPERTY_PATCHSTATEW ) ||
1747                  !wcscmp( szProperty, INSTALLPROPERTY_DISPLAYNAMEW ) ||
1748                  !wcscmp( szProperty, INSTALLPROPERTY_MOREINFOURLW ))
1749         {
1750             datakey = patch;
1751         }
1752         else
1753         {
1754             r = ERROR_UNKNOWN_PROPERTY;
1755             goto done;
1756         }
1757     }
1758 
1759     val = reg_get_value(datakey, szProperty, &type);
1760     if (!val)
1761         val = wcsdup(L"");
1762 
1763     r = ERROR_SUCCESS;
1764 
1765     if (!pcchValue)
1766         goto done;
1767 
1768     if (lpValue)
1769         lstrcpynW(lpValue, val, *pcchValue);
1770 
1771     len = lstrlenW(val);
1772     if ((*val && *pcchValue < len + 1) || !lpValue)
1773     {
1774         if (lpValue)
1775             r = ERROR_MORE_DATA;
1776 
1777         *pcchValue = len * sizeof(WCHAR);
1778     }
1779 
1780     *pcchValue = len;
1781 
1782 done:
1783     free(val);
1784     RegCloseKey(prodpatches);
1785     RegCloseKey(prod);
1786     RegCloseKey(patch);
1787     RegCloseKey(patches);
1788     RegCloseKey(udpatch);
1789     RegCloseKey(props);
1790     RegCloseKey(udprod);
1791 
1792     return r;
1793 }
1794 
MsiGetPatchInfoA(LPCSTR patch,LPCSTR attr,LPSTR buffer,LPDWORD buflen)1795 UINT WINAPI MsiGetPatchInfoA( LPCSTR patch, LPCSTR attr, LPSTR buffer, LPDWORD buflen )
1796 {
1797     UINT r = ERROR_OUTOFMEMORY;
1798     DWORD size;
1799     LPWSTR patchW = NULL, attrW = NULL, bufferW = NULL;
1800 
1801     TRACE("%s %s %p %p\n", debugstr_a(patch), debugstr_a(attr), buffer, buflen);
1802 
1803     if (!patch || !attr)
1804         return ERROR_INVALID_PARAMETER;
1805 
1806     if (!(patchW = strdupAtoW( patch )))
1807         goto done;
1808 
1809     if (!(attrW = strdupAtoW( attr )))
1810         goto done;
1811 
1812     size = 0;
1813     r = MsiGetPatchInfoW( patchW, attrW, NULL, &size );
1814     if (r != ERROR_SUCCESS)
1815         goto done;
1816 
1817     size++;
1818     if (!(bufferW = malloc( size * sizeof(WCHAR) )))
1819     {
1820         r = ERROR_OUTOFMEMORY;
1821         goto done;
1822     }
1823 
1824     r = MsiGetPatchInfoW( patchW, attrW, bufferW, &size );
1825     if (r == ERROR_SUCCESS)
1826     {
1827         int len = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
1828         if (len > *buflen)
1829             r = ERROR_MORE_DATA;
1830         else if (buffer)
1831             WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, *buflen, NULL, NULL );
1832 
1833         *buflen = len - 1;
1834     }
1835 
1836 done:
1837     free( patchW );
1838     free( attrW );
1839     free( bufferW );
1840     return r;
1841 }
1842 
MsiGetPatchInfoW(LPCWSTR patch,LPCWSTR attr,LPWSTR buffer,LPDWORD buflen)1843 UINT WINAPI MsiGetPatchInfoW( LPCWSTR patch, LPCWSTR attr, LPWSTR buffer, LPDWORD buflen )
1844 {
1845     UINT r;
1846     WCHAR product[GUID_SIZE];
1847     DWORD index;
1848 
1849     TRACE("%s %s %p %p\n", debugstr_w(patch), debugstr_w(attr), buffer, buflen);
1850 
1851     if (!patch || !attr)
1852         return ERROR_INVALID_PARAMETER;
1853 
1854     if (wcscmp( INSTALLPROPERTY_LOCALPACKAGEW, attr ))
1855         return ERROR_UNKNOWN_PROPERTY;
1856 
1857     index = 0;
1858     while (1)
1859     {
1860         r = MsiEnumProductsW( index, product );
1861         if (r != ERROR_SUCCESS)
1862             break;
1863 
1864         r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_USERMANAGED, attr, buffer, buflen );
1865         if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA)
1866             return r;
1867 
1868         r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, attr, buffer, buflen );
1869         if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA)
1870             return r;
1871 
1872         r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_MACHINE, attr, buffer, buflen );
1873         if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA)
1874             return r;
1875 
1876         index++;
1877     }
1878 
1879     return ERROR_UNKNOWN_PRODUCT;
1880 }
1881 
MsiEnableLogA(DWORD dwLogMode,const char * szLogFile,DWORD attributes)1882 UINT WINAPI MsiEnableLogA( DWORD dwLogMode, const char *szLogFile, DWORD attributes )
1883 {
1884     LPWSTR szwLogFile = NULL;
1885     UINT r;
1886 
1887     TRACE( "%#lx, %s, %#lx\n", dwLogMode, debugstr_a(szLogFile), attributes );
1888 
1889     if( szLogFile )
1890     {
1891         szwLogFile = strdupAtoW( szLogFile );
1892         if( !szwLogFile )
1893             return ERROR_OUTOFMEMORY;
1894     }
1895     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
1896     free( szwLogFile );
1897     return r;
1898 }
1899 
MsiEnableLogW(DWORD dwLogMode,const WCHAR * szLogFile,DWORD attributes)1900 UINT WINAPI MsiEnableLogW( DWORD dwLogMode, const WCHAR *szLogFile, DWORD attributes )
1901 {
1902     TRACE( "%#lx, %s, %#lx\n", dwLogMode, debugstr_w(szLogFile), attributes );
1903 
1904     free(gszLogFile);
1905     gszLogFile = NULL;
1906     if (szLogFile)
1907     {
1908         HANDLE file;
1909 
1910         if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
1911             DeleteFileW(szLogFile);
1912         file = CreateFileW(szLogFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
1913                            FILE_ATTRIBUTE_NORMAL, NULL);
1914         if (file != INVALID_HANDLE_VALUE)
1915         {
1916             gszLogFile = wcsdup(szLogFile);
1917             CloseHandle(file);
1918         }
1919         else ERR( "unable to enable log %s (%lu)\n", debugstr_w(szLogFile), GetLastError() );
1920     }
1921 
1922     return ERROR_SUCCESS;
1923 }
1924 
MsiEnumComponentCostsA(MSIHANDLE handle,const char * component,DWORD index,INSTALLSTATE state,char * drive,DWORD * buflen,int * cost,int * temp)1925 UINT WINAPI MsiEnumComponentCostsA( MSIHANDLE handle, const char *component, DWORD index, INSTALLSTATE state,
1926                                     char *drive, DWORD *buflen, int *cost, int *temp )
1927 {
1928     UINT r;
1929     DWORD len;
1930     WCHAR *driveW, *componentW = NULL;
1931 
1932     TRACE( "%lu, %s, %lu, %d, %p, %p, %p, %p\n", handle, debugstr_a(component), index, state, drive, buflen, cost,
1933            temp );
1934 
1935     if (!drive || !buflen) return ERROR_INVALID_PARAMETER;
1936     if (component && !(componentW = strdupAtoW( component ))) return ERROR_OUTOFMEMORY;
1937 
1938     len = *buflen;
1939     if (!(driveW = malloc( len * sizeof(WCHAR) )))
1940     {
1941         free( componentW );
1942         return ERROR_OUTOFMEMORY;
1943     }
1944     r = MsiEnumComponentCostsW( handle, componentW, index, state, driveW, buflen, cost, temp );
1945     if (!r)
1946     {
1947         WideCharToMultiByte( CP_ACP, 0, driveW, -1, drive, len, NULL, NULL );
1948     }
1949     free( componentW );
1950     free( driveW );
1951     return r;
1952 }
1953 
set_drive(WCHAR * buffer,WCHAR letter)1954 static UINT set_drive( WCHAR *buffer, WCHAR letter )
1955 {
1956     buffer[0] = letter;
1957     buffer[1] = ':';
1958     buffer[2] = 0;
1959     return 2;
1960 }
1961 
MsiEnumComponentCostsW(MSIHANDLE handle,const WCHAR * component,DWORD index,INSTALLSTATE state,WCHAR * drive,DWORD * buflen,int * cost,int * temp)1962 UINT WINAPI MsiEnumComponentCostsW( MSIHANDLE handle, const WCHAR *component, DWORD index, INSTALLSTATE state,
1963                                     WCHAR *drive, DWORD *buflen, int *cost, int *temp )
1964 {
1965     UINT r = ERROR_NO_MORE_ITEMS;
1966     MSICOMPONENT *comp = NULL;
1967     MSIPACKAGE *package;
1968     MSIFILE *file;
1969     STATSTG stat = {0};
1970     WCHAR path[MAX_PATH];
1971 
1972     TRACE( "%lu, %s, %lu, %d, %p, %p, %p, %p\n", handle, debugstr_w(component), index, state, drive, buflen, cost,
1973            temp );
1974 
1975     if (!drive || !buflen || !cost || !temp) return ERROR_INVALID_PARAMETER;
1976     if (!(package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE )))
1977     {
1978         WCHAR buffer[3];
1979         MSIHANDLE remote;
1980 
1981         if (!(remote = msi_get_remote(handle)))
1982             return ERROR_INVALID_HANDLE;
1983 
1984         __TRY
1985         {
1986             r = remote_EnumComponentCosts(remote, component, index, state, buffer, cost, temp);
1987         }
1988         __EXCEPT(rpc_filter)
1989         {
1990             r = GetExceptionCode();
1991         }
1992         __ENDTRY
1993 
1994         if (r == ERROR_SUCCESS)
1995         {
1996             lstrcpynW(drive, buffer, *buflen);
1997             if (*buflen < 3)
1998                 r = ERROR_MORE_DATA;
1999             *buflen = 2;
2000         }
2001         return r;
2002     }
2003 
2004     if (!msi_get_property_int( package->db, L"CostingComplete", 0 ))
2005     {
2006         msiobj_release( &package->hdr );
2007         return ERROR_FUNCTION_NOT_CALLED;
2008     }
2009     if (component && component[0] && !(comp = msi_get_loaded_component( package, component )))
2010     {
2011         msiobj_release( &package->hdr );
2012         return ERROR_UNKNOWN_COMPONENT;
2013     }
2014     if (*buflen < 3)
2015     {
2016         *buflen = 2;
2017         msiobj_release( &package->hdr );
2018         return ERROR_MORE_DATA;
2019     }
2020     if (index)
2021     {
2022         msiobj_release( &package->hdr );
2023         return ERROR_NO_MORE_ITEMS;
2024     }
2025 
2026     drive[0] = 0;
2027     *cost = *temp = 0;
2028     GetWindowsDirectoryW( path, MAX_PATH );
2029     if (component && component[0])
2030     {
2031         if (msi_is_global_assembly( comp )) *temp = comp->cost;
2032         if (!comp->Enabled || !comp->KeyPath)
2033         {
2034             *cost = 0;
2035             *buflen = set_drive( drive, path[0] );
2036             r = ERROR_SUCCESS;
2037         }
2038         else if ((file = msi_get_loaded_file( package, comp->KeyPath )))
2039         {
2040             *cost = comp->cost;
2041             *buflen = set_drive( drive, file->TargetPath[0] );
2042             r = ERROR_SUCCESS;
2043         }
2044     }
2045     else if (IStorage_Stat( package->db->storage, &stat, STATFLAG_NONAME ) == S_OK)
2046     {
2047         *temp = cost_from_size( stat.cbSize.QuadPart );
2048         *buflen = set_drive( drive, path[0] );
2049         r = ERROR_SUCCESS;
2050     }
2051     msiobj_release( &package->hdr );
2052     return r;
2053 }
2054 
MsiQueryComponentStateA(LPCSTR szProductCode,LPCSTR szUserSid,MSIINSTALLCONTEXT dwContext,LPCSTR szComponent,INSTALLSTATE * pdwState)2055 UINT WINAPI MsiQueryComponentStateA(LPCSTR szProductCode,
2056                                     LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
2057                                     LPCSTR szComponent, INSTALLSTATE *pdwState)
2058 {
2059     LPWSTR prodcode = NULL, usersid = NULL, comp = NULL;
2060     UINT r;
2061 
2062     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_a(szProductCode),
2063           debugstr_a(szUserSid), dwContext, debugstr_a(szComponent), pdwState);
2064 
2065     if (szProductCode && !(prodcode = strdupAtoW(szProductCode)))
2066         return ERROR_OUTOFMEMORY;
2067 
2068     if (szUserSid && !(usersid = strdupAtoW(szUserSid)))
2069             return ERROR_OUTOFMEMORY;
2070 
2071     if (szComponent && !(comp = strdupAtoW(szComponent)))
2072             return ERROR_OUTOFMEMORY;
2073 
2074     r = MsiQueryComponentStateW(prodcode, usersid, dwContext, comp, pdwState);
2075 
2076     free(prodcode);
2077     free(usersid);
2078     free(comp);
2079 
2080     return r;
2081 }
2082 
comp_find_prod_key(const WCHAR * prodcode,MSIINSTALLCONTEXT context)2083 static BOOL comp_find_prod_key(const WCHAR *prodcode, MSIINSTALLCONTEXT context)
2084 {
2085     UINT r;
2086     HKEY hkey = NULL;
2087 
2088     r = MSIREG_OpenProductKey(prodcode, NULL, context, &hkey, FALSE);
2089     RegCloseKey(hkey);
2090     return (r == ERROR_SUCCESS);
2091 }
2092 
comp_find_package(const WCHAR * prodcode,MSIINSTALLCONTEXT context)2093 static BOOL comp_find_package(const WCHAR *prodcode, MSIINSTALLCONTEXT context)
2094 {
2095     LPCWSTR package;
2096     HKEY hkey;
2097     DWORD sz;
2098     LONG res;
2099     UINT r;
2100 
2101     r = MSIREG_OpenInstallProps(prodcode, context, NULL, &hkey, FALSE);
2102     if (r != ERROR_SUCCESS)
2103         return FALSE;
2104 
2105     if (context == MSIINSTALLCONTEXT_USERMANAGED)
2106         package = L"ManagedLocalPackage";
2107     else
2108         package = L"LocalPackage";
2109 
2110     sz = 0;
2111     res = RegQueryValueExW(hkey, package, NULL, NULL, NULL, &sz);
2112     RegCloseKey(hkey);
2113 
2114     return (res == ERROR_SUCCESS);
2115 }
2116 
comp_find_prodcode(const WCHAR * squashed_pc,MSIINSTALLCONTEXT context,const WCHAR * comp,WCHAR * val,DWORD * sz)2117 static UINT comp_find_prodcode(const WCHAR *squashed_pc, MSIINSTALLCONTEXT context, const WCHAR *comp, WCHAR *val,
2118                                DWORD *sz)
2119 {
2120     HKEY hkey;
2121     LONG res;
2122     UINT r;
2123 
2124     if (context == MSIINSTALLCONTEXT_MACHINE)
2125         r = MSIREG_OpenUserDataComponentKey(comp, L"S-1-5-18", &hkey, FALSE);
2126     else
2127         r = MSIREG_OpenUserDataComponentKey(comp, NULL, &hkey, FALSE);
2128 
2129     if (r != ERROR_SUCCESS)
2130         return r;
2131 
2132     res = RegQueryValueExW( hkey, squashed_pc, NULL, NULL, (BYTE *)val, sz );
2133     if (res != ERROR_SUCCESS)
2134         return res;
2135 
2136     RegCloseKey(hkey);
2137     return res;
2138 }
2139 
MsiQueryComponentStateW(LPCWSTR szProductCode,LPCWSTR szUserSid,MSIINSTALLCONTEXT dwContext,LPCWSTR szComponent,INSTALLSTATE * pdwState)2140 UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode,
2141                                     LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
2142                                     LPCWSTR szComponent, INSTALLSTATE *pdwState)
2143 {
2144     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
2145     BOOL found;
2146     DWORD sz;
2147 
2148     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_w(szProductCode),
2149           debugstr_w(szUserSid), dwContext, debugstr_w(szComponent), pdwState);
2150 
2151     if (!pdwState || !szComponent)
2152         return ERROR_INVALID_PARAMETER;
2153 
2154     if (!szProductCode || !*szProductCode || lstrlenW(szProductCode) != GUID_SIZE - 1)
2155         return ERROR_INVALID_PARAMETER;
2156 
2157     if (!squash_guid( szProductCode, squashed_pc ))
2158         return ERROR_INVALID_PARAMETER;
2159 
2160     found = comp_find_prod_key(szProductCode, dwContext);
2161 
2162     if (!comp_find_package(szProductCode, dwContext))
2163     {
2164         if (found)
2165         {
2166             *pdwState = INSTALLSTATE_UNKNOWN;
2167             return ERROR_UNKNOWN_COMPONENT;
2168         }
2169 
2170         return ERROR_UNKNOWN_PRODUCT;
2171     }
2172 
2173     *pdwState = INSTALLSTATE_UNKNOWN;
2174 
2175     sz = 0;
2176     if (comp_find_prodcode( squashed_pc, dwContext, szComponent, NULL, &sz ))
2177         return ERROR_UNKNOWN_COMPONENT;
2178 
2179     if (sz == 0)
2180         *pdwState = INSTALLSTATE_NOTUSED;
2181     else
2182     {
2183         WCHAR *val;
2184         UINT r;
2185 
2186         if (!(val = malloc( sz ))) return ERROR_OUTOFMEMORY;
2187         if ((r = comp_find_prodcode( squashed_pc, dwContext, szComponent, val, &sz )))
2188         {
2189             free(val);
2190             return r;
2191         }
2192 
2193         if (lstrlenW(val) > 2 &&
2194             val[0] >= '0' && val[0] <= '9' && val[1] >= '0' && val[1] <= '9' && val[2] != ':')
2195         {
2196             *pdwState = INSTALLSTATE_SOURCE;
2197         }
2198         else
2199             *pdwState = INSTALLSTATE_LOCAL;
2200         free( val );
2201     }
2202 
2203     TRACE("-> %d\n", *pdwState);
2204     return ERROR_SUCCESS;
2205 }
2206 
MsiQueryProductStateA(LPCSTR szProduct)2207 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
2208 {
2209     LPWSTR szwProduct = NULL;
2210     INSTALLSTATE r;
2211 
2212     if( szProduct )
2213     {
2214          szwProduct = strdupAtoW( szProduct );
2215          if( !szwProduct )
2216              return ERROR_OUTOFMEMORY;
2217     }
2218     r = MsiQueryProductStateW( szwProduct );
2219     free( szwProduct );
2220     return r;
2221 }
2222 
MsiQueryProductStateW(LPCWSTR szProduct)2223 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
2224 {
2225     MSIINSTALLCONTEXT context = MSIINSTALLCONTEXT_USERUNMANAGED;
2226     INSTALLSTATE state = INSTALLSTATE_ADVERTISED;
2227     HKEY prodkey = 0, userdata = 0;
2228     DWORD val;
2229     UINT r;
2230 
2231     TRACE("%s\n", debugstr_w(szProduct));
2232 
2233     if (!szProduct || !*szProduct)
2234         return INSTALLSTATE_INVALIDARG;
2235 
2236     if (lstrlenW(szProduct) != GUID_SIZE - 1)
2237         return INSTALLSTATE_INVALIDARG;
2238 
2239     if (szProduct[0] != '{' || szProduct[37] != '}')
2240         return INSTALLSTATE_UNKNOWN;
2241 
2242     SetLastError( ERROR_SUCCESS );
2243 
2244     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2245                               &prodkey, FALSE) != ERROR_SUCCESS &&
2246         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2247                               &prodkey, FALSE) != ERROR_SUCCESS &&
2248         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2249                               &prodkey, FALSE) == ERROR_SUCCESS)
2250     {
2251         context = MSIINSTALLCONTEXT_MACHINE;
2252     }
2253 
2254     r = MSIREG_OpenInstallProps(szProduct, context, NULL, &userdata, FALSE);
2255     if (r != ERROR_SUCCESS)
2256         goto done;
2257 
2258     if (!msi_reg_get_val_dword(userdata, L"WindowsInstaller", &val))
2259         goto done;
2260 
2261     if (val)
2262         state = INSTALLSTATE_DEFAULT;
2263     else
2264         state = INSTALLSTATE_UNKNOWN;
2265 
2266 done:
2267     if (!prodkey)
2268     {
2269         state = INSTALLSTATE_UNKNOWN;
2270 
2271         if (userdata)
2272             state = INSTALLSTATE_ABSENT;
2273     }
2274 
2275     RegCloseKey(prodkey);
2276     RegCloseKey(userdata);
2277     TRACE("-> %d\n", state);
2278     return state;
2279 }
2280 
MsiSetInternalUI(INSTALLUILEVEL dwUILevel,HWND * phWnd)2281 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
2282 {
2283     INSTALLUILEVEL old = gUILevel;
2284     HWND oldwnd = gUIhwnd;
2285 
2286     TRACE("%08x %p\n", dwUILevel, phWnd);
2287 
2288     if (dwUILevel & ~(INSTALLUILEVEL_MASK|INSTALLUILEVEL_HIDECANCEL|INSTALLUILEVEL_PROGRESSONLY|
2289                       INSTALLUILEVEL_ENDDIALOG|INSTALLUILEVEL_SOURCERESONLY))
2290     {
2291         FIXME("Unrecognized flags %08x\n", dwUILevel);
2292         return INSTALLUILEVEL_NOCHANGE;
2293     }
2294 
2295     if (dwUILevel != INSTALLUILEVEL_NOCHANGE)
2296         gUILevel = dwUILevel;
2297 
2298     if (phWnd)
2299     {
2300         gUIhwnd = *phWnd;
2301         *phWnd = oldwnd;
2302     }
2303     return old;
2304 }
2305 
MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,DWORD dwMessageFilter,void * pvContext)2306 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA( INSTALLUI_HANDLERA puiHandler, DWORD dwMessageFilter, void *pvContext )
2307 {
2308     INSTALLUI_HANDLERA prev = gUIHandlerA;
2309 
2310     TRACE( "%p, %#lx, %p\n", puiHandler, dwMessageFilter, pvContext );
2311 
2312     gUIHandlerA = puiHandler;
2313     gUIHandlerW = NULL;
2314     gUIFilter   = dwMessageFilter;
2315     gUIContext  = pvContext;
2316 
2317     return prev;
2318 }
2319 
MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,DWORD dwMessageFilter,void * pvContext)2320 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW( INSTALLUI_HANDLERW puiHandler, DWORD dwMessageFilter, void *pvContext )
2321 {
2322     INSTALLUI_HANDLERW prev = gUIHandlerW;
2323 
2324     TRACE( "%p, %#lx, %p\n", puiHandler, dwMessageFilter, pvContext );
2325 
2326     gUIHandlerA = NULL;
2327     gUIHandlerW = puiHandler;
2328     gUIFilter   = dwMessageFilter;
2329     gUIContext  = pvContext;
2330 
2331     return prev;
2332 }
2333 
2334 /******************************************************************
2335  *  MsiLoadStringW            [MSI.@]
2336  *
2337  * Loads a string from MSI's string resources.
2338  *
2339  * PARAMS
2340  *
2341  *   handle        [I]  only -1 is handled currently
2342  *   id            [I]  id of the string to be loaded
2343  *   lpBuffer      [O]  buffer for the string to be written to
2344  *   nBufferMax    [I]  maximum size of the buffer in characters
2345  *   lang          [I]  the preferred language for the string
2346  *
2347  * RETURNS
2348  *
2349  *   If successful, this function returns the language id of the string loaded
2350  *   If the function fails, the function returns zero.
2351  *
2352  * NOTES
2353  *
2354  *   The type of the first parameter is unknown.  LoadString's prototype
2355  *  suggests that it might be a module handle.  I have made it an MSI handle
2356  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
2357  *  handle.  Maybe strings can be stored in an MSI database somehow.
2358  */
MsiLoadStringW(MSIHANDLE handle,UINT id,WCHAR * lpBuffer,int nBufferMax,LANGID lang)2359 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, WCHAR *lpBuffer, int nBufferMax, LANGID lang )
2360 {
2361     HRSRC hres;
2362     HGLOBAL hResData;
2363     LPWSTR p;
2364     DWORD i, len;
2365 
2366     TRACE( "%lu, %u, %p, %d, %#x\n", handle, id, lpBuffer, nBufferMax, lang );
2367 
2368     if( handle != -1 )
2369         FIXME( "don't know how to deal with handle = %lu\n", handle );
2370 
2371     if( !lang )
2372         lang = GetUserDefaultLangID();
2373 
2374     hres = FindResourceExW( msi_hInstance, (const WCHAR *)RT_STRING, (WCHAR *)1, lang );
2375     if( !hres )
2376         return 0;
2377     hResData = LoadResource( msi_hInstance, hres );
2378     if( !hResData )
2379         return 0;
2380     p = LockResource( hResData );
2381     if( !p )
2382         return 0;
2383 
2384     for (i = 0; i < (id & 0xf); i++) p += *p + 1;
2385     len = *p;
2386 
2387     if( nBufferMax <= len )
2388         return 0;
2389 
2390     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
2391     lpBuffer[ len ] = 0;
2392 
2393     TRACE("found -> %s\n", debugstr_w(lpBuffer));
2394     return lang;
2395 }
2396 
MsiLoadStringA(MSIHANDLE handle,UINT id,LPSTR lpBuffer,int nBufferMax,LANGID lang)2397 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
2398                 int nBufferMax, LANGID lang )
2399 {
2400     LPWSTR bufW;
2401     LANGID r;
2402     INT len;
2403 
2404     bufW = malloc(nBufferMax * sizeof(WCHAR));
2405     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
2406     if( r )
2407     {
2408         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
2409         if( len <= nBufferMax )
2410             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
2411                                  lpBuffer, nBufferMax, NULL, NULL );
2412         else
2413             r = 0;
2414     }
2415     free(bufW);
2416     return r;
2417 }
2418 
MsiLocateComponentA(LPCSTR szComponent,LPSTR lpPathBuf,LPDWORD pcchBuf)2419 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
2420                 LPDWORD pcchBuf)
2421 {
2422     char szProduct[GUID_SIZE];
2423 
2424     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
2425 
2426     if (!szComponent || !pcchBuf)
2427         return INSTALLSTATE_INVALIDARG;
2428 
2429     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
2430         return INSTALLSTATE_UNKNOWN;
2431 
2432     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
2433 }
2434 
MsiLocateComponentW(LPCWSTR szComponent,LPWSTR lpPathBuf,LPDWORD pcchBuf)2435 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
2436                 LPDWORD pcchBuf)
2437 {
2438     WCHAR szProduct[GUID_SIZE];
2439 
2440     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
2441 
2442     if (!szComponent || !pcchBuf)
2443         return INSTALLSTATE_INVALIDARG;
2444 
2445     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
2446         return INSTALLSTATE_UNKNOWN;
2447 
2448     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
2449 }
2450 
MsiMessageBoxA(HWND hWnd,const char * lpText,const char * lpCaption,UINT uType,WORD wLanguageId,DWORD f)2451 UINT WINAPI MsiMessageBoxA( HWND hWnd, const char *lpText, const char *lpCaption, UINT uType, WORD wLanguageId,
2452                             DWORD f )
2453 {
2454     FIXME( "%p, %s, %s, %u, %#x, %#lx\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption), uType, wLanguageId, f );
2455     return MessageBoxExA( hWnd, lpText, lpCaption, uType, wLanguageId );
2456 }
2457 
MsiMessageBoxW(HWND hWnd,const WCHAR * lpText,const WCHAR * lpCaption,UINT uType,WORD wLanguageId,DWORD f)2458 UINT WINAPI MsiMessageBoxW( HWND hWnd, const WCHAR *lpText, const WCHAR *lpCaption, UINT uType, WORD wLanguageId,
2459                             DWORD f )
2460 {
2461     FIXME( "%p, %s, %s, %u, %#x %#lx\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption), uType, wLanguageId, f );
2462     return MessageBoxExW( hWnd, lpText, lpCaption, uType, wLanguageId );
2463 }
2464 
MsiMessageBoxExA(HWND hWnd,const char * lpText,const char * lpCaption,UINT uType,DWORD unknown,WORD wLanguageId,DWORD f)2465 UINT WINAPI MsiMessageBoxExA( HWND hWnd, const char *lpText, const char *lpCaption, UINT uType, DWORD unknown,
2466                               WORD wLanguageId, DWORD f )
2467 {
2468     FIXME( "%p, %s, %s, %u, %#lx, %#x, %#lx): semi-stub\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption), uType,
2469            unknown, wLanguageId, f );
2470     return MessageBoxExA( hWnd, lpText, lpCaption, uType, wLanguageId );
2471 }
2472 
MsiMessageBoxExW(HWND hWnd,const WCHAR * lpText,const WCHAR * lpCaption,UINT uType,DWORD unknown,WORD wLanguageId,DWORD f)2473 UINT WINAPI MsiMessageBoxExW( HWND hWnd, const WCHAR *lpText, const WCHAR *lpCaption, UINT uType, DWORD unknown,
2474                               WORD wLanguageId, DWORD f )
2475 {
2476     FIXME( "%p, %s, %s, %u, %#lx, %#x, %#lx): semi-stub\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption), uType,
2477            unknown, wLanguageId, f );
2478     return MessageBoxExW( hWnd, lpText, lpCaption, uType, wLanguageId );
2479 }
2480 
MsiProvideAssemblyA(const char * szAssemblyName,const char * szAppContext,DWORD dwInstallMode,DWORD dwAssemblyInfo,char * lpPathBuf,DWORD * pcchPathBuf)2481 UINT WINAPI MsiProvideAssemblyA( const char *szAssemblyName, const char *szAppContext, DWORD dwInstallMode,
2482                                  DWORD dwAssemblyInfo, char *lpPathBuf, DWORD *pcchPathBuf )
2483 {
2484     FIXME( "%s, %s, %#lx, %#lx, %p, %p\n", debugstr_a(szAssemblyName), debugstr_a(szAppContext), dwInstallMode,
2485            dwAssemblyInfo, lpPathBuf, pcchPathBuf );
2486     return ERROR_CALL_NOT_IMPLEMENTED;
2487 }
2488 
MsiProvideAssemblyW(const WCHAR * szAssemblyName,const WCHAR * szAppContext,DWORD dwInstallMode,DWORD dwAssemblyInfo,WCHAR * lpPathBuf,DWORD * pcchPathBuf)2489 UINT WINAPI MsiProvideAssemblyW( const WCHAR *szAssemblyName, const WCHAR *szAppContext, DWORD dwInstallMode,
2490                                  DWORD dwAssemblyInfo, WCHAR *lpPathBuf, DWORD *pcchPathBuf )
2491 {
2492     FIXME( "%s, %s, %#lx, %#lx, %p, %p\n", debugstr_w(szAssemblyName), debugstr_w(szAppContext), dwInstallMode,
2493            dwAssemblyInfo, lpPathBuf, pcchPathBuf );
2494     return ERROR_CALL_NOT_IMPLEMENTED;
2495 }
2496 
MsiProvideComponentFromDescriptorA(LPCSTR szDescriptor,LPSTR szPath,LPDWORD pcchPath,LPDWORD pcchArgs)2497 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
2498                 LPSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2499 {
2500     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
2501     return ERROR_CALL_NOT_IMPLEMENTED;
2502 }
2503 
MsiProvideComponentFromDescriptorW(LPCWSTR szDescriptor,LPWSTR szPath,LPDWORD pcchPath,LPDWORD pcchArgs)2504 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
2505                 LPWSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2506 {
2507     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
2508     return ERROR_CALL_NOT_IMPLEMENTED;
2509 }
2510 
MsiGetFileSignatureInformationA(const char * path,DWORD flags,PCCERT_CONTEXT * cert,BYTE * hash,DWORD * hashlen)2511 HRESULT WINAPI MsiGetFileSignatureInformationA( const char *path, DWORD flags, PCCERT_CONTEXT *cert, BYTE *hash,
2512                                                 DWORD *hashlen )
2513 {
2514     UINT r;
2515     WCHAR *pathW = NULL;
2516 
2517     TRACE( "%s, %#lx, %p, %p, %p\n", debugstr_a(path), flags, cert, hash, hashlen );
2518 
2519     if (path && !(pathW = strdupAtoW( path ))) return E_OUTOFMEMORY;
2520     r = MsiGetFileSignatureInformationW( pathW, flags, cert, hash, hashlen );
2521     free( pathW );
2522     return r;
2523 }
2524 
MsiGetFileSignatureInformationW(const WCHAR * path,DWORD flags,PCCERT_CONTEXT * cert,BYTE * hash,DWORD * hashlen)2525 HRESULT WINAPI MsiGetFileSignatureInformationW( const WCHAR *path, DWORD flags, PCCERT_CONTEXT *cert, BYTE *hash,
2526                                                 DWORD *hashlen )
2527 {
2528     static GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
2529     HRESULT hr;
2530     WINTRUST_DATA data;
2531     WINTRUST_FILE_INFO info;
2532     CRYPT_PROVIDER_SGNR *signer;
2533     CRYPT_PROVIDER_CERT *provider;
2534 
2535     TRACE( "%s, %#lx, %p, %p, %p\n", debugstr_w(path), flags, cert, hash, hashlen );
2536 
2537     if (!path || !cert) return E_INVALIDARG;
2538 
2539     info.cbStruct       = sizeof(info);
2540     info.pcwszFilePath  = path;
2541     info.hFile          = NULL;
2542     info.pgKnownSubject = NULL;
2543 
2544     memset( &data, 0, sizeof(data) );
2545     data.cbStruct            = sizeof(data);
2546     data.dwUIChoice          = WTD_UI_NONE;
2547     data.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
2548     data.dwUnionChoice       = WTD_CHOICE_FILE;
2549     data.pFile               = &info;
2550     data.dwStateAction       = WTD_STATEACTION_VERIFY;
2551     data.dwUIContext         = WTD_UICONTEXT_INSTALL;
2552 
2553     hr = WinVerifyTrustEx( INVALID_HANDLE_VALUE, &generic_verify_v2, &data );
2554     *cert = NULL;
2555     if (FAILED(hr)) goto done;
2556 
2557     if (!(signer = WTHelperGetProvSignerFromChain( data.hWVTStateData, 0, FALSE, 0 )))
2558     {
2559         hr = TRUST_E_NOSIGNATURE;
2560         goto done;
2561     }
2562     if (hash)
2563     {
2564         DWORD len = signer->psSigner->EncryptedHash.cbData;
2565         if (*hashlen < len)
2566         {
2567             *hashlen = len;
2568             hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
2569             goto done;
2570         }
2571         memcpy( hash, signer->psSigner->EncryptedHash.pbData, len );
2572         *hashlen = len;
2573     }
2574     if (!(provider = WTHelperGetProvCertFromChain( signer, 0 )))
2575     {
2576         hr = TRUST_E_PROVIDER_UNKNOWN;
2577         goto done;
2578     }
2579     *cert = CertDuplicateCertificateContext( provider->pCert );
2580 
2581 done:
2582     data.dwStateAction = WTD_STATEACTION_CLOSE;
2583     WinVerifyTrustEx( INVALID_HANDLE_VALUE, &generic_verify_v2, &data );
2584     return hr;
2585 }
2586 
2587 /******************************************************************
2588  * MsiGetProductPropertyA      [MSI.@]
2589  */
MsiGetProductPropertyA(MSIHANDLE hProduct,const char * szProperty,char * szValue,DWORD * pccbValue)2590 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, const char *szProperty, char *szValue, DWORD *pccbValue )
2591 {
2592     LPWSTR prop = NULL, val = NULL;
2593     DWORD len;
2594     UINT r;
2595 
2596     TRACE( "%lu, %s, %p, %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue );
2597 
2598     if (szValue && !pccbValue)
2599         return ERROR_INVALID_PARAMETER;
2600 
2601     if (szProperty) prop = strdupAtoW(szProperty);
2602 
2603     len = 0;
2604     r = MsiGetProductPropertyW(hProduct, prop, NULL, &len);
2605     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2606         goto done;
2607 
2608     if (r == ERROR_SUCCESS)
2609     {
2610         if (szValue) *szValue = '\0';
2611         if (pccbValue) *pccbValue = 0;
2612         goto done;
2613     }
2614 
2615     val = malloc(++len * sizeof(WCHAR));
2616     if (!val)
2617     {
2618         r = ERROR_OUTOFMEMORY;
2619         goto done;
2620     }
2621 
2622     r = MsiGetProductPropertyW(hProduct, prop, val, &len);
2623     if (r != ERROR_SUCCESS)
2624         goto done;
2625 
2626     len = WideCharToMultiByte(CP_ACP, 0, val, -1, NULL, 0, NULL, NULL);
2627 
2628     if (szValue)
2629         WideCharToMultiByte(CP_ACP, 0, val, -1, szValue,
2630                             *pccbValue, NULL, NULL);
2631 
2632     if (pccbValue)
2633     {
2634         if (len > *pccbValue)
2635             r = ERROR_MORE_DATA;
2636 
2637         *pccbValue = len - 1;
2638     }
2639 
2640 done:
2641     free(prop);
2642     free(val);
2643 
2644     return r;
2645 }
2646 
2647 /******************************************************************
2648  * MsiGetProductPropertyW      [MSI.@]
2649  */
MsiGetProductPropertyW(MSIHANDLE hProduct,const WCHAR * szProperty,WCHAR * szValue,DWORD * pccbValue)2650 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, const WCHAR *szProperty, WCHAR *szValue, DWORD *pccbValue )
2651 {
2652     MSIPACKAGE *package;
2653     MSIQUERY *view = NULL;
2654     MSIRECORD *rec = NULL;
2655     LPCWSTR val;
2656     UINT r;
2657 
2658     TRACE( "%lu, %s, %p, %p)\n", hProduct, debugstr_w(szProperty), szValue, pccbValue );
2659 
2660     if (!szProperty)
2661         return ERROR_INVALID_PARAMETER;
2662 
2663     if (szValue && !pccbValue)
2664         return ERROR_INVALID_PARAMETER;
2665 
2666     package = msihandle2msiinfo(hProduct, MSIHANDLETYPE_PACKAGE);
2667     if (!package)
2668         return ERROR_INVALID_HANDLE;
2669 
2670     r = MSI_OpenQuery(package->db, &view, L"SELECT * FROM `Property` WHERE `Property` = '%s'", szProperty);
2671     if (r != ERROR_SUCCESS)
2672         goto done;
2673 
2674     r = MSI_ViewExecute(view, 0);
2675     if (r != ERROR_SUCCESS)
2676         goto done;
2677 
2678     r = MSI_ViewFetch(view, &rec);
2679     if (r != ERROR_SUCCESS)
2680         goto done;
2681 
2682     val = MSI_RecordGetString(rec, 2);
2683     if (!val)
2684         goto done;
2685 
2686     if (lstrlenW(val) >= *pccbValue)
2687     {
2688         if (szValue) lstrcpynW(szValue, val, *pccbValue);
2689         r = ERROR_MORE_DATA;
2690     }
2691     else
2692     {
2693         if (szValue) lstrcpyW(szValue, val);
2694         r = ERROR_SUCCESS;
2695     }
2696 
2697     *pccbValue = lstrlenW(val);
2698 
2699 done:
2700     if (view)
2701     {
2702         MSI_ViewClose(view);
2703         msiobj_release(&view->hdr);
2704         if (rec) msiobj_release(&rec->hdr);
2705     }
2706 
2707     if (!rec)
2708     {
2709         if (szValue) *szValue = '\0';
2710         if (pccbValue) *pccbValue = 0;
2711         r = ERROR_SUCCESS;
2712     }
2713 
2714     msiobj_release(&package->hdr);
2715     return r;
2716 }
2717 
MsiVerifyPackageA(LPCSTR szPackage)2718 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
2719 {
2720     UINT r;
2721     LPWSTR szPack = NULL;
2722 
2723     TRACE("%s\n", debugstr_a(szPackage) );
2724 
2725     if( szPackage )
2726     {
2727         szPack = strdupAtoW( szPackage );
2728         if( !szPack )
2729             return ERROR_OUTOFMEMORY;
2730     }
2731 
2732     r = MsiVerifyPackageW( szPack );
2733 
2734     free( szPack );
2735 
2736     return r;
2737 }
2738 
MsiVerifyPackageW(LPCWSTR szPackage)2739 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
2740 {
2741     MSIHANDLE handle;
2742     UINT r;
2743 
2744     TRACE("%s\n", debugstr_w(szPackage) );
2745 
2746     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
2747     MsiCloseHandle( handle );
2748 
2749     return r;
2750 }
2751 
open_userdata_comp_key(const WCHAR * comp,const WCHAR * usersid,MSIINSTALLCONTEXT ctx,HKEY * hkey)2752 static BOOL open_userdata_comp_key( const WCHAR *comp, const WCHAR *usersid, MSIINSTALLCONTEXT ctx,
2753                                     HKEY *hkey )
2754 {
2755     if (ctx & MSIINSTALLCONTEXT_MACHINE)
2756     {
2757         if (!MSIREG_OpenUserDataComponentKey( comp, L"S-1-5-18", hkey, FALSE )) return TRUE;
2758     }
2759     if (ctx & (MSIINSTALLCONTEXT_USERMANAGED|MSIINSTALLCONTEXT_USERUNMANAGED))
2760     {
2761         if (usersid && !wcsicmp( usersid, L"S-1-1-0" ))
2762         {
2763             FIXME( "only looking at the current user\n" );
2764             usersid = NULL;
2765         }
2766         if (!MSIREG_OpenUserDataComponentKey( comp, usersid, hkey, FALSE )) return TRUE;
2767     }
2768     return FALSE;
2769 }
2770 
MSI_GetComponentPath(const WCHAR * szProduct,const WCHAR * szComponent,const WCHAR * szUserSid,MSIINSTALLCONTEXT ctx,awstring * lpPathBuf,DWORD * pcchBuf)2771 static INSTALLSTATE MSI_GetComponentPath( const WCHAR *szProduct, const WCHAR *szComponent,
2772                                           const WCHAR *szUserSid, MSIINSTALLCONTEXT ctx,
2773                                           awstring *lpPathBuf, DWORD *pcchBuf )
2774 {
2775     WCHAR *path = NULL, squashed_pc[SQUASHED_GUID_SIZE], squashed_comp[SQUASHED_GUID_SIZE];
2776     HKEY hkey;
2777     INSTALLSTATE state;
2778     DWORD version;
2779 
2780     if (!szProduct || !szComponent)
2781         return INSTALLSTATE_INVALIDARG;
2782 
2783     if (lpPathBuf->str.w && !pcchBuf)
2784         return INSTALLSTATE_INVALIDARG;
2785 
2786     if (!squash_guid( szProduct, squashed_pc ) || !squash_guid( szComponent, squashed_comp ))
2787         return INSTALLSTATE_INVALIDARG;
2788 
2789     if (szUserSid && ctx == MSIINSTALLCONTEXT_MACHINE)
2790         return INSTALLSTATE_INVALIDARG;
2791 
2792     state = INSTALLSTATE_UNKNOWN;
2793 
2794     if (open_userdata_comp_key( szComponent, szUserSid, ctx, &hkey ))
2795     {
2796         path = msi_reg_get_val_str( hkey, squashed_pc );
2797         RegCloseKey(hkey);
2798 
2799         state = INSTALLSTATE_ABSENT;
2800 
2801         if ((!MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE, NULL, &hkey, FALSE) ||
2802              !MSIREG_OpenUserDataProductKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED, NULL, &hkey, FALSE)) &&
2803             msi_reg_get_val_dword(hkey, L"WindowsInstaller", &version) &&
2804             GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2805         {
2806             RegCloseKey(hkey);
2807             state = INSTALLSTATE_LOCAL;
2808         }
2809     }
2810 
2811     if (state != INSTALLSTATE_LOCAL &&
2812         (!MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, &hkey, FALSE) ||
2813          !MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE, &hkey, FALSE)))
2814     {
2815         RegCloseKey(hkey);
2816 
2817         if (open_userdata_comp_key( szComponent, szUserSid, ctx, &hkey ))
2818         {
2819             free(path);
2820             path = msi_reg_get_val_str( hkey, squashed_pc );
2821             RegCloseKey(hkey);
2822 
2823             state = INSTALLSTATE_ABSENT;
2824 
2825             if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2826                 state = INSTALLSTATE_LOCAL;
2827         }
2828     }
2829 
2830     if (!path)
2831         return INSTALLSTATE_UNKNOWN;
2832 
2833     if (state == INSTALLSTATE_LOCAL && !*path)
2834         state = INSTALLSTATE_NOTUSED;
2835 
2836     if (msi_strcpy_to_awstring(path, -1, lpPathBuf, pcchBuf) == ERROR_MORE_DATA)
2837         state = INSTALLSTATE_MOREDATA;
2838 
2839     free(path);
2840     return state;
2841 }
2842 
2843 /******************************************************************
2844  * MsiGetComponentPathExW      [MSI.@]
2845  */
MsiGetComponentPathExW(LPCWSTR product,LPCWSTR comp,LPCWSTR usersid,MSIINSTALLCONTEXT ctx,LPWSTR buf,LPDWORD buflen)2846 INSTALLSTATE WINAPI MsiGetComponentPathExW( LPCWSTR product, LPCWSTR comp, LPCWSTR usersid,
2847                                             MSIINSTALLCONTEXT ctx, LPWSTR buf, LPDWORD buflen )
2848 {
2849     awstring path;
2850 
2851     TRACE( "%s %s %s 0x%x %p %p\n", debugstr_w(product), debugstr_w(comp), debugstr_w(usersid),
2852            ctx, buf, buflen );
2853 
2854     path.unicode = TRUE;
2855     path.str.w   = buf;
2856 
2857     return MSI_GetComponentPath( product, comp, usersid, ctx, &path, buflen );
2858 }
2859 
MsiGetComponentPathExA(LPCSTR product,LPCSTR comp,LPCSTR usersid,MSIINSTALLCONTEXT ctx,LPSTR buf,LPDWORD buflen)2860 INSTALLSTATE WINAPI MsiGetComponentPathExA( LPCSTR product, LPCSTR comp, LPCSTR usersid,
2861                                             MSIINSTALLCONTEXT ctx, LPSTR buf, LPDWORD buflen )
2862 {
2863     WCHAR *productW = NULL, *compW = NULL, *usersidW =  NULL;
2864     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
2865     awstring path;
2866 
2867     TRACE( "%s %s %s 0x%x %p %p\n", debugstr_a(product), debugstr_a(comp), debugstr_a(usersid),
2868            ctx, buf, buflen );
2869 
2870     if (product && !(productW = strdupAtoW( product ))) return INSTALLSTATE_UNKNOWN;
2871     if (comp && !(compW = strdupAtoW( comp ))) goto end;
2872     if (usersid && !(usersidW = strdupAtoW( usersid ))) goto end;
2873 
2874     path.unicode = FALSE;
2875     path.str.a   = buf;
2876 
2877     r = MSI_GetComponentPath( productW, compW, usersidW, ctx, &path, buflen );
2878 
2879 end:
2880     free( productW );
2881     free( compW );
2882     free( usersidW );
2883 
2884     return r;
2885 }
2886 
2887 /******************************************************************
2888  * MsiGetComponentPathW      [MSI.@]
2889  */
MsiGetComponentPathW(LPCWSTR product,LPCWSTR comp,LPWSTR buf,LPDWORD buflen)2890 INSTALLSTATE WINAPI MsiGetComponentPathW( LPCWSTR product, LPCWSTR comp, LPWSTR buf, LPDWORD buflen )
2891 {
2892     return MsiGetComponentPathExW( product, comp, L"S-1-1-0", MSIINSTALLCONTEXT_ALL, buf, buflen );
2893 }
2894 
2895 /******************************************************************
2896  * MsiGetComponentPathA      [MSI.@]
2897  */
MsiGetComponentPathA(LPCSTR product,LPCSTR comp,LPSTR buf,LPDWORD buflen)2898 INSTALLSTATE WINAPI MsiGetComponentPathA( LPCSTR product, LPCSTR comp, LPSTR buf, LPDWORD buflen )
2899 {
2900     return MsiGetComponentPathExA( product, comp, "s-1-1-0", MSIINSTALLCONTEXT_ALL, buf, buflen );
2901 }
2902 
query_feature_state(const WCHAR * product,const WCHAR * squashed,const WCHAR * usersid,MSIINSTALLCONTEXT ctx,const WCHAR * feature,INSTALLSTATE * state)2903 static UINT query_feature_state( const WCHAR *product, const WCHAR *squashed, const WCHAR *usersid,
2904                                  MSIINSTALLCONTEXT ctx, const WCHAR *feature, INSTALLSTATE *state )
2905 {
2906     UINT r;
2907     HKEY hkey;
2908     WCHAR *parent, *components, *path;
2909     const WCHAR *p;
2910     BOOL missing = FALSE, source = FALSE;
2911     WCHAR comp[GUID_SIZE];
2912     GUID guid;
2913 
2914     if (ctx != MSIINSTALLCONTEXT_MACHINE) SetLastError( ERROR_SUCCESS );
2915 
2916     if (MSIREG_OpenFeaturesKey( product, usersid, ctx, &hkey, FALSE )) return ERROR_UNKNOWN_PRODUCT;
2917 
2918     parent = msi_reg_get_val_str( hkey, feature );
2919     RegCloseKey( hkey );
2920     if (!parent) return ERROR_UNKNOWN_FEATURE;
2921 
2922     *state = (parent[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
2923     free( parent );
2924     if (*state == INSTALLSTATE_ABSENT)
2925         return ERROR_SUCCESS;
2926 
2927     r = MSIREG_OpenUserDataFeaturesKey( product, usersid, ctx, &hkey, FALSE );
2928     if (r != ERROR_SUCCESS)
2929     {
2930         *state = INSTALLSTATE_ADVERTISED;
2931         return ERROR_SUCCESS;
2932     }
2933     components = msi_reg_get_val_str( hkey, feature );
2934     RegCloseKey( hkey );
2935 
2936     TRACE("buffer = %s\n", debugstr_w(components));
2937 
2938     if (!components)
2939     {
2940         *state = INSTALLSTATE_ADVERTISED;
2941         return ERROR_SUCCESS;
2942     }
2943     for (p = components; *p && *p != 2 ; p += 20)
2944     {
2945         if (!decode_base85_guid( p, &guid ))
2946         {
2947             if (p != components) break;
2948             free( components );
2949             *state = INSTALLSTATE_BADCONFIG;
2950             return ERROR_BAD_CONFIGURATION;
2951         }
2952         StringFromGUID2( &guid, comp, GUID_SIZE );
2953         if (ctx == MSIINSTALLCONTEXT_MACHINE)
2954             r = MSIREG_OpenUserDataComponentKey( comp, L"S-1-5-18", &hkey, FALSE );
2955         else
2956             r = MSIREG_OpenUserDataComponentKey( comp, usersid, &hkey, FALSE );
2957 
2958         if (r != ERROR_SUCCESS)
2959         {
2960             free( components );
2961             *state = INSTALLSTATE_ADVERTISED;
2962             return ERROR_SUCCESS;
2963         }
2964         path = msi_reg_get_val_str( hkey, squashed );
2965         if (!path) missing = TRUE;
2966         else if (lstrlenW( path ) > 2 &&
2967                  path[0] >= '0' && path[0] <= '9' &&
2968                  path[1] >= '0' && path[1] <= '9')
2969         {
2970             source = TRUE;
2971         }
2972         free( path );
2973     }
2974     free( components );
2975 
2976     if (missing)
2977         *state = INSTALLSTATE_ADVERTISED;
2978     else if (source)
2979         *state = INSTALLSTATE_SOURCE;
2980     else
2981         *state = INSTALLSTATE_LOCAL;
2982 
2983     TRACE("returning state %d\n", *state);
2984     return ERROR_SUCCESS;
2985 }
2986 
MsiQueryFeatureStateExA(LPCSTR product,LPCSTR usersid,MSIINSTALLCONTEXT ctx,LPCSTR feature,INSTALLSTATE * state)2987 UINT WINAPI MsiQueryFeatureStateExA( LPCSTR product, LPCSTR usersid, MSIINSTALLCONTEXT ctx,
2988                                      LPCSTR feature, INSTALLSTATE *state )
2989 {
2990     UINT r;
2991     WCHAR *productW = NULL, *usersidW = NULL, *featureW = NULL;
2992 
2993     if (product && !(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
2994     if (usersid && !(usersidW = strdupAtoW( usersid )))
2995     {
2996         free( productW );
2997         return ERROR_OUTOFMEMORY;
2998     }
2999     if (feature && !(featureW = strdupAtoW( feature )))
3000     {
3001         free( productW );
3002         free( usersidW );
3003         return ERROR_OUTOFMEMORY;
3004     }
3005     r = MsiQueryFeatureStateExW( productW, usersidW, ctx, featureW, state );
3006     free( productW );
3007     free( usersidW );
3008     free( featureW );
3009     return r;
3010 }
3011 
MsiQueryFeatureStateExW(LPCWSTR product,LPCWSTR usersid,MSIINSTALLCONTEXT ctx,LPCWSTR feature,INSTALLSTATE * state)3012 UINT WINAPI MsiQueryFeatureStateExW( LPCWSTR product, LPCWSTR usersid, MSIINSTALLCONTEXT ctx,
3013                                      LPCWSTR feature, INSTALLSTATE *state )
3014 {
3015     WCHAR squashed[33];
3016     if (!squash_guid( product, squashed )) return ERROR_INVALID_PARAMETER;
3017     return query_feature_state( product, squashed, usersid, ctx, feature, state );
3018 }
3019 
3020 /******************************************************************
3021  * MsiQueryFeatureStateA      [MSI.@]
3022  */
MsiQueryFeatureStateA(LPCSTR szProduct,LPCSTR szFeature)3023 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
3024 {
3025     LPWSTR szwProduct = NULL, szwFeature= NULL;
3026     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
3027 
3028     szwProduct = strdupAtoW( szProduct );
3029     if ( szProduct && !szwProduct )
3030         goto end;
3031 
3032     szwFeature = strdupAtoW( szFeature );
3033     if ( szFeature && !szwFeature )
3034         goto end;
3035 
3036     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
3037 
3038 end:
3039     free(szwProduct);
3040     free(szwFeature);
3041 
3042     return rc;
3043 }
3044 
3045 /******************************************************************
3046  * MsiQueryFeatureStateW      [MSI.@]
3047  *
3048  * Checks the state of a feature
3049  *
3050  * PARAMS
3051  *   szProduct     [I]  Product's GUID string
3052  *   szFeature     [I]  Feature's GUID string
3053  *
3054  * RETURNS
3055  *   INSTALLSTATE_LOCAL        Feature is installed and usable
3056  *   INSTALLSTATE_ABSENT       Feature is absent
3057  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
3058  *   INSTALLSTATE_UNKNOWN      An error occurred
3059  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
3060  *
3061  */
MsiQueryFeatureStateW(LPCWSTR szProduct,LPCWSTR szFeature)3062 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
3063 {
3064     UINT r;
3065     INSTALLSTATE state;
3066     WCHAR squashed[33];
3067 
3068     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
3069 
3070     if (!szProduct || !szFeature || !squash_guid( szProduct, squashed ))
3071         return INSTALLSTATE_INVALIDARG;
3072 
3073     r = query_feature_state( szProduct, squashed, NULL, MSIINSTALLCONTEXT_USERMANAGED, szFeature, &state );
3074     if (r == ERROR_SUCCESS || r == ERROR_BAD_CONFIGURATION) return state;
3075 
3076     r = query_feature_state( szProduct, squashed, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, szFeature, &state );
3077     if (r == ERROR_SUCCESS || r == ERROR_BAD_CONFIGURATION) return state;
3078 
3079     r = query_feature_state( szProduct, squashed, NULL, MSIINSTALLCONTEXT_MACHINE, szFeature, &state );
3080     if (r == ERROR_SUCCESS || r == ERROR_BAD_CONFIGURATION) return state;
3081 
3082     return INSTALLSTATE_UNKNOWN;
3083 }
3084 
3085 /******************************************************************
3086  * MsiGetFileVersionA         [MSI.@]
3087  */
MsiGetFileVersionA(LPCSTR szFilePath,LPSTR lpVersionBuf,LPDWORD pcchVersionBuf,LPSTR lpLangBuf,LPDWORD pcchLangBuf)3088 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
3089                 LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf)
3090 {
3091     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
3092     UINT ret = ERROR_OUTOFMEMORY;
3093 
3094     if ((lpVersionBuf && !pcchVersionBuf) ||
3095         (lpLangBuf && !pcchLangBuf))
3096         return ERROR_INVALID_PARAMETER;
3097 
3098     if( szFilePath )
3099     {
3100         szwFilePath = strdupAtoW( szFilePath );
3101         if( !szwFilePath )
3102             goto end;
3103     }
3104 
3105     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
3106     {
3107         lpwVersionBuff = malloc(*pcchVersionBuf * sizeof(WCHAR));
3108         if( !lpwVersionBuff )
3109             goto end;
3110     }
3111 
3112     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
3113     {
3114         lpwLangBuff = malloc(*pcchLangBuf * sizeof(WCHAR));
3115         if( !lpwLangBuff )
3116             goto end;
3117     }
3118 
3119     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
3120                              lpwLangBuff, pcchLangBuf);
3121 
3122     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff )
3123         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
3124                             lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL);
3125     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff )
3126         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
3127                             lpLangBuf, *pcchLangBuf + 1, NULL, NULL);
3128 
3129 end:
3130     free(szwFilePath);
3131     free(lpwVersionBuff);
3132     free(lpwLangBuff);
3133 
3134     return ret;
3135 }
3136 
get_file_version(const WCHAR * path,WCHAR * verbuf,DWORD * verlen,WCHAR * langbuf,DWORD * langlen)3137 static UINT get_file_version( const WCHAR *path, WCHAR *verbuf, DWORD *verlen,
3138                               WCHAR *langbuf, DWORD *langlen )
3139 {
3140     UINT ret = ERROR_MORE_DATA;
3141     UINT len;
3142     DWORD error;
3143     LPVOID version;
3144     VS_FIXEDFILEINFO *ffi;
3145     USHORT *lang;
3146     WCHAR tmp[32];
3147 
3148     if (!(len = GetFileVersionInfoSizeW( path, NULL )))
3149     {
3150         error = GetLastError();
3151         if (error == ERROR_BAD_PATHNAME) return ERROR_FILE_NOT_FOUND;
3152         if (error == ERROR_RESOURCE_DATA_NOT_FOUND) return ERROR_FILE_INVALID;
3153         return error;
3154     }
3155     if (!(version = malloc( len ))) return ERROR_OUTOFMEMORY;
3156     if (!GetFileVersionInfoW( path, 0, len, version ))
3157     {
3158         free( version );
3159         return GetLastError();
3160     }
3161     if (!verbuf && !verlen && !langbuf && !langlen)
3162     {
3163         free( version );
3164         return ERROR_SUCCESS;
3165     }
3166     if (verlen)
3167     {
3168         if (VerQueryValueW( version, L"\\", (LPVOID *)&ffi, &len ) && len > 0)
3169         {
3170             swprintf( tmp, ARRAY_SIZE(tmp), L"%d.%d.%d.%d",
3171                       HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
3172                       HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS) );
3173             if (verbuf) lstrcpynW( verbuf, tmp, *verlen );
3174             len = lstrlenW( tmp );
3175             if (*verlen > len) ret = ERROR_SUCCESS;
3176             *verlen = len;
3177         }
3178         else
3179         {
3180             if (verbuf) *verbuf = 0;
3181             *verlen = 0;
3182         }
3183     }
3184     if (langlen)
3185     {
3186         if (VerQueryValueW( version, L"\\VarFileInfo\\Translation", (LPVOID *)&lang, &len ) && len > 0)
3187         {
3188             swprintf( tmp, ARRAY_SIZE(tmp), L"%d", *lang );
3189             if (langbuf) lstrcpynW( langbuf, tmp, *langlen );
3190             len = lstrlenW( tmp );
3191             if (*langlen > len) ret = ERROR_SUCCESS;
3192             *langlen = len;
3193         }
3194         else
3195         {
3196             if (langbuf) *langbuf = 0;
3197             *langlen = 0;
3198         }
3199     }
3200     free( version );
3201     return ret;
3202 }
3203 
3204 
3205 /******************************************************************
3206  * MsiGetFileVersionW         [MSI.@]
3207  */
MsiGetFileVersionW(const WCHAR * path,WCHAR * verbuf,DWORD * verlen,WCHAR * langbuf,DWORD * langlen)3208 UINT WINAPI MsiGetFileVersionW( const WCHAR *path, WCHAR *verbuf, DWORD *verlen, WCHAR *langbuf, DWORD *langlen )
3209 {
3210     UINT ret;
3211 
3212     TRACE( "%s, %p(%lu), %p(%lu)\n", debugstr_w(path), verbuf, verlen ? *verlen : 0, langbuf, langlen ? *langlen : 0 );
3213 
3214     if ((verbuf && !verlen) || (langbuf && !langlen))
3215         return ERROR_INVALID_PARAMETER;
3216 
3217     ret = get_file_version( path, verbuf, verlen, langbuf, langlen );
3218     if (ret == ERROR_RESOURCE_DATA_NOT_FOUND && verlen)
3219     {
3220         int len;
3221         WCHAR *version = msi_get_font_file_version( NULL, path );
3222         if (!version) return ERROR_FILE_INVALID;
3223         len = lstrlenW( version );
3224         if (len >= *verlen) ret = ERROR_MORE_DATA;
3225         else if (verbuf)
3226         {
3227             lstrcpyW( verbuf, version );
3228             ret = ERROR_SUCCESS;
3229         }
3230         *verlen = len;
3231         free( version );
3232     }
3233     return ret;
3234 }
3235 
3236 /***********************************************************************
3237  * MsiGetFeatureUsageW           [MSI.@]
3238  */
MsiGetFeatureUsageW(LPCWSTR szProduct,LPCWSTR szFeature,LPDWORD pdwUseCount,LPWORD pwDateUsed)3239 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
3240                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
3241 {
3242     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
3243           pdwUseCount, pwDateUsed);
3244     return ERROR_CALL_NOT_IMPLEMENTED;
3245 }
3246 
3247 /***********************************************************************
3248  * MsiGetFeatureUsageA           [MSI.@]
3249  */
MsiGetFeatureUsageA(LPCSTR szProduct,LPCSTR szFeature,LPDWORD pdwUseCount,LPWORD pwDateUsed)3250 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
3251                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
3252 {
3253     LPWSTR prod = NULL, feat = NULL;
3254     UINT ret = ERROR_OUTOFMEMORY;
3255 
3256     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
3257           pdwUseCount, pwDateUsed);
3258 
3259     prod = strdupAtoW( szProduct );
3260     if (szProduct && !prod)
3261         goto end;
3262 
3263     feat = strdupAtoW( szFeature );
3264     if (szFeature && !feat)
3265         goto end;
3266 
3267     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
3268 
3269 end:
3270     free( prod );
3271     free( feat );
3272 
3273     return ret;
3274 }
3275 
3276 /***********************************************************************
3277  * MsiUseFeatureExW           [MSI.@]
3278  */
MsiUseFeatureExW(const WCHAR * szProduct,const WCHAR * szFeature,DWORD dwInstallMode,DWORD dwReserved)3279 INSTALLSTATE WINAPI MsiUseFeatureExW( const WCHAR *szProduct, const WCHAR *szFeature, DWORD dwInstallMode,
3280                                       DWORD dwReserved )
3281 {
3282     INSTALLSTATE state;
3283 
3284     TRACE( "%s, %s, %lu %#lx\n", debugstr_w(szProduct), debugstr_w(szFeature), dwInstallMode, dwReserved );
3285 
3286     state = MsiQueryFeatureStateW( szProduct, szFeature );
3287 
3288     if (dwReserved)
3289         return INSTALLSTATE_INVALIDARG;
3290 
3291     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
3292     {
3293         FIXME("mark product %s feature %s as used\n",
3294               debugstr_w(szProduct), debugstr_w(szFeature) );
3295     }
3296 
3297     return state;
3298 }
3299 
3300 /***********************************************************************
3301  * MsiUseFeatureExA           [MSI.@]
3302  */
MsiUseFeatureExA(const char * szProduct,const char * szFeature,DWORD dwInstallMode,DWORD dwReserved)3303 INSTALLSTATE WINAPI MsiUseFeatureExA( const char *szProduct, const char *szFeature, DWORD dwInstallMode,
3304                                       DWORD dwReserved )
3305 {
3306     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
3307     WCHAR *prod = NULL, *feat = NULL;
3308 
3309     TRACE( "%s, %s, %lu, %#lx\n", debugstr_a(szProduct), debugstr_a(szFeature), dwInstallMode, dwReserved );
3310 
3311     prod = strdupAtoW( szProduct );
3312     if (szProduct && !prod)
3313         goto end;
3314 
3315     feat = strdupAtoW( szFeature );
3316     if (szFeature && !feat)
3317         goto end;
3318 
3319     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
3320 
3321 end:
3322     free( prod );
3323     free( feat );
3324 
3325     return ret;
3326 }
3327 
3328 /***********************************************************************
3329  * MsiUseFeatureW             [MSI.@]
3330  */
MsiUseFeatureW(LPCWSTR szProduct,LPCWSTR szFeature)3331 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
3332 {
3333     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
3334 }
3335 
3336 /***********************************************************************
3337  * MsiUseFeatureA             [MSI.@]
3338  */
MsiUseFeatureA(LPCSTR szProduct,LPCSTR szFeature)3339 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
3340 {
3341     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
3342 }
3343 
reg_get_multisz(HKEY hkey,const WCHAR * name)3344 static WCHAR *reg_get_multisz( HKEY hkey, const WCHAR *name )
3345 {
3346     WCHAR *ret;
3347     DWORD len, type;
3348     if (RegQueryValueExW( hkey, name, NULL, &type, NULL, &len ) || type != REG_MULTI_SZ) return NULL;
3349     if ((ret = malloc( len ))) RegQueryValueExW( hkey, name, NULL, NULL, (BYTE *)ret, &len );
3350     return ret;
3351 }
3352 
reg_get_sz(HKEY hkey,const WCHAR * name)3353 static WCHAR *reg_get_sz( HKEY hkey, const WCHAR *name )
3354 {
3355     WCHAR *ret;
3356     DWORD len, type;
3357     if (RegQueryValueExW( hkey, name, NULL, &type, NULL, &len ) || type != REG_SZ) return NULL;
3358     if ((ret = malloc( len ))) RegQueryValueExW( hkey, name, NULL, NULL, (BYTE *)ret, &len );
3359     return ret;
3360 }
3361 
3362 #define BASE85_SIZE 20
3363 
3364 /***********************************************************************
3365  * MSI_ProvideQualifiedComponentEx [internal]
3366  */
MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,LPCWSTR szQualifier,DWORD dwInstallMode,LPCWSTR szProduct,DWORD Unused1,DWORD Unused2,awstring * lpPathBuf,LPDWORD pcchPathBuf)3367 static UINT MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
3368                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
3369                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
3370                 LPDWORD pcchPathBuf)
3371 {
3372     WCHAR product[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
3373     WCHAR *desc;
3374     HKEY hkey;
3375     DWORD size;
3376     UINT ret;
3377     INSTALLSTATE state;
3378 
3379     if (MSIREG_OpenUserComponentsKey( szComponent, &hkey, FALSE )) return ERROR_UNKNOWN_COMPONENT;
3380 
3381     desc = reg_get_multisz( hkey, szQualifier );
3382     RegCloseKey(hkey);
3383     if (!desc) return ERROR_INDEX_ABSENT;
3384 
3385     /* FIXME: handle multiple descriptors */
3386     ret = MsiDecomposeDescriptorW( desc, product, feature, comp, &size );
3387     free( desc );
3388     if (ret != ERROR_SUCCESS) return ret;
3389 
3390     if (!szProduct) szProduct = product;
3391     if (!comp[0])
3392     {
3393         MSIINSTALLCONTEXT ctx;
3394         WCHAR *components;
3395         GUID guid;
3396 
3397         /* use the first component of the feature if the descriptor component is empty */
3398         if ((ret = msi_locate_product( szProduct, &ctx ))) return ret;
3399         if ((ret = MSIREG_OpenUserDataFeaturesKey( szProduct, NULL, ctx, &hkey, FALSE )))
3400         {
3401             return ERROR_FILE_NOT_FOUND;
3402         }
3403         components = reg_get_sz( hkey, feature );
3404         RegCloseKey( hkey );
3405         if (!components) return ERROR_FILE_NOT_FOUND;
3406 
3407         if (lstrlenW( components ) < BASE85_SIZE || !decode_base85_guid( components, &guid ))
3408         {
3409             free( components );
3410             return ERROR_FILE_NOT_FOUND;
3411         }
3412         free( components );
3413         StringFromGUID2( &guid, comp, ARRAY_SIZE( comp ));
3414     }
3415 
3416     state = MSI_GetComponentPath( szProduct, comp, L"S-1-1-0", MSIINSTALLCONTEXT_ALL, lpPathBuf, pcchPathBuf );
3417 
3418     if (state == INSTALLSTATE_MOREDATA) return ERROR_MORE_DATA;
3419     if (state != INSTALLSTATE_LOCAL) return ERROR_FILE_NOT_FOUND;
3420     return ERROR_SUCCESS;
3421 }
3422 
3423 /***********************************************************************
3424  * MsiProvideQualifiedComponentExW [MSI.@]
3425  */
MsiProvideQualifiedComponentExW(const WCHAR * szComponent,const WCHAR * szQualifier,DWORD dwInstallMode,const WCHAR * szProduct,DWORD Unused1,DWORD Unused2,WCHAR * lpPathBuf,DWORD * pcchPathBuf)3426 UINT WINAPI MsiProvideQualifiedComponentExW( const WCHAR *szComponent, const WCHAR *szQualifier, DWORD dwInstallMode,
3427                                              const WCHAR *szProduct, DWORD Unused1, DWORD Unused2, WCHAR *lpPathBuf,
3428                                              DWORD *pcchPathBuf )
3429 {
3430     awstring path;
3431 
3432     TRACE( "%s, %s, %lu, %s, %#lx, %#lx, %p, %p\n", debugstr_w(szComponent), debugstr_w(szQualifier), dwInstallMode,
3433            debugstr_w(szProduct), Unused1, Unused2, lpPathBuf, pcchPathBuf );
3434 
3435     path.unicode = TRUE;
3436     path.str.w = lpPathBuf;
3437 
3438     return MSI_ProvideQualifiedComponentEx( szComponent, szQualifier, dwInstallMode, szProduct, Unused1, Unused2,
3439                                             &path, pcchPathBuf );
3440 }
3441 
3442 /***********************************************************************
3443  * MsiProvideQualifiedComponentExA [MSI.@]
3444  */
MsiProvideQualifiedComponentExA(const char * szComponent,const char * szQualifier,DWORD dwInstallMode,const char * szProduct,DWORD Unused1,DWORD Unused2,char * lpPathBuf,DWORD * pcchPathBuf)3445 UINT WINAPI MsiProvideQualifiedComponentExA( const char *szComponent, const char *szQualifier, DWORD dwInstallMode,
3446                                              const char *szProduct, DWORD Unused1, DWORD Unused2, char *lpPathBuf,
3447                                              DWORD *pcchPathBuf )
3448 {
3449     WCHAR *szwComponent, *szwQualifier = NULL, *szwProduct = NULL;
3450     UINT r = ERROR_OUTOFMEMORY;
3451     awstring path;
3452 
3453     TRACE( "%s, %s, %lu, %s, %#lx, %#lx, %p, %p\n", debugstr_a(szComponent), debugstr_a(szQualifier), dwInstallMode,
3454            debugstr_a(szProduct), Unused1, Unused2, lpPathBuf, pcchPathBuf );
3455 
3456     szwComponent = strdupAtoW( szComponent );
3457     if (szComponent && !szwComponent)
3458         goto end;
3459 
3460     szwQualifier = strdupAtoW( szQualifier );
3461     if (szQualifier && !szwQualifier)
3462         goto end;
3463 
3464     szwProduct = strdupAtoW( szProduct );
3465     if (szProduct && !szwProduct)
3466         goto end;
3467 
3468     path.unicode = FALSE;
3469     path.str.a = lpPathBuf;
3470 
3471     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
3472                               dwInstallMode, szwProduct, Unused1,
3473                               Unused2, &path, pcchPathBuf);
3474 end:
3475     free(szwProduct);
3476     free(szwComponent);
3477     free(szwQualifier);
3478 
3479     return r;
3480 }
3481 
3482 /***********************************************************************
3483  * MsiProvideQualifiedComponentW [MSI.@]
3484  */
MsiProvideQualifiedComponentW(LPCWSTR szComponent,LPCWSTR szQualifier,DWORD dwInstallMode,LPWSTR lpPathBuf,LPDWORD pcchPathBuf)3485 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
3486                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
3487                 LPDWORD pcchPathBuf)
3488 {
3489     return MsiProvideQualifiedComponentExW(szComponent, szQualifier,
3490                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
3491 }
3492 
3493 /***********************************************************************
3494  * MsiProvideQualifiedComponentA [MSI.@]
3495  */
MsiProvideQualifiedComponentA(LPCSTR szComponent,LPCSTR szQualifier,DWORD dwInstallMode,LPSTR lpPathBuf,LPDWORD pcchPathBuf)3496 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
3497                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
3498                 LPDWORD pcchPathBuf)
3499 {
3500     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
3501                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
3502 }
3503 
3504 /***********************************************************************
3505  * MSI_GetUserInfo [internal]
3506  */
MSI_GetUserInfo(LPCWSTR szProduct,awstring * lpUserNameBuf,LPDWORD pcchUserNameBuf,awstring * lpOrgNameBuf,LPDWORD pcchOrgNameBuf,awstring * lpSerialBuf,LPDWORD pcchSerialBuf)3507 static USERINFOSTATE MSI_GetUserInfo(LPCWSTR szProduct,
3508                 awstring *lpUserNameBuf, LPDWORD pcchUserNameBuf,
3509                 awstring *lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3510                 awstring *lpSerialBuf, LPDWORD pcchSerialBuf)
3511 {
3512     WCHAR *user, *org, *serial, squashed_pc[SQUASHED_GUID_SIZE];
3513     USERINFOSTATE state;
3514     HKEY hkey, props;
3515     LPCWSTR orgptr;
3516     UINT r;
3517 
3518     TRACE("%s %p %p %p %p %p %p\n", debugstr_w(szProduct), lpUserNameBuf,
3519           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
3520           pcchSerialBuf);
3521 
3522     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
3523         return USERINFOSTATE_INVALIDARG;
3524 
3525     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
3526                               &hkey, FALSE) != ERROR_SUCCESS &&
3527         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3528                               &hkey, FALSE) != ERROR_SUCCESS &&
3529         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
3530                               &hkey, FALSE) != ERROR_SUCCESS)
3531     {
3532         return USERINFOSTATE_UNKNOWN;
3533     }
3534 
3535     if (MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
3536                                 NULL, &props, FALSE) != ERROR_SUCCESS &&
3537         MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE,
3538                                 NULL, &props, FALSE) != ERROR_SUCCESS)
3539     {
3540         RegCloseKey(hkey);
3541         return USERINFOSTATE_ABSENT;
3542     }
3543 
3544     user = msi_reg_get_val_str(props, INSTALLPROPERTY_REGOWNERW);
3545     org = msi_reg_get_val_str(props, INSTALLPROPERTY_REGCOMPANYW);
3546     serial = msi_reg_get_val_str(props, INSTALLPROPERTY_PRODUCTIDW);
3547     state = USERINFOSTATE_ABSENT;
3548 
3549     RegCloseKey(hkey);
3550     RegCloseKey(props);
3551 
3552     if (user && serial)
3553         state = USERINFOSTATE_PRESENT;
3554 
3555     if (pcchUserNameBuf)
3556     {
3557         if (lpUserNameBuf && !user)
3558         {
3559             (*pcchUserNameBuf)--;
3560             goto done;
3561         }
3562 
3563         r = msi_strcpy_to_awstring(user, -1, lpUserNameBuf, pcchUserNameBuf);
3564         if (r == ERROR_MORE_DATA)
3565         {
3566             state = USERINFOSTATE_MOREDATA;
3567             goto done;
3568         }
3569     }
3570 
3571     if (pcchOrgNameBuf)
3572     {
3573         orgptr = org;
3574         if (!orgptr) orgptr = L"";
3575 
3576         r = msi_strcpy_to_awstring(orgptr, -1, lpOrgNameBuf, pcchOrgNameBuf);
3577         if (r == ERROR_MORE_DATA)
3578         {
3579             state = USERINFOSTATE_MOREDATA;
3580             goto done;
3581         }
3582     }
3583 
3584     if (pcchSerialBuf)
3585     {
3586         if (!serial)
3587         {
3588             (*pcchSerialBuf)--;
3589             goto done;
3590         }
3591 
3592         r = msi_strcpy_to_awstring(serial, -1, lpSerialBuf, pcchSerialBuf);
3593         if (r == ERROR_MORE_DATA)
3594             state = USERINFOSTATE_MOREDATA;
3595     }
3596 
3597 done:
3598     free(user);
3599     free(org);
3600     free(serial);
3601 
3602     return state;
3603 }
3604 
3605 /***********************************************************************
3606  * MsiGetUserInfoW [MSI.@]
3607  */
MsiGetUserInfoW(LPCWSTR szProduct,LPWSTR lpUserNameBuf,LPDWORD pcchUserNameBuf,LPWSTR lpOrgNameBuf,LPDWORD pcchOrgNameBuf,LPWSTR lpSerialBuf,LPDWORD pcchSerialBuf)3608 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
3609                 LPWSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3610                 LPWSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3611                 LPWSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3612 {
3613     awstring user, org, serial;
3614 
3615     if ((lpUserNameBuf && !pcchUserNameBuf) ||
3616         (lpOrgNameBuf && !pcchOrgNameBuf) ||
3617         (lpSerialBuf && !pcchSerialBuf))
3618         return USERINFOSTATE_INVALIDARG;
3619 
3620     user.unicode = TRUE;
3621     user.str.w = lpUserNameBuf;
3622     org.unicode = TRUE;
3623     org.str.w = lpOrgNameBuf;
3624     serial.unicode = TRUE;
3625     serial.str.w = lpSerialBuf;
3626 
3627     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
3628                             &org, pcchOrgNameBuf,
3629                             &serial, pcchSerialBuf );
3630 }
3631 
MsiGetUserInfoA(LPCSTR szProduct,LPSTR lpUserNameBuf,LPDWORD pcchUserNameBuf,LPSTR lpOrgNameBuf,LPDWORD pcchOrgNameBuf,LPSTR lpSerialBuf,LPDWORD pcchSerialBuf)3632 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
3633                 LPSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3634                 LPSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3635                 LPSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3636 {
3637     awstring user, org, serial;
3638     LPWSTR prod;
3639     UINT r;
3640 
3641     if ((lpUserNameBuf && !pcchUserNameBuf) ||
3642         (lpOrgNameBuf && !pcchOrgNameBuf) ||
3643         (lpSerialBuf && !pcchSerialBuf))
3644         return USERINFOSTATE_INVALIDARG;
3645 
3646     prod = strdupAtoW( szProduct );
3647     if (szProduct && !prod)
3648         return ERROR_OUTOFMEMORY;
3649 
3650     user.unicode = FALSE;
3651     user.str.a = lpUserNameBuf;
3652     org.unicode = FALSE;
3653     org.str.a = lpOrgNameBuf;
3654     serial.unicode = FALSE;
3655     serial.str.a = lpSerialBuf;
3656 
3657     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
3658                          &org, pcchOrgNameBuf,
3659                          &serial, pcchSerialBuf );
3660 
3661     free( prod );
3662 
3663     return r;
3664 }
3665 
MsiCollectUserInfoW(LPCWSTR szProduct)3666 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
3667 {
3668     MSIHANDLE handle;
3669     UINT rc;
3670     MSIPACKAGE *package;
3671 
3672     TRACE("(%s)\n",debugstr_w(szProduct));
3673 
3674     rc = MsiOpenProductW(szProduct,&handle);
3675     if (rc != ERROR_SUCCESS)
3676         return ERROR_INVALID_PARAMETER;
3677 
3678     /* MsiCollectUserInfo cannot be called from a custom action. */
3679     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3680     if (!package)
3681         return ERROR_CALL_NOT_IMPLEMENTED;
3682 
3683     rc = ACTION_PerformAction(package, L"FirstRun");
3684     msiobj_release( &package->hdr );
3685 
3686     MsiCloseHandle(handle);
3687 
3688     return rc;
3689 }
3690 
MsiCollectUserInfoA(LPCSTR szProduct)3691 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
3692 {
3693     MSIHANDLE handle;
3694     UINT rc;
3695     MSIPACKAGE *package;
3696 
3697     TRACE("(%s)\n",debugstr_a(szProduct));
3698 
3699     rc = MsiOpenProductA(szProduct,&handle);
3700     if (rc != ERROR_SUCCESS)
3701         return ERROR_INVALID_PARAMETER;
3702 
3703     /* MsiCollectUserInfo cannot be called from a custom action. */
3704     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3705     if (!package)
3706         return ERROR_CALL_NOT_IMPLEMENTED;
3707 
3708     rc = ACTION_PerformAction(package, L"FirstRun");
3709     msiobj_release( &package->hdr );
3710 
3711     MsiCloseHandle(handle);
3712 
3713     return rc;
3714 }
3715 
3716 /***********************************************************************
3717  * MsiConfigureFeatureA            [MSI.@]
3718  */
MsiConfigureFeatureA(LPCSTR szProduct,LPCSTR szFeature,INSTALLSTATE eInstallState)3719 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
3720 {
3721     LPWSTR prod, feat = NULL;
3722     UINT r = ERROR_OUTOFMEMORY;
3723 
3724     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
3725 
3726     prod = strdupAtoW( szProduct );
3727     if (szProduct && !prod)
3728         goto end;
3729 
3730     feat = strdupAtoW( szFeature );
3731     if (szFeature && !feat)
3732         goto end;
3733 
3734     r = MsiConfigureFeatureW(prod, feat, eInstallState);
3735 
3736 end:
3737     free(feat);
3738     free(prod);
3739 
3740     return r;
3741 }
3742 
3743 /***********************************************************************
3744  * MsiConfigureFeatureW            [MSI.@]
3745  */
MsiConfigureFeatureW(LPCWSTR szProduct,LPCWSTR szFeature,INSTALLSTATE eInstallState)3746 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
3747 {
3748     MSIPACKAGE *package = NULL;
3749     UINT r;
3750     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
3751     DWORD sz;
3752 
3753     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
3754 
3755     if (!szProduct || !szFeature)
3756         return ERROR_INVALID_PARAMETER;
3757 
3758     switch (eInstallState)
3759     {
3760     case INSTALLSTATE_DEFAULT:
3761         /* FIXME: how do we figure out the default location? */
3762         eInstallState = INSTALLSTATE_LOCAL;
3763         break;
3764     case INSTALLSTATE_LOCAL:
3765     case INSTALLSTATE_SOURCE:
3766     case INSTALLSTATE_ABSENT:
3767     case INSTALLSTATE_ADVERTISED:
3768         break;
3769     default:
3770         return ERROR_INVALID_PARAMETER;
3771     }
3772 
3773     r = MSI_OpenProductW( szProduct, &package );
3774     if (r != ERROR_SUCCESS)
3775         return r;
3776 
3777     sz = sizeof(sourcepath);
3778     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3779                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
3780 
3781     sz = sizeof(filename);
3782     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3783                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
3784 
3785     lstrcatW( sourcepath, filename );
3786 
3787     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
3788 
3789     r = ACTION_PerformAction(package, L"CostInitialize");
3790     if (r != ERROR_SUCCESS)
3791         goto end;
3792 
3793     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
3794     if (r != ERROR_SUCCESS)
3795         goto end;
3796 
3797     r = MSI_InstallPackage( package, sourcepath, NULL );
3798 
3799 end:
3800     msiobj_release( &package->hdr );
3801 
3802     return r;
3803 }
3804 
3805 /***********************************************************************
3806  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
3807  *
3808  * Notes: undocumented
3809  */
MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)3810 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
3811 {
3812     WCHAR path[MAX_PATH];
3813 
3814     TRACE( "%#lx\n", dwReserved );
3815 
3816     if (dwReserved)
3817     {
3818         FIXME( "dwReserved = %#lx\n", dwReserved );
3819         return ERROR_INVALID_PARAMETER;
3820     }
3821 
3822     if (!GetWindowsDirectoryW(path, MAX_PATH))
3823         return ERROR_FUNCTION_FAILED;
3824 
3825     lstrcatW(path, L"\\Installer");
3826 
3827     if (!CreateDirectoryW(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
3828         return ERROR_FUNCTION_FAILED;
3829 
3830     return ERROR_SUCCESS;
3831 }
3832 
3833 /***********************************************************************
3834  * MsiGetShortcutTargetA           [MSI.@]
3835  */
MsiGetShortcutTargetA(LPCSTR szShortcutTarget,LPSTR szProductCode,LPSTR szFeatureId,LPSTR szComponentCode)3836 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
3837                                    LPSTR szProductCode, LPSTR szFeatureId,
3838                                    LPSTR szComponentCode )
3839 {
3840     LPWSTR target;
3841     const int len = MAX_FEATURE_CHARS+1;
3842     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
3843     UINT r;
3844 
3845     target = strdupAtoW( szShortcutTarget );
3846     if (szShortcutTarget && !target )
3847         return ERROR_OUTOFMEMORY;
3848     product[0] = 0;
3849     feature[0] = 0;
3850     component[0] = 0;
3851     r = MsiGetShortcutTargetW( target, product, feature, component );
3852     free( target );
3853     if (r == ERROR_SUCCESS)
3854     {
3855         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
3856         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
3857         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
3858     }
3859     return r;
3860 }
3861 
3862 /***********************************************************************
3863  * MsiGetShortcutTargetW           [MSI.@]
3864  */
MsiGetShortcutTargetW(LPCWSTR szShortcutTarget,LPWSTR szProductCode,LPWSTR szFeatureId,LPWSTR szComponentCode)3865 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
3866                                    LPWSTR szProductCode, LPWSTR szFeatureId,
3867                                    LPWSTR szComponentCode )
3868 {
3869     IShellLinkDataList *dl = NULL;
3870     IPersistFile *pf = NULL;
3871     LPEXP_DARWIN_LINK darwin = NULL;
3872     HRESULT r, init;
3873 
3874     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
3875           szProductCode, szFeatureId, szComponentCode );
3876 
3877     init = CoInitialize(NULL);
3878 
3879     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3880                           &IID_IPersistFile, (LPVOID*) &pf );
3881     if( SUCCEEDED( r ) )
3882     {
3883         r = IPersistFile_Load( pf, szShortcutTarget,
3884                                STGM_READ | STGM_SHARE_DENY_WRITE );
3885         if( SUCCEEDED( r ) )
3886         {
3887             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
3888                                              (LPVOID*) &dl );
3889             if( SUCCEEDED( r ) )
3890             {
3891                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
3892                                                   (LPVOID) &darwin );
3893                 IShellLinkDataList_Release( dl );
3894             }
3895         }
3896         IPersistFile_Release( pf );
3897     }
3898 
3899     if (SUCCEEDED(init))
3900         CoUninitialize();
3901 
3902     TRACE("darwin = %p\n", darwin);
3903 
3904     if (darwin)
3905     {
3906         DWORD sz;
3907         UINT ret;
3908 
3909         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
3910                   szProductCode, szFeatureId, szComponentCode, &sz );
3911         LocalFree( darwin );
3912         return ret;
3913     }
3914 
3915     return ERROR_FUNCTION_FAILED;
3916 }
3917 
MsiReinstallFeatureW(const WCHAR * szProduct,const WCHAR * szFeature,DWORD dwReinstallMode)3918 UINT WINAPI MsiReinstallFeatureW( const WCHAR *szProduct, const WCHAR *szFeature, DWORD dwReinstallMode )
3919 {
3920     MSIPACKAGE *package;
3921     MSIINSTALLCONTEXT context;
3922     UINT r;
3923     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH], reinstallmode[11];
3924     WCHAR *ptr, *cmdline;
3925     DWORD sz;
3926 
3927     TRACE( "%s, %s, %#lx\n", debugstr_w(szProduct), debugstr_w(szFeature), dwReinstallMode );
3928 
3929     r = msi_locate_product( szProduct, &context );
3930     if (r != ERROR_SUCCESS)
3931         return r;
3932 
3933     ptr = reinstallmode;
3934 
3935     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
3936         *ptr++ = 'p';
3937     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
3938         *ptr++ = 'o';
3939     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
3940         *ptr++ = 'w';
3941     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
3942         *ptr++ = 'd';
3943     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
3944         *ptr++ = 'c';
3945     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
3946         *ptr++ = 'a';
3947     if (dwReinstallMode & REINSTALLMODE_USERDATA)
3948         *ptr++ = 'u';
3949     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
3950         *ptr++ = 'm';
3951     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
3952         *ptr++ = 's';
3953     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
3954         *ptr++ = 'v';
3955     *ptr = 0;
3956 
3957     sz = sizeof(sourcepath);
3958     MsiSourceListGetInfoW( szProduct, NULL, context, MSICODE_PRODUCT,
3959                            INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz );
3960     sz = sizeof(filename);
3961     MsiSourceListGetInfoW( szProduct, NULL, context, MSICODE_PRODUCT,
3962                            INSTALLPROPERTY_PACKAGENAMEW, filename, &sz );
3963     lstrcatW( sourcepath, filename );
3964 
3965     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
3966         r = MSI_OpenPackageW( sourcepath, 0, &package );
3967     else
3968         r = MSI_OpenProductW( szProduct, &package );
3969 
3970     if (r != ERROR_SUCCESS)
3971         return r;
3972 
3973     sz = (lstrlenW( L"%s=%s %s=%s" ) + lstrlenW( L"REINSTALLMODE" ) + lstrlenW( reinstallmode )) * sizeof(WCHAR);
3974     sz += (lstrlenW( L"REINSTALL" ) + lstrlenW( szFeature )) * sizeof(WCHAR);
3975     if (!(cmdline = malloc( sz )))
3976     {
3977         msiobj_release( &package->hdr );
3978         return ERROR_OUTOFMEMORY;
3979     }
3980     swprintf( cmdline, sz / sizeof(WCHAR), L"%s=%s %s=%s", L"REINSTALLMODE", reinstallmode, L"REINSTALL", szFeature );
3981 
3982     r = MSI_InstallPackage( package, sourcepath, cmdline );
3983     msiobj_release( &package->hdr );
3984     free( cmdline );
3985 
3986     return r;
3987 }
3988 
MsiReinstallFeatureA(const char * szProduct,const char * szFeature,DWORD dwReinstallMode)3989 UINT WINAPI MsiReinstallFeatureA( const char *szProduct, const char *szFeature, DWORD dwReinstallMode )
3990 {
3991     WCHAR *wszProduct, *wszFeature;
3992     UINT rc;
3993 
3994     TRACE( "%s, %s, %lu\n", debugstr_a(szProduct), debugstr_a(szFeature), dwReinstallMode );
3995 
3996     wszProduct = strdupAtoW(szProduct);
3997     wszFeature = strdupAtoW(szFeature);
3998 
3999     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
4000 
4001     free(wszProduct);
4002     free(wszFeature);
4003     return rc;
4004 }
4005 
4006 struct md5_ctx
4007 {
4008     unsigned int i[2];
4009     unsigned int buf[4];
4010     unsigned char in[64];
4011     unsigned char digest[16];
4012 };
4013 
4014 extern void WINAPI MD5Init( struct md5_ctx * );
4015 extern void WINAPI MD5Update( struct md5_ctx *, const unsigned char *, unsigned int );
4016 extern void WINAPI MD5Final( struct md5_ctx * );
4017 
msi_get_filehash(MSIPACKAGE * package,const WCHAR * path,MSIFILEHASHINFO * hash)4018 UINT msi_get_filehash( MSIPACKAGE *package, const WCHAR *path, MSIFILEHASHINFO *hash )
4019 {
4020     HANDLE handle, mapping;
4021     void *p;
4022     DWORD length;
4023     UINT r = ERROR_FUNCTION_FAILED;
4024 
4025     if (package)
4026         handle = msi_create_file( package, path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE, OPEN_EXISTING, 0 );
4027     else
4028         handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
4029     if (handle == INVALID_HANDLE_VALUE)
4030     {
4031         WARN( "can't open file %lu\n", GetLastError() );
4032         return ERROR_FILE_NOT_FOUND;
4033     }
4034     if ((length = GetFileSize( handle, NULL )))
4035     {
4036         if ((mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL )))
4037         {
4038             if ((p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length )))
4039             {
4040                 struct md5_ctx ctx;
4041 
4042                 MD5Init( &ctx );
4043                 MD5Update( &ctx, p, length );
4044                 MD5Final( &ctx );
4045                 UnmapViewOfFile( p );
4046 
4047                 memcpy( hash->dwData, ctx.digest, sizeof(hash->dwData) );
4048                 r = ERROR_SUCCESS;
4049             }
4050             CloseHandle( mapping );
4051         }
4052     }
4053     else
4054     {
4055         /* Empty file -> set hash to 0 */
4056         memset( hash->dwData, 0, sizeof(hash->dwData) );
4057         r = ERROR_SUCCESS;
4058     }
4059 
4060     CloseHandle( handle );
4061     return r;
4062 }
4063 
4064 /***********************************************************************
4065  * MsiGetFileHashW            [MSI.@]
4066  */
MsiGetFileHashW(const WCHAR * szFilePath,DWORD dwOptions,MSIFILEHASHINFO * pHash)4067 UINT WINAPI MsiGetFileHashW( const WCHAR *szFilePath, DWORD dwOptions, MSIFILEHASHINFO *pHash )
4068 {
4069     TRACE( "%s, %#lx, %p\n", debugstr_w(szFilePath), dwOptions, pHash );
4070 
4071     if (!szFilePath)
4072         return ERROR_INVALID_PARAMETER;
4073 
4074     if (!*szFilePath)
4075         return ERROR_PATH_NOT_FOUND;
4076 
4077     if (dwOptions)
4078         return ERROR_INVALID_PARAMETER;
4079     if (!pHash)
4080         return ERROR_INVALID_PARAMETER;
4081     if (pHash->dwFileHashInfoSize < sizeof *pHash)
4082         return ERROR_INVALID_PARAMETER;
4083 
4084     return msi_get_filehash( NULL, szFilePath, pHash );
4085 }
4086 
4087 /***********************************************************************
4088  * MsiGetFileHashA            [MSI.@]
4089  */
MsiGetFileHashA(const char * szFilePath,DWORD dwOptions,MSIFILEHASHINFO * pHash)4090 UINT WINAPI MsiGetFileHashA( const char *szFilePath, DWORD dwOptions, MSIFILEHASHINFO *pHash )
4091 {
4092     LPWSTR file;
4093     UINT r;
4094 
4095     TRACE( "%s, %#lx, %p\n", debugstr_a(szFilePath), dwOptions, pHash );
4096 
4097     file = strdupAtoW( szFilePath );
4098     if (szFilePath && !file)
4099         return ERROR_OUTOFMEMORY;
4100 
4101     r = MsiGetFileHashW( file, dwOptions, pHash );
4102     free( file );
4103     return r;
4104 }
4105 
4106 /***********************************************************************
4107  * MsiAdvertiseScriptW        [MSI.@]
4108  */
MsiAdvertiseScriptW(const WCHAR * szScriptFile,DWORD dwFlags,HKEY * phRegData,BOOL fRemoveItems)4109 UINT WINAPI MsiAdvertiseScriptW( const WCHAR *szScriptFile, DWORD dwFlags, HKEY *phRegData, BOOL fRemoveItems )
4110 {
4111     FIXME( "%s, %#lx, %p, %d\n", debugstr_w(szScriptFile), dwFlags, phRegData, fRemoveItems );
4112     return ERROR_CALL_NOT_IMPLEMENTED;
4113 }
4114 
4115 /***********************************************************************
4116  * MsiAdvertiseScriptA        [MSI.@]
4117  */
MsiAdvertiseScriptA(const char * szScriptFile,DWORD dwFlags,HKEY * phRegData,BOOL fRemoveItems)4118 UINT WINAPI MsiAdvertiseScriptA( const char *szScriptFile, DWORD dwFlags, HKEY *phRegData, BOOL fRemoveItems )
4119 {
4120     FIXME( "%s, %#lx, %p, %d\n", debugstr_a(szScriptFile), dwFlags, phRegData, fRemoveItems );
4121     return ERROR_CALL_NOT_IMPLEMENTED;
4122 }
4123 
4124 /***********************************************************************
4125  * MsiIsProductElevatedW        [MSI.@]
4126  */
MsiIsProductElevatedW(LPCWSTR szProduct,BOOL * pfElevated)4127 UINT WINAPI MsiIsProductElevatedW( LPCWSTR szProduct, BOOL *pfElevated )
4128 {
4129     FIXME("%s %p - stub\n",
4130           debugstr_w( szProduct ), pfElevated );
4131     *pfElevated = TRUE;
4132     return ERROR_SUCCESS;
4133 }
4134 
4135 /***********************************************************************
4136  * MsiIsProductElevatedA        [MSI.@]
4137  */
MsiIsProductElevatedA(LPCSTR szProduct,BOOL * pfElevated)4138 UINT WINAPI MsiIsProductElevatedA( LPCSTR szProduct, BOOL *pfElevated )
4139 {
4140     FIXME("%s %p - stub\n",
4141           debugstr_a( szProduct ), pfElevated );
4142     *pfElevated = TRUE;
4143     return ERROR_SUCCESS;
4144 }
4145 
4146 /***********************************************************************
4147  * MsiSetExternalUIRecord     [MSI.@]
4148  */
MsiSetExternalUIRecord(INSTALLUI_HANDLER_RECORD handler,DWORD filter,void * context,INSTALLUI_HANDLER_RECORD * prev)4149 UINT WINAPI MsiSetExternalUIRecord( INSTALLUI_HANDLER_RECORD handler, DWORD filter, void *context,
4150                                     INSTALLUI_HANDLER_RECORD *prev )
4151 {
4152     TRACE( "%p, %#lx, %p, %p\n", handler, filter, context, prev );
4153 
4154     if (prev)
4155         *prev = gUIHandlerRecord;
4156 
4157     gUIHandlerRecord = handler;
4158     gUIFilterRecord  = filter;
4159     gUIContextRecord = context;
4160 
4161     return ERROR_SUCCESS;
4162 }
4163 
4164 /***********************************************************************
4165  * MsiInstallMissingComponentA     [MSI.@]
4166  */
MsiInstallMissingComponentA(LPCSTR product,LPCSTR component,INSTALLSTATE state)4167 UINT WINAPI MsiInstallMissingComponentA( LPCSTR product, LPCSTR component, INSTALLSTATE state )
4168 {
4169     UINT r;
4170     WCHAR *productW = NULL, *componentW = NULL;
4171 
4172     TRACE("%s, %s, %d\n", debugstr_a(product), debugstr_a(component), state);
4173 
4174     if (product && !(productW = strdupAtoW( product )))
4175         return ERROR_OUTOFMEMORY;
4176 
4177     if (component && !(componentW = strdupAtoW( component )))
4178     {
4179         free( productW );
4180         return ERROR_OUTOFMEMORY;
4181     }
4182 
4183     r = MsiInstallMissingComponentW( productW, componentW, state );
4184     free( productW );
4185     free( componentW );
4186     return r;
4187 }
4188 
4189 /***********************************************************************
4190  * MsiInstallMissingComponentW     [MSI.@]
4191  */
MsiInstallMissingComponentW(LPCWSTR szProduct,LPCWSTR szComponent,INSTALLSTATE eInstallState)4192 UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent, INSTALLSTATE eInstallState)
4193 {
4194     FIXME("(%s %s %d\n", debugstr_w(szProduct), debugstr_w(szComponent), eInstallState);
4195     return ERROR_SUCCESS;
4196 }
4197 
MsiProvideComponentA(const char * product,const char * feature,const char * component,DWORD mode,char * buf,DWORD * buflen)4198 UINT WINAPI MsiProvideComponentA( const char *product, const char *feature, const char *component, DWORD mode,
4199                                   char *buf, DWORD *buflen )
4200 {
4201     WCHAR *productW = NULL, *componentW = NULL, *featureW = NULL, *bufW = NULL;
4202     UINT r = ERROR_OUTOFMEMORY;
4203     DWORD lenW = 0;
4204     int len;
4205 
4206     TRACE( "%s, %s, %s, %#lx, %p, %p\n", debugstr_a(product), debugstr_a(component), debugstr_a(feature), mode,
4207            buf, buflen );
4208 
4209     if (product && !(productW = strdupAtoW( product ))) goto done;
4210     if (feature && !(featureW = strdupAtoW( feature ))) goto done;
4211     if (component && !(componentW = strdupAtoW( component ))) goto done;
4212 
4213     r = MsiProvideComponentW( productW, featureW, componentW, mode, NULL, &lenW );
4214     if (r != ERROR_SUCCESS)
4215         goto done;
4216 
4217     if (!(bufW = malloc( ++lenW * sizeof(WCHAR) )))
4218     {
4219         r = ERROR_OUTOFMEMORY;
4220         goto done;
4221     }
4222 
4223     r = MsiProvideComponentW( productW, featureW, componentW, mode, bufW, &lenW );
4224     if (r != ERROR_SUCCESS)
4225         goto done;
4226 
4227     len = WideCharToMultiByte( CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
4228     if (buf)
4229     {
4230         if (len > *buflen)
4231             r = ERROR_MORE_DATA;
4232         else
4233             WideCharToMultiByte( CP_ACP, 0, bufW, -1, buf, *buflen, NULL, NULL );
4234     }
4235 
4236     *buflen = len - 1;
4237 
4238 done:
4239     free( productW );
4240     free( featureW );
4241     free( componentW );
4242     free( bufW );
4243     return r;
4244 }
4245 
MsiProvideComponentW(const WCHAR * product,const WCHAR * feature,const WCHAR * component,DWORD mode,WCHAR * buf,DWORD * buflen)4246 UINT WINAPI MsiProvideComponentW( const WCHAR *product, const WCHAR *feature, const WCHAR *component, DWORD mode,
4247                                   WCHAR *buf, DWORD *buflen )
4248 {
4249     INSTALLSTATE state;
4250 
4251     TRACE( "%s, %s, %s, %#lx, %p, %p\n", debugstr_w(product), debugstr_w(component), debugstr_w(feature), mode,
4252            buf, buflen);
4253 
4254     state = MsiQueryFeatureStateW( product, feature );
4255     TRACE("feature state: %d\n", state);
4256     switch (mode)
4257     {
4258     case INSTALLMODE_NODETECTION:
4259         break;
4260 
4261     default:
4262         FIXME( "mode %#lx not implemented\n", mode );
4263         return ERROR_INSTALL_FAILURE;
4264     }
4265 
4266     state = MsiGetComponentPathW( product, component, buf, buflen );
4267     TRACE("component state: %d\n", state);
4268     switch (state)
4269     {
4270     case INSTALLSTATE_INVALIDARG:
4271         return ERROR_INVALID_PARAMETER;
4272 
4273     case INSTALLSTATE_MOREDATA:
4274         return ERROR_MORE_DATA;
4275 
4276     case INSTALLSTATE_ADVERTISED:
4277     case INSTALLSTATE_LOCAL:
4278     case INSTALLSTATE_SOURCE:
4279         MsiUseFeatureW( product, feature );
4280         return ERROR_SUCCESS;
4281 
4282     default:
4283         TRACE("MsiGetComponentPathW returned %d\n", state);
4284         return ERROR_INSTALL_FAILURE;
4285     }
4286 }
4287 
4288 /***********************************************************************
4289  * MsiBeginTransactionA     [MSI.@]
4290  */
MsiBeginTransactionA(const char * name,DWORD attrs,MSIHANDLE * id,HANDLE * event)4291 UINT WINAPI MsiBeginTransactionA( const char *name, DWORD attrs, MSIHANDLE *id, HANDLE *event )
4292 {
4293     WCHAR *nameW;
4294     UINT r;
4295 
4296     FIXME( "%s, %#lx, %p, %p\n", debugstr_a(name), attrs, id, event );
4297 
4298     nameW = strdupAtoW( name );
4299     if (name && !nameW)
4300         return ERROR_OUTOFMEMORY;
4301 
4302     r = MsiBeginTransactionW( nameW, attrs, id, event );
4303     free( nameW );
4304     return r;
4305 }
4306 
4307 /***********************************************************************
4308  * MsiBeginTransactionW     [MSI.@]
4309  */
MsiBeginTransactionW(const WCHAR * name,DWORD attrs,MSIHANDLE * id,HANDLE * event)4310 UINT WINAPI MsiBeginTransactionW( const WCHAR *name, DWORD attrs, MSIHANDLE *id, HANDLE *event )
4311 {
4312     FIXME( "%s, %#lx, %p, %p\n", debugstr_w(name), attrs, id, event );
4313 
4314     *id = (MSIHANDLE)0xdeadbeef;
4315     *event = (HANDLE)0xdeadbeef;
4316 
4317     return ERROR_SUCCESS;
4318 }
4319 
4320 /***********************************************************************
4321  * MsiJoinTransaction     [MSI.@]
4322  */
MsiJoinTransaction(MSIHANDLE handle,DWORD attrs,HANDLE * event)4323 UINT WINAPI MsiJoinTransaction( MSIHANDLE handle, DWORD attrs, HANDLE *event )
4324 {
4325     FIXME( "%lu, %#lx, %p\n", handle, attrs, event );
4326 
4327     *event = (HANDLE)0xdeadbeef;
4328     return ERROR_SUCCESS;
4329 }
4330 
4331 /***********************************************************************
4332  * MsiEndTransaction     [MSI.@]
4333  */
MsiEndTransaction(DWORD state)4334 UINT WINAPI MsiEndTransaction( DWORD state )
4335 {
4336     FIXME( "%#lx\n", state );
4337     return ERROR_SUCCESS;
4338 }
4339 
Migrate10CachedPackagesW(void * a,void * b,void * c,DWORD d)4340 UINT WINAPI Migrate10CachedPackagesW( void *a, void *b, void *c, DWORD d )
4341 {
4342     FIXME( "%p, %p, %p, %#lx\n", a, b, c, d );
4343     return ERROR_SUCCESS;
4344 }
4345 
4346 /***********************************************************************
4347  * MsiRemovePatchesA     [MSI.@]
4348  */
MsiRemovePatchesA(LPCSTR patchlist,LPCSTR product,INSTALLTYPE type,LPCSTR propertylist)4349 UINT WINAPI MsiRemovePatchesA(LPCSTR patchlist, LPCSTR product, INSTALLTYPE type, LPCSTR propertylist)
4350 {
4351     FIXME("(%s %s %d %s\n", debugstr_a(patchlist), debugstr_a(product), type, debugstr_a(propertylist));
4352     return ERROR_SUCCESS;
4353 }
4354 
4355 /***********************************************************************
4356  * MsiRemovePatchesW    [MSI.@]
4357  */
MsiRemovePatchesW(LPCWSTR patchlist,LPCWSTR product,INSTALLTYPE type,LPCWSTR propertylist)4358 UINT WINAPI MsiRemovePatchesW(LPCWSTR patchlist, LPCWSTR product, INSTALLTYPE type, LPCWSTR propertylist)
4359 {
4360     FIXME("(%s %s %d %s\n", debugstr_w(patchlist), debugstr_w(product), type, debugstr_w(propertylist));
4361     return ERROR_SUCCESS;
4362 }
4363