我正在使用此功能从我的msi调用可执行文件。但是,可执行文件的窗口隐藏在我的MSI窗口后面。有什么办法可以把它带到前面。很抱歉nobe问题,但是我已经尝试在调用之前最小化所有窗口,ShellExecute但是仍然不能将可执行窗口置于最前面。谢谢
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);
}
Run Code Online (Sandbox Code Playgroud)
更新的代码:
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);
}
Run Code Online (Sandbox Code Playgroud)
Windows不允许进程抢占前台窗口,除非用户启动它们。这是为了避免说服用户在错误的窗口中键入其银行详细信息。但是,当前的前台进程可以将权限传递给另一个进程来执行此操作。有关详细信息,请参见AllowSetForegroundWindow。为此,您必须提供将成为前台的进程的进程ID,而ShellExecute不提供该ID。但是,如果切换到使用ShellExecuteEx,则可以从SHELLEXECUTEINFO结构上的hProcess成员获取此信息。
然后,您可以在新进程中调用SetForegroundWindow,它将被允许。否则,它只会开始在任务栏上闪烁。
编辑
如果您的初始应用程序是前台应用程序,并且从该应用程序启动了子进程,则该子进程应自动成为前台,如这些功能的文档所述。
下面是一个示例,说明如何选择启用和设置另一个应用程序成为前台窗口。在这种情况下,它只是创建一个文本文件,并用open动词调用ShellExecuteEx 。我们必须等待子进程开始并准备好其窗口,然后才能从进程ID中找到该窗口并为其授予权限并将其窗口设置为前台。在这种情况下,启动的记事本(或.txt文件的“打开”动词无论如何)将始终是前台。如果您单独运行一个记事本进程并在该进程的进程ID中替换子项(通常我们将其放在子进程ID中),那么我们可以使另一个进程成为前台进程-该进程不属于进程树。可以使用Visual C ++与cl -nologo -W3 -O2 -MD fg_test.cpp 产生一个fg_test.exe。
#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);
}
Run Code Online (Sandbox Code Playgroud)