因此,我的目标是“模仿”CDialog :: DoModal方法,但针对另一个进程中的对话框窗口。
我将该对话框窗口构建为独立的x64 MFC基于对话框的应用程序。它以文件路径作为输入参数,内部完成所有工作,并返回简单的用户选择:OK,Cancel。
因此,我从我的主要父进程执行以下操作:
//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
函数来自这个链接。
这个方法基本上可以实现它的功能,但有以下问题:
(1)任务栏上会有两个图标:一个是主应用程序的,另一个是子应用程序的。有没有办法不显示子级图标?
(2)我可以从子窗口切换到父窗口,反之亦然。在实际模式对话框窗口中,当子窗口打开时,不能返回到父窗口。是否有办法解决这个问题?
(3)如果我开始与父窗口交互,它似乎会"挂起",操作系统甚至会在标题栏上显示它。
因此,我想知道是否有办法解决所有这些问题?
PeekMessage
循环?或者你严格遵循Win32?(2) 你的方法不能从任务栏中删除子进程的图标。要在MyDialogBasedApp.exe
进程中实现这一点,你需要在WM_INITDIALOG
处理程序中从自身窗口中删除WS_EX_APPWINDOW
扩展样式。 - c00000fdwhile (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) App->PumpMessage();
替代while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){..}
。 2) 在我的测试中,我使用了不会在任务栏上创建图标的 MessageBoxW 对话框。我没有使用 WS_EX_APPWINDOW。当然,我不知道您在MyDialogBasedApp.exe
中使用了什么。 - RbMmMessageBox
,那么在其运行时,内部消息循环将在MessageBox
中执行而不是在你的 MFC 循环中执行。主 UI 线程必须永久调用PeekMessage
或GetMessage
来处理 Windows 消息,否则 UI 将挂起。 - RbMm