diff options
Diffstat (limited to 'src')
31 files changed, 716 insertions, 124 deletions
diff --git a/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h b/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h index 0b81b35a..df8cac76 100644 --- a/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h +++ b/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h | |||
| @@ -224,6 +224,7 @@ enum BOOTSTRAPPER_APPLICATION_MESSAGE | |||
| 224 | BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRESTORERELATEDBUNDLE, | 224 | BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRESTORERELATEDBUNDLE, |
| 225 | BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLETYPE, | 225 | BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLETYPE, |
| 226 | BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE, | 226 | BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE, |
| 227 | BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROCESSCANCEL, | ||
| 227 | }; | 228 | }; |
| 228 | 229 | ||
| 229 | enum BOOTSTRAPPER_APPLYCOMPLETE_ACTION | 230 | enum BOOTSTRAPPER_APPLYCOMPLETE_ACTION |
| @@ -282,6 +283,18 @@ enum BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION | |||
| 282 | BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_SUSPEND, | 283 | BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_SUSPEND, |
| 283 | }; | 284 | }; |
| 284 | 285 | ||
| 286 | enum BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION | ||
| 287 | { | ||
| 288 | // Instructs the engine to stop waiting for the process to exit. | ||
| 289 | // The package is immediately considered to have failed with ERROR_INSTALL_USEREXIT. | ||
| 290 | // The engine will never rollback the package. | ||
| 291 | BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION_ABANDON, | ||
| 292 | // Instructs the engine to wait for the process to exit. | ||
| 293 | // Once the process has exited, the package is considered to have failed with ERROR_INSTALL_USEREXIT. | ||
| 294 | // This allows the engine to rollback the package if necessary. | ||
| 295 | BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION_WAIT, | ||
| 296 | }; | ||
| 297 | |||
| 285 | enum BOOTSTRAPPER_SHUTDOWN_ACTION | 298 | enum BOOTSTRAPPER_SHUTDOWN_ACTION |
| 286 | { | 299 | { |
| 287 | BOOTSTRAPPER_SHUTDOWN_ACTION_NONE, | 300 | BOOTSTRAPPER_SHUTDOWN_ACTION_NONE, |
| @@ -997,6 +1010,20 @@ struct BA_ONEXECUTEPATCHTARGET_RESULTS | |||
| 997 | BOOL fCancel; | 1010 | BOOL fCancel; |
| 998 | }; | 1011 | }; |
| 999 | 1012 | ||
| 1013 | struct BA_ONEXECUTEPROCESSCANCEL_ARGS | ||
| 1014 | { | ||
| 1015 | DWORD cbSize; | ||
| 1016 | LPCWSTR wzPackageId; | ||
| 1017 | DWORD dwProcessId; | ||
| 1018 | BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION recommendation; | ||
| 1019 | }; | ||
| 1020 | |||
| 1021 | struct BA_ONEXECUTEPROCESSCANCEL_RESULTS | ||
| 1022 | { | ||
| 1023 | DWORD cbSize; | ||
| 1024 | BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION action; | ||
| 1025 | }; | ||
| 1026 | |||
| 1000 | struct BA_ONEXECUTEPROGRESS_ARGS | 1027 | struct BA_ONEXECUTEPROGRESS_ARGS |
| 1001 | { | 1028 | { |
| 1002 | DWORD cbSize; | 1029 | DWORD cbSize; |
diff --git a/src/api/burn/WixToolset.Mba.Core/BootstrapperApplication.cs b/src/api/burn/WixToolset.Mba.Core/BootstrapperApplication.cs index 8a2e0e93..5ed064fa 100644 --- a/src/api/burn/WixToolset.Mba.Core/BootstrapperApplication.cs +++ b/src/api/burn/WixToolset.Mba.Core/BootstrapperApplication.cs | |||
| @@ -280,6 +280,9 @@ namespace WixToolset.Mba.Core | |||
| 280 | /// <inheritdoc/> | 280 | /// <inheritdoc/> |
| 281 | public event EventHandler<PlanRestoreRelatedBundleEventArgs> PlanRestoreRelatedBundle; | 281 | public event EventHandler<PlanRestoreRelatedBundleEventArgs> PlanRestoreRelatedBundle; |
| 282 | 282 | ||
| 283 | /// <inheritdoc/> | ||
| 284 | public event EventHandler<ExecuteProcessCancelEventArgs> ExecuteProcessCancel; | ||
| 285 | |||
| 283 | /// <summary> | 286 | /// <summary> |
| 284 | /// Entry point that is called when the bootstrapper application is ready to run. | 287 | /// Entry point that is called when the bootstrapper application is ready to run. |
| 285 | /// </summary> | 288 | /// </summary> |
| @@ -1369,6 +1372,19 @@ namespace WixToolset.Mba.Core | |||
| 1369 | } | 1372 | } |
| 1370 | } | 1373 | } |
| 1371 | 1374 | ||
| 1375 | /// <summary> | ||
| 1376 | /// Called by the engine, raises the <see cref="ExecuteProcessCancel"/> event. | ||
| 1377 | /// </summary> | ||
| 1378 | /// <param name="args">Additional arguments for this event.</param> | ||
| 1379 | protected virtual void OnExecuteProcessCancel(ExecuteProcessCancelEventArgs args) | ||
| 1380 | { | ||
| 1381 | EventHandler<ExecuteProcessCancelEventArgs> handler = this.ExecuteProcessCancel; | ||
| 1382 | if (null != handler) | ||
| 1383 | { | ||
| 1384 | handler(this, args); | ||
| 1385 | } | ||
| 1386 | } | ||
| 1387 | |||
| 1372 | #region IBootstrapperApplication Members | 1388 | #region IBootstrapperApplication Members |
| 1373 | 1389 | ||
| 1374 | int IBootstrapperApplication.BAProc(int message, IntPtr pvArgs, IntPtr pvResults, IntPtr pvContext) | 1390 | int IBootstrapperApplication.BAProc(int message, IntPtr pvArgs, IntPtr pvResults, IntPtr pvContext) |
| @@ -2119,6 +2135,15 @@ namespace WixToolset.Mba.Core | |||
| 2119 | return args.HResult; | 2135 | return args.HResult; |
| 2120 | } | 2136 | } |
| 2121 | 2137 | ||
| 2138 | int IBootstrapperApplication.OnExecuteProcessCancel(string wzPackageId, int processId, BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION recommendation, ref BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION pAction) | ||
| 2139 | { | ||
| 2140 | ExecuteProcessCancelEventArgs args = new ExecuteProcessCancelEventArgs(wzPackageId, processId, recommendation, pAction); | ||
| 2141 | this.OnExecuteProcessCancel(args); | ||
| 2142 | |||
| 2143 | pAction = args.Action; | ||
| 2144 | return args.HResult; | ||
| 2145 | } | ||
| 2146 | |||
| 2122 | #endregion | 2147 | #endregion |
| 2123 | } | 2148 | } |
| 2124 | } | 2149 | } |
diff --git a/src/api/burn/WixToolset.Mba.Core/EventArgs.cs b/src/api/burn/WixToolset.Mba.Core/EventArgs.cs index c93c2885..c2c73067 100644 --- a/src/api/burn/WixToolset.Mba.Core/EventArgs.cs +++ b/src/api/burn/WixToolset.Mba.Core/EventArgs.cs | |||
| @@ -2488,4 +2488,40 @@ namespace WixToolset.Mba.Core | |||
| 2488 | /// </summary> | 2488 | /// </summary> |
| 2489 | public RequestState State { get; set; } | 2489 | public RequestState State { get; set; } |
| 2490 | } | 2490 | } |
| 2491 | |||
| 2492 | /// <summary> | ||
| 2493 | /// Event arguments for <see cref="IDefaultBootstrapperApplication.ExecuteProcessCancel"/> | ||
| 2494 | /// </summary> | ||
| 2495 | [Serializable] | ||
| 2496 | public class ExecuteProcessCancelEventArgs : HResultEventArgs | ||
| 2497 | { | ||
| 2498 | /// <summary /> | ||
| 2499 | public ExecuteProcessCancelEventArgs(string packageId, int processId, BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION recommendation, BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION action) | ||
| 2500 | { | ||
| 2501 | this.PackageId = packageId; | ||
| 2502 | this.ProcessId = processId; | ||
| 2503 | this.Recommendation = recommendation; | ||
| 2504 | this.Action = action; | ||
| 2505 | } | ||
| 2506 | |||
| 2507 | /// <summary> | ||
| 2508 | /// Gets the identity of the package. | ||
| 2509 | /// </summary> | ||
| 2510 | public string PackageId { get; private set; } | ||
| 2511 | |||
| 2512 | /// <summary> | ||
| 2513 | /// Gets the process id. | ||
| 2514 | /// </summary> | ||
| 2515 | public int ProcessId { get; private set; } | ||
| 2516 | |||
| 2517 | /// <summary> | ||
| 2518 | /// Gets the recommended action from the engine. | ||
| 2519 | /// </summary> | ||
| 2520 | public BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION Recommendation { get; private set; } | ||
| 2521 | |||
| 2522 | /// <summary> | ||
| 2523 | /// Gets or sets the action to be performed. This is passed back to the engine. | ||
| 2524 | /// </summary> | ||
| 2525 | public BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION Action { get; set; } | ||
| 2526 | } | ||
| 2491 | } | 2527 | } |
diff --git a/src/api/burn/WixToolset.Mba.Core/IBootstrapperApplication.cs b/src/api/burn/WixToolset.Mba.Core/IBootstrapperApplication.cs index d4fe8320..1786eecd 100644 --- a/src/api/burn/WixToolset.Mba.Core/IBootstrapperApplication.cs +++ b/src/api/burn/WixToolset.Mba.Core/IBootstrapperApplication.cs | |||
| @@ -1170,6 +1170,18 @@ namespace WixToolset.Mba.Core | |||
| 1170 | [MarshalAs(UnmanagedType.I4)] int hrRecommended, | 1170 | [MarshalAs(UnmanagedType.I4)] int hrRecommended, |
| 1171 | [MarshalAs(UnmanagedType.I4)] ref int hrStatus | 1171 | [MarshalAs(UnmanagedType.I4)] ref int hrStatus |
| 1172 | ); | 1172 | ); |
| 1173 | |||
| 1174 | /// <summary> | ||
| 1175 | /// See <see cref="IDefaultBootstrapperApplication.ExecuteProcessCancel"/>. | ||
| 1176 | /// </summary> | ||
| 1177 | [PreserveSig] | ||
| 1178 | [return: MarshalAs(UnmanagedType.I4)] | ||
| 1179 | int OnExecuteProcessCancel( | ||
| 1180 | [MarshalAs(UnmanagedType.LPWStr)] string wzPackageId, | ||
| 1181 | int processId, | ||
| 1182 | [MarshalAs(UnmanagedType.I4)] BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION recommendation, | ||
| 1183 | [MarshalAs(UnmanagedType.I4)] ref BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION pAction | ||
| 1184 | ); | ||
| 1173 | } | 1185 | } |
| 1174 | 1186 | ||
| 1175 | /// <summary> | 1187 | /// <summary> |
| @@ -1907,6 +1919,26 @@ namespace WixToolset.Mba.Core | |||
| 1907 | } | 1919 | } |
| 1908 | 1920 | ||
| 1909 | /// <summary> | 1921 | /// <summary> |
| 1922 | /// The available actions for <see cref="IDefaultBootstrapperApplication.ExecuteProcessCancel"/>. | ||
| 1923 | /// </summary> | ||
| 1924 | public enum BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION | ||
| 1925 | { | ||
| 1926 | /// <summary> | ||
| 1927 | /// Instructs the engine to stop waiting for the process to exit. | ||
| 1928 | /// The package is immediately considered to have failed with ERROR_INSTALL_USEREXIT. | ||
| 1929 | /// The engine will never rollback the package. | ||
| 1930 | /// </summary> | ||
| 1931 | Abandon, | ||
| 1932 | |||
| 1933 | /// <summary> | ||
| 1934 | /// Instructs the engine to wait for the process to exit. | ||
| 1935 | /// Once the process has exited, the package is considered to have failed with ERROR_INSTALL_USEREXIT. | ||
| 1936 | /// This allows the engine to rollback the package if necessary. | ||
| 1937 | /// </summary> | ||
| 1938 | Wait, | ||
| 1939 | } | ||
| 1940 | |||
| 1941 | /// <summary> | ||
| 1910 | /// The result of evaluating a condition from a package. | 1942 | /// The result of evaluating a condition from a package. |
| 1911 | /// </summary> | 1943 | /// </summary> |
| 1912 | public enum BOOTSTRAPPER_PACKAGE_CONDITION_RESULT | 1944 | public enum BOOTSTRAPPER_PACKAGE_CONDITION_RESULT |
diff --git a/src/api/burn/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs b/src/api/burn/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs index c9284b69..21d99b32 100644 --- a/src/api/burn/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs +++ b/src/api/burn/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs | |||
| @@ -244,6 +244,11 @@ namespace WixToolset.Mba.Core | |||
| 244 | event EventHandler<ExecutePackageCompleteEventArgs> ExecutePackageComplete; | 244 | event EventHandler<ExecutePackageCompleteEventArgs> ExecutePackageComplete; |
| 245 | 245 | ||
| 246 | /// <summary> | 246 | /// <summary> |
| 247 | /// Fired when a package that spawned a process is cancelled. | ||
| 248 | /// </summary> | ||
| 249 | event EventHandler<ExecuteProcessCancelEventArgs> ExecuteProcessCancel; | ||
| 250 | |||
| 251 | /// <summary> | ||
| 247 | /// Fired when the engine executes one or more patches targeting a product. | 252 | /// Fired when the engine executes one or more patches targeting a product. |
| 248 | /// </summary> | 253 | /// </summary> |
| 249 | event EventHandler<ExecutePatchTargetEventArgs> ExecutePatchTarget; | 254 | event EventHandler<ExecutePatchTargetEventArgs> ExecutePatchTarget; |
diff --git a/src/api/burn/balutil/inc/BAFunctions.h b/src/api/burn/balutil/inc/BAFunctions.h index 58c26166..158e65b5 100644 --- a/src/api/burn/balutil/inc/BAFunctions.h +++ b/src/api/burn/balutil/inc/BAFunctions.h | |||
| @@ -91,6 +91,7 @@ enum BA_FUNCTIONS_MESSAGE | |||
| 91 | BA_FUNCTIONS_MESSAGE_ONPLANRESTORERELATEDBUNDLE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRESTORERELATEDBUNDLE, | 91 | BA_FUNCTIONS_MESSAGE_ONPLANRESTORERELATEDBUNDLE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRESTORERELATEDBUNDLE, |
| 92 | BA_FUNCTIONS_MESSAGE_ONPLANRELATEDBUNDLETYPE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLETYPE, | 92 | BA_FUNCTIONS_MESSAGE_ONPLANRELATEDBUNDLETYPE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLETYPE, |
| 93 | BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE, | 93 | BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE, |
| 94 | BA_FUNCTIONS_MESSAGE_ONEXECUTEPROCESSCANCEL = BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROCESSCANCEL, | ||
| 94 | 95 | ||
| 95 | BA_FUNCTIONS_MESSAGE_ONTHEMELOADED = 1024, | 96 | BA_FUNCTIONS_MESSAGE_ONTHEMELOADED = 1024, |
| 96 | BA_FUNCTIONS_MESSAGE_WNDPROC, | 97 | BA_FUNCTIONS_MESSAGE_WNDPROC, |
diff --git a/src/api/burn/balutil/inc/BalBaseBAFunctions.h b/src/api/burn/balutil/inc/BalBaseBAFunctions.h index fe5c99ba..614d4bcf 100644 --- a/src/api/burn/balutil/inc/BalBaseBAFunctions.h +++ b/src/api/burn/balutil/inc/BalBaseBAFunctions.h | |||
| @@ -877,6 +877,16 @@ public: // IBootstrapperApplication | |||
| 877 | return S_OK; | 877 | return S_OK; |
| 878 | } | 878 | } |
| 879 | 879 | ||
| 880 | virtual STDMETHODIMP OnExecuteProcessCancel( | ||
| 881 | __in_z LPCWSTR /*wzPackageId*/, | ||
| 882 | __in DWORD /*dwProcessId*/, | ||
| 883 | __in BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION /*recommendation*/, | ||
| 884 | __inout BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION* /*pAction*/ | ||
| 885 | ) | ||
| 886 | { | ||
| 887 | return S_OK; | ||
| 888 | } | ||
| 889 | |||
| 880 | public: // IBAFunctions | 890 | public: // IBAFunctions |
| 881 | virtual STDMETHODIMP OnPlan( | 891 | virtual STDMETHODIMP OnPlan( |
| 882 | ) | 892 | ) |
diff --git a/src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h b/src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h index 100e5c30..b96a180c 100644 --- a/src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h +++ b/src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h | |||
| @@ -162,6 +162,7 @@ static HRESULT WINAPI BalBaseBAFunctionsProc( | |||
| 162 | case BA_FUNCTIONS_MESSAGE_ONPLANRESTORERELATEDBUNDLE: | 162 | case BA_FUNCTIONS_MESSAGE_ONPLANRESTORERELATEDBUNDLE: |
| 163 | case BA_FUNCTIONS_MESSAGE_ONPLANRELATEDBUNDLETYPE: | 163 | case BA_FUNCTIONS_MESSAGE_ONPLANRELATEDBUNDLETYPE: |
| 164 | case BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE: | 164 | case BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE: |
| 165 | case BA_FUNCTIONS_MESSAGE_ONEXECUTEPROCESSCANCEL: | ||
| 165 | hr = BalBaseBootstrapperApplicationProc((BOOTSTRAPPER_APPLICATION_MESSAGE)message, pvArgs, pvResults, pvContext); | 166 | hr = BalBaseBootstrapperApplicationProc((BOOTSTRAPPER_APPLICATION_MESSAGE)message, pvArgs, pvResults, pvContext); |
| 166 | break; | 167 | break; |
| 167 | case BA_FUNCTIONS_MESSAGE_ONTHEMELOADED: | 168 | case BA_FUNCTIONS_MESSAGE_ONTHEMELOADED: |
diff --git a/src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h b/src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h index fd06a83f..25570ffd 100644 --- a/src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h +++ b/src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h | |||
| @@ -1077,6 +1077,16 @@ public: // IBootstrapperApplication | |||
| 1077 | return S_OK; | 1077 | return S_OK; |
| 1078 | } | 1078 | } |
| 1079 | 1079 | ||
| 1080 | virtual STDMETHODIMP OnExecuteProcessCancel( | ||
| 1081 | __in_z LPCWSTR /*wzPackageId*/, | ||
| 1082 | __in DWORD /*dwProcessId*/, | ||
| 1083 | __in BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION /*recommendation*/, | ||
| 1084 | __inout BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION* /*pAction*/ | ||
| 1085 | ) | ||
| 1086 | { | ||
| 1087 | return S_OK; | ||
| 1088 | } | ||
| 1089 | |||
| 1080 | public: //CBalBaseBootstrapperApplication | 1090 | public: //CBalBaseBootstrapperApplication |
| 1081 | virtual STDMETHODIMP Initialize( | 1091 | virtual STDMETHODIMP Initialize( |
| 1082 | __in const BOOTSTRAPPER_CREATE_ARGS* pCreateArgs | 1092 | __in const BOOTSTRAPPER_CREATE_ARGS* pCreateArgs |
diff --git a/src/api/burn/balutil/inc/BalBaseBootstrapperApplicationProc.h b/src/api/burn/balutil/inc/BalBaseBootstrapperApplicationProc.h index 4e413e4e..b196d183 100644 --- a/src/api/burn/balutil/inc/BalBaseBootstrapperApplicationProc.h +++ b/src/api/burn/balutil/inc/BalBaseBootstrapperApplicationProc.h | |||
| @@ -486,6 +486,15 @@ static HRESULT BalBaseBAProcOnExecutePackageComplete( | |||
| 486 | return pBA->OnExecutePackageComplete(pArgs->wzPackageId, pArgs->hrStatus, pArgs->restart, pArgs->recommendation, &pResults->action); | 486 | return pBA->OnExecutePackageComplete(pArgs->wzPackageId, pArgs->hrStatus, pArgs->restart, pArgs->recommendation, &pResults->action); |
| 487 | } | 487 | } |
| 488 | 488 | ||
| 489 | static HRESULT BalBaseBAProcOnExecuteProcessCancel( | ||
| 490 | __in IBootstrapperApplication* pBA, | ||
| 491 | __in BA_ONEXECUTEPROCESSCANCEL_ARGS* pArgs, | ||
| 492 | __inout BA_ONEXECUTEPROCESSCANCEL_RESULTS* pResults | ||
| 493 | ) | ||
| 494 | { | ||
| 495 | return pBA->OnExecuteProcessCancel(pArgs->wzPackageId, pArgs->dwProcessId, pArgs->recommendation, &pResults->action); | ||
| 496 | } | ||
| 497 | |||
| 489 | static HRESULT BalBaseBAProcOnExecuteComplete( | 498 | static HRESULT BalBaseBAProcOnExecuteComplete( |
| 490 | __in IBootstrapperApplication* pBA, | 499 | __in IBootstrapperApplication* pBA, |
| 491 | __in BA_ONEXECUTECOMPLETE_ARGS* pArgs, | 500 | __in BA_ONEXECUTECOMPLETE_ARGS* pArgs, |
| @@ -1012,6 +1021,9 @@ static HRESULT WINAPI BalBaseBootstrapperApplicationProc( | |||
| 1012 | case BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE: | 1021 | case BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE: |
| 1013 | hr = BalBaseBAProcOnApplyDowngrade(pBA, reinterpret_cast<BA_ONAPPLYDOWNGRADE_ARGS*>(pvArgs), reinterpret_cast<BA_ONAPPLYDOWNGRADE_RESULTS*>(pvResults)); | 1022 | hr = BalBaseBAProcOnApplyDowngrade(pBA, reinterpret_cast<BA_ONAPPLYDOWNGRADE_ARGS*>(pvArgs), reinterpret_cast<BA_ONAPPLYDOWNGRADE_RESULTS*>(pvResults)); |
| 1014 | break; | 1023 | break; |
| 1024 | case BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROCESSCANCEL: | ||
| 1025 | hr = BalBaseBAProcOnExecuteProcessCancel(pBA, reinterpret_cast<BA_ONEXECUTEPROCESSCANCEL_ARGS*>(pvArgs), reinterpret_cast<BA_ONEXECUTEPROCESSCANCEL_RESULTS*>(pvResults)); | ||
| 1026 | break; | ||
| 1015 | } | 1027 | } |
| 1016 | } | 1028 | } |
| 1017 | 1029 | ||
diff --git a/src/api/burn/balutil/inc/IBootstrapperApplication.h b/src/api/burn/balutil/inc/IBootstrapperApplication.h index c9cf3126..6174c290 100644 --- a/src/api/burn/balutil/inc/IBootstrapperApplication.h +++ b/src/api/burn/balutil/inc/IBootstrapperApplication.h | |||
| @@ -714,4 +714,13 @@ DECLARE_INTERFACE_IID_(IBootstrapperApplication, IUnknown, "53C31D56-49C0-426B-A | |||
| 714 | __in HRESULT hrRecommended, | 714 | __in HRESULT hrRecommended, |
| 715 | __inout HRESULT* phrStatus | 715 | __inout HRESULT* phrStatus |
| 716 | ) = 0; | 716 | ) = 0; |
| 717 | |||
| 718 | // OnExecuteProcessCancel - called when a package that spawned a process is cancelled. | ||
| 719 | // | ||
| 720 | STDMETHOD(OnExecuteProcessCancel)( | ||
| 721 | __in_z LPCWSTR wzPackageId, | ||
| 722 | __in DWORD dwProcessId, | ||
| 723 | __in BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION recommendation, | ||
| 724 | __inout BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION* pAction | ||
| 725 | ) = 0; | ||
| 717 | }; | 726 | }; |
diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp index 3ad22e9b..73b5b396 100644 --- a/src/burn/engine/apply.cpp +++ b/src/burn/engine/apply.cpp | |||
| @@ -3326,6 +3326,14 @@ static int GenericExecuteMessageHandler( | |||
| 3326 | } | 3326 | } |
| 3327 | break; | 3327 | break; |
| 3328 | 3328 | ||
| 3329 | case GENERIC_EXECUTE_MESSAGE_PROCESS_CANCEL: | ||
| 3330 | { | ||
| 3331 | BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION action = BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION_ABANDON; | ||
| 3332 | UserExperienceOnExecuteProcessCancel(pContext->pUX, pContext->wzExecutingPackageId, pMessage->processCancel.dwProcessId, &action); // ignore return value. | ||
| 3333 | nResult = BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION_WAIT == action ? IDRETRY : IDIGNORE; | ||
| 3334 | } | ||
| 3335 | break; | ||
| 3336 | |||
| 3329 | case GENERIC_EXECUTE_MESSAGE_ERROR: | 3337 | case GENERIC_EXECUTE_MESSAGE_ERROR: |
| 3330 | UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_EXE_PACKAGE, pContext->wzExecutingPackageId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, 0, NULL, &nResult); // ignore return value. | 3338 | UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_EXE_PACKAGE, pContext->wzExecutingPackageId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, 0, NULL, &nResult); // ignore return value. |
| 3331 | break; | 3339 | break; |
diff --git a/src/burn/engine/apply.h b/src/burn/engine/apply.h index 1717a71a..47f0ece6 100644 --- a/src/burn/engine/apply.h +++ b/src/burn/engine/apply.h | |||
| @@ -13,6 +13,7 @@ enum GENERIC_EXECUTE_MESSAGE_TYPE | |||
| 13 | GENERIC_EXECUTE_MESSAGE_ERROR, | 13 | GENERIC_EXECUTE_MESSAGE_ERROR, |
| 14 | GENERIC_EXECUTE_MESSAGE_PROGRESS, | 14 | GENERIC_EXECUTE_MESSAGE_PROGRESS, |
| 15 | GENERIC_EXECUTE_MESSAGE_NETFX_FILES_IN_USE, | 15 | GENERIC_EXECUTE_MESSAGE_NETFX_FILES_IN_USE, |
| 16 | GENERIC_EXECUTE_MESSAGE_PROCESS_CANCEL, | ||
| 16 | }; | 17 | }; |
| 17 | 18 | ||
| 18 | typedef struct _APPLY_AUTHENTICATION_REQUIRED_DATA | 19 | typedef struct _APPLY_AUTHENTICATION_REQUIRED_DATA |
| @@ -43,6 +44,10 @@ typedef struct _GENERIC_EXECUTE_MESSAGE | |||
| 43 | DWORD cFiles; | 44 | DWORD cFiles; |
| 44 | LPCWSTR* rgwzFiles; | 45 | LPCWSTR* rgwzFiles; |
| 45 | } filesInUse; | 46 | } filesInUse; |
| 47 | struct | ||
| 48 | { | ||
| 49 | DWORD dwProcessId; | ||
| 50 | } processCancel; | ||
| 46 | }; | 51 | }; |
| 47 | } GENERIC_EXECUTE_MESSAGE; | 52 | } GENERIC_EXECUTE_MESSAGE; |
| 48 | 53 | ||
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp index 88a00f5e..0bee054f 100644 --- a/src/burn/engine/bundlepackageengine.cpp +++ b/src/burn/engine/bundlepackageengine.cpp | |||
| @@ -251,7 +251,6 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( | |||
| 251 | ) | 251 | ) |
| 252 | { | 252 | { |
| 253 | HRESULT hr = S_OK; | 253 | HRESULT hr = S_OK; |
| 254 | int nResult = IDNOACTION; | ||
| 255 | LPCWSTR wzArguments = NULL; | 254 | LPCWSTR wzArguments = NULL; |
| 256 | LPWSTR sczArguments = NULL; | 255 | LPWSTR sczArguments = NULL; |
| 257 | LPWSTR sczArgumentsFormatted = NULL; | 256 | LPWSTR sczArgumentsFormatted = NULL; |
| @@ -420,31 +419,10 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( | |||
| 420 | hr = EmbeddedRunBundle(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); | 419 | hr = EmbeddedRunBundle(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); |
| 421 | ExitOnFailure(hr, "Failed to run bundle as embedded from path: %ls", sczExecutablePath); | 420 | ExitOnFailure(hr, "Failed to run bundle as embedded from path: %ls", sczExecutablePath); |
| 422 | } | 421 | } |
| 423 | else // create and wait for the executable process while sending fake progress to allow cancel. | 422 | else |
| 424 | { | 423 | { |
| 425 | // Make the cache location of the executable the current directory to help those executables | 424 | hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczExecutablePath, sczCommand, sczCachedDirectory, &dwExitCode); |
| 426 | // that expect stuff to be relative to them. | 425 | ExitOnFailure(hr, "Failed to run BUNDLE process"); |
| 427 | si.cb = sizeof(si); | ||
| 428 | if (!::CreateProcessW(sczExecutablePath, sczCommand, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, sczCachedDirectory, &si, &pi)) | ||
| 429 | { | ||
| 430 | ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", sczExecutablePath); | ||
| 431 | } | ||
| 432 | |||
| 433 | do | ||
| 434 | { | ||
| 435 | message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; | ||
| 436 | message.dwUIHint = MB_OKCANCEL; | ||
| 437 | message.progress.dwPercentage = 50; | ||
| 438 | nResult = pfnGenericMessageHandler(&message, pvContext); | ||
| 439 | hr = (IDOK == nResult || IDNOACTION == nResult) ? S_OK : IDCANCEL == nResult ? HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) : HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE); | ||
| 440 | ExitOnRootFailure(hr, "Bootstrapper application aborted during BUNDLE progress."); | ||
| 441 | |||
| 442 | hr = ProcWaitForCompletion(pi.hProcess, 500, &dwExitCode); | ||
| 443 | if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) != hr) | ||
| 444 | { | ||
| 445 | ExitOnFailure(hr, "Failed to wait for executable to complete: %ls", sczExecutablePath); | ||
| 446 | } | ||
| 447 | } while (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == hr); | ||
| 448 | } | 426 | } |
| 449 | 427 | ||
| 450 | hr = ExeEngineHandleExitCode(pPackage->Bundle.rgExitCodes, pPackage->Bundle.cExitCodes, dwExitCode, pRestart); | 428 | hr = ExeEngineHandleExitCode(pPackage->Bundle.rgExitCodes, pPackage->Bundle.cExitCodes, dwExitCode, pRestart); |
diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index 636d67ce..3c2872f1 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp | |||
| @@ -43,6 +43,7 @@ typedef enum _BURN_ELEVATION_MESSAGE_TYPE | |||
| 43 | BURN_ELEVATION_MESSAGE_TYPE_BURN_CACHE_COMPLETE, | 43 | BURN_ELEVATION_MESSAGE_TYPE_BURN_CACHE_COMPLETE, |
| 44 | BURN_ELEVATION_MESSAGE_TYPE_BURN_CACHE_SUCCESS, | 44 | BURN_ELEVATION_MESSAGE_TYPE_BURN_CACHE_SUCCESS, |
| 45 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROGRESS, | 45 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROGRESS, |
| 46 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_CANCEL, | ||
| 46 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ERROR, | 47 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ERROR, |
| 47 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_MESSAGE, | 48 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_MESSAGE, |
| 48 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_FILES_IN_USE, | 49 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_FILES_IN_USE, |
| @@ -1812,7 +1813,14 @@ static HRESULT ProcessGenericExecuteMessages( | |||
| 1812 | 1813 | ||
| 1813 | // read message parameters | 1814 | // read message parameters |
| 1814 | hr = BuffReadNumber((BYTE*)pMsg->pvData, pMsg->cbData, &iData, &message.progress.dwPercentage); | 1815 | hr = BuffReadNumber((BYTE*)pMsg->pvData, pMsg->cbData, &iData, &message.progress.dwPercentage); |
| 1815 | ExitOnFailure(hr, "Failed to progress."); | 1816 | ExitOnFailure(hr, "Failed to read progress."); |
| 1817 | break; | ||
| 1818 | |||
| 1819 | case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_CANCEL: | ||
| 1820 | message.type = GENERIC_EXECUTE_MESSAGE_PROCESS_CANCEL; | ||
| 1821 | |||
| 1822 | hr = BuffReadNumber((BYTE*)pMsg->pvData, pMsg->cbData, &iData, &message.processCancel.dwProcessId); | ||
| 1823 | ExitOnFailure(hr, "Failed to read processId."); | ||
| 1816 | break; | 1824 | break; |
| 1817 | 1825 | ||
| 1818 | case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ERROR: | 1826 | case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ERROR: |
| @@ -3450,6 +3458,13 @@ static int GenericExecuteMessageHandler( | |||
| 3450 | dwMessage = BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROGRESS; | 3458 | dwMessage = BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROGRESS; |
| 3451 | break; | 3459 | break; |
| 3452 | 3460 | ||
| 3461 | case GENERIC_EXECUTE_MESSAGE_PROCESS_CANCEL: | ||
| 3462 | hr = BuffWriteNumber(&pbData, &cbData, pMessage->processCancel.dwProcessId); | ||
| 3463 | ExitOnFailure(hr, "Failed to write progress percentage to message buffer."); | ||
| 3464 | |||
| 3465 | dwMessage = BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_CANCEL; | ||
| 3466 | break; | ||
| 3467 | |||
| 3453 | case GENERIC_EXECUTE_MESSAGE_ERROR: | 3468 | case GENERIC_EXECUTE_MESSAGE_ERROR: |
| 3454 | // serialize message data | 3469 | // serialize message data |
| 3455 | hr = BuffWriteNumber(&pbData, &cbData, pMessage->error.dwErrorCode); | 3470 | hr = BuffWriteNumber(&pbData, &cbData, pMessage->error.dwErrorCode); |
diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc index 53e6b256..9e139661 100644 --- a/src/burn/engine/engine.mc +++ b/src/burn/engine/engine.mc | |||
| @@ -933,6 +933,13 @@ Language=English | |||
| 933 | Could not create system restore point, error: 0x%1!x!. Continuing... | 933 | Could not create system restore point, error: 0x%1!x!. Continuing... |
| 934 | . | 934 | . |
| 935 | 935 | ||
| 936 | MessageId=364 | ||
| 937 | Severity=Success | ||
| 938 | SymbolicName=MSG_EXECUTE_PROCESS_DELAYED_CANCEL_REQUESTED | ||
| 939 | Language=English | ||
| 940 | Bootstrapper application requested delayed cancel during package process progress, id: %1!ls!. Waiting... | ||
| 941 | . | ||
| 942 | |||
| 936 | MessageId=370 | 943 | MessageId=370 |
| 937 | Severity=Success | 944 | Severity=Success |
| 938 | SymbolicName=MSG_SESSION_BEGIN | 945 | SymbolicName=MSG_SESSION_BEGIN |
diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp index c984f5a7..4c3c6fb0 100644 --- a/src/burn/engine/exeengine.cpp +++ b/src/burn/engine/exeengine.cpp | |||
| @@ -317,7 +317,6 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
| 317 | ) | 317 | ) |
| 318 | { | 318 | { |
| 319 | HRESULT hr = S_OK; | 319 | HRESULT hr = S_OK; |
| 320 | int nResult = IDNOACTION; | ||
| 321 | LPCWSTR wzArguments = NULL; | 320 | LPCWSTR wzArguments = NULL; |
| 322 | LPWSTR sczArguments = NULL; | 321 | LPWSTR sczArguments = NULL; |
| 323 | LPWSTR sczArgumentsFormatted = NULL; | 322 | LPWSTR sczArgumentsFormatted = NULL; |
| @@ -327,10 +326,7 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
| 327 | LPWSTR sczCommand = NULL; | 326 | LPWSTR sczCommand = NULL; |
| 328 | LPWSTR sczCommandObfuscated = NULL; | 327 | LPWSTR sczCommandObfuscated = NULL; |
| 329 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; | 328 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; |
| 330 | STARTUPINFOW si = { }; | ||
| 331 | PROCESS_INFORMATION pi = { }; | ||
| 332 | DWORD dwExitCode = 0; | 329 | DWORD dwExitCode = 0; |
| 333 | GENERIC_EXECUTE_MESSAGE message = { }; | ||
| 334 | BURN_PACKAGE* pPackage = pExecuteAction->exePackage.pPackage; | 330 | BURN_PACKAGE* pPackage = pExecuteAction->exePackage.pPackage; |
| 335 | BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload; | 331 | BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload; |
| 336 | 332 | ||
| @@ -442,37 +438,10 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
| 442 | hr = NetFxRunChainer(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); | 438 | hr = NetFxRunChainer(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); |
| 443 | ExitOnFailure(hr, "Failed to run netfx chainer: %ls", sczExecutablePath); | 439 | ExitOnFailure(hr, "Failed to run netfx chainer: %ls", sczExecutablePath); |
| 444 | } | 440 | } |
| 445 | else // create and wait for the executable process while sending fake progress to allow cancel. | 441 | else |
| 446 | { | 442 | { |
| 447 | // Make the cache location of the executable the current directory to help those executables | 443 | hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczExecutablePath, sczCommand, sczCachedDirectory, &dwExitCode); |
| 448 | // that expect stuff to be relative to them. | 444 | ExitOnFailure(hr, "Failed to run EXE process"); |
| 449 | si.cb = sizeof(si); | ||
| 450 | if (!::CreateProcessW(sczExecutablePath, sczCommand, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, sczCachedDirectory, &si, &pi)) | ||
| 451 | { | ||
| 452 | ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", sczExecutablePath); | ||
| 453 | } | ||
| 454 | |||
| 455 | if (pPackage->Exe.fFireAndForget) | ||
| 456 | { | ||
| 457 | ::WaitForInputIdle(pi.hProcess, 5000); | ||
| 458 | ExitFunction(); | ||
| 459 | } | ||
| 460 | |||
| 461 | do | ||
| 462 | { | ||
| 463 | message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; | ||
| 464 | message.dwUIHint = MB_OKCANCEL; | ||
| 465 | message.progress.dwPercentage = 50; | ||
| 466 | nResult = pfnGenericMessageHandler(&message, pvContext); | ||
| 467 | hr = (IDOK == nResult || IDNOACTION == nResult) ? S_OK : IDCANCEL == nResult ? HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) : HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE); | ||
| 468 | ExitOnRootFailure(hr, "Bootstrapper application aborted during EXE progress."); | ||
| 469 | |||
| 470 | hr = ProcWaitForCompletion(pi.hProcess, 500, &dwExitCode); | ||
| 471 | if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) != hr) | ||
| 472 | { | ||
| 473 | ExitOnFailure(hr, "Failed to wait for executable to complete: %ls", sczExecutablePath); | ||
| 474 | } | ||
| 475 | } while (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == hr); | ||
| 476 | } | 445 | } |
| 477 | 446 | ||
| 478 | hr = ExeEngineHandleExitCode(pPackage->Exe.rgExitCodes, pPackage->Exe.cExitCodes, dwExitCode, pRestart); | 447 | hr = ExeEngineHandleExitCode(pPackage->Exe.rgExitCodes, pPackage->Exe.cExitCodes, dwExitCode, pRestart); |
| @@ -487,8 +456,6 @@ LExit: | |||
| 487 | StrSecureZeroFreeString(sczCommand); | 456 | StrSecureZeroFreeString(sczCommand); |
| 488 | ReleaseStr(sczCommandObfuscated); | 457 | ReleaseStr(sczCommandObfuscated); |
| 489 | 458 | ||
| 490 | ReleaseHandle(pi.hThread); | ||
| 491 | ReleaseHandle(pi.hProcess); | ||
| 492 | ReleaseFileHandle(hExecutableFile); | 459 | ReleaseFileHandle(hExecutableFile); |
| 493 | 460 | ||
| 494 | // Best effort to clear the execute package cache folder and action variables. | 461 | // Best effort to clear the execute package cache folder and action variables. |
| @@ -498,6 +465,99 @@ LExit: | |||
| 498 | return hr; | 465 | return hr; |
| 499 | } | 466 | } |
| 500 | 467 | ||
| 468 | extern "C" HRESULT ExeEngineRunProcess( | ||
| 469 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | ||
| 470 | __in LPVOID pvContext, | ||
| 471 | __in BURN_PACKAGE* pPackage, | ||
| 472 | __in_z LPCWSTR wzExecutablePath, | ||
| 473 | __in_z LPWSTR wzCommand, | ||
| 474 | __in_z_opt LPCWSTR wzCachedDirectory, | ||
| 475 | __inout DWORD* pdwExitCode | ||
| 476 | ) | ||
| 477 | { | ||
| 478 | HRESULT hr = S_OK; | ||
| 479 | STARTUPINFOW si = { }; | ||
| 480 | PROCESS_INFORMATION pi = { }; | ||
| 481 | GENERIC_EXECUTE_MESSAGE message = { }; | ||
| 482 | int nResult = IDNOACTION; | ||
| 483 | DWORD dwProcessId = 0; | ||
| 484 | BOOL fDelayedCancel = FALSE; | ||
| 485 | BOOL fFireAndForget = BURN_PACKAGE_TYPE_EXE == pPackage->type && pPackage->Exe.fFireAndForget; | ||
| 486 | BOOL fInheritHandles = BURN_PACKAGE_TYPE_BUNDLE == pPackage->type; | ||
| 487 | |||
| 488 | // Make the cache location of the executable the current directory to help those executables | ||
| 489 | // that expect stuff to be relative to them. | ||
| 490 | si.cb = sizeof(si); | ||
| 491 | if (!::CreateProcessW(wzExecutablePath, wzCommand, NULL, NULL, fInheritHandles, CREATE_NO_WINDOW, NULL, wzCachedDirectory, &si, &pi)) | ||
| 492 | { | ||
| 493 | ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", wzExecutablePath); | ||
| 494 | } | ||
| 495 | |||
| 496 | if (fFireAndForget) | ||
| 497 | { | ||
| 498 | ::WaitForInputIdle(pi.hProcess, 5000); | ||
| 499 | ExitFunction(); | ||
| 500 | } | ||
| 501 | |||
| 502 | dwProcessId = ::GetProcessId(pi.hProcess); | ||
| 503 | |||
| 504 | // Wait for the executable process while sending fake progress to allow cancel. | ||
| 505 | do | ||
| 506 | { | ||
| 507 | message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; | ||
| 508 | message.dwUIHint = MB_OKCANCEL; | ||
| 509 | message.progress.dwPercentage = 50; | ||
| 510 | nResult = pfnGenericMessageHandler(&message, pvContext); | ||
| 511 | |||
| 512 | if (IDCANCEL == nResult) | ||
| 513 | { | ||
| 514 | memset(&message, 0, sizeof(message)); | ||
| 515 | message.type = GENERIC_EXECUTE_MESSAGE_PROCESS_CANCEL; | ||
| 516 | message.dwUIHint = MB_ABORTRETRYIGNORE; | ||
| 517 | message.processCancel.dwProcessId = dwProcessId; | ||
| 518 | nResult = pfnGenericMessageHandler(&message, pvContext); | ||
| 519 | |||
| 520 | if (IDIGNORE == nResult) // abandon | ||
| 521 | { | ||
| 522 | nResult = IDCANCEL; | ||
| 523 | fDelayedCancel = FALSE; | ||
| 524 | } | ||
| 525 | //else if (IDABORT == nResult) // kill | ||
| 526 | else // wait | ||
| 527 | { | ||
| 528 | if (!fDelayedCancel) | ||
| 529 | { | ||
| 530 | fDelayedCancel = TRUE; | ||
| 531 | |||
| 532 | LogId(REPORT_STANDARD, MSG_EXECUTE_PROCESS_DELAYED_CANCEL_REQUESTED, pPackage->sczId); | ||
| 533 | } | ||
| 534 | |||
| 535 | nResult = IDNOACTION; | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | hr = (IDOK == nResult || IDNOACTION == nResult) ? S_OK : IDCANCEL == nResult ? HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) : HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE); | ||
| 540 | ExitOnRootFailure(hr, "Bootstrapper application aborted during package process progress."); | ||
| 541 | |||
| 542 | hr = ProcWaitForCompletion(pi.hProcess, 500, pdwExitCode); | ||
| 543 | if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) != hr) | ||
| 544 | { | ||
| 545 | ExitOnFailure(hr, "Failed to wait for executable to complete: %ls", wzExecutablePath); | ||
| 546 | } | ||
| 547 | } while (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == hr); | ||
| 548 | |||
| 549 | if (fDelayedCancel) | ||
| 550 | { | ||
| 551 | ExitWithRootFailure(hr, HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT), "Bootstrapper application cancelled during package process progress, exit code: 0x%x", *pdwExitCode); | ||
| 552 | } | ||
| 553 | |||
| 554 | LExit: | ||
| 555 | ReleaseHandle(pi.hThread); | ||
| 556 | ReleaseHandle(pi.hProcess); | ||
| 557 | |||
| 558 | return hr; | ||
| 559 | } | ||
| 560 | |||
| 501 | extern "C" void ExeEngineUpdateInstallRegistrationState( | 561 | extern "C" void ExeEngineUpdateInstallRegistrationState( |
| 502 | __in BURN_EXECUTE_ACTION* pAction, | 562 | __in BURN_EXECUTE_ACTION* pAction, |
| 503 | __in HRESULT hrExecute | 563 | __in HRESULT hrExecute |
diff --git a/src/burn/engine/exeengine.h b/src/burn/engine/exeengine.h index 743621b7..636988f1 100644 --- a/src/burn/engine/exeengine.h +++ b/src/burn/engine/exeengine.h | |||
| @@ -42,6 +42,15 @@ HRESULT ExeEngineExecutePackage( | |||
| 42 | __in LPVOID pvContext, | 42 | __in LPVOID pvContext, |
| 43 | __out BOOTSTRAPPER_APPLY_RESTART* pRestart | 43 | __out BOOTSTRAPPER_APPLY_RESTART* pRestart |
| 44 | ); | 44 | ); |
| 45 | HRESULT ExeEngineRunProcess( | ||
| 46 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | ||
| 47 | __in LPVOID pvContext, | ||
| 48 | __in BURN_PACKAGE* pPackage, | ||
| 49 | __in_z LPCWSTR wzExecutablePath, | ||
| 50 | __in_z LPWSTR wzCommand, | ||
| 51 | __in_z_opt LPCWSTR wzCachedDirectory, | ||
| 52 | __inout DWORD* pdwExitCode | ||
| 53 | ); | ||
| 45 | void ExeEngineUpdateInstallRegistrationState( | 54 | void ExeEngineUpdateInstallRegistrationState( |
| 46 | __in BURN_EXECUTE_ACTION* pAction, | 55 | __in BURN_EXECUTE_ACTION* pAction, |
| 47 | __in HRESULT hrExecute | 56 | __in HRESULT hrExecute |
diff --git a/src/burn/engine/msuengine.cpp b/src/burn/engine/msuengine.cpp index 091bbe62..2f1fb61c 100644 --- a/src/burn/engine/msuengine.cpp +++ b/src/burn/engine/msuengine.cpp | |||
| @@ -264,7 +264,6 @@ extern "C" HRESULT MsuEngineExecutePackage( | |||
| 264 | ) | 264 | ) |
| 265 | { | 265 | { |
| 266 | HRESULT hr = S_OK; | 266 | HRESULT hr = S_OK; |
| 267 | int nResult = IDNOACTION; | ||
| 268 | LPWSTR sczCachedDirectory = NULL; | 267 | LPWSTR sczCachedDirectory = NULL; |
| 269 | LPWSTR sczMsuPath = NULL; | 268 | LPWSTR sczMsuPath = NULL; |
| 270 | LPWSTR sczWindowsPath = NULL; | 269 | LPWSTR sczWindowsPath = NULL; |
| @@ -350,35 +349,8 @@ extern "C" HRESULT MsuEngineExecutePackage( | |||
| 350 | hr = EnsureWUServiceEnabled(fStopWusaService, &schWu, &fWuWasDisabled); | 349 | hr = EnsureWUServiceEnabled(fStopWusaService, &schWu, &fWuWasDisabled); |
| 351 | ExitOnFailure(hr, "Failed to ensure WU service was enabled to install MSU package."); | 350 | ExitOnFailure(hr, "Failed to ensure WU service was enabled to install MSU package."); |
| 352 | 351 | ||
| 353 | // create process | 352 | hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczWusaPath, sczCommand, NULL, &dwExitCode); |
| 354 | si.cb = sizeof(si); | 353 | ExitOnFailure(hr, "Failed to run MSU process"); |
| 355 | if (!::CreateProcessW(sczWusaPath, sczCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) | ||
| 356 | { | ||
| 357 | ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", sczWusaPath); | ||
| 358 | } | ||
| 359 | |||
| 360 | do | ||
| 361 | { | ||
| 362 | message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; | ||
| 363 | message.dwUIHint = MB_OKCANCEL; | ||
| 364 | message.progress.dwPercentage = 50; | ||
| 365 | nResult = pfnGenericMessageHandler(&message, pvContext); | ||
| 366 | hr = (IDOK == nResult || IDNOACTION == nResult) ? S_OK : IDCANCEL == nResult ? HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) : HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE); | ||
| 367 | ExitOnRootFailure(hr, "Bootstrapper application aborted during MSU progress."); | ||
| 368 | |||
| 369 | // wait for process to terminate | ||
| 370 | hr = ProcWaitForCompletion(pi.hProcess, 500, &dwExitCode); | ||
| 371 | if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) != hr) | ||
| 372 | { | ||
| 373 | ExitOnFailure(hr, "Failed to wait for executable to complete: %ls", sczWusaPath); | ||
| 374 | } | ||
| 375 | } while (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == hr); | ||
| 376 | |||
| 377 | // get process exit code | ||
| 378 | if (!::GetExitCodeProcess(pi.hProcess, &dwExitCode)) | ||
| 379 | { | ||
| 380 | ExitWithLastError(hr, "Failed to get process exit code."); | ||
| 381 | } | ||
| 382 | 354 | ||
| 383 | // We'll normalize the restart required error code from wusa.exe just in case. Most likely | 355 | // We'll normalize the restart required error code from wusa.exe just in case. Most likely |
| 384 | // that on reboot we'll actually get WU_S_REBOOT_REQUIRED. | 356 | // that on reboot we'll actually get WU_S_REBOOT_REQUIRED. |
diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp index 81ce8bb9..06f87363 100644 --- a/src/burn/engine/userexperience.cpp +++ b/src/burn/engine/userexperience.cpp | |||
| @@ -104,7 +104,7 @@ extern "C" HRESULT UserExperienceLoad( | |||
| 104 | args.pCommand = pCommand; | 104 | args.pCommand = pCommand; |
| 105 | args.pfnBootstrapperEngineProc = EngineForApplicationProc; | 105 | args.pfnBootstrapperEngineProc = EngineForApplicationProc; |
| 106 | args.pvBootstrapperEngineProcContext = pEngineContext; | 106 | args.pvBootstrapperEngineProcContext = pEngineContext; |
| 107 | args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 3, 14, 0); | 107 | args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 3, 17, 0); |
| 108 | 108 | ||
| 109 | results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); | 109 | results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); |
| 110 | 110 | ||
| @@ -1701,6 +1701,34 @@ LExit: | |||
| 1701 | return hr; | 1701 | return hr; |
| 1702 | } | 1702 | } |
| 1703 | 1703 | ||
| 1704 | BAAPI UserExperienceOnExecuteProcessCancel( | ||
| 1705 | __in BURN_USER_EXPERIENCE* pUserExperience, | ||
| 1706 | __in_z LPCWSTR wzPackageId, | ||
| 1707 | __in DWORD dwProcessId, | ||
| 1708 | __inout BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION* pAction | ||
| 1709 | ) | ||
| 1710 | { | ||
| 1711 | HRESULT hr = S_OK; | ||
| 1712 | BA_ONEXECUTEPROCESSCANCEL_ARGS args = { }; | ||
| 1713 | BA_ONEXECUTEPROCESSCANCEL_RESULTS results = { }; | ||
| 1714 | |||
| 1715 | args.cbSize = sizeof(args); | ||
| 1716 | args.wzPackageId = wzPackageId; | ||
| 1717 | args.dwProcessId = dwProcessId; | ||
| 1718 | args.recommendation = *pAction; | ||
| 1719 | |||
| 1720 | results.cbSize = sizeof(results); | ||
| 1721 | results.action = *pAction; | ||
| 1722 | |||
| 1723 | hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROCESSCANCEL, &args, &results); | ||
| 1724 | ExitOnFailure(hr, "BA OnExecuteProcessCancel failed."); | ||
| 1725 | |||
| 1726 | *pAction = results.action; | ||
| 1727 | |||
| 1728 | LExit: | ||
| 1729 | return hr; | ||
| 1730 | } | ||
| 1731 | |||
| 1704 | EXTERN_C BAAPI UserExperienceOnExecuteProgress( | 1732 | EXTERN_C BAAPI UserExperienceOnExecuteProgress( |
| 1705 | __in BURN_USER_EXPERIENCE* pUserExperience, | 1733 | __in BURN_USER_EXPERIENCE* pUserExperience, |
| 1706 | __in_z LPCWSTR wzPackageId, | 1734 | __in_z LPCWSTR wzPackageId, |
diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h index 2f18acdd..de558ad5 100644 --- a/src/burn/engine/userexperience.h +++ b/src/burn/engine/userexperience.h | |||
| @@ -398,6 +398,12 @@ BAAPI UserExperienceOnExecutePatchTarget( | |||
| 398 | __in_z LPCWSTR wzPackageId, | 398 | __in_z LPCWSTR wzPackageId, |
| 399 | __in_z LPCWSTR wzTargetProductCode | 399 | __in_z LPCWSTR wzTargetProductCode |
| 400 | ); | 400 | ); |
| 401 | BAAPI UserExperienceOnExecuteProcessCancel( | ||
| 402 | __in BURN_USER_EXPERIENCE* pUserExperience, | ||
| 403 | __in_z LPCWSTR wzPackageId, | ||
| 404 | __in DWORD dwProcessId, | ||
| 405 | __inout BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION* pAction | ||
| 406 | ); | ||
| 401 | BAAPI UserExperienceOnExecuteProgress( | 407 | BAAPI UserExperienceOnExecuteProgress( |
| 402 | __in BURN_USER_EXPERIENCE* pUserExperience, | 408 | __in BURN_USER_EXPERIENCE* pUserExperience, |
| 403 | __in_z LPCWSTR wzPackageId, | 409 | __in_z LPCWSTR wzPackageId, |
diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj index 7375af86..35415dc3 100644 --- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj +++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj | |||
| @@ -80,7 +80,9 @@ | |||
| 80 | <ItemGroup> | 80 | <ItemGroup> |
| 81 | <None Include="TestData\CacheTest\CacheSignatureTest.File" CopyToOutputDirectory="PreserveNewest" /> | 81 | <None Include="TestData\CacheTest\CacheSignatureTest.File" CopyToOutputDirectory="PreserveNewest" /> |
| 82 | <None Include="TestData\PlanTest\BasicFunctionality_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | 82 | <None Include="TestData\PlanTest\BasicFunctionality_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> |
| 83 | <None Include="TestData\PlanTest\Failure_BundleD_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | ||
| 83 | <None Include="TestData\PlanTest\MsiTransaction_BundleAv1_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | 84 | <None Include="TestData\PlanTest\MsiTransaction_BundleAv1_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> |
| 85 | <None Include="TestData\PlanTest\MsuPackageFixture_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | ||
| 84 | <None Include="TestData\PlanTest\Slipstream_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | 86 | <None Include="TestData\PlanTest\Slipstream_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> |
| 85 | <None Include="TestData\PlanTest\Slipstream_BundleA_modified_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | 87 | <None Include="TestData\PlanTest\Slipstream_BundleA_modified_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> |
| 86 | </ItemGroup> | 88 | </ItemGroup> |
diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index 4d726fb4..770922b4 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp | |||
| @@ -10,7 +10,9 @@ static HRESULT WINAPI PlanTestBAProc( | |||
| 10 | ); | 10 | ); |
| 11 | 11 | ||
| 12 | static LPCWSTR wzMsiTransactionManifestFileName = L"MsiTransaction_BundleAv1_manifest.xml"; | 12 | static LPCWSTR wzMsiTransactionManifestFileName = L"MsiTransaction_BundleAv1_manifest.xml"; |
| 13 | static LPCWSTR wzSingleExeManifestFileName = L"Failure_BundleD_manifest.xml"; | ||
| 13 | static LPCWSTR wzSingleMsiManifestFileName = L"BasicFunctionality_BundleA_manifest.xml"; | 14 | static LPCWSTR wzSingleMsiManifestFileName = L"BasicFunctionality_BundleA_manifest.xml"; |
| 15 | static LPCWSTR wzSingleMsuManifestFileName = L"MsuPackageFixture_manifest.xml"; | ||
| 14 | static LPCWSTR wzSlipstreamManifestFileName = L"Slipstream_BundleA_manifest.xml"; | 16 | static LPCWSTR wzSlipstreamManifestFileName = L"Slipstream_BundleA_manifest.xml"; |
| 15 | static LPCWSTR wzSlipstreamModifiedManifestFileName = L"Slipstream_BundleA_modified_manifest.xml"; | 17 | static LPCWSTR wzSlipstreamModifiedManifestFileName = L"Slipstream_BundleA_modified_manifest.xml"; |
| 16 | 18 | ||
| @@ -659,6 +661,97 @@ namespace Bootstrapper | |||
| 659 | } | 661 | } |
| 660 | 662 | ||
| 661 | [Fact] | 663 | [Fact] |
| 664 | void SingleExeInstallTest() | ||
| 665 | { | ||
| 666 | HRESULT hr = S_OK; | ||
| 667 | BURN_ENGINE_STATE engineState = { }; | ||
| 668 | BURN_ENGINE_STATE* pEngineState = &engineState; | ||
| 669 | BURN_PLAN* pPlan = &engineState.plan; | ||
| 670 | |||
| 671 | InitializeEngineStateForCorePlan(wzSingleExeManifestFileName, pEngineState); | ||
| 672 | DetectAttachedContainerAsAttached(pEngineState); | ||
| 673 | DetectPermanentPackagesAsPresentAndCached(pEngineState); | ||
| 674 | |||
| 675 | hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); | ||
| 676 | NativeAssert::Succeeded(hr, "CorePlan failed"); | ||
| 677 | |||
| 678 | Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); | ||
| 679 | NativeAssert::StringEqual(L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}", pPlan->wzBundleId); | ||
| 680 | NativeAssert::StringEqual(L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}", pPlan->wzBundleProviderKey); | ||
| 681 | Assert::Equal<BOOL>(FALSE, pPlan->fEnabledForwardCompatibleBundle); | ||
| 682 | Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine); | ||
| 683 | Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState); | ||
| 684 | Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback); | ||
| 685 | Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval); | ||
| 686 | Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade); | ||
| 687 | |||
| 688 | BOOL fRollback = FALSE; | ||
| 689 | DWORD dwIndex = 0; | ||
| 690 | ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, TRUE, L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}", L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}"); | ||
| 691 | Assert::Equal(dwIndex, pPlan->cRegistrationActions); | ||
| 692 | |||
| 693 | fRollback = TRUE; | ||
| 694 | dwIndex = 0; | ||
| 695 | ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, FALSE, L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}", L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}"); | ||
| 696 | Assert::Equal(dwIndex, pPlan->cRollbackRegistrationActions); | ||
| 697 | |||
| 698 | fRollback = FALSE; | ||
| 699 | dwIndex = 0; | ||
| 700 | ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); | ||
| 701 | ValidateCachePackage(pPlan, fRollback, dwIndex++, L"ExeA"); | ||
| 702 | ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); | ||
| 703 | Assert::Equal(dwIndex, pPlan->cCacheActions); | ||
| 704 | |||
| 705 | fRollback = TRUE; | ||
| 706 | dwIndex = 0; | ||
| 707 | Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); | ||
| 708 | |||
| 709 | Assert::Equal(1463267ull, pPlan->qwEstimatedSize); | ||
| 710 | Assert::Equal(119695ull, pPlan->qwCacheSizeTotal); | ||
| 711 | |||
| 712 | fRollback = FALSE; | ||
| 713 | dwIndex = 0; | ||
| 714 | DWORD dwExecuteCheckpointId = 2; | ||
| 715 | ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
| 716 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 717 | ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"ExeA"); | ||
| 718 | ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_INSTALL); | ||
| 719 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 720 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 721 | ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); | ||
| 722 | Assert::Equal(dwIndex, pPlan->cExecuteActions); | ||
| 723 | |||
| 724 | fRollback = TRUE; | ||
| 725 | dwIndex = 0; | ||
| 726 | dwExecuteCheckpointId = 2; | ||
| 727 | ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
| 728 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 729 | ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL); | ||
| 730 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 731 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 732 | ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); | ||
| 733 | Assert::Equal(dwIndex, pPlan->cRollbackActions); | ||
| 734 | |||
| 735 | Assert::Equal(1ul, pPlan->cExecutePackagesTotal); | ||
| 736 | Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); | ||
| 737 | |||
| 738 | dwIndex = 0; | ||
| 739 | Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); | ||
| 740 | |||
| 741 | dwIndex = 0; | ||
| 742 | ValidateCleanAction(pPlan, dwIndex++, L"NetFx48Web"); | ||
| 743 | ValidateCleanAction(pPlan, dwIndex++, L"ExeA"); | ||
| 744 | Assert::Equal(dwIndex, pPlan->cCleanActions); | ||
| 745 | |||
| 746 | UINT uIndex = 0; | ||
| 747 | ValidatePlannedProvider(pPlan, uIndex++, L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}", NULL); | ||
| 748 | Assert::Equal(uIndex, pPlan->cPlannedProviders); | ||
| 749 | |||
| 750 | Assert::Equal(2ul, pEngineState->packages.cPackages); | ||
| 751 | ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"ExeA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); | ||
| 752 | } | ||
| 753 | |||
| 754 | [Fact] | ||
| 662 | void SingleMsiCacheTest() | 755 | void SingleMsiCacheTest() |
| 663 | { | 756 | { |
| 664 | HRESULT hr = S_OK; | 757 | HRESULT hr = S_OK; |
| @@ -1533,6 +1626,98 @@ namespace Bootstrapper | |||
| 1533 | } | 1626 | } |
| 1534 | 1627 | ||
| 1535 | [Fact] | 1628 | [Fact] |
| 1629 | void SingleMsuInstallTest() | ||
| 1630 | { | ||
| 1631 | HRESULT hr = S_OK; | ||
| 1632 | BURN_ENGINE_STATE engineState = { }; | ||
| 1633 | BURN_ENGINE_STATE* pEngineState = &engineState; | ||
| 1634 | BURN_PLAN* pPlan = &engineState.plan; | ||
| 1635 | |||
| 1636 | InitializeEngineStateForCorePlan(wzSingleMsuManifestFileName, pEngineState); | ||
| 1637 | DetectAttachedContainerAsAttached(pEngineState); | ||
| 1638 | DetectPackagesAsAbsent(pEngineState); | ||
| 1639 | |||
| 1640 | hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); | ||
| 1641 | NativeAssert::Succeeded(hr, "CorePlan failed"); | ||
| 1642 | |||
| 1643 | Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); | ||
| 1644 | NativeAssert::StringEqual(L"{06077C60-DC46-4F4A-8D3C-05F869187191}", pPlan->wzBundleId); | ||
| 1645 | NativeAssert::StringEqual(L"{06077C60-DC46-4F4A-8D3C-05F869187191}", pPlan->wzBundleProviderKey); | ||
| 1646 | Assert::Equal<BOOL>(FALSE, pPlan->fEnabledForwardCompatibleBundle); | ||
| 1647 | Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine); | ||
| 1648 | Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState); | ||
| 1649 | Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback); | ||
| 1650 | Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval); | ||
| 1651 | Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade); | ||
| 1652 | |||
| 1653 | BOOL fRollback = FALSE; | ||
| 1654 | DWORD dwIndex = 0; | ||
| 1655 | ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, TRUE, L"{06077C60-DC46-4F4A-8D3C-05F869187191}", L"{06077C60-DC46-4F4A-8D3C-05F869187191}"); | ||
| 1656 | Assert::Equal(dwIndex, pPlan->cRegistrationActions); | ||
| 1657 | |||
| 1658 | fRollback = TRUE; | ||
| 1659 | dwIndex = 0; | ||
| 1660 | ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, FALSE, L"{06077C60-DC46-4F4A-8D3C-05F869187191}", L"{06077C60-DC46-4F4A-8D3C-05F869187191}"); | ||
| 1661 | Assert::Equal(dwIndex, pPlan->cRollbackRegistrationActions); | ||
| 1662 | |||
| 1663 | fRollback = FALSE; | ||
| 1664 | dwIndex = 0; | ||
| 1665 | ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); | ||
| 1666 | ValidateCachePackage(pPlan, fRollback, dwIndex++, L"test.msu"); | ||
| 1667 | ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); | ||
| 1668 | Assert::Equal(dwIndex, pPlan->cCacheActions); | ||
| 1669 | |||
| 1670 | fRollback = TRUE; | ||
| 1671 | dwIndex = 0; | ||
| 1672 | ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"test.msu"); | ||
| 1673 | ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); | ||
| 1674 | Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); | ||
| 1675 | |||
| 1676 | Assert::Equal(56ull, pPlan->qwEstimatedSize); | ||
| 1677 | Assert::Equal(140ull, pPlan->qwCacheSizeTotal); | ||
| 1678 | |||
| 1679 | fRollback = FALSE; | ||
| 1680 | dwIndex = 0; | ||
| 1681 | DWORD dwExecuteCheckpointId = 2; | ||
| 1682 | ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
| 1683 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1684 | ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"test.msu"); | ||
| 1685 | ValidateExecuteMsuPackage(pPlan, fRollback, dwIndex++, L"test.msu", BOOTSTRAPPER_ACTION_STATE_INSTALL); | ||
| 1686 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1687 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1688 | ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); | ||
| 1689 | Assert::Equal(dwIndex, pPlan->cExecuteActions); | ||
| 1690 | |||
| 1691 | fRollback = TRUE; | ||
| 1692 | dwIndex = 0; | ||
| 1693 | dwExecuteCheckpointId = 2; | ||
| 1694 | ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
| 1695 | ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"test.msu"); | ||
| 1696 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1697 | ValidateExecuteMsuPackage(pPlan, fRollback, dwIndex++, L"test.msu", BOOTSTRAPPER_ACTION_STATE_UNINSTALL); | ||
| 1698 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1699 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1700 | ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); | ||
| 1701 | Assert::Equal(dwIndex, pPlan->cRollbackActions); | ||
| 1702 | |||
| 1703 | Assert::Equal(1ul, pPlan->cExecutePackagesTotal); | ||
| 1704 | Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); | ||
| 1705 | |||
| 1706 | dwIndex = 0; | ||
| 1707 | Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); | ||
| 1708 | |||
| 1709 | dwIndex = 0; | ||
| 1710 | Assert::Equal(dwIndex, pPlan->cCleanActions); | ||
| 1711 | |||
| 1712 | UINT uIndex = 0; | ||
| 1713 | ValidatePlannedProvider(pPlan, uIndex++, L"{06077C60-DC46-4F4A-8D3C-05F869187191}", NULL); | ||
| 1714 | Assert::Equal(uIndex, pPlan->cPlannedProviders); | ||
| 1715 | |||
| 1716 | Assert::Equal(1ul, pEngineState->packages.cPackages); | ||
| 1717 | ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"test.msu", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); | ||
| 1718 | } | ||
| 1719 | |||
| 1720 | [Fact] | ||
| 1536 | void SlipstreamInstallTest() | 1721 | void SlipstreamInstallTest() |
| 1537 | { | 1722 | { |
| 1538 | HRESULT hr = S_OK; | 1723 | HRESULT hr = S_OK; |
| @@ -2571,6 +2756,21 @@ namespace Bootstrapper | |||
| 2571 | NativeAssert::StringEqual(wzPackageId, pOrderedPatch->pPackage->sczId); | 2756 | NativeAssert::StringEqual(wzPackageId, pOrderedPatch->pPackage->sczId); |
| 2572 | } | 2757 | } |
| 2573 | 2758 | ||
| 2759 | void ValidateExecuteMsuPackage( | ||
| 2760 | __in BURN_PLAN* pPlan, | ||
| 2761 | __in BOOL fRollback, | ||
| 2762 | __in DWORD dwIndex, | ||
| 2763 | __in LPCWSTR wzPackageId, | ||
| 2764 | __in BOOTSTRAPPER_ACTION_STATE action | ||
| 2765 | ) | ||
| 2766 | { | ||
| 2767 | BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); | ||
| 2768 | Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_MSU_PACKAGE, pAction->type); | ||
| 2769 | NativeAssert::StringEqual(wzPackageId, pAction->msuPackage.pPackage->sczId); | ||
| 2770 | Assert::Equal<DWORD>(action, pAction->msuPackage.action); | ||
| 2771 | Assert::Equal<BOOL>(FALSE, pAction->fDeleted); | ||
| 2772 | } | ||
| 2773 | |||
| 2574 | void ValidateExecutePackageDependency( | 2774 | void ValidateExecutePackageDependency( |
| 2575 | __in BURN_PLAN* pPlan, | 2775 | __in BURN_PLAN* pPlan, |
| 2576 | __in BOOL fRollback, | 2776 | __in BOOL fRollback, |
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/Failure_BundleD_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/Failure_BundleD_manifest.xml new file mode 100644 index 00000000..6afb0108 --- /dev/null +++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/Failure_BundleD_manifest.xml | |||
| @@ -0,0 +1 @@ | |||
| <?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~FailureTests_BundleD" Extension=".log" /><RelatedBundle Id="{3C1A4842-81AC-4C90-8B35-A5E18F034C8D}" Action="Upgrade" /><Variable Id="TestGroupName" Value="FailureTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><RegistrySearch Id="wrsQ7JTGqvaQuDYjfHJoyjxtkLlR6c" Variable="ExeA_Version" Root="HKLM" Key="Software\WiX\Tests\FailureTests\ExeA" Value="Version" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u34" /></UX><Container Id="WixAttachedContainer" FileSize="24029" Hash="03F9C95A2ADA5563D3D937C0161F22A76E12F2F0AF2AA6BE567292D0AB122E2C42990E97CA9C1EE9A5F43A571B01C4ED7A3EA5759A6836AC8BFD959D7FFDCB18" FilePath="BundleD.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1439328" CertificateRootPublicKeyIdentifier="F49F9B33E25E33CCA0BFB15A62B7C29FFAB3880B" CertificateRootThumbprint="ABDCA79AF9DD48A0EA702AD45260B3C03093FB4B" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="TestExe.exe" FilePath="TestExe.exe" FileSize="23552" Hash="4344604ECBA4DFE5DE7C680CB1AA5BD6FAA29BF95CE07740F02878C2BB1EF6DE6432944A0DB79B034D1C6F68CF80842EEE442EA8A551816E52D3F68901C50AB9" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="paygJp32KbpyjbVEQFNbl5_izmhdZw" FilePath="TestExe.exe.config" FileSize="387" Hash="8C819A9E835F3921FA80C5C783AB0C42DDAADF0C0F2BEF8630EA122ABCB9DC8EAF0B14E061C46B37C92F55114BB09A8D5B1B613947A76A648953F2C63C0ACA63" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{9C184683-04FB-49AD-9D79-65101BDC3EE3}" ExecutableName="BundleD.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{9C184683-04FB-49AD-9D79-65101BDC3EE3}"><Arp Register="yes" DisplayName="~FailureTests - BundleD" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="remove" CacheId="642721C60D52051C7F3434D8710FE3406A7CFE10B2B39E90EA847719ED1697D7C614F2DF44AD50412B1DF8C98DD78FDC57CA1D047D28C81AC158092E5FB18040" InstallSize="1439328" Size="1439328" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 >= 528040" InstallArguments="/q /norestart /log "[NetFx48WebLog].html"" UninstallArguments="" Uninstallable="no" RepairArguments="" Repairable="no" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><ExePackage Id="ExeA" Cache="remove" CacheId="4344604ECBA4DFE5DE7C680CB1AA5BD6FAA29BF95CE07740F02878C2BB1EF6DE6432944A0DB79B034D1C6F68CF80842EEE442EA8A551816E52D3F68901C50AB9" InstallSize="23939" Size="23939" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_ExeA" RollbackLogPathVariable="WixBundleRollbackLog_ExeA" DetectCondition="ExeA_Version AND ExeA_Version >= v1.0.0.0" InstallArguments="/s 5000 /regw "HKLM\Software\WiX\Tests\FailureTests\ExeA,Version,String,1.0.0.0"" UninstallArguments="/regd "HKLM\Software\WiX\Tests\FailureTests\ExeA,Version"" Uninstallable="yes" RepairArguments="/regw "HKLM\Software\WiX\Tests\FailureTests\ExeA,Version,String,1.0.0.0"" Repairable="yes"><PayloadRef Id="TestExe.exe" /><PayloadRef Id="paygJp32KbpyjbVEQFNbl5_izmhdZw" /></ExePackage></Chain><CommandLine Variables="upperCase" /></BurnManifest> \ No newline at end of file | |||
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/MsuPackageFixture_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/MsuPackageFixture_manifest.xml new file mode 100644 index 00000000..fb6afa88 --- /dev/null +++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/MsuPackageFixture_manifest.xml | |||
| @@ -0,0 +1 @@ | |||
| <?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="BurnBundle" Extension="log" /><RelatedBundle Id="{B94478B1-E1F3-4700-9CE8-6AA090854AEC}" Action="Upgrade" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><UX><Payload Id="payaQenPi7_8hq6T._EXtBW0NvR7gA" FilePath="fakeba.dll" SourcePath="u0" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u1" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u2" /></UX><Container Id="WixAttachedContainer" FileSize="119" Hash="06D28293FD57CD231E125EF9C82418A488928A98832A6937A77A3283A17A5C37F8D619C51759319A57E8F8A948FA73E8C5814185A0114130F3213AB268073555" FilePath="test.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="test.msu" FilePath="test.msu" FileSize="28" Hash="B040F02D2F90E04E9AFBDC91C00CEB5DF97D48E205D96DC0A44E10AF8870794DAE62CA70224F12BE9112AA730BBE470CA81FB5617AAC690E832F3F84510E92BA" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{06077C60-DC46-4F4A-8D3C-05F869187191}" ExecutableName="test.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{06077C60-DC46-4F4A-8D3C-05F869187191}"><Arp Register="yes" DisplayName="BurnBundle" DisplayVersion="1.0.0.0" Publisher="Example Corporation" /></Registration><Chain><MsuPackage Id="test.msu" Cache="keep" CacheId="B040F02D2F90E04E9AFBDC91C00CEB5DF97D48E205D96DC0A44E10AF8870794DAE62CA70224F12BE9112AA730BBE470CA81FB5617AAC690E832F3F84510E92BA" InstallSize="28" Size="28" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" RollbackBoundaryBackward="WixDefaultBoundary" DetectCondition="DetectedTheMsu" KB="xyz"><PayloadRef Id="test.msu" /></MsuPackage></Chain><CommandLine Variables="upperCase" /></BurnManifest> \ No newline at end of file | |||
diff --git a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp index 84e32867..444a917f 100644 --- a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp +++ b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp | |||
| @@ -2170,6 +2170,14 @@ private: // privates | |||
| 2170 | m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE, pArgs, pResults, m_pvBAFunctionsProcContext); | 2170 | m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE, pArgs, pResults, m_pvBAFunctionsProcContext); |
| 2171 | } | 2171 | } |
| 2172 | 2172 | ||
| 2173 | void OnExecuteProcessCancelFallback( | ||
| 2174 | __in BA_ONEXECUTEPROCESSCANCEL_ARGS* pArgs, | ||
| 2175 | __inout BA_ONEXECUTEPROCESSCANCEL_RESULTS* pResults | ||
| 2176 | ) | ||
| 2177 | { | ||
| 2178 | m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONEXECUTEPROCESSCANCEL, pArgs, pResults, m_pvBAFunctionsProcContext); | ||
| 2179 | } | ||
| 2180 | |||
| 2173 | 2181 | ||
| 2174 | public: //CBalBaseBootstrapperApplication | 2182 | public: //CBalBaseBootstrapperApplication |
| 2175 | virtual STDMETHODIMP Initialize( | 2183 | virtual STDMETHODIMP Initialize( |
diff --git a/src/test/burn/TestBA/TestBA.cs b/src/test/burn/TestBA/TestBA.cs index 3688e028..c219ce9c 100644 --- a/src/test/burn/TestBA/TestBA.cs +++ b/src/test/burn/TestBA/TestBA.cs | |||
| @@ -21,7 +21,7 @@ namespace WixToolset.Test.BA | |||
| 21 | private Form dummyWindow; | 21 | private Form dummyWindow; |
| 22 | private IntPtr windowHandle; | 22 | private IntPtr windowHandle; |
| 23 | private LaunchAction action; | 23 | private LaunchAction action; |
| 24 | private ManualResetEvent wait; | 24 | private readonly ManualResetEvent wait; |
| 25 | private int result; | 25 | private int result; |
| 26 | 26 | ||
| 27 | private string updateBundlePath; | 27 | private string updateBundlePath; |
| @@ -397,6 +397,35 @@ namespace WixToolset.Test.BA | |||
| 397 | } | 397 | } |
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | protected override void OnExecutePackageComplete(ExecutePackageCompleteEventArgs args) | ||
| 401 | { | ||
| 402 | bool logTestRegistryValue; | ||
| 403 | string recordTestRegistryValue = this.ReadPackageAction(args.PackageId, "RecordTestRegistryValue"); | ||
| 404 | if (!String.IsNullOrEmpty(recordTestRegistryValue) && Boolean.TryParse(recordTestRegistryValue, out logTestRegistryValue) && logTestRegistryValue) | ||
| 405 | { | ||
| 406 | var value = this.ReadTestRegistryValue(args.PackageId); | ||
| 407 | this.Log("TestRegistryValue: {0}, Version, '{1}'", args.PackageId, value); | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | protected override void OnExecuteProcessCancel(ExecuteProcessCancelEventArgs args) | ||
| 412 | { | ||
| 413 | BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION action; | ||
| 414 | string actionValue = this.ReadPackageAction(args.PackageId, "ProcessCancelAction"); | ||
| 415 | if (actionValue != null && TryParseEnum<BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION>(actionValue, out action)) | ||
| 416 | { | ||
| 417 | args.Action = action; | ||
| 418 | } | ||
| 419 | |||
| 420 | if (args.Action == BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION.Abandon) | ||
| 421 | { | ||
| 422 | // Give time to the process to start before its files are deleted. | ||
| 423 | Thread.Sleep(2000); | ||
| 424 | } | ||
| 425 | |||
| 426 | this.Log("OnExecuteProcessCancel({0})", args.Action); | ||
| 427 | } | ||
| 428 | |||
| 400 | protected override void OnExecuteFilesInUse(ExecuteFilesInUseEventArgs args) | 429 | protected override void OnExecuteFilesInUse(ExecuteFilesInUseEventArgs args) |
| 401 | { | 430 | { |
| 402 | this.Log("OnExecuteFilesInUse() - package: {0}, source: {1}, retries remaining: {2}, data: {3}", args.PackageId, args.Source, this.retryExecuteFilesInUse, String.Join(", ", args.Files.ToArray())); | 431 | this.Log("OnExecuteFilesInUse() - package: {0}, source: {1}, retries remaining: {2}, data: {3}", args.PackageId, args.Source, this.retryExecuteFilesInUse, String.Join(", ", args.Files.ToArray())); |
| @@ -488,43 +517,34 @@ namespace WixToolset.Test.BA | |||
| 488 | private void TestVariables() | 517 | private void TestVariables() |
| 489 | { | 518 | { |
| 490 | // First make sure we can check and get standard variables of each type. | 519 | // First make sure we can check and get standard variables of each type. |
| 520 | if (this.Engine.ContainsVariable("WindowsFolder")) | ||
| 491 | { | 521 | { |
| 492 | string value = null; | 522 | string value = this.Engine.GetVariableString("WindowsFolder"); |
| 493 | if (this.Engine.ContainsVariable("WindowsFolder")) | 523 | this.Engine.Log(LogLevel.Verbose, String.Format("TEST: Successfully retrieved a string variable: WindowsFolder '{0}'", value)); |
| 494 | { | 524 | } |
| 495 | value = this.Engine.GetVariableString("WindowsFolder"); | 525 | else |
| 496 | this.Engine.Log(LogLevel.Verbose, "TEST: Successfully retrieved a string variable: WindowsFolder"); | 526 | { |
| 497 | } | 527 | throw new Exception("Engine did not define a standard variable: WindowsFolder"); |
| 498 | else | ||
| 499 | { | ||
| 500 | throw new Exception("Engine did not define a standard variable: WindowsFolder"); | ||
| 501 | } | ||
| 502 | } | 528 | } |
| 503 | 529 | ||
| 530 | if (this.Engine.ContainsVariable("NTProductType")) | ||
| 504 | { | 531 | { |
| 505 | long value = 0; | 532 | long value = this.Engine.GetVariableNumeric("NTProductType"); |
| 506 | if (this.Engine.ContainsVariable("NTProductType")) | 533 | this.Engine.Log(LogLevel.Verbose, String.Format("TEST: Successfully retrieved a numeric variable: NTProductType '{0}'", value)); |
| 507 | { | 534 | } |
| 508 | value = this.Engine.GetVariableNumeric("NTProductType"); | 535 | else |
| 509 | this.Engine.Log(LogLevel.Verbose, "TEST: Successfully retrieved a numeric variable: NTProductType"); | 536 | { |
| 510 | } | 537 | throw new Exception("Engine did not define a standard variable: NTProductType"); |
| 511 | else | ||
| 512 | { | ||
| 513 | throw new Exception("Engine did not define a standard variable: NTProductType"); | ||
| 514 | } | ||
| 515 | } | 538 | } |
| 516 | 539 | ||
| 540 | if (this.Engine.ContainsVariable("VersionMsi")) | ||
| 517 | { | 541 | { |
| 518 | string value = null; | 542 | string value = this.Engine.GetVariableVersion("VersionMsi"); |
| 519 | if (this.Engine.ContainsVariable("VersionMsi")) | 543 | this.Engine.Log(LogLevel.Verbose, String.Format("TEST: Successfully retrieved a version variable: VersionMsi '{0}'", value)); |
| 520 | { | 544 | } |
| 521 | value = this.Engine.GetVariableVersion("VersionMsi"); | 545 | else |
| 522 | this.Engine.Log(LogLevel.Verbose, "TEST: Successfully retrieved a version variable: VersionMsi"); | 546 | { |
| 523 | } | 547 | throw new Exception("Engine did not define a standard variable: VersionMsi"); |
| 524 | else | ||
| 525 | { | ||
| 526 | throw new Exception("Engine did not define a standard variable: VersionMsi"); | ||
| 527 | } | ||
| 528 | } | 548 | } |
| 529 | 549 | ||
| 530 | // Now validate that Contians returns false for non-existant variables of each type. | 550 | // Now validate that Contians returns false for non-existant variables of each type. |
| @@ -596,6 +616,15 @@ namespace WixToolset.Test.BA | |||
| 596 | } | 616 | } |
| 597 | } | 617 | } |
| 598 | 618 | ||
| 619 | private string ReadTestRegistryValue(string name) | ||
| 620 | { | ||
| 621 | string testName = this.Engine.GetVariableString("TestGroupName"); | ||
| 622 | using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\{0}\{1}", testName, name))) | ||
| 623 | { | ||
| 624 | return testKey == null ? null : testKey.GetValue("Version") as string; | ||
| 625 | } | ||
| 626 | } | ||
| 627 | |||
| 599 | private static bool TryParseEnum<T>(string value, out T t) | 628 | private static bool TryParseEnum<T>(string value, out T t) |
| 600 | { | 629 | { |
| 601 | try | 630 | try |
diff --git a/src/test/burn/TestData/FailureTests/BundleD/BundleD.wixproj b/src/test/burn/TestData/FailureTests/BundleD/BundleD.wixproj new file mode 100644 index 00000000..7b7408c6 --- /dev/null +++ b/src/test/burn/TestData/FailureTests/BundleD/BundleD.wixproj | |||
| @@ -0,0 +1,19 @@ | |||
| 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 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <OutputType>Bundle</OutputType> | ||
| 5 | <UpgradeCode>{3C1A4842-81AC-4C90-8B35-A5E18F034C8D}</UpgradeCode> | ||
| 6 | <Version>1.0.0.0</Version> | ||
| 7 | </PropertyGroup> | ||
| 8 | <ItemGroup> | ||
| 9 | <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" /> | ||
| 10 | </ItemGroup> | ||
| 11 | <ItemGroup> | ||
| 12 | <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" /> | ||
| 13 | </ItemGroup> | ||
| 14 | <ItemGroup> | ||
| 15 | <PackageReference Include="WixToolset.Bal.wixext" /> | ||
| 16 | <PackageReference Include="WixToolset.NetFx.wixext" /> | ||
| 17 | <PackageReference Include="WixToolset.Util.wixext" /> | ||
| 18 | </ItemGroup> | ||
| 19 | </Project> \ No newline at end of file | ||
diff --git a/src/test/burn/TestData/FailureTests/BundleD/BundleD.wxs b/src/test/burn/TestData/FailureTests/BundleD/BundleD.wxs new file mode 100644 index 00000000..ca70236d --- /dev/null +++ b/src/test/burn/TestData/FailureTests/BundleD/BundleD.wxs | |||
| @@ -0,0 +1,19 @@ | |||
| 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 | <?define TestExeRegistryKey = Software\WiX\Tests\$(var.TestGroupName)\ExeA?> | ||
| 4 | |||
| 5 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 6 | <Fragment> | ||
| 7 | <util:RegistrySearch Root="HKLM" Key="$(var.TestExeRegistryKey)" Value="Version" Variable="ExeA_Version" /> | ||
| 8 | |||
| 9 | <PackageGroup Id="BundlePackages"> | ||
| 10 | <ExePackage Id="ExeA" Cache="remove" PerMachine="yes" | ||
| 11 | DetectCondition="ExeA_Version AND ExeA_Version >= v$(var.Version)" | ||
| 12 | InstallArguments="/s 5000 /regw "HKLM\$(var.TestExeRegistryKey),Version,String,$(var.Version)"" | ||
| 13 | RepairArguments="/regw "HKLM\$(var.TestExeRegistryKey),Version,String,$(var.Version)"" | ||
| 14 | UninstallArguments="/regd "HKLM\$(var.TestExeRegistryKey),Version""> | ||
| 15 | <PayloadGroupRef Id="TestExePayloads" /> | ||
| 16 | </ExePackage> | ||
| 17 | </PackageGroup> | ||
| 18 | </Fragment> | ||
| 19 | </Wix> | ||
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/FailureTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/FailureTests.cs index d8428a54..bbc0b387 100644 --- a/src/test/burn/WixToolsetTest.BurnE2E/FailureTests.cs +++ b/src/test/burn/WixToolsetTest.BurnE2E/FailureTests.cs | |||
| @@ -2,7 +2,9 @@ | |||
| 2 | 2 | ||
| 3 | namespace WixToolsetTest.BurnE2E | 3 | namespace WixToolsetTest.BurnE2E |
| 4 | { | 4 | { |
| 5 | using System.Threading; | ||
| 5 | using WixTestTools; | 6 | using WixTestTools; |
| 7 | using WixToolset.Mba.Core; | ||
| 6 | using Xunit; | 8 | using Xunit; |
| 7 | using Xunit.Abstractions; | 9 | using Xunit.Abstractions; |
| 8 | 10 | ||
| @@ -11,6 +13,46 @@ namespace WixToolsetTest.BurnE2E | |||
| 11 | public FailureTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } | 13 | public FailureTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } |
| 12 | 14 | ||
| 13 | [Fact] | 15 | [Fact] |
| 16 | public void CanCancelExePackageAndAbandonIt() | ||
| 17 | { | ||
| 18 | var bundleD = this.CreateBundleInstaller("BundleD"); | ||
| 19 | var testBAController = this.CreateTestBAController(); | ||
| 20 | |||
| 21 | // Cancel package ExeA after it starts. | ||
| 22 | testBAController.SetPackageCancelExecuteAtProgress("ExeA", 1); | ||
| 23 | testBAController.SetPackageRecordTestRegistryValue("ExeA"); | ||
| 24 | |||
| 25 | var logPath = bundleD.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT); | ||
| 26 | bundleD.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
| 27 | |||
| 28 | Assert.True(LogVerifier.MessageInLogFile(logPath, "TestRegistryValue: ExeA, Version, ''")); | ||
| 29 | |||
| 30 | // Make sure ExeA finishes running. | ||
| 31 | Thread.Sleep(3000); | ||
| 32 | |||
| 33 | bundleD.VerifyExeTestRegistryValue("ExeA", "1.0.0.0"); | ||
| 34 | } | ||
| 35 | |||
| 36 | [Fact] | ||
| 37 | public void CanCancelExePackageAndWaitUntilItCompletes() | ||
| 38 | { | ||
| 39 | var bundleD = this.CreateBundleInstaller("BundleD"); | ||
| 40 | var testBAController = this.CreateTestBAController(); | ||
| 41 | |||
| 42 | // Cancel package ExeA after it starts. | ||
| 43 | testBAController.SetPackageCancelExecuteAtProgress("ExeA", 1); | ||
| 44 | testBAController.SetPackageProcessCancelAction("ExeA", BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION.Wait); | ||
| 45 | testBAController.SetPackageRecordTestRegistryValue("ExeA"); | ||
| 46 | |||
| 47 | var logPath = bundleD.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT); | ||
| 48 | bundleD.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
| 49 | |||
| 50 | Assert.True(LogVerifier.MessageInLogFile(logPath, "TestRegistryValue: ExeA, Version, '1.0.0.0'")); | ||
| 51 | |||
| 52 | bundleD.VerifyExeTestRegistryValue("ExeA", "1.0.0.0"); | ||
| 53 | } | ||
| 54 | |||
| 55 | [Fact] | ||
| 14 | public void CanCancelMsiPackageVeryEarly() | 56 | public void CanCancelMsiPackageVeryEarly() |
| 15 | { | 57 | { |
| 16 | var packageA = this.CreatePackageInstaller("PackageA"); | 58 | var packageA = this.CreatePackageInstaller("PackageA"); |
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/TestBAController.cs b/src/test/burn/WixToolsetTest.BurnE2E/TestBAController.cs index d2e8a1ca..fa553919 100644 --- a/src/test/burn/WixToolsetTest.BurnE2E/TestBAController.cs +++ b/src/test/burn/WixToolsetTest.BurnE2E/TestBAController.cs | |||
| @@ -148,6 +148,21 @@ namespace WixToolsetTest.BurnE2E | |||
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | /// <summary> | 150 | /// <summary> |
| 151 | /// Requests the BA to log the test registry value for the specified package. | ||
| 152 | /// </summary> | ||
| 153 | /// <param name="packageId"></param> | ||
| 154 | /// <param name="value"></param> | ||
| 155 | public void SetPackageRecordTestRegistryValue(string packageId, string value = "true") | ||
| 156 | { | ||
| 157 | this.SetPackageState(packageId, "RecordTestRegistryValue", value); | ||
| 158 | } | ||
| 159 | |||
| 160 | public void SetPackageProcessCancelAction(string packageId, BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION action) | ||
| 161 | { | ||
| 162 | this.SetPackageState(packageId, "ProcessCancelAction", action.ToString()); | ||
| 163 | } | ||
| 164 | |||
| 165 | /// <summary> | ||
| 151 | /// Sets the number of times to re-run the Detect phase. | 166 | /// Sets the number of times to re-run the Detect phase. |
| 152 | /// </summary> | 167 | /// </summary> |
| 153 | /// <param name="state">Number of times to run Detect (after the first, normal, Detect).</param> | 168 | /// <param name="state">Number of times to run Detect (after the first, normal, Detect).</param> |
