extern "C" HRESULT DisplayStart( __in HINSTANCE hInstance, __in HWND hWnd, __out HANDLE *phThread, __out DWORD* pdwThreadId ) { HRESULT hr = S_OK; HANDLE rgHandles[2] = { }; DISPLAY_THREAD_CONTEXT context = { }; rgHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL); ExitOnNullWithLastError(rgHandles[0], hr, "Failed to create load init event."); context.hWnd = hWnd; context.hInstance = hInstance; context.hInit = rgHandles[0]; rgHandles[1] = ::CreateThread(NULL, 0, DisplayThreadProc, reinterpret_cast<LPVOID>(&context), 0, pdwThreadId); ExitOnNullWithLastError(rgHandles[1], hr, "Failed to create display thread."); ::WaitForMultipleObjects(countof(rgHandles), rgHandles, FALSE, INFINITE); *phThread = rgHandles[1]; rgHandles[1] = NULL; LExit: ReleaseHandle(rgHandles[1]); ReleaseHandle(rgHandles[0]); return hr; }
static HRESULT CreateMessageWindow( __out HWND* phWnd ) { HRESULT hr = S_OK; HANDLE rgWaitHandles[2] = { }; UITHREAD_CONTEXT context = { }; // Create event to signal after the UI thread / window is initialized. rgWaitHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL); ExitOnNullWithLastError(rgWaitHandles[0], hr, "Failed to create initialization event."); // Pass necessary information to create the window. context.hInitializedEvent = rgWaitHandles[0]; context.hInstance = (HINSTANCE)g_hInstCADLL; // Create our separate UI thread. rgWaitHandles[1] = ::CreateThread(NULL, 0, ThreadProc, &context, 0, NULL); ExitOnNullWithLastError(rgWaitHandles[1], hr, "Failed to create the UI thread."); // Wait for either the thread to be initialized or the window to exit / fail prematurely. ::WaitForMultipleObjects(countof(rgWaitHandles), rgWaitHandles, FALSE, INFINITE); // Pass the window back to the caller. *phWnd = context.hWnd; LExit: ReleaseHandle(rgWaitHandles[1]); ReleaseHandle(rgWaitHandles[0]); return hr; }
void CALLBACK my_InternetStatusCallback(HINTERNET hRequest, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength) { LPINTERNET_ASYNC_RESULT AsyncResult = (LPINTERNET_ASYNC_RESULT) lpvStatusInformation; INTERNET_STATUS_CALLBACK RealInetCallback; PHANDLE_CONTEXT Ctx; ENTER_HOOK(); if (Ctx = FindHandle(hRequest)) { switch (dwInternetStatus) { case INTERNET_STATUS_HANDLE_CLOSING: DelHandle(hRequest); break; case INTERNET_STATUS_REQUEST_COMPLETE: if (Ctx->Status == DOWNLOADING) { if (!AsyncResult->dwResult) Ctx->Status = ERROR_WHILE_LOADING; SetEvent(Ctx->AsyncEvent); ReleaseHandle(Ctx); LEAVE_HOOK(); return; } // if (Ctx->Status == DOWNLOADING) else { ULONG HttpStatus, bSize = sizeof(ULONG); if (HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, &HttpStatus, &bSize, &bSize)) { if (HttpStatus == 1) { __debugbreak(); } } else bSize = GetLastError(); } break; default: break; } // switch (dwInternetStatus) if (RealInetCallback = Ctx->Callback) { ASSERT((LONG_PTR)Ctx->Callback > 0); // User-mode address (RealInetCallback) (hRequest, dwContext, dwInternetStatus, lpvStatusInformation, dwStatusInformationLength); } ReleaseHandle(Ctx); } // if (Ctx = FindHandle(hInternet)) LEAVE_HOOK(); }
// // Common routine for InternetReadFileExA and InternetReadFileExW hooks. // static BOOL CommonInternetReadFileEx( HINTERNET hFile, LPINTERNET_BUFFERS lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext, BOOL IsUnicode ) { BOOL Ret = FALSE; PHANDLE_CONTEXT Ctx; if (Ctx = IeGetContext(hFile)) { do // not a loop { GetPageContent(Ctx, hFile); lpBuffersOut->dwBufferTotal = lpBuffersOut->dwBufferLength; if (CoInvoke(Ctx->pStream, Read, lpBuffersOut->lpvBuffer, lpBuffersOut->dwBufferLength, &lpBuffersOut->dwBufferLength) == S_OK) Ret = TRUE; } while(FALSE); ReleaseHandle(Ctx); } else { if (IsUnicode) Ret = InternetReadFileExW(hFile, (LPINTERNET_BUFFERSW)lpBuffersOut, dwFlags, dwContext); else Ret = InternetReadFileExA(hFile, lpBuffersOut, dwFlags, dwContext); } return(Ret); }
/******************************************************************* PipeLaunchChildProcess - Called from the per-user process to create the per-machine process and set up the communication pipe. *******************************************************************/ extern "C" HRESULT PipeLaunchChildProcess( __in_z LPCWSTR wzExecutablePath, __in BURN_PIPE_CONNECTION* pConnection, __in BOOL fElevate, __in_opt HWND hwndParent ) { HRESULT hr = S_OK; DWORD dwCurrentProcessId = ::GetCurrentProcessId(); LPWSTR sczParameters = NULL; OS_VERSION osVersion = OS_VERSION_UNKNOWN; DWORD dwServicePack = 0; LPCWSTR wzVerb = NULL; HANDLE hProcess = NULL; hr = StrAllocFormatted(&sczParameters, L"-q -%ls %ls %ls %u", BURN_COMMANDLINE_SWITCH_ELEVATED, pConnection->sczName, pConnection->sczSecret, dwCurrentProcessId); ExitOnFailure(hr, "Failed to allocate parameters for elevated process."); OsGetVersion(&osVersion, &dwServicePack); wzVerb = (OS_VERSION_VISTA > osVersion) || !fElevate ? L"open" : L"runas"; hr = ShelExec(wzExecutablePath, sczParameters, wzVerb, NULL, SW_HIDE, hwndParent, &hProcess); ExitOnFailure(hr, "Failed to launch elevated child process: %ls", wzExecutablePath); pConnection->dwProcessId = ::GetProcessId(hProcess); pConnection->hProcess = hProcess; hProcess = NULL; LExit: ReleaseHandle(hProcess); ReleaseStr(sczParameters); return hr; }
BOOL WINAPI my_InternetQueryDataAvailable(HINTERNET hFile, LPDWORD lpdwNumberOfBytesAvailable, DWORD dwFlags, DWORD_PTR dwContext) { BOOL Ret = FALSE; PHANDLE_CONTEXT Ctx; ENTER_HOOK(); *lpdwNumberOfBytesAvailable = 0; if (Ctx = IeGetContext(hFile)) { do // not a loop { ULONG Pos; ULONG Length; GetPageContent(Ctx, hFile); Pos = StreamGetPos(Ctx->pStream); Length = StreamGetLength(Ctx->pStream); *lpdwNumberOfBytesAvailable = Length - Pos; Ret = TRUE; } while(FALSE); ReleaseHandle(Ctx); } else Ret = InternetQueryDataAvailable( hFile, lpdwNumberOfBytesAvailable, dwFlags, dwContext); LEAVE_HOOK(); return(Ret); }
LONG PRIO_Poll( PRPollDesc *pds, LONG npds ) { LONG i, Count = 0; for(i=0; i<npds; i++) { if (pds[i].in_flags & PR_POLL_READ) { PHANDLE_CONTEXT Ctx; if (Ctx = FindHandle(pds[i].fd)) { if (StreamGetLength(Ctx->pStream)) { pds[Count].fd = pds[i].fd; pds[Count].in_flags = pds[i].in_flags; pds[Count].out_flags = PR_POLL_READ; Count += 1; } ReleaseHandle(Ctx); } // if (Ctx = FindHandle(pds[i]->fd)) } // if (pds[i]->in_flags & PR_POLL_READ) } // for(i=0; i<npds; i++) return(Count); }
VOID TaskMgrSS::ReleaseHandles( TASKSETHANDLE *phSet,UINT uSet ) { for( UINT uIdx = 0; uIdx < uSet; ++uIdx ) { ReleaseHandle( phSet[ uIdx ] ); } }
static HRESULT RunRunOnce( __in const BURN_REGISTRATION* pRegistration, __in int nCmdShow ) { HRESULT hr = S_OK; LPWSTR sczNewCommandLine = NULL; LPWSTR sczBurnPath = NULL; HANDLE hProcess = NULL; hr = RegistrationGetResumeCommandLine(pRegistration, &sczNewCommandLine); ExitOnFailure(hr, "Unable to get resume command line from the registry"); // and re-launch hr = PathForCurrentProcess(&sczBurnPath, NULL); ExitOnFailure(hr, "Failed to get current process path."); hr = ProcExec(sczBurnPath, 0 < sczNewCommandLine ? sczNewCommandLine : L"", nCmdShow, &hProcess); ExitOnFailure(hr, "Failed to re-launch bundle process after RunOnce: %ls", sczBurnPath); LExit: ReleaseHandle(hProcess); ReleaseStr(sczNewCommandLine); ReleaseStr(sczBurnPath); return hr; }
static VOID DestroyNetFxChainer( __in NetFxChainer* pChainer ) { if (pChainer) { ReleaseHandle(pChainer->hSection); ReleaseHandle(pChainer->hEventChaineeSend); ReleaseHandle(pChainer->hEventChainerSend); ReleaseHandle(pChainer->hMutex); if (pChainer->pData) { ::UnmapViewOfFile(pChainer->pData); } MemFree(pChainer); } }
HRESULT PipeLaunchParentProcess( __in_z LPCWSTR wzCommandLine, __in int nCmdShow, __in_z LPWSTR sczConnectionName, __in_z LPWSTR sczSecret, __in BOOL /*fDisableUnelevate*/ ) { HRESULT hr = S_OK; DWORD dwProcessId = 0; LPWSTR sczBurnPath = NULL; LPWSTR sczParameters = NULL; HANDLE hProcess = NULL; dwProcessId = ::GetCurrentProcessId(); hr = PathForCurrentProcess(&sczBurnPath, NULL); ExitOnFailure(hr, "Failed to get current process path."); hr = StrAllocFormatted(&sczParameters, L"-%ls %ls %ls %u %ls", BURN_COMMANDLINE_SWITCH_UNELEVATED, sczConnectionName, sczSecret, dwProcessId, wzCommandLine); ExitOnFailure(hr, "Failed to allocate parameters for unelevated process."); #ifdef ENABLE_UNELEVATE if (fDisableUnelevate) { hr = ProcExec(sczBurnPath, sczParameters, nCmdShow, &hProcess); ExitOnFailure1(hr, "Failed to launch parent process with unelevate disabled: %ls", sczBurnPath); } else { // Try to launch unelevated and if that fails for any reason, try launch our process normally (even though that may make it elevated). hr = ProcExecuteAsInteractiveUser(sczBurnPath, sczParameters, &hProcess); if (FAILED(hr)) { hr = ShelExecUnelevated(sczBurnPath, sczParameters, L"open", NULL, nCmdShow); if (FAILED(hr)) { hr = ShelExec(sczBurnPath, sczParameters, L"open", NULL, nCmdShow, NULL, NULL); ExitOnFailure1(hr, "Failed to launch parent process: %ls", sczBurnPath); } } } #else hr = ProcExec(sczBurnPath, sczParameters, nCmdShow, &hProcess); ExitOnFailure1(hr, "Failed to launch parent process with unelevate disabled: %ls", sczBurnPath); #endif LExit: ReleaseHandle(hProcess); ReleaseStr(sczParameters); ReleaseStr(sczBurnPath); return hr; }
/******************************************************************* PipeConnectionUninitialize - free data in a pipe connection. *******************************************************************/ void PipeConnectionUninitialize( __in BURN_PIPE_CONNECTION* pConnection ) { ReleaseFileHandle(pConnection->hCachePipe); ReleaseFileHandle(pConnection->hPipe); ReleaseHandle(pConnection->hProcess); ReleaseStr(pConnection->sczSecret); ReleaseStr(pConnection->sczName); memset(pConnection, 0, sizeof(BURN_PIPE_CONNECTION)); pConnection->hPipe = INVALID_HANDLE_VALUE; pConnection->hCachePipe = INVALID_HANDLE_VALUE; }
extern "C" HRESULT LoadStart( __in_z LPCWSTR wzThemePath, __in HWND hWnd, __out HANDLE* phThread ) { HRESULT hr = S_OK; HANDLE rgHandles[2] = { }; LPWSTR sczThemePath = NULL; LOAD_THREAD_CONTEXT context = { }; rgHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL); ExitOnNullWithLastError(rgHandles[0], hr, "Failed to create load init event."); hr = StrAllocString(&sczThemePath, wzThemePath, 0); ExitOnFailure(hr, "Failed to copy path to initial theme file."); context.hWnd = hWnd; context.sczThemePath = sczThemePath; context.hInit = rgHandles[0]; rgHandles[1] = ::CreateThread(NULL, 0, LoadThreadProc, &context, 0, NULL); ExitOnNullWithLastError(rgHandles[1], hr, "Failed to create load thread."); ::WaitForMultipleObjects(countof(rgHandles), rgHandles, FALSE, INFINITE); *phThread = rgHandles[1]; rgHandles[1] = NULL; sczThemePath = NULL; LExit: ReleaseHandle(rgHandles[1]); ReleaseHandle(rgHandles[0]); ReleaseStr(sczThemePath); return hr; }
VOID TaskMgrSS::CompleteTaskSet( TASKSETHANDLE hSet ) { TaskSet* pSet = &mSets[ hSet ]; UINT uCount = _InterlockedDecrement( (LONG*)&pSet->muCompletionCount ); if( 0 == uCount ) { pSet->mbCompleted = TRUE; pSet->mpFunc = 0; // // The task set has completed. We need to look at the successors // and signal them that this dependency of theirs has completed. // pSet->mSuccessorsLock.aquire(); for( UINT uSuccessor = 0; uSuccessor < MAX_SUCCESSORS; ++uSuccessor ) { TaskSet* pSuccessor = pSet->Successors[ uSuccessor ]; // // A signaled successor must be removed from the Successors list // before the mSuccessorsLock can be released. // pSet->Successors[ uSuccessor ] = NULL; if( NULL != pSuccessor ) { UINT uStart; uStart = _InterlockedDecrement( (LONG*)&pSuccessor->muStartCount ); // // If the start count is 0 the successor has had all its // dependencies satisified and can be scheduled. // if( 0 == uStart ) { mTaskScheduler.AddTaskSet( pSuccessor->mhTaskset, pSuccessor->muSize ); } } } pSet->mSuccessorsLock.release(); ReleaseHandle( hSet ); } }
static HRESULT Restart() { HRESULT hr = S_OK; HANDLE hProcessToken = NULL; TOKEN_PRIVILEGES priv = { }; DWORD dwRetries = 0; if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hProcessToken)) { ExitWithLastError(hr, "Failed to get process token."); } priv.PrivilegeCount = 1; priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!::LookupPrivilegeValueW(NULL, L"SeShutdownPrivilege", &priv.Privileges[0].Luid)) { ExitWithLastError(hr, "Failed to get shutdown privilege LUID."); } if (!::AdjustTokenPrivileges(hProcessToken, FALSE, &priv, sizeof(TOKEN_PRIVILEGES), NULL, 0)) { ExitWithLastError(hr, "Failed to adjust token to add shutdown privileges."); } do { hr = S_OK; // Wait a second to let the companion process (assuming we did an elevated install) to get to the // point where it too is thinking about restarting the computer. Only one will schedule the restart // but both will have their log files closed and otherwise be ready to exit. // // On retry, we'll also wait a second to let the OS try to get to a place where the restart can // be initiated. ::Sleep(1000); if (!vpfnInitiateSystemShutdownExW(NULL, NULL, 0, FALSE, TRUE, SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED)) { hr = HRESULT_FROM_WIN32(::GetLastError()); } } while (dwRetries++ < RESTART_RETRIES && (HRESULT_FROM_WIN32(ERROR_MACHINE_LOCKED) == hr || HRESULT_FROM_WIN32(ERROR_NOT_READY) == hr)); ExitOnRootFailure(hr, "Failed to schedule restart."); LExit: ReleaseHandle(hProcessToken); return hr; }
static HRESULT RunRunOnce( __in_z_opt LPCWSTR wzCommandLine, __in int nCmdShow ) { HRESULT hr = S_OK; LPWSTR sczNewCommandLine = NULL; LPWSTR sczBurnPath = NULL; HANDLE hProcess = NULL; int argc = 0; LPWSTR* argv = NULL; // rebuild the command line without the runonce switch if (wzCommandLine && *wzCommandLine) { argv = ::CommandLineToArgvW(wzCommandLine, &argc); ExitOnNullWithLastError(argv, hr, "Failed to get command line."); for (int i = 0; i < argc; ++i) { if (!((argv[i][0] == L'-' || argv[i][0] == L'/') && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RUNONCE, -1))) { PathCommandLineAppend(&sczNewCommandLine, argv[i]); } } } // and re-launch hr = PathForCurrentProcess(&sczBurnPath, NULL); ExitOnFailure(hr, "Failed to get current process path."); hr = ProcExec(sczBurnPath, 0 < sczNewCommandLine ? sczNewCommandLine : L"", nCmdShow, &hProcess); ExitOnFailure1(hr, "Failed to re-launch bundle process after RunOnce: %ls", sczBurnPath); LExit: if (argv) { ::LocalFree(argv); } ReleaseHandle(hProcess); ReleaseStr(sczNewCommandLine); ReleaseStr(sczBurnPath); return hr; }
// // Performs handle check and returns handle-associated context. // static PHANDLE_CONTEXT IeGetContext(HANDLE hRequest) { PHANDLE_CONTEXT Ctx = NULL; if (Ctx = FindHandle(hRequest)) { if (!(Ctx->Flags & (CF_SKIP | CF_CONTENT))) { Ctx->Flags |= CF_SKIP; // Checking content type if ((Ctx->Flags & CF_REPLACE) || IeCheckContentType(hRequest)) { ULONG bLen = 0; ASSERT(Ctx->Url == NULL); // Querying the URL InternetQueryOption(hRequest, INTERNET_OPTION_URL, NULL, &bLen); if ((bLen) && (Ctx->Url = hAlloc(bLen + sizeof(_TCHAR)))) { if (InternetQueryOption(hRequest, INTERNET_OPTION_URL, Ctx->Url, &bLen)) { Ctx->Url[bLen] = 0; Ctx->Flags |= CF_CONTENT; Ctx->Flags ^= CF_SKIP; } else { hFree(Ctx->Url); Ctx->Url = NULL; } } // if ((bLen) && (Ctx->Url = hAlloc(bLen + sizeof(_TCHAR)))) } // if (IeCheckContentType(hFile)) } // if (!(Ctx->Flags & (CF_SKIP | CF_CONTENT))) if (Ctx->Flags & CF_SKIP) { ReleaseHandle(Ctx); Ctx = NULL; } } // if (Ctx = FindHandle(hFile)) return(Ctx); }
static void UninitializeEngineState( __in BURN_ENGINE_STATE* pEngineState ) { ReleaseStr(pEngineState->sczIgnoreDependencies); PipeConnectionUninitialize(&pEngineState->embeddedConnection); PipeConnectionUninitialize(&pEngineState->companionConnection); ReleaseStr(pEngineState->sczBundleEngineWorkingPath) ReleaseHandle(pEngineState->hMessageWindowThread); ::DeleteCriticalSection(&pEngineState->userExperience.csEngineActive); UserExperienceUninitialize(&pEngineState->userExperience); ApprovedExesUninitialize(&pEngineState->approvedExes); UpdateUninitialize(&pEngineState->update); VariablesUninitialize(&pEngineState->variables); SearchesUninitialize(&pEngineState->searches); RegistrationUninitialize(&pEngineState->registration); PayloadsUninitialize(&pEngineState->payloads); PackagesUninitialize(&pEngineState->packages); CatalogUninitialize(&pEngineState->catalogs); SectionUninitialize(&pEngineState->section); ContainersUninitialize(&pEngineState->containers); ReleaseStr(pEngineState->command.wzLayoutDirectory); ReleaseStr(pEngineState->command.wzCommandLine); ReleaseStr(pEngineState->log.sczExtension); ReleaseStr(pEngineState->log.sczPrefix); ReleaseStr(pEngineState->log.sczPath); ReleaseStr(pEngineState->log.sczPathVariable); if (TLS_OUT_OF_INDEXES != pEngineState->dwElevatedLoggingTlsId) { ::TlsFree(pEngineState->dwElevatedLoggingTlsId); } ::DeleteCriticalSection(&pEngineState->csActive); // clear struct memset(pEngineState, 0, sizeof(BURN_ENGINE_STATE)); }
extern "C" void CatalogUninitialize( __in BURN_CATALOGS* pCatalogs ) { if (pCatalogs->rgCatalogs) { for (DWORD i = 0; i < pCatalogs->cCatalogs; ++i) { BURN_CATALOG* pCatalog = &pCatalogs->rgCatalogs[i]; ReleaseHandle(pCatalog->hFile); ReleaseStr(pCatalog->sczKey); ReleaseStr(pCatalog->sczLocalFilePath); ReleaseStr(pCatalog->sczPayload); } MemFree(pCatalogs->rgCatalogs); } // clear struct memset(pCatalogs, 0, sizeof(BURN_CATALOGS)); }
BOOL WINAPI my_HttpSendRequestW(HINTERNET hRequest, LPWSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength) { BOOL Ret = FALSE; LPWSTR NewHeaders; LPSTR pHeaders = NULL; WINERROR Error; PHANDLE_CONTEXT Ctx = NULL; ENTER_HOOK(); if (NewHeaders = IeCreateContextModifyHeadersW(hRequest, lpszHeaders, dwHeadersLength, &pHeaders, &Ctx)) lpszHeaders = NewHeaders; if (Ctx && Ctx->Status == REQUEST_BLOCKED) { ReleaseHandle(Ctx); Error = ERROR_INTERNET_CANNOT_CONNECT; } else { if ((dwOptionalLength) && (lpOptional)) IeQueryUrlPostForms(hRequest, pHeaders, lpOptional, dwOptionalLength); Ret = HttpSendRequestW(hRequest, lpszHeaders, dwHeadersLength, lpOptional, dwOptionalLength); Error = GetLastError(); } if (NewHeaders) hFree(NewHeaders); if (pHeaders) hFree(pHeaders); SetLastError(Error); LEAVE_HOOK(); return(Ret); }
/******************************************************************** ShelExec() - executes a target. *******************************************************************/ extern "C" HRESULT DAPI ShelExec( __in_z LPCWSTR wzTargetPath, __in_z_opt LPCWSTR wzParameters, __in_z_opt LPCWSTR wzVerb, __in_z_opt LPCWSTR wzWorkingDirectory, __in int nShowCmd, __in_opt HWND hwndParent, __out_opt HANDLE* phProcess ) { HRESULT hr = S_OK; SHELLEXECUTEINFOW shExecInfo = {}; shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); shExecInfo.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS; shExecInfo.hwnd = hwndParent; shExecInfo.lpVerb = wzVerb; shExecInfo.lpFile = wzTargetPath; shExecInfo.lpParameters = wzParameters; shExecInfo.lpDirectory = wzWorkingDirectory; shExecInfo.nShow = nShowCmd; if (!vpfnShellExecuteExW(&shExecInfo)) { ExitWithLastError1(hr, "ShellExecEx failed with return code: %d", Dutil_er); } if (phProcess) { *phProcess = shExecInfo.hProcess; shExecInfo.hProcess = NULL; } LExit: ReleaseHandle(shExecInfo.hProcess); return hr; }
// // This function used for full page replace. The idea is to redirect querying any infromation from the source page // HTTTP headers to the result page HTTP headers. // static BOOL HttpQueryInfoCommon( HINTERNET hRequest, DWORD dwInfoLevel, LPVOID lpvBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex, BOOL bUnicode ) { BOOL Ret = FALSE; PHANDLE_CONTEXT Ctx; if (Ctx = FindHandle(hRequest)) { // Checking if the page will be replaced if (Ctx->Flags & CF_REPLACE) { PTRANSFER_CONTEXT tCtx = (PTRANSFER_CONTEXT)Ctx->tCtx; DbgPrint("ISFB_%04x: HttpQueryInfo replace, dwInfoLevel = %u\n", g_CurrentProcessId, dwInfoLevel); // Copmlete loading of the page to replace with if ((tCtx) && ((tCtx->Headers) || (TransferCompleteReceive(tCtx, TRUE) == NO_ERROR))) // Replacing request handle hRequest = tCtx->hRequest; } // if (Ctx->Flags & CF_REPLACE) ReleaseHandle(Ctx); } // if (Ctx = FindHandle(hRequest)) if (bUnicode) Ret = HttpQueryInfoW(hRequest, dwInfoLevel, lpvBuffer, lpdwBufferLength, lpdwIndex); else Ret = HttpQueryInfoA(hRequest, dwInfoLevel, lpvBuffer, lpdwBufferLength, lpdwIndex); return(Ret); }
BOOL WINAPI my_InternetReadFile(HINTERNET hFile, LPVOID lpBuffer, DWORD dwNumberOfBytesToRead, LPDWORD lpdwNumberOfBytesRead) { BOOL Ret = FALSE; PHANDLE_CONTEXT Ctx = NULL; ENTER_HOOK(); *lpdwNumberOfBytesRead = 0; if (Ctx = IeGetContext(hFile)) { GetPageContent(Ctx, hFile); if (CoInvoke(Ctx->pStream, Read, lpBuffer, dwNumberOfBytesToRead, lpdwNumberOfBytesRead) == S_OK) Ret = TRUE; ReleaseHandle(Ctx); } else Ret = InternetReadFile(hFile, lpBuffer, dwNumberOfBytesToRead, lpdwNumberOfBytesRead); LEAVE_HOOK(); return(Ret); }
/******************************************************************* PipeLaunchChildProcess - Called from the per-user process to create the per-machine process and set up the communication pipe. *******************************************************************/ extern "C" HRESULT PipeLaunchChildProcess( __in_z LPCWSTR wzExecutablePath, __in BURN_PIPE_CONNECTION* pConnection, __in BOOL fElevate, __in_opt HWND hwndParent ) { HRESULT hr = S_OK; DWORD dwCurrentProcessId = ::GetCurrentProcessId(); LPWSTR sczParameters = NULL; OS_VERSION osVersion = OS_VERSION_UNKNOWN; DWORD dwServicePack = 0; LPCWSTR wzVerb = NULL; HANDLE hProcess = NULL; hr = StrAllocFormatted(&sczParameters, L"-q -%ls %ls %ls %u", BURN_COMMANDLINE_SWITCH_ELEVATED, pConnection->sczName, pConnection->sczSecret, dwCurrentProcessId); ExitOnFailure(hr, "Failed to allocate parameters for elevated process."); OsGetVersion(&osVersion, &dwServicePack); wzVerb = (OS_VERSION_VISTA > osVersion) || !fElevate ? L"open" : L"runas"; // Since ShellExecuteEx doesn't support passing inherited handles, don't bother with CoreAppendFileHandleSelfToCommandLine. // We could fallback to using ::DuplicateHandle to inject the file handle later if necessary. hr = ShelExec(wzExecutablePath, sczParameters, wzVerb, NULL, SW_SHOWNA, hwndParent, &hProcess); ExitOnFailure(hr, "Failed to launch elevated child process: %ls", wzExecutablePath); pConnection->dwProcessId = ::GetProcessId(hProcess); pConnection->hProcess = hProcess; hProcess = NULL; LExit: ReleaseHandle(hProcess); ReleaseStr(sczParameters); return hr; }
/******************************************************************** ShelExec() - executes a target. *******************************************************************/ extern "C" HRESULT DAPI ShelExec( __in_z LPCWSTR wzTargetPath, __in_z_opt LPCWSTR wzParameters, __in_z_opt LPCWSTR wzVerb, __in_z_opt LPCWSTR wzWorkingDirectory, __in int nShowCmd, __in_opt HWND hwndParent, __out_opt HANDLE* phProcess ) { HRESULT hr = S_OK; SHELLEXECUTEINFOW shExecInfo = {}; shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); shExecInfo.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS; shExecInfo.hwnd = hwndParent; shExecInfo.lpVerb = wzVerb; shExecInfo.lpFile = wzTargetPath; shExecInfo.lpParameters = wzParameters; shExecInfo.lpDirectory = wzWorkingDirectory; shExecInfo.nShow = nShowCmd; if (!vpfnShellExecuteExW(&shExecInfo)) { switch (reinterpret_cast<DWORD_PTR>(shExecInfo.hInstApp)) { case SE_ERR_FNF: hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); break; case SE_ERR_PNF: hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); break; case ERROR_BAD_FORMAT: hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); break; case SE_ERR_ASSOCINCOMPLETE: case SE_ERR_NOASSOC: hr = HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION); break; case SE_ERR_DDEBUSY: __fallthrough; case SE_ERR_DDEFAIL: __fallthrough; case SE_ERR_DDETIMEOUT: hr = HRESULT_FROM_WIN32(ERROR_DDE_FAIL); break; case SE_ERR_DLLNOTFOUND: hr = HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND); break; case SE_ERR_OOM: hr = E_OUTOFMEMORY; break; case SE_ERR_ACCESSDENIED: hr = E_ACCESSDENIED; break; default: hr = E_FAIL; } ExitOnFailure1(hr, "ShellExecEx failed with return code %d", reinterpret_cast<DWORD_PTR>(shExecInfo.hInstApp)); } if (phProcess) { *phProcess = shExecInfo.hProcess; shExecInfo.hProcess = NULL; } LExit: ReleaseHandle(shExecInfo.hProcess); return hr; }
Shader::~Shader(void) { ReleaseHandle(); }
extern "C" HRESULT NetFxRunChainer( __in LPCWSTR wzExecutablePath, __in LPCWSTR wzArguments, __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, __in LPVOID pvContext, __out DWORD* pdwExitCode ) { HRESULT hr = S_OK; DWORD er = 0; UUID guid = { }; WCHAR wzGuid[39]; RPC_STATUS rs = RPC_S_OK; LPWSTR sczEventName = NULL; LPWSTR sczSectionName = NULL; LPWSTR sczCommand = NULL; NetFxChainer* pNetfxChainer = NULL; STARTUPINFOW si = { }; PROCESS_INFORMATION pi = { }; HRESULT hrInternalError = 0; // Create the unique name suffix. rs = ::UuidCreate(&guid); hr = HRESULT_FROM_RPC(rs); ExitOnFailure(hr, "Failed to create netfx chainer guid."); if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid))) { hr = E_OUTOFMEMORY; ExitOnRootFailure(hr, "Failed to convert netfx chainer guid into string."); } hr = StrAllocFormatted(&sczSectionName, L"NetFxSection.%ls", wzGuid); ExitOnFailure(hr, "Failed to allocate section name."); hr = StrAllocFormatted(&sczEventName, L"NetFxEvent.%ls", wzGuid); ExitOnFailure(hr, "Failed to allocate event name."); hr = CreateNetFxChainer(sczSectionName, sczEventName, &pNetfxChainer); ExitOnFailure(hr, "Failed to create netfx chainer."); hr = StrAllocFormatted(&sczCommand, L"%ls /pipe %ls", wzArguments, sczSectionName); ExitOnFailure(hr, "Failed to allocate netfx chainer arguments."); si.cb = sizeof(si); if (!::CreateProcessW(wzExecutablePath, sczCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { ExitWithLastError1(hr, "Failed to CreateProcess on path: %ls", wzExecutablePath); } HANDLE handles[2] = { pi.hProcess, pNetfxChainer->hEventChaineeSend }; for (;;) { er = ::WaitForMultipleObjects(2, handles, FALSE, 100); if (WAIT_OBJECT_0 == er) { // Process has exited *pdwExitCode = NetFxGetResult(pNetfxChainer, &hrInternalError); if (E_PENDING == *pdwExitCode) { if (!::GetExitCodeProcess(pi.hProcess, pdwExitCode)) { ExitWithLastError(hr, "Failed to get netfx return code."); } } else if (FAILED(hrInternalError)) { // push internal error message OnNetFxError(pNetfxChainer, hrInternalError, pfnGenericMessageHandler, pvContext); ExitOnFailure(hr, "Failed to send internal error message from netfx chainer."); } break; } else if (WAIT_OBJECT_0 + 1 == er) { // Chainee has notified us of a change. hr = ProcessNetFxMessage(pNetfxChainer, pfnGenericMessageHandler, pvContext); ExitOnFailure(hr, "Failed to process netfx chainer message."); } else if (WAIT_FAILED == er) { ExitWithLastError(hr, "Failed to wait for netfx chainer process to complete"); } } LExit: ReleaseStr(sczSectionName); ReleaseStr(sczEventName); ReleaseStr(sczCommand); DestroyNetFxChainer(pNetfxChainer); ReleaseHandle(pi.hThread); ReleaseHandle(pi.hProcess); return hr; }
// // Obtains target URL and referer from the specified request handle and HTTP headers string. // Checks URL and referer and creates handle context if needed. // Adds "Accept-Encoding: identity" header. // static LPSTR IeCreateContextModifyHeadersA( HINTERNET hRequest, LPSTR lpszHeaders, DWORD dwHeadersLength, LPSTR* ppHeaders, PHANDLE_CONTEXT* pCtx ) { LPSTR NewHeaders = NULL, pHeaders = NULL, pReferer = NULL; ULONG Len; CHAR OldChar; PHANDLE_CONTEXT Ctx = NULL; // Check if we already have a context for the specified handle if (!(Ctx = FindHandle(hRequest))) { if (lpszHeaders) { if (dwHeadersLength == -1) Len = lstrlenA(lpszHeaders); else Len = dwHeadersLength; if (pHeaders = hAlloc(Len + sizeof(CHAR))) { memcpy(pHeaders, lpszHeaders, Len); pHeaders[Len] = 0; } } // if (lpszHeaders) else pHeaders = TaransferGetRequestHeaders(hRequest); if (pHeaders) { if (pReferer = HttpFindHeaderA(pHeaders, szReferer, &Len)) { OldChar = pReferer[Len]; pReferer[Len] = 0; } } // if (pHeaders) if (ppHeaders) *ppHeaders = pHeaders; // Creating a context for the handle if (Ctx = IeCheckAddHandle(hRequest, pReferer)) SetCallback(hRequest, Ctx); if (pReferer) pReferer[Len] = OldChar; } // if (!(Ctx = IeGetContext(hRequest))) else ReleaseHandle(Ctx); if (Ctx) { if ((lpszHeaders) && (dwHeadersLength == -1)) // Setting "Accept-Encoding: identity" header NewHeaders = HttpSetHeaderA(lpszHeaders, szAcceptEncoding, szIdentity, NULL); } if (pCtx) *pCtx = Ctx; return(NewHeaders); }
int WINAPI wWinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE /* hPrevInstance */, __in_z_opt LPWSTR lpCmdLine, __in int /*nCmdShow*/ ) { ::HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); HRESULT hr = S_OK; BOOL fComInitialized = FALSE; LPWSTR sczThemeFile = NULL; ATOM atom = 0; HWND hWnd = NULL; HANDLE hDisplayThread = NULL; HANDLE hLoadThread = NULL; BOOL fRet = FALSE; MSG msg = { }; hr = ::CoInitialize(NULL); ExitOnFailure(hr, "Failed to initialize COM."); fComInitialized = TRUE; hr = ProcessCommandLine(lpCmdLine, &sczThemeFile); ExitOnFailure(hr, "Failed to process command line."); hr = CreateTheme(hInstance, &vpTheme); ExitOnFailure(hr, "Failed to create theme."); hr = CreateMainWindowClass(hInstance, vpTheme, &atom); ExitOnFailure(hr, "Failed to create main window."); hWnd = ::CreateWindowExW(0, reinterpret_cast<LPCWSTR>(atom), vpTheme->sczCaption, vpTheme->dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, vpTheme->nWidth, vpTheme->nHeight, HWND_DESKTOP, NULL, hInstance, NULL); ExitOnNullWithLastError(hWnd, hr, "Failed to create window."); if (!sczThemeFile) { // Prompt for a path to the theme file. OPENFILENAMEW ofn = { }; WCHAR wzFile[MAX_PATH] = { }; ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hWnd; ofn.lpstrFile = wzFile; ofn.nMaxFile = countof(wzFile); ofn.lpstrFilter = L"Theme Files\0*.thm\0XML Files\0*.xml\0All Files\0*.*\0"; ofn.nFilterIndex = 1; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; ofn.lpstrTitle = vpTheme->sczCaption; if (::GetOpenFileNameW(&ofn)) { hr = StrAllocString(&sczThemeFile, wzFile, 0); ExitOnFailure(hr, "Failed to copy opened file to theme file."); } else { ::MessageBoxW(hWnd, L"Must specify a path to theme file.", vpTheme->sczCaption, MB_OK | MB_ICONERROR); ExitFunction1(hr = E_INVALIDARG); } } hr = DisplayStart(hInstance, hWnd, &hDisplayThread, &vdwDisplayThreadId); ExitOnFailure(hr, "Failed to start display."); hr = LoadStart(sczThemeFile, hWnd, &hLoadThread); ExitOnFailure(hr, "Failed to start load."); // message pump while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0))) { if (-1 == fRet) { hr = E_UNEXPECTED; ExitOnFailure(hr, "Unexpected return value from message pump."); } else if (!ThemeHandleKeyboardMessage(vpTheme, msg.hwnd, &msg)) { ::TranslateMessage(&msg); ::DispatchMessageW(&msg); } } LExit: if (::IsWindow(hWnd)) { ::DestroyWindow(hWnd); } if (hDisplayThread) { ::PostThreadMessageW(vdwDisplayThreadId, WM_QUIT, 0, 0); ::WaitForSingleObject(hDisplayThread, 10000); ::CloseHandle(hDisplayThread); } // TODO: come up with a good way to kill the load thread, probably need to switch // the ReadDirectoryW() to overlapped mode. ReleaseHandle(hLoadThread); if (atom && !::UnregisterClassW(reinterpret_cast<LPCWSTR>(atom), hInstance)) { DWORD er = ::GetLastError(); er = er; } ThemeFree(vpTheme); ThemeUninitialize(); // uninitialize COM if (fComInitialized) { ::CoUninitialize(); } ReleaseStr(sczThemeFile); return hr; }
extern "C" HRESULT ExeEngineExecutePackage( __in BURN_EXECUTE_ACTION* pExecuteAction, __in BURN_VARIABLES* pVariables, __in BOOL fRollback, __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, __in LPVOID pvContext, __out BOOTSTRAPPER_APPLY_RESTART* pRestart ) { HRESULT hr = S_OK; WCHAR wzCurrentDirectory[MAX_PATH] = { }; BOOL fChangedCurrentDirectory = FALSE; int nResult = IDNOACTION; LPCWSTR wzArguments = NULL; LPWSTR sczArgumentsFormatted = NULL; LPWSTR sczArgumentsObfuscated = NULL; LPWSTR sczCachedDirectory = NULL; LPWSTR sczExecutablePath = NULL; LPWSTR sczCommand = NULL; LPWSTR sczCommandObfuscated = NULL; STARTUPINFOW si = { }; PROCESS_INFORMATION pi = { }; DWORD dwExitCode = 0; GENERIC_EXECUTE_MESSAGE message = { }; // get cached executable path hr = CacheGetCompletedPath(pExecuteAction->exePackage.pPackage->fPerMachine, pExecuteAction->exePackage.pPackage->sczCacheId, &sczCachedDirectory); ExitOnFailure1(hr, "Failed to get cached path for package: %ls", pExecuteAction->exePackage.pPackage->sczId); // Best effort to set the execute package cache folder variable. VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, sczCachedDirectory, TRUE); hr = PathConcat(sczCachedDirectory, pExecuteAction->exePackage.pPackage->rgPayloads[0].pPayload->sczFilePath, &sczExecutablePath); ExitOnFailure(hr, "Failed to build executable path."); // pick arguments switch (pExecuteAction->exePackage.action) { case BOOTSTRAPPER_ACTION_STATE_INSTALL: wzArguments = pExecuteAction->exePackage.pPackage->Exe.sczInstallArguments; break; case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: wzArguments = pExecuteAction->exePackage.pPackage->Exe.sczUninstallArguments; break; case BOOTSTRAPPER_ACTION_STATE_REPAIR: wzArguments = pExecuteAction->exePackage.pPackage->Exe.sczRepairArguments; break; default: hr = E_UNEXPECTED; ExitOnFailure(hr, "Failed to get action arguments for executable package."); } // build command if (wzArguments && *wzArguments) { hr = VariableFormatString(pVariables, wzArguments, &sczArgumentsFormatted, NULL); ExitOnFailure(hr, "Failed to format argument string."); hr = StrAllocFormattedSecure(&sczCommand, L"\"%ls\" %s", sczExecutablePath, sczArgumentsFormatted); ExitOnFailure(hr, "Failed to create executable command."); hr = VariableFormatStringObfuscated(pVariables, wzArguments, &sczArgumentsObfuscated, NULL); ExitOnFailure(hr, "Failed to format obfuscated argument string."); hr = StrAllocFormatted(&sczCommandObfuscated, L"\"%ls\" %s", sczExecutablePath, sczArgumentsObfuscated); } else { hr = StrAllocFormatted(&sczCommand, L"\"%ls\"", sczExecutablePath); ExitOnFailure(hr, "Failed to create executable command."); hr = StrAllocFormatted(&sczCommandObfuscated, L"\"%ls\"", sczExecutablePath); } ExitOnFailure(hr, "Failed to create obfuscated executable command."); if (BURN_EXE_PROTOCOL_TYPE_BURN == pExecuteAction->exePackage.pPackage->Exe.protocol) { // Add the list of dependencies to ignore, if any, to the burn command line. if (pExecuteAction->exePackage.sczIgnoreDependencies && BURN_EXE_PROTOCOL_TYPE_BURN == pExecuteAction->exePackage.pPackage->Exe.protocol) { hr = StrAllocFormattedSecure(&sczCommand, L"%ls -%ls=%ls", sczCommand, BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->exePackage.sczIgnoreDependencies); ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line."); hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls -%ls=%ls", sczCommandObfuscated, BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->exePackage.sczIgnoreDependencies); ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the obfuscated command line."); } // Add the list of ancestors, if any, to the burn command line. if (pExecuteAction->exePackage.sczAncestors) { hr = StrAllocFormattedSecure(&sczCommand, L"%ls -%ls=%ls", sczCommand, BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->exePackage.sczAncestors); ExitOnFailure(hr, "Failed to append the list of ancestors to the command line."); hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls -%ls=%ls", sczCommandObfuscated, BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->exePackage.sczAncestors); ExitOnFailure(hr, "Failed to append the list of ancestors to the obfuscated command line."); } } // Log before we add the secret pipe name and client token for embedded processes. LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pExecuteAction->exePackage.pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), sczExecutablePath, sczCommandObfuscated); if (!pExecuteAction->exePackage.fFireAndForget && BURN_EXE_PROTOCOL_TYPE_BURN == pExecuteAction->exePackage.pPackage->Exe.protocol) { hr = EmbeddedRunBundle(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); ExitOnFailure1(hr, "Failed to run bundle as embedded from path: %ls", sczExecutablePath); } else if (!pExecuteAction->exePackage.fFireAndForget && BURN_EXE_PROTOCOL_TYPE_NETFX4 == pExecuteAction->exePackage.pPackage->Exe.protocol) { hr = NetFxRunChainer(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); ExitOnFailure1(hr, "Failed to run netfx chainer: %ls", sczExecutablePath); } else // create and wait for the executable process while sending fake progress to allow cancel. { // Make the cache location of the executable the current directory to help those executables // that expect stuff to be relative to them. if (::GetCurrentDirectoryW(countof(wzCurrentDirectory), wzCurrentDirectory)) { fChangedCurrentDirectory = ::SetCurrentDirectoryW(sczCachedDirectory); } si.cb = sizeof(si); // TODO: hookup the stdin/stdout/stderr pipes for logging purposes? if (!::CreateProcessW(sczExecutablePath, sczCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { ExitWithLastError1(hr, "Failed to CreateProcess on path: %ls", sczExecutablePath); } if (pExecuteAction->exePackage.fFireAndForget) { ::WaitForInputIdle(pi.hProcess, 5000); ExitFunction(); } do { message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; message.dwAllowedResults = MB_OKCANCEL; message.progress.dwPercentage = 50; nResult = pfnGenericMessageHandler(&message, pvContext); hr = (IDOK == nResult || IDNOACTION == nResult) ? S_OK : IDCANCEL == nResult ? HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) : HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE); ExitOnRootFailure(hr, "Bootstrapper application aborted during EXE progress."); hr = ProcWaitForCompletion(pi.hProcess, 500, &dwExitCode); if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) != hr) { ExitOnFailure1(hr, "Failed to wait for executable to complete: %ls", sczExecutablePath); } } while (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == hr); } hr = HandleExitCode(pExecuteAction->exePackage.pPackage, dwExitCode, pRestart); ExitOnRootFailure1(hr, "Process returned error: 0x%x", dwExitCode); LExit: if (fChangedCurrentDirectory) { ::SetCurrentDirectoryW(wzCurrentDirectory); } StrSecureZeroFreeString(sczArgumentsFormatted); ReleaseStr(sczArgumentsObfuscated); ReleaseStr(sczCachedDirectory); ReleaseStr(sczExecutablePath); StrSecureZeroFreeString(sczCommand); ReleaseStr(sczCommandObfuscated); ReleaseHandle(pi.hThread); ReleaseHandle(pi.hProcess); // Best effort to clear the execute package cache folder variable. VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, NULL, TRUE); return hr; }