aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine/netfxchainer.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-22 17:06:54 -0700
committerRob Mensching <rob@firegiant.com>2021-04-29 16:36:06 -0700
commitaf10c45d7b3a44af0b461a557847fe03263dcc10 (patch)
tree6a5c1532304782c36ffe4200b38f3afb76789a43 /src/burn/engine/netfxchainer.cpp
parent9c2aed97299fb96aeee3f1471ce40225437aaecf (diff)
downloadwix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.gz
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.bz2
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.zip
Move burn into burn
Diffstat (limited to 'src/burn/engine/netfxchainer.cpp')
-rw-r--r--src/burn/engine/netfxchainer.cpp418
1 files changed, 418 insertions, 0 deletions
diff --git a/src/burn/engine/netfxchainer.cpp b/src/burn/engine/netfxchainer.cpp
new file mode 100644
index 00000000..4e7a7720
--- /dev/null
+++ b/src/burn/engine/netfxchainer.cpp
@@ -0,0 +1,418 @@
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
5static VOID DestroyNetFxChainer(
6 __in NetFxChainer* pChainer
7 )
8{
9 if (pChainer)
10 {
11 ReleaseHandle(pChainer->hSection);
12 ReleaseHandle(pChainer->hEventChaineeSend);
13 ReleaseHandle(pChainer->hEventChainerSend);
14 ReleaseHandle(pChainer->hMutex);
15
16 if (pChainer->pData)
17 {
18 ::UnmapViewOfFile(pChainer->pData);
19 }
20
21 MemFree(pChainer);
22 }
23}
24
25static HRESULT CreateNetFxChainer(
26 __in LPCWSTR wzSectionName,
27 __in LPCWSTR wzEventName,
28 __out NetFxChainer** ppChainer
29 )
30{
31 HRESULT hr = S_OK;
32 LPWSTR sczName = NULL;
33 NetFxChainer* pChainer = NULL;
34
35 pChainer = (NetFxChainer*)MemAlloc(sizeof(NetFxChainer), TRUE);
36 ExitOnNull(pChainer, hr, E_OUTOFMEMORY, "Failed to allocate memory for NetFxChainer struct.");
37
38 pChainer->hEventChaineeSend = ::CreateEvent(NULL, FALSE, FALSE, wzEventName);
39 ExitOnNullWithLastError(pChainer->hEventChaineeSend, hr, "Failed to create event: %ls", wzEventName);
40
41 hr = StrAllocFormatted(&sczName, L"%ls_send", wzEventName);
42 ExitOnFailure(hr, "failed to allocate memory for event name");
43
44 pChainer->hEventChainerSend = ::CreateEvent(NULL, FALSE, FALSE, sczName);
45 ExitOnNullWithLastError(pChainer->hEventChainerSend, hr, "Failed to create event: %ls", sczName);
46
47 hr = StrAllocFormatted(&sczName, L"%ls_mutex", wzEventName);
48 ExitOnFailure(hr, "failed to allocate memory for mutex name");
49
50 // Create the mutex, we initially own
51 pChainer->hMutex = ::CreateMutex(NULL, TRUE, sczName);
52 ExitOnNullWithLastError(pChainer->hMutex, hr, "Failed to create mutex: %ls", sczName);
53
54 pChainer->hSection = ::CreateFileMapping(INVALID_HANDLE_VALUE,
55 NULL, // security attributes
56 PAGE_READWRITE,
57 0, // high-order DWORD of maximum size
58 NETFXDATA_SIZE, // low-order DWORD of maximum size
59 wzSectionName);
60 ExitOnNullWithLastError(pChainer->hSection, hr, "Failed to memory map cabinet file: %ls", wzSectionName);
61
62 pChainer->pData = reinterpret_cast<NetFxDataStructure*>(::MapViewOfFile(pChainer->hSection,
63 FILE_MAP_WRITE,
64 0, 0, // offsets
65 0 // map entire file
66 ));
67 ExitOnNullWithLastError(pChainer->pData, hr, "Failed to MapViewOfFile for %ls.", wzSectionName);
68
69 // Initialize the shared memory
70 hr = ::StringCchCopyW(pChainer->pData->szEventName, countof(pChainer->pData->szEventName), wzEventName);
71 ExitOnFailure(hr, "failed to copy event name to shared memory structure.");
72 pChainer->pData->downloadFinished = false;
73 pChainer->pData->downloadSoFar = 0;
74 pChainer->pData->hrDownloadFinished = E_PENDING;
75 pChainer->pData->downloadAbort = false;
76 pChainer->pData->installFinished = false;
77 pChainer->pData->installSoFar = 0;
78 pChainer->pData->hrInstallFinished = E_PENDING;
79 pChainer->pData->installAbort = false;
80 pChainer->pData->hrInternalError = S_OK;
81 pChainer->pData->version = NETFXDATA_VERSION;
82 pChainer->pData->messageCode = 0;
83 pChainer->pData->messageResponse = 0;
84 pChainer->pData->messageDataLength = 0;
85
86 // Done with initialization, allow others to access.
87 ::ReleaseMutex(pChainer->hMutex);
88
89 *ppChainer = pChainer;
90 pChainer = NULL;
91
92LExit:
93 ReleaseStr(sczName);
94
95 if (pChainer)
96 {
97 // Something failed, release the mutex and destroy the object
98 if (pChainer->hMutex)
99 {
100 ::ReleaseMutex(pChainer->hMutex);
101 }
102
103 DestroyNetFxChainer(pChainer);
104 }
105
106 return hr;
107}
108
109
110static VOID NetFxAbort(
111 __in NetFxChainer* pChainer
112 )
113{
114 ::WaitForSingleObject(pChainer->hMutex, INFINITE);
115
116 pChainer->pData->downloadAbort = true;
117 pChainer->pData->installAbort = true;
118
119 ::ReleaseMutex(pChainer->hMutex);
120
121 ::SetEvent(pChainer->hEventChainerSend);
122}
123
124static BYTE NetFxGetProgress(
125 __in NetFxChainer* pChainer
126 )
127{
128 BYTE bProgress = 0;
129 ::WaitForSingleObject(pChainer->hMutex, INFINITE);
130
131 bProgress = (pChainer->pData->installSoFar + pChainer->pData->downloadSoFar) / 2;
132
133 ::ReleaseMutex(pChainer->hMutex);
134
135 return bProgress;
136}
137
138static HRESULT NetFxGetMessage(
139 __in NetFxChainer* pChainer,
140 __out DWORD* pdwMessage,
141 __out LPVOID* ppBuffer,
142 __out DWORD* pdwBufferSize
143 )
144{
145 HRESULT hr = S_OK;
146 ::WaitForSingleObject(pChainer->hMutex, INFINITE);
147
148 *pdwMessage = pChainer->pData->messageCode;
149 *ppBuffer = NULL;
150 *pdwBufferSize = 0;
151
152 if (NETFX_NO_MESSAGE != *pdwMessage)
153 {
154 *ppBuffer = MemAlloc(pChainer->pData->messageDataLength, TRUE);
155 ExitOnNull(*ppBuffer, hr, E_OUTOFMEMORY, "Failed to allocate memory for message data");
156
157 memcpy(*ppBuffer, pChainer->pData->messageData, pChainer->pData->messageDataLength);
158 *pdwBufferSize = pChainer->pData->messageDataLength;
159 }
160
161LExit:
162 ::ReleaseMutex(pChainer->hMutex);
163
164 return hr;
165}
166
167static void NetFxRespond(
168 __in NetFxChainer* pChainer,
169 __in DWORD dwResponse
170 )
171{
172 ::WaitForSingleObject(pChainer->hMutex, INFINITE);
173
174 pChainer->pData->messageCode = NETFX_NO_MESSAGE;
175 pChainer->pData->messageResponse = dwResponse;
176 if (IDCANCEL == dwResponse)
177 {
178 pChainer->pData->downloadAbort = true;
179 pChainer->pData->installAbort = true;
180 }
181
182 ::ReleaseMutex(pChainer->hMutex);
183
184 ::SetEvent(pChainer->hEventChainerSend);
185}
186
187static HRESULT NetFxGetResult(
188 __in NetFxChainer* pChainer,
189 __out HRESULT* phrInternalError
190 )
191{
192 HRESULT hr = S_OK;
193 ::WaitForSingleObject(pChainer->hMutex, INFINITE);
194
195 hr = pChainer->pData->hrInstallFinished;
196
197 if (FAILED(pChainer->pData->hrDownloadFinished) && // Download failed
198 (S_OK == hr || E_ABORT == hr)) // Install succeeded or was aborted
199 {
200 hr = pChainer->pData->hrDownloadFinished;
201 }
202
203 if (phrInternalError)
204 {
205 *phrInternalError = pChainer->pData->hrInternalError;
206 }
207
208 ::ReleaseMutex(pChainer->hMutex);
209
210 return hr;
211}
212
213static HRESULT OnNetFxFilesInUse(
214 __in NetFxChainer* pNetfxChainer,
215 __in NetFxCloseApplications* pCloseApps,
216 __in PFN_GENERICMESSAGEHANDLER pfnMessageHandler,
217 __in LPVOID pvContext
218 )
219{
220 HRESULT hr = S_OK;
221 DWORD cFiles = 0;
222 LPWSTR* rgwzFiles = NULL;
223 GENERIC_EXECUTE_MESSAGE message = { };
224 DWORD dwResponse = 0;
225
226 cFiles = pCloseApps->dwApplicationsSize;
227 rgwzFiles = (LPWSTR*)MemAlloc(sizeof(LPWSTR*) * cFiles, TRUE);
228 ExitOnNull(rgwzFiles, hr, E_OUTOFMEMORY, "Failed to allocate buffer.");
229
230 for (DWORD i = 0; i < pCloseApps->dwApplicationsSize; ++i)
231 {
232 rgwzFiles[i] = pCloseApps->applications[i].szName;
233 }
234
235 // send message
236 message.type = GENERIC_EXECUTE_MESSAGE_FILES_IN_USE;
237 message.dwAllowedResults = MB_ABORTRETRYIGNORE;
238 message.filesInUse.cFiles = cFiles;
239 message.filesInUse.rgwzFiles = (LPCWSTR*)rgwzFiles;
240 dwResponse = (DWORD)pfnMessageHandler(&message, pvContext);
241
242 NetFxRespond(pNetfxChainer, dwResponse);
243
244LExit:
245 ReleaseMem(rgwzFiles);
246
247 return hr;
248}
249
250static HRESULT OnNetFxProgress(
251 __in NetFxChainer* pNetfxChainer,
252 __in BYTE bProgress,
253 __in PFN_GENERICMESSAGEHANDLER pfnMessageHandler,
254 __in LPVOID pvContext
255 )
256{
257 GENERIC_EXECUTE_MESSAGE message = { };
258 DWORD dwResponse = 0;
259
260 // send message
261 message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS;
262 message.dwAllowedResults = MB_OKCANCEL;
263 message.progress.dwPercentage = 100 * (DWORD)bProgress / BYTE_MAX;
264 dwResponse = (DWORD)pfnMessageHandler(&message, pvContext);
265
266 if (IDCANCEL == dwResponse)
267 {
268 NetFxAbort(pNetfxChainer);
269 }
270
271 return S_OK;
272}
273
274static HRESULT OnNetFxError(
275 __in NetFxChainer* /*pNetfxChainer*/,
276 __in HRESULT hrError,
277 __in PFN_GENERICMESSAGEHANDLER pfnMessageHandler,
278 __in LPVOID pvContext
279 )
280{
281 GENERIC_EXECUTE_MESSAGE message = { };
282 DWORD dwResponse = 0;
283
284 // send message
285 message.type = GENERIC_EXECUTE_MESSAGE_ERROR;
286 message.dwAllowedResults = MB_OK;
287 message.error.dwErrorCode = hrError;
288 message.error.wzMessage = NULL;
289 dwResponse = (DWORD)pfnMessageHandler(&message, pvContext);
290
291 return S_OK;
292}
293
294static HRESULT ProcessNetFxMessage(
295 __in NetFxChainer* pNetfxChainer,
296 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler,
297 __in LPVOID pvContext
298 )
299{
300 HRESULT hr = S_OK;
301 DWORD dwMessage = NETFX_NO_MESSAGE;
302 DWORD dwBufferSize = 0;
303 LPVOID pBuffer = NULL;
304
305 // send progress
306 hr = OnNetFxProgress(pNetfxChainer, NetFxGetProgress(pNetfxChainer), pfnGenericMessageHandler, pvContext);
307 ExitOnFailure(hr, "Failed to send progress from netfx chainer.");
308
309 // Check for message
310 hr = NetFxGetMessage(pNetfxChainer, &dwMessage, &pBuffer, &dwBufferSize);
311 ExitOnFailure(hr, "Failed to get message from netfx chainer.");
312
313 switch(dwMessage)
314 {
315 case NETFX_CLOSE_APPS:
316 hr = OnNetFxFilesInUse(pNetfxChainer, (NetFxCloseApplications*)pBuffer, pfnGenericMessageHandler, pvContext);
317 ExitOnFailure(hr, "Failed to send files in use message from netfx chainer.");
318 break;
319
320 default:
321 // No message we understand.
322 break;
323 }
324
325LExit:
326 ReleaseMem(pBuffer);
327
328 return hr;
329}
330
331extern "C" HRESULT NetFxRunChainer(
332 __in LPCWSTR wzExecutablePath,
333 __in LPCWSTR wzArguments,
334 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler,
335 __in LPVOID pvContext,
336 __out DWORD* pdwExitCode
337 )
338{
339 HRESULT hr = S_OK;
340 DWORD er = 0;
341 WCHAR wzGuid[GUID_STRING_LENGTH];
342 LPWSTR sczEventName = NULL;
343 LPWSTR sczSectionName = NULL;
344 LPWSTR sczCommand = NULL;
345 NetFxChainer* pNetfxChainer = NULL;
346 STARTUPINFOW si = { };
347 PROCESS_INFORMATION pi = { };
348 HRESULT hrInternalError = 0;
349
350 // Create the unique name suffix.
351 hr = GuidFixedCreate(wzGuid);
352 ExitOnRootFailure(hr, "Failed to create netfx chainer guid.");
353
354 hr = StrAllocFormatted(&sczSectionName, L"NetFxSection.%ls", wzGuid);
355 ExitOnFailure(hr, "Failed to allocate section name.");
356
357 hr = StrAllocFormatted(&sczEventName, L"NetFxEvent.%ls", wzGuid);
358 ExitOnFailure(hr, "Failed to allocate event name.");
359
360 hr = CreateNetFxChainer(sczSectionName, sczEventName, &pNetfxChainer);
361 ExitOnFailure(hr, "Failed to create netfx chainer.");
362
363 hr = StrAllocFormattedSecure(&sczCommand, L"%ls /pipe %ls", wzArguments, sczSectionName);
364 ExitOnFailure(hr, "Failed to allocate netfx chainer arguments.");
365
366 si.cb = sizeof(si);
367 if (!::CreateProcessW(wzExecutablePath, sczCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
368 {
369 ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", wzExecutablePath);
370 }
371
372 HANDLE handles[2] = { pi.hProcess, pNetfxChainer->hEventChaineeSend };
373
374 for (;;)
375 {
376 er = ::WaitForMultipleObjects(2, handles, FALSE, 100);
377 if (WAIT_OBJECT_0 == er)
378 {
379 // Process has exited
380 *pdwExitCode = NetFxGetResult(pNetfxChainer, &hrInternalError);
381 if (E_PENDING == *pdwExitCode)
382 {
383 if (!::GetExitCodeProcess(pi.hProcess, pdwExitCode))
384 {
385 ExitWithLastError(hr, "Failed to get netfx return code.");
386 }
387 }
388 else if (FAILED(hrInternalError))
389 {
390 // push internal error message
391 OnNetFxError(pNetfxChainer, hrInternalError, pfnGenericMessageHandler, pvContext);
392 ExitOnFailure(hr, "Failed to send internal error message from netfx chainer.");
393 }
394
395 break;
396 }
397 else if (WAIT_OBJECT_0 + 1 == er)
398 {
399 // Chainee has notified us of a change.
400 hr = ProcessNetFxMessage(pNetfxChainer, pfnGenericMessageHandler, pvContext);
401 ExitOnFailure(hr, "Failed to process netfx chainer message.");
402 }
403 else if (WAIT_FAILED == er)
404 {
405 ExitWithLastError(hr, "Failed to wait for netfx chainer process to complete");
406 }
407 }
408
409LExit:
410 ReleaseStr(sczSectionName);
411 ReleaseStr(sczEventName);
412 StrSecureZeroFreeString(sczCommand);
413 DestroyNetFxChainer(pNetfxChainer);
414 ReleaseHandle(pi.hThread);
415 ReleaseHandle(pi.hProcess);
416
417 return hr;
418}