diff options
Diffstat (limited to 'src/ext/ComPlus/ca/cputilsched.cpp')
-rw-r--r-- | src/ext/ComPlus/ca/cputilsched.cpp | 885 |
1 files changed, 885 insertions, 0 deletions
diff --git a/src/ext/ComPlus/ca/cputilsched.cpp b/src/ext/ComPlus/ca/cputilsched.cpp new file mode 100644 index 00000000..1a958c56 --- /dev/null +++ b/src/ext/ComPlus/ca/cputilsched.cpp | |||
@@ -0,0 +1,885 @@ | |||
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 `User` 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"ComPlusPartition")) giTables |= cptComPlusPartition; | ||
57 | if (S_OK == WcaTableExists(L"ComPlusPartitionProperty")) giTables |= cptComPlusPartitionProperty; | ||
58 | if (S_OK == WcaTableExists(L"ComPlusPartitionRole")) giTables |= cptComPlusPartitionRole; | ||
59 | if (S_OK == WcaTableExists(L"ComPlusUserInPartitionRole")) giTables |= cptComPlusUserInPartitionRole; | ||
60 | if (S_OK == WcaTableExists(L"ComPlusGroupInPartitionRole")) giTables |= cptComPlusGroupInPartitionRole; | ||
61 | if (S_OK == WcaTableExists(L"ComPlusPartitionUser")) giTables |= cptComPlusPartitionUser; | ||
62 | if (S_OK == WcaTableExists(L"ComPlusApplication")) giTables |= cptComPlusApplication; | ||
63 | if (S_OK == WcaTableExists(L"ComPlusApplicationProperty")) giTables |= cptComPlusApplicationProperty; | ||
64 | if (S_OK == WcaTableExists(L"ComPlusApplicationRole")) giTables |= cptComPlusApplicationRole; | ||
65 | if (S_OK == WcaTableExists(L"ComPlusApplicationRoleProperty")) giTables |= cptComPlusApplicationRoleProperty; | ||
66 | if (S_OK == WcaTableExists(L"ComPlusUserInApplicationRole")) giTables |= cptComPlusUserInApplicationRole; | ||
67 | if (S_OK == WcaTableExists(L"ComPlusGroupInApplicationRole")) giTables |= cptComPlusGroupInApplicationRole; | ||
68 | if (S_OK == WcaTableExists(L"ComPlusAssembly")) giTables |= cptComPlusAssembly; | ||
69 | if (S_OK == WcaTableExists(L"ComPlusAssemblyDependency")) giTables |= cptComPlusAssemblyDependency; | ||
70 | if (S_OK == WcaTableExists(L"ComPlusComponent")) giTables |= cptComPlusComponent; | ||
71 | if (S_OK == WcaTableExists(L"ComPlusComponentProperty")) giTables |= cptComPlusComponentProperty; | ||
72 | if (S_OK == WcaTableExists(L"ComPlusRoleForComponent")) giTables |= cptComPlusRoleForComponent; | ||
73 | if (S_OK == WcaTableExists(L"ComPlusInterface")) giTables |= cptComPlusInterface; | ||
74 | if (S_OK == WcaTableExists(L"ComPlusInterfaceProperty")) giTables |= cptComPlusInterfaceProperty; | ||
75 | if (S_OK == WcaTableExists(L"ComPlusRoleForInterface")) giTables |= cptComPlusRoleForInterface; | ||
76 | if (S_OK == WcaTableExists(L"ComPlusMethod")) giTables |= cptComPlusMethod; | ||
77 | if (S_OK == WcaTableExists(L"ComPlusMethodProperty")) giTables |= cptComPlusMethodProperty; | ||
78 | if (S_OK == WcaTableExists(L"ComPlusRoleForMethod")) giTables |= cptComPlusRoleForMethod; | ||
79 | if (S_OK == WcaTableExists(L"ComPlusSubscription")) giTables |= cptComPlusSubscription; | ||
80 | if (S_OK == WcaTableExists(L"ComPlusSubscriptionProperty")) 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 collecton 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 | } | ||