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