/******************************************************************* LoadSystemLibraryWithPath - Fully qualifies the path to a module in the Windows system directory and loads it and returns the path Returns E_MODNOTFOUND - The module could not be found. * - Another error occured. ********************************************************************/ extern "C" HRESULT DAPI LoadSystemLibraryWithPath( __in_z LPCWSTR wzModuleName, __out HMODULE *phModule, __deref_out_z_opt LPWSTR* psczPath ) { HRESULT hr = S_OK; DWORD cch = 0; WCHAR wzPath[MAX_PATH] = { }; cch = ::GetSystemDirectoryW(wzPath, MAX_PATH); ExitOnNullWithLastError(cch, hr, "Failed to get the Windows system directory."); if (L'\\' != wzPath[cch - 1]) { hr = ::StringCchCatNW(wzPath, MAX_PATH, L"\\", 1); ExitOnRootFailure(hr, "Failed to terminate the string with a backslash."); } hr = ::StringCchCatW(wzPath, MAX_PATH, wzModuleName); ExitOnRootFailure1(hr, "Failed to create the fully-qualified path to %ls.", wzModuleName); *phModule = ::LoadLibraryW(wzPath); ExitOnNullWithLastError1(*phModule, hr, "Failed to load the library %ls.", wzModuleName); if (psczPath) { hr = StrAllocString(psczPath, wzPath, MAX_PATH); ExitOnFailure(hr, "Failed to copy the path to library."); } LExit: return hr; }
static HRESULT GetUpdateMutex( __in LPCWSTR wzAppId, __out HANDLE *phMutex ) { HRESULT hr = S_OK; HANDLE h = INVALID_HANDLE_VALUE; WCHAR wzMutexName[MAX_PATH]; hr = ::StringCchPrintfW(wzMutexName, countof(wzMutexName), L"Local\\CT_UPDATE_%S",wzAppId); ExitOnFailure(hr, "Failed to StringCchPrintfW the Update mutex's name."); h = ::CreateMutexW(NULL, FALSE, wzMutexName); ExitOnNullWithLastError1(h, hr, "Failed to open mutex %S", wzMutexName); if (WAIT_OBJECT_0 == ::WaitForSingleObject(h, 0)) { *phMutex = h; } else { ::CloseHandle(h); *phMutex = INVALID_HANDLE_VALUE; } LExit: return hr; }
HRESULT GetUpdateMutex( __in const GUID *pGuid, __out HANDLE *phMutex ) { HRESULT hr = S_OK; HANDLE h = INVALID_HANDLE_VALUE; WCHAR wzMutexName[MAX_PATH]; hr = ::StringCchPrintfW( wzMutexName, countof(wzMutexName), L"Local\\CT_UPDATE_%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", pGuid->Data1, pGuid->Data2, pGuid->Data3, pGuid->Data4[0], pGuid->Data4[1], pGuid->Data4[2], pGuid->Data4[3], pGuid->Data4[4], pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7] ); ExitOnFailure(hr, "Failed to StringCchPrintfW the Update mutex's name."); h = ::CreateMutexW(NULL, FALSE, wzMutexName); ExitOnNullWithLastError1(h, hr, "Failed to open mutex %S", wzMutexName); if (WAIT_OBJECT_0 == ::WaitForSingleObject(h, 0)) { *phMutex = h; } else { ::CloseHandle(h); *phMutex = INVALID_HANDLE_VALUE; } LExit: return hr; }
/******************************************************************** RmuAddProcessById - Adds the process ID to the Restart Manager sesion. You should call this multiple times as necessary before calling RmuRegisterResources. ********************************************************************/ extern "C" HRESULT DAPI RmuAddProcessById( __in PRMU_SESSION pSession, __in DWORD dwProcessId ) { HRESULT hr = S_OK; HANDLE hProcess = NULL; FILETIME CreationTime = {}; FILETIME ExitTime = {}; FILETIME KernelTime = {}; FILETIME UserTime = {}; BOOL fLocked = FALSE; hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId); ExitOnNullWithLastError1(hProcess, hr, "Failed to open the process ID %d.", dwProcessId); if (!::GetProcessTimes(hProcess, &CreationTime, &ExitTime, &KernelTime, &UserTime)) { ExitWithLastError1(hr, "Failed to get the process times for process ID %d.", dwProcessId); } ::EnterCriticalSection(&pSession->cs); fLocked = TRUE; hr = RmuApplicationArrayAlloc(&pSession->rgApplications, &pSession->cApplications, dwProcessId, CreationTime); ExitOnFailure(hr, "Failed to add the application to the array."); LExit: if (hProcess) { ::CloseHandle(hProcess); } if (fLocked) { ::LeaveCriticalSection(&pSession->cs); } return hr; }
/******************************************************************** ResGetStringLangId - get the language id for a string in the string table. ********************************************************************/ extern "C" HRESULT DAPI ResGetStringLangId( __in_opt LPCWSTR wzPath, __in UINT uID, __out WORD *pwLangId ) { Assert(pwLangId); HRESULT hr = S_OK; HINSTANCE hModule = NULL; DWORD dwBlockId = (uID / RES_STRINGS_PER_BLOCK) + 1; WORD wFoundLangId = 0; if (wzPath && *wzPath) { hModule = LoadLibraryExW(wzPath, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); ExitOnNullWithLastError1(hModule, hr, "Failed to open resource file: %ls", wzPath); } #pragma prefast(push) #pragma prefast(disable:25068) if (!::EnumResourceLanguagesA(hModule, RT_STRING, MAKEINTRESOURCE(dwBlockId), static_cast<ENUMRESLANGPROC>(EnumLangIdProc), reinterpret_cast<LONG_PTR>(&wFoundLangId))) #pragma prefast(pop) { ExitWithLastError(hr, "Failed to find string language identifier."); } *pwLangId = wFoundLangId; LExit: if (hModule) { ::FreeLibrary(hModule); } return hr; }
static HRESULT CreateNetFxChainer( __in LPCWSTR wzSectionName, __in LPCWSTR wzEventName, __out NetFxChainer** ppChainer ) { HRESULT hr = S_OK; LPWSTR sczName = NULL; NetFxChainer* pChainer = NULL; pChainer = (NetFxChainer*)MemAlloc(sizeof(NetFxChainer), TRUE); ExitOnNull(pChainer, hr, E_OUTOFMEMORY, "Failed to allocate memory for NetFxChainer struct."); pChainer->hEventChaineeSend = ::CreateEvent(NULL, FALSE, FALSE, wzEventName); ExitOnNullWithLastError1(pChainer->hEventChaineeSend, hr, "Failed to create event: %ls", wzEventName); hr = StrAllocFormatted(&sczName, L"%ls_send", wzEventName); ExitOnFailure(hr, "failed to allocate memory for event name"); pChainer->hEventChainerSend = ::CreateEvent(NULL, FALSE, FALSE, sczName); ExitOnNullWithLastError1(pChainer->hEventChainerSend, hr, "Failed to create event: %ls", sczName); hr = StrAllocFormatted(&sczName, L"%ls_mutex", wzEventName); ExitOnFailure(hr, "failed to allocate memory for mutex name"); // Create the mutex, we initially own pChainer->hMutex = ::CreateMutex(NULL, TRUE, sczName); ExitOnNullWithLastError1(pChainer->hMutex, hr, "Failed to create mutex: %ls", sczName); pChainer->hSection = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, // security attributes PAGE_READWRITE, 0, // high-order DWORD of maximum size NETFXDATA_SIZE, // low-order DWORD of maximum size wzSectionName); ExitOnNullWithLastError1(pChainer->hSection, hr, "Failed to memory map cabinet file: %ls", wzSectionName); pChainer->pData = reinterpret_cast<NetFxDataStructure*>(::MapViewOfFile(pChainer->hSection, FILE_MAP_WRITE, 0, 0, // offsets 0 // map entire file )); ExitOnNullWithLastError1(pChainer->pData, hr, "Failed to MapViewOfFile for %ls.", wzSectionName); // Initialize the shared memory hr = ::StringCchCopyW(pChainer->pData->szEventName, countof(pChainer->pData->szEventName), wzEventName); ExitOnFailure(hr, "failed to copy event name to shared memory structure."); pChainer->pData->downloadFinished = false; pChainer->pData->downloadSoFar = 0; pChainer->pData->hrDownloadFinished = E_PENDING; pChainer->pData->downloadAbort = false; pChainer->pData->installFinished = false; pChainer->pData->installSoFar = 0; pChainer->pData->hrInstallFinished = E_PENDING; pChainer->pData->installAbort = false; pChainer->pData->hrInternalError = S_OK; pChainer->pData->version = NETFXDATA_VERSION; pChainer->pData->messageCode = 0; pChainer->pData->messageResponse = 0; pChainer->pData->messageDataLength = 0; // Done with initialization, allow others to access. ::ReleaseMutex(pChainer->hMutex); *ppChainer = pChainer; pChainer = NULL; LExit: ReleaseStr(sczName); if (pChainer) { // Something failed, release the mutex and destroy the object if (pChainer->hMutex) { ::ReleaseMutex(pChainer->hMutex); } DestroyNetFxChainer(pChainer); } return hr; }
/******************************************************************* PipeChildConnect - Called from the child process to connect back to the pipe provided by the parent process. *******************************************************************/ extern "C" HRESULT PipeChildConnect( __in BURN_PIPE_CONNECTION* pConnection, __in BOOL fConnectCachePipe ) { Assert(pConnection->sczName); Assert(pConnection->sczSecret); Assert(!pConnection->hProcess); Assert(INVALID_HANDLE_VALUE == pConnection->hPipe); Assert(INVALID_HANDLE_VALUE == pConnection->hCachePipe); HRESULT hr = S_OK; LPWSTR sczPipeName = NULL; // Try to connect to the parent. hr = StrAllocFormatted(&sczPipeName, PIPE_NAME_FORMAT_STRING, pConnection->sczName); ExitOnFailure(hr, "Failed to allocate name of parent pipe."); hr = E_UNEXPECTED; for (DWORD cRetry = 0; FAILED(hr) && cRetry < PIPE_RETRY_FOR_CONNECTION; ++cRetry) { pConnection->hPipe = ::CreateFileW(sczPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (INVALID_HANDLE_VALUE == pConnection->hPipe) { hr = HRESULT_FROM_WIN32(::GetLastError()); if (E_FILENOTFOUND == hr) // if the pipe isn't created, call it a timeout waiting on the parent. { hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT); } ::Sleep(PIPE_WAIT_FOR_CONNECTION); } else // we have a connection, go with it. { hr = S_OK; } } ExitOnRootFailure1(hr, "Failed to open parent pipe: %ls", sczPipeName) // Verify the parent and notify it that the child connected. hr = ChildPipeConnected(pConnection->hPipe, pConnection->sczSecret, &pConnection->dwProcessId); ExitOnFailure1(hr, "Failed to verify parent pipe: %ls", sczPipeName); if (fConnectCachePipe) { // Connect to the parent for the cache pipe. hr = StrAllocFormatted(&sczPipeName, CACHE_PIPE_NAME_FORMAT_STRING, pConnection->sczName); ExitOnFailure(hr, "Failed to allocate name of parent cache pipe."); pConnection->hCachePipe = ::CreateFileW(sczPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (INVALID_HANDLE_VALUE == pConnection->hCachePipe) { ExitWithLastError1(hr, "Failed to open parent pipe: %ls", sczPipeName) } // Verify the parent and notify it that the child connected. hr = ChildPipeConnected(pConnection->hCachePipe, pConnection->sczSecret, &pConnection->dwProcessId); ExitOnFailure1(hr, "Failed to verify parent pipe: %ls", sczPipeName); } pConnection->hProcess = ::OpenProcess(SYNCHRONIZE, FALSE, pConnection->dwProcessId); ExitOnNullWithLastError1(pConnection->hProcess, hr, "Failed to open companion process with PID: %u", pConnection->dwProcessId); LExit: ReleaseStr(sczPipeName); return hr; }
static HRESULT MakeRequest( __in BURN_USER_EXPERIENCE* pUX, __in_z LPCWSTR wzPackageOrContainerId, __in_z LPCWSTR wzPayloadId, __in HINTERNET hSession, __inout_z LPWSTR* psczSourceUrl, __in_z_opt LPCWSTR wzMethod, __in_z_opt LPCWSTR wzHeaders, __in_z_opt LPCWSTR wzUser, __in_z_opt LPCWSTR wzPassword, __out HINTERNET* phConnect, __out HINTERNET* phUrl, __out BOOL* pfRangeRequestsAccepted ) { HRESULT hr = S_OK; HINTERNET hConnect = NULL; HINTERNET hUrl = NULL; URI_INFO uri = { }; // Try to open the URL. BOOL fRetry; do { fRetry = FALSE; // If the URL was opened close it, so we can reopen it again. ReleaseInternet(hUrl); ReleaseInternet(hConnect); // Open the url. hr = UriCrackEx(*psczSourceUrl, &uri); ExitOnFailure(hr, "Failed to break URL into server and resource parts."); hConnect = ::InternetConnectW(hSession, uri.sczHostName, uri.port, (wzUser && *wzUser) ? wzUser : uri.sczUser, (wzPassword && *wzPassword) ? wzPassword : uri.sczPassword, INTERNET_SCHEME_FTP == uri.scheme ? INTERNET_SERVICE_FTP : INTERNET_SERVICE_HTTP, 0, 0); ExitOnNullWithLastError1(hConnect, hr, "Failed to connect to URL: %ls", *psczSourceUrl); // Best effort set the proxy username and password, if they were provided. if ((wzUser && *wzUser) && (wzPassword && *wzPassword)) { if (::InternetSetOptionW(hConnect, INTERNET_OPTION_PROXY_USERNAME, (LPVOID)wzUser, lstrlenW(wzUser))) { ::InternetSetOptionW(hConnect, INTERNET_OPTION_PROXY_PASSWORD, (LPVOID)wzPassword, lstrlenW(wzPassword)); } } hr = OpenRequest(hConnect, wzMethod, uri.scheme, uri.sczPath, uri.sczQueryString, wzHeaders, &hUrl); ExitOnFailure1(hr, "Failed to open internet URL: %ls", *psczSourceUrl); hr = SendRequest(pUX, wzPackageOrContainerId, wzPayloadId, hUrl, psczSourceUrl, &fRetry, pfRangeRequestsAccepted); ExitOnFailure1(hr, "Failed to send request to URL: %ls", *psczSourceUrl); } while (fRetry); // Okay, we're all ready to start downloading. Update the connection information. *phConnect = hConnect; hConnect = NULL; *phUrl = hUrl; hUrl = NULL; LExit: UriInfoUninitialize(&uri); ReleaseInternet(hUrl); ReleaseInternet(hConnect); return hr; }