我想从另一个人那里调用Win32应用程序,我该怎么办?

时间:2014-07-26 12:06:01

标签: c++ winapi visual-c++ visual-studio-2012

我有一个创建一个简单窗口的Win32应用程序,我需要从另一个程序(cryengine)调用该程序/窗口。我的应用从int WINAPI WinMain(...)开始。我该怎么做才能实现这一目标?动态库,.exe,静态库?

我原计划从我的其他程序调用.exe。使用.dll会更好吗?

2 个答案:

答案 0 :(得分:2)

您不必使用DLL或静态库方式从其他程序启动程序。

使用CreateProcessShellExecuteShellExecuteEx

如果您的程序可能已在运行,那么您可以使用FindWindow获取应用程序窗口并使用SendMessage发送一些消息,告诉应用程序激活该窗口。

然而,找到&激活(SetForegroundWindow)只会闪烁任务栏中的窗口按钮,以引起用户的注意。这是由Windows完成的,因此其他应用程序无法中断并导致可用性问题。

答案 1 :(得分:1)

使用DLL的主要原因是在与EXE相同的进程中托管它。如果您想要启动另一个程序,那么您想要启动另一个EXE。

虽然原则上这很容易,但这可能带来潜在的问题。

首先,CreateProcess是启动另一个EXE的最低级别方式,它可以工作,但前提是目标程序在相同的权限级别运行。对于Win32应用程序,您应该使用ShellExecuteEx。确保当前正确的工作目录也存在问题。

以下是您可以使用的相当强大的代码片段:

BOOL Autorun::SpawnProcess( const WCHAR* szExePath, const WCHAR* szExeArgs )
{
    if( !szExePath )
        return FALSE;

    // NOTE: szExeArgs can be NULL.

    // Get working directory from executable path.    
    WCHAR szDirectory[MAX_PATH];
    wcscpy_s( szDirectory, szExePath );
    PathRemoveFileSpec( szDirectory );

    // ShellExecute or ShellExecuteEx must be used instead of CreateProcess
    // to permit the shell to display a UAC prompt asking for consent to
    // elevate when the target executable's manifest specifies a run level
    // of "requireAdministrator".
    //
    // You can only use CreateProcess if you know that the application you
    // are spawning will be at the same run level as the current process.
    // Otherwise, you will receive ERROR_ACCESS_DENIED if the elevation
    // consent could not be obtained.
    SHELLEXECUTEINFO info;
    ZeroMemory( &info, sizeof( info ) );
    info.cbSize = sizeof( info );
    info.lpVerb = L"open";
    info.fMask = SEE_MASK_FLAG_NO_UI;
    info.lpFile = szExePath;
    info.lpParameters = szExeArgs;
    info.lpDirectory = szDirectory;
    info.nShow = SW_SHOW;
    if( !ShellExecuteEx( &info ) )
        return FALSE;

    return TRUE;
}

此处的另一个挑战是,如果您想尝试在“工作”中跟踪子进程。一些发射器试图使用“作业对象”来跟踪子进程本身可能启动的所有内容。特别的问题是LAUNCHER - >目标计划 - > REAL PROGRAM和原始TARGET PROGRAM退出。问题是Windows程序兼容性助手隐式使用“作业对象”,并且您无法将进程添加到多个作业。您可以确保创建的流程未添加到PCA作业的唯一可靠方法是确保您使用的所有程序都具有正确的清单元素。有关详细信息,请参阅此blog post

对于仅关心子进程本身的简化情况,您可以使用类似此代码段的内容:

BOOL Autorun::SpawnProcessAndWait( const WCHAR *szExePath, const WCHAR *szExeArgs, DWORD *pdwExitCode )
{
    if( !szExePath )
        return FALSE;

    // NOTE: szExeArgs can be NULL.
    // NOTE: pExitCode can be NULL.

    // Get working directory from executable path.    
    WCHAR szDirectory[MAX_PATH];
    wcscpy_s( szDirectory, szExePath );
    PathRemoveFileSpec( szDirectory );

    // See SpawnProcess for information why ShellExecute or ShellExecuteEx
    // must be used instead of CreateProcess.
    SHELLEXECUTEINFO info;
    ZeroMemory( &info, sizeof( info ) );
    info.cbSize = sizeof( info );
    info.lpVerb = L"open";
    info.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS;
    info.lpFile = szExePath;
    info.lpParameters = szExeArgs;
    info.lpDirectory = szDirectory;
    info.nShow = SW_SHOW;
    if( !ShellExecuteEx( &info ) )
        return FALSE;

    // Wait for process to finish.
    WaitForSingleObject( info.hProcess, INFINITE );

    // Return exit code from process, if requested by caller.
    if( pdwExitCode )
        GetExitCodeProcess( info.hProcess, pdwExitCode );

    CloseHandle( info.hProcess );
    return TRUE;
}
BTW,这两个代码片段都来自传统的DirectX SDK(2010年6月)样本“Autorun”。