/****************************************************************** SendApplicationMessage - helper function to iterate through the processes for the specified application and send all applicable process Ids a message and give them time to process the message. ******************************************************************/ void SendApplicationMessage( __in LPCWSTR wzApplication, __in DWORD dwMessageId, __in DWORD dwTimeout ) { DWORD *prgProcessIds = NULL; DWORD cProcessIds = 0, iProcessId; HRESULT hr = S_OK; WcaLog(LOGMSG_VERBOSE, "Checking App: %ls ", wzApplication); hr = ProcFindAllIdsFromExeName(wzApplication, &prgProcessIds, &cProcessIds); if (SUCCEEDED(hr) && 0 < cProcessIds) { WcaLog(LOGMSG_VERBOSE, "App: %ls found running, %d processes, attempting to send message.", wzApplication, cProcessIds); for (iProcessId = 0; iProcessId < cProcessIds; ++iProcessId) { SendProcessMessage(prgProcessIds[iProcessId], dwMessageId, dwTimeout); } ProcWaitForIds(prgProcessIds, cProcessIds, dwTimeout); } ReleaseMem(prgProcessIds); }
/****************************************************************** 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; }
/****************************************************************** SetRunningProcessProperty - helper function that sets the specified property if there are any instances of the specified executable running. Useful to show custom UI to ask for shutdown. ******************************************************************/ void SetRunningProcessProperty( __in LPCWSTR wzApplication, __in LPCWSTR wzProperty ) { DWORD *prgProcessIds = NULL; DWORD cProcessIds = 0; HRESULT hr = S_OK; WcaLog(LOGMSG_VERBOSE, "Checking App: %ls ", wzApplication); hr = ProcFindAllIdsFromExeName(wzApplication, &prgProcessIds, &cProcessIds); if (SUCCEEDED(hr) && 0 < cProcessIds) { WcaLog(LOGMSG_VERBOSE, "App: %ls found running, %d processes, setting '%ls' property.", wzApplication, cProcessIds, wzProperty); WcaSetIntProperty(wzProperty, cProcessIds); } ReleaseMem(prgProcessIds); }
/******************************************************************** RmuAddProcessesByName - Adds all processes by the given process name to the Restart Manager Session. You should call this multiple times as necessary before calling RmuRegisterResources. ********************************************************************/ extern "C" HRESULT DAPI RmuAddProcessesByName( __in PRMU_SESSION pSession, __in_z LPCWSTR wzProcessName ) { HRESULT hr = S_OK; DWORD *pdwProcessIds = NULL; DWORD cProcessIds = 0; BOOL fNotFound = FALSE; hr = ProcFindAllIdsFromExeName(wzProcessName, &pdwProcessIds, &cProcessIds); ExitOnFailure(hr, "Failed to enumerate all the processes by name %ls.", wzProcessName); for (DWORD i = 0; i < cProcessIds; ++i) { hr = RmuAddProcessById(pSession, pdwProcessIds[i]); if (E_NOTFOUND == hr) { // RmuAddProcessById returns E_NOTFOUND when this setup is not elevated and OpenProcess returned access denied (target process running under another user account). fNotFound = TRUE; } else { ExitOnFailure(hr, "Failed to add process %ls (%d) to the Restart Manager session.", wzProcessName, pdwProcessIds[i]); } } // If one or more calls to RmuAddProcessById returned E_NOTFOUND, then return E_NOTFOUND even if other calls succeeded, so that caller can log the issue. if (fNotFound) { hr = E_NOTFOUND; } LExit: ReleaseMem(pdwProcessIds); return hr; }
/******************************************************************** RmuAddProcessesByName - Adds all processes by the given process name to the Restart Manager Session. You should call this multiple times as necessary before calling RmuRegisterResources. ********************************************************************/ extern "C" HRESULT DAPI RmuAddProcessesByName( __in PRMU_SESSION pSession, __in_z LPCWSTR wzProcessName ) { HRESULT hr = S_OK; DWORD *pdwProcessIds = NULL; DWORD cProcessIds = 0; hr = ProcFindAllIdsFromExeName(wzProcessName, &pdwProcessIds, &cProcessIds); ExitOnFailure1(hr, "Failed to enumerate all the processes by name %ls.", wzProcessName); for (DWORD i = 0; i < cProcessIds; ++i) { hr = RmuAddProcessById(pSession, pdwProcessIds[i]); ExitOnFailure2(hr, "Failed to add process %ls (%d) to the Restart Manager session.", wzProcessName, pdwProcessIds[i]); } LExit: ReleaseMem(pdwProcessIds); return hr; }