diff options
author | Rob Mensching <rob@firegiant.com> | 2021-04-22 17:06:54 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2021-04-29 16:36:06 -0700 |
commit | af10c45d7b3a44af0b461a557847fe03263dcc10 (patch) | |
tree | 6a5c1532304782c36ffe4200b38f3afb76789a43 /src/burn/engine/netfxchainer.cpp | |
parent | 9c2aed97299fb96aeee3f1471ce40225437aaecf (diff) | |
download | wix-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.cpp | 418 |
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 | |||
5 | static 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 | |||
25 | static 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 | |||
92 | LExit: | ||
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 | |||
110 | static 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 | |||
124 | static 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 | |||
138 | static 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 | |||
161 | LExit: | ||
162 | ::ReleaseMutex(pChainer->hMutex); | ||
163 | |||
164 | return hr; | ||
165 | } | ||
166 | |||
167 | static 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 | |||
187 | static 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 | |||
213 | static 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 | |||
244 | LExit: | ||
245 | ReleaseMem(rgwzFiles); | ||
246 | |||
247 | return hr; | ||
248 | } | ||
249 | |||
250 | static 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 | |||
274 | static 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 | |||
294 | static 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 | |||
325 | LExit: | ||
326 | ReleaseMem(pBuffer); | ||
327 | |||
328 | return hr; | ||
329 | } | ||
330 | |||
331 | extern "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 | |||
409 | LExit: | ||
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 | } | ||