c++ - 启动另一个应用程序作为弹出窗口

标签 c++ winapi mfc

我有一个MFC应用程序,它会作为弹出窗口启动其他(通用窗口,黑盒)应用程序,并等待它们完成。 parent 与 child 之间不需要交流/互动,应该避免。仅需要“子应用程序表现为父应用程序的模式对话框”。
正确的方法是什么?

可以在以下位置看到“启动另一个应用程序作为子窗口”的示例:Activating an application as a child/popup of another application导致http://www.codeproject.com/Articles/18724/Hosting-exe-applications-into-a-dialog(这不是我想要的,我想要模式弹出行为)

为简单起见,我们可以假设启动和启动的应用程序都具有单个“堆栈”窗口(一个带有模式对话框的主窗口可以具有自己的模式对话框)。

我当前的伪代码(为简单起见,省略了错误处理和回调函数)

//get the current MFC dialog of launcher program we are launching the other app from
parentWnd = AfxGetMainWnd()->GetActiveWindow(); 
parentHwnd = parentWnd->GetSafeHwnd(); //HWND

// launch child and retrieve basic info from PROCESSINFO structure
CreateProcess(childExecutable); // => childProcessHandle, childProcessId 

//get the "main" window of child application
EnumWindows(EnumProc_That_Retrieves_TopLevelWindow_With_childProcessId); // => childHwnd

//link the child window as popup
SetWindowLong(childHwnd, GW_OWNER, parentHwnd);

//disable input into parent window
parentWnd->EnableWindow(FALSE);

//remove taskbar entry for child
SetWindowLong(child, GWL_EXSTYLE, GetWindowLong(child, GWL_EXSTYLE)&~WS_APPWINDOW);

//now keep waiting for the child process termination and process parent messages (e.g. WM_PAINT)
while (MsgWaitForMultipleObjects(childProcessHandle and process QS_ALLINPUT) {
   while (PeekMessage(PM_NOREMOVE)) AfxGetApp()->PumpMessage();
}

//re-enable input into parent window
parentWnd->EnableWindow(TRUE);

现在,我的较小问题是前景视觉样式(例如,前景=蓝色标题栏与背景=灰色标题栏)和键盘输入焦点行为:

1)最初删除子级WS_APPWINDOW样式将从子级应用程序中删除前景视觉和输入焦点。在这一点上,没有应用程序具有焦点。

2)当用户单击任何父应用程序窗口时,将切换子前景的视觉样式。键盘焦点保留在子应用程序中。
例如:子应用具有前景+焦点->第一次单击父项->子失去前景,保持焦点->单击父项第二次->子获得前景,保持焦点->等等。

预期的行为(“常规” MFC弹出窗口会执行的操作):
子应用具有前景+焦点->单击父项->子标题栏短暂闪烁并保留前景+焦点
子应用程序没有前景+焦点->单击父项->子标题栏获得前景和键盘焦点

现在这是最糟糕的问题:
3)我遇到了一个MFC应用程序,当单独启动该应用程序时,用户可以打开“模式对话框堆栈” A-> B-> C-> D-> E,Windows的所有权与此完全匹配(E由D拥有,D由C等拥有)。但是,如果我从MFC应用程序(M)中打开它,则所有权看起来就像M-> A-> B-> C,D,E(C,D,E全部由B拥有,B由A拥有,A拥有通过我的应用窗口M)。这导致“不支持堆栈”的http://blogs.msdn.com/b/oldnewthing/archive/2005/02/24/379635.aspx问题。
当我删除SetWindowLong(childHwnd, GW_OWNER, parentHwnd)时,此行为消失了,因此弄乱所有权可能会触发子应用程序的有害行为,但是如果没有这样做,我似乎无法保证模式对话框的前提是“一个位于另一个之上”。

因此,还有一个大问题:执行此任务并避免出现我所描述的问题的正确方法是什么?

编辑

到目前为止的解决方案

我们必须避免像@mfc所建议的那样弄乱所有者拥有的结构,因此,任务基本上是以另一种方式为我们的父子对重新实现窗口管理器的这一方面。我已经使用Windows Hooks建立了解决方案的原型(prototype)。但是,完成它似乎相当复杂且乏味,因此我决定采用另一种原始方法(截止日期,截止日期)。为了举例,我将描述两者的基本思想。

挂钩解决方案

免责声明:只有父焦点挂钩已被确认可以正常工作,其余都是理论上的努力。也许有一个更清洁/更轻量级的实现,可能会在实际的Windows窗口管理器实现中获得启发(记住整个要点是避免设置GW_OWNER,该功能对于窗口管理器来说很好用,但是会破坏子黑盒应用程序的行为)。
  • 在父应用程序循环中(间歇地)不使用Windows时向父消息循环中添加一些“忽略子项运行时的输入”
  • 为每个调用
  • 创建共享内存和结构来保存[parentPid,parentHwnd,childPid]
  • 为[父非自有窗口列表,其UI线程,子钩子(Hook)]创建DLL实例内存
  • 将系统范围内的钩子(Hook)连接到WH_CBT-> HCBT_CREATEWND,如果childPid匹配,则在列表中注册窗口,为该子线程注册另一个钩子(Hook)HCBT_ACTIVATE,如果尚未存在
  • 整个系统范围内的
  • 钩子(Hook)到WH_CBT-> HCBT_DESTROYWND,如果childPid匹配,则注销列表中的窗口,如果这是给定线程的最后一个窗口,则注销HCBT_ACTIVATE钩子(Hook),如果这是子应用程序的最后一个窗口,则取消钩子(Hook)父HCBT_ACTIVATE钩子(Hook)并集中父
  • li
  • 父线程HCBT_ACTIVATE钩子(Hook)阻止获得焦点,而是使用EnumWindows聚焦子应用程序。
  • 子线程HCBT_ACTIVATE钩子(Hook)可以防止焦点丢失(如果目标是父对象),请以Z顺序
  • 将父对象保持在子对象下方
  • 创建子进程已挂起,仅在钩子(Hook)就位时恢复
  • 记得在所有地方都摘钩

  • 原始方法

    基本上在先前解决方案的第一点上应用了焦点开关,当单击父对象时,它会在子对象之间来回转移时闪烁闪烁。
  • “在运行子级时忽略输入”(丢弃各种父级消息循环中的各种消息)(丢弃子级运行时的父级消息循环),请使用EnumWindows代替子级应用程序。
  • 最佳答案

    更改不属于您的其他窗口的父子关系非常棘手,并且容易出错。
    如果启动器程序与启动的程序没有通信,并且主要目的是避免与启动器有任何UI,则可以使用ShowWindow(SW_HIDE)在成功启动辅助程序后简单地隐藏启动器。
    在隐藏模式下,它将继续监视启动的程序,并在辅助程序终止时取消隐藏自身。

    关于c++ - 启动另一个应用程序作为弹出窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11988863/

    相关文章:

    c++ - 观察 QStringList 的新项目

    c++ - 如何使用 CLANG 作为解析器并使用 Python 作为脚本语言来解析 C++ 代码中的宏?

    c++ - 两个整数的异或可以超出界限吗?

    c++ - 迭代类中的每个对象

    c# - 跟踪 WMI Defrag Class 的进度

    WPF 应用程序消息循环和 PostThreadMessage

    c++ - 为什么 C++ try/catch 没有捕获到 "pure virtual call"异常?

    c++ - 在C++/MFC中停止和启动DirectX声音合成器时弹出/单击

    mfc - CString 总是以 null 结尾吗?

    c++ - 如何处理 ATLMFC 包含文件中的指针截断?