Shell Execute将Window带到前面

时间:2013-06-18 10:09:30

标签: c++ c windows

我正在使用此函数从我的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);
}

更新代码:

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);
}

1 个答案:

答案 0 :(得分:5)

Windows不允许进程抢夺前台窗口,除非用户启动它们。这是为了避免说服用户将他们的银行详细信息键入错误的窗口。但是,当前前台进程可以将权限传递给另一个进程来执行此操作。有关详细信息,请参阅AllowSetForegroundWindow。为此,您必须为将成为前台的进程提供进程ID,而ShellExecute不提供该进程ID。但是,如果切换到使用ShellExecuteEx,则可以从SHELLEXECUTEINFO结构上的hProcess成员获取此内容。

然后,您可以在新流程中调用SetForegroundWindow,然后才允许。否则它只是在任务栏上开始闪烁。

修改

如果您的初始应用程序是前台应用程序并且您从该应用程序启动子进程,那么子进程应该自动变为前景,如这些函数的文档中所述。

下面是我们如何选择启用并将另一个应用程序设置为前台窗口的示例。在这种情况下,它只是创建一个文本文件,并使用open动词调用ShellExecuteEx。我们必须等待子进程继续运行并准备好窗口,然后我们可以从进程ID找到窗口并赋予它权限并将其窗口设置为前台。在这种情况下,启动的记事本(或任何是.txt文件的“开放”动词)无论如何都将是前台。如果您在我们通常放入子进程ID的进程的进程ID中单独运行记事本进程和substiture,那么我们可以使另一个进程成为前台 - 一个不属于我们进程的进程树。这可以使用带有cl -nologo -W3 -O2 -MD fg_test.cpp的Visual C ++进行编译,以生成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);
}