5

この関数を使用して、MSI から実行可能ファイルを呼び出しています。ただし、実行可能ファイルのウィンドウは MSI ウィンドウの後ろに隠れます。前面に出す方法はありますか?

呼び出しの直前にすべてのウィンドウを最小化しようとしまし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);
}
4

1 に答える 1

6

Windows は、ユーザーが起動しない限り、プロセスがフォアグラウンド ウィンドウを奪うことを許可しません。これは、銀行の詳細を間違ったウィンドウに入力するようにユーザーを説得するようなことを避けるためです。ただし、現在のフォアグラウンド プロセスは、これを行うための許可を別のプロセスに渡すことができます。詳細については、 AllowSetForegroundWindowを参照してください。これを行うには、フォアグラウンドになるプロセスのプロセス ID を提供する必要がありますが、ShellExecute はそれを提供しません。ただし、ShellExecuteExの使用に切り替えると、SHELLEXECUTEINFO 構造体の hProcess メンバーからこれを取得できます。

その後、新しいプロセスでSetForegroundWindowを呼び出すことができ、許可されます。そうしないと、タスクバーで点滅し始めます。

編集

最初のアプリケーションがフォアグラウンド アプリケーションであり、そこからサブプロセスを開始する場合、これらの関数のドキュメントで説明されているように、サブプロセスは自動的にフォアグラウンドになります。

以下は、別のアプリケーションを有効にしてフォアグラウンド ウィンドウになるように設定する方法の例です。この場合、テキスト ファイルを作成し、open動詞を指定して ShellExecuteEx を呼び出すだけです。子プロセスが起動し、そのウィンドウが準備されるのを待つ必要があります。その後、プロセス ID からウィンドウを見つけてアクセス許可を与え、そのウィンドウをフォアグラウンドに設定できます。この場合、起動されたメモ帳 (または .txt ファイルの "open" 動詞) はとにかくフォアグラウンドになります。メモ帳のプロセスを個別に実行し、そのプロセスのプロセス ID を代入すると、通常は子プロセス ID を挿入すると、別のプロセス (プロセス ツリーの一部ではないプロセス) をフォアグラウンドにすることができます。これは、Visual C++ を使用してコンパイルできます。cl -nologo -W3 -O2 -MD fg_test.cppfg_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);
}
于 2013-06-18T10:22:54.700 に答える