diff options
Diffstat (limited to 'src/burn/engine/exeengine.cpp')
-rw-r--r-- | src/burn/engine/exeengine.cpp | 295 |
1 files changed, 265 insertions, 30 deletions
diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp index 808577bc..3a64ecd8 100644 --- a/src/burn/engine/exeengine.cpp +++ b/src/burn/engine/exeengine.cpp | |||
@@ -2,6 +2,16 @@ | |||
2 | 2 | ||
3 | #include "precomp.h" | 3 | #include "precomp.h" |
4 | 4 | ||
5 | static HRESULT DetectArpEntry( | ||
6 | __in const BURN_PACKAGE* pPackage, | ||
7 | __out BOOTSTRAPPER_PACKAGE_STATE* pPackageState, | ||
8 | __out_opt LPWSTR* psczQuietUninstallString | ||
9 | ); | ||
10 | static HRESULT ParseArpUninstallString( | ||
11 | __in_z LPCWSTR wzArpUninstallString, | ||
12 | __inout LPWSTR* psczExecutablePath, | ||
13 | __inout LPWSTR* psczArguments | ||
14 | ); | ||
5 | 15 | ||
6 | // function definitions | 16 | // function definitions |
7 | 17 | ||
@@ -16,18 +26,73 @@ extern "C" HRESULT ExeEngineParsePackageFromXml( | |||
16 | IXMLDOMNode* pixnNode = NULL; | 26 | IXMLDOMNode* pixnNode = NULL; |
17 | LPWSTR scz = NULL; | 27 | LPWSTR scz = NULL; |
18 | 28 | ||
19 | // @DetectCondition | 29 | // @DetectionType |
20 | hr = XmlGetAttributeEx(pixnExePackage, L"DetectCondition", &pPackage->Exe.sczDetectCondition); | 30 | hr = XmlGetAttributeEx(pixnExePackage, L"DetectionType", &scz); |
21 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @DetectCondition."); | 31 | ExitOnRequiredXmlQueryFailure(hr, "Failed to get @DetectionType."); |
32 | |||
33 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"condition", -1)) | ||
34 | { | ||
35 | pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_CONDITION; | ||
36 | } | ||
37 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"arp", -1)) | ||
38 | { | ||
39 | pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_ARP; | ||
40 | } | ||
41 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"none", -1)) | ||
42 | { | ||
43 | pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_NONE; | ||
44 | } | ||
45 | else | ||
46 | { | ||
47 | ExitWithRootFailure(hr, E_UNEXPECTED, "Invalid detection type: %ls", scz); | ||
48 | } | ||
49 | |||
50 | if (BURN_EXE_DETECTION_TYPE_CONDITION == pPackage->Exe.detectionType) | ||
51 | { | ||
52 | // @DetectCondition | ||
53 | hr = XmlGetAttributeEx(pixnExePackage, L"DetectCondition", &pPackage->Exe.sczDetectCondition); | ||
54 | ExitOnRequiredXmlQueryFailure(hr, "Failed to get @DetectCondition."); | ||
55 | |||
56 | // @UninstallArguments | ||
57 | hr = XmlGetAttributeEx(pixnExePackage, L"UninstallArguments", &pPackage->Exe.sczUninstallArguments); | ||
58 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @UninstallArguments."); | ||
59 | |||
60 | // @Uninstallable | ||
61 | hr = XmlGetYesNoAttribute(pixnExePackage, L"Uninstallable", &pPackage->Exe.fUninstallable); | ||
62 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Uninstallable."); | ||
63 | } | ||
64 | else if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType) | ||
65 | { | ||
66 | // @ArpId | ||
67 | hr = XmlGetAttributeEx(pixnExePackage, L"ArpId", &scz); | ||
68 | ExitOnRequiredXmlQueryFailure(hr, "Failed to get @ArpId."); | ||
69 | |||
70 | hr = PathConcatRelativeToBase(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\", scz, &pPackage->Exe.sczArpKeyPath); | ||
71 | ExitOnFailure(hr, "Failed to build full key path."); | ||
72 | |||
73 | // @ArpDisplayVersion | ||
74 | hr = XmlGetAttributeEx(pixnExePackage, L"ArpDisplayVersion", &scz); | ||
75 | ExitOnRequiredXmlQueryFailure(hr, "Failed to get @ArpDisplayVersion."); | ||
76 | |||
77 | hr = VerParseVersion(scz, 0, FALSE, &pPackage->Exe.pArpDisplayVersion); | ||
78 | ExitOnFailure(hr, "Failed to parse @ArpDisplayVersion: %ls", scz); | ||
79 | |||
80 | if (pPackage->Exe.pArpDisplayVersion->fInvalid) | ||
81 | { | ||
82 | LogId(REPORT_WARNING, MSG_MANIFEST_INVALID_VERSION, scz); | ||
83 | } | ||
84 | |||
85 | // @ArpWin64 | ||
86 | hr = XmlGetYesNoAttribute(pixnExePackage, L"ArpWin64", &pPackage->Exe.fArpWin64); | ||
87 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @ArpWin64."); | ||
88 | |||
89 | pPackage->Exe.fUninstallable = TRUE; | ||
90 | } | ||
22 | 91 | ||
23 | // @InstallArguments | 92 | // @InstallArguments |
24 | hr = XmlGetAttributeEx(pixnExePackage, L"InstallArguments", &pPackage->Exe.sczInstallArguments); | 93 | hr = XmlGetAttributeEx(pixnExePackage, L"InstallArguments", &pPackage->Exe.sczInstallArguments); |
25 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallArguments."); | 94 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallArguments."); |
26 | 95 | ||
27 | // @UninstallArguments | ||
28 | hr = XmlGetAttributeEx(pixnExePackage, L"UninstallArguments", &pPackage->Exe.sczUninstallArguments); | ||
29 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @UninstallArguments."); | ||
30 | |||
31 | // @RepairArguments | 96 | // @RepairArguments |
32 | hr = XmlGetAttributeEx(pixnExePackage, L"RepairArguments", &pPackage->Exe.sczRepairArguments); | 97 | hr = XmlGetAttributeEx(pixnExePackage, L"RepairArguments", &pPackage->Exe.sczRepairArguments); |
33 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RepairArguments."); | 98 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RepairArguments."); |
@@ -36,10 +101,6 @@ extern "C" HRESULT ExeEngineParsePackageFromXml( | |||
36 | hr = XmlGetYesNoAttribute(pixnExePackage, L"Repairable", &pPackage->Exe.fRepairable); | 101 | hr = XmlGetYesNoAttribute(pixnExePackage, L"Repairable", &pPackage->Exe.fRepairable); |
37 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Repairable."); | 102 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Repairable."); |
38 | 103 | ||
39 | // @Uninstallable | ||
40 | hr = XmlGetYesNoAttribute(pixnExePackage, L"Uninstallable", &pPackage->Exe.fUninstallable); | ||
41 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Uninstallable."); | ||
42 | |||
43 | // @Bundle | 104 | // @Bundle |
44 | hr = XmlGetYesNoAttribute(pixnExePackage, L"Bundle", &pPackage->Exe.fBundle); | 105 | hr = XmlGetYesNoAttribute(pixnExePackage, L"Bundle", &pPackage->Exe.fBundle); |
45 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Bundle."); | 106 | ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Bundle."); |
@@ -64,8 +125,7 @@ extern "C" HRESULT ExeEngineParsePackageFromXml( | |||
64 | } | 125 | } |
65 | else | 126 | else |
66 | { | 127 | { |
67 | hr = E_UNEXPECTED; | 128 | ExitWithRootFailure(hr, E_UNEXPECTED, "Invalid protocol type: %ls", scz); |
68 | ExitOnFailure(hr, "Invalid protocol type: %ls", scz); | ||
69 | } | 129 | } |
70 | } | 130 | } |
71 | 131 | ||
@@ -91,6 +151,8 @@ extern "C" void ExeEnginePackageUninitialize( | |||
91 | ReleaseStr(pPackage->Exe.sczInstallArguments); | 151 | ReleaseStr(pPackage->Exe.sczInstallArguments); |
92 | ReleaseStr(pPackage->Exe.sczRepairArguments); | 152 | ReleaseStr(pPackage->Exe.sczRepairArguments); |
93 | ReleaseStr(pPackage->Exe.sczUninstallArguments); | 153 | ReleaseStr(pPackage->Exe.sczUninstallArguments); |
154 | ReleaseStr(pPackage->Exe.sczArpKeyPath); | ||
155 | ReleaseVerutilVersion(pPackage->Exe.pArpDisplayVersion); | ||
94 | ReleaseMem(pPackage->Exe.rgExitCodes); | 156 | ReleaseMem(pPackage->Exe.rgExitCodes); |
95 | 157 | ||
96 | // free command-line arguments | 158 | // free command-line arguments |
@@ -126,15 +188,31 @@ extern "C" HRESULT ExeEngineDetectPackage( | |||
126 | HRESULT hr = S_OK; | 188 | HRESULT hr = S_OK; |
127 | BOOL fDetected = FALSE; | 189 | BOOL fDetected = FALSE; |
128 | 190 | ||
129 | // evaluate detect condition | 191 | switch (pPackage->Exe.detectionType) |
130 | if (pPackage->Exe.sczDetectCondition && *pPackage->Exe.sczDetectCondition) | ||
131 | { | 192 | { |
132 | hr = ConditionEvaluate(pVariables, pPackage->Exe.sczDetectCondition, &fDetected); | 193 | case BURN_EXE_DETECTION_TYPE_NONE: |
133 | ExitOnFailure(hr, "Failed to evaluate executable package detect condition."); | 194 | pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT; |
134 | } | 195 | break; |
196 | case BURN_EXE_DETECTION_TYPE_CONDITION: | ||
197 | // evaluate detect condition | ||
198 | if (pPackage->Exe.sczDetectCondition && *pPackage->Exe.sczDetectCondition) | ||
199 | { | ||
200 | hr = ConditionEvaluate(pVariables, pPackage->Exe.sczDetectCondition, &fDetected); | ||
201 | ExitOnFailure(hr, "Failed to evaluate EXE package detect condition."); | ||
202 | } | ||
203 | |||
204 | // update detect state | ||
205 | pPackage->currentState = fDetected ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT; | ||
135 | 206 | ||
136 | // update detect state | 207 | break; |
137 | pPackage->currentState = fDetected ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT; | 208 | case BURN_EXE_DETECTION_TYPE_ARP: |
209 | hr = DetectArpEntry(pPackage, &pPackage->currentState, NULL); | ||
210 | ExitOnFailure(hr, "Failed to detect EXE package by ArpEntry."); | ||
211 | |||
212 | break; | ||
213 | default: | ||
214 | ExitWithRootFailure(hr, E_INVALIDARG, "Unknown EXE package detection type: %d.", pPackage->Exe.detectionType); | ||
215 | } | ||
138 | 216 | ||
139 | if (pPackage->fCanAffectRegistration) | 217 | if (pPackage->fCanAffectRegistration) |
140 | { | 218 | { |
@@ -187,6 +265,7 @@ extern "C" HRESULT ExeEnginePlanCalculatePackage( | |||
187 | } | 265 | } |
188 | break; | 266 | break; |
189 | 267 | ||
268 | case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough; | ||
190 | case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: | 269 | case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: |
191 | switch (pPackage->requested) | 270 | switch (pPackage->requested) |
192 | { | 271 | { |
@@ -205,8 +284,7 @@ extern "C" HRESULT ExeEnginePlanCalculatePackage( | |||
205 | break; | 284 | break; |
206 | 285 | ||
207 | default: | 286 | default: |
208 | hr = E_INVALIDARG; | 287 | ExitWithRootFailure(hr, E_INVALIDARG, "Invalid package current state: %d.", pPackage->currentState); |
209 | ExitOnRootFailure(hr, "Invalid package current state: %d.", pPackage->currentState); | ||
210 | } | 288 | } |
211 | 289 | ||
212 | // Calculate the rollback action if there is an execute action. | 290 | // Calculate the rollback action if there is an execute action. |
@@ -232,6 +310,7 @@ extern "C" HRESULT ExeEnginePlanCalculatePackage( | |||
232 | } | 310 | } |
233 | break; | 311 | break; |
234 | 312 | ||
313 | case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough; | ||
235 | case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: | 314 | case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: |
236 | switch (pPackage->requested) | 315 | switch (pPackage->requested) |
237 | { | 316 | { |
@@ -251,8 +330,7 @@ extern "C" HRESULT ExeEnginePlanCalculatePackage( | |||
251 | break; | 330 | break; |
252 | 331 | ||
253 | default: | 332 | default: |
254 | hr = E_INVALIDARG; | 333 | ExitWithRootFailure(hr, E_INVALIDARG, "Invalid package expected state."); |
255 | ExitOnRootFailure(hr, "Invalid package expected state."); | ||
256 | } | 334 | } |
257 | } | 335 | } |
258 | 336 | ||
@@ -356,10 +434,41 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
356 | LPWSTR sczUserArgs = NULL; | 434 | LPWSTR sczUserArgs = NULL; |
357 | LPWSTR sczUserArgsObfuscated = NULL; | 435 | LPWSTR sczUserArgsObfuscated = NULL; |
358 | LPWSTR sczCommandObfuscated = NULL; | 436 | LPWSTR sczCommandObfuscated = NULL; |
437 | LPWSTR sczArpUninstallString = NULL; | ||
438 | LPWSTR sczArpArguments = NULL; | ||
439 | BOOTSTRAPPER_PACKAGE_STATE applyState = BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN; | ||
359 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; | 440 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; |
360 | DWORD dwExitCode = 0; | 441 | DWORD dwExitCode = 0; |
361 | BURN_PACKAGE* pPackage = pExecuteAction->exePackage.pPackage; | 442 | BURN_PACKAGE* pPackage = pExecuteAction->exePackage.pPackage; |
362 | BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload; | 443 | BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload; |
444 | LPCWSTR wzUninstallArguments = pPackage->Exe.sczUninstallArguments; | ||
445 | |||
446 | if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType && | ||
447 | (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action || | ||
448 | BOOTSTRAPPER_ACTION_STATE_INSTALL == pExecuteAction->exePackage.action && fRollback)) | ||
449 | { | ||
450 | hr = DetectArpEntry(pPackage, &applyState, &sczArpUninstallString); | ||
451 | ExitOnFailure(hr, "Failed to query ArpEntry for uninstall."); | ||
452 | |||
453 | if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT == applyState && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action) | ||
454 | { | ||
455 | if (fRollback) | ||
456 | { | ||
457 | LogId(REPORT_STANDARD, MSG_ROLLBACK_PACKAGE_SKIPPED, pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), LoggingPackageStateToString(applyState)); | ||
458 | } | ||
459 | else | ||
460 | { | ||
461 | LogId(REPORT_STANDARD, MSG_ATTEMPTED_UNINSTALL_ABSENT_PACKAGE, pPackage->sczId); | ||
462 | } | ||
463 | |||
464 | ExitFunction(); | ||
465 | } | ||
466 | else if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT != applyState && BOOTSTRAPPER_ACTION_STATE_INSTALL == pExecuteAction->exePackage.action) | ||
467 | { | ||
468 | LogId(REPORT_STANDARD, MSG_ROLLBACK_PACKAGE_SKIPPED, pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), LoggingPackageStateToString(applyState)); | ||
469 | ExitFunction(); | ||
470 | } | ||
471 | } | ||
363 | 472 | ||
364 | if (pPackage->Exe.fPseudoPackage && BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE != pPackagePayload->verification) | 473 | if (pPackage->Exe.fPseudoPackage && BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE != pPackagePayload->verification) |
365 | { | 474 | { |
@@ -372,7 +481,30 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
372 | ExitOnFailure(hr, "Failed to build executable path."); | 481 | ExitOnFailure(hr, "Failed to build executable path."); |
373 | 482 | ||
374 | hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); | 483 | hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); |
375 | ExitOnFailure(hr, "Failed to get cached path for pseudo-package: %ls", pPackage->sczId); | 484 | ExitOnFailure(hr, "Failed to get parent directory for pseudo-package: %ls", pPackage->sczId); |
485 | } | ||
486 | else if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action) | ||
487 | { | ||
488 | ExitOnNull(sczArpUninstallString, hr, E_INVALIDARG, "QuietUninstallString is null."); | ||
489 | |||
490 | hr = ParseArpUninstallString(sczArpUninstallString, &sczExecutablePath, &sczArpArguments); | ||
491 | ExitOnFailure(hr, "Failed to parse QuietUninstallString: %ls.", sczArpUninstallString); | ||
492 | |||
493 | if (pPackage->fPerMachine) | ||
494 | { | ||
495 | hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath); | ||
496 | ExitOnFailure(hr, "Failed to verify the QuietUninstallString executable path is in a secure location: %ls", sczExecutablePath); | ||
497 | if (S_FALSE == hr) | ||
498 | { | ||
499 | LogStringLine(REPORT_STANDARD, "The QuietUninstallString executable path is not in a secure location: %ls", sczExecutablePath); | ||
500 | ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)); | ||
501 | } | ||
502 | } | ||
503 | |||
504 | hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); | ||
505 | ExitOnFailure(hr, "Failed to get parent directory for QuietUninstallString executable path: %ls", sczExecutablePath); | ||
506 | |||
507 | wzUninstallArguments = sczArpArguments; | ||
376 | } | 508 | } |
377 | else | 509 | else |
378 | { | 510 | { |
@@ -396,7 +528,7 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
396 | break; | 528 | break; |
397 | 529 | ||
398 | case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: | 530 | case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: |
399 | wzArguments = pPackage->Exe.sczUninstallArguments; | 531 | wzArguments = wzUninstallArguments; |
400 | break; | 532 | break; |
401 | 533 | ||
402 | case BOOTSTRAPPER_ACTION_STATE_REPAIR: | 534 | case BOOTSTRAPPER_ACTION_STATE_REPAIR: |
@@ -404,8 +536,7 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
404 | break; | 536 | break; |
405 | 537 | ||
406 | default: | 538 | default: |
407 | hr = E_INVALIDARG; | 539 | ExitWithRootFailure(hr, E_INVALIDARG, "Invalid Exe package action: %d.", pExecuteAction->exePackage.action); |
408 | ExitOnFailure(hr, "Invalid Exe package action: %d.", pExecuteAction->exePackage.action); | ||
409 | } | 540 | } |
410 | 541 | ||
411 | // now add optional arguments | 542 | // now add optional arguments |
@@ -443,8 +574,7 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
443 | break; | 574 | break; |
444 | 575 | ||
445 | default: | 576 | default: |
446 | hr = E_INVALIDARG; | 577 | ExitWithRootFailure(hr, E_INVALIDARG, "Invalid Exe package action: %d.", pExecuteAction->exePackage.action); |
447 | ExitOnFailure(hr, "Invalid Exe package action: %d.", pExecuteAction->exePackage.action); | ||
448 | } | 578 | } |
449 | } | 579 | } |
450 | } | 580 | } |
@@ -524,6 +654,8 @@ LExit: | |||
524 | StrSecureZeroFreeString(sczUserArgs); | 654 | StrSecureZeroFreeString(sczUserArgs); |
525 | ReleaseStr(sczUserArgsObfuscated); | 655 | ReleaseStr(sczUserArgsObfuscated); |
526 | ReleaseStr(sczCommandObfuscated); | 656 | ReleaseStr(sczCommandObfuscated); |
657 | ReleaseStr(sczArpUninstallString); | ||
658 | ReleaseStr(sczArpArguments); | ||
527 | 659 | ||
528 | ReleaseFileHandle(hExecutableFile); | 660 | ReleaseFileHandle(hExecutableFile); |
529 | 661 | ||
@@ -894,3 +1026,106 @@ extern "C" HRESULT ExeEngineHandleExitCode( | |||
894 | //LExit: | 1026 | //LExit: |
895 | return hr; | 1027 | return hr; |
896 | } | 1028 | } |
1029 | |||
1030 | static HRESULT DetectArpEntry( | ||
1031 | __in const BURN_PACKAGE* pPackage, | ||
1032 | __out BOOTSTRAPPER_PACKAGE_STATE* pPackageState, | ||
1033 | __out_opt LPWSTR* psczQuietUninstallString | ||
1034 | ) | ||
1035 | { | ||
1036 | HRESULT hr = S_OK; | ||
1037 | HKEY hKey = NULL; | ||
1038 | VERUTIL_VERSION* pVersion = NULL; | ||
1039 | int nCompareResult = 0; | ||
1040 | HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | ||
1041 | REG_KEY_BITNESS keyBitness = pPackage->Exe.fArpWin64 ? REG_KEY_64BIT : REG_KEY_32BIT; | ||
1042 | |||
1043 | *pPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT; | ||
1044 | if (psczQuietUninstallString) | ||
1045 | { | ||
1046 | ReleaseNullStr(*psczQuietUninstallString); | ||
1047 | } | ||
1048 | |||
1049 | hr = RegOpenEx(hkRoot, pPackage->Exe.sczArpKeyPath, KEY_READ, keyBitness, &hKey); | ||
1050 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
1051 | { | ||
1052 | ExitFunction1(hr = S_OK); | ||
1053 | } | ||
1054 | ExitOnFailure(hr, "Failed to open registry key: %ls.", pPackage->Exe.sczArpKeyPath); | ||
1055 | |||
1056 | hr = RegReadWixVersion(hKey, L"DisplayVersion", &pVersion); | ||
1057 | if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
1058 | { | ||
1059 | ExitFunction1(hr = S_OK); | ||
1060 | } | ||
1061 | ExitOnFailure(hr, "Failed to read DisplayVersion."); | ||
1062 | |||
1063 | if (pVersion->fInvalid) | ||
1064 | { | ||
1065 | LogId(REPORT_WARNING, MSG_DETECTED_EXE_PACKAGE_INVALID_VERSION, pPackage->Exe.sczArpKeyPath, pVersion->sczVersion); | ||
1066 | } | ||
1067 | |||
1068 | hr = VerCompareParsedVersions(pPackage->Exe.pArpDisplayVersion, pVersion, &nCompareResult); | ||
1069 | ExitOnFailure(hr, "Failed to compare versions."); | ||
1070 | |||
1071 | if (nCompareResult < 0) | ||
1072 | { | ||
1073 | *pPackageState = BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE; | ||
1074 | } | ||
1075 | else if (nCompareResult > 0) | ||
1076 | { | ||
1077 | *pPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT; | ||
1078 | } | ||
1079 | else | ||
1080 | { | ||
1081 | *pPackageState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT; | ||
1082 | } | ||
1083 | |||
1084 | if (psczQuietUninstallString) | ||
1085 | { | ||
1086 | hr = RegReadString(hKey, L"QuietUninstallString", psczQuietUninstallString); | ||
1087 | if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
1088 | { | ||
1089 | hr = S_OK; | ||
1090 | } | ||
1091 | ExitOnFailure(hr, "Failed to read QuietUninstallString."); | ||
1092 | } | ||
1093 | |||
1094 | LExit: | ||
1095 | ReleaseRegKey(hKey); | ||
1096 | ReleaseVerutilVersion(pVersion); | ||
1097 | |||
1098 | return hr; | ||
1099 | } | ||
1100 | |||
1101 | static HRESULT ParseArpUninstallString( | ||
1102 | __in_z LPCWSTR wzArpUninstallString, | ||
1103 | __inout LPWSTR* psczExecutablePath, | ||
1104 | __inout LPWSTR* psczArguments | ||
1105 | ) | ||
1106 | { | ||
1107 | HRESULT hr = S_OK; | ||
1108 | int argc = 0; | ||
1109 | LPWSTR* argv = NULL; | ||
1110 | |||
1111 | hr = AppParseCommandLine(wzArpUninstallString, &argc, &argv); | ||
1112 | ExitOnFailure(hr, "Failed to parse uninstall string as command line: %ls.", wzArpUninstallString); | ||
1113 | ExitOnNull(argc, hr, E_INVALIDARG, "Uninstall string must contain an executable path."); | ||
1114 | |||
1115 | hr = StrAllocString(psczExecutablePath, argv[0], 0); | ||
1116 | ExitOnFailure(hr, "Failed to copy executable path for ArpCommand."); | ||
1117 | |||
1118 | for (int i = 1; i < argc; ++i) | ||
1119 | { | ||
1120 | hr = AppAppendCommandLineArgument(psczArguments, argv[i]); | ||
1121 | ExitOnFailure(hr, "Failed to append argument for ArpCommand."); | ||
1122 | } | ||
1123 | |||
1124 | LExit: | ||
1125 | if (argv) | ||
1126 | { | ||
1127 | AppFreeCommandLineArgs(argv); | ||
1128 | } | ||
1129 | |||
1130 | return hr; | ||
1131 | } | ||