【发布时间】:2011-04-14 14:06:24
【问题描述】:
【问题讨论】:
-
不是重复的,略有不同,另一篇是直接申请,他要移动一个外部应用窗口。
标签: c# monitor multiple-monitors
【问题讨论】:
标签: c# monitor multiple-monitors
由于窗口不是您的,您只能通过调用 Windows API 来移动它。你必须这样做:
启动进程。
使用FindWindow 检索窗口句柄。如果窗口尚不存在,则该进程尚未创建它;睡眠 500 毫秒,然后重试。 (但不要进入无限循环;如果在合理的超时后找不到窗口,请停止。)
使用SetWindowPos改变窗口的位置。
如果不知道窗口的标题,就不能使用FindWindow。在这种情况下,
启动进程并通过检索Process.Handle获取进程句柄。
使用EnumWindows 检索所有窗口。对于每个窗口,使用GetWindowThreadProcessId 检查它是否属于您的进程。如果没有窗口属于您的进程,请等待并继续尝试。
使用SetWindowPos改变窗口的位置。
当然,您可以使用Screen.AllScreens[n].WorkingArea 来检索您想要的屏幕的位置和大小,然后您可以相对于它定位窗口。
【讨论】:
首先使用类似的方法从第二台显示器的区域中取出:
Rectangle area = Screen.AllScreens[1].WorkingArea;
使用 Windows API SetWindowPos 移动它,使用从另一个进程开始时获得的 Process.MainWindowHandle 作为句柄。
【讨论】:
Timwi 提供了一个非常有用的提示,因此我决定创建一个 powershell 脚本,调用具有这些函数的库以便于使用,并分享解决方案。
我需要在启动时运行多个 Chrome 窗口,而 GitHub 上的解决方案正是针对这个问题(相关问题:https://superuser.com/a/901790/111424)。
但底层逻辑是一样的:
找到要操作的 Windows 句柄。您可以在 Timwi 提到的一般情况下使用 FindWindow 或 EnumWindows。但是,如果您的流程很简单并且只有一个主窗口,那就是:
var hndl = proc.MainWindowHandle
有了句柄,你就可以使用下面的函数了。您只需要提供显示编号(从 1 开始)和句柄:
public static bool MoveToMonitor(IntPtr windowHandle, int monitor)
{
monitor = monitor - 1;
return WinApi.SetWindowPos(windowHandle, IntPtr.Zero, Screen.AllScreens[monitor].WorkingArea.Left,
Screen.AllScreens[monitor].WorkingArea.Top, 1000, 800, SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOREDRAW);
}
您可以在 http://www.pinvoke.net/ 上找到所有枚举和函数导入,或者直接在 GitHub 上复制我的代码:https://github.com/alex-tomin/Tomin.Tools.KioskMode。
【讨论】:
您需要启动进程,获取进程主窗口并使用 API 调用(如 SetWindowPos())将窗口移动到所需的屏幕。
【讨论】:
尝试把这段代码放在form_load方法中:
this.setdesktoplocation(int x, int y);
this.windowstate = formwindowstate.maximized;
x 的值必须大于主屏幕的宽度。例如,如果您的主屏幕的分辨率为 1366 x 786 像素,您应该为 x 提供至少 1368 或更高的值。
它对我有用。但这仅用于调试目的。毕竟,您必须在应用完成后在主监视器中运行它。
【讨论】:
如果您没有最大化您的窗口,但在您关闭它时让它未最大化,则下次打开应用程序时,它将显示在上次打开的监视器上。
如果应用程序/窗口在您关闭时最大化,并且如果您下次再次打开它,它将显示在您的主显示器上。
【讨论】: