main
cpp 427 lines 12.9 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 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_NETFX_FILES_IN_USE;
237 message.dwUIHint = 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.dwUIHint = 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.dwUIHint = 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_z LPCWSTR wzExecutablePath,
333 __in_z LPWSTR sczBaseCommand,
334 __in_z_opt LPCWSTR wzUserArgs,
335 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler,
336 __in LPVOID pvContext,
337 __out DWORD* pdwExitCode
338 )
339 {
340 HRESULT hr = S_OK;
341 DWORD dwSignaledIndex = 0;
342 BOOL fTimedOut = 0;
343 WCHAR wzGuid[GUID_STRING_LENGTH];
344 LPWSTR sczEventName = NULL;
345 LPWSTR sczSectionName = NULL;
346 LPWSTR sczCommand = NULL;
347 NetFxChainer* pNetfxChainer = NULL;
348 PROCESS_INFORMATION pi = { };
349 HRESULT hrInternalError = 0;
350
351 // Create the unique name suffix.
352 hr = GuidFixedCreate(wzGuid);
353 ExitOnRootFailure(hr, "Failed to create netfx chainer guid.");
354
355 hr = StrAllocFormatted(&sczSectionName, L"NetFxSection.%ls", wzGuid);
356 ExitOnFailure(hr, "Failed to allocate section name.");
357
358 hr = StrAllocFormatted(&sczEventName, L"NetFxEvent.%ls", wzGuid);
359 ExitOnFailure(hr, "Failed to allocate event name.");
360
361 hr = CreateNetFxChainer(sczSectionName, sczEventName, &pNetfxChainer);
362 ExitOnFailure(hr, "Failed to create netfx chainer.");
363
364 hr = StrAllocFormatted(&sczCommand, L"%ls /pipe %ls", sczBaseCommand, sczSectionName);
365 ExitOnFailure(hr, "Failed to append netfx chainer args.");
366
367 // Always add user supplied arguments last.
368 if (wzUserArgs)
369 {
370 hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", wzUserArgs);
371 ExitOnFailure(hr, "Failed to append user args.");
372 }
373
374 hr = CoreCreateProcess(wzExecutablePath, sczCommand, FALSE, CREATE_NO_WINDOW, NULL, 0, &pi);
375 ExitOnFailure(hr, "Failed to CreateProcess on path: %ls", wzExecutablePath);
376
377 HANDLE handles[2] = { pi.hProcess, pNetfxChainer->hEventChaineeSend };
378
379 for (;;)
380 {
381 hr = AppWaitForMultipleObjects(2, handles, FALSE, 100, &dwSignaledIndex);
382 ExitOnWaitObjectFailure(hr, fTimedOut, "Failed to wait for netfx chainer process to complete");
383
384 if (fTimedOut)
385 {
386 continue;
387 }
388
389 switch (dwSignaledIndex)
390 {
391 case 0:
392 // Process has exited
393 *pdwExitCode = NetFxGetResult(pNetfxChainer, &hrInternalError);
394 if (E_PENDING == *pdwExitCode)
395 {
396 if (!::GetExitCodeProcess(pi.hProcess, pdwExitCode))
397 {
398 ExitWithLastError(hr, "Failed to get netfx return code.");
399 }
400 }
401 else if (FAILED(hrInternalError))
402 {
403 // push internal error message
404 hr = OnNetFxError(pNetfxChainer, hrInternalError, pfnGenericMessageHandler, pvContext);
405 ExitOnFailure(hr, "Failed to send internal error message from netfx chainer.");
406 }
407
408 ExitFunction();
409 case 1:
410 // Chainee has notified us of a change.
411 hr = ProcessNetFxMessage(pNetfxChainer, pfnGenericMessageHandler, pvContext);
412 ExitOnFailure(hr, "Failed to process netfx chainer message.");
413
414 break;
415 }
416 }
417
418 LExit:
419 ReleaseStr(sczSectionName);
420 ReleaseStr(sczEventName);
421 StrSecureZeroFreeString(sczCommand);
422 DestroyNetFxChainer(pNetfxChainer);
423 ReleaseHandle(pi.hThread);
424 ReleaseHandle(pi.hProcess);
425
426 return hr;
427 }