我有一个32位的MFC应用程序,它使用了一个自定义库,如果重新编译成x64,那将是一场噩梦。一般来说,该应用程序实际上并不需要以64位运行,只有一种情况例外--那就是呈现要在对话框窗口中显示的内容,这可以从更大的寻址空间中受益。
因此我的目标是“模仿”CDialog::DoModal
方法但在另一个进程中进行对话。
我将该对话框窗口构建为一个独立的基于x64 MFC对话框的应用程序。它将文件路径作为输入参数,在内部完成所有工作,并返回简单的用户选择:一个月一个月一个月,一个月二个月。
因此,我从我的主父进程执行以下操作:
//Error checks omitted for brevity
CString strCmd = L"D:\\C++\\MyDialogBasedApp.exe";
HWND hParWnd = this->GetSafeHwnd();
SHELLEXECUTEINFO sei = {0};
sei.cbSize = sizeof(sei);
sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_UNICODE | SEE_MASK_NOCLOSEPROCESS;
sei.nShow = SW_SHOW;
sei.lpVerb = _T("open");
sei.lpFile = strCmd.GetBuffer();
sei.hwnd = hParWnd;
BOOL bInitted = SUCCEEDED(::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
ShellExecuteEx(&sei);
DWORD dwProcID = ::GetProcessId(sei.hProcess);
//Try to get main Wnd handle for the child process
HWND hMainChildWnd = NULL;
for(;; ::Sleep(100))
{
hMainChildWnd = getHwndFromProcID(dwProcID);
if(hMainChildWnd)
break;
}
HWND hPrevParWnd = ::SetParent(hMainChildWnd, hParWnd);
if(hPrevParWnd)
{
//Wait for child process to close
::WaitForSingleObject(sei.hProcess, INFINITE);
//Reset parent back
::SetParent(hMainChildWnd, hPrevParWnd);
}
::CloseHandle(sei.hProcess);
if(bInitted)
::CoUninitialize();
其中getHwndFromProcID
取from here。
这是工作,除了以下:
(1)任务栏上有两个图标:一个用于我的主应用程序,一个用于子应用程序。有没有办法不显示子图标?
(2)我可以将焦点从子窗口切换到父窗口,反之亦然。在实际的模式对话框窗口中,当子窗口打开时,不能切换回父窗口。有办法做到这一点吗?
(3)如果我开始与父级交互,它似乎被“挂起”,操作系统甚至会在其标题栏上显示它。
所以我很好奇,有没有办法解决这些问题?
3条答案
按热度按时间ruarlubt1#
1.你需要把自己窗口的指针传递给子进程
1.当你等待子进程退出时,你需要处理windows消息。此处不能接受
WaitForSingleObject
-需要使用MsgWaitForMultipleObjectsEx
1.子进程必须在创建时将您的窗口设置为自身所有者窗口-您不需要调用
SetParent
有了这个,一切都将完美地工作。2在你32位MFC应用程序中,你需要使用下面的代码:
在
MyDialogBasedApp.exe
中,让我们使用MessageBox
作为演示对话框。我们将使用您MFC窗口作为它的第一个参数。使用以下代码:
(1)主应用程序的任务栏上只有一个图标
(2)您不能将焦点从子窗口切换到父窗口,反之亦然所有窗口都作为实际模式对话框窗口工作
(3)父进程未“挂起”,因为它正在处理Windows消息(
MsgWaitForMultipleObjectsEx
)-您的代码已“挂起”,因为您未执行此操作,而是在WaitForSingleObject
中等待0mkxixxg2#
胁迫回应对话方块会执行两项动作,使其成为“胁迫回应”:
我对此进行了一些尝试,虽然您可以手动执行这些操作,但最简单的方法是将父窗口句柄传递给
DialogBox
函数(或MFC中的CDialog
构造函数)。您的子进程可以使用
FindWindow
(或类似的机制)来获取父窗口句柄,并使用该句柄来显示对话框,而不是在父进程中执行ShellExecuteEx
之后的所有工作。lnxxn5zx3#
您尝试的操作无法安全地完成。blog条目Is it legal to have a cross-process parent/child or owner/owned window relationship?解释说,安装跨进程的所有者/被拥有的窗口关系会导致系统调用AttachThreadInput,并且--正如我们所知--AttachThreadInput is like taking two threads and pooling their money into a joint bank account, where both parties need to be present in order to withdraw any money。这会产生非常真实的的死锁可能性。您只能安全地防止这种情况发生。因为至少有一个线程使用了第三方应用程序框架(在本例中为MFC),所以这是禁止的。
由于我们已经确定,您提出的解决方案无法安全地实现,因此您需要寻找替代方案。一种解决方案可能是将工作委派给64位进程进行计算,并将结果传递回32位进程进行显示。