Shell Execute brings a window to the forefront

I use this function to call an executable from my msi. However, the window for the executable is hidden behind my MSI window. Is there any way to bring it to the front. Sorry for the nobe question, but I tried to minimize all windows before invoking ShellExecute , but that still doesn't bring the executable window to the forefront. Thanks

 extern "C" UINT __stdcall InstallDrivers(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; HANDLE hFile = INVALID_HANDLE_VALUE; BYTE* pbData = NULL; DWORD cbData = 0; char pwzFilename[MAX_PATH], szDriverType[MAX_PATH], pwzSentinelFilename[MAX_PATH], szIsInstalled[MAX_PATH]; LPWSTR szValueBuf = NULL, szIsHaspInstalled = NULL, szIsSentinelInstalled = NULL; hr = WcaInitialize(hInstall, "InstallDrivers"); ExitOnFailure(hr, "Failed to initialize"); WcaLog(LOGMSG_STANDARD, "Initialized."); WcaLog(LOGMSG_STANDARD, "%s", szValueBuf); CreateDirectory("C:\\Temp", NULL); strcpy_s(pwzFilename, "C:\\Temp\\HASPUserSetup.exe"); hr = ExtractBinary(L"Hasp", &pbData, &cbData); ExitOnFailure(hr, "failed to extract binary data"); if ((hFile = CreateFile(pwzFilename, GENERIC_WRITE,FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { PMSIHANDLE hRecord = MsiCreateRecord(0); MsiRecordSetString(hRecord, 0, TEXT("Could not create new temporary file")); MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord); return ERROR_INSTALL_USEREXIT; } DWORD cbWritten = 0; if ( !WriteFile(hFile, pbData, cbData, &cbWritten, NULL) ) { PMSIHANDLE hRecord = MsiCreateRecord(0); MsiRecordSetString(hRecord, 0, TEXT("Could not write to file")); MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord); return ERROR_INSTALL_USEREXIT; } CloseHandle(hFile); strcpy_s(pwzSentinelFilename, "C:\\Temp\\sentinel_setup.exe"); hr = ExtractBinary(L"Sentinel", &pbData, &cbData); ExitOnFailure(hr, "failed to extract binary data"); if ((hFile = CreateFile(pwzSentinelFilename, GENERIC_WRITE,FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { PMSIHANDLE hRecord = MsiCreateRecord(0); MsiRecordSetString(hRecord, 0, TEXT("Could not create new temporary file")); MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord); return ERROR_INSTALL_USEREXIT; } if ( !WriteFile(hFile, pbData, cbData, &cbWritten, NULL) ) { PMSIHANDLE hRecord = MsiCreateRecord(0); MsiRecordSetString(hRecord, 0, TEXT("Could not write to file")); MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord); return ERROR_INSTALL_USEREXIT; } CloseHandle(hFile); hr = WcaGetProperty(L"DRIVER", &szValueBuf); ExitOnFailure(hr, "failed to get driver info"); wcstombs(szDriverType, szValueBuf, 260); if (strcmp(szDriverType, "Hasp") == 0) { hr = WcaGetProperty(L"SENTINELINSTALLED", &szIsSentinelInstalled); ExitOnFailure(hr, "failed to get driver info"); wcstombs(szIsInstalled, szValueBuf, 260); if (strcmp(szIsInstalled, "Sentinel Protection Installer 7.6.5") == 0) { ShellExecute(NULL, "open", pwzSentinelFilename, NULL, NULL, SW_SHOWNORMAL); } ShellExecute(NULL, "open", pwzFilename, NULL, NULL, SW_SHOWNORMAL); }else { hr = WcaGetProperty(L"HASPINSTALLED", &szIsHaspInstalled); ExitOnFailure(hr, "failed to get driver info"); wcstombs(szIsInstalled, szIsHaspInstalled, 260); if (strcmp(szIsInstalled, "Sentinel Runtime") == 0) { ShellExecute(NULL, "open", pwzFilename, NULL, NULL, SW_SHOWNORMAL); } ShellExecute(NULL, "open", pwzSentinelFilename, NULL, NULL, SW_SHOWNORMAL); } LExit: er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); } 

Updated code:

 extern "C" UINT __stdcall InstallDrivers(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; HANDLE hFile = INVALID_HANDLE_VALUE; BYTE* pbData = NULL; DWORD cbData = 0; char pwzFilename[MAX_PATH], szDriverType[MAX_PATH], pwzSentinelFilename[MAX_PATH], szIsInstalled[MAX_PATH]; LPWSTR szValueBuf = NULL, szIsHaspInstalled = NULL, szIsSentinelInstalled = NULL; SHELLEXECUTEINFO ShExecInfo; ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = NULL; ShExecInfo.hwnd = NULL; ShExecInfo.lpVerb = NULL; ShExecInfo.lpParameters = NULL; ShExecInfo.lpDirectory = NULL; ShExecInfo.nShow = SW_SHOWNORMAL; ShExecInfo.hInstApp = NULL; hr = WcaInitialize(hInstall, "InstallDrivers"); ExitOnFailure(hr, "Failed to initialize"); WcaLog(LOGMSG_STANDARD, "Initialized."); WcaLog(LOGMSG_STANDARD, "%s", szValueBuf); CreateDirectory("C:\\Temp", NULL); strcpy_s(pwzFilename, "C:\\Temp\\HASPUserSetup.exe"); hr = ExtractBinary(L"Hasp", &pbData, &cbData); ExitOnFailure(hr, "failed to extract binary data"); if ((hFile = CreateFile(pwzFilename, GENERIC_WRITE,FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { PMSIHANDLE hRecord = MsiCreateRecord(0); MsiRecordSetString(hRecord, 0, TEXT("Could not create new temporary file")); MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord); return ERROR_INSTALL_USEREXIT; } DWORD cbWritten = 0; if ( !WriteFile(hFile, pbData, cbData, &cbWritten, NULL) ) { PMSIHANDLE hRecord = MsiCreateRecord(0); MsiRecordSetString(hRecord, 0, TEXT("Could not write to file")); MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord); return ERROR_INSTALL_USEREXIT; } CloseHandle(hFile); strcpy_s(pwzSentinelFilename, "C:\\Temp\\sentinel_setup.exe"); hr = ExtractBinary(L"Sentinel", &pbData, &cbData); ExitOnFailure(hr, "failed to extract binary data"); if ((hFile = CreateFile(pwzSentinelFilename, GENERIC_WRITE,FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { PMSIHANDLE hRecord = MsiCreateRecord(0); MsiRecordSetString(hRecord, 0, TEXT("Could not create new temporary file")); MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord); return ERROR_INSTALL_USEREXIT; } if ( !WriteFile(hFile, pbData, cbData, &cbWritten, NULL) ) { PMSIHANDLE hRecord = MsiCreateRecord(0); MsiRecordSetString(hRecord, 0, TEXT("Could not write to file")); MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord); return ERROR_INSTALL_USEREXIT; } CloseHandle(hFile); hr = WcaGetProperty(L"DRIVER", &szValueBuf); ExitOnFailure(hr, "failed to get driver info"); wcstombs(szDriverType, szValueBuf, 260); if (strcmp(szDriverType, "Hasp") == 0) { hr = WcaGetProperty(L"SENTINELINSTALLED", &szIsSentinelInstalled); ExitOnFailure(hr, "failed to get driver info"); wcstombs(szIsInstalled, szValueBuf, 260); if (strcmp(szIsInstalled, "Sentinel Protection Installer 7.6.5") == 0) { AllowSetForegroundWindow(ASFW_ANY); ShExecInfo.lpFile = pwzSentinelFilename; ShellExecuteEx(&ShExecInfo); /*ShellExecute(NULL, "open", pwzSentinelFilename, NULL, NULL, SW_SHOWNORMAL);*/ } AllowSetForegroundWindow(ASFW_ANY); ShExecInfo.lpFile = pwzFilename; ShellExecuteEx(&ShExecInfo); /*ShellExecute(NULL, "open", pwzFilename, NULL, NULL, SW_SHOWNORMAL);*/ }else { hr = WcaGetProperty(L"HASPINSTALLED", &szIsHaspInstalled); ExitOnFailure(hr, "failed to get driver info"); wcstombs(szIsInstalled, szIsHaspInstalled, 260); if (strcmp(szIsInstalled, "Sentinel Runtime") == 0) { AllowSetForegroundWindow(ASFW_ANY); /*ShellExecute(NULL, "open", pwzFilename, NULL, NULL, SW_SHOWNORMAL);*/ ShExecInfo.lpFile = pwzFilename; ShellExecuteEx(&ShExecInfo); } AllowSetForegroundWindow(ASFW_ANY); ShExecInfo.lpFile = pwzSentinelFilename; ShellExecuteEx(&ShExecInfo); /* ShellExecute(NULL, "open", pwzSentinelFilename, NULL, NULL, SW_SHOWNORMAL);*/ } LExit: er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); } 
+4
source share
1 answer

Windows does not allow processes to tear out the foreground window unless the user starts them. It is necessary to avoid such things as persuading the user to enter their bank details in the wrong window. However, the current foreground process may transfer permission to another process for this. See AllowSetForegroundWindow for details . To do this, you must provide a process identifier for the process to become a priority, and ShellExecute does not provide this. However, if you switch to using ShellExecuteEx , you can get this from the hProcess member in the SHELLEXECUTEINFO structure.

You can then call SetForegroundWindow in your new process, and that will be allowed. Otherwise, it just starts flashing on the taskbar.

EDIT

If your source application is a foreground application and you start a subprocess with it, then the subprocess should automatically become the foreground, as described in the documentation for these functions.

Below is an example of how we can choose to enable and install another application as a foreground window. In this case, it simply creates a text file and calls ShellExecuteEx with the verb open . We must wait until the process of the child process begins and prepares its window, and then we can find the window from the process identifier and provide it with permissions and set its window in the foreground. In this case, the running notepad (or something else - your "open" verb for .txt files) will be in any case a priority. If you separately start the process and substitute the notepad in the process identifier for this process, where we usually add the identifier of the child process, we can make another process a priority - one that is not part of our process tree. This can be compiled using Visual C ++ using cl -nologo -W3 -O2 -MD fg_test.cpp to create the fg_test.exe file.

 #define STRICT #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <stdio.h> #include <tchar.h> #include <shellapi.h> #pragma comment(lib, "shell32") #pragma comment(lib, "user32") static void PrintError(LPCTSTR szPrefix, DWORD dwError); static BOOL CALLBACK OnGetWindowByProcess(HWND hwnd, LPARAM lParam); typedef struct { DWORD pid; HWND hwnd; } WINDOWPROCESSINFO; int _tmain(int argc, TCHAR *argv[]) { SHELLEXECUTEINFO sxi = {0}; sxi.cbSize = sizeof(sxi); sxi.nShow = SW_SHOWNORMAL; FILE *fp = NULL; _tfopen_s(&fp, _T("junk.txt"), _T("wt")); _fputts(_T("Example text file\n"), fp); fclose(fp); sxi.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_WAITFORINPUTIDLE; sxi.lpVerb = _T("open"); sxi.lpFile = _T("junk.txt"); if (!ShellExecuteEx(&sxi)) PrintError(_T("ShellExecuteEx"), GetLastError()); else { WINDOWPROCESSINFO info; info.pid = GetProcessId(sxi.hProcess); // SPECIFY PID info.hwnd = 0; AllowSetForegroundWindow(info.pid); EnumWindows(OnGetWindowByProcess, (LPARAM)&info); if (info.hwnd != 0) { SetForegroundWindow(info.hwnd); SetActiveWindow(info.hwnd); } CloseHandle(sxi.hProcess); } return 0; } static BOOL CALLBACK OnGetWindowByProcess(HWND hwnd, LPARAM lParam) { WINDOWPROCESSINFO *infoPtr = (WINDOWPROCESSINFO *)lParam; DWORD check = 0; BOOL br = TRUE; GetWindowThreadProcessId(hwnd, &check); _tprintf(_T("%x %x %x\n"), hwnd, check, infoPtr->pid); if (check == infoPtr->pid) { _tprintf(_T("found window %x for process id %x\n"), hwnd, check); infoPtr->hwnd = hwnd; br = FALSE; } return br; } static void PrintError(LPCTSTR szPrefix, DWORD dwError) { LPTSTR lpsz = NULL; DWORD cch = 0; cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, LANG_NEUTRAL, (LPTSTR)&lpsz, 0, NULL); if (cch < 1) { cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, _T("Code 0x%1!08x!"), 0, LANG_NEUTRAL, (LPTSTR)&lpsz, 0, (va_list*)&dwError); } _ftprintf(stderr, _T("%s: %s"), szPrefix, lpsz); LocalFree((HLOCAL)lpsz); } 
+4
source

Source: https://habr.com/ru/post/1486790/


All Articles