main
cpp 200 lines 6.21 KB
Raw
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 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 EmbeddedRunBundle -
40
41 *******************************************************************/
42 extern "C" HRESULT EmbeddedRunBundle(
43 __in BURN_PIPE_CONNECTION* pConnection,
44 __in_z LPCWSTR wzExecutablePath,
45 __in_z LPWSTR sczBaseCommand,
46 __in_z_opt LPCWSTR wzUserArgs,
47 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler,
48 __in LPVOID pvContext,
49 __out DWORD* pdwExitCode
50 )
51 {
52 HRESULT hr = S_OK;
53 DWORD dwCurrentProcessId = ::GetCurrentProcessId();
54 LPWSTR sczCommand = NULL;
55 PROCESS_INFORMATION pi = { };
56 BURN_PIPE_RESULT result = { };
57
58 BurnPipeConnectionInitialize(pConnection);
59
60 BURN_EMBEDDED_CALLBACK_CONTEXT context = { };
61 context.pfnGenericMessageHandler = pfnGenericMessageHandler;
62 context.pvContext = pvContext;
63
64 hr = BurnPipeCreateNameAndSecret(&pConnection->sczName, &pConnection->sczSecret);
65 ExitOnFailure(hr, "Failed to create embedded pipe name and client token.");
66
67 hr = BurnPipeCreatePipes(pConnection, FALSE);
68 ExitOnFailure(hr, "Failed to create embedded pipe.");
69
70 hr = StrAllocFormatted(&sczCommand, L"%ls -%ls %ls %ls %u", sczBaseCommand, BURN_COMMANDLINE_SWITCH_EMBEDDED, pConnection->sczName, pConnection->sczSecret, dwCurrentProcessId);
71 ExitOnFailure(hr, "Failed to append embedded args.");
72
73 // Always add user supplied arguments last.
74 if (wzUserArgs)
75 {
76 hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", wzUserArgs);
77 ExitOnFailure(hr, "Failed to append user args.");
78 }
79
80 hr = CoreCreateProcess(wzExecutablePath, sczCommand, TRUE, CREATE_NO_WINDOW, NULL, 0, &pi);
81 ExitOnFailure(hr, "Failed to create embedded process at path: %ls", wzExecutablePath);
82
83 pConnection->dwProcessId = ::GetProcessId(pi.hProcess);
84 pConnection->hProcess = pi.hProcess;
85 pi.hProcess = NULL;
86
87 hr = BurnPipeWaitForChildConnect(pConnection);
88 ExitOnFailure(hr, "Failed to wait for embedded process to connect to pipe.");
89
90 hr = BurnPipePumpMessages(pConnection->hPipe, ProcessEmbeddedMessages, &context, &result);
91 ExitOnFailure(hr, "Failed to process messages from embedded message.");
92
93 // Get the return code from the embedded process.
94 hr = CoreWaitForProcCompletion(pConnection->hProcess, INFINITE, pdwExitCode);
95 ExitOnFailure(hr, "Failed to wait for embedded executable: %ls", wzExecutablePath);
96
97 LExit:
98 ReleaseHandle(pi.hThread);
99 ReleaseHandle(pi.hProcess);
100
101 StrSecureZeroFreeString(sczCommand);
102 BurnPipeConnectionUninitialize(pConnection);
103
104 return hr;
105 }
106
107
108 // internal function definitions
109
110 static HRESULT ProcessEmbeddedMessages(
111 __in PIPE_MESSAGE* pMsg,
112 __in_opt LPVOID pvContext,
113 __out DWORD* pdwResult
114 )
115 {
116 HRESULT hr = S_OK;
117 BURN_EMBEDDED_CALLBACK_CONTEXT* pContext = static_cast<BURN_EMBEDDED_CALLBACK_CONTEXT*>(pvContext);
118 DWORD dwResult = 0;
119
120 // Process the message.
121 switch (pMsg->dwMessageType)
122 {
123 case BURN_EMBEDDED_MESSAGE_TYPE_ERROR:
124 hr = OnEmbeddedErrorMessage(pContext->pfnGenericMessageHandler, pContext->pvContext, static_cast<BYTE*>(pMsg->pvData), pMsg->cbData, &dwResult);
125 ExitOnFailure(hr, "Failed to process embedded error message.");
126 break;
127
128 case BURN_EMBEDDED_MESSAGE_TYPE_PROGRESS:
129 hr = OnEmbeddedProgress(pContext->pfnGenericMessageHandler, pContext->pvContext, static_cast<BYTE*>(pMsg->pvData), pMsg->cbData, &dwResult);
130 ExitOnFailure(hr, "Failed to process embedded progress message.");
131 break;
132
133 default:
134 LogStringLine(REPORT_DEBUG, "Unexpected embedded message received from child process, msg: %u", pMsg->dwMessageType);
135 dwResult = (DWORD)E_NOTIMPL;
136 }
137
138 *pdwResult = dwResult;
139
140 LExit:
141 return hr;
142 }
143
144 static HRESULT OnEmbeddedErrorMessage(
145 __in PFN_GENERICMESSAGEHANDLER pfnMessageHandler,
146 __in LPVOID pvContext,
147 __in_bcount(cbData) BYTE* pbData,
148 __in SIZE_T cbData,
149 __out DWORD* pdwResult
150 )
151 {
152 HRESULT hr = S_OK;
153 SIZE_T iData = 0;
154 GENERIC_EXECUTE_MESSAGE message = { };
155 LPWSTR sczMessage = NULL;
156
157 message.type = GENERIC_EXECUTE_MESSAGE_ERROR;
158
159 hr = BuffReadNumber(pbData, cbData, &iData, &message.error.dwErrorCode);
160 ExitOnFailure(hr, "Failed to read error code from buffer.");
161
162 hr = BuffReadString(pbData, cbData, &iData, &sczMessage);
163 ExitOnFailure(hr, "Failed to read error message from buffer.");
164
165 message.error.wzMessage = sczMessage;
166
167 hr = BuffReadNumber(pbData, cbData, &iData, &message.dwUIHint);
168 ExitOnFailure(hr, "Failed to read UI hint from buffer.");
169
170 *pdwResult = (DWORD)pfnMessageHandler(&message, pvContext);
171
172 LExit:
173 ReleaseStr(sczMessage);
174
175 return hr;
176 }
177
178 static HRESULT OnEmbeddedProgress(
179 __in PFN_GENERICMESSAGEHANDLER pfnMessageHandler,
180 __in LPVOID pvContext,
181 __in_bcount(cbData) BYTE* pbData,
182 __in SIZE_T cbData,
183 __out DWORD* pdwResult
184 )
185 {
186 HRESULT hr = S_OK;
187 SIZE_T iData = 0;
188 GENERIC_EXECUTE_MESSAGE message = { };
189
190 message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS;
191 message.dwUIHint = MB_OKCANCEL;
192
193 hr = BuffReadNumber(pbData, cbData, &iData, &message.progress.dwPercentage);
194 ExitOnFailure(hr, "Failed to read progress from buffer.");
195
196 *pdwResult = (DWORD)pfnMessageHandler(&message, pvContext);
197
198 LExit:
199 return hr;
200 }