/******************************************************************* DirCreateTempPath *******************************************************************/ extern "C" HRESULT DAPI DirCreateTempPath( __in LPCWSTR wzPrefix, __in LPWSTR wzPath, __in DWORD cchPath ) { Assert(wzPrefix); Assert(wzPath); HRESULT hr = S_OK; WCHAR wzDir[MAX_PATH]; WCHAR wzFile[MAX_PATH]; DWORD cch = 0; cch = ::GetTempPathW(countof(wzDir), wzDir); if (!cch || cch >= countof(wzDir)) { ExitWithLastError(hr, "Failed to GetTempPath."); } if (!::GetTempFileNameW(wzDir, wzPrefix, 0, wzFile)) { ExitWithLastError(hr, "Failed to GetTempFileName."); } hr = ::StringCchCopyW(wzPath, cchPath, wzFile); LExit: return hr; }
static HRESULT WriteToFile( __in HINTERNET hUrl, __in HANDLE hPayloadFile, __inout DWORD64* pdw64ResumeOffset, __in HANDLE hResumeFile, __in DWORD64 dw64ResourceLength, __in LPBYTE pbData, __in DWORD cbData, __in_opt BURN_CACHE_CALLBACK* pCallback ) { HRESULT hr = S_OK; DWORD cbReadData = 0; hr = FileSetPointer(hPayloadFile, *pdw64ResumeOffset, NULL, FILE_BEGIN); ExitOnFailure(hr, "Failed to seek to start point in file."); do { // Read bits from the internet. if (!::InternetReadFile(hUrl, static_cast<void*>(pbData), cbData, &cbReadData)) { ExitWithLastError(hr, "Failed while reading from internet."); } // Write bits to disk (if there are any). if (cbReadData) { DWORD cbTotalWritten = 0; DWORD cbWritten = 0; do { if (!::WriteFile(hPayloadFile, pbData + cbTotalWritten, cbReadData - cbTotalWritten, &cbWritten, NULL)) { ExitWithLastError(hr, "Failed to write data from internet."); } cbTotalWritten += cbWritten; } while (cbWritten && cbTotalWritten < cbReadData); // Ignore failure from updating resume file as this doesn't mean the download cannot succeed. UpdateResumeOffset(pdw64ResumeOffset, hResumeFile, cbTotalWritten); if (pCallback && pCallback->pfnProgress) { hr = CacheSendProgressCallback(pCallback, *pdw64ResumeOffset, dw64ResourceLength, hPayloadFile); ExitOnFailure(hr, "UX aborted on cache progress."); } } } while (cbReadData); LExit: return hr; }
/******************************************************************** WcaCaScriptWriteString() - writes a string to the ca script. ********************************************************************/ extern "C" HRESULT WIXAPI WcaCaScriptWriteString( __in WCA_CASCRIPT_HANDLE hScript, __in LPCWSTR wzValue ) { HRESULT hr = S_OK; DWORD cbFile = 0; DWORD cbWrite = 0; DWORD cbTotalWritten = 0; WCHAR delim[] = { MAGIC_MULTISZ_DELIM }; // magic char followed by NULL terminator cbFile = ::SetFilePointer(hScript->hScriptFile, 0, NULL, FILE_END); if (INVALID_SET_FILE_POINTER == cbFile) { ExitWithLastError(hr, "Failed to move file pointer to end of file."); } // If there is existing data in the file, append on the magic delimeter // before adding our new data on the end of the file. if (0 < cbFile) { cbWrite = sizeof(delim); cbTotalWritten = 0; while (cbTotalWritten < cbWrite) { DWORD cbWritten = 0; if (!::WriteFile(hScript->hScriptFile, reinterpret_cast<BYTE*>(delim) + cbTotalWritten, cbWrite - cbTotalWritten, &cbWritten, NULL)) { ExitWithLastError(hr, "Failed to write data to ca script."); } cbTotalWritten += cbWritten; } } cbWrite = lstrlenW(wzValue) * sizeof(WCHAR); cbTotalWritten = 0; while (cbTotalWritten < cbWrite) { DWORD cbWritten = 0; if (!::WriteFile(hScript->hScriptFile, reinterpret_cast<const BYTE*>(wzValue) + cbTotalWritten, cbWrite - cbTotalWritten, &cbWritten, NULL)) { ExitWithLastError(hr, "Failed to write data to ca script."); } cbTotalWritten += cbWritten; } LExit: return hr; }
static HRESULT GetUpdateInfoFileName( __in LPCWSTR wzApplicationId, __out LPWSTR* ppwzUpdateInfoPath ) { HRESULT hr = S_OK; WCHAR wzTempPath[MAX_PATH]; DWORD cchTempPath = countof(wzTempPath); cchTempPath = ::GetTempPathW(cchTempPath, wzTempPath); if (0 == cchTempPath) { ExitWithLastError(hr, "Failed to get temp path."); } else if (countof(wzTempPath) < cchTempPath) { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); ExitOnFailure(hr, "Failed to get temp path."); } hr = StrAllocConcat(ppwzUpdateInfoPath, wzTempPath, 0); ExitOnFailure(hr, "Failed to allocate path to update info."); hr = StrAllocConcat(ppwzUpdateInfoPath, wzApplicationId, 0); ExitOnFailure(hr, "Failed to allocate path to update info."); LExit: return hr; }
HRESULT SendBackgroundConflictsFoundCallback( __in DWORD dwThreadId, __in CFGDB_HANDLE cdHandle, __in CONFLICT_PRODUCT *rgcpProduct, __in DWORD cProduct ) { HRESULT hr = S_OK; BACKGROUND_CONFLICTS_FOUND_CALLBACK *pBackgroundConflictsFoundCallback = NULL; pBackgroundConflictsFoundCallback = static_cast<BACKGROUND_CONFLICTS_FOUND_CALLBACK *>(MemAlloc(sizeof(BACKGROUND_CONFLICTS_FOUND_CALLBACK), TRUE)); pBackgroundConflictsFoundCallback->cdHandle = cdHandle; pBackgroundConflictsFoundCallback->rgcpProduct = rgcpProduct; pBackgroundConflictsFoundCallback->cProduct = cProduct; if (!::PostThreadMessageW(dwThreadId, WM_BROWSE_BACKGROUND_CONFLICTS_FOUND_CALLBACK, reinterpret_cast<WPARAM>(pBackgroundConflictsFoundCallback), 0)) { ExitWithLastError(hr, "Failed to send message WM_BROWSE_BACKGROUND_CONFLICTS_FOUND_CALLBACK to worker thread"); } pBackgroundConflictsFoundCallback = NULL; LExit: ReleaseBackgroundConflictsFoundCallback(pBackgroundConflictsFoundCallback); return hr; }
/******************************************************************** ProcFindAllIdsFromExeName() - returns an array of process ids that are running specified executable. *******************************************************************/ extern "C" HRESULT DAPI ProcFindAllIdsFromExeName( __in_z LPCWSTR wzExeName, __out DWORD** ppdwProcessIds, __out DWORD* pcProcessIds ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; HANDLE hSnap = INVALID_HANDLE_VALUE; BOOL fContinue = FALSE; PROCESSENTRY32W peData = { sizeof(peData) }; hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (INVALID_HANDLE_VALUE == hSnap) { ExitWithLastError(hr, "Failed to create snapshot of processes on system"); } fContinue = ::Process32FirstW(hSnap, &peData); while (fContinue) { if (0 == lstrcmpiW((LPCWSTR)&(peData.szExeFile), wzExeName)) { if (!*ppdwProcessIds) { *ppdwProcessIds = static_cast<DWORD*>(MemAlloc(sizeof(DWORD), TRUE)); ExitOnNull(ppdwProcessIds, hr, E_OUTOFMEMORY, "Failed to allocate array for returned process IDs."); } else { DWORD* pdwReAllocReturnedPids = NULL; pdwReAllocReturnedPids = static_cast<DWORD*>(MemReAlloc(*ppdwProcessIds, sizeof(DWORD) * ((*pcProcessIds) + 1), TRUE)); ExitOnNull(pdwReAllocReturnedPids, hr, E_OUTOFMEMORY, "Failed to re-allocate array for returned process IDs."); *ppdwProcessIds = pdwReAllocReturnedPids; } (*ppdwProcessIds)[*pcProcessIds] = peData.th32ProcessID; ++(*pcProcessIds); } fContinue = ::Process32NextW(hSnap, &peData); } er = ::GetLastError(); if (ERROR_NO_MORE_FILES == er) { hr = S_OK; } else { hr = HRESULT_FROM_WIN32(er); } LExit: ReleaseFile(hSnap); return hr; }
static HRESULT CreateMainWindowClass( __in HINSTANCE hInstance, __in THEME* pTheme, __out ATOM* pAtom ) { HRESULT hr = S_OK; ATOM atom = 0; WNDCLASSW wc = { }; wc.lpfnWndProc = MainWndProc; wc.hInstance = hInstance; wc.hIcon = reinterpret_cast<HICON>(pTheme->hIcon); wc.hCursor = ::LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); wc.hbrBackground = pTheme->rgFonts[pTheme->dwFontId].hBackground; wc.lpszMenuName = NULL; wc.lpszClassName = THMVWR_WINDOW_CLASS_MAIN; atom = ::RegisterClassW(&wc); if (!atom) { ExitWithLastError(hr, "Failed to register main windowclass ."); } *pAtom = atom; LExit: return hr; }
static __callback long FAR DIAMONDAPI CabExtractSeek(__in INT_PTR hf, __in long dist, __in int seektype) { HRESULT hr = S_OK; DWORD dwMoveMethod; LONG lMove = 0; switch (seektype) { case 0: // SEEK_SET dwMoveMethod = FILE_BEGIN; dist += static_cast<long>(vdw64EmbeddedOffset); break; case 1: /// SEEK_CUR dwMoveMethod = FILE_CURRENT; break; case 2: // SEEK_END dwMoveMethod = FILE_END; break; default : dwMoveMethod = 0; hr = E_UNEXPECTED; ExitOnFailure(hr, "unexpected seektype in FDISeek(): %d", seektype); } // SetFilePointer returns -1 if it fails (this will cause FDI to quit with an FDIERROR_USER_ABORT error. // (Unless this happens while working on a cabinet, in which case FDI returns FDIERROR_CORRUPT_CABINET) lMove = ::SetFilePointer(reinterpret_cast<HANDLE>(hf), dist, NULL, dwMoveMethod); if (0xFFFFFFFF == lMove) { ExitWithLastError(hr, "failed to move file pointer %d bytes", dist); } LExit: return FAILED(hr) ? -1 : lMove - static_cast<long>(vdw64EmbeddedOffset); }
static __callback INT_PTR FAR DIAMONDAPI CabExtractOpen(__in_z PSTR pszFile, __in int oflag, __in int pmode) { HRESULT hr = S_OK; INT_PTR pFile = -1; LPWSTR sczCabFile = NULL; // if FDI asks for some unusual mode (in low memory situation it could ask for a scratch file) fail if ((oflag != (/*_O_BINARY*/ 0x8000 | /*_O_RDONLY*/ 0x0000)) || (pmode != (_S_IREAD | _S_IWRITE))) { hr = E_OUTOFMEMORY; ExitOnFailure(hr, "FDI asked for a scratch file to be created, which is unsupported"); } hr = StrAllocStringAnsi(&sczCabFile, pszFile, 0, CP_UTF8); ExitOnFailure(hr, "Failed to convert UTF8 cab file name to wide character string"); pFile = reinterpret_cast<INT_PTR>(::CreateFileW(sczCabFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); if (INVALID_HANDLE_VALUE == reinterpret_cast<HANDLE>(pFile)) { ExitWithLastError(hr, "failed to open file: %ls", sczCabFile); } if (vdw64EmbeddedOffset) { hr = CabExtractSeek(pFile, 0, 0); ExitOnFailure(hr, "Failed to seek to embedded offset %I64d", vdw64EmbeddedOffset); } LExit: ReleaseStr(sczCabFile); return FAILED(hr) ? -1 : pFile; }
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; }
/******************************************************************* PipeTerminateChildProcess - *******************************************************************/ extern "C" HRESULT PipeTerminateChildProcess( __in BURN_PIPE_CONNECTION* pConnection, __in DWORD dwParentExitCode, __in BOOL fRestart ) { HRESULT hr = S_OK; BYTE* pbData = NULL; SIZE_T cbData = 0; // Prepare the exit message. hr = BuffWriteNumber(&pbData, &cbData, dwParentExitCode); ExitOnFailure(hr, "Failed to write exit code to message buffer."); hr = BuffWriteNumber(&pbData, &cbData, fRestart); ExitOnFailure(hr, "Failed to write restart to message buffer."); // Send the messages. if (INVALID_HANDLE_VALUE != pConnection->hCachePipe) { hr = WritePipeMessage(pConnection->hCachePipe, static_cast<DWORD>(BURN_PIPE_MESSAGE_TYPE_TERMINATE), pbData, cbData); ExitOnFailure(hr, "Failed to post terminate message to child process cache thread."); } hr = WritePipeMessage(pConnection->hPipe, static_cast<DWORD>(BURN_PIPE_MESSAGE_TYPE_TERMINATE), pbData, cbData); ExitOnFailure(hr, "Failed to post terminate message to child process."); // If we were able to get a handle to the other process, wait for it to exit. if (pConnection->hProcess) { if (WAIT_FAILED == ::WaitForSingleObject(pConnection->hProcess, PIPE_WAIT_FOR_CONNECTION * PIPE_RETRY_FOR_CONNECTION)) { ExitWithLastError(hr, "Failed to wait for child process exit."); } #ifdef DEBUG DWORD dwChildExitCode = 0; DWORD dwErrorCode = ERROR_SUCCESS; BOOL fReturnedExitCode = ::GetExitCodeProcess(pConnection->hProcess, &dwChildExitCode); if (!fReturnedExitCode) { dwErrorCode = ::GetLastError(); // if the other process is elevated and we are not, then we'll get ERROR_ACCESS_DENIED. // The unit test use a thread instead of a process so try to get the exit code from // the thread because we failed to get it from the process. if (ERROR_INVALID_HANDLE == dwErrorCode) { fReturnedExitCode = ::GetExitCodeThread(pConnection->hProcess, &dwChildExitCode); } } AssertSz((fReturnedExitCode && dwChildExitCode == dwParentExitCode) || (!fReturnedExitCode && ERROR_ACCESS_DENIED == dwErrorCode), "Child elevated process did not return matching exit code to parent process."); #endif } LExit: return hr; }
extern "C" HRESULT DAPI CertGetAuthenticodeSigningTimestamp( __in CMSG_SIGNER_INFO* pSignerInfo, __out FILETIME* pftSigningTimestamp ) { HRESULT hr = S_OK; CRYPT_INTEGER_BLOB* pBlob = NULL; PCMSG_SIGNER_INFO pCounterSignerInfo = NULL; DWORD cbSigningTimestamp = sizeof(FILETIME); // Find the countersigner blob. The countersigner in Authenticode contains the time // that signing took place. It's a "countersigner" because the signing time was sent // off to the certificate authority in the sky to return the verified time signed. for (DWORD i = 0; i < pSignerInfo->UnauthAttrs.cAttr; ++i) { if (CSTR_EQUAL == ::CompareStringA(LOCALE_NEUTRAL, 0, szOID_RSA_counterSign, -1, pSignerInfo->UnauthAttrs.rgAttr[i].pszObjId, -1)) { pBlob = pSignerInfo->UnauthAttrs.rgAttr[i].rgValue; break; } } if (!pBlob) { hr = TRUST_E_FAIL; ExitOnFailure(hr, "Failed to find countersigner in signer information."); } hr = CrypDecodeObject(PKCS7_SIGNER_INFO, pBlob->pbData, pBlob->cbData, 0, reinterpret_cast<LPVOID*>(&pCounterSignerInfo), NULL); ExitOnFailure(hr, "Failed to decode countersigner information."); pBlob = NULL; // reset the blob before searching for the signing time. // Find the signing time blob in the countersigner. for (DWORD i = 0; i < pCounterSignerInfo->AuthAttrs.cAttr; ++i) { if (CSTR_EQUAL == ::CompareStringA(LOCALE_NEUTRAL, 0, szOID_RSA_signingTime, -1, pCounterSignerInfo->AuthAttrs.rgAttr[i].pszObjId, -1)) { pBlob = pCounterSignerInfo->AuthAttrs.rgAttr[i].rgValue; break; } } if (!pBlob) { hr = TRUST_E_FAIL; ExitOnFailure(hr, "Failed to find signing time in countersigner information."); } if (!::CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_RSA_signingTime, pBlob->pbData, pBlob->cbData, 0, pftSigningTimestamp, &cbSigningTimestamp)) { ExitWithLastError(hr, "Failed to decode countersigner signing timestamp."); } LExit: ReleaseMem(pCounterSignerInfo); return hr; }
static DWORD WINAPI ThreadProc( __in LPVOID pvContext ) { HRESULT hr = S_OK; UITHREAD_CONTEXT* pContext = static_cast<UITHREAD_CONTEXT*>(pvContext); WNDCLASSW wc = { }; BOOL fRegistered = TRUE; HWND hWnd = NULL; BOOL fRet = FALSE; MSG msg = { }; wc.lpfnWndProc = WndProc; wc.hInstance = pContext->hInstance; wc.lpszClassName = WIXCA_UITHREAD_CLASS_WINDOW; if (!::RegisterClassW(&wc)) { ExitWithLastError(hr, "Failed to register window."); } fRegistered = TRUE; // Create the window to handle reboots without activating it. hWnd = ::CreateWindowExW(WS_EX_TOOLWINDOW, wc.lpszClassName, NULL, WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, SW_SHOWNA, 0, 0, HWND_DESKTOP, NULL, pContext->hInstance, NULL); ExitOnNullWithLastError(hWnd, hr, "Failed to create window."); // Persist the window handle and let the caller know we've initialized. pContext->hWnd = hWnd; ::SetEvent(pContext->hInitializedEvent); // Pump messages until the window is closed. while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0))) { if (-1 == fRet) { hr = E_UNEXPECTED; ExitOnFailure(hr, "Unexpected return value from message pump."); } else if (!::IsDialogMessageW(msg.hwnd, &msg)) { ::TranslateMessage(&msg); ::DispatchMessageW(&msg); } } LExit: if (fRegistered) { ::UnregisterClassW(WIXCA_UITHREAD_CLASS_WINDOW, pContext->hInstance); } return hr; }
static HRESULT CaScriptFileName( __in WCA_ACTION action, __in WCA_CASCRIPT script, __in BOOL fImpersonated, __in LPCWSTR wzScriptKey, __out LPWSTR* ppwzScriptName ) { HRESULT hr = S_OK; WCHAR wzTempPath[MAX_PATH]; LPWSTR pwzProductCode = NULL; WCHAR chInstallOrUninstall = action == WCA_ACTION_INSTALL ? L'i' : L'u'; WCHAR chScheduledOrRollback = script == WCA_CASCRIPT_SCHEDULED ? L's' : L'r'; WCHAR chUserOrMachine = fImpersonated ? L'u' : L'm'; if (fImpersonated) { if (!::GetTempPathW(countof(wzTempPath), wzTempPath)) { ExitWithLastError(hr, "Failed to get temp path."); } } else { if (!::GetWindowsDirectoryW(wzTempPath, countof(wzTempPath))) { ExitWithLastError(hr, "Failed to get windows path."); } hr = ::StringCchCatW(wzTempPath, countof(wzTempPath), L"\\Installer\\"); ExitOnFailure(hr, "Failed to concat Installer directory on windows path string."); } hr = WcaGetProperty(L"ProductCode", &pwzProductCode); ExitOnFailure(hr, "Failed to get ProductCode."); hr = StrAllocFormatted(ppwzScriptName, L"%swix%s.%s.%c%c%c", wzTempPath, pwzProductCode, wzScriptKey, chScheduledOrRollback, chUserOrMachine, chInstallOrUninstall); ExitOnFailure(hr, "Failed to allocate path to ca script."); LExit: ReleaseStr(pwzProductCode); return hr; }
/******************************************************************** CreateRichTextWindow - Creates Window and Child RichText control. ********************************************************************/ HRESULT CreateRichTextWindow( __out HWND* phWndMain, __out BOOL* pfRegisteredClass ) { HRESULT hr = S_OK; HWND hWndMain = NULL; WNDCLASSEXW wcex; // // Register the window class // wcex.cbSize = sizeof(WNDCLASSEXW); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = NULL; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = WINDOW_CLASS; wcex.hIconSm = NULL; if (0 == ::RegisterClassExW(&wcex)) { DWORD dwResult = ::GetLastError(); // If we get "Class already exists" error ignore it. We might // encounter this when the user tries to print more than once // in the same setup instance and we are unable to clean up fully. if (dwResult != ERROR_CLASS_ALREADY_EXISTS) { ExitOnFailure(hr = HRESULT_FROM_WIN32(dwResult), "failed to register window class"); } } *pfRegisteredClass = TRUE; // Perform application initialization: hWndMain = ::CreateWindowW(WINDOW_CLASS, NULL, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, NULL, NULL); ExitOnNullWithLastError(hWndMain, hr, "failed to create window for printing"); ::ShowWindow(hWndMain, SW_HIDE); if (!::UpdateWindow(hWndMain)) { ExitWithLastError(hr, "failed to update window"); } *phWndMain = hWndMain; LExit: return hr; }
static HRESULT EnsureWUServiceEnabled( __in BOOL fStopWusaService, __out SC_HANDLE* pschWu, __out BOOL* pfPreviouslyDisabled ) { HRESULT hr = S_OK; SC_HANDLE schSCM = NULL; SC_HANDLE schWu = NULL; SERVICE_STATUS serviceStatus = { }; QUERY_SERVICE_CONFIGW* pConfig = NULL; schSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); ExitOnNullWithLastError(schSCM, hr, "Failed to open service control manager."); schWu = ::OpenServiceW(schSCM, L"wuauserv", SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_STOP ); ExitOnNullWithLastError(schWu, hr, "Failed to open WU service."); if (!::QueryServiceStatus(schWu, &serviceStatus) ) { ExitWithLastError(hr, "Failed to query status of WU service."); } // Stop service if requested to. if (SERVICE_STOPPED != serviceStatus.dwCurrentState && fStopWusaService) { hr = StopWUService(schWu); } // If the service is not running then it might be disabled so let's check. if (SERVICE_RUNNING != serviceStatus.dwCurrentState) { hr = SvcQueryConfig(schWu, &pConfig); ExitOnFailure(hr, "Failed to read configuration for WU service."); // If WU is disabled, change it to a demand start service (but touch nothing else). if (SERVICE_DISABLED == pConfig->dwStartType) { hr = SetServiceStartType(schWu, SERVICE_DEMAND_START); ExitOnFailure(hr, "Failed to mark WU service to start on demand."); *pfPreviouslyDisabled = TRUE; } } *pschWu = schWu; schWu = NULL; LExit: ReleaseMem(pConfig); ReleaseServiceHandle(schWu); ReleaseServiceHandle(schSCM); return hr; }
static __callback int FAR DIAMONDAPI CabExtractClose(__in INT_PTR hf) { HRESULT hr = S_OK; if (!::CloseHandle(reinterpret_cast<HANDLE>(hf))) { ExitWithLastError(hr, "failed to close file during cabinet extraction"); } LExit: return FAILED(hr) ? -1 : 0; }
extern "C" HRESULT DAPI GetProvSecurityDesc( __in HCRYPTPROV hProv, __deref_out SECURITY_DESCRIPTOR** ppSecurity) { HRESULT hr = S_OK; ULONG ulSize = 0; SECURITY_DESCRIPTOR* pSecurity = NULL; // Get the size of the security descriptor. if (!::CryptGetProvParam( hProv, PP_KEYSET_SEC_DESCR, NULL, &ulSize, DACL_SECURITY_INFORMATION)) { ExitWithLastError(hr, "Error getting security descriptor size for CSP."); } // Allocate the memory for the security descriptor. pSecurity = static_cast<SECURITY_DESCRIPTOR *>(MemAlloc(ulSize, TRUE)); ExitOnNullWithLastError(pSecurity, hr, "Error allocating memory for CSP DACL"); // Get the security descriptor. if (!::CryptGetProvParam( hProv, PP_KEYSET_SEC_DESCR, (BYTE*)pSecurity, &ulSize, DACL_SECURITY_INFORMATION)) { MemFree(pSecurity); ExitWithLastError(hr, "Error getting security descriptor for CSP."); } *ppSecurity = pSecurity; LExit: return hr; }
static HRESULT OpenRequest( __in HINTERNET hConnect, __in_z_opt LPCWSTR wzMethod, __in INTERNET_SCHEME scheme, __in_z LPCWSTR wzResource, __in_z_opt LPCWSTR wzQueryString, __in_z_opt LPCWSTR wzHeader, __out HINTERNET* phUrl ) { HRESULT hr = S_OK; DWORD dwRequestFlags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD; LPWSTR sczResource = NULL; HINTERNET hUrl = NULL; if (INTERNET_SCHEME_HTTPS == scheme) { dwRequestFlags |= INTERNET_FLAG_SECURE; } // Allocate the resource name. hr = StrAllocString(&sczResource, wzResource, 0); ExitOnFailure(hr, "Failed to allocate string for resource URI."); if (wzQueryString && *wzQueryString) { hr = StrAllocConcat(&sczResource, wzQueryString, 0); ExitOnFailure(hr, "Failed to append query strong to resource from URI."); } // Open the request and add the header if provided. hUrl = ::HttpOpenRequestW(hConnect, wzMethod, sczResource, NULL, NULL, BURN_DOWNLOAD_ENGINE_ACCEPT_TYPES, dwRequestFlags, NULL); ExitOnNullWithLastError(hUrl, hr, "Failed to open internet request."); if (wzHeader && *wzHeader) { if (!::HttpAddRequestHeadersW(hUrl, wzHeader, static_cast<DWORD>(-1), HTTP_ADDREQ_FLAG_COALESCE)) { ExitWithLastError(hr, "Failed to add header to HTTP request."); } } *phUrl = hUrl; hUrl = NULL; LExit: ReleaseInternet(hUrl); ReleaseStr(sczResource); return hr; }
static __callback UINT FAR DIAMONDAPI CabExtractWrite(__in INT_PTR hf, __in void FAR *pv, __in UINT cb) { HRESULT hr = S_OK; DWORD cbWrite = 0; ExitOnNull(hf, hr, E_INVALIDARG, "Failed to write file during cabinet extraction - no file given to write"); if (!::WriteFile(reinterpret_cast<HANDLE>(hf), pv, cb, &cbWrite, NULL)) { ExitWithLastError(hr, "failed to write during cabinet extraction"); } LExit: return FAILED(hr) ? -1 : cbWrite; }
static HRESULT SetServiceStartType( __in SC_HANDLE sch, __in DWORD startType ) { HRESULT hr = S_OK; if (!::ChangeServiceConfigW(sch, SERVICE_NO_CHANGE, startType, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) { ExitWithLastError(hr, "Failed to set service start type."); } LExit: return hr; }
/******************************************************************** CertReadProperty - reads a property from the certificate. NOTE: call MemFree() on the returned pvValue. ********************************************************************/ extern "C" HRESULT DAPI CertReadProperty( __in PCCERT_CONTEXT pCertContext, __in DWORD dwProperty, __deref_out_bound LPVOID* ppvValue, __out_opt DWORD* pcbValue ) { HRESULT hr = S_OK; LPVOID pv = NULL; DWORD cb = 0; if (!::CertGetCertificateContextProperty(pCertContext, dwProperty, NULL, &cb)) { ExitWithLastError(hr, "Failed to get size of certificate property."); } pv = MemAlloc(cb, TRUE); ExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to allocate memory for certificate property."); if (!::CertGetCertificateContextProperty(pCertContext, dwProperty, pv, &cb)) { ExitWithLastError(hr, "Failed to get certificate property."); } *ppvValue = pv; pv = NULL; if (pcbValue) { *pcbValue = cb; } LExit: ReleaseMem(pv); return hr; }
static HRESULT StopWUService( __in SC_HANDLE schWu ) { HRESULT hr = S_OK; SERVICE_STATUS serviceStatus = { }; if(!::ControlService(schWu, SERVICE_CONTROL_STOP, &serviceStatus)) { ExitWithLastError(hr, "Failed to stop wusa service."); } LExit: return hr; }
/******************************************************************** WcaInitializeWow64() - Initializes the Wow64 API ********************************************************************/ extern "C" HRESULT WIXAPI WcaInitializeWow64() { AssertSz(WcaIsInitialized(), "WcaInitialize() should be called before calling WcaInitializeWow64()"); AssertSz(!WcaIsWow64Initialized(), "WcaInitializeWow64() should not be called twice without calling WcaFinalizeWow64()"); s_fWow64Initialized = FALSE; HRESULT hr = S_OK; s_Wow64FSRevertState = NULL; s_fWow64FSDisabled = false; // Test if we have access to the Wow64 API, and store the result in bWow64APIPresent s_hKernel32 = ::GetModuleHandleW(L"kernel32.dll"); if (!s_hKernel32) { ExitWithLastError(hr, "failed to get handle to kernel32.dll"); } // This will test if we have access to the Wow64 API s_pfnIsWow64Process = (BOOL (*)(HANDLE, PBOOL))::GetProcAddress(s_hKernel32, "IsWow64Process"); if (NULL != s_pfnIsWow64Process) { s_pfnDisableWow64 = (BOOL (*)(PVOID *))::GetProcAddress(s_hKernel32, "Wow64DisableWow64FsRedirection"); // If we fail, log the error but proceed, because we may not need a particular function, or the Wow64 API at all if (!s_pfnDisableWow64) { return S_FALSE; } s_pfnRevertWow64 = (BOOL (*)(PVOID))::GetProcAddress(s_hKernel32, "Wow64RevertWow64FsRedirection"); if (!s_pfnRevertWow64) { return S_FALSE; } if (s_pfnDisableWow64 && s_pfnRevertWow64) { s_fWow64Initialized = TRUE; } } else { return S_FALSE; } LExit: return hr; }
HRESULT SendBackgroundStatusCallback( __in DWORD dwThreadId, __in HRESULT hrStatus, __in BACKGROUND_STATUS_TYPE type, __in_z LPCWSTR wzString1, __in_z LPCWSTR wzString2, __in_z LPCWSTR wzString3 ) { HRESULT hr = S_OK; BACKGROUND_STATUS_CALLBACK *pBackgroundStatusCallback = NULL; pBackgroundStatusCallback = static_cast<BACKGROUND_STATUS_CALLBACK *>(MemAlloc(sizeof(BACKGROUND_STATUS_CALLBACK), TRUE)); pBackgroundStatusCallback->hrStatus = hrStatus; pBackgroundStatusCallback->type = type; if (NULL != wzString1) { hr = StrAllocString(&pBackgroundStatusCallback->sczString1, wzString1, 0); ExitOnFailure1(hr, "Failed to allocate copy of string1: %ls", wzString1); } if (NULL != wzString2) { hr = StrAllocString(&pBackgroundStatusCallback->sczString2, wzString2, 0); ExitOnFailure1(hr, "Failed to allocate copy of string2: %ls", wzString2); } if (NULL != wzString3) { hr = StrAllocString(&pBackgroundStatusCallback->sczString3, wzString3, 0); ExitOnFailure1(hr, "Failed to allocate copy of string3: %ls", wzString3); } if (!::PostThreadMessageW(dwThreadId, WM_BROWSE_BACKGROUND_STATUS_CALLBACK, reinterpret_cast<WPARAM>(pBackgroundStatusCallback), 0)) { ExitWithLastError(hr, "Failed to send message WM_BROWSE_BACKGROUND_STATUS_CALLBACK to worker thread"); } pBackgroundStatusCallback = NULL; LExit: ReleaseBackgroundStatusCallback(pBackgroundStatusCallback); return hr; }
extern "C" HRESULT DAPI SetProvSecurityDesc( __in HCRYPTPROV hProv, __in SECURITY_DESCRIPTOR* pSecurity) { HRESULT hr = S_OK; // Set the new security descriptor. if (!::CryptSetProvParam( hProv, PP_KEYSET_SEC_DESCR, (BYTE*)pSecurity, DACL_SECURITY_INFORMATION)) { ExitWithLastError(hr, "Error setting security descriptor for CSP."); } LExit: return hr; }
/******************************************************************** WcaCaScriptCreate() - creates the appropriate script for this CustomAction Script Key. ********************************************************************/ extern "C" HRESULT WIXAPI WcaCaScriptCreate( __in WCA_ACTION action, __in WCA_CASCRIPT script, __in BOOL fImpersonated, __in LPCWSTR wzScriptKey, __in BOOL fAppend, __in WCA_CASCRIPT_HANDLE* phScript ) { HRESULT hr = S_OK; LPWSTR pwzScriptPath = NULL; HANDLE hScriptFile = INVALID_HANDLE_VALUE; hr = CaScriptFileName(action, script, fImpersonated, wzScriptKey, &pwzScriptPath); ExitOnFailure(hr, "Failed to calculate script file name."); hScriptFile = ::CreateFileW(pwzScriptPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, fAppend ? OPEN_ALWAYS : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (INVALID_HANDLE_VALUE == hScriptFile) { ExitWithLastError1(hr, "Failed to open CaScript: %S", pwzScriptPath); } if (fAppend && INVALID_SET_FILE_POINTER == ::SetFilePointer(hScriptFile, 0, NULL, FILE_END)) { ExitWithLastError(hr, "Failed to seek to end of file."); } *phScript = reinterpret_cast<WCA_CASCRIPT_HANDLE>(MemAlloc(sizeof(WCA_CASCRIPT_STRUCT), TRUE)); ExitOnNull(*phScript, hr, E_OUTOFMEMORY, "Failed to allocate space for cascript handle."); (*phScript)->pwzScriptPath = pwzScriptPath; pwzScriptPath = NULL; (*phScript)->hScriptFile = hScriptFile; hScriptFile = INVALID_HANDLE_VALUE; LExit: if (INVALID_HANDLE_VALUE != hScriptFile) { ::CloseHandle(hScriptFile); } ReleaseStr(pwzScriptPath); return hr; }
static HRESULT GetNonSessionSpecificTempFolder( __deref_out_z LPWSTR* psczNonSessionTempFolder ) { HRESULT hr = S_OK; WCHAR wzTempFolder[MAX_PATH] = { }; DWORD cchTempFolder = 0; DWORD dwSessionId = 0; LPWSTR sczSessionId = 0; DWORD cchSessionId = 0; if (!::GetTempPathW(countof(wzTempFolder), wzTempFolder)) { ExitWithLastError(hr, "Failed to get temp folder."); } hr = ::StringCchLengthW(wzTempFolder, countof(wzTempFolder), reinterpret_cast<size_t*>(&cchTempFolder)); ExitOnFailure(hr, "Failed to get length of temp folder."); // If our session id is in the TEMP path then remove that part so we get the non-session // specific temporary folder. if (::ProcessIdToSessionId(::GetCurrentProcessId(), &dwSessionId)) { hr = StrAllocFormatted(&sczSessionId, L"%u\\", dwSessionId); ExitOnFailure(hr, "Failed to format session id as a string."); hr = ::StringCchLengthW(sczSessionId, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchSessionId)); ExitOnFailure(hr, "Failed to get length of session id string."); if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzTempFolder + cchTempFolder - cchSessionId, cchSessionId, sczSessionId, cchSessionId)) { cchTempFolder -= cchSessionId; } } hr = StrAllocString(psczNonSessionTempFolder, wzTempFolder, cchTempFolder); ExitOnFailure(hr, "Failed to copy temp folder."); LExit: ReleaseStr(sczSessionId); return hr; }
HRESULT RssUpdateDeleteUpdateInfo( __in LPCWSTR wzApplicationId ) { HRESULT hr = S_OK; LPWSTR pwzUpdateInfoPath = NULL; hr = GetUpdateInfoFileName(wzApplicationId, &pwzUpdateInfoPath); ExitOnFailure(hr, "Failed to allocate path to update info."); if (!::DeleteFileW(pwzUpdateInfoPath)) { ExitWithLastError(hr, "Failed to delete update info."); } LExit: ReleaseStr(pwzUpdateInfoPath); return hr; }
/******************************************************************** WcaDisableWow64FSRedirection() - Disables Wow64 FS Redirection ********************************************************************/ extern "C" HRESULT WIXAPI WcaDisableWow64FSRedirection() { AssertSz(s_fWow64Initialized && s_pfnDisableWow64 != NULL, "WcaDisableWow64FSRedirection() called, but Wow64 API was not initialized"); #ifdef DEBUG AssertSz(!s_fWow64FSDisabled, "You must call WcaRevertWow64FSRedirection() before calling WcaDisableWow64FSRedirection() again"); #endif HRESULT hr = S_OK; if (s_pfnDisableWow64(&s_Wow64FSRevertState)) { s_fWow64FSDisabled = TRUE; } else { ExitWithLastError(hr, "Failed to disable WOW64."); } LExit: return hr; }