Batch script for opening an application at desired window position from command line

September 20th, 2020

I recently had the need to launch/open multiple instances of the same windows application at different window positions. The web provided various solutions, but there wasn’t any single tidy batch script that tied everything together. My desire was to have a single batch script where I could specify the position, application, and all the application’s arguments in one command line.

This is accomplished with the “launchnmove.bat” batch script which is shown below.

You invoke it with:

launchnmove.bat <xposition> <yposition> <program name> [arg1] [arg2] ...

<xposition> is the desired new upper left position of the window
<yposition> is the desired top right position of the window
<program name> is the application you desire to launch
[arg1] [arg2] … corresponds to the arguments to your application.

See the example below of another batch file where 2 different notepad applications are launched at 2 different window positions:

call launchnmove.bat 0 0 notepad.exe doc1.txt
call launchnmove.bat 300 50 notepad.exe doc2.txt

Above example assumes “launchnmove.bat” is in your PATH, but you could update the example to provide the full path to launchnmove.bat.

You can use launchnmove.bat inside of other batch scripts to open the same, or different windows applications at desired positions. For usage inside of other batch scripts make sure to use “call” such as “call launchnmove.bat …”.

Here are the contents of launchnmove.bat so that you may copy/paste and use it:

<# :
:: Based on https://gist.github.com/coldnebo/1148334
:: Converted to a batch/powershell hybrid via http://www.dostips.com/forum/viewtopic.php?p=37780#p37780
@echo off
setlocal
set "POWERSHELL_BAT_ARGS=%*"
if defined POWERSHELL_BAT_ARGS set "POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"%"
endlocal & powershell -NoLogo -NoProfile -Command "$_ = $input; Invoke-Expression $( '$input = $_; $_ = \"\"; $args = @( &{ $args } %POWERSHELL_BAT_ARGS% );' + [String]::Join( [char]10, $( Get-Content \"%~f0\" ) ) )"
goto :EOF
#>

Add-Type @"
  using System;
  using System.Runtime.InteropServices;

  public class Win32 {
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
  }

  public struct RECT
  {
    public int Left;        // x position of upper-left corner
    public int Top;         // y position of upper-left corner
    public int Right;       // x position of lower-right corner
    public int Bottom;      // y position of lower-right corner
  }
"@

$progname = $args[2]
$progargs = $args[3..($args.Count-1)]
#Write-Host "progargs=$progargs"
$rcWindow = New-Object RECT
$MyProcess = Start-Process -FilePath $progname -ArgumentList $progargs -PassThru

While ($MyProcess.MainWindowHandle -eq 0) {
Start-Sleep -Seconds 1
}

$h = $MyProcess.MainWindowHandle

# Set GetWindowRect output = to $ret so that it doesn't print 'True' to the terminal
$ret = [Win32]::GetWindowRect($h,[ref]$rcWindow)

$win_width = $rcWindow.Right - $rcWindow.Left
$win_height = $rcWindow.Bottom - $rcWindow.Top
$screen_x=$args[0]
$screen_y=$args[1]

# Set MoveWindow output = to $ret so that it doesn't print 'True' to the terminal
$ret = [Win32]::MoveWindow($h, $screen_x, $screen_y, $win_width, $win_height, $true )

 

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.