092aac82c3a4329be3b8bbc92792935ba829ae8a
[reactos.git] / dll / win32 / msi / msi.c
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2002,2003,2004,2005 Mike McCormack for CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "msipriv.h"
22
23 #include <softpub.h>
24 #include <initguid.h>
25 #include <msxml2.h>
26
27 WINE_DEFAULT_DEBUG_CHANNEL(msi);
28
29 static const WCHAR installerW[] = {'\\','I','n','s','t','a','l','l','e','r',0};
30
31 UINT msi_locate_product(LPCWSTR szProduct, MSIINSTALLCONTEXT *context)
32 {
33 HKEY hkey = NULL;
34
35 *context = MSIINSTALLCONTEXT_NONE;
36 if (!szProduct) return ERROR_UNKNOWN_PRODUCT;
37
38 if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
39 &hkey, FALSE) == ERROR_SUCCESS)
40 *context = MSIINSTALLCONTEXT_USERMANAGED;
41 else if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
42 &hkey, FALSE) == ERROR_SUCCESS)
43 *context = MSIINSTALLCONTEXT_MACHINE;
44 else if (MSIREG_OpenProductKey(szProduct, NULL,
45 MSIINSTALLCONTEXT_USERUNMANAGED,
46 &hkey, FALSE) == ERROR_SUCCESS)
47 *context = MSIINSTALLCONTEXT_USERUNMANAGED;
48
49 RegCloseKey(hkey);
50
51 if (*context == MSIINSTALLCONTEXT_NONE)
52 return ERROR_UNKNOWN_PRODUCT;
53
54 return ERROR_SUCCESS;
55 }
56
57 UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
58 {
59 UINT r;
60 LPWSTR szwProd = NULL;
61
62 TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
63
64 if( szProduct )
65 {
66 szwProd = strdupAtoW( szProduct );
67 if( !szwProd )
68 return ERROR_OUTOFMEMORY;
69 }
70
71 r = MsiOpenProductW( szwProd, phProduct );
72
73 msi_free( szwProd );
74
75 return r;
76 }
77
78 static UINT MSI_OpenProductW(LPCWSTR szProduct, MSIPACKAGE **package)
79 {
80 UINT r;
81 HKEY props;
82 LPWSTR path;
83 MSIINSTALLCONTEXT context;
84
85 static const WCHAR managed[] = {
86 'M','a','n','a','g','e','d','L','o','c','a','l','P','a','c','k','a','g','e',0};
87 static const WCHAR local[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
88
89 TRACE("%s %p\n", debugstr_w(szProduct), package);
90
91 r = msi_locate_product(szProduct, &context);
92 if (r != ERROR_SUCCESS)
93 return r;
94
95 r = MSIREG_OpenInstallProps(szProduct, context, NULL, &props, FALSE);
96 if (r != ERROR_SUCCESS)
97 return ERROR_UNKNOWN_PRODUCT;
98
99 if (context == MSIINSTALLCONTEXT_USERMANAGED)
100 path = msi_reg_get_val_str(props, managed);
101 else
102 path = msi_reg_get_val_str(props, local);
103
104 r = ERROR_UNKNOWN_PRODUCT;
105
106 if (!path || GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
107 goto done;
108
109 if (PathIsRelativeW(path))
110 {
111 r = ERROR_INSTALL_PACKAGE_OPEN_FAILED;
112 goto done;
113 }
114
115 r = MSI_OpenPackageW(path, package);
116
117 done:
118 RegCloseKey(props);
119 msi_free(path);
120 return r;
121 }
122
123 UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct)
124 {
125 MSIPACKAGE *package = NULL;
126 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
127 UINT r;
128
129 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
130 return ERROR_INVALID_PARAMETER;
131
132 if (!phProduct)
133 return ERROR_INVALID_PARAMETER;
134
135 r = MSI_OpenProductW(szProduct, &package);
136 if (r != ERROR_SUCCESS)
137 return r;
138
139 *phProduct = alloc_msihandle(&package->hdr);
140 if (!*phProduct)
141 r = ERROR_NOT_ENOUGH_MEMORY;
142
143 msiobj_release(&package->hdr);
144 return r;
145 }
146
147 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
148 LPCSTR szTransforms, LANGID lgidLanguage)
149 {
150 FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath),
151 debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
152 return ERROR_CALL_NOT_IMPLEMENTED;
153 }
154
155 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
156 LPCWSTR szTransforms, LANGID lgidLanguage)
157 {
158 FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath),
159 debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
160 return ERROR_CALL_NOT_IMPLEMENTED;
161 }
162
163 UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
164 LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
165 {
166 FIXME("%s %s %s %08x %08x %08x\n", debugstr_a(szPackagePath),
167 debugstr_a(szScriptfilePath), debugstr_a(szTransforms),
168 lgidLanguage, dwPlatform, dwOptions);
169 return ERROR_CALL_NOT_IMPLEMENTED;
170 }
171
172 UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
173 LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
174 {
175 FIXME("%s %s %s %08x %08x %08x\n", debugstr_w(szPackagePath),
176 debugstr_w(szScriptfilePath), debugstr_w(szTransforms),
177 lgidLanguage, dwPlatform, dwOptions);
178 return ERROR_CALL_NOT_IMPLEMENTED;
179 }
180
181 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
182 {
183 LPWSTR szwPath = NULL, szwCommand = NULL;
184 UINT r = ERROR_OUTOFMEMORY;
185
186 TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
187
188 if( szPackagePath )
189 {
190 szwPath = strdupAtoW( szPackagePath );
191 if( !szwPath )
192 goto end;
193 }
194
195 if( szCommandLine )
196 {
197 szwCommand = strdupAtoW( szCommandLine );
198 if( !szwCommand )
199 goto end;
200 }
201
202 r = MsiInstallProductW( szwPath, szwCommand );
203
204 end:
205 msi_free( szwPath );
206 msi_free( szwCommand );
207
208 return r;
209 }
210
211 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
212 {
213 MSIPACKAGE *package = NULL;
214 UINT r;
215
216 TRACE("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
217
218 if (!szPackagePath)
219 return ERROR_INVALID_PARAMETER;
220
221 if (!*szPackagePath)
222 return ERROR_PATH_NOT_FOUND;
223
224 r = MSI_OpenPackageW( szPackagePath, &package );
225 if (r == ERROR_SUCCESS)
226 {
227 r = MSI_InstallPackage( package, szPackagePath, szCommandLine );
228 msiobj_release( &package->hdr );
229 }
230
231 return r;
232 }
233
234 UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode)
235 {
236 LPWSTR wszProduct;
237 UINT rc;
238
239 TRACE("%s %08x\n", debugstr_a(szProduct), dwReinstallMode);
240
241 wszProduct = strdupAtoW(szProduct);
242
243 rc = MsiReinstallProductW(wszProduct, dwReinstallMode);
244
245 msi_free(wszProduct);
246 return rc;
247 }
248
249 UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode)
250 {
251 TRACE("%s %08x\n", debugstr_w(szProduct), dwReinstallMode);
252
253 return MsiReinstallFeatureW(szProduct, szAll, dwReinstallMode);
254 }
255
256 UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage,
257 INSTALLTYPE eInstallType, LPCSTR szCommandLine)
258 {
259 LPWSTR patch_package = NULL;
260 LPWSTR install_package = NULL;
261 LPWSTR command_line = NULL;
262 UINT r = ERROR_OUTOFMEMORY;
263
264 TRACE("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage),
265 eInstallType, debugstr_a(szCommandLine));
266
267 if (szPatchPackage && !(patch_package = strdupAtoW(szPatchPackage)))
268 goto done;
269
270 if (szInstallPackage && !(install_package = strdupAtoW(szInstallPackage)))
271 goto done;
272
273 if (szCommandLine && !(command_line = strdupAtoW(szCommandLine)))
274 goto done;
275
276 r = MsiApplyPatchW(patch_package, install_package, eInstallType, command_line);
277
278 done:
279 msi_free(patch_package);
280 msi_free(install_package);
281 msi_free(command_line);
282
283 return r;
284 }
285
286 static UINT get_patch_product_codes( LPCWSTR szPatchPackage, WCHAR ***product_codes )
287 {
288 MSIHANDLE patch, info = 0;
289 UINT r, type;
290 DWORD size;
291 static WCHAR empty[] = {0};
292 WCHAR *codes = NULL;
293
294 r = MsiOpenDatabaseW( szPatchPackage, MSIDBOPEN_READONLY, &patch );
295 if (r != ERROR_SUCCESS)
296 return r;
297
298 r = MsiGetSummaryInformationW( patch, NULL, 0, &info );
299 if (r != ERROR_SUCCESS)
300 goto done;
301
302 size = 0;
303 r = MsiSummaryInfoGetPropertyW( info, PID_TEMPLATE, &type, NULL, NULL, empty, &size );
304 if (r != ERROR_MORE_DATA || !size || type != VT_LPSTR)
305 {
306 ERR("Failed to read product codes from patch\n");
307 r = ERROR_FUNCTION_FAILED;
308 goto done;
309 }
310
311 codes = msi_alloc( ++size * sizeof(WCHAR) );
312 if (!codes)
313 {
314 r = ERROR_OUTOFMEMORY;
315 goto done;
316 }
317
318 r = MsiSummaryInfoGetPropertyW( info, PID_TEMPLATE, &type, NULL, NULL, codes, &size );
319 if (r == ERROR_SUCCESS)
320 *product_codes = msi_split_string( codes, ';' );
321
322 done:
323 MsiCloseHandle( info );
324 MsiCloseHandle( patch );
325 msi_free( codes );
326 return r;
327 }
328
329 static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWSTR szCommandLine)
330 {
331 UINT i, r = ERROR_FUNCTION_FAILED;
332 DWORD size;
333 LPCWSTR cmd_ptr = szCommandLine;
334 LPWSTR cmd, *codes = NULL;
335 BOOL succeeded = FALSE;
336
337 static const WCHAR fmt[] = {'%','s',' ','P','A','T','C','H','=','"','%','s','"',0};
338 static const WCHAR empty[] = {0};
339
340 if (!szPatchPackage || !szPatchPackage[0])
341 return ERROR_INVALID_PARAMETER;
342
343 if (!szProductCode && (r = get_patch_product_codes( szPatchPackage, &codes )))
344 return r;
345
346 if (!szCommandLine)
347 cmd_ptr = empty;
348
349 size = strlenW(cmd_ptr) + strlenW(fmt) + strlenW(szPatchPackage) + 1;
350 cmd = msi_alloc(size * sizeof(WCHAR));
351 if (!cmd)
352 {
353 msi_free(codes);
354 return ERROR_OUTOFMEMORY;
355 }
356 sprintfW(cmd, fmt, cmd_ptr, szPatchPackage);
357
358 if (szProductCode)
359 r = MsiConfigureProductExW(szProductCode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
360 else
361 {
362 for (i = 0; codes[i]; i++)
363 {
364 r = MsiConfigureProductExW(codes[i], INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
365 if (r == ERROR_SUCCESS)
366 {
367 TRACE("patch applied\n");
368 succeeded = TRUE;
369 }
370 }
371
372 if (succeeded)
373 r = ERROR_SUCCESS;
374 }
375
376 msi_free(cmd);
377 msi_free(codes);
378 return r;
379 }
380
381 UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
382 INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
383 {
384 TRACE("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage),
385 eInstallType, debugstr_w(szCommandLine));
386
387 if (szInstallPackage || eInstallType == INSTALLTYPE_NETWORK_IMAGE ||
388 eInstallType == INSTALLTYPE_SINGLE_INSTANCE)
389 {
390 FIXME("Only reading target products from patch\n");
391 return ERROR_CALL_NOT_IMPLEMENTED;
392 }
393
394 return MSI_ApplyPatchW(szPatchPackage, NULL, szCommandLine);
395 }
396
397 UINT WINAPI MsiApplyMultiplePatchesA(LPCSTR szPatchPackages,
398 LPCSTR szProductCode, LPCSTR szPropertiesList)
399 {
400 LPWSTR patch_packages = NULL;
401 LPWSTR product_code = NULL;
402 LPWSTR properties_list = NULL;
403 UINT r = ERROR_OUTOFMEMORY;
404
405 TRACE("%s %s %s\n", debugstr_a(szPatchPackages), debugstr_a(szProductCode),
406 debugstr_a(szPropertiesList));
407
408 if (!szPatchPackages || !szPatchPackages[0])
409 return ERROR_INVALID_PARAMETER;
410
411 if (!(patch_packages = strdupAtoW(szPatchPackages)))
412 return ERROR_OUTOFMEMORY;
413
414 if (szProductCode && !(product_code = strdupAtoW(szProductCode)))
415 goto done;
416
417 if (szPropertiesList && !(properties_list = strdupAtoW(szPropertiesList)))
418 goto done;
419
420 r = MsiApplyMultiplePatchesW(patch_packages, product_code, properties_list);
421
422 done:
423 msi_free(patch_packages);
424 msi_free(product_code);
425 msi_free(properties_list);
426
427 return r;
428 }
429
430 UINT WINAPI MsiApplyMultiplePatchesW(LPCWSTR szPatchPackages,
431 LPCWSTR szProductCode, LPCWSTR szPropertiesList)
432 {
433 UINT r = ERROR_SUCCESS;
434 LPCWSTR beg, end;
435
436 TRACE("%s %s %s\n", debugstr_w(szPatchPackages), debugstr_w(szProductCode),
437 debugstr_w(szPropertiesList));
438
439 if (!szPatchPackages || !szPatchPackages[0])
440 return ERROR_INVALID_PARAMETER;
441
442 beg = end = szPatchPackages;
443 while (*beg)
444 {
445 DWORD len;
446 LPWSTR patch;
447
448 while (*beg == ' ') beg++;
449 while (*end && *end != ';') end++;
450
451 len = end - beg;
452 while (len && beg[len - 1] == ' ') len--;
453
454 if (!len) return ERROR_INVALID_NAME;
455
456 patch = msi_alloc((len + 1) * sizeof(WCHAR));
457 if (!patch)
458 return ERROR_OUTOFMEMORY;
459
460 memcpy(patch, beg, len * sizeof(WCHAR));
461 patch[len] = '\0';
462
463 r = MSI_ApplyPatchW(patch, szProductCode, szPropertiesList);
464 msi_free(patch);
465
466 if (r != ERROR_SUCCESS || !*end)
467 break;
468
469 beg = ++end;
470 }
471 return r;
472 }
473
474 static void free_patchinfo( DWORD count, MSIPATCHSEQUENCEINFOW *info )
475 {
476 DWORD i;
477 for (i = 0; i < count; i++) msi_free( (WCHAR *)info[i].szPatchData );
478 msi_free( info );
479 }
480
481 static MSIPATCHSEQUENCEINFOW *patchinfoAtoW( DWORD count, const MSIPATCHSEQUENCEINFOA *info )
482 {
483 DWORD i;
484 MSIPATCHSEQUENCEINFOW *ret;
485
486 if (!(ret = msi_alloc( count * sizeof(MSIPATCHSEQUENCEINFOW) ))) return NULL;
487 for (i = 0; i < count; i++)
488 {
489 if (info[i].szPatchData && !(ret[i].szPatchData = strdupAtoW( info[i].szPatchData )))
490 {
491 free_patchinfo( i, ret );
492 return NULL;
493 }
494 ret[i].ePatchDataType = info[i].ePatchDataType;
495 ret[i].dwOrder = info[i].dwOrder;
496 ret[i].uStatus = info[i].uStatus;
497 }
498 return ret;
499 }
500
501 UINT WINAPI MsiDetermineApplicablePatchesA(LPCSTR szProductPackagePath,
502 DWORD cPatchInfo, PMSIPATCHSEQUENCEINFOA pPatchInfo)
503 {
504 UINT i, r;
505 WCHAR *package_path = NULL;
506 MSIPATCHSEQUENCEINFOW *psi;
507
508 TRACE("%s, %u, %p\n", debugstr_a(szProductPackagePath), cPatchInfo, pPatchInfo);
509
510 if (szProductPackagePath && !(package_path = strdupAtoW( szProductPackagePath )))
511 return ERROR_OUTOFMEMORY;
512
513 if (!(psi = patchinfoAtoW( cPatchInfo, pPatchInfo )))
514 {
515 msi_free( package_path );
516 return ERROR_OUTOFMEMORY;
517 }
518 r = MsiDetermineApplicablePatchesW( package_path, cPatchInfo, psi );
519 if (r == ERROR_SUCCESS)
520 {
521 for (i = 0; i < cPatchInfo; i++)
522 {
523 pPatchInfo[i].dwOrder = psi[i].dwOrder;
524 pPatchInfo[i].uStatus = psi[i].uStatus;
525 }
526 }
527 msi_free( package_path );
528 free_patchinfo( cPatchInfo, psi );
529 return r;
530 }
531
532 static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch )
533 {
534 MSISUMMARYINFO *si;
535 MSIDATABASE *patch_db;
536 UINT r;
537
538 r = MSI_OpenDatabaseW( patch, MSIDBOPEN_READONLY, &patch_db );
539 if (r != ERROR_SUCCESS)
540 {
541 WARN("failed to open patch file %s\n", debugstr_w(patch));
542 return r;
543 }
544
545 r = msi_get_suminfo( patch_db->storage, 0, &si );
546 if (r != ERROR_SUCCESS)
547 {
548 msiobj_release( &patch_db->hdr );
549 return ERROR_FUNCTION_FAILED;
550 }
551
552 r = msi_check_patch_applicable( package, si );
553 if (r != ERROR_SUCCESS)
554 TRACE("patch not applicable\n");
555
556 msiobj_release( &patch_db->hdr );
557 msiobj_release( &si->hdr );
558 return r;
559 }
560
561 /* IXMLDOMDocument should be set to XPath mode already */
562 static UINT MSI_ApplicablePatchXML( MSIPACKAGE *package, IXMLDOMDocument *desc )
563 {
564 static const WCHAR queryW[] = {'M','s','i','P','a','t','c','h','/',
565 'T','a','r','g','e','t','P','r','o','d','u','c','t','/',
566 'T','a','r','g','e','t','P','r','o','d','u','c','t','C','o','d','e',0};
567 UINT r = ERROR_FUNCTION_FAILED;
568 IXMLDOMNodeList *list;
569 LPWSTR product_code;
570 IXMLDOMNode *node;
571 HRESULT hr;
572 BSTR s;
573
574 product_code = msi_dup_property( package->db, szProductCode );
575 if (!product_code)
576 {
577 /* FIXME: the property ProductCode should be written into the DB somewhere */
578 ERR("no product code to check\n");
579 return ERROR_SUCCESS;
580 }
581
582 s = SysAllocString(queryW);
583 hr = IXMLDOMDocument_selectNodes( desc, s, &list );
584 SysFreeString(s);
585 if (hr != S_OK)
586 return ERROR_INVALID_PATCH_XML;
587
588 while (IXMLDOMNodeList_nextNode( list, &node ) == S_OK && r != ERROR_SUCCESS)
589 {
590 hr = IXMLDOMNode_get_text( node, &s );
591 IXMLDOMNode_Release( node );
592 if (hr == S_OK)
593 {
594 if (!strcmpW( s, product_code )) r = ERROR_SUCCESS;
595 SysFreeString( s );
596 }
597 }
598 IXMLDOMNodeList_Release( list );
599
600 if (r != ERROR_SUCCESS)
601 TRACE("patch not applicable\n");
602
603 msi_free( product_code );
604 return r;
605 }
606
607 static UINT determine_patch_sequence( MSIPACKAGE *package, DWORD count, MSIPATCHSEQUENCEINFOW *info )
608 {
609 IXMLDOMDocument *desc = NULL;
610 DWORD i;
611
612 if (count > 1)
613 FIXME("patch ordering not supported\n");
614
615 for (i = 0; i < count; i++)
616 {
617 switch (info[i].ePatchDataType)
618 {
619 case MSIPATCH_DATATYPE_PATCHFILE:
620 {
621 if (MSI_ApplicablePatchW( package, info[i].szPatchData ) != ERROR_SUCCESS)
622 {
623 info[i].dwOrder = ~0u;
624 info[i].uStatus = ERROR_PATCH_TARGET_NOT_FOUND;
625 }
626 else
627 {
628 info[i].dwOrder = i;
629 info[i].uStatus = ERROR_SUCCESS;
630 }
631 break;
632 }
633 case MSIPATCH_DATATYPE_XMLPATH:
634 case MSIPATCH_DATATYPE_XMLBLOB:
635 {
636 VARIANT_BOOL b;
637 HRESULT hr;
638 BSTR s;
639
640 if (!desc)
641 {
642 hr = CoCreateInstance( &CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER,
643 &IID_IXMLDOMDocument, (void**)&desc );
644 if (hr != S_OK)
645 {
646 ERR("failed to create DOMDocument30 instance, 0x%08x\n", hr);
647 return ERROR_FUNCTION_FAILED;
648 }
649 }
650
651 s = SysAllocString( info[i].szPatchData );
652 if (info[i].ePatchDataType == MSIPATCH_DATATYPE_XMLPATH)
653 {
654 VARIANT src;
655
656 V_VT(&src) = VT_BSTR;
657 V_BSTR(&src) = s;
658 hr = IXMLDOMDocument_load( desc, src, &b );
659 }
660 else
661 hr = IXMLDOMDocument_loadXML( desc, s, &b );
662 SysFreeString( s );
663 if ( hr != S_OK )
664 {
665 ERR("failed to parse patch description\n");
666 IXMLDOMDocument_Release( desc );
667 break;
668 }
669
670 if (MSI_ApplicablePatchXML( package, desc ) != ERROR_SUCCESS)
671 {
672 info[i].dwOrder = ~0u;
673 info[i].uStatus = ERROR_PATCH_TARGET_NOT_FOUND;
674 }
675 else
676 {
677 info[i].dwOrder = i;
678 info[i].uStatus = ERROR_SUCCESS;
679 }
680 break;
681 }
682 default:
683 {
684 FIXME("unknown patch data type %u\n", info[i].ePatchDataType);
685 info[i].dwOrder = i;
686 info[i].uStatus = ERROR_SUCCESS;
687 break;
688 }
689 }
690
691 TRACE("szPatchData: %s\n", debugstr_w(info[i].szPatchData));
692 TRACE("ePatchDataType: %u\n", info[i].ePatchDataType);
693 TRACE("dwOrder: %u\n", info[i].dwOrder);
694 TRACE("uStatus: %u\n", info[i].uStatus);
695 }
696
697 if (desc) IXMLDOMDocument_Release( desc );
698
699 return ERROR_SUCCESS;
700 }
701
702 UINT WINAPI MsiDetermineApplicablePatchesW(LPCWSTR szProductPackagePath,
703 DWORD cPatchInfo, PMSIPATCHSEQUENCEINFOW pPatchInfo)
704 {
705 UINT r;
706 MSIPACKAGE *package;
707
708 TRACE("%s, %u, %p\n", debugstr_w(szProductPackagePath), cPatchInfo, pPatchInfo);
709
710 r = MSI_OpenPackageW( szProductPackagePath, &package );
711 if (r != ERROR_SUCCESS)
712 {
713 ERR("failed to open package %u\n", r);
714 return r;
715 }
716 r = determine_patch_sequence( package, cPatchInfo, pPatchInfo );
717 msiobj_release( &package->hdr );
718 return r;
719 }
720
721 UINT WINAPI MsiDeterminePatchSequenceA( LPCSTR product, LPCSTR usersid,
722 MSIINSTALLCONTEXT context, DWORD count, PMSIPATCHSEQUENCEINFOA patchinfo )
723 {
724 UINT i, r;
725 WCHAR *productW, *usersidW = NULL;
726 MSIPATCHSEQUENCEINFOW *patchinfoW;
727
728 TRACE("%s, %s, %d, %d, %p\n", debugstr_a(product), debugstr_a(usersid),
729 context, count, patchinfo);
730
731 if (!product) return ERROR_INVALID_PARAMETER;
732 if (!(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
733 if (usersid && !(usersidW = strdupAtoW( usersid )))
734 {
735 msi_free( productW );
736 return ERROR_OUTOFMEMORY;
737 }
738 if (!(patchinfoW = patchinfoAtoW( count, patchinfo )))
739 {
740 msi_free( productW );
741 msi_free( usersidW );
742 return ERROR_OUTOFMEMORY;
743 }
744 r = MsiDeterminePatchSequenceW( productW, usersidW, context, count, patchinfoW );
745 if (r == ERROR_SUCCESS)
746 {
747 for (i = 0; i < count; i++)
748 {
749 patchinfo[i].dwOrder = patchinfoW[i].dwOrder;
750 patchinfo[i].uStatus = patchinfoW[i].uStatus;
751 }
752 }
753 msi_free( productW );
754 msi_free( usersidW );
755 free_patchinfo( count, patchinfoW );
756 return r;
757 }
758
759 static UINT open_package( const WCHAR *product, const WCHAR *usersid,
760 MSIINSTALLCONTEXT context, MSIPACKAGE **package )
761 {
762 UINT r;
763 HKEY props;
764 WCHAR *localpath, sourcepath[MAX_PATH], filename[MAX_PATH];
765
766 r = MSIREG_OpenInstallProps( product, context, usersid, &props, FALSE );
767 if (r != ERROR_SUCCESS) return ERROR_BAD_CONFIGURATION;
768
769 if ((localpath = msi_reg_get_val_str( props, szLocalPackage )))
770 {
771 strcpyW( sourcepath, localpath );
772 msi_free( localpath );
773 }
774 RegCloseKey( props );
775 if (!localpath || GetFileAttributesW( sourcepath ) == INVALID_FILE_ATTRIBUTES)
776 {
777 DWORD sz = sizeof(sourcepath);
778 MsiSourceListGetInfoW( product, usersid, context, MSICODE_PRODUCT,
779 INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz );
780 sz = sizeof(filename);
781 MsiSourceListGetInfoW( product, usersid, context, MSICODE_PRODUCT,
782 INSTALLPROPERTY_PACKAGENAMEW, filename, &sz );
783 strcatW( sourcepath, filename );
784 }
785 if (GetFileAttributesW( sourcepath ) == INVALID_FILE_ATTRIBUTES)
786 return ERROR_INSTALL_SOURCE_ABSENT;
787
788 return MSI_OpenPackageW( sourcepath, package );
789 }
790
791 UINT WINAPI MsiDeterminePatchSequenceW( LPCWSTR product, LPCWSTR usersid,
792 MSIINSTALLCONTEXT context, DWORD count, PMSIPATCHSEQUENCEINFOW patchinfo )
793 {
794 UINT r;
795 MSIPACKAGE *package;
796
797 TRACE("%s, %s, %d, %d, %p\n", debugstr_w(product), debugstr_w(usersid),
798 context, count, patchinfo);
799
800 if (!product) return ERROR_INVALID_PARAMETER;
801 r = open_package( product, usersid, context, &package );
802 if (r != ERROR_SUCCESS) return r;
803
804 r = determine_patch_sequence( package, count, patchinfo );
805 msiobj_release( &package->hdr );
806 return r;
807 }
808
809 UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
810 INSTALLSTATE eInstallState, LPCWSTR szCommandLine)
811 {
812 MSIPACKAGE* package = NULL;
813 MSIINSTALLCONTEXT context;
814 UINT r;
815 DWORD sz;
816 WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
817 LPWSTR commandline;
818
819 static const WCHAR szInstalled[] = {
820 ' ','I','n','s','t','a','l','l','e','d','=','1',0};
821 static const WCHAR szMaxInstallLevel[] = {
822 ' ','I','N','S','T','A','L','L','L','E','V','E','L','=','3','2','7','6','7',0};
823 static const WCHAR szRemoveAll[] = {
824 ' ','R','E','M','O','V','E','=','A','L','L',0};
825 static const WCHAR szMachine[] = {
826 ' ','A','L','L','U','S','E','R','S','=','1',0};
827
828 TRACE("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState,
829 debugstr_w(szCommandLine));
830
831 if (!szProduct || lstrlenW(szProduct) != GUID_SIZE - 1)
832 return ERROR_INVALID_PARAMETER;
833
834 if (eInstallState == INSTALLSTATE_ADVERTISED ||
835 eInstallState == INSTALLSTATE_SOURCE)
836 {
837 FIXME("State %d not implemented\n", eInstallState);
838 return ERROR_CALL_NOT_IMPLEMENTED;
839 }
840
841 r = msi_locate_product(szProduct, &context);
842 if (r != ERROR_SUCCESS)
843 return r;
844
845 r = open_package(szProduct, NULL, context, &package);
846 if (r != ERROR_SUCCESS)
847 return r;
848
849 sz = lstrlenW(szInstalled) + 1;
850
851 if (szCommandLine)
852 sz += lstrlenW(szCommandLine);
853
854 if (eInstallState != INSTALLSTATE_DEFAULT)
855 sz += lstrlenW(szMaxInstallLevel);
856
857 if (eInstallState == INSTALLSTATE_ABSENT)
858 sz += lstrlenW(szRemoveAll);
859
860 if (context == MSIINSTALLCONTEXT_MACHINE)
861 sz += lstrlenW(szMachine);
862
863 commandline = msi_alloc(sz * sizeof(WCHAR));
864 if (!commandline)
865 {
866 r = ERROR_OUTOFMEMORY;
867 goto end;
868 }
869
870 commandline[0] = 0;
871 if (szCommandLine)
872 lstrcpyW(commandline,szCommandLine);
873
874 if (eInstallState != INSTALLSTATE_DEFAULT)
875 lstrcatW(commandline, szMaxInstallLevel);
876
877 if (eInstallState == INSTALLSTATE_ABSENT)
878 lstrcatW(commandline, szRemoveAll);
879
880 if (context == MSIINSTALLCONTEXT_MACHINE)
881 lstrcatW(commandline, szMachine);
882
883 sz = sizeof(sourcepath);
884 MsiSourceListGetInfoW(szProduct, NULL, context, MSICODE_PRODUCT,
885 INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
886
887 sz = sizeof(filename);
888 MsiSourceListGetInfoW(szProduct, NULL, context, MSICODE_PRODUCT,
889 INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
890
891 strcatW(sourcepath, filename);
892
893 r = MSI_InstallPackage( package, sourcepath, commandline );
894
895 msi_free(commandline);
896
897 end:
898 msiobj_release( &package->hdr );
899
900 return r;
901 }
902
903 UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel,
904 INSTALLSTATE eInstallState, LPCSTR szCommandLine)
905 {
906 LPWSTR szwProduct = NULL;
907 LPWSTR szwCommandLine = NULL;
908 UINT r = ERROR_OUTOFMEMORY;
909
910 if( szProduct )
911 {
912 szwProduct = strdupAtoW( szProduct );
913 if( !szwProduct )
914 goto end;
915 }
916
917 if( szCommandLine)
918 {
919 szwCommandLine = strdupAtoW( szCommandLine );
920 if( !szwCommandLine)
921 goto end;
922 }
923
924 r = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState,
925 szwCommandLine );
926 end:
927 msi_free( szwProduct );
928 msi_free( szwCommandLine);
929
930 return r;
931 }
932
933 UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel,
934 INSTALLSTATE eInstallState)
935 {
936 LPWSTR szwProduct = NULL;
937 UINT r;
938
939 TRACE("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
940
941 if( szProduct )
942 {
943 szwProduct = strdupAtoW( szProduct );
944 if( !szwProduct )
945 return ERROR_OUTOFMEMORY;
946 }
947
948 r = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState );
949 msi_free( szwProduct );
950
951 return r;
952 }
953
954 UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel,
955 INSTALLSTATE eInstallState)
956 {
957 return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL);
958 }
959
960 UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
961 {
962 LPWSTR szwComponent = NULL;
963 UINT r;
964 WCHAR szwBuffer[GUID_SIZE];
965
966 TRACE("%s %p\n", debugstr_a(szComponent), szBuffer);
967
968 if( szComponent )
969 {
970 szwComponent = strdupAtoW( szComponent );
971 if( !szwComponent )
972 return ERROR_OUTOFMEMORY;
973 }
974
975 *szwBuffer = '\0';
976 r = MsiGetProductCodeW( szwComponent, szwBuffer );
977
978 if(*szwBuffer)
979 WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL);
980
981 msi_free( szwComponent );
982
983 return r;
984 }
985
986 UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
987 {
988 UINT rc, index;
989 HKEY compkey, prodkey;
990 WCHAR squashed_comp[SQUASHED_GUID_SIZE], squashed_prod[SQUASHED_GUID_SIZE];
991 DWORD sz = sizeof(squashed_prod)/sizeof(squashed_prod[0]);
992
993 TRACE("%s %p\n", debugstr_w(szComponent), szBuffer);
994
995 if (!szComponent || !*szComponent)
996 return ERROR_INVALID_PARAMETER;
997
998 if (!squash_guid( szComponent, squashed_comp ))
999 return ERROR_INVALID_PARAMETER;
1000
1001 if (MSIREG_OpenUserDataComponentKey(szComponent, NULL, &compkey, FALSE) != ERROR_SUCCESS &&
1002 MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &compkey, FALSE) != ERROR_SUCCESS)
1003 {
1004 return ERROR_UNKNOWN_COMPONENT;
1005 }
1006
1007 rc = RegEnumValueW( compkey, 0, squashed_prod, &sz, NULL, NULL, NULL, NULL );
1008 if (rc != ERROR_SUCCESS)
1009 {
1010 RegCloseKey(compkey);
1011 return ERROR_UNKNOWN_COMPONENT;
1012 }
1013
1014 /* check simple case, only one product */
1015 rc = RegEnumValueW( compkey, 1, squashed_prod, &sz, NULL, NULL, NULL, NULL );
1016 if (rc == ERROR_NO_MORE_ITEMS)
1017 {
1018 rc = ERROR_SUCCESS;
1019 goto done;
1020 }
1021
1022 index = 0;
1023 while ((rc = RegEnumValueW( compkey, index, squashed_prod, &sz, NULL, NULL, NULL, NULL )) !=
1024 ERROR_NO_MORE_ITEMS)
1025 {
1026 index++;
1027 sz = GUID_SIZE;
1028 unsquash_guid( squashed_prod, szBuffer );
1029
1030 if (MSIREG_OpenProductKey(szBuffer, NULL,
1031 MSIINSTALLCONTEXT_USERMANAGED,
1032 &prodkey, FALSE) == ERROR_SUCCESS ||
1033 MSIREG_OpenProductKey(szBuffer, NULL,
1034 MSIINSTALLCONTEXT_USERUNMANAGED,
1035 &prodkey, FALSE) == ERROR_SUCCESS ||
1036 MSIREG_OpenProductKey(szBuffer, NULL,
1037 MSIINSTALLCONTEXT_MACHINE,
1038 &prodkey, FALSE) == ERROR_SUCCESS)
1039 {
1040 RegCloseKey(prodkey);
1041 rc = ERROR_SUCCESS;
1042 goto done;
1043 }
1044 }
1045
1046 rc = ERROR_INSTALL_FAILURE;
1047
1048 done:
1049 RegCloseKey(compkey);
1050 unsquash_guid( squashed_prod, szBuffer );
1051 return rc;
1052 }
1053
1054 static WCHAR *reg_get_value( HKEY hkey, const WCHAR *name, DWORD *type )
1055 {
1056 LONG res;
1057
1058 if ((res = RegQueryValueExW( hkey, name, NULL, type, NULL, NULL )) != ERROR_SUCCESS) return NULL;
1059
1060 if (*type == REG_SZ) return msi_reg_get_val_str( hkey, name );
1061 if (*type == REG_DWORD)
1062 {
1063 static const WCHAR fmt[] = {'%','u',0};
1064 WCHAR temp[11];
1065 DWORD val;
1066
1067 if (!msi_reg_get_val_dword( hkey, name, &val )) return NULL;
1068 sprintfW( temp, fmt, val );
1069 return strdupW( temp );
1070 }
1071
1072 ERR( "unhandled value type %u\n", *type );
1073 return NULL;
1074 }
1075
1076 static UINT MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
1077 awstring *szValue, LPDWORD pcchValueBuf)
1078 {
1079 static WCHAR empty[] = {0};
1080 static const WCHAR sourcelist[] = {'S','o','u','r','c','e','L','i','s','t',0};
1081 static const WCHAR display_name[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
1082 static const WCHAR display_version[] = {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
1083 static const WCHAR assignment[] = {'A','s','s','i','g','n','m','e','n','t',0};
1084 MSIINSTALLCONTEXT context = MSIINSTALLCONTEXT_USERUNMANAGED;
1085 UINT r = ERROR_UNKNOWN_PROPERTY;
1086 HKEY prodkey, userdata, source;
1087 WCHAR *val = NULL, squashed_pc[SQUASHED_GUID_SIZE], packagecode[GUID_SIZE];
1088 BOOL badconfig = FALSE;
1089 LONG res;
1090 DWORD type = REG_NONE;
1091
1092 TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1093 debugstr_w(szAttribute), szValue, pcchValueBuf);
1094
1095 if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szAttribute)
1096 return ERROR_INVALID_PARAMETER;
1097
1098 if (!squash_guid( szProduct, squashed_pc ))
1099 return ERROR_INVALID_PARAMETER;
1100
1101 if ((r = MSIREG_OpenProductKey(szProduct, NULL,
1102 MSIINSTALLCONTEXT_USERMANAGED,
1103 &prodkey, FALSE)) != ERROR_SUCCESS &&
1104 (r = MSIREG_OpenProductKey(szProduct, NULL,
1105 MSIINSTALLCONTEXT_USERUNMANAGED,
1106 &prodkey, FALSE)) != ERROR_SUCCESS &&
1107 (r = MSIREG_OpenProductKey(szProduct, NULL,
1108 MSIINSTALLCONTEXT_MACHINE,
1109 &prodkey, FALSE)) == ERROR_SUCCESS)
1110 {
1111 context = MSIINSTALLCONTEXT_MACHINE;
1112 }
1113
1114 if (!strcmpW( szAttribute, INSTALLPROPERTY_HELPLINKW ) ||
1115 !strcmpW( szAttribute, INSTALLPROPERTY_HELPTELEPHONEW ) ||
1116 !strcmpW( szAttribute, INSTALLPROPERTY_INSTALLDATEW ) ||
1117 !strcmpW( szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ) ||
1118 !strcmpW( szAttribute, INSTALLPROPERTY_INSTALLLOCATIONW ) ||
1119 !strcmpW( szAttribute, INSTALLPROPERTY_INSTALLSOURCEW ) ||
1120 !strcmpW( szAttribute, INSTALLPROPERTY_LOCALPACKAGEW ) ||
1121 !strcmpW( szAttribute, INSTALLPROPERTY_PUBLISHERW ) ||
1122 !strcmpW( szAttribute, INSTALLPROPERTY_URLINFOABOUTW ) ||
1123 !strcmpW( szAttribute, INSTALLPROPERTY_URLUPDATEINFOW ) ||
1124 !strcmpW( szAttribute, INSTALLPROPERTY_VERSIONMINORW ) ||
1125 !strcmpW( szAttribute, INSTALLPROPERTY_VERSIONMAJORW ) ||
1126 !strcmpW( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ) ||
1127 !strcmpW( szAttribute, INSTALLPROPERTY_PRODUCTIDW ) ||
1128 !strcmpW( szAttribute, INSTALLPROPERTY_REGCOMPANYW ) ||
1129 !strcmpW( szAttribute, INSTALLPROPERTY_REGOWNERW ))
1130 {
1131 if (!prodkey)
1132 {
1133 r = ERROR_UNKNOWN_PRODUCT;
1134 goto done;
1135 }
1136 if (MSIREG_OpenInstallProps(szProduct, context, NULL, &userdata, FALSE))
1137 {
1138 r = ERROR_UNKNOWN_PROPERTY;
1139 goto done;
1140 }
1141
1142 if (!strcmpW( szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ))
1143 szAttribute = display_name;
1144 else if (!strcmpW( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ))
1145 szAttribute = display_version;
1146
1147 val = reg_get_value(userdata, szAttribute, &type);
1148 if (!val)
1149 val = empty;
1150 RegCloseKey(userdata);
1151 }
1152 else if (!strcmpW( szAttribute, INSTALLPROPERTY_INSTANCETYPEW ) ||
1153 !strcmpW( szAttribute, INSTALLPROPERTY_TRANSFORMSW ) ||
1154 !strcmpW( szAttribute, INSTALLPROPERTY_LANGUAGEW ) ||
1155 !strcmpW( szAttribute, INSTALLPROPERTY_PRODUCTNAMEW ) ||
1156 !strcmpW( szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW ) ||
1157 !strcmpW( szAttribute, INSTALLPROPERTY_PACKAGECODEW ) ||
1158 !strcmpW( szAttribute, INSTALLPROPERTY_VERSIONW ) ||
1159 !strcmpW( szAttribute, INSTALLPROPERTY_PRODUCTICONW ) ||
1160 !strcmpW( szAttribute, INSTALLPROPERTY_PACKAGENAMEW ) ||
1161 !strcmpW( szAttribute, INSTALLPROPERTY_AUTHORIZED_LUA_APPW ))
1162 {
1163 if (!prodkey)
1164 {
1165 r = ERROR_UNKNOWN_PRODUCT;
1166 goto done;
1167 }
1168
1169 if (!strcmpW( szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW ))
1170 szAttribute = assignment;
1171
1172 if (!strcmpW( szAttribute, INSTALLPROPERTY_PACKAGENAMEW ))
1173 {
1174 res = RegOpenKeyW(prodkey, sourcelist, &source);
1175 if (res != ERROR_SUCCESS)
1176 {
1177 r = ERROR_UNKNOWN_PRODUCT;
1178 goto done;
1179 }
1180
1181 val = reg_get_value(source, szAttribute, &type);
1182 if (!val)
1183 val = empty;
1184
1185 RegCloseKey(source);
1186 }
1187 else
1188 {
1189 val = reg_get_value(prodkey, szAttribute, &type);
1190 if (!val)
1191 val = empty;
1192 }
1193
1194 if (val != empty && type != REG_DWORD &&
1195 !strcmpW( szAttribute, INSTALLPROPERTY_PACKAGECODEW ))
1196 {
1197 if (lstrlenW( val ) != SQUASHED_GUID_SIZE - 1)
1198 badconfig = TRUE;
1199 else
1200 {
1201 unsquash_guid(val, packagecode);
1202 msi_free(val);
1203 val = strdupW(packagecode);
1204 }
1205 }
1206 }
1207
1208 if (!val)
1209 {
1210 r = ERROR_UNKNOWN_PROPERTY;
1211 goto done;
1212 }
1213
1214 if (pcchValueBuf)
1215 {
1216 int len = strlenW( val );
1217
1218 /* If szBuffer (szValue->str) is NULL, there's no need to copy the value
1219 * out. Also, *pcchValueBuf may be uninitialized in this case, so we
1220 * can't rely on its value.
1221 */
1222 if (szValue->str.a || szValue->str.w)
1223 {
1224 DWORD size = *pcchValueBuf;
1225 if (len < size)
1226 r = msi_strcpy_to_awstring( val, len, szValue, &size );
1227 else
1228 r = ERROR_MORE_DATA;
1229 }
1230
1231 if (!badconfig)
1232 *pcchValueBuf = len;
1233 }
1234
1235 if (badconfig)
1236 r = ERROR_BAD_CONFIGURATION;
1237
1238 if (val != empty)
1239 msi_free(val);
1240
1241 done:
1242 RegCloseKey(prodkey);
1243 return r;
1244 }
1245
1246 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
1247 LPSTR szBuffer, LPDWORD pcchValueBuf)
1248 {
1249 LPWSTR szwProduct, szwAttribute = NULL;
1250 UINT r = ERROR_OUTOFMEMORY;
1251 awstring buffer;
1252
1253 TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
1254 szBuffer, pcchValueBuf);
1255
1256 szwProduct = strdupAtoW( szProduct );
1257 if( szProduct && !szwProduct )
1258 goto end;
1259
1260 szwAttribute = strdupAtoW( szAttribute );
1261 if( szAttribute && !szwAttribute )
1262 goto end;
1263
1264 buffer.unicode = FALSE;
1265 buffer.str.a = szBuffer;
1266
1267 r = MSI_GetProductInfo( szwProduct, szwAttribute,
1268 &buffer, pcchValueBuf );
1269
1270 end:
1271 msi_free( szwProduct );
1272 msi_free( szwAttribute );
1273
1274 return r;
1275 }
1276
1277 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
1278 LPWSTR szBuffer, LPDWORD pcchValueBuf)
1279 {
1280 awstring buffer;
1281
1282 TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szAttribute),
1283 szBuffer, pcchValueBuf);
1284
1285 buffer.unicode = TRUE;
1286 buffer.str.w = szBuffer;
1287
1288 return MSI_GetProductInfo( szProduct, szAttribute,
1289 &buffer, pcchValueBuf );
1290 }
1291
1292 UINT WINAPI MsiGetProductInfoExA(LPCSTR szProductCode, LPCSTR szUserSid,
1293 MSIINSTALLCONTEXT dwContext, LPCSTR szProperty,
1294 LPSTR szValue, LPDWORD pcchValue)
1295 {
1296 LPWSTR product = NULL;
1297 LPWSTR usersid = NULL;
1298 LPWSTR property = NULL;
1299 LPWSTR value = NULL;
1300 DWORD len = 0;
1301 UINT r;
1302
1303 TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_a(szProductCode),
1304 debugstr_a(szUserSid), dwContext, debugstr_a(szProperty),
1305 szValue, pcchValue);
1306
1307 if (szValue && !pcchValue)
1308 return ERROR_INVALID_PARAMETER;
1309
1310 if (szProductCode) product = strdupAtoW(szProductCode);
1311 if (szUserSid) usersid = strdupAtoW(szUserSid);
1312 if (szProperty) property = strdupAtoW(szProperty);
1313
1314 r = MsiGetProductInfoExW(product, usersid, dwContext, property,
1315 NULL, &len);
1316 if (r != ERROR_SUCCESS)
1317 goto done;
1318
1319 value = msi_alloc(++len * sizeof(WCHAR));
1320 if (!value)
1321 {
1322 r = ERROR_OUTOFMEMORY;
1323 goto done;
1324 }
1325
1326 r = MsiGetProductInfoExW(product, usersid, dwContext, property,
1327 value, &len);
1328 if (r != ERROR_SUCCESS)
1329 goto done;
1330
1331 if (!pcchValue)
1332 goto done;
1333
1334 len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
1335 if (*pcchValue >= len)
1336 WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
1337 else if (szValue)
1338 {
1339 r = ERROR_MORE_DATA;
1340 if (*pcchValue > 0)
1341 *szValue = '\0';
1342 }
1343
1344 if (*pcchValue <= len || !szValue)
1345 len = len * sizeof(WCHAR) - 1;
1346
1347 *pcchValue = len - 1;
1348
1349 done:
1350 msi_free(product);
1351 msi_free(usersid);
1352 msi_free(property);
1353 msi_free(value);
1354
1355 return r;
1356 }
1357
1358 static UINT msi_copy_outval(LPWSTR val, LPWSTR out, LPDWORD size)
1359 {
1360 UINT r = ERROR_SUCCESS;
1361
1362 if (!val)
1363 return ERROR_UNKNOWN_PROPERTY;
1364
1365 if (out)
1366 {
1367 if (strlenW(val) >= *size)
1368 {
1369 r = ERROR_MORE_DATA;
1370 if (*size > 0)
1371 *out = '\0';
1372 }
1373 else
1374 lstrcpyW(out, val);
1375 }
1376
1377 if (size)
1378 *size = lstrlenW(val);
1379
1380 return r;
1381 }
1382
1383 UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
1384 MSIINSTALLCONTEXT dwContext, LPCWSTR szProperty,
1385 LPWSTR szValue, LPDWORD pcchValue)
1386 {
1387 static const WCHAR five[] = {'5',0};
1388 static const WCHAR displayname[] = {
1389 'D','i','s','p','l','a','y','N','a','m','e',0};
1390 static const WCHAR displayversion[] = {
1391 'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
1392 static const WCHAR managed_local_package[] = {
1393 'M','a','n','a','g','e','d','L','o','c','a','l',
1394 'P','a','c','k','a','g','e',0};
1395 WCHAR *val = NULL, squashed_pc[SQUASHED_GUID_SIZE];
1396 LPCWSTR package = NULL;
1397 HKEY props = NULL, prod, classes = NULL, managed, hkey = NULL;
1398 DWORD type;
1399 UINT r = ERROR_UNKNOWN_PRODUCT;
1400
1401 TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_w(szProductCode),
1402 debugstr_w(szUserSid), dwContext, debugstr_w(szProperty),
1403 szValue, pcchValue);
1404
1405 if (!szProductCode || !squash_guid( szProductCode, squashed_pc ))
1406 return ERROR_INVALID_PARAMETER;
1407
1408 if (szValue && !pcchValue)
1409 return ERROR_INVALID_PARAMETER;
1410
1411 if (dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
1412 dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
1413 dwContext != MSIINSTALLCONTEXT_MACHINE)
1414 return ERROR_INVALID_PARAMETER;
1415
1416 if (!szProperty || !*szProperty)
1417 return ERROR_INVALID_PARAMETER;
1418
1419 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
1420 return ERROR_INVALID_PARAMETER;
1421
1422 /* FIXME: dwContext is provided, no need to search for it */
1423 MSIREG_OpenProductKey(szProductCode, NULL,MSIINSTALLCONTEXT_USERMANAGED,
1424 &managed, FALSE);
1425 MSIREG_OpenProductKey(szProductCode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1426 &prod, FALSE);
1427
1428 MSIREG_OpenInstallProps(szProductCode, dwContext, NULL, &props, FALSE);
1429
1430 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
1431 {
1432 package = INSTALLPROPERTY_LOCALPACKAGEW;
1433
1434 if (!props && !prod)
1435 goto done;
1436 }
1437 else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1438 {
1439 package = managed_local_package;
1440
1441 if (!props && !managed)
1442 goto done;
1443 }
1444 else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1445 {
1446 package = INSTALLPROPERTY_LOCALPACKAGEW;
1447 MSIREG_OpenProductKey(szProductCode, NULL, dwContext, &classes, FALSE);
1448
1449 if (!props && !classes)
1450 goto done;
1451 }
1452
1453 if (!strcmpW( szProperty, INSTALLPROPERTY_HELPLINKW ) ||
1454 !strcmpW( szProperty, INSTALLPROPERTY_HELPTELEPHONEW ) ||
1455 !strcmpW( szProperty, INSTALLPROPERTY_INSTALLDATEW ) ||
1456 !strcmpW( szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ) ||
1457 !strcmpW( szProperty, INSTALLPROPERTY_INSTALLLOCATIONW ) ||
1458 !strcmpW( szProperty, INSTALLPROPERTY_INSTALLSOURCEW ) ||
1459 !strcmpW( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ) ||
1460 !strcmpW( szProperty, INSTALLPROPERTY_PUBLISHERW ) ||
1461 !strcmpW( szProperty, INSTALLPROPERTY_URLINFOABOUTW ) ||
1462 !strcmpW( szProperty, INSTALLPROPERTY_URLUPDATEINFOW ) ||
1463 !strcmpW( szProperty, INSTALLPROPERTY_VERSIONMINORW ) ||
1464 !strcmpW( szProperty, INSTALLPROPERTY_VERSIONMAJORW ) ||
1465 !strcmpW( szProperty, INSTALLPROPERTY_VERSIONSTRINGW ) ||
1466 !strcmpW( szProperty, INSTALLPROPERTY_PRODUCTIDW ) ||
1467 !strcmpW( szProperty, INSTALLPROPERTY_REGCOMPANYW ) ||
1468 !strcmpW( szProperty, INSTALLPROPERTY_REGOWNERW ) ||
1469 !strcmpW( szProperty, INSTALLPROPERTY_INSTANCETYPEW ))
1470 {
1471 val = reg_get_value(props, package, &type);
1472 if (!val)
1473 {
1474 if (prod || classes)
1475 r = ERROR_UNKNOWN_PROPERTY;
1476
1477 goto done;
1478 }
1479
1480 msi_free(val);
1481
1482 if (!strcmpW( szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ))
1483 szProperty = displayname;
1484 else if (!strcmpW( szProperty, INSTALLPROPERTY_VERSIONSTRINGW ))
1485 szProperty = displayversion;
1486
1487 val = reg_get_value(props, szProperty, &type);
1488 if (!val)
1489 val = strdupW(szEmpty);
1490
1491 r = msi_copy_outval(val, szValue, pcchValue);
1492 }
1493 else if (!strcmpW( szProperty, INSTALLPROPERTY_TRANSFORMSW ) ||
1494 !strcmpW( szProperty, INSTALLPROPERTY_LANGUAGEW ) ||
1495 !strcmpW( szProperty, INSTALLPROPERTY_PRODUCTNAMEW ) ||
1496 !strcmpW( szProperty, INSTALLPROPERTY_PACKAGECODEW ) ||
1497 !strcmpW( szProperty, INSTALLPROPERTY_VERSIONW ) ||
1498 !strcmpW( szProperty, INSTALLPROPERTY_PRODUCTICONW ) ||
1499 !strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW ) ||
1500 !strcmpW( szProperty, INSTALLPROPERTY_AUTHORIZED_LUA_APPW ))
1501 {
1502 if (!prod && !classes)
1503 goto done;
1504
1505 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
1506 hkey = prod;
1507 else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1508 hkey = managed;
1509 else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1510 hkey = classes;
1511
1512 val = reg_get_value(hkey, szProperty, &type);
1513 if (!val)
1514 val = strdupW(szEmpty);
1515
1516 r = msi_copy_outval(val, szValue, pcchValue);
1517 }
1518 else if (!strcmpW( szProperty, INSTALLPROPERTY_PRODUCTSTATEW ))
1519 {
1520 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1521 {
1522 if (props)
1523 {
1524 val = reg_get_value(props, package, &type);
1525 if (!val)
1526 goto done;
1527
1528 msi_free(val);
1529 val = strdupW(five);
1530 }
1531 else
1532 val = strdupW(szOne);
1533
1534 r = msi_copy_outval(val, szValue, pcchValue);
1535 goto done;
1536 }
1537 else if (props && (val = reg_get_value(props, package, &type)))
1538 {
1539 msi_free(val);
1540 val = strdupW(five);
1541 r = msi_copy_outval(val, szValue, pcchValue);
1542 goto done;
1543 }
1544
1545 if (prod || managed)
1546 val = strdupW(szOne);
1547 else
1548 goto done;
1549
1550 r = msi_copy_outval(val, szValue, pcchValue);
1551 }
1552 else if (!strcmpW( szProperty, INSTALLPROPERTY_ASSIGNMENTTYPEW ))
1553 {
1554 if (!prod && !classes)
1555 goto done;
1556
1557 /* FIXME */
1558 val = strdupW(szEmpty);
1559 r = msi_copy_outval(val, szValue, pcchValue);
1560 }
1561 else
1562 r = ERROR_UNKNOWN_PROPERTY;
1563
1564 done:
1565 RegCloseKey(props);
1566 RegCloseKey(prod);
1567 RegCloseKey(managed);
1568 RegCloseKey(classes);
1569 msi_free(val);
1570
1571 return r;
1572 }
1573
1574 UINT WINAPI MsiGetPatchFileListA(LPCSTR szProductCode, LPCSTR szPatchList,
1575 LPDWORD pcFiles, MSIHANDLE **pphFileRecords)
1576 {
1577 FIXME("(%s, %s, %p, %p) stub!\n", debugstr_a(szProductCode),
1578 debugstr_a(szPatchList), pcFiles, pphFileRecords);
1579 return ERROR_FUNCTION_FAILED;
1580 }
1581
1582 UINT WINAPI MsiGetPatchFileListW(LPCWSTR szProductCode, LPCWSTR szPatchList,
1583 LPDWORD pcFiles, MSIHANDLE **pphFileRecords)
1584 {
1585 FIXME("(%s, %s, %p, %p) stub!\n", debugstr_w(szProductCode),
1586 debugstr_w(szPatchList), pcFiles, pphFileRecords);
1587 return ERROR_FUNCTION_FAILED;
1588 }
1589
1590 UINT WINAPI MsiGetPatchInfoExA(LPCSTR szPatchCode, LPCSTR szProductCode,
1591 LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1592 LPCSTR szProperty, LPSTR lpValue, DWORD *pcchValue)
1593 {
1594 LPWSTR patch = NULL, product = NULL, usersid = NULL;
1595 LPWSTR property = NULL, val = NULL;
1596 DWORD len;
1597 UINT r;
1598
1599 TRACE("(%s, %s, %s, %d, %s, %p, %p)\n", debugstr_a(szPatchCode),
1600 debugstr_a(szProductCode), debugstr_a(szUserSid), dwContext,
1601 debugstr_a(szProperty), lpValue, pcchValue);
1602
1603 if (lpValue && !pcchValue)
1604 return ERROR_INVALID_PARAMETER;
1605
1606 if (szPatchCode) patch = strdupAtoW(szPatchCode);
1607 if (szProductCode) product = strdupAtoW(szProductCode);
1608 if (szUserSid) usersid = strdupAtoW(szUserSid);
1609 if (szProperty) property = strdupAtoW(szProperty);
1610
1611 len = 0;
1612 r = MsiGetPatchInfoExW(patch, product, usersid, dwContext, property,
1613 NULL, &len);
1614 if (r != ERROR_SUCCESS)
1615 goto done;
1616
1617 val = msi_alloc(++len * sizeof(WCHAR));
1618 if (!val)
1619 {
1620 r = ERROR_OUTOFMEMORY;
1621 goto done;
1622 }
1623
1624 r = MsiGetPatchInfoExW(patch, product, usersid, dwContext, property,
1625 val, &len);
1626 if (r != ERROR_SUCCESS || !pcchValue)
1627 goto done;
1628
1629 if (lpValue)
1630 WideCharToMultiByte(CP_ACP, 0, val, -1, lpValue,
1631 *pcchValue - 1, NULL, NULL);
1632
1633 len = lstrlenW(val);
1634 if ((*val && *pcchValue < len + 1) || !lpValue)
1635 {
1636 if (lpValue)
1637 {
1638 r = ERROR_MORE_DATA;
1639 lpValue[*pcchValue - 1] = '\0';
1640 }
1641
1642 *pcchValue = len * sizeof(WCHAR);
1643 }
1644 else
1645 *pcchValue = len;
1646
1647 done:
1648 msi_free(val);
1649 msi_free(patch);
1650 msi_free(product);
1651 msi_free(usersid);
1652 msi_free(property);
1653
1654 return r;
1655 }
1656
1657 UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode,
1658 LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1659 LPCWSTR szProperty, LPWSTR lpValue, DWORD *pcchValue)
1660 {
1661 static const WCHAR szManagedPackage[] =
1662 {'M','a','n','a','g','e','d','L','o','c','a','l','P','a','c','k','a','g','e',0};
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;
1668 UINT r = ERROR_UNKNOWN_PRODUCT;
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 && !strcmpW( szUserSid, szLocalSid ))
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
1707 r = ERROR_UNKNOWN_PATCH;
1708
1709 res = RegOpenKeyExW(udprod, szPatches, 0, KEY_WOW64_64KEY|KEY_READ, &patches);
1710 if (res != ERROR_SUCCESS)
1711 goto done;
1712
1713 res = RegOpenKeyExW( patches, squashed_patch, 0, KEY_WOW64_64KEY|KEY_READ, &patch );
1714 if (res != ERROR_SUCCESS)
1715 goto done;
1716
1717 if (!strcmpW( szProperty, INSTALLPROPERTY_TRANSFORMSW ))
1718 {
1719 if (MSIREG_OpenProductKey(szProductCode, NULL, dwContext,
1720 &prod, FALSE) != ERROR_SUCCESS)
1721 goto done;
1722
1723 res = RegOpenKeyExW(prod, szPatches, 0, KEY_WOW64_64KEY|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 (!strcmpW( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ))
1737 {
1738 if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1739 szProperty = szManagedPackage;
1740 datakey = udpatch;
1741 }
1742 else if (!strcmpW( szProperty, INSTALLPROPERTY_INSTALLDATEW ))
1743 {
1744 datakey = patch;
1745 szProperty = szInstalled;
1746 }
1747 else if (!strcmpW( szProperty, INSTALLPROPERTY_UNINSTALLABLEW ) ||
1748 !strcmpW( szProperty, INSTALLPROPERTY_PATCHSTATEW ) ||
1749 !strcmpW( szProperty, INSTALLPROPERTY_DISPLAYNAMEW ) ||
1750 !strcmpW( szProperty, INSTALLPROPERTY_MOREINFOURLW ))
1751 {
1752 datakey = patch;
1753 }
1754 else
1755 {
1756 r = ERROR_UNKNOWN_PROPERTY;
1757 goto done;
1758 }
1759 }
1760
1761 val = reg_get_value(datakey, szProperty, &type);
1762 if (!val)
1763 val = strdupW(szEmpty);
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
1797 UINT WINAPI MsiGetPatchInfoA( LPCSTR patch, LPCSTR attr, LPSTR buffer, LPDWORD buflen )
1798 {
1799 UINT r = ERROR_OUTOFMEMORY;
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
1845 UINT WINAPI MsiGetPatchInfoW( LPCWSTR patch, LPCWSTR attr, LPWSTR buffer, LPDWORD buflen )
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
1856 if (strcmpW( INSTALLPROPERTY_LOCALPACKAGEW, attr ))
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, LPCSTR szLogFile, DWORD attributes)
1885 {
1886 LPWSTR szwLogFile = NULL;
1887 UINT r;
1888
1889 TRACE("%08x %s %08x\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, LPCWSTR szLogFile, DWORD attributes)
1903 {
1904 TRACE("%08x %s %08x\n", dwLogMode, debugstr_w(szLogFile), attributes);
1905
1906 msi_free(gszLogFile);
1907 gszLogFile = NULL;
1908 if (szLogFile)
1909 {
1910 HANDLE file;
1911
1912 if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
1913 DeleteFileW(szLogFile);
1914 file = CreateFileW(szLogFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
1915 FILE_ATTRIBUTE_NORMAL, NULL);
1916 if (file != INVALID_HANDLE_VALUE)
1917 {
1918 gszLogFile = strdupW(szLogFile);
1919 CloseHandle(file);
1920 }
1921 else
1922 ERR("Unable to enable log %s (%u)\n", debugstr_w(szLogFile), GetLastError());
1923 }
1924
1925 return ERROR_SUCCESS;
1926 }
1927
1928 UINT WINAPI MsiEnumComponentCostsA( MSIHANDLE handle, LPCSTR component, DWORD index,
1929 INSTALLSTATE state, LPSTR drive, DWORD *buflen,
1930 int *cost, int *temp )
1931 {
1932 UINT r;
1933 DWORD len;
1934 WCHAR *driveW, *componentW = NULL;
1935
1936 TRACE("%d, %s, %u, %d, %p, %p, %p %p\n", handle, debugstr_a(component), index,
1937 state, drive, buflen, cost, temp);
1938
1939 if (!drive || !buflen) return ERROR_INVALID_PARAMETER;
1940 if (component && !(componentW = strdupAtoW( component ))) return ERROR_OUTOFMEMORY;
1941
1942 len = *buflen;
1943 if (!(driveW = msi_alloc( len * sizeof(WCHAR) )))
1944 {
1945 msi_free( componentW );
1946 return ERROR_OUTOFMEMORY;
1947 }
1948 r = MsiEnumComponentCostsW( handle, componentW, index, state, driveW, buflen, cost, temp );
1949 if (!r)
1950 {
1951 WideCharToMultiByte( CP_ACP, 0, driveW, -1, drive, len, NULL, NULL );
1952 }
1953 msi_free( componentW );
1954 msi_free( driveW );
1955 return r;
1956 }
1957
1958 static UINT set_drive( WCHAR *buffer, WCHAR letter )
1959 {
1960 buffer[0] = letter;
1961 buffer[1] = ':';
1962 buffer[2] = 0;
1963 return 2;
1964 }
1965
1966 UINT WINAPI MsiEnumComponentCostsW( MSIHANDLE handle, LPCWSTR component, DWORD index,
1967 INSTALLSTATE state, LPWSTR drive, DWORD *buflen,
1968 int *cost, int *temp )
1969 {
1970 UINT r = ERROR_NO_MORE_ITEMS;
1971 MSICOMPONENT *comp = NULL;
1972 MSIPACKAGE *package;
1973 MSIFILE *file;
1974 STATSTG stat = {0};
1975 WCHAR path[MAX_PATH];
1976
1977 TRACE("%d, %s, %u, %d, %p, %p, %p %p\n", handle, debugstr_w(component), index,
1978 state, drive, buflen, cost, temp);
1979
1980 if (!drive || !buflen || !cost || !temp) return ERROR_INVALID_PARAMETER;
1981 if (!(package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE )))
1982 {
1983 HRESULT hr;
1984 IWineMsiRemotePackage *remote_package;
1985 BSTR bname = NULL;
1986
1987 if (!(remote_package = (IWineMsiRemotePackage *)msi_get_remote( handle )))
1988 return ERROR_INVALID_HANDLE;
1989
1990 if (component && !(bname = SysAllocString( component )))
1991 {
1992 IWineMsiRemotePackage_Release( remote_package );
1993 return ERROR_OUTOFMEMORY;
1994 }
1995 hr = IWineMsiRemotePackage_EnumComponentCosts( remote_package, bname, index, state, drive, buflen, cost, temp );
1996 IWineMsiRemotePackage_Release( remote_package );
1997 SysFreeString( bname );
1998 if (FAILED(hr))
1999 {
2000 if (HRESULT_FACILITY(hr) == FACILITY_WIN32) return HRESULT_CODE(hr);
2001 return ERROR_FUNCTION_FAILED;
2002 }
2003 return ERROR_SUCCESS;
2004 }
2005
2006 if (!msi_get_property_int( package->db, szCostingComplete, 0 ))
2007 {
2008 msiobj_release( &package->hdr );
2009 return ERROR_FUNCTION_NOT_CALLED;
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;
2030 GetWindowsDirectoryW( path, MAX_PATH );
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
2057 UINT WINAPI MsiQueryComponentStateA(LPCSTR szProductCode,
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
2085 static BOOL msi_comp_find_prod_key(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
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
2095 static BOOL msi_comp_find_package(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
2096 {
2097 LPCWSTR package;
2098 HKEY hkey;
2099 DWORD sz;
2100 LONG res;
2101 UINT r;
2102
2103 static const WCHAR local_package[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
2104 static const WCHAR managed_local_package[] = {
2105 'M','a','n','a','g','e','d','L','o','c','a','l','P','a','c','k','a','g','e',0
2106 };
2107
2108 r = MSIREG_OpenInstallProps(prodcode, context, NULL, &hkey, FALSE);
2109 if (r != ERROR_SUCCESS)
2110 return FALSE;
2111
2112 if (context == MSIINSTALLCONTEXT_USERMANAGED)
2113 package = managed_local_package;
2114 else
2115 package = local_package;
2116
2117 sz = 0;
2118 res = RegQueryValueExW(hkey, package, NULL, NULL, NULL, &sz);
2119 RegCloseKey(hkey);
2120
2121 return (res == ERROR_SUCCESS);
2122 }
2123
2124 static UINT msi_comp_find_prodcode(WCHAR *squashed_pc,
2125 MSIINSTALLCONTEXT context,
2126 LPCWSTR comp, LPWSTR val, DWORD *sz)
2127 {
2128 HKEY hkey;
2129 LONG res;
2130 UINT r;
2131
2132 if (context == MSIINSTALLCONTEXT_MACHINE)
2133 r = MSIREG_OpenUserDataComponentKey(comp, szLocalSid, &hkey, FALSE);
2134 else
2135 r = MSIREG_OpenUserDataComponentKey(comp, NULL, &hkey, FALSE);
2136
2137 if (r != ERROR_SUCCESS)
2138 return r;
2139
2140 res = RegQueryValueExW( hkey, squashed_pc, NULL, NULL, (BYTE *)val, sz );
2141 if (res != ERROR_SUCCESS)
2142 return res;
2143
2144 RegCloseKey(hkey);
2145 return res;
2146 }
2147
2148 UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode,
2149 LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
2150 LPCWSTR szComponent, INSTALLSTATE *pdwState)
2151 {
2152 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
2153 BOOL found;
2154 DWORD sz;
2155
2156 TRACE("(%s, %s, %d, %s, %p)\n", debugstr_w(szProductCode),
2157 debugstr_w(szUserSid), dwContext, debugstr_w(szComponent), pdwState);
2158
2159 if (!pdwState || !szComponent)
2160 return ERROR_INVALID_PARAMETER;
2161
2162 if (!szProductCode || !*szProductCode || lstrlenW(szProductCode) != GUID_SIZE - 1)
2163 return ERROR_INVALID_PARAMETER;
2164
2165 if (!squash_guid( szProductCode, squashed_pc ))
2166 return ERROR_INVALID_PARAMETER;
2167
2168 found = msi_comp_find_prod_key(szProductCode, dwContext);
2169
2170 if (!msi_comp_find_package(szProductCode, dwContext))
2171 {
2172 if (found)
2173 {
2174 *pdwState = INSTALLSTATE_UNKNOWN;
2175 return ERROR_UNKNOWN_COMPONENT;
2176 }
2177
2178 return ERROR_UNKNOWN_PRODUCT;
2179 }
2180
2181 *pdwState = INSTALLSTATE_UNKNOWN;
2182
2183 sz = 0;
2184 if (msi_comp_find_prodcode( squashed_pc, dwContext, szComponent, NULL, &sz ))
2185 return ERROR_UNKNOWN_COMPONENT;
2186
2187 if (sz == 0)
2188 *pdwState = INSTALLSTATE_NOTUSED;
2189 else
2190 {
2191 WCHAR *val;
2192 UINT r;
2193
2194 if (!(val = msi_alloc( sz ))) return ERROR_OUTOFMEMORY;
2195 if ((r = msi_comp_find_prodcode( squashed_pc, dwContext, szComponent, val, &sz )))
2196 {
2197 msi_free(val);
2198 return r;
2199 }
2200
2201 if (lstrlenW(val) > 2 &&
2202 val[0] >= '0' && val[0] <= '9' && val[1] >= '0' && val[1] <= '9' && val[2] != ':')
2203 {
2204 *pdwState = INSTALLSTATE_SOURCE;
2205 }
2206 else
2207 *pdwState = INSTALLSTATE_LOCAL;
2208 msi_free( val );
2209 }
2210
2211 TRACE("-> %d\n", *pdwState);
2212 return ERROR_SUCCESS;
2213 }
2214
2215 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
2216 {
2217 LPWSTR szwProduct = NULL;
2218 INSTALLSTATE r;
2219
2220 if( szProduct )
2221 {
2222 szwProduct = strdupAtoW( szProduct );
2223 if( !szwProduct )
2224 return ERROR_OUTOFMEMORY;
2225 }
2226 r = MsiQueryProductStateW( szwProduct );
2227 msi_free( szwProduct );
2228 return r;
2229 }
2230
2231 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
2232 {
2233 MSIINSTALLCONTEXT context = MSIINSTALLCONTEXT_USERUNMANAGED;
2234 INSTALLSTATE state = INSTALLSTATE_ADVERTISED;
2235 HKEY prodkey = 0, userdata = 0;
2236 DWORD val;
2237 UINT r;
2238
2239 TRACE("%s\n", debugstr_w(szProduct));
2240
2241 if (!szProduct || !*szProduct)
2242 return INSTALLSTATE_INVALIDARG;
2243
2244 if (lstrlenW(szProduct) != GUID_SIZE - 1)
2245 return INSTALLSTATE_INVALIDARG;
2246
2247 if (szProduct[0] != '{' || szProduct[37] != '}')
2248 return INSTALLSTATE_UNKNOWN;
2249
2250 SetLastError( ERROR_SUCCESS );
2251
2252 if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2253 &prodkey, FALSE) != ERROR_SUCCESS &&
2254 MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2255 &prodkey, FALSE) != ERROR_SUCCESS &&
2256 MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2257 &prodkey, FALSE) == ERROR_SUCCESS)
2258 {
2259 context = MSIINSTALLCONTEXT_MACHINE;
2260 }
2261
2262 r = MSIREG_OpenInstallProps(szProduct, context, NULL, &userdata, FALSE);
2263 if (r != ERROR_SUCCESS)
2264 goto done;
2265
2266 if (!msi_reg_get_val_dword(userdata, szWindowsInstaller, &val))
2267 goto done;
2268
2269 if (val)
2270 state = INSTALLSTATE_DEFAULT;
2271 else
2272 state = INSTALLSTATE_UNKNOWN;
2273
2274 done:
2275 if (!prodkey)
2276 {
2277 state = INSTALLSTATE_UNKNOWN;
2278
2279 if (userdata)
2280 state = INSTALLSTATE_ABSENT;
2281 }
2282
2283 RegCloseKey(prodkey);
2284 RegCloseKey(userdata);
2285 TRACE("-> %d\n", state);
2286 return state;
2287 }
2288
2289 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
2290 {
2291 INSTALLUILEVEL old = gUILevel;
2292 HWND oldwnd = gUIhwnd;
2293
2294 TRACE("%08x %p\n", dwUILevel, phWnd);
2295
2296 if (dwUILevel & ~(INSTALLUILEVEL_MASK|INSTALLUILEVEL_HIDECANCEL|INSTALLUILEVEL_PROGRESSONLY|
2297 INSTALLUILEVEL_ENDDIALOG|INSTALLUILEVEL_SOURCERESONLY))
2298 {
2299 FIXME("Unrecognized flags %08x\n", dwUILevel);
2300 return INSTALLUILEVEL_NOCHANGE;
2301 }
2302
2303 if (dwUILevel != INSTALLUILEVEL_NOCHANGE)
2304 gUILevel = dwUILevel;
2305
2306 if (phWnd)
2307 {
2308 gUIhwnd = *phWnd;
2309 *phWnd = oldwnd;
2310 }
2311 return old;
2312 }
2313
2314 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
2315 DWORD dwMessageFilter, LPVOID pvContext)
2316 {
2317 INSTALLUI_HANDLERA prev = gUIHandlerA;
2318
2319 TRACE("%p %08x %p\n", puiHandler, dwMessageFilter, pvContext);
2320
2321 gUIHandlerA = puiHandler;
2322 gUIHandlerW = NULL;
2323 gUIFilter = dwMessageFilter;
2324 gUIContext = pvContext;
2325
2326 return prev;
2327 }
2328
2329 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
2330 DWORD dwMessageFilter, LPVOID pvContext)
2331 {
2332 INSTALLUI_HANDLERW prev = gUIHandlerW;
2333
2334 TRACE("%p %08x %p\n", puiHandler, dwMessageFilter, pvContext);
2335
2336 gUIHandlerA = NULL;
2337 gUIHandlerW = puiHandler;
2338 gUIFilter = dwMessageFilter;
2339 gUIContext = pvContext;
2340
2341 return prev;
2342 }
2343
2344 /******************************************************************
2345 * MsiLoadStringW [MSI.@]
2346 *
2347 * Loads a string from MSI's string resources.
2348 *
2349 * PARAMS
2350 *
2351 * handle [I] only -1 is handled currently
2352 * id [I] id of the string to be loaded
2353 * lpBuffer [O] buffer for the string to be written to
2354 * nBufferMax [I] maximum size of the buffer in characters
2355 * lang [I] the preferred language for the string
2356 *
2357 * RETURNS
2358 *
2359 * If successful, this function returns the language id of the string loaded
2360 * If the function fails, the function returns zero.
2361 *
2362 * NOTES
2363 *
2364 * The type of the first parameter is unknown. LoadString's prototype
2365 * suggests that it might be a module handle. I have made it an MSI handle
2366 * for starters, as -1 is an invalid MSI handle, but not an invalid module
2367 * handle. Maybe strings can be stored in an MSI database somehow.
2368 */
2369 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
2370 int nBufferMax, LANGID lang )
2371 {
2372 HRSRC hres;
2373 HGLOBAL hResData;
2374 LPWSTR p;
2375 DWORD i, len;
2376
2377 TRACE("%d %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
2378
2379 if( handle != -1 )
2380 FIXME("don't know how to deal with handle = %08x\n", handle);
2381
2382 if( !lang )
2383 lang = GetUserDefaultLangID();
2384
2385 hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
2386 (LPWSTR)1, lang );
2387 if( !hres )
2388 return 0;
2389 hResData = LoadResource( msi_hInstance, hres );
2390 if( !hResData )
2391 return 0;
2392 p = LockResource( hResData );
2393 if( !p )
2394 return 0;
2395
2396 for (i = 0; i < (id & 0xf); i++) p += *p + 1;
2397 len = *p;
2398
2399 if( nBufferMax <= len )
2400 return 0;
2401
2402 memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
2403 lpBuffer[ len ] = 0;
2404
2405 TRACE("found -> %s\n", debugstr_w(lpBuffer));
2406 return lang;
2407 }
2408
2409 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
2410 int nBufferMax, LANGID lang )
2411 {
2412 LPWSTR bufW;
2413 LANGID r;
2414 INT len;
2415
2416 bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
2417 r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
2418 if( r )
2419 {
2420 len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
2421 if( len <= nBufferMax )
2422 WideCharToMultiByte( CP_ACP, 0, bufW, -1,
2423 lpBuffer, nBufferMax, NULL, NULL );
2424 else
2425 r = 0;
2426 }
2427 msi_free(bufW);
2428 return r;
2429 }
2430
2431 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
2432 LPDWORD pcchBuf)
2433 {
2434 char szProduct[GUID_SIZE];
2435
2436 TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
2437
2438 if (!szComponent || !pcchBuf)
2439 return INSTALLSTATE_INVALIDARG;
2440
2441 if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
2442 return INSTALLSTATE_UNKNOWN;
2443
2444 return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
2445 }
2446
2447 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
2448 LPDWORD pcchBuf)
2449 {
2450 WCHAR szProduct[GUID_SIZE];
2451
2452 TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
2453
2454 if (!szComponent || !pcchBuf)
2455 return INSTALLSTATE_INVALIDARG;
2456
2457 if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
2458 return INSTALLSTATE_UNKNOWN;
2459
2460 return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
2461 }
2462
2463 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
2464 WORD wLanguageId, DWORD f)
2465 {
2466 FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption),
2467 uType, wLanguageId, f);
2468 return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId);
2469 }
2470
2471 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
2472 WORD wLanguageId, DWORD f)
2473 {
2474 FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption),
2475 uType, wLanguageId, f);
2476 return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId);
2477 }
2478
2479 UINT WINAPI MsiMessageBoxExA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
2480 DWORD unknown, WORD wLanguageId, DWORD f)
2481 {
2482 FIXME("(%p, %s, %s, %u, 0x%08x, 0x%08x, 0x%08x): semi-stub\n", hWnd, debugstr_a(lpText),
2483 debugstr_a(lpCaption), uType, unknown, wLanguageId, f);
2484 return MessageBoxExA(hWnd, lpText, lpCaption, uType, wLanguageId);
2485 }
2486
2487 UINT WINAPI MsiMessageBoxExW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
2488 DWORD unknown, WORD wLanguageId, DWORD f)
2489 {
2490 FIXME("(%p, %s, %s, %u, 0x%08x, 0x%08x, 0x%08x): semi-stub\n", hWnd, debugstr_w(lpText),
2491 debugstr_w(lpCaption), uType, unknown, wLanguageId, f);
2492 return MessageBoxExW(hWnd, lpText, lpCaption, uType, wLanguageId);
2493 }
2494
2495 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
2496 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
2497 LPDWORD pcchPathBuf )
2498 {
2499 FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
2500 debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
2501 pcchPathBuf);
2502 return ERROR_CALL_NOT_IMPLEMENTED;
2503 }
2504
2505 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
2506 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
2507 LPDWORD pcchPathBuf )
2508 {
2509 FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
2510 debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
2511 pcchPathBuf);
2512 return ERROR_CALL_NOT_IMPLEMENTED;
2513 }
2514
2515 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
2516 LPSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2517 {
2518 FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
2519 return ERROR_CALL_NOT_IMPLEMENTED;
2520 }
2521
2522 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
2523 LPWSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2524 {
2525 FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
2526 return ERROR_CALL_NOT_IMPLEMENTED;
2527 }
2528
2529 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR path, DWORD flags, PCCERT_CONTEXT *cert,
2530 LPBYTE hash, LPDWORD hashlen )
2531 {
2532 UINT r;
2533 WCHAR *pathW = NULL;
2534
2535 TRACE("%s %08x %p %p %p\n", debugstr_a(path), flags, cert, hash, hashlen);
2536
2537 if (path && !(pathW = strdupAtoW( path ))) return E_OUTOFMEMORY;
2538 r = MsiGetFileSignatureInformationW( pathW, flags, cert, hash, hashlen );
2539 msi_free( pathW );
2540 return r;
2541 }
2542
2543 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR path, DWORD flags, PCCERT_CONTEXT *cert,
2544 LPBYTE hash, LPDWORD hashlen )
2545 {
2546 static GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
2547 HRESULT hr;
2548 WINTRUST_DATA data;
2549 WINTRUST_FILE_INFO info;
2550 CRYPT_PROVIDER_SGNR *signer;
2551 CRYPT_PROVIDER_CERT *provider;
2552
2553 TRACE("%s %08x %p %p %p\n", debugstr_w(path), flags, cert, hash, hashlen);
2554
2555 if (!path || !cert) return E_INVALIDARG;
2556
2557 info.cbStruct = sizeof(info);
2558 info.pcwszFilePath = path;
2559 info.hFile = NULL;
2560 info.pgKnownSubject = NULL;
2561
2562 data.cbStruct = sizeof(data);
2563 data.pPolicyCallbackData = NULL;
2564 data.pSIPClientData = NULL;
2565 data.dwUIChoice = WTD_UI_NONE;
2566 data.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
2567 data.dwUnionChoice = WTD_CHOICE_FILE;
2568 data.u.pFile = &info;
2569 data.dwStateAction = WTD_STATEACTION_VERIFY;
2570 data.hWVTStateData = NULL;
2571 data.pwszURLReference = NULL;
2572 data.dwProvFlags = 0;
2573 data.dwUIContext = WTD_UICONTEXT_INSTALL;
2574 hr = WinVerifyTrustEx( INVALID_HANDLE_VALUE, &generic_verify_v2, &data );
2575 *cert = NULL;
2576 if (FAILED(hr)) goto done;
2577
2578 if (!(signer = WTHelperGetProvSignerFromChain( data.hWVTStateData, 0, FALSE, 0 )))
2579 {
2580 hr = TRUST_E_NOSIGNATURE;
2581 goto done;
2582 }
2583 if (hash)
2584 {
2585 DWORD len = signer->psSigner->EncryptedHash.cbData;
2586 if (*hashlen < len)
2587 {
2588 *hashlen = len;
2589 hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
2590 goto done;
2591 }
2592 memcpy( hash, signer->psSigner->EncryptedHash.pbData, len );
2593 *hashlen = len;
2594 }
2595 if (!(provider = WTHelperGetProvCertFromChain( signer, 0 )))
2596 {
2597 hr = TRUST_E_PROVIDER_UNKNOWN;
2598 goto done;
2599 }
2600 *cert = CertDuplicateCertificateContext( provider->pCert );
2601
2602 done:
2603 data.dwStateAction = WTD_STATEACTION_CLOSE;
2604 WinVerifyTrustEx( INVALID_HANDLE_VALUE, &generic_verify_v2, &data );
2605 return hr;
2606 }
2607
2608 /******************************************************************
2609 * MsiGetProductPropertyA [MSI.@]
2610 */
2611 UINT WINAPI MsiGetProductPropertyA(MSIHANDLE hProduct, LPCSTR szProperty,
2612 LPSTR szValue, LPDWORD pccbValue)
2613 {
2614 LPWSTR prop = NULL, val = NULL;
2615 DWORD len;
2616 UINT r;
2617
2618 TRACE("(%d, %s, %p, %p)\n", hProduct, debugstr_a(szProperty),
2619 szValue, pccbValue);
2620
2621 if (szValue && !pccbValue)
2622 return ERROR_INVALID_PARAMETER;
2623
2624 if (szProperty) prop = strdupAtoW(szProperty);
2625
2626 len = 0;
2627 r = MsiGetProductPropertyW(hProduct, prop, NULL, &len);
2628 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2629 goto done;
2630
2631 if (r == ERROR_SUCCESS)
2632 {
2633 if (szValue) *szValue = '\0';
2634 if (pccbValue) *pccbValue = 0;
2635 goto done;
2636 }
2637
2638 val = msi_alloc(++len * sizeof(WCHAR));
2639 if (!val)
2640 {
2641 r = ERROR_OUTOFMEMORY;
2642 goto done;
2643 }
2644
2645 r = MsiGetProductPropertyW(hProduct, prop, val, &len);
2646 if (r != ERROR_SUCCESS)
2647 goto done;
2648
2649 len = WideCharToMultiByte(CP_ACP, 0, val, -1, NULL, 0, NULL, NULL);
2650
2651 if (szValue)
2652 WideCharToMultiByte(CP_ACP, 0, val, -1, szValue,
2653 *pccbValue, NULL, NULL);
2654
2655 if (pccbValue)
2656 {
2657 if (len > *pccbValue)
2658 r = ERROR_MORE_DATA;
2659
2660 *pccbValue = len - 1;
2661 }
2662
2663 done:
2664 msi_free(prop);
2665 msi_free(val);
2666
2667 return r;
2668 }
2669
2670 /******************************************************************
2671 * MsiGetProductPropertyW [MSI.@]
2672 */
2673 UINT WINAPI MsiGetProductPropertyW(MSIHANDLE hProduct, LPCWSTR szProperty,
2674 LPWSTR szValue, LPDWORD pccbValue)
2675 {
2676 MSIPACKAGE *package;
2677 MSIQUERY *view = NULL;
2678 MSIRECORD *rec = NULL;
2679 LPCWSTR val;
2680 UINT r;
2681
2682 static const WCHAR query[] = {
2683 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2684 '`','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
2685 '`','P','r','o','p','e','r','t','y','`','=','\'','%','s','\'',0};
2686
2687 TRACE("(%d, %s, %p, %p)\n", hProduct, debugstr_w(szProperty),
2688 szValue, pccbValue);
2689
2690 if (!szProperty)
2691 return ERROR_INVALID_PARAMETER;
2692
2693 if (szValue && !pccbValue)
2694 return ERROR_INVALID_PARAMETER;
2695
2696 package = msihandle2msiinfo(hProduct, MSIHANDLETYPE_PACKAGE);
2697 if (!package)
2698 return ERROR_INVALID_HANDLE;
2699
2700 r = MSI_OpenQuery(package->db, &view, query, szProperty);
2701 if (r != ERROR_SUCCESS)
2702 goto done;
2703
2704 r = MSI_ViewExecute(view, 0);
2705 if (r != ERROR_SUCCESS)
2706 goto done;
2707
2708 r = MSI_ViewFetch(view, &rec);
2709 if (r != ERROR_SUCCESS)
2710 goto done;
2711
2712 val = MSI_RecordGetString(rec, 2);
2713 if (!val)
2714 goto done;
2715
2716 if (lstrlenW(val) >= *pccbValue)
2717 {
2718 if (szValue) lstrcpynW(szValue, val, *pccbValue);
2719 r = ERROR_MORE_DATA;
2720 }
2721 else
2722 {
2723 if (szValue) lstrcpyW(szValue, val);
2724 r = ERROR_SUCCESS;
2725 }
2726
2727 *pccbValue = lstrlenW(val);
2728
2729 done:
2730 if (view)
2731 {
2732 MSI_ViewClose(view);
2733 msiobj_release(&view->hdr);
2734 if (rec) msiobj_release(&rec->hdr);
2735 }
2736
2737 if (!rec)
2738 {
2739 if (szValue) *szValue = '\0';
2740 if (pccbValue) *pccbValue = 0;
2741 r = ERROR_SUCCESS;
2742 }
2743
2744 msiobj_release(&package->hdr);
2745 return r;
2746 }
2747
2748 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
2749 {
2750 UINT r;
2751 LPWSTR szPack = NULL;
2752
2753 TRACE("%s\n", debugstr_a(szPackage) );
2754
2755 if( szPackage )
2756 {
2757 szPack = strdupAtoW( szPackage );
2758 if( !szPack )
2759 return ERROR_OUTOFMEMORY;
2760 }
2761
2762 r = MsiVerifyPackageW( szPack );
2763
2764 msi_free( szPack );
2765
2766 return r;
2767 }
2768
2769 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
2770 {
2771 MSIHANDLE handle;
2772 UINT r;
2773
2774 TRACE("%s\n", debugstr_w(szPackage) );
2775
2776 r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
2777 MsiCloseHandle( handle );
2778
2779 return r;
2780 }
2781
2782 static BOOL open_userdata_comp_key( const WCHAR *comp, const WCHAR *usersid, MSIINSTALLCONTEXT ctx,
2783 HKEY *hkey )
2784 {
2785 if (ctx & MSIINSTALLCONTEXT_MACHINE)
2786 {
2787 if (!MSIREG_OpenUserDataComponentKey( comp, szLocalSid, hkey, FALSE )) return TRUE;
2788 }
2789 if (ctx & (MSIINSTALLCONTEXT_USERMANAGED|MSIINSTALLCONTEXT_USERUNMANAGED))
2790 {
2791 if (usersid && !strcmpiW( usersid, szAllSid ))
2792 {
2793 FIXME( "only looking at the current user\n" );
2794 usersid = NULL;
2795 }
2796 if (!MSIREG_OpenUserDataComponentKey( comp, usersid, hkey, FALSE )) return TRUE;
2797 }
2798 return FALSE;
2799 }
2800
2801 static INSTALLSTATE MSI_GetComponentPath( const WCHAR *szProduct, const WCHAR *szComponent,
2802 const WCHAR *szUserSid, MSIINSTALLCONTEXT ctx,
2803 awstring *lpPathBuf, DWORD *pcchBuf )
2804 {
2805 static const WCHAR wininstaller[] =
2806 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
2807 WCHAR *path = NULL, squashed_pc[SQUASHED_GUID_SIZE], squashed_comp[SQUASHED_GUID_SIZE];
2808 HKEY hkey;
2809 INSTALLSTATE state;
2810 DWORD version;
2811
2812 if (!szProduct || !szComponent)
2813 return INSTALLSTATE_INVALIDARG;
2814
2815 if (lpPathBuf->str.w && !pcchBuf)
2816 return INSTALLSTATE_INVALIDARG;
2817
2818 if (!squash_guid( szProduct, squashed_pc ) || !squash_guid( szComponent, squashed_comp ))
2819 return INSTALLSTATE_INVALIDARG;
2820
2821 if (szUserSid && ctx == MSIINSTALLCONTEXT_MACHINE)
2822 return INSTALLSTATE_INVALIDARG;
2823
2824 state = INSTALLSTATE_UNKNOWN;
2825
2826 if (open_userdata_comp_key( szComponent, szUserSid, ctx, &hkey ))
2827 {
2828 path = msi_reg_get_val_str( hkey, squashed_pc );
2829 RegCloseKey(hkey);
2830
2831 state = INSTALLSTATE_ABSENT;
2832
2833 if ((!MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE, NULL, &hkey, FALSE) ||
2834 !MSIREG_OpenUserDataProductKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED, NULL, &hkey, FALSE)) &&
2835 msi_reg_get_val_dword(hkey, wininstaller, &version) &&
2836 GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2837 {
2838 RegCloseKey(hkey);
2839 state = INSTALLSTATE_LOCAL;
2840 }
2841 }
2842
2843 if (state != INSTALLSTATE_LOCAL &&
2844 (!MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, &hkey, FALSE) ||
2845 !MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE, &hkey, FALSE)))
2846 {
2847 RegCloseKey(hkey);
2848
2849 if (open_userdata_comp_key( szComponent, szUserSid, ctx, &hkey ))
2850 {
2851 msi_free(path);
2852 path = msi_reg_get_val_str( hkey, squashed_pc );
2853 RegCloseKey(hkey);
2854
2855 state = INSTALLSTATE_ABSENT;
2856
2857 if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2858 state = INSTALLSTATE_LOCAL;
2859 }
2860 }
2861
2862 if (!path)
2863 return INSTALLSTATE_UNKNOWN;
2864
2865 if (state == INSTALLSTATE_LOCAL && !*path)
2866 state = INSTALLSTATE_NOTUSED;
2867
2868 if (msi_strcpy_to_awstring(path, -1, lpPathBuf, pcchBuf) == ERROR_MORE_DATA)
2869 state = INSTALLSTATE_MOREDATA;
2870
2871 msi_free(path);
2872 return state;
2873 }
2874
2875 /******************************************************************
2876 * MsiGetComponentPathExW [MSI.@]
2877 */
2878 INSTALLSTATE WINAPI MsiGetComponentPathExW( LPCWSTR product, LPCWSTR comp, LPCWSTR usersid,
2879 MSIINSTALLCONTEXT ctx, LPWSTR buf, LPDWORD buflen )
2880 {
2881 awstring path;
2882
2883 TRACE( "%s %s %s 0x%x %p %p\n", debugstr_w(product), debugstr_w(comp), debugstr_w(usersid),
2884 ctx, buf, buflen );
2885
2886 path.unicode = TRUE;
2887 path.str.w = buf;
2888
2889 return MSI_GetComponentPath( product, comp, usersid, ctx, &path, buflen );
2890 }
2891
2892 INSTALLSTATE WINAPI MsiGetComponentPathExA( LPCSTR product, LPCSTR comp, LPCSTR usersid,
2893 MSIINSTALLCONTEXT ctx, LPSTR buf, LPDWORD buflen )
2894 {
2895 WCHAR *productW = NULL, *compW = NULL, *usersidW = NULL;
2896 INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
2897 awstring path;
2898
2899 TRACE( "%s %s %s 0x%x %p %p\n", debugstr_a(product), debugstr_a(comp), debugstr_a(usersid),
2900 ctx, buf, buflen );
2901
2902 if (product && !(productW = strdupAtoW( product ))) return INSTALLSTATE_UNKNOWN;
2903 if (comp && !(compW = strdupAtoW( comp ))) goto end;
2904 if (usersid && !(usersidW = strdupAtoW( usersid ))) goto end;
2905
2906 path.unicode = FALSE;
2907 path.str.a = buf;
2908
2909 r = MSI_GetComponentPath( productW, compW, usersidW, ctx, &path, buflen );
2910
2911 end:
2912 msi_free( productW );
2913 msi_free( compW );
2914 msi_free( usersidW );
2915
2916 return r;
2917 }
2918
2919 /******************************************************************
2920 * MsiGetComponentPathW [MSI.@]
2921 */
2922 INSTALLSTATE WINAPI MsiGetComponentPathW( LPCWSTR product, LPCWSTR comp, LPWSTR buf, LPDWORD buflen )
2923 {
2924 return MsiGetComponentPathExW( product, comp, szAllSid, MSIINSTALLCONTEXT_ALL, buf, buflen );
2925 }
2926
2927 /******************************************************************
2928 * MsiGetComponentPathA [MSI.@]
2929 */
2930 INSTALLSTATE WINAPI MsiGetComponentPathA( LPCSTR product, LPCSTR comp, LPSTR buf, LPDWORD buflen )
2931 {
2932 return MsiGetComponentPathExA( product, comp, "s-1-1-0", MSIINSTALLCONTEXT_ALL, buf, buflen );
2933 }
2934
2935 static UINT query_feature_state( const WCHAR *product, const WCHAR *squashed, const WCHAR *usersid,
2936 MSIINSTALLCONTEXT ctx, const WCHAR *feature, INSTALLSTATE *state )
2937 {
2938 UINT r;
2939 HKEY hkey;
2940 WCHAR *parent, *components, *path;
2941 const WCHAR *p;
2942 BOOL missing = FALSE, source = FALSE;
2943 WCHAR comp[GUID_SIZE];
2944 GUID guid;
2945
2946 if (ctx != MSIINSTALLCONTEXT_MACHINE) SetLastError( ERROR_SUCCESS );
2947
2948 if (MSIREG_OpenFeaturesKey( product, usersid, ctx, &hkey, FALSE )) return ERROR_UNKNOWN_PRODUCT;
2949
2950 parent = msi_reg_get_val_str( hkey, feature );
2951 RegCloseKey( hkey );
2952 if (!parent) return ERROR_UNKNOWN_FEATURE;
2953
2954 *state = (parent[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
2955 msi_free( parent );
2956 if (*state == INSTALLSTATE_ABSENT)
2957 return ERROR_SUCCESS;
2958
2959 r = MSIREG_OpenUserDataFeaturesKey( product, usersid, ctx, &hkey, FALSE );
2960 if (r != ERROR_SUCCESS)
2961 {
2962 *state = INSTALLSTATE_ADVERTISED;
2963 return ERROR_SUCCESS;
2964 }
2965 components = msi_reg_get_val_str( hkey, feature );
2966 RegCloseKey( hkey );
2967
2968 TRACE("buffer = %s\n", debugstr_w(components));
2969
2970 if (!components)
2971 {
2972 *state = INSTALLSTATE_ADVERTISED;
2973 return ERROR_SUCCESS;
2974 }
2975 for (p = components; *p && *p != 2 ; p += 20)
2976 {
2977 if (!decode_base85_guid( p, &guid ))
2978 {
2979 if (p != components) break;
2980 msi_free( components );
2981 *state = INSTALLSTATE_BADCONFIG;
2982 return ERROR_BAD_CONFIGURATION;
2983 }
2984 StringFromGUID2( &guid, comp, GUID_SIZE );
2985 if (ctx == MSIINSTALLCONTEXT_MACHINE)
2986 r = MSIREG_OpenUserDataComponentKey( comp, szLocalSid, &hkey, FALSE );
2987 else
2988 r = MSIREG_OpenUserDataComponentKey( comp, usersid, &hkey, FALSE );
2989
2990 if (r != ERROR_SUCCESS)
2991 {
2992 msi_free( components );
2993 *state = INSTALLSTATE_ADVERTISED;
2994 return ERROR_SUCCESS;
2995 }
2996 path = msi_reg_get_val_str( hkey, squashed );
2997 if (!path) missing = TRUE;
2998 else if (strlenW( path ) > 2 &&
2999 path[0] >= '0' && path[0] <= '9' &&
3000 path[1] >= '0' && path[1] <= '9')
3001 {
3002 source = TRUE;
3003 }
3004 msi_free( path );
3005 }
3006 msi_free( components );
3007
3008 if (missing)
3009 *state = INSTALLSTATE_ADVERTISED;
3010 else if (source)
3011 *state = INSTALLSTATE_SOURCE;
3012 else
3013 *state = INSTALLSTATE_LOCAL;
3014
3015 TRACE("returning state %d\n", *state);
3016 return ERROR_SUCCESS;
3017 }
3018
3019 UINT WINAPI MsiQueryFeatureStateExA( LPCSTR product, LPCSTR usersid, MSIINSTALLCONTEXT ctx,
3020 LPCSTR feature, INSTALLSTATE *state )
3021 {
3022 UINT r;
3023 WCHAR *productW = NULL, *usersidW = NULL, *featureW = NULL;
3024
3025 if (product && !(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
3026 if (usersid && !(usersidW = strdupAtoW( usersid )))
3027 {
3028 msi_free( productW );
3029 return ERROR_OUTOFMEMORY;
3030 }
3031 if (feature && !(featureW = strdupAtoW( feature )))
3032 {
3033 msi_free( productW );
3034 msi_free( usersidW );
3035 return ERROR_OUTOFMEMORY;
3036 }
3037 r = MsiQueryFeatureStateExW( productW, usersidW, ctx, featureW, state );
3038 msi_free( productW );
3039 msi_free( usersidW );
3040 msi_free( featureW );
3041 return r;
3042 }
3043
3044 UINT WINAPI MsiQueryFeatureStateExW( LPCWSTR product, LPCWSTR usersid, MSIINSTALLCONTEXT ctx,
3045 LPCWSTR feature, INSTALLSTATE *state )
3046 {
3047 WCHAR squashed[33];
3048 if (!squash_guid( product, squashed )) return ERROR_INVALID_PARAMETER;
3049 return query_feature_state( product, squashed, usersid, ctx, feature, state );
3050 }
3051
3052 /******************************************************************
3053 * MsiQueryFeatureStateA [MSI.@]
3054 */
3055 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
3056 {
3057 LPWSTR szwProduct = NULL, szwFeature= NULL;
3058 INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
3059
3060 szwProduct = strdupAtoW( szProduct );
3061 if ( szProduct && !szwProduct )
3062 goto end;
3063
3064 szwFeature = strdupAtoW( szFeature );
3065 if ( szFeature && !szwFeature )
3066 goto end;
3067
3068 rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
3069
3070 end:
3071 msi_free( szwProduct);
3072 msi_free( szwFeature);
3073
3074 return rc;
3075 }
3076
3077 /******************************************************************
3078 * MsiQueryFeatureStateW [MSI.@]
3079 *
3080 * Checks the state of a feature
3081 *
3082 * PARAMS
3083 * szProduct [I] Product's GUID string
3084 * szFeature [I] Feature's GUID string
3085 *
3086 * RETURNS
3087 * INSTALLSTATE_LOCAL Feature is installed and usable
3088 * INSTALLSTATE_ABSENT Feature is absent
3089 * INSTALLSTATE_ADVERTISED Feature should be installed on demand
3090 * INSTALLSTATE_UNKNOWN An error occurred
3091 * INSTALLSTATE_INVALIDARG One of the GUIDs was invalid
3092 *
3093 */
3094 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
3095 {
3096 UINT r;
3097 INSTALLSTATE state;
3098 WCHAR squashed[33];
3099
3100 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
3101
3102 if (!szProduct || !szFeature || !squash_guid( szProduct, squashed ))
3103 return INSTALLSTATE_INVALIDARG;
3104
3105 r = query_feature_state( szProduct, squashed, NULL, MSIINSTALLCONTEXT_USERMANAGED, szFeature, &state );
3106 if (r == ERROR_SUCCESS || r == ERROR_BAD_CONFIGURATION) return state;
3107
3108 r = query_feature_state( szProduct, squashed, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, szFeature, &state );
3109 if (r == ERROR_SUCCESS || r == ERROR_BAD_CONFIGURATION) return state;
3110
3111 r = query_feature_state( szProduct, squashed, NULL, MSIINSTALLCONTEXT_MACHINE, szFeature, &state );
3112 if (r == ERROR_SUCCESS || r == ERROR_BAD_CONFIGURATION) return state;
3113
3114 return INSTALLSTATE_UNKNOWN;
3115 }
3116
3117 /******************************************************************
3118 * MsiGetFileVersionA [MSI.@]
3119 */
3120 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
3121 LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf)
3122 {
3123 LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
3124 UINT ret = ERROR_OUTOFMEMORY;
3125
3126 if ((lpVersionBuf && !pcchVersionBuf) ||
3127 (lpLangBuf && !pcchLangBuf))
3128 return ERROR_INVALID_PARAMETER;
3129
3130 if( szFilePath )
3131 {
3132 szwFilePath = strdupAtoW( szFilePath );
3133 if( !szwFilePath )
3134 goto end;
3135 }
3136
3137 if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
3138 {
3139 lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
3140 if( !lpwVersionBuff )
3141 goto end;
3142 }
3143
3144 if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
3145 {
3146 lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
3147 if( !lpwLangBuff )
3148 goto end;
3149 }
3150
3151 ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
3152 lpwLangBuff, pcchLangBuf);
3153
3154 if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff )
3155 WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
3156 lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL);
3157 if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff )
3158 WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
3159 lpLangBuf, *pcchLangBuf + 1, NULL, NULL);
3160
3161 end:
3162 msi_free(szwFilePath);
3163 msi_free(lpwVersionBuff);
3164 msi_free(lpwLangBuff);
3165
3166 return ret;
3167 }
3168
3169 static UINT get_file_version( const WCHAR *path, WCHAR *verbuf, DWORD *verlen,
3170 WCHAR *langbuf, DWORD *langlen )
3171 {
3172 static const WCHAR szVersionResource[] = {'\\',0};
3173 static const WCHAR szVersionFormat[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
3174 static const WCHAR szLangFormat[] = {'%','d',0};
3175 UINT ret = ERROR_MORE_DATA;
3176 DWORD len, error;
3177 LPVOID version;
3178 VS_FIXEDFILEINFO *ffi;
3179 USHORT *lang;
3180 WCHAR tmp[32];
3181
3182 if (!(len = GetFileVersionInfoSizeW( path, NULL )))
3183 {
3184 error = GetLastError();
3185 if (error == ERROR_BAD_PATHNAME) return ERROR_FILE_NOT_FOUND;
3186 if (error == ERROR_RESOURCE_DATA_NOT_FOUND) return ERROR_FILE_INVALID;
3187 return error;
3188 }
3189 if (!(version = msi_alloc( len ))) return ERROR_OUTOFMEMORY;
3190 if (!GetFileVersionInfoW( path, 0, len, version ))
3191 {
3192 msi_free( version );
3193 return GetLastError();
3194 }
3195 if (!verbuf && !verlen && !langbuf && !langlen)
3196 {
3197 msi_free( version );
3198 return ERROR_SUCCESS;
3199 }
3200 if (verlen)
3201 {
3202 if (VerQueryValueW( version, szVersionResource, (LPVOID *)&ffi, &len ) && len > 0)
3203 {
3204 sprintfW( tmp, szVersionFormat,
3205 HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
3206 HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS) );
3207 if (verbuf) lstrcpynW( verbuf, tmp, *verlen );
3208 len = strlenW( tmp );
3209 if (*verlen > len) ret = ERROR_SUCCESS;
3210 *verlen = len;
3211 }
3212 else
3213 {
3214 if (verbuf) *verbuf = 0;
3215 *verlen = 0;
3216 }
3217 }
3218 if (langlen)
3219 {
3220 if (VerQueryValueW( version, szLangResource, (LPVOID *)&lang, &len ) && len > 0)
3221 {
3222 sprintfW( tmp, szLangFormat, *lang );
3223 if (langbuf) lstrcpynW( langbuf, tmp, *langlen );
3224 len = strlenW( tmp );
3225 if (*langlen > len) ret = ERROR_SUCCESS;
3226 *langlen = len;
3227 }
3228 else
3229 {
3230 if (langbuf) *langbuf = 0;
3231 *langlen = 0;
3232 }
3233 }
3234 msi_free( version );
3235 return ret;
3236 }
3237
3238
3239 /******************************************************************
3240 * MsiGetFileVersionW [MSI.@]
3241 */
3242 UINT WINAPI MsiGetFileVersionW( LPCWSTR path, LPWSTR verbuf, LPDWORD verlen,
3243 LPWSTR langbuf, LPDWORD langlen )
3244 {
3245 UINT ret;
3246
3247 TRACE("%s %p %u %p %u\n", debugstr_w(path), verbuf, verlen ? *verlen : 0,
3248 langbuf, langlen ? *langlen : 0);
3249
3250 if ((verbuf && !verlen) || (langbuf && !langlen))
3251 return ERROR_INVALID_PARAMETER;
3252
3253 ret = get_file_version( path, verbuf, verlen, langbuf, langlen );
3254 if (ret == ERROR_RESOURCE_DATA_NOT_FOUND && verlen)
3255 {
3256 int len;
3257 WCHAR *version = msi_font_version_from_file( path );
3258 if (!version) return ERROR_FILE_INVALID;
3259 len = strlenW( version );
3260 if (len >= *verlen) ret = ERROR_MORE_DATA;
3261 else if (verbuf)
3262 {
3263 strcpyW( verbuf, version );
3264 ret = ERROR_SUCCESS;
3265 }
3266 *verlen = len;
3267 msi_free( version );
3268 }
3269 return ret;
3270 }
3271
3272 /***********************************************************************
3273 * MsiGetFeatureUsageW [MSI.@]
3274 */
3275 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
3276 LPDWORD pdwUseCount, LPWORD pwDateUsed )
3277 {
3278 FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
3279 pdwUseCount, pwDateUsed);
3280 return ERROR_CALL_NOT_IMPLEMENTED;
3281 }
3282
3283 /***********************************************************************
3284 * MsiGetFeatureUsageA [MSI.@]
3285 */
3286 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
3287 LPDWORD pdwUseCount, LPWORD pwDateUsed )
3288 {
3289 LPWSTR prod = NULL, feat = NULL;
3290 UINT ret = ERROR_OUTOFMEMORY;
3291
3292 TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
3293 pdwUseCount, pwDateUsed);
3294
3295 prod = strdupAtoW( szProduct );
3296 if (szProduct && !prod)
3297 goto end;
3298
3299 feat = strdupAtoW( szFeature );
3300 if (szFeature && !feat)
3301 goto end;
3302
3303 ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
3304
3305 end:
3306 msi_free( prod );
3307 msi_free( feat );
3308
3309 return ret;
3310 }
3311
3312 /***********************************************************************
3313 * MsiUseFeatureExW [MSI.@]
3314 */
3315 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
3316 DWORD dwInstallMode, DWORD dwReserved )
3317 {
3318 INSTALLSTATE state;
3319
3320 TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
3321 dwInstallMode, dwReserved);
3322
3323 state = MsiQueryFeatureStateW( szProduct, szFeature );
3324
3325 if (dwReserved)
3326 return INSTALLSTATE_INVALIDARG;
3327
3328 if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
3329 {
3330 FIXME("mark product %s feature %s as used\n",
3331 debugstr_w(szProduct), debugstr_w(szFeature) );
3332 }
3333
3334 return state;
3335 }
3336
3337 /***********************************************************************
3338 * MsiUseFeatureExA [MSI.@]
3339 */
3340 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
3341 DWORD dwInstallMode, DWORD dwReserved )
3342 {
3343 INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
3344 LPWSTR prod = NULL, feat = NULL;
3345
3346 TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
3347 dwInstallMode, dwReserved);
3348
3349 prod = strdupAtoW( szProduct );
3350 if (szProduct && !prod)
3351 goto end;
3352
3353 feat = strdupAtoW( szFeature );
3354 if (szFeature && !feat)
3355 goto end;
3356
3357 ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
3358
3359 end:
3360 msi_free( prod );
3361 msi_free( feat );
3362
3363 return ret;
3364 }
3365
3366 /***********************************************************************
3367 * MsiUseFeatureW [MSI.@]
3368 */
3369 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
3370 {
3371 return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
3372 }
3373
3374 /***********************************************************************
3375 * MsiUseFeatureA [MSI.@]
3376 */
3377 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
3378 {
3379 return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
3380 }
3381
3382 static WCHAR *reg_get_multisz( HKEY hkey, const WCHAR *name )
3383 {
3384 WCHAR *ret;
3385 DWORD len, type;
3386 if (RegQueryValueExW( hkey, name, NULL, &type, NULL, &len ) || type != REG_MULTI_SZ) return NULL;
3387 if ((ret = msi_alloc( len ))) RegQueryValueExW( hkey, name, NULL, NULL, (BYTE *)ret, &len );
3388 return ret;
3389 }
3390
3391 static WCHAR *reg_get_sz( HKEY hkey, const WCHAR *name )
3392 {
3393 WCHAR *ret;
3394 DWORD len, type;
3395 if (RegQueryValueExW( hkey, name, NULL, &type, NULL, &len ) || type != REG_SZ) return NULL;
3396 if ((ret = msi_alloc( len ))) RegQueryValueExW( hkey, name, NULL, NULL, (BYTE *)ret, &len );
3397 return ret;
3398 }
3399
3400 #define BASE85_SIZE 20
3401
3402 /***********************************************************************
3403 * MSI_ProvideQualifiedComponentEx [internal]
3404 */
3405 static UINT MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
3406 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
3407 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
3408 LPDWORD pcchPathBuf)
3409 {
3410 WCHAR product[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
3411 WCHAR *desc;
3412 HKEY hkey;
3413 DWORD size;
3414 UINT ret;
3415 INSTALLSTATE state;
3416
3417 if (MSIREG_OpenUserComponentsKey( szComponent, &hkey, FALSE )) return ERROR_UNKNOWN_COMPONENT;
3418
3419 desc = reg_get_multisz( hkey, szQualifier );
3420 RegCloseKey(hkey);
3421 if (!desc) return ERROR_INDEX_ABSENT;
3422
3423 /* FIXME: handle multiple descriptors */
3424 ret = MsiDecomposeDescriptorW( desc, product, feature, comp, &size );
3425 msi_free( desc );
3426 if (ret != ERROR_SUCCESS) return ret;
3427
3428 if (!szProduct) szProduct = product;
3429 if (!comp[0])
3430 {
3431 MSIINSTALLCONTEXT ctx;
3432 WCHAR *components;
3433 GUID guid;
3434
3435 /* use the first component of the feature if the descriptor component is empty */
3436 if ((ret = msi_locate_product( szProduct, &ctx ))) return ret;
3437 if ((ret = MSIREG_OpenUserDataFeaturesKey( szProduct, NULL, ctx, &hkey, FALSE )))
3438 {
3439 return ERROR_FILE_NOT_FOUND;
3440 }
3441 components = reg_get_sz( hkey, feature );
3442 RegCloseKey( hkey );
3443 if (!components) return ERROR_FILE_NOT_FOUND;
3444
3445 if (strlenW( components ) < BASE85_SIZE || !decode_base85_guid( components, &guid ))
3446 {
3447 msi_free( components );
3448 return ERROR_FILE_NOT_FOUND;
3449 }
3450 msi_free( components );
3451 StringFromGUID2( &guid, comp, sizeof(comp)/sizeof(comp[0]) );
3452 }
3453
3454 state = MSI_GetComponentPath( szProduct, comp, szAllSid, MSIINSTALLCONTEXT_ALL, lpPathBuf, pcchPathBuf );
3455
3456 if (state == INSTALLSTATE_MOREDATA) return ERROR_MORE_DATA;
3457 if (state != INSTALLSTATE_LOCAL) return ERROR_FILE_NOT_FOUND;
3458 return ERROR_SUCCESS;
3459 }
3460
3461 /***********************************************************************
3462 * MsiProvideQualifiedComponentExW [MSI.@]
3463 */
3464 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
3465 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
3466 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
3467 LPDWORD pcchPathBuf)
3468 {
3469 awstring path;
3470
3471 TRACE("%s %s %u %s %u %u %p %p\n", debugstr_w(szComponent),
3472 debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
3473 Unused1, Unused2, lpPathBuf, pcchPathBuf);
3474
3475 path.unicode = TRUE;
3476 path.str.w = lpPathBuf;
3477
3478 return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
3479 dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
3480 }
3481
3482 /***********************************************************************
3483 * MsiProvideQualifiedComponentExA [MSI.@]
3484 */
3485 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
3486 LPCSTR szQualifier, DWORD dwInstallMode, LPCSTR szProduct,
3487 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
3488 LPDWORD pcchPathBuf)
3489 {
3490 LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
3491 UINT r = ERROR_OUTOFMEMORY;
3492 awstring path;
3493
3494 TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
3495 debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
3496 Unused1, Unused2, lpPathBuf, pcchPathBuf);
3497
3498 szwComponent = strdupAtoW( szComponent );
3499 if (szComponent && !szwComponent)
3500 goto end;
3501
3502 szwQualifier = strdupAtoW( szQualifier );
3503 if (szQualifier && !szwQualifier)
3504 goto end;
3505
3506 szwProduct = strdupAtoW( szProduct );
3507 if (szProduct && !szwProduct)
3508 goto end;
3509
3510 path.unicode = FALSE;
3511 path.str.a = lpPathBuf;
3512
3513 r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
3514 dwInstallMode, szwProduct, Unused1,
3515 Unused2, &path, pcchPathBuf);
3516 end:
3517 msi_free(szwProduct);
3518 msi_free(szwComponent);
3519 msi_free(szwQualifier);
3520
3521 return r;
3522 }
3523
3524 /***********************************************************************
3525 * MsiProvideQualifiedComponentW [MSI.@]
3526 */
3527 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
3528 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
3529 LPDWORD pcchPathBuf)
3530 {
3531 return MsiProvideQualifiedComponentExW(szComponent, szQualifier,
3532 dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
3533 }
3534
3535 /***********************************************************************
3536 * MsiProvideQualifiedComponentA [MSI.@]
3537 */
3538 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
3539 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
3540 LPDWORD pcchPathBuf)
3541 {
3542 return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
3543 dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
3544 }
3545
3546 /***********************************************************************
3547 * MSI_GetUserInfo [internal]
3548 */
3549 static USERINFOSTATE MSI_GetUserInfo(LPCWSTR szProduct,
3550 awstring *lpUserNameBuf, LPDWORD pcchUserNameBuf,
3551 awstring *lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3552 awstring *lpSerialBuf, LPDWORD pcchSerialBuf)
3553 {
3554 WCHAR *user, *org, *serial, squashed_pc[SQUASHED_GUID_SIZE];
3555 USERINFOSTATE state;
3556 HKEY hkey, props;
3557 LPCWSTR orgptr;
3558 UINT r;
3559
3560 TRACE("%s %p %p %p %p %p %p\n", debugstr_w(szProduct), lpUserNameBuf,
3561 pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
3562 pcchSerialBuf);
3563
3564 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
3565 return USERINFOSTATE_INVALIDARG;
3566
3567 if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
3568 &hkey, FALSE) != ERROR_SUCCESS &&
3569 MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3570 &hkey, FALSE) != ERROR_SUCCESS &&
3571 MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
3572 &hkey, FALSE) != ERROR_SUCCESS)
3573 {
3574 return USERINFOSTATE_UNKNOWN;
3575 }
3576
3577 if (MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
3578 NULL, &props, FALSE) != ERROR_SUCCESS &&
3579 MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE,
3580 NULL, &props, FALSE) != ERROR_SUCCESS)
3581 {
3582 RegCloseKey(hkey);
3583 return USERINFOSTATE_ABSENT;
3584 }
3585
3586 user = msi_reg_get_val_str(props, INSTALLPROPERTY_REGOWNERW);
3587 org = msi_reg_get_val_str(props, INSTALLPROPERTY_REGCOMPANYW);
3588 serial = msi_reg_get_val_str(props, INSTALLPROPERTY_PRODUCTIDW);
3589 state = USERINFOSTATE_ABSENT;
3590
3591 RegCloseKey(hkey);
3592 RegCloseKey(props);
3593
3594 if (user && serial)
3595 state = USERINFOSTATE_PRESENT;
3596
3597 if (pcchUserNameBuf)
3598 {
3599 if (lpUserNameBuf && !user)
3600 {
3601 (*pcchUserNameBuf)--;
3602 goto done;
3603 }
3604
3605 r = msi_strcpy_to_awstring(user, -1, lpUserNameBuf, pcchUserNameBuf);
3606 if (r == ERROR_MORE_DATA)
3607 {
3608 state = USERINFOSTATE_MOREDATA;
3609 goto done;
3610 }
3611 }
3612
3613 if (pcchOrgNameBuf)
3614 {
3615 orgptr = org;
3616 if (!orgptr) orgptr = szEmpty;
3617
3618 r = msi_strcpy_to_awstring(orgptr, -1, lpOrgNameBuf, pcchOrgNameBuf);
3619 if (r == ERROR_MORE_DATA)
3620 {
3621 state = USERINFOSTATE_MOREDATA;
3622 goto done;
3623 }
3624 }
3625
3626 if (pcchSerialBuf)
3627 {
3628 if (!serial)
3629 {
3630 (*pcchSerialBuf)--;
3631 goto done;
3632 }
3633
3634 r = msi_strcpy_to_awstring(serial, -1, lpSerialBuf, pcchSerialBuf);
3635 if (r == ERROR_MORE_DATA)
3636 state = USERINFOSTATE_MOREDATA;
3637 }
3638
3639 done:
3640 msi_free(user);
3641 msi_free(org);
3642 msi_free(serial);
3643
3644 return state;
3645 }
3646
3647 /***********************************************************************
3648 * MsiGetUserInfoW [MSI.@]
3649 */
3650 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
3651 LPWSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3652 LPWSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3653 LPWSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3654 {
3655 awstring user, org, serial;
3656
3657 if ((lpUserNameBuf && !pcchUserNameBuf) ||
3658 (lpOrgNameBuf && !pcchOrgNameBuf) ||
3659 (lpSerialBuf && !pcchSerialBuf))
3660 return USERINFOSTATE_INVALIDARG;
3661
3662 user.unicode = TRUE;
3663 user.str.w = lpUserNameBuf;
3664 org.unicode = TRUE;
3665 org.str.w = lpOrgNameBuf;
3666 serial.unicode = TRUE;
3667 serial.str.w = lpSerialBuf;
3668
3669 return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
3670 &org, pcchOrgNameBuf,
3671 &serial, pcchSerialBuf );
3672 }
3673
3674 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
3675 LPSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3676 LPSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3677 LPSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3678 {
3679 awstring user, org, serial;
3680 LPWSTR prod;
3681 UINT r;
3682
3683 if ((lpUserNameBuf && !pcchUserNameBuf) ||
3684 (lpOrgNameBuf && !pcchOrgNameBuf) ||
3685 (lpSerialBuf && !pcchSerialBuf))
3686 return USERINFOSTATE_INVALIDARG;
3687
3688 prod = strdupAtoW( szProduct );
3689 if (szProduct && !prod)
3690 return ERROR_OUTOFMEMORY;
3691
3692 user.unicode = FALSE;
3693 user.str.a = lpUserNameBuf;
3694 org.unicode = FALSE;
3695 org.str.a = lpOrgNameBuf;
3696 serial.unicode = FALSE;
3697 serial.str.a = lpSerialBuf;
3698
3699 r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
3700 &org, pcchOrgNameBuf,
3701 &serial, pcchSerialBuf );
3702
3703 msi_free( prod );
3704
3705 return r;
3706 }
3707
3708 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
3709 {
3710 MSIHANDLE handle;
3711 UINT rc;
3712 MSIPACKAGE *package;
3713 static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
3714
3715 TRACE("(%s)\n",debugstr_w(szProduct));
3716
3717 rc = MsiOpenProductW(szProduct,&handle);
3718 if (rc != ERROR_SUCCESS)
3719 return ERROR_INVALID_PARAMETER;
3720
3721 /* MsiCollectUserInfo cannot be called from a custom action. */
3722 package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3723 if (!package)
3724 return ERROR_CALL_NOT_IMPLEMENTED;
3725
3726 rc = ACTION_PerformUIAction(package, szFirstRun, SCRIPT_NONE);
3727 msiobj_release( &package->hdr );
3728
3729 MsiCloseHandle(handle);
3730
3731 return rc;
3732 }
3733
3734 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
3735 {
3736 MSIHANDLE handle;
3737 UINT rc;
3738 MSIPACKAGE *package;
3739 static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
3740
3741 TRACE("(%s)\n",debugstr_a(szProduct));
3742
3743 rc = MsiOpenProductA(szProduct,&handle);
3744 if (rc != ERROR_SUCCESS)
3745 return ERROR_INVALID_PARAMETER;
3746
3747 /* MsiCollectUserInfo cannot be called from a custom action. */
3748 package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3749 if (!package)
3750 return ERROR_CALL_NOT_IMPLEMENTED;
3751
3752 rc = ACTION_PerformUIAction(package, szFirstRun, SCRIPT_NONE);
3753 msiobj_release( &package->hdr );
3754
3755 MsiCloseHandle(handle);
3756
3757 return rc;
3758 }
3759
3760 /***********************************************************************
3761 * MsiConfigureFeatureA [MSI.@]
3762 */
3763 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
3764 {
3765 LPWSTR prod, feat = NULL;
3766 UINT r = ERROR_OUTOFMEMORY;
3767
3768 TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
3769
3770 prod = strdupAtoW( szProduct );
3771 if (szProduct && !prod)
3772 goto end;
3773
3774 feat = strdupAtoW( szFeature );
3775 if (szFeature && !feat)
3776 goto end;
3777
3778 r = MsiConfigureFeatureW(prod, feat, eInstallState);
3779
3780 end: