在与父进程相同的监视器上运行进程
Posted
技术标签:
【中文标题】在与父进程相同的监视器上运行进程【英文标题】:Run process on the same monitor as the parent process 【发布时间】:2019-12-08 00:25:29 【问题描述】:我有一个用 C++ 编写的 MFC 应用程序,它通过 ShellExecuteEx()
启动记事本。假设这两个应用程序都在双显示器系统上运行,我如何确保记事本与主应用程序在同一显示器上打开?
【问题讨论】:
您可以在SHELLEXECUTEINFO
结构的fMask
成员中设置SEE_MASK_HMONITOR
位,并在hMonitor
成员中指定监视器句柄。
... 并使用MonitorFromWindow
API 来获取应用程序主窗口(大部分)所在的监视器的句柄。
谢谢阿德里安。我将在星期一对此进行测试,因为我目前无法访问双显示器系统。假设记事本已经启动,是否可以将其移动到与其他应用程序相同的显示器上?
@melanie93 给定目标HMONITOR
和HWND
移动,您可以使用GetMonitorInfo()
获取显示器的屏幕矩形,然后使用SetWindowPos()
在该矩形内移动窗口
【参考方案1】:
您可以在SHELLEXECTUTEINFO
结构的fMask
成员中设置SEE_MASK_HMONITOR
位,并在hMonitor
成员中指定所需监视器的句柄。您可以使用MonitorFromWindow
API 调用获取应用程序主窗口的监视器句柄。
下面的代码(或类似的代码)应该可以解决问题:
void RunNotepadOnMyMonitor()
SHELLEXECUTEINFO sei;
memset(&sei, 0, sizeof(SHELLEXECUTEINFO));
sei.cbSize = sizeof(SHELLEXECUTEINFO);
sei.fMask = SEE_MASK_HMONITOR;
sei.lpVerb = _T("open"); // Optional in this case: it's the default
sei.lpFile = _T("notepad.exe");
sei.lpParameters = nullptr; // Add name of file to open - if you want!
sei.nShow = SW_SHOW;
sei.hMonitor = ::MonitorFromWindow(AfxGetMainWnd()->GetSafeHwnd(), MONITOR_DEFAULTTONEAREST);
ShellExecuteEx(&sei);
【讨论】:
内部ShellExecuteEx
调用CreateProcessW
以启动进程。所以必须在STARTUPINFOW
结构中进行选项编码。真的 - 如果从任务栏或跳转列表启动进程,系统会将hStdOutput
设置为包含用于启动进程的任务栏或跳转列表的监视器的句柄。。所以我们需要将hMonitor
放在hStdOutput
中。此处未记录的内容 - 还需要在 dwFlags
中使用 0x400
标志。
but main in next - 进程可以然后使用句柄来定位它的窗口。 - 所以不确定窗口是否会被系统强制定位或过程需要自己做这个
@RbMm 没有冒犯,但我不清楚您要说什么(但我知道您对WinAPI
呼叫的工作原理非常了解)!但是这样怎么样:如果用户将应用程序的主窗口移动到不同的监视器,那么hStdOutput
仍将指向它的原始 监视器——而不是应用程序窗口已经移动到的那个监视器。而dwFlags
中的0x400
(在MonitorFromWindow
调用中?)实际上做了什么?
我只是试着解释一下SEE_MASK_HMONITOR
是如何在内部工作的。真的sei.hMonitor
移动到STARTUPINFOW::hStdOutput
并且未记录的标志STARTF_xxx == 0x400
设置在STARTUPINFOW::dwFlags
中。我无法测试的内容(因为只有单个显示器) - 在这种情况下,系统是否强制在给定显示器或应用程序上强制初始放置窗口必须自行执行此操作。 如果用户将应用程序的主窗口移动到不同的监视器,则 hStdOutput 仍将指向其原始监视器 - 当然 - hStdOutput
不会改变,只会影响初始位置
@RbMm 好的 - 现在清楚多了。此外,直到明天我只有一个监视器系统 - 所以我们都在等待看看实际会发生什么! ?以上是关于在与父进程相同的监视器上运行进程的主要内容,如果未能解决你的问题,请参考以下文章