Specify monitor when opening file. (.bat)

后端 未结 2 1228
温柔的废话
温柔的废话 2020-12-06 20:56

The following .bat file below simply opens two text files overlaying them, but I\'m wondering if it\'s possible to define a specific display source, or if anyone can assist

相关标签:
2条回答
  • 2020-12-06 21:47

    Unless the application you're launching has a command-line switch for it, there's no easy way to specify on which monitor to display a window. As far as I'm aware, neither start nor notepad supports such a switch. The closest solution I've found is to move a window after it's already open.

    Edit: user32.dll SetWindowPos() invoked from PowerShell

    Here's a hybrid batch + PowerShell script to launch a program and move it to a specific monitor. Save it with a .bat extension.

    <# : batch portion
    @echo off & setlocal disabledelayedexpansion
    
    set args=%*
    call set args=%%args:%1 %2=%%
    set "exe=%~2"
    set "monitor=%~1"
    set "scriptname=%~nx0"
    powershell -noprofile "iex (${%~f0} | out-string)"
    exit /b %ERRORLEVEL%
    
    : end batch / begin powershell #>
    
    function usage() {
        write-host -nonewline "Usage: "
        write-host -f white "$env:scriptname monitor# filename [arguments]`n"
        write-host -nonewline "* "
        write-host -f white -nonewline "monitor# "
        write-host "is a 1-indexed integer.  Monitor 1 = 1, monitor 2 = 2, etc."
        write-host -nonewline "* "
        write-host -f white -nonewline "filename "
        write-host "is an executable or a document or media file.`n"
        write-host -nonewline "$env:scriptname mimics "
        write-host -f white -nonewline "start"
        write-host ", searching for filename both in %PATH% and"
        write-host "in Windows' app paths (web browsers, media players, etc).`n"
        write-host "Examples:"
        write-host "To display YouTube in Firefox on your second monitor, do"
        write-host -f white "     $env:scriptname 2 firefox `"www.youtube.com`"`n"
        write-host "To play an mp3 file using the default player on monitor 1:"
        write-host -f white "     $env:scriptname 1 mp3file.mp3"
        exit 1
    }
    
    add-type user32_dll @'
        [DllImport("user32.dll")]
        public static extern void SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
            int x, int y, int cx, int cy, uint uFlags);
    '@ -namespace System
    
    add-type -as System.Windows.Forms
    if ($env:monitor -gt [windows.forms.systeminformation]::MonitorCount) {
        [int]$monitor = [windows.forms.systeminformation]::MonitorCount
    } else {
        [int]$monitor = $env:monitor
    }
    try {
        if ($env:args) {
            $p = start $env:exe $env:args -passthru
        } else {
            $p = start $env:exe -passthru
        }
    }
    catch { usage }
    
    $shell = new-object -COM Wscript.Shell
    while (-not $shell.AppActivate($p.Id) -and ++$i -lt 100) { sleep -m 50 }
    
    try {
        $x = [Windows.Forms.Screen]::AllScreens[--$monitor].Bounds.X
        $hwnd = (Get-Process -id $p.Id)[0].MainWindowHandle
        [user32_dll]::SetWindowPos($hwnd, [intptr]::Zero, $x, 0, 0, 0, 0x41);
    }
    finally { exit 0 }
    

    Original answer: compile and link c# executable

    And moving a window is no easy task, either. See this post for some other options. But here's a batch script that will compose and link a C# app on the fly to handle window moves.

    @echo off
    setlocal
    
    :: // generate c.cs
    call :heredoc movewind >"%temp%\c.cs" && goto compile_and_link
    // syntax: movewind.exe [pid | "window title"] x y
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    class movewind {
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
    
        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
        static void Main(string[] args) {
            int pid;
            string title;
            bool res = Int32.TryParse(args[0], out pid);
            if (res) {title = Process.GetProcessById(pid).MainWindowTitle;} else {title = args[0];}
            IntPtr handle = FindWindow(null, title);
            try {
                SetWindowPos(handle, IntPtr.Zero, Convert.ToInt32(args[1]), Convert.ToInt32(args[2]), 0, 0, 0x41);
            }
            catch (Exception e) {
                Console.WriteLine("Exception caught while attempting to move window with handle " + handle);
                Console.WriteLine(e);
            }
        }
    }
    :compile_and_link
    
    set "movewind=%temp%\movewind.exe"
    
    for /f "delims=" %%I in ('dir /b /s "%windir%\microsoft.net\*csc.exe"') do (
        if not exist "%movewind%" "%%I" /nologo /out:"%movewind%" "%temp%\c.cs" 2>NUL
    )
    del "%temp%\c.cs"
    if not exist "%movewind%" (
        echo Error: Please install .NET 2.0 or newer.
        goto :EOF
    )
    
    :: // get left monitor width
    for /f "tokens=2 delims==" %%I in ('wmic desktopmonitor get screenwidth /format:list') do set "x=%%I"
    
    :: // make sure test environment is in place
    if not exist "c:\test" mkdir "c:\test"
    if not exist "c:\test\screen1.txt" >"c:\test\screen1.txt" echo This should be on the left.
    if not exist "c:\test\screen2.txt" >"c:\test\screen2.txt" echo This should be on the right.
    
    :: // syntax: movewind.exe [pid | "window title"] x y
    start /max notepad.exe "c:\test\screen1.txt"
    call :movewind "screen1.txt - Notepad" 0 0
    start /max notepad.exe "c:\test\screen2.txt"
    call :movewind "screen2.txt - Notepad" %x% 0
    
    del "%movewind%"
    
    :: // end main runtime
    goto :EOF
    
    :: // SCRIPT FUNCTIONS
    
    :movewind <title> <x> <y>
    tasklist /v | find /i "%~1" && (
        "%movewind%" "%~1" %~2 %~3
        goto :EOF
    ) || (
        ping -n 1 -w 500 169.254.1.1 >NUL
        goto movewind
    )
    
    :heredoc <uniqueIDX>
    :: // https://stackoverflow.com/a/15032476/1683264
    setlocal enabledelayedexpansion
    set go=
    for /f "delims=" %%A in ('findstr /n "^" "%~f0"') do (
        set "line=%%A" && set "line=!line:*:=!"
        if defined go (if #!line:~1!==#!go::=! (goto :EOF) else echo(!line!)
        if "!line:~0,13!"=="call :heredoc" (
            for /f "tokens=3 delims=>^ " %%i in ("!line!") do (
                if #%%i==#%1 (
                    for /f "tokens=2 delims=&" %%I in ("!line!") do (
                        for /f "tokens=2" %%x in ("%%I") do set "go=%%x"
                    )
                )
            )
        )
    )
    goto :EOF
    
    0 讨论(0)
  • 2020-12-06 21:50

    (Win 7) To specify location to open a CMD window just run the batch or CMD and then position the CMD window where you want it, including on which monitor if you have more than one, and then right click on its title bar, select Properties, and click OK. The next time the CMD window opens using the same batch or icon it will be in the new location.

    0 讨论(0)
提交回复
热议问题