main
cpp 885 lines 24.3 KB
Raw
1 // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3 #include "precomp.h"
4
5
6 // sql queries
7
8 LPCWSTR vcsActionTextQuery =
9 L"SELECT `Description`, `Template` FROM `ActionText` WHERE `Action` = ?";
10 enum eActionTextQuery { atqDescription = 1, atqTemplate };
11
12 LPCWSTR vcsComponentAttributesQuery =
13 L"SELECT `Attributes` FROM `Component` WHERE `Component` = ?";
14 enum eComponentAttributesQuery { caqAttributes = 1 };
15
16 LPCWSTR vcsUserQuery = L"SELECT `Domain`, `Name` FROM `Wix4User` WHERE `User` = ?";
17 enum eUserQuery { uqDomain = 1, uqName };
18
19 enum ePropertyQuery { pqName = 1, pqValue };
20
21
22 // prototypes for private helper functions
23
24 static HRESULT FindPropertyDefinition(
25 CPI_PROPERTY_DEFINITION* pPropDefList,
26 LPCWSTR pwzName,
27 CPI_PROPERTY_DEFINITION** ppPropDef
28 );
29 static HRESULT GetUserAccountName(
30 LPCWSTR pwzKey,
31 LPWSTR* ppwzAccount
32 );
33
34
35 // variables
36
37 static ICOMAdminCatalog* gpiCatalog;
38 static ICatalogCollection* gpiPartColl;
39 static ICatalogCollection* gpiAppColl;
40
41 static int giTables;
42
43
44 // function definitions
45
46 void CpiSchedInitialize()
47 {
48 // collections
49 gpiCatalog = NULL;
50 gpiPartColl = NULL;
51 gpiAppColl = NULL;
52
53 // tables
54 giTables = 0;
55
56 if (S_OK == WcaTableExists(L"Wix4ComPlusPartition")) giTables |= cptComPlusPartition;
57 if (S_OK == WcaTableExists(L"Wix4ComPlusPartitionProperty")) giTables |= cptComPlusPartitionProperty;
58 if (S_OK == WcaTableExists(L"Wix4ComPlusPartitionRole")) giTables |= cptComPlusPartitionRole;
59 if (S_OK == WcaTableExists(L"Wix4ComPlusUserInPartitionRole")) giTables |= cptComPlusUserInPartitionRole;
60 if (S_OK == WcaTableExists(L"Wix4ComPlusGroupInPartitionRole")) giTables |= cptComPlusGroupInPartitionRole;
61 if (S_OK == WcaTableExists(L"Wix4ComPlusPartitionUser")) giTables |= cptComPlusPartitionUser;
62 if (S_OK == WcaTableExists(L"Wix4ComPlusApplication")) giTables |= cptComPlusApplication;
63 if (S_OK == WcaTableExists(L"Wix4ComPlusApplicationProperty")) giTables |= cptComPlusApplicationProperty;
64 if (S_OK == WcaTableExists(L"Wix4ComPlusApplicationRole")) giTables |= cptComPlusApplicationRole;
65 if (S_OK == WcaTableExists(L"Wix4ComPlusAppRoleProperty")) giTables |= cptComPlusApplicationRoleProperty;
66 if (S_OK == WcaTableExists(L"Wix4ComPlusUserInAppRole")) giTables |= cptComPlusUserInApplicationRole;
67 if (S_OK == WcaTableExists(L"Wix4ComPlusGroupInAppRole")) giTables |= cptComPlusGroupInApplicationRole;
68 if (S_OK == WcaTableExists(L"Wix4ComPlusAssembly")) giTables |= cptComPlusAssembly;
69 if (S_OK == WcaTableExists(L"Wix4ComPlusAssemblyDependency")) giTables |= cptComPlusAssemblyDependency;
70 if (S_OK == WcaTableExists(L"Wix4ComPlusComponent")) giTables |= cptComPlusComponent;
71 if (S_OK == WcaTableExists(L"Wix4ComPlusComponentProperty")) giTables |= cptComPlusComponentProperty;
72 if (S_OK == WcaTableExists(L"Wix4ComPlusRoleForComponent")) giTables |= cptComPlusRoleForComponent;
73 if (S_OK == WcaTableExists(L"Wix4ComPlusInterface")) giTables |= cptComPlusInterface;
74 if (S_OK == WcaTableExists(L"Wix4ComPlusInterfaceProperty")) giTables |= cptComPlusInterfaceProperty;
75 if (S_OK == WcaTableExists(L"Wix4ComPlusRoleForInterface")) giTables |= cptComPlusRoleForInterface;
76 if (S_OK == WcaTableExists(L"Wix4ComPlusMethod")) giTables |= cptComPlusMethod;
77 if (S_OK == WcaTableExists(L"Wix4ComPlusMethodProperty")) giTables |= cptComPlusMethodProperty;
78 if (S_OK == WcaTableExists(L"Wix4ComPlusRoleForMethod")) giTables |= cptComPlusRoleForMethod;
79 if (S_OK == WcaTableExists(L"Wix4ComPlusSubscription")) giTables |= cptComPlusSubscription;
80 if (S_OK == WcaTableExists(L"Wix4ComPlusSubscriptionProperty")) giTables |= cptComPlusSubscriptionProperty;
81 }
82
83 void CpiSchedFinalize()
84 {
85 // collections
86 ReleaseObject(gpiCatalog);
87 ReleaseObject(gpiPartColl);
88 ReleaseObject(gpiAppColl);
89 }
90
91 BOOL CpiTableExists(
92 int iTable
93 )
94 {
95 return (giTables & iTable) == iTable;
96 }
97
98 HRESULT CpiSchedGetAdminCatalog(
99 ICOMAdminCatalog** ppiCatalog
100 )
101 {
102 HRESULT hr = S_OK;
103
104 if (!gpiCatalog)
105 {
106 // get collection
107 hr = ::CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_ALL, IID_ICOMAdminCatalog, (void**)&gpiCatalog);
108 ExitOnFailure(hr, "Failed to create COM+ admin catalog object");
109 }
110
111 // return value
112 gpiCatalog->AddRef();
113 *ppiCatalog = gpiCatalog;
114
115 hr = S_OK;
116
117 LExit:
118 return hr;
119 }
120
121 HRESULT CpiSchedGetCatalogCollection(
122 LPCWSTR pwzName,
123 ICatalogCollection** ppiColl
124 )
125 {
126 HRESULT hr = S_OK;
127
128 ICOMAdminCatalog* piCatalog = NULL;
129 IDispatch* piDisp = NULL;
130 BSTR bstrName = NULL;
131
132 // copy name string
133 bstrName = ::SysAllocString(pwzName);
134 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name");
135
136 // get catalog
137 hr = CpiSchedGetAdminCatalog(&piCatalog);
138 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
139
140 // get collection from catalog
141 hr = piCatalog->GetCollection(bstrName, &piDisp);
142 ExitOnFailure(hr, "Failed to get collection");
143
144 hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl);
145 ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface");
146
147 // populate collection
148 hr = (*ppiColl)->Populate();
149 ExitOnFailure(hr, "Failed to populate collection");
150
151 hr = S_OK;
152
153 LExit:
154 // clean up
155 ReleaseObject(piCatalog);
156 ReleaseObject(piDisp);
157 ReleaseBSTR(bstrName);
158
159 return hr;
160 }
161
162 HRESULT CpiSchedGetCatalogCollection(
163 ICatalogCollection* piColl,
164 ICatalogObject* piObj,
165 LPCWSTR pwzName,
166 ICatalogCollection** ppiColl
167 )
168 {
169 HRESULT hr = S_OK;
170
171 ICOMAdminCatalog* piCatalog = NULL;
172 IDispatch* piDisp = NULL;
173 BSTR bstrName = NULL;
174
175 VARIANT vtKey;
176 ::VariantInit(&vtKey);
177
178 // copy name string
179 bstrName = ::SysAllocString(pwzName);
180 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name");
181
182 // get catalog
183 hr = CpiSchedGetAdminCatalog(&piCatalog);
184 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
185
186 // get key
187 hr = piObj->get_Key(&vtKey);
188 ExitOnFailure(hr, "Failed to get object key");
189
190 // get collecton from catalog
191 hr = piColl->GetCollection(bstrName, vtKey, &piDisp);
192 ExitOnFailure(hr, "Failed to get collection");
193
194 hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl);
195 ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface");
196
197 // populate collection
198 hr = (*ppiColl)->Populate();
199 ExitOnFailure(hr, "Failed to populate collection");
200
201 hr = S_OK;
202
203 LExit:
204 // clean up
205 ReleaseObject(piCatalog);
206 ReleaseObject(piDisp);
207 ReleaseBSTR(bstrName);
208 ::VariantClear(&vtKey);
209
210 return hr;
211 }
212
213 HRESULT CpiGetKeyForObject(
214 ICatalogObject* piObj,
215 LPWSTR pwzKey,
216 SIZE_T cchKey
217 )
218 {
219 HRESULT hr = S_OK;
220
221 VARIANT vtKey;
222 ::VariantInit(&vtKey);
223
224 // get key
225 hr = piObj->get_Key(&vtKey);
226 ExitOnFailure(hr, "Failed to get key");
227
228 // change variant type
229 hr = ::VariantChangeType(&vtKey, &vtKey, 0, VT_BSTR);
230 ExitOnFailure(hr, "Failed to change variant type");
231
232 // copy key
233 hr = StringCchCopyW(pwzKey, cchKey, vtKey.bstrVal);
234 ExitOnFailure(hr, "Failed to copy key");
235
236 hr = S_OK;
237
238 LExit:
239 // clean up
240 ::VariantClear(&vtKey);
241
242 return hr;
243 }
244
245 HRESULT CpiFindCollectionObject(
246 ICatalogCollection* piColl,
247 LPCWSTR pwzID,
248 LPCWSTR pwzName,
249 ICatalogObject** ppiObj
250 )
251 {
252 HRESULT hr = S_OK;
253
254 IDispatch* piDisp = NULL;
255 ICatalogObject* piObj = NULL;
256
257 VARIANT vtVal;
258 ::VariantInit(&vtVal);
259
260 long lCnt;
261 hr = piColl->get_Count(&lCnt);
262 ExitOnFailure(hr, "Failed to get to number of items in collection");
263
264 for (long i = 0; i < lCnt; i++)
265 {
266 // get ICatalogObject interface
267 hr = piColl->get_Item(i, &piDisp);
268 ExitOnFailure(hr, "Failed to get object from collection");
269
270 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
271 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
272
273 // compare id
274 if (pwzID && *pwzID)
275 {
276 hr = piObj->get_Key(&vtVal);
277 ExitOnFailure(hr, "Failed to get key");
278
279 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
280 ExitOnFailure(hr, "Failed to change variant type");
281
282 if (0 == lstrcmpiW(vtVal.bstrVal, pwzID))
283 {
284 if (ppiObj)
285 {
286 *ppiObj = piObj;
287 piObj = NULL;
288 }
289 ExitFunction1(hr = S_OK);
290 }
291
292 ::VariantClear(&vtVal);
293 }
294
295 // compare name
296 if (pwzName && *pwzName)
297 {
298 hr = piObj->get_Name(&vtVal);
299 ExitOnFailure(hr, "Failed to get name");
300
301 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
302 ExitOnFailure(hr, "Failed to change variant type");
303
304 if (0 == lstrcmpW(vtVal.bstrVal, pwzName))
305 {
306 if (ppiObj)
307 {
308 *ppiObj = piObj;
309 piObj = NULL;
310 }
311 ExitFunction1(hr = S_OK);
312 }
313
314 ::VariantClear(&vtVal);
315 }
316
317 // release interface pointers
318 ReleaseNullObject(piDisp);
319 ReleaseNullObject(piObj);
320 }
321
322 hr = S_FALSE;
323
324 LExit:
325 // clean up
326 ReleaseObject(piDisp);
327 ReleaseObject(piObj);
328
329 ::VariantClear(&vtVal);
330
331 return hr;
332 }
333
334 HRESULT CpiSchedGetPartitionsCollection(
335 ICatalogCollection** ppiPartColl
336 )
337 {
338 HRESULT hr = S_OK;
339
340 if (!gpiPartColl)
341 {
342 // get collection
343 hr = CpiSchedGetCatalogCollection(L"Partitions", &gpiPartColl);
344 ExitOnFailure(hr, "Failed to get partitions collection");
345 }
346
347 // return value
348 gpiPartColl->AddRef();
349 *ppiPartColl = gpiPartColl;
350
351 hr = S_OK;
352
353 LExit:
354 return hr;
355 }
356
357 HRESULT CpiSchedGetApplicationsCollection(
358 ICatalogCollection** ppiAppColl
359 )
360 {
361 HRESULT hr = S_OK;
362
363 ICOMAdminCatalog* piCatalog = NULL;
364 ICOMAdminCatalog2* piCatalog2 = NULL;
365 ICatalogCollection* piPartColl = NULL;
366 ICatalogObject* piPartObj = NULL;
367 BSTR bstrGlobPartID = NULL;
368
369 if (!gpiAppColl)
370 {
371 // get catalog
372 hr = CpiSchedGetAdminCatalog(&piCatalog);
373 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
374
375 // get ICOMAdminCatalog2 interface
376 hr = piCatalog->QueryInterface(IID_ICOMAdminCatalog2, (void**)&piCatalog2);
377
378 // COM+ 1.5 or later
379 if (E_NOINTERFACE != hr)
380 {
381 ExitOnFailure(hr, "Failed to get IID_ICOMAdminCatalog2 interface");
382
383 // get global partition id
384 hr = piCatalog2->get_GlobalPartitionID(&bstrGlobPartID);
385 ExitOnFailure(hr, "Failed to get global partition id");
386
387 // get partitions collection
388 hr = CpiSchedGetPartitionsCollection(&piPartColl);
389 ExitOnFailure(hr, "Failed to get partitions collection");
390
391 // find object
392 hr = CpiFindCollectionObject(piPartColl, bstrGlobPartID, NULL, &piPartObj);
393 ExitOnFailure(hr, "Failed to find collection object");
394
395 if (S_FALSE == hr)
396 ExitFunction(); // partition not found, exit with hr = S_FALSE
397
398 // get applications collection
399 hr = CpiSchedGetCatalogCollection(piPartColl, piPartObj, L"Applications", &gpiAppColl);
400 ExitOnFailure(hr, "Failed to get applications collection");
401 }
402
403 // COM+ pre 1.5
404 else
405 {
406 // get applications collection
407 hr = CpiSchedGetCatalogCollection(L"Applications", &gpiAppColl);
408 ExitOnFailure(hr, "Failed to get applications collection");
409 }
410 }
411
412 // return value
413 gpiAppColl->AddRef();
414 *ppiAppColl = gpiAppColl;
415
416 hr = S_OK;
417
418 LExit:
419 // clean up
420 ReleaseObject(piCatalog);
421 ReleaseObject(piCatalog2);
422 ReleaseObject(piPartColl);
423 ReleaseObject(piPartObj);
424 ReleaseBSTR(bstrGlobPartID);
425
426 return hr;
427 }
428
429 HRESULT CpiAddActionTextToActionData(
430 LPCWSTR pwzAction,
431 LPWSTR* ppwzActionData
432 )
433 {
434 HRESULT hr = S_OK;
435
436 PMSIHANDLE hView, hRecKey, hRec;
437
438 LPWSTR pwzDescription = NULL;
439 LPWSTR pwzTemplate = NULL;
440
441 if (S_OK == WcaTableExists(L"ActionText"))
442 {
443 // create parameter record
444 hRecKey = ::MsiCreateRecord(1);
445 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
446 hr = WcaSetRecordString(hRecKey, 1, pwzAction);
447 ExitOnFailure(hr, "Failed to set record string");
448
449 // open view
450 hr = WcaOpenView(vcsActionTextQuery, &hView);
451 ExitOnFailure(hr, "Failed to open view on ActionText table");
452 hr = WcaExecuteView(hView, hRecKey);
453 ExitOnFailure(hr, "Failed to execute view on ActionText table");
454
455 // fetch record
456 hr = WcaFetchSingleRecord(hView, &hRec);
457 if (S_FALSE != hr)
458 {
459 ExitOnFailure(hr, "Failed to fetch action text record");
460
461 // get description
462 hr = WcaGetRecordString(hRec, atqDescription, &pwzDescription);
463 ExitOnFailure(hr, "Failed to get description");
464
465 // get template
466 hr = WcaGetRecordString(hRec, atqTemplate, &pwzTemplate);
467 ExitOnFailure(hr, "Failed to get template");
468 }
469 }
470
471 // add action name to action data
472 hr = WcaWriteStringToCaData(pwzAction, ppwzActionData);
473 ExitOnFailure(hr, "Failed to add action name to custom action data");
474
475 // add description to action data
476 hr = WcaWriteStringToCaData(pwzDescription ? pwzDescription : L"", ppwzActionData);
477 ExitOnFailure(hr, "Failed to add description to custom action data");
478
479 // add template to action data
480 hr = WcaWriteStringToCaData(pwzTemplate ? pwzTemplate : L"", ppwzActionData);
481 ExitOnFailure(hr, "Failed to add template to custom action data");
482
483 hr = S_OK;
484
485 LExit:
486 // clean up
487 ReleaseStr(pwzDescription);
488 ReleaseStr(pwzTemplate);
489
490 return hr;
491 }
492
493 HRESULT CpiVerifyComponentArchitecure(
494 LPCWSTR pwzComponent,
495 BOOL* pfMatchingArchitecture
496 )
497 {
498 HRESULT hr = S_OK;
499
500 PMSIHANDLE hView, hRecKey, hRec;
501
502 int iAttributes = 0;
503
504 if (S_OK == WcaTableExists(L"Component"))
505 {
506 // create parameter record
507 hRecKey = ::MsiCreateRecord(1);
508 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
509 hr = WcaSetRecordString(hRecKey, 1, pwzComponent);
510 ExitOnFailure(hr, "Failed to set record string");
511
512 // open view
513 hr = WcaOpenView(vcsComponentAttributesQuery, &hView);
514 ExitOnFailure(hr, "Failed to open view on ActionText table");
515 hr = WcaExecuteView(hView, hRecKey);
516 ExitOnFailure(hr, "Failed to execute view on ActionText table");
517
518 // fetch record
519 hr = WcaFetchSingleRecord(hView, &hRec);
520 if (S_FALSE != hr)
521 {
522 ExitOnFailure(hr, "Failed to fetch component record");
523
524 hr = WcaGetRecordInteger(hRec, caqAttributes, &iAttributes);
525 ExitOnFailure(hr, "Failed to get component attributes");
526 }
527 }
528
529 // return values
530 #ifdef _WIN64
531 *pfMatchingArchitecture = 256 == (iAttributes & 256);
532 #else
533 *pfMatchingArchitecture = 256 != (iAttributes & 256);
534 #endif
535
536 hr = S_OK;
537
538 LExit:
539 return hr;
540 }
541
542 HRESULT CpiPropertiesRead(
543 LPCWSTR pwzQuery,
544 LPCWSTR pwzKey,
545 CPI_PROPERTY_DEFINITION* pPropDefList,
546 CPI_PROPERTY** ppPropList,
547 int* piCount
548 )
549 {
550 HRESULT hr = S_OK;
551
552 PMSIHANDLE hView, hRecKey, hRec;
553
554 CPI_PROPERTY* pItm = NULL;
555 LPWSTR pwzData = NULL;
556
557 int iVersionNT = 0;
558
559 CPI_PROPERTY_DEFINITION* pPropDef;
560
561 *piCount = 0;
562
563 // get NT version
564 hr = WcaGetIntProperty(L"VersionNT", &iVersionNT);
565 ExitOnFailure(hr, "Failed to set record string");
566
567 // create parameter record
568 hRecKey = ::MsiCreateRecord(1);
569 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
570 hr = WcaSetRecordString(hRecKey, 1, pwzKey);
571 ExitOnFailure(hr, "Failed to set record string");
572
573 // open view
574 hr = WcaOpenView(pwzQuery, &hView);
575 ExitOnFailure(hr, "Failed to open view on property table");
576 hr = WcaExecuteView(hView, hRecKey);
577 ExitOnFailure(hr, "Failed to execute view on property table");
578
579 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
580 {
581 // create entry
582 pItm = (CPI_PROPERTY*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PROPERTY));
583 if (!pItm)
584 ExitFunction1(hr = E_OUTOFMEMORY);
585
586 // get name
587 hr = WcaGetRecordString(hRec, pqName, &pwzData);
588 ExitOnFailure(hr, "Failed to get name");
589 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
590
591 // get value
592 hr = WcaGetRecordFormattedString(hRec, pqValue, &pItm->pwzValue);
593 ExitOnFailure(hr, "Failed to get value");
594
595 // find property definition
596 hr = FindPropertyDefinition(pPropDefList, pItm->wzName, &pPropDef);
597 ExitOnFailure(hr, "Failed to find property definition");
598
599 if (S_FALSE == hr)
600 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Unknown property, key: %S, property: %S", pwzKey, pItm->wzName);
601
602 // check version, ignore if catalog version is too low
603 if (iVersionNT < pPropDef->iMinVersionNT)
604 {
605 WcaLog(LOGMSG_VERBOSE, "Skipping property since NT version is too low, key: %S, property: %S", pwzKey, pItm->wzName);
606 CpiPropertiesFreeList(pItm);
607 pItm = NULL;
608 continue;
609 }
610
611 // if the property is a user, replace the User table key with a user account name
612 if (cpptUser == pPropDef->iType)
613 {
614 hr = GetUserAccountName(pItm->pwzValue, &pItm->pwzValue);
615 ExitOnFailure(hr, "Failed to get user account name");
616 }
617
618 // add entry
619 ++*piCount;
620 if (*ppPropList)
621 pItm->pNext = *ppPropList;
622 *ppPropList = pItm;
623 pItm = NULL;
624 }
625
626 if (E_NOMOREITEMS == hr)
627 hr = S_OK;
628
629 LExit:
630 // clean up
631 if (pItm)
632 CpiPropertiesFreeList(pItm);
633
634 ReleaseStr(pwzData);
635
636 return hr;
637 }
638
639 void CpiPropertiesFreeList(
640 CPI_PROPERTY* pList
641 )
642 {
643 while (pList)
644 {
645 ReleaseStr(pList->pwzValue);
646
647 CPI_PROPERTY* pDelete = pList;
648 pList = pList->pNext;
649 ::HeapFree(::GetProcessHeap(), 0, pDelete);
650 }
651 }
652
653 HRESULT CpiAddPropertiesToActionData(
654 int iPropCount,
655 CPI_PROPERTY* pPropList,
656 LPWSTR* ppwzActionData
657 )
658 {
659 HRESULT hr = S_OK;
660
661 hr = WcaWriteIntegerToCaData(iPropCount, ppwzActionData);
662 ExitOnFailure(hr, "Failed to add count to custom action data");
663
664 if (iPropCount) // count might be 0 event thought there are elements in the list
665 {
666 for (CPI_PROPERTY* pProp = pPropList; pProp; pProp = pProp->pNext)
667 {
668 hr = WcaWriteStringToCaData(pProp->wzName, ppwzActionData);
669 ExitOnFailure(hr, "Failed to add property name to custom action data, name: %S", pProp->wzName);
670
671 hr = WcaWriteStringToCaData(pProp->pwzValue, ppwzActionData);
672 ExitOnFailure(hr, "Failed to add property value to custom action data, name: %S", pProp->wzName);
673 }
674 }
675
676 hr = S_OK;
677
678 LExit:
679 return hr;
680 }
681
682 HRESULT CpiBuildAccountName(
683 LPCWSTR pwzDomain,
684 LPCWSTR pwzName,
685 LPWSTR* ppwzAccount
686 )
687 {
688 HRESULT hr = S_OK;
689
690 WCHAR wzComputerName[MAX_COMPUTERNAME_LENGTH + 1];
691 ::ZeroMemory(wzComputerName, sizeof(wzComputerName));
692
693 // if domain is '.', get computer name
694 if (0 == lstrcmpW(pwzDomain, L"."))
695 {
696 DWORD dwSize = countof(wzComputerName);
697 if (!::GetComputerNameW(wzComputerName, &dwSize))
698 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to get computer name");
699 }
700
701 // build account name
702 hr = StrAllocFormatted(ppwzAccount, L"%s\\%s", *wzComputerName ? wzComputerName : pwzDomain, pwzName);
703 ExitOnFailure(hr, "Failed to build domain user name");
704
705 hr = S_OK;
706
707 LExit:
708 return hr;
709 }
710
711 HRESULT CpiGetTempFileName(
712 LPWSTR* ppwzTempFile
713 )
714 {
715 HRESULT hr = S_OK;
716
717 // get temp path
718 WCHAR wzTempPath[MAX_PATH];
719 DWORD dw = ::GetTempPathW(countof(wzTempPath), wzTempPath);
720 if (countof(wzTempPath) <= dw)
721 ExitOnFailure(hr = E_FAIL, "TEMP directory path too long");
722
723 // get unique number
724 LARGE_INTEGER liCount;
725 if (!::QueryPerformanceCounter(&liCount))
726 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to query performance counter");
727
728 // create temp file name
729 hr = StrAllocFormatted(ppwzTempFile, L"%sCPI%I64X.tmp", wzTempPath, liCount.QuadPart);
730 ExitOnFailure(hr, "Failed to create temp file name string");
731
732 hr = S_OK;
733
734 LExit:
735 return hr;
736 }
737
738 HRESULT CpiCreateId(
739 LPWSTR pwzDest,
740 SIZE_T cchDest
741 )
742 {
743 HRESULT hr = S_OK;
744
745 GUID guid;
746
747 // create new guid
748 hr = ::CoCreateGuid(&guid);
749 ExitOnFailure(hr, "Failed to create new guid");
750
751 // convert guid to string
752 if (0 == ::StringFromGUID2(guid, pwzDest, (int)cchDest))
753 ExitOnFailure(hr = E_FAIL, "Failed to convert guid to string");
754
755 hr = S_OK;
756
757 LExit:
758 return hr;
759 }
760
761 BOOL CpiIsInstalled(
762 INSTALLSTATE isInstalled
763 )
764 {
765 return INSTALLSTATE_LOCAL == isInstalled || INSTALLSTATE_SOURCE == isInstalled;
766 }
767
768 BOOL CpiWillBeInstalled(
769 INSTALLSTATE isInstalled,
770 INSTALLSTATE isAction
771 )
772 {
773 return WcaIsInstalling(isInstalled, isAction) ||
774 (CpiIsInstalled(isInstalled) && !WcaIsUninstalling(isInstalled, isAction));
775 }
776
777 HRESULT PcaGuidToRegFormat(
778 LPWSTR pwzGuid,
779 LPWSTR pwzDest,
780 SIZE_T cchDest
781 )
782 {
783 HRESULT hr = S_OK;
784
785 GUID guid = GUID_NULL;
786 int cch = 0;
787
788 WCHAR wz[39];
789 ::ZeroMemory(wz, sizeof(wz));
790
791 cch = lstrlenW(pwzGuid);
792
793 if (38 == cch && L'{' == pwzGuid[0] && L'}' == pwzGuid[37])
794 StringCchCopyW(wz, countof(wz), pwzGuid);
795 else if (36 == cch)
796 StringCchPrintfW(wz, countof(wz), L"{%s}", pwzGuid);
797 else
798 ExitFunction1(hr = E_INVALIDARG);
799
800 // convert string to guid
801 hr = ::CLSIDFromString(wz, &guid);
802 ExitOnFailure(hr, "Failed to parse guid string");
803
804 // convert guid to string
805 if (0 == ::StringFromGUID2(guid, pwzDest, (int)cchDest))
806 ExitOnFailure(hr = E_FAIL, "Failed to convert guid to string");
807
808 hr = S_OK;
809
810 LExit:
811 return hr;
812 }
813
814
815 // helper function definitions
816
817 static HRESULT FindPropertyDefinition(
818 CPI_PROPERTY_DEFINITION* pPropDefList,
819 LPCWSTR pwzName,
820 CPI_PROPERTY_DEFINITION** ppPropDef
821 )
822 {
823 for (CPI_PROPERTY_DEFINITION* pItm = pPropDefList; pItm->pwzName; pItm++)
824 {
825 if (0 == lstrcmpW(pItm->pwzName, pwzName))
826 {
827 *ppPropDef = pItm;
828 return S_OK;
829 }
830 }
831
832 return S_FALSE;
833 }
834
835 static HRESULT GetUserAccountName(
836 LPCWSTR pwzKey,
837 LPWSTR* ppwzAccount
838 )
839 {
840 HRESULT hr = S_OK;
841
842 PMSIHANDLE hView, hRecKey, hRec;
843
844 LPWSTR pwzDomain = NULL;
845 LPWSTR pwzName = NULL;
846
847 // create parameter record
848 hRecKey = ::MsiCreateRecord(1);
849 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
850 hr = WcaSetRecordString(hRecKey, 1, pwzKey);
851 ExitOnFailure(hr, "Failed to set record string");
852
853 // open view
854 hr = WcaOpenView(vcsUserQuery, &hView);
855 ExitOnFailure(hr, "Failed to open view on User table");
856 hr = WcaExecuteView(hView, hRecKey);
857 ExitOnFailure(hr, "Failed to execute view on User table");
858
859 // fetch record
860 hr = WcaFetchSingleRecord(hView, &hRec);
861 if (S_FALSE == hr)
862 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "User not found, key: %S", pwzKey);
863 ExitOnFailure(hr, "Failed to fetch user record");
864
865 // get user domain
866 hr = WcaGetRecordFormattedString(hRec, uqDomain, &pwzDomain);
867 ExitOnFailure(hr, "Failed to get domain");
868
869 // get user name
870 hr = WcaGetRecordFormattedString(hRec, uqName, &pwzName);
871 ExitOnFailure(hr, "Failed to get name");
872
873 // build account name
874 hr = CpiBuildAccountName(pwzDomain, pwzName, ppwzAccount);
875 ExitOnFailure(hr, "Failed to build account name");
876
877 hr = S_OK;
878
879 LExit:
880 // clean up
881 ReleaseStr(pwzDomain);
882 ReleaseStr(pwzName);
883
884 return hr;
885 }