/******************************************************************** RegValueEnum - enumerates a registry value. *********************************************************************/ HRESULT DAPI RegValueEnum( __in HKEY hk, __in DWORD dwIndex, __deref_out_z LPWSTR* psczName, __out_opt DWORD *pdwType ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; DWORD cbValueName = 0; er = vpfnRegQueryInfoKeyW(hk, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &cbValueName, NULL, NULL, NULL); ExitOnWin32Error(er, hr, "Failed to get max size of value name under registry key."); // Add one for null terminator ++cbValueName; hr = StrAlloc(psczName, cbValueName); ExitOnFailure(hr, "Failed to allocate array for registry value name"); er = vpfnRegEnumValueW(hk, dwIndex, *psczName, &cbValueName, NULL, pdwType, NULL, NULL); if (ERROR_NO_MORE_ITEMS == er) { ExitFunction1(hr = E_NOMOREITEMS); } ExitOnWin32Error(er, hr, "Failed to enumerate registry value"); LExit: return hr; }
/******************************************************************** RegKeyEnum - enumerates a registry key. *********************************************************************/ extern "C" HRESULT DAPI RegKeyEnum( __in HKEY hk, __in DWORD dwIndex, __deref_out_z LPWSTR* psczKey ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; DWORD cch = 0; if (psczKey && *psczKey) { hr = StrMaxLength(*psczKey, reinterpret_cast<DWORD_PTR*>(&cch)); ExitOnFailure(hr, "Failed to determine length of string."); } if (2 > cch) { cch = 2; hr = StrAlloc(psczKey, cch); ExitOnFailure(hr, "Failed to allocate string to minimum size."); } er = vpfnRegEnumKeyExW(hk, dwIndex, *psczKey, &cch, NULL, NULL, NULL, NULL); if (ERROR_MORE_DATA == er) { er = vpfnRegQueryInfoKeyW(hk, NULL, NULL, NULL, NULL, &cch, NULL, NULL, NULL, NULL, NULL, NULL); ExitOnWin32Error(er, hr, "Failed to get max size of subkey name under registry key."); ++cch; // add one because RegQueryInfoKeyW() returns the length of the subkeys without the null terminator. hr = StrAlloc(psczKey, cch); ExitOnFailure(hr, "Failed to allocate string bigger for enum registry key."); er = vpfnRegEnumKeyExW(hk, dwIndex, *psczKey, &cch, NULL, NULL, NULL, NULL); } else if (ERROR_NO_MORE_ITEMS == er) { ExitFunction1(hr = E_NOMOREITEMS); } ExitOnWin32Error(er, hr, "Failed to enum registry key."); // Always ensure the registry key name is null terminated. #pragma prefast(push) #pragma prefast(disable:26018) (*psczKey)[cch] = L'\0'; // note that cch will always be one less than the size of the buffer because that's how RegEnumKeyExW() works. #pragma prefast(pop) LExit: return hr; }
/****************************************************************** PromptToContinue - displays the prompt if the application is still running. ******************************************************************/ static HRESULT PromptToContinue( __in_z LPCWSTR wzApplication, __in_z LPCWSTR wzPrompt ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; PMSIHANDLE hRecMessage = NULL; DWORD *prgProcessIds = NULL; DWORD cProcessIds = 0; hRecMessage = ::MsiCreateRecord(1); ExitOnNull(hRecMessage, hr, E_OUTOFMEMORY, "Failed to create record for prompt."); er = ::MsiRecordSetStringW(hRecMessage, 0, wzPrompt); ExitOnWin32Error(er, hr, "Failed to set prompt record field string"); do { hr = ProcFindAllIdsFromExeName(wzApplication, &prgProcessIds, &cProcessIds); if (SUCCEEDED(hr) && 0 < cProcessIds) { er = WcaProcessMessage(static_cast<INSTALLMESSAGE>(INSTALLMESSAGE_WARNING | MB_ABORTRETRYIGNORE | MB_DEFBUTTON3 | MB_ICONWARNING), hRecMessage); if (IDABORT == er) { hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT); } else if (IDRETRY == er) { hr = S_FALSE; } else if (IDIGNORE == er) { hr = S_OK; } else { ExitOnWin32Error(er, hr, "Unexpected return value from prompt to continue."); } } ReleaseNullMem(prgProcessIds); cProcessIds = 0; } while (S_FALSE == hr); LExit: ReleaseMem(prgProcessIds); return hr; }
DAPI_(HRESULT) SrpCreateRestorePoint( __in_z LPCWSTR wzApplicationName, __in SRP_ACTION action ) { HRESULT hr = S_OK; RESTOREPOINTINFOW restorePoint = { }; STATEMGRSTATUS status = { }; if (!vpfnSRSetRestorePointW) { ExitFunction1(hr = E_NOTIMPL); } restorePoint.dwEventType = BEGIN_SYSTEM_CHANGE; restorePoint.dwRestorePtType = (SRP_ACTION_INSTALL == action) ? APPLICATION_INSTALL : (SRP_ACTION_UNINSTALL == action) ? APPLICATION_UNINSTALL : MODIFY_SETTINGS; ::StringCbCopyW(restorePoint.szDescription, sizeof(restorePoint.szDescription), wzApplicationName); if (!vpfnSRSetRestorePointW(&restorePoint, &status)) { ExitOnWin32Error(status.nStatus, hr, "Failed to create system restore point."); } LExit: return hr; }
/******************************************************************** RmuRegisterResources - Registers resources for the Restart Manager. This should be called rarely because it is expensive to run. Call functions like RmuAddFile for multiple resources then commit them as a batch of updates to RmuRegisterResources. Duplicate resources appear to be handled by Restart Manager. Only one WM_QUERYENDSESSION is being sent for each top-level window. ********************************************************************/ extern "C" HRESULT DAPI RmuRegisterResources( __in PRMU_SESSION pSession ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; HMODULE hModule = NULL; PFNRMREGISTERRESOURCES pfnRmRegisterResources = NULL; AssertSz(vcRmuInitialized, "Restart Manager was not properly initialized."); ::EnterCriticalSection(&pSession->cs); er = vpfnRmRegisterResources( pSession->dwSessionHandle, pSession->cFilenames, pSession->rgsczFilenames, pSession->cApplications, pSession->rgApplications, pSession->cServiceNames, pSession->rgsczServiceNames ); ExitOnWin32Error(er, hr, "Failed to register the resources with the Restart Manager session."); // Empty the arrays if registered in case additional resources are added later. ReleaseNullStrArray(pSession->rgsczFilenames, pSession->cFilenames); ReleaseNullApplicationArray(pSession->rgApplications, pSession->cApplications); ReleaseNullStrArray(pSession->rgsczServiceNames, pSession->cServiceNames); LExit: ::LeaveCriticalSection(&pSession->cs); return hr; }
/******************************************************************** RmuEndSession - Ends the session. If the session was joined by RmuJoinSession, any remaining resources are registered before the session is ended (left). ********************************************************************/ extern "C" HRESULT DAPI RmuEndSession( __in PRMU_SESSION pSession ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; AssertSz(vcRmuInitialized, "Restart Manager was not properly initialized."); // Make sure all resources are registered if we joined the session. if (!pSession->fStartedSessionHandle) { hr = RmuRegisterResources(pSession); ExitOnFailure(hr, "Failed to register remaining resources."); } er = vpfnRmEndSession(pSession->dwSessionHandle); ExitOnWin32Error(er, hr, "Failed to end the Restart Manager session."); LExit: if (pSession->fInitialized) { ::DeleteCriticalSection(&pSession->cs); } ReleaseNullStrArray(pSession->rgsczFilenames, pSession->cFilenames); ReleaseNullApplicationArray(pSession->rgApplications, pSession->cApplications); ReleaseNullStrArray(pSession->rgsczServiceNames, pSession->cServiceNames); ReleaseNullMem(pSession); RmuUninitialize(); return hr; }
/******************************************************************** RegCreate - creates a registry key with extra options. *********************************************************************/ HRESULT DAPI RegCreateEx( __in HKEY hkRoot, __in_z LPCWSTR wzSubKey, __in DWORD dwAccess, __in BOOL fVolatile, __in_opt SECURITY_ATTRIBUTES* pSecurityAttributes, __out HKEY* phk, __out_opt BOOL* pfCreated ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; DWORD dwDisposition; er = vpfnRegCreateKeyExW(hkRoot, wzSubKey, 0, NULL, fVolatile ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE, dwAccess, pSecurityAttributes, phk, &dwDisposition); ExitOnWin32Error(er, hr, "Failed to create registry key."); if (pfCreated) { *pfCreated = (REG_CREATED_NEW_KEY == dwDisposition); } LExit: return hr; }
/******************************************************************** WcaOpenExecuteView() - opens and executes a view on the installing database ********************************************************************/ extern "C" HRESULT WIXAPI WcaOpenExecuteView( __in_z LPCWSTR wzSql, __out MSIHANDLE* phView ) { if (!wzSql || !*wzSql|| !phView) { return E_INVALIDARG; } HRESULT hr = S_OK; UINT er = ::MsiDatabaseOpenViewW(WcaGetDatabaseHandle(), wzSql, phView); ExitOnWin32Error(er, hr, "failed to open view on database"); er = ::MsiViewExecute(*phView, NULL); ExitOnWin32Error(er, hr, "failed to execute view"); LExit: return hr; }
/******************************************************************** WcaGetRecordFormattedString() - gets formatted string filed from record ********************************************************************/ extern "C" HRESULT WIXAPI WcaGetRecordFormattedString( __in MSIHANDLE hRec, __in UINT uiField, __inout LPWSTR* ppwzData ) { if (!hRec || !ppwzData) { return E_INVALIDARG; } HRESULT hr = S_OK; UINT er; DWORD_PTR cch = 0; PMSIHANDLE hRecFormat; // get the format string hr = WcaGetRecordString(hRec, uiField, ppwzData); ExitOnFailure(hr, "failed to get string from record"); if (!**ppwzData) { ExitFunction(); } // hide the nulls '[~]' so we can get them back after formatting HideNulls(*ppwzData); // set up the format record hRecFormat = ::MsiCreateRecord(1); ExitOnNull(hRecFormat, hr, E_UNEXPECTED, "Failed to create record to format string"); hr = WcaSetRecordString(hRecFormat, 0, *ppwzData); ExitOnFailure(hr, "failed to set string to format record"); // format the string hr = StrMaxLength(*ppwzData, &cch); ExitOnFailure(hr, "failed to get max length of string"); er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecFormat, *ppwzData, (DWORD*)&cch); if (ERROR_MORE_DATA == er) { hr = StrAlloc(ppwzData, ++cch); ExitOnFailure(hr, "Failed to allocate memory for record string"); er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecFormat, *ppwzData, (DWORD*)&cch); } ExitOnWin32Error(er, hr, "Failed to format string"); // put the nulls back RevealNulls(*ppwzData); LExit: return hr; }
/******************************************************************** RegCreate - creates a registry key. *********************************************************************/ extern "C" HRESULT DAPI RegCreate( __in HKEY hkRoot, __in_z LPCWSTR wzSubKey, __in DWORD dwAccess, __out HKEY* phk ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; er = vpfnRegCreateKeyExW(hkRoot, wzSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, dwAccess, NULL, phk, NULL); ExitOnWin32Error(er, hr, "Failed to create registry key."); LExit: return hr; }
/******************************************************************** WcaGetRecordString() - gets a string field out of a record ********************************************************************/ extern "C" HRESULT WIXAPI WcaGetRecordString( __in MSIHANDLE hRec, __in UINT uiField, __inout LPWSTR* ppwzData ) { if (!hRec || !ppwzData) return E_INVALIDARG; HRESULT hr = S_OK; UINT er; DWORD_PTR cch = 0; if (!*ppwzData) { WCHAR szEmpty[1] = L""; er = ::MsiRecordGetStringW(hRec, uiField, szEmpty, (DWORD*)&cch); if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) { hr = StrAlloc(ppwzData, ++cch); } else { hr = HRESULT_FROM_WIN32(er); } ExitOnFailure(hr, "Failed to allocate memory for record string"); } else { hr = StrMaxLength(*ppwzData, &cch); ExitOnFailure(hr, "Failed to get previous size of string"); } er = ::MsiRecordGetStringW(hRec, uiField, *ppwzData, (DWORD*)&cch); if (ERROR_MORE_DATA == er) { hr = StrAlloc(ppwzData, ++cch); ExitOnFailure(hr, "Failed to allocate memory for record string"); er = ::MsiRecordGetStringW(hRec, uiField, *ppwzData, (DWORD*)&cch); } ExitOnWin32Error(er, hr, "Failed to get string from record"); LExit: return hr; }
/******************************************************************** WcaExecuteView() - executes a parameterized open view on the installing database ********************************************************************/ extern "C" HRESULT WIXAPI WcaExecuteView( __in MSIHANDLE hView, __in MSIHANDLE hRec ) { if (!hView) { return E_INVALIDARG; } AssertSz(hRec, "Use WcaOpenExecuteView() if you don't need to pass in a record"); HRESULT hr = S_OK; UINT er = ::MsiViewExecute(hView, hRec); ExitOnWin32Error(er, hr, "failed to execute view"); LExit: return hr; }
/******************************************************************** RegOpen - opens a registry key. *********************************************************************/ extern "C" HRESULT DAPI RegOpen( __in HKEY hkRoot, __in_z LPCWSTR wzSubKey, __in DWORD dwAccess, __out HKEY* phk ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; er = vpfnRegOpenKeyExW(hkRoot, wzSubKey, 0, dwAccess, phk); if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er)) { ExitFunction1(hr = E_FILENOTFOUND); } ExitOnWin32Error(er, hr, "Failed to open registry key."); LExit: return hr; }
static HRESULT InitializeComSecurity() { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; SECURITY_DESCRIPTOR sd = {0}; EXPLICIT_ACCESS ea[5] = {0}; ACL* pAcl = NULL; ULONGLONG rgSidBA[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; ULONGLONG rgSidLS[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; ULONGLONG rgSidNS[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; ULONGLONG rgSidPS[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; ULONGLONG rgSidSY[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; DWORD cbSid = 0; // Create the security descriptor explicitly as follows because // CoInitializeSecurity() will not accept the relative security descriptors // returned by ConvertStringSecurityDescriptorToSecurityDescriptor(). // // The result is a security descriptor that is equivalent to the following // security descriptor definition language (SDDL) string: // // O:BAG:BAD:(A;;0x1;;;LS)(A;;0x1;;;NS)(A;;0x1;;;PS)(A;;0x1;;;SY)(A;;0x1;;;BA) // // Initialize the security descriptor. if (!::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { ExitWithLastError(hr, "Failed to initialize security descriptor for system restore."); } // Create an administrator group security identifier (SID). cbSid = sizeof(rgSidBA); if (!::CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, rgSidBA, &cbSid)) { ExitWithLastError(hr, "Failed to create administrator SID for system restore."); } // Create a local service security identifier (SID). cbSid = sizeof(rgSidLS); if (!::CreateWellKnownSid(WinLocalServiceSid, NULL, rgSidLS, &cbSid)) { ExitWithLastError(hr, "Failed to create local service SID for system restore."); } // Create a network service security identifier (SID). cbSid = sizeof(rgSidNS); if (!::CreateWellKnownSid(WinNetworkServiceSid, NULL, rgSidNS, &cbSid)) { ExitWithLastError(hr, "Failed to create network service SID for system restore."); } // Create a personal account security identifier (SID). cbSid = sizeof(rgSidPS); if (!::CreateWellKnownSid(WinSelfSid, NULL, rgSidPS, &cbSid)) { ExitWithLastError(hr, "Failed to create self SID for system restore."); } // Create a local service security identifier (SID). cbSid = sizeof(rgSidSY); if (!::CreateWellKnownSid(WinLocalSystemSid, NULL, rgSidSY, &cbSid)) { ExitWithLastError(hr, "Failed to create local system SID for system restore."); } // Setup the access control entries (ACE) for COM. COM_RIGHTS_EXECUTE and // COM_RIGHTS_EXECUTE_LOCAL are the minimum access rights required. ea[0].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; ea[0].grfAccessMode = SET_ACCESS; ea[0].grfInheritance = NO_INHERITANCE; ea[0].Trustee.pMultipleTrustee = NULL; ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea[0].Trustee.ptstrName = (LPTSTR)rgSidBA; ea[1].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; ea[1].grfAccessMode = SET_ACCESS; ea[1].grfInheritance = NO_INHERITANCE; ea[1].Trustee.pMultipleTrustee = NULL; ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea[1].Trustee.ptstrName = (LPTSTR)rgSidLS; ea[2].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; ea[2].grfAccessMode = SET_ACCESS; ea[2].grfInheritance = NO_INHERITANCE; ea[2].Trustee.pMultipleTrustee = NULL; ea[2].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[2].Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea[2].Trustee.ptstrName = (LPTSTR)rgSidNS; ea[3].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; ea[3].grfAccessMode = SET_ACCESS; ea[3].grfInheritance = NO_INHERITANCE; ea[3].Trustee.pMultipleTrustee = NULL; ea[3].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; ea[3].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[3].Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea[3].Trustee.ptstrName = (LPTSTR)rgSidPS; ea[4].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; ea[4].grfAccessMode = SET_ACCESS; ea[4].grfInheritance = NO_INHERITANCE; ea[4].Trustee.pMultipleTrustee = NULL; ea[4].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; ea[4].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[4].Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea[4].Trustee.ptstrName = (LPTSTR)rgSidSY; // Create an access control list (ACL) using this ACE list. er = ::SetEntriesInAcl(countof(ea), ea, NULL, &pAcl); ExitOnWin32Error(er, hr, "Failed to create ACL for system restore."); // Set the security descriptor owner to Administrators. if (!::SetSecurityDescriptorOwner(&sd, rgSidBA, FALSE)) { ExitWithLastError(hr, "Failed to set administrators owner for system restore."); } // Set the security descriptor group to Administrators. if (!::SetSecurityDescriptorGroup(&sd, rgSidBA, FALSE)) { ExitWithLastError(hr, "Failed to set administrators group access for system restore."); } // Set the discretionary access control list (DACL) to the ACL. if (!::SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) { ExitWithLastError(hr, "Failed to set DACL for system restore."); } // Note that an explicit security descriptor is being passed in. hr= ::CoInitializeSecurity(&sd, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL, NULL); ExitOnFailure(hr, "Failed to initialize COM security for system restore."); LExit: if (pAcl) { ::LocalFree(pAcl); } return hr; }
/****************************************************************** WixWaitForEvent - entry point for WixWaitForEvent custom action which waits for either the WixWaitForEventFail or WixWaitForEventSucceed named auto reset events. Signaling the WixWaitForEventFail event will return ERROR_INSTALL_FAILURE or signaling the WixWaitForEventSucceed event will return ERROR_SUCCESS. Both events are declared in the Global\ namespace. ********************************************************************/ extern "C" UINT __stdcall WixWaitForEvent( __in MSIHANDLE hInstall ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; HWND hMessageWindow = NULL; LPCWSTR wzSDDL = L"D:(A;;GA;;;WD)"; OS_VERSION version = OS_VERSION_UNKNOWN; DWORD dwServicePack = 0; PSECURITY_DESCRIPTOR pSD = NULL; SECURITY_ATTRIBUTES sa = { }; HANDLE rghEvents[2]; hr = WcaInitialize(hInstall, "WixWaitForEvent"); ExitOnFailure(hr, "Failed to initialize."); // Create a window to prevent shutdown requests. hr = CreateMessageWindow(&hMessageWindow); ExitOnFailure(hr, "Failed to create message window."); // If running on Vista/2008 or newer use integrity enhancements. OsGetVersion(&version, &dwServicePack); if (OS_VERSION_VISTA <= version) { // Add SACL to allow Everyone to signal from a medium integrity level. wzSDDL = L"D:(A;;GA;;;WD)S:(ML;;NW;;;ME)"; } // Create the security descriptor and attributes for the events. if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(wzSDDL, SDDL_REVISION_1, &pSD, NULL)) { ExitWithLastError(hr, "Failed to create the security descriptor for the events."); } sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = pSD; sa.bInheritHandle = FALSE; rghEvents[0] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventFail"); ExitOnNullWithLastError(rghEvents[0], hr, "Failed to create the Global\\WixWaitForEventFail event."); rghEvents[1] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventSucceed"); ExitOnNullWithLastError(rghEvents[1], hr, "Failed to create the Global\\WixWaitForEventSucceed event."); // Wait for either of the events to be signaled and handle accordingly. er = ::WaitForMultipleObjects(countof(rghEvents), rghEvents, FALSE, INFINITE); switch (er) { case WAIT_OBJECT_0 + 0: er = ERROR_INSTALL_FAILURE; break; case WAIT_OBJECT_0 + 1: er = ERROR_SUCCESS; break; default: ExitOnWin32Error(er, hr, "Unexpected failure."); } LExit: ReleaseHandle(rghEvents[1]); ReleaseHandle(rghEvents[0]); if (pSD) { ::LocalFree(pSD); } if (hMessageWindow) { CloseMessageWindow(hMessageWindow); } if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
/******************************************************************** RegDelete - deletes a registry key (and optionally it's whole tree). *********************************************************************/ extern "C" HRESULT DAPI RegDelete( __in HKEY hkRoot, __in_z LPCWSTR wzSubKey, __in REG_KEY_BITNESS kbKeyBitness, __in BOOL fDeleteTree ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; LPWSTR pszEnumeratedSubKey = NULL; LPWSTR pszRecursiveSubKey = NULL; HKEY hkKey = NULL; REGSAM samDesired = 0; if (fDeleteTree) { hr = RegOpen(hkRoot, wzSubKey, KEY_READ, &hkKey); if (E_FILENOTFOUND == hr) { ExitFunction1(hr = S_OK); } ExitOnFailure1(hr, "Failed to open this key for enumerating subkeys", wzSubKey); // Yes, keep enumerating the 0th item, because we're deleting it every time while (E_NOMOREITEMS != (hr = RegKeyEnum(hkKey, 0, &pszEnumeratedSubKey))) { ExitOnFailure(hr, "Failed to enumerate key 0"); hr = PathConcat(wzSubKey, pszEnumeratedSubKey, &pszRecursiveSubKey); ExitOnFailure2(hr, "Failed to concatenate paths while recursively deleting subkeys. Path1: %ls, Path2: %ls", wzSubKey, pszEnumeratedSubKey); hr = RegDelete(hkRoot, pszRecursiveSubKey, kbKeyBitness, fDeleteTree); ExitOnFailure1(hr, "Failed to recursively delete subkey: %ls", pszRecursiveSubKey); } hr = S_OK; } if (!vfRegInitialized && REG_KEY_DEFAULT != kbKeyBitness) { hr = E_INVALIDARG; ExitOnFailure(hr, "RegInitialize must be called first in order to RegDelete() a key with non-default bit attributes!"); } switch (kbKeyBitness) { case REG_KEY_32BIT: samDesired = KEY_WOW64_32KEY; break; case REG_KEY_64BIT: samDesired = KEY_WOW64_64KEY; break; case REG_KEY_DEFAULT: // Nothing to do break; } if (NULL != vpfnRegDeleteKeyExW) { er = vpfnRegDeleteKeyExW(hkRoot, wzSubKey, samDesired, 0); if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er)) { ExitFunction1(hr = E_FILENOTFOUND); } ExitOnWin32Error(er, hr, "Failed to delete registry key (ex)."); } else { er = vpfnRegDeleteKeyW(hkRoot, wzSubKey); if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er)) { ExitFunction1(hr = E_FILENOTFOUND); } ExitOnWin32Error(er, hr, "Failed to delete registry key."); } LExit: ReleaseRegKey(hkKey); ReleaseStr(pszEnumeratedSubKey); ReleaseStr(pszRecursiveSubKey); return hr; }
HRESULT WIXAPI QuietExecEx( __inout_z LPWSTR wzCommand, __in DWORD dwTimeout, __in BOOL fLogCommand, __in BOOL fLogOutput ) { HRESULT hr = S_OK; PROCESS_INFORMATION oProcInfo; STARTUPINFOW oStartInfo; DWORD dwExitCode = ERROR_SUCCESS; HANDLE hOutRead = INVALID_HANDLE_VALUE; HANDLE hOutWrite = INVALID_HANDLE_VALUE; HANDLE hErrWrite = INVALID_HANDLE_VALUE; HANDLE hInRead = INVALID_HANDLE_VALUE; HANDLE hInWrite = INVALID_HANDLE_VALUE; memset(&oProcInfo, 0, sizeof(oProcInfo)); memset(&oStartInfo, 0, sizeof(oStartInfo)); // Create output redirect pipes hr = CreatePipes(&hOutRead, &hOutWrite, &hErrWrite, &hInRead, &hInWrite); ExitOnFailure(hr, "Failed to create output pipes"); // Set up startup structure oStartInfo.cb = sizeof(STARTUPINFOW); oStartInfo.dwFlags = STARTF_USESTDHANDLES; oStartInfo.hStdInput = hInRead; oStartInfo.hStdOutput = hOutWrite; oStartInfo.hStdError = hErrWrite; // Log command if we were asked to do so if (fLogCommand) { WcaLog(LOGMSG_VERBOSE, "%ls", wzCommand); } #pragma prefast(suppress:25028) if (::CreateProcessW(NULL, wzCommand, // command line NULL, // security info NULL, // thread info TRUE, // inherit handles ::GetPriorityClass(::GetCurrentProcess()) | CREATE_NO_WINDOW, // creation flags NULL, // environment NULL, // cur dir &oStartInfo, &oProcInfo)) { ReleaseFile(oProcInfo.hThread); // Close child output/input handles so it doesn't hang ReleaseFile(hOutWrite); ReleaseFile(hErrWrite); ReleaseFile(hInRead); // Log output if we were asked to do so; otherwise just read the output handle HandleOutput(fLogOutput, hOutRead); // Wait for everything to finish ::WaitForSingleObject(oProcInfo.hProcess, dwTimeout); if (!::GetExitCodeProcess(oProcInfo.hProcess, &dwExitCode)) { dwExitCode = ERROR_SEM_IS_SET; } ReleaseFile(hOutRead); ReleaseFile(hInWrite); ReleaseFile(oProcInfo.hProcess); } else { ExitOnLastError(hr, "Command failed to execute."); } ExitOnWin32Error(dwExitCode, hr, "Command line returned an error."); 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; HANDLE hToken = NULL; TOKEN_PRIVILEGES priv = { 0 }; TOKEN_PRIVILEGES* pPrevPriv = NULL; DWORD cbPrevPriv = 0; DWORD er = ERROR_SUCCESS; BOOL fAdjustedPrivileges = FALSE; BOOL fElevated = FALSE; ProcElevated(::GetCurrentProcess(), &fElevated); // Must be elevated to adjust process privileges if (fElevated) { // Adding SeDebugPrivilege in the event that the process targeted by ::OpenProcess() is in a another user context. if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) { ExitWithLastError(hr, "Failed to get process token."); } priv.PrivilegeCount = 1; priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!::LookupPrivilegeValueW(NULL, L"SeDebugPrivilege", &priv.Privileges[0].Luid)) { ExitWithLastError(hr, "Failed to get debug privilege LUID."); } cbPrevPriv = sizeof(TOKEN_PRIVILEGES); pPrevPriv = static_cast<TOKEN_PRIVILEGES*>(MemAlloc(cbPrevPriv, TRUE)); ExitOnNull(pPrevPriv, hr, E_OUTOFMEMORY, "Failed to allocate memory for empty previous privileges."); if (!::AdjustTokenPrivileges(hToken, FALSE, &priv, cbPrevPriv, pPrevPriv, &cbPrevPriv)) { LPVOID pv = MemReAlloc(pPrevPriv, cbPrevPriv, TRUE); ExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to allocate memory for previous privileges."); pPrevPriv = static_cast<TOKEN_PRIVILEGES*>(pv); if (!::AdjustTokenPrivileges(hToken, FALSE, &priv, cbPrevPriv, pPrevPriv, &cbPrevPriv)) { ExitWithLastError(hr, "Failed to get debug privilege LUID."); } } fAdjustedPrivileges = TRUE; } hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId); if (hProcess) { if (!::GetProcessTimes(hProcess, &CreationTime, &ExitTime, &KernelTime, &UserTime)) { ExitWithLastError(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."); } else { er = ::GetLastError(); if (ERROR_ACCESS_DENIED == er) { // OpenProcess will fail when not elevated and the target process is in another user context. Let the caller log and continue. hr = E_NOTFOUND; } else { ExitOnWin32Error(er, hr, "Failed to open the process ID %d.", dwProcessId); } } LExit: if (hProcess) { ::CloseHandle(hProcess); } if (fAdjustedPrivileges) { ::AdjustTokenPrivileges(hToken, FALSE, pPrevPriv, 0, NULL, NULL); } ReleaseMem(pPrevPriv); ReleaseHandle(hToken); if (fLocked) { ::LeaveCriticalSection(&pSession->cs); } return hr; }