gpt4 book ai didi

c++ - 如何显示来自另一个进程的模态对话框窗口?

转载 作者:可可西里 更新时间:2023-11-01 09:23:10 26 4
gpt4 key购买 nike

我有一个 32 位 MFC 应用程序,它使用一个自定义库,重新编译成 x64 将是一场噩梦。一般而言,应用程序并不真正需要以 64 位运行,但在一种情况下除外——即呈现内容以显示在对话框窗口中,这可以从更大的寻址空间中获益。

所以我的目标是“模仿”CDialog::DoModal 方法,但用于另一个进程中的对话。

我将该对话框窗口构建为独立的基于 x64 MFC 对话框的应用程序。它以文件路径作为输入参数,在内部完成所有工作,并返回简单的用户选择:OKCancel

所以我从我的主要父进程中执行以下操作:

//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) 如果我开始与父级交互,它似乎已“挂起”,操作系统甚至会在其标题栏上显示它。

所以我很好奇是否有办法解决所有这些问题?

最佳答案

  1. 你需要将自己窗口的指针传递给子进程
  2. 您需要处理窗口消息,同时等待子进程导出。 WaitForSingleObject在这里令人无法接受 - 需要使用 MsgWaitForMultipleObjectsEx
  3. 子进程必须在创建时将您的窗口设置为自己的所有者窗口时间 - 你不需要打电话 SetParent

有了这个,一切都会完美无缺。在您的 32 位 MFC 应用程序中,您需要使用下一个代码:

BOOL DoExternalModal(HWND hwnd, PCWSTR ApplicationName)
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
WCHAR CommandLine[32];
swprintf(CommandLine, L"*%p", hwnd);

if (CreateProcessW(ApplicationName, CommandLine, 0, 0, 0, 0, 0, 0, &si, &pi))
{
CloseHandle(pi.hThread);

MSG msg;

for (;;)
{
switch (MsgWaitForMultipleObjectsEx(1, &pi.hProcess, INFINITE, QS_ALLINPUT, 0))
{
case WAIT_OBJECT_0:
CloseHandle(pi.hProcess);
return TRUE;
case WAIT_OBJECT_0 + 1:
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
continue;
default: __debugbreak();
}
}
}

return FALSE;
}

MyDialogBasedApp.exe让我们使用MessageBox作为演示对话框。我们将使用您的 MFC 窗口作为它的第一个参数。

void ExeEntry()
{
int ec = -1;

if (PWSTR CommandLine = GetCommandLine())
{
if (CommandLine = wcschr(CommandLine, '*'))
{
HWND hwnd = (HWND)(ULONG_PTR)_wcstoi64(CommandLine + 1, &CommandLine, 16);

if (hwnd && !*CommandLine && IsWindow(hwnd))
{
ec = MessageBoxW(hwnd, L"aaa", L"bbb", MB_OK);
}
}
}

ExitProcess(ec);
}

使用此代码:

(1) 主应用的任务栏上只有一个图标

(2) 您不能将焦点从子窗口切换到父窗口,反之亦然。所有都作为实际的模态对话框窗口工作

(3) 父级未“挂断”,因为它处理 Windows 消息 (MsgWaitForMultipleObjectsEx) - 您的代码“挂断”是因为您没有这样做,而是在 WaitForSingleObject 中等待

关于c++ - 如何显示来自另一个进程的模态对话框窗口?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41337948/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com