繁体   English   中英

启动应用程序并将其发送到第二台显示器?

[英]Launch an application and send it to second monitor?

有没有办法在另一个屏幕上通过 Process 启动/午餐程序?

有人在这里问过,但没有答案。

注意:它不是我的应用程序中的表单,我问的是在另一个屏幕上运行外部程序!

由于该窗口不是您的窗口,因此只能通过调用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 )。

但是基本逻辑是相同的:

  1. 查找要使用的Windows句柄。 您可以在Timwi提到的一般情况下使用FindWindow或EnumWindows。 但是,如果您的过程很简单并且只有一个主窗口,那么它就是:

     var hndl = proc.MainWindowHandle 
  2. 有了手柄,您可以使用以下功能。 您只需要提供显示编号(从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

您将需要启动进程,获取进程主窗口,并使用SetWindowPos()之类的API调用将窗口移至所需的屏幕。

尝试将这段代码放在form_load方法中:

this.setdesktoplocation(int x, int y);
this.windowstate = formwindowstate.maximized;

x的值必须大于主屏幕的宽度。 例如,如果主屏幕的分辨率为1366 x 786像素,则xa值至少应为1368或更高。

它为我工作。 但这仅用于调试目的。 毕竟,应用程序完成后,您必须在主监视器中运行它。

如果您没有最大化窗口,但是在关闭窗口时未最大化窗口,则下次打开该应用程序时,它将出现在上次的监视器上。

如果应用程序/窗口在关闭时已最大化,并且下次再次打开它,它将显示在主监视器上。

这是怎么回事?

首先,感谢您为这个问题分享这么多技巧,它确实帮助我更多地了解了我的疑问。

我正在努力制作一个脚本来打开许多带有 chrome 页面的监视器屏幕进行监控 - 我使用下面的代码

Add-Type -AssemblyName System.Windows.Forms
$screens = [System.Windows.Forms.Screen]::AllScreens
$chromePath ='C:\Program Files\Google\Chrome\Application\chrome.exe'

$ChromeStartDelay = 4

$urls = @('https://docs.microsoft.com/pt-br/powershell/scripting/learn/deep-dives/everything-about-arrays?view=powershell-7.2','https://stackoverflow.com/questions/42783351/calling-dynamic-variable-in-powershell','https://powershellexplained.com/2017-01-13-powershell-variable-substitution-in-strings')

$screens.Count //just to log 

foreach ($screen in $screens)
{
    $deviceName = $screen.DeviceName
    $positionX = [int]$screen.Bounds.Location.X
    $positionY = [int]$screen.Bounds.Location.Y

    Write-Output $deviceName, "Postion X $positionX, Poxition Y $positionY"
    $chromeArguments = "--app=""https://stackoverflow.com/questions/53012896/using-setwindowpos-with-multiple-monitors"" --window-position=$positionX,$positionY  --kiosk --user-data-dir=c:/$deviceName"
    Start-Sleep -Seconds $ChromeStartDelay
    Start-Process $chromePath "$chromeArguments"
}

它使用 System.Windows.Forms 做了什么,该 System.Windows.Forms 包含基于 windows 的类和 windows 界面功能。

使用下面的那一行,我创建了一个获取所有屏幕信息的实例

$screens = [System.Windows.Forms.Screen]::AllScreens

创建该对象后,在foreach循环内,我动态保存对象键值以与 chrome 进程运行行一起使用

$deviceName = $screen.DeviceName
$positionX = [int]$screen.Bounds.Location.X
$positionY = [int]$screen.Bounds.Location.Y

最后我使用更重要的标志运行 chrome.exe - windows-positionuser-data-dir

第一个标志获取保存的位置并动态定位变量,第二个标志为找到的每个新屏幕创建一个新的会话 crhome 窗口。

$chromeArguments = "--app=""https://stackoverflow.com/questions/53012896/using-setwindowpos-with-multiple-monitors"" --window-position=$positionX,$positionY  --kiosk --user-data-dir=c:/$deviceName"

是的,我仍在努力动态获取 url,它不是一个负责任的代码,更像是一个片段,但我希望这可以帮助这个问题需要更多的方法来帮助得出结论。

对不起我的英语,如果我能改进那个提示,我会再次分享。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM