diff options
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 | } | ||
