From 75c22ecc4fe810602ced1b6512f697a1d9c963ac Mon Sep 17 00:00:00 2001 From: Nir Bar Date: Sun, 5 May 2024 13:22:50 +0300 Subject: [PATCH] Support sending custom messages on embedded pipe --- Readme.md | 1 + src/burn/engine/EngineForApplication.cpp | 33 +++++++++++++ src/burn/engine/apply.cpp | 4 ++ src/burn/engine/apply.h | 6 +++ src/burn/engine/embedded.cpp | 46 ++++++++++++++++++ src/burn/engine/embedded.h | 1 + src/burn/inc/IBootstrapperApplication.h | 10 ++++ src/burn/inc/IBootstrapperEngine.h | 6 +++ .../mba/core/BootstrapperApplication.cs | 26 ++++++++++ src/ext/BalExtension/mba/core/Engine.cs | 12 +++++ src/ext/BalExtension/mba/core/EventArgs.cs | 47 +++++++++++++++++++ .../mba/core/IBootstrapperApplication.cs | 8 ++++ .../mba/core/IBootstrapperEngine.cs | 6 +++ src/libs/balutil/inc/BalBaseBaFunctions.h | 9 ++++ .../inc/BalBaseBootstrapperApplication.h | 9 ++++ 15 files changed, 224 insertions(+) diff --git a/Readme.md b/Readme.md index 04aaf4111..ace54bf8e 100644 --- a/Readme.md +++ b/Readme.md @@ -35,6 +35,7 @@ - Changes by WiX up to git commit 376423b8101f4b59ee865e8a255cfe190fa5a7f1 - Build for .NET Framework 4.0 - Not overwriting log files when retrying to execute a package +- Support sending custom messages on embedded pipe # WiX Toolset on GitHub The WiX Toolset builds Windows installation packages from XML source code. The toolset supports a command-line environment that developers may integrate into their build processes to build Windows Installer (MSI) packages and executable bundles. The WiX GitHub project hosts the WiX source code Git repositories. The following links will take you to more details: diff --git a/src/burn/engine/EngineForApplication.cpp b/src/burn/engine/EngineForApplication.cpp index 9b3d67860..32db03b80 100644 --- a/src/burn/engine/EngineForApplication.cpp +++ b/src/burn/engine/EngineForApplication.cpp @@ -370,6 +370,39 @@ class CEngineForApplication : public IBootstrapperEngine, public IMarshal return hr; } + virtual STDMETHODIMP SendEmbeddedCustomMessage( + __in DWORD dwCode, + __in_z_opt LPCWSTR wzMessage, + __out int* pnResult + ) + { + HRESULT hr = S_OK; + BYTE* pbData = NULL; + DWORD cbData = 0; + DWORD dwResult = 0; + + if (BURN_MODE_EMBEDDED != m_pEngineState->mode) + { + hr = HRESULT_FROM_WIN32(ERROR_INVALID_STATE); + ExitOnRootFailure(hr, "Application requested to send embedded progress message when not in embedded mode."); + } + + hr = BuffWriteNumber(&pbData, &cbData, dwCode); + ExitOnFailure(hr, "Failed to write code to message buffer."); + + hr = BuffWriteString(&pbData, &cbData, wzMessage ? wzMessage : L""); + ExitOnFailure(hr, "Failed to write text to message buffer."); + + hr = PipeSendMessage(m_pEngineState->embeddedConnection.hPipe, BURN_EMBEDDED_MESSAGE_TYPE_CUSTOM, pbData, cbData, NULL, NULL, &dwResult); + ExitOnFailure(hr, "Failed to send embedded progress message over pipe."); + + *pnResult = static_cast(dwResult); + + LExit: + ReleaseBuffer(pbData); + return hr; + } + virtual STDMETHODIMP SetUpdate( __in_z_opt LPCWSTR wzLocalSource, __in_z_opt LPCWSTR wzDownloadSource, diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp index 481c9226e..647b4739c 100644 --- a/src/burn/engine/apply.cpp +++ b/src/burn/engine/apply.cpp @@ -2492,6 +2492,10 @@ static int GenericExecuteMessageHandler( case GENERIC_EXECUTE_MESSAGE_FILES_IN_USE: nResult = pContext->pUX->pUserExperience->OnExecuteFilesInUse(pContext->pExecutingPackage->sczId, pMessage->filesInUse.cFiles, pMessage->filesInUse.rgwzFiles); break; + + case GENERIC_EXECUTE_MESSAGE_CUSTOM: + nResult = pContext->pUX->pUserExperience->OnEmbeddedCustomMessage(pContext->pExecutingPackage->sczId, pMessage->custom.dwCode, pMessage->custom.wzMessage); + break; } nResult = UserExperienceCheckExecuteResult(pContext->pUX, pContext->fRollback, pMessage->dwAllowedResults, nResult); diff --git a/src/burn/engine/apply.h b/src/burn/engine/apply.h index b717251e1..963663179 100644 --- a/src/burn/engine/apply.h +++ b/src/burn/engine/apply.h @@ -13,6 +13,7 @@ enum GENERIC_EXECUTE_MESSAGE_TYPE GENERIC_EXECUTE_MESSAGE_ERROR, GENERIC_EXECUTE_MESSAGE_PROGRESS, GENERIC_EXECUTE_MESSAGE_FILES_IN_USE, + GENERIC_EXECUTE_MESSAGE_CUSTOM, }; typedef struct _APPLY_AUTHENTICATION_REQUIRED_DATA @@ -43,6 +44,11 @@ typedef struct _GENERIC_EXECUTE_MESSAGE DWORD cFiles; LPCWSTR* rgwzFiles; } filesInUse; + struct + { + DWORD dwCode; + LPCWSTR wzMessage; + } custom; }; } GENERIC_EXECUTE_MESSAGE; diff --git a/src/burn/engine/embedded.cpp b/src/burn/engine/embedded.cpp index b6e4ee200..d3960ba65 100644 --- a/src/burn/engine/embedded.cpp +++ b/src/burn/engine/embedded.cpp @@ -32,6 +32,13 @@ static HRESULT OnEmbeddedProgress( __in DWORD cbData, __out DWORD* pdwResult ); +static HRESULT OnEmbeddedCustomMessage( + __in PFN_GENERICMESSAGEHANDLER pfnMessageHandler, + __in LPVOID pvContext, + __in_bcount(cbData) BYTE* pbData, + __in DWORD cbData, + __out DWORD* pdwResult + ); // function definitions @@ -127,6 +134,11 @@ static HRESULT ProcessEmbeddedMessages( ExitOnFailure(hr, "Failed to process embedded progress message."); break; + case BURN_EMBEDDED_MESSAGE_TYPE_CUSTOM: + hr = OnEmbeddedCustomMessage(pContext->pfnGenericMessageHandler, pContext->pvContext, static_cast(pMsg->pvData), pMsg->cbData, &dwResult); + ExitOnFailure(hr, "Failed to process embedded custom message."); + break; + default: hr = E_INVALIDARG; ExitOnRootFailure1(hr, "Unexpected embedded message sent to child process, msg: %u", pMsg->dwMessage); @@ -172,6 +184,40 @@ static HRESULT OnEmbeddedErrorMessage( return hr; } +static HRESULT OnEmbeddedCustomMessage( + __in PFN_GENERICMESSAGEHANDLER pfnMessageHandler, + __in LPVOID pvContext, + __in_bcount(cbData) BYTE* pbData, + __in DWORD cbData, + __out DWORD* pdwResult + ) +{ + HRESULT hr = S_OK; + DWORD iData = 0; + GENERIC_EXECUTE_MESSAGE message = { }; + LPWSTR sczMessage = NULL; + + message.type = GENERIC_EXECUTE_MESSAGE_CUSTOM; + + hr = BuffReadNumber(pbData, cbData, &iData, &message.custom.dwCode); + ExitOnFailure(hr, "Failed to read custom code from buffer."); + + hr = BuffReadString(pbData, cbData, &iData, &sczMessage); + ExitOnFailure(hr, "Failed to read custom message from buffer."); + + message.custom.wzMessage = sczMessage; + + hr = BuffReadNumber(pbData, cbData, &iData, &message.dwAllowedResults); + ExitOnFailure(hr, "Failed to read UI hint from buffer."); + + *pdwResult = (DWORD)pfnMessageHandler(&message, pvContext); + +LExit: + ReleaseStr(sczMessage); + + return hr; +} + static HRESULT OnEmbeddedProgress( __in PFN_GENERICMESSAGEHANDLER pfnMessageHandler, __in LPVOID pvContext, diff --git a/src/burn/engine/embedded.h b/src/burn/engine/embedded.h index 08adeae0a..ac4cfed0a 100644 --- a/src/burn/engine/embedded.h +++ b/src/burn/engine/embedded.h @@ -11,6 +11,7 @@ typedef enum _BURN_EMBEDDED_MESSAGE_TYPE BURN_EMBEDDED_MESSAGE_TYPE_UNKNOWN, BURN_EMBEDDED_MESSAGE_TYPE_ERROR, BURN_EMBEDDED_MESSAGE_TYPE_PROGRESS, + BURN_EMBEDDED_MESSAGE_TYPE_CUSTOM, } BURN_EMBEDDED_MESSAGE_TYPE; diff --git a/src/burn/inc/IBootstrapperApplication.h b/src/burn/inc/IBootstrapperApplication.h index 0d712ab7b..569471b66 100644 --- a/src/burn/inc/IBootstrapperApplication.h +++ b/src/burn/inc/IBootstrapperApplication.h @@ -725,6 +725,16 @@ DECLARE_INTERFACE_IID_(IBootstrapperApplication, IUnknown, "53C31D56-49C0-426B-A __in DWORD cFiles, __in_ecount_z(cFiles) LPCWSTR* rgwzFiles ) = 0; + + // OnEmbeddedCustomMessage - called when an embedded burn package send a SendEmbeddedCustomMessage(...). + // + // Return: + // Any code that the sender and recipient agree on. + STDMETHOD_(int, OnEmbeddedCustomMessage)( + __in_z LPCWSTR wzPackageId, + __in DWORD dwCode, + __in_z LPCWSTR wzMessage + ) = 0; // OnExecutePackageComplete - called when a package execution is complete. // diff --git a/src/burn/inc/IBootstrapperEngine.h b/src/burn/inc/IBootstrapperEngine.h index b98027ba2..f903c787f 100644 --- a/src/burn/inc/IBootstrapperEngine.h +++ b/src/burn/inc/IBootstrapperEngine.h @@ -158,6 +158,12 @@ DECLARE_INTERFACE_IID_(IBootstrapperEngine, IUnknown, "6480D616-27A0-44D7-905B-8 __out int* pnResult ) = 0; + STDMETHOD(SendEmbeddedCustomMessage)( + __in DWORD dwCode, + __in_z_opt LPCWSTR wzMessage, + __out int* pnResult + ) = 0; + STDMETHOD(SetUpdate)( __in_z_opt LPCWSTR wzLocalSource, __in_z_opt LPCWSTR wzDownloadSource, diff --git a/src/ext/BalExtension/mba/core/BootstrapperApplication.cs b/src/ext/BalExtension/mba/core/BootstrapperApplication.cs index b29d08d54..6b4af0121 100644 --- a/src/ext/BalExtension/mba/core/BootstrapperApplication.cs +++ b/src/ext/BalExtension/mba/core/BootstrapperApplication.cs @@ -315,6 +315,11 @@ protected BootstrapperApplication() /// public event EventHandler ExecuteFilesInUse; + /// + /// Fired when an embedded burn package sends a SendEmbeddedCustomMessage(...) + /// + public event EventHandler EmbeddedCustomMessage; + /// /// Fired when the engine has completed installing a specific package. /// @@ -1141,6 +1146,19 @@ protected virtual void OnExecuteFilesInUse(ExecuteFilesInUseEventArgs args) } } + /// + /// Called when an embedded burn package sends a SendEmbeddedCustomMessage(...). + /// + /// Additional arguments for this event. + protected virtual void OnEmbeddedCustomMessage(EmbeddedCustomMessageEventArgs args) + { + EventHandler handler = this.EmbeddedCustomMessage; + if (null != handler) + { + handler(this, args); + } + } + /// /// Called when the engine has completed installing a specific package. /// @@ -1638,6 +1656,14 @@ Result IBootstrapperApplication.OnExecuteFilesInUse(string wzPackageId, int cFil return args.Result; } + Result IBootstrapperApplication.OnEmbeddedCustomMessage(string wzPackageId, int dwCode, string wzMessage) + { + EmbeddedCustomMessageEventArgs args = new EmbeddedCustomMessageEventArgs(wzPackageId, dwCode, wzMessage); + this.OnEmbeddedCustomMessage(args); + + return args.Result; + } + Result IBootstrapperApplication.OnExecutePackageComplete(string wzPackageId, int hrExitCode, ApplyRestart restart, int nRecommendation) { ExecutePackageCompleteEventArgs args = new ExecutePackageCompleteEventArgs(wzPackageId, hrExitCode, restart, nRecommendation); diff --git a/src/ext/BalExtension/mba/core/Engine.cs b/src/ext/BalExtension/mba/core/Engine.cs index 047b27ae8..345f2b442 100644 --- a/src/ext/BalExtension/mba/core/Engine.cs +++ b/src/ext/BalExtension/mba/core/Engine.cs @@ -440,6 +440,18 @@ public int SendEmbeddedProgress(int progressPercentage, int overallPercentage) return result; } + /// + /// Sends a custom embedded message. + /// + /// Custom message code. + /// Optional text. + public int SendEmbeddedCustomMessage(int code, string message) + { + int result = 0; + this.engine.SendEmbeddedCustomMessage(code, message, out result); + return result; + } + /// /// Shuts down the engine. /// diff --git a/src/ext/BalExtension/mba/core/EventArgs.cs b/src/ext/BalExtension/mba/core/EventArgs.cs index 474ab0d65..78198a5d1 100644 --- a/src/ext/BalExtension/mba/core/EventArgs.cs +++ b/src/ext/BalExtension/mba/core/EventArgs.cs @@ -1943,6 +1943,53 @@ public IList Files get { return this.files; } } } + + /// + /// Additional arugments used for embedded custom messages. + /// + [Serializable] + public class EmbeddedCustomMessageEventArgs : ResultEventArgs + { + private string packageId; + private int code; + private string message; + + /// + /// Creates a new instance of the class. + /// + /// The identity of the package that yielded the files in use message. + /// The list of files in use. + public EmbeddedCustomMessageEventArgs(string packageId, int code, string message) + { + this.packageId = packageId; + this.code = code; + this.message = message; + } + + /// + /// Gets the identity of the package that yielded the files in use message. + /// + public string PackageId + { + get { return this.packageId; } + } + + /// + /// Gets the message code. + /// + public int Code + { + get { return this.code; } + } + + /// + /// Gets the message text. + /// + public string Message + { + get { return this.message; } + } + } /// /// Additional arguments used when the engine has completed installing a specific package. diff --git a/src/ext/BalExtension/mba/core/IBootstrapperApplication.cs b/src/ext/BalExtension/mba/core/IBootstrapperApplication.cs index a707b4d82..bdabd8b2e 100644 --- a/src/ext/BalExtension/mba/core/IBootstrapperApplication.cs +++ b/src/ext/BalExtension/mba/core/IBootstrapperApplication.cs @@ -389,6 +389,14 @@ Result OnExecuteFilesInUse( [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1, ArraySubType = UnmanagedType.LPWStr), In] string[] rgwzFiles ); + [PreserveSig] + [return: MarshalAs(UnmanagedType.I4)] + Result OnEmbeddedCustomMessage( + [MarshalAs(UnmanagedType.LPWStr)] string wzPackageId, + [MarshalAs(UnmanagedType.U4)] int code, + [MarshalAs(UnmanagedType.LPWStr)] string wzMessage + ); + [PreserveSig] [return: MarshalAs(UnmanagedType.I4)] Result OnExecutePackageComplete( diff --git a/src/ext/BalExtension/mba/core/IBootstrapperEngine.cs b/src/ext/BalExtension/mba/core/IBootstrapperEngine.cs index a557c2e95..832782ac4 100644 --- a/src/ext/BalExtension/mba/core/IBootstrapperEngine.cs +++ b/src/ext/BalExtension/mba/core/IBootstrapperEngine.cs @@ -70,6 +70,12 @@ void SendEmbeddedError( [MarshalAs(UnmanagedType.I4)] out int pnResult ); + void SendEmbeddedCustomMessage( + [MarshalAs(UnmanagedType.U4)] int dwCode, + [MarshalAs(UnmanagedType.LPWStr)] string wzMessage, + [MarshalAs(UnmanagedType.I4)] out int pnResult + ); + void SendEmbeddedProgress( [MarshalAs(UnmanagedType.U4)] int dwProgressPercentage, [MarshalAs(UnmanagedType.U4)] int dwOverallProgressPercentage, diff --git a/src/libs/balutil/inc/BalBaseBaFunctions.h b/src/libs/balutil/inc/BalBaseBaFunctions.h index 8c5886e9c..08238118b 100644 --- a/src/libs/balutil/inc/BalBaseBaFunctions.h +++ b/src/libs/balutil/inc/BalBaseBaFunctions.h @@ -538,6 +538,15 @@ class BalBaseBaFunctions : public IBootstrapperApplication return IDNOACTION; } + virtual STDMETHODIMP_(int) OnEmbeddedCustomMessage( + __in_z LPCWSTR /*wzPackageId*/, + __in DWORD /*dwCode*/, + __in_z LPCWSTR /*wzMessage*/ + ) + { + return IDNOACTION; + } + virtual STDMETHODIMP_(int) OnExecutePackageComplete( __in_z LPCWSTR /*wzPackageId*/, __in HRESULT /*hrExitCode*/, diff --git a/src/libs/balutil/inc/BalBaseBootstrapperApplication.h b/src/libs/balutil/inc/BalBaseBootstrapperApplication.h index dec67d97d..524e8adef 100644 --- a/src/libs/balutil/inc/BalBaseBootstrapperApplication.h +++ b/src/libs/balutil/inc/BalBaseBootstrapperApplication.h @@ -606,6 +606,15 @@ class CBalBaseBootstrapperApplication : public IBootstrapperApplication return CheckCanceled() ? IDCANCEL : IDNOACTION; } + virtual STDMETHODIMP_(int) OnEmbeddedCustomMessage( + __in_z LPCWSTR /*wzPackageId*/, + __in DWORD /*dwCode*/, + __in_z LPCWSTR /*wzMessage*/ + ) + { + return CheckCanceled() ? IDCANCEL : IDNOACTION; + } + virtual STDMETHODIMP_(int) OnExecutePackageComplete( __in_z LPCWSTR wzPackageId, __in HRESULT hrExitCode,