diff options
Diffstat (limited to 'src/burn/engine/embedded.cpp')
| -rw-r--r-- | src/burn/engine/embedded.cpp | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/burn/engine/embedded.cpp b/src/burn/engine/embedded.cpp new file mode 100644 index 00000000..03898ebd --- /dev/null +++ b/src/burn/engine/embedded.cpp | |||
| @@ -0,0 +1,197 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | #include "precomp.h" | ||
| 4 | |||
| 5 | |||
| 6 | // struct | ||
| 7 | |||
| 8 | struct BURN_EMBEDDED_CALLBACK_CONTEXT | ||
| 9 | { | ||
| 10 | PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler; | ||
| 11 | LPVOID pvContext; | ||
| 12 | }; | ||
| 13 | |||
| 14 | // internal function declarations | ||
| 15 | |||
| 16 | static HRESULT ProcessEmbeddedMessages( | ||
| 17 | __in BURN_PIPE_MESSAGE* pMsg, | ||
| 18 | __in_opt LPVOID pvContext, | ||
| 19 | __out DWORD* pdwResult | ||
| 20 | ); | ||
| 21 | static HRESULT OnEmbeddedErrorMessage( | ||
| 22 | __in PFN_GENERICMESSAGEHANDLER pfnMessageHandler, | ||
| 23 | __in LPVOID pvContext, | ||
| 24 | __in_bcount(cbData) BYTE* pbData, | ||
| 25 | __in SIZE_T cbData, | ||
| 26 | __out DWORD* pdwResult | ||
| 27 | ); | ||
| 28 | static HRESULT OnEmbeddedProgress( | ||
| 29 | __in PFN_GENERICMESSAGEHANDLER pfnMessageHandler, | ||
| 30 | __in LPVOID pvContext, | ||
| 31 | __in_bcount(cbData) BYTE* pbData, | ||
| 32 | __in SIZE_T cbData, | ||
| 33 | __out DWORD* pdwResult | ||
| 34 | ); | ||
| 35 | |||
| 36 | // function definitions | ||
| 37 | |||
| 38 | /******************************************************************* | ||
| 39 | EmbeddedLaunchChildProcess - | ||
| 40 | |||
| 41 | *******************************************************************/ | ||
| 42 | extern "C" HRESULT EmbeddedRunBundle( | ||
| 43 | __in LPCWSTR wzExecutablePath, | ||
| 44 | __in LPCWSTR wzArguments, | ||
| 45 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | ||
| 46 | __in LPVOID pvContext, | ||
| 47 | __out DWORD* pdwExitCode | ||
| 48 | ) | ||
| 49 | { | ||
| 50 | HRESULT hr = S_OK; | ||
| 51 | DWORD dwCurrentProcessId = ::GetCurrentProcessId(); | ||
| 52 | HANDLE hCreatedPipesEvent = NULL; | ||
| 53 | LPWSTR sczCommand = NULL; | ||
| 54 | STARTUPINFOW si = { }; | ||
| 55 | PROCESS_INFORMATION pi = { }; | ||
| 56 | BURN_PIPE_RESULT result = { }; | ||
| 57 | |||
| 58 | BURN_PIPE_CONNECTION connection = { }; | ||
| 59 | PipeConnectionInitialize(&connection); | ||
| 60 | |||
| 61 | BURN_EMBEDDED_CALLBACK_CONTEXT context = { }; | ||
| 62 | context.pfnGenericMessageHandler = pfnGenericMessageHandler; | ||
| 63 | context.pvContext = pvContext; | ||
| 64 | |||
| 65 | hr = PipeCreateNameAndSecret(&connection.sczName, &connection.sczSecret); | ||
| 66 | ExitOnFailure(hr, "Failed to create embedded pipe name and client token."); | ||
| 67 | |||
| 68 | hr = PipeCreatePipes(&connection, FALSE, &hCreatedPipesEvent); | ||
| 69 | ExitOnFailure(hr, "Failed to create embedded pipe."); | ||
| 70 | |||
| 71 | hr = StrAllocFormattedSecure(&sczCommand, L"%ls -%ls %ls %ls %u", wzArguments, BURN_COMMANDLINE_SWITCH_EMBEDDED, connection.sczName, connection.sczSecret, dwCurrentProcessId); | ||
| 72 | ExitOnFailure(hr, "Failed to allocate embedded command."); | ||
| 73 | |||
| 74 | if (!::CreateProcessW(wzExecutablePath, sczCommand, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) | ||
| 75 | { | ||
| 76 | ExitWithLastError(hr, "Failed to create embedded process at path: %ls", wzExecutablePath); | ||
| 77 | } | ||
| 78 | |||
| 79 | connection.dwProcessId = ::GetProcessId(pi.hProcess); | ||
| 80 | connection.hProcess = pi.hProcess; | ||
| 81 | pi.hProcess = NULL; | ||
| 82 | |||
| 83 | hr = PipeWaitForChildConnect(&connection); | ||
| 84 | ExitOnFailure(hr, "Failed to wait for embedded process to connect to pipe."); | ||
| 85 | |||
| 86 | hr = PipePumpMessages(connection.hPipe, ProcessEmbeddedMessages, &context, &result); | ||
| 87 | ExitOnFailure(hr, "Failed to process messages from embedded message."); | ||
| 88 | |||
| 89 | // Get the return code from the embedded process. | ||
| 90 | hr = ProcWaitForCompletion(connection.hProcess, INFINITE, pdwExitCode); | ||
| 91 | ExitOnFailure(hr, "Failed to wait for embedded executable: %ls", wzExecutablePath); | ||
| 92 | |||
| 93 | LExit: | ||
| 94 | ReleaseHandle(pi.hThread); | ||
| 95 | ReleaseHandle(pi.hProcess); | ||
| 96 | |||
| 97 | StrSecureZeroFreeString(sczCommand); | ||
| 98 | ReleaseHandle(hCreatedPipesEvent); | ||
| 99 | PipeConnectionUninitialize(&connection); | ||
| 100 | |||
| 101 | return hr; | ||
| 102 | } | ||
| 103 | |||
| 104 | |||
| 105 | // internal function definitions | ||
| 106 | |||
| 107 | static HRESULT ProcessEmbeddedMessages( | ||
| 108 | __in BURN_PIPE_MESSAGE* pMsg, | ||
| 109 | __in_opt LPVOID pvContext, | ||
| 110 | __out DWORD* pdwResult | ||
| 111 | ) | ||
| 112 | { | ||
| 113 | HRESULT hr = S_OK; | ||
| 114 | BURN_EMBEDDED_CALLBACK_CONTEXT* pContext = static_cast<BURN_EMBEDDED_CALLBACK_CONTEXT*>(pvContext); | ||
| 115 | DWORD dwResult = 0; | ||
| 116 | |||
| 117 | // Process the message. | ||
| 118 | switch (pMsg->dwMessage) | ||
| 119 | { | ||
| 120 | case BURN_EMBEDDED_MESSAGE_TYPE_ERROR: | ||
| 121 | hr = OnEmbeddedErrorMessage(pContext->pfnGenericMessageHandler, pContext->pvContext, static_cast<BYTE*>(pMsg->pvData), pMsg->cbData, &dwResult); | ||
| 122 | ExitOnFailure(hr, "Failed to process embedded error message."); | ||
| 123 | break; | ||
| 124 | |||
| 125 | case BURN_EMBEDDED_MESSAGE_TYPE_PROGRESS: | ||
| 126 | hr = OnEmbeddedProgress(pContext->pfnGenericMessageHandler, pContext->pvContext, static_cast<BYTE*>(pMsg->pvData), pMsg->cbData, &dwResult); | ||
| 127 | ExitOnFailure(hr, "Failed to process embedded progress message."); | ||
| 128 | break; | ||
| 129 | |||
| 130 | default: | ||
| 131 | hr = E_INVALIDARG; | ||
| 132 | ExitOnRootFailure(hr, "Unexpected embedded message sent to child process, msg: %u", pMsg->dwMessage); | ||
| 133 | } | ||
| 134 | |||
| 135 | *pdwResult = dwResult; | ||
| 136 | |||
| 137 | LExit: | ||
| 138 | return hr; | ||
| 139 | } | ||
| 140 | |||
| 141 | static HRESULT OnEmbeddedErrorMessage( | ||
| 142 | __in PFN_GENERICMESSAGEHANDLER pfnMessageHandler, | ||
| 143 | __in LPVOID pvContext, | ||
| 144 | __in_bcount(cbData) BYTE* pbData, | ||
| 145 | __in SIZE_T cbData, | ||
| 146 | __out DWORD* pdwResult | ||
| 147 | ) | ||
| 148 | { | ||
| 149 | HRESULT hr = S_OK; | ||
| 150 | SIZE_T iData = 0; | ||
| 151 | GENERIC_EXECUTE_MESSAGE message = { }; | ||
| 152 | LPWSTR sczMessage = NULL; | ||
| 153 | |||
| 154 | message.type = GENERIC_EXECUTE_MESSAGE_ERROR; | ||
| 155 | |||
| 156 | hr = BuffReadNumber(pbData, cbData, &iData, &message.error.dwErrorCode); | ||
| 157 | ExitOnFailure(hr, "Failed to read error code from buffer."); | ||
| 158 | |||
| 159 | hr = BuffReadString(pbData, cbData, &iData, &sczMessage); | ||
| 160 | ExitOnFailure(hr, "Failed to read error message from buffer."); | ||
| 161 | |||
| 162 | message.error.wzMessage = sczMessage; | ||
| 163 | |||
| 164 | hr = BuffReadNumber(pbData, cbData, &iData, &message.dwAllowedResults); | ||
| 165 | ExitOnFailure(hr, "Failed to read UI hint from buffer."); | ||
| 166 | |||
| 167 | *pdwResult = (DWORD)pfnMessageHandler(&message, pvContext); | ||
| 168 | |||
| 169 | LExit: | ||
| 170 | ReleaseStr(sczMessage); | ||
| 171 | |||
| 172 | return hr; | ||
| 173 | } | ||
| 174 | |||
| 175 | static HRESULT OnEmbeddedProgress( | ||
| 176 | __in PFN_GENERICMESSAGEHANDLER pfnMessageHandler, | ||
| 177 | __in LPVOID pvContext, | ||
| 178 | __in_bcount(cbData) BYTE* pbData, | ||
| 179 | __in SIZE_T cbData, | ||
| 180 | __out DWORD* pdwResult | ||
| 181 | ) | ||
| 182 | { | ||
| 183 | HRESULT hr = S_OK; | ||
| 184 | SIZE_T iData = 0; | ||
| 185 | GENERIC_EXECUTE_MESSAGE message = { }; | ||
| 186 | |||
| 187 | message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; | ||
| 188 | message.dwAllowedResults = MB_OKCANCEL; | ||
| 189 | |||
| 190 | hr = BuffReadNumber(pbData, cbData, &iData, &message.progress.dwPercentage); | ||
| 191 | ExitOnFailure(hr, "Failed to read progress from buffer."); | ||
| 192 | |||
| 193 | *pdwResult = (DWORD)pfnMessageHandler(&message, pvContext); | ||
| 194 | |||
| 195 | LExit: | ||
| 196 | return hr; | ||
| 197 | } | ||
