Skip to content

Instantly share code, notes, and snippets.

@DejayRezme
Last active May 30, 2024 20:58
Show Gist options
  • Save DejayRezme/1f3fa4eab895cb51b8ea57e54136b75b to your computer and use it in GitHub Desktop.
Save DejayRezme/1f3fa4eab895cb51b8ea57e54136b75b to your computer and use it in GitHub Desktop.
#####################################################################################
#
# Code is released As is, no guarantees, use at your own risk
# MIT license
#
#####################################################################################
# Settings
#####################################################################################
# number of wow boxes to launch
$WoWClients = 5
# Base path of your world of warcraft installation. This script should reside there or you need to set your location here
$WoWInstall = (Get-Location).ToString()
# remove caption titlebar and frame for a neater window, but no easy maximizing
$WoWBorderLess = $true
# subtract this amount of pixels for the layout to keep taskbar visible (about 42 pixel is the answer)
$subtractTaskbarHeight = 0 # 42
# select style of layout
# Layout5in3x3
# Layout5in4x4
# Layout8in4x4
# Layout8in4x4WithYT
# LayoutNinNxN
# LayoutNwithPIP
$LayoutStyle = "Layout5in3x3"
# If you have sequentially numbered config1.wtf etc files the script will check if they exist and use them.
# That way you can have different settings for quality, sound and default account
#####################################################################################
#
#####################################################################################
#Add-Type -assemblyName WindowsBase
#Add-Type -assemblyName PresentationFramework
#Add-Type -assemblyName PresentationCore
$code = @'
using System;
using System.Runtime.InteropServices;
public class Win32Util {
[DllImport("user32.dll", SetLastError = true)]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[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 GetClientRect(IntPtr hWnd, out RECT lpRect);
[DllImport("User32.dll")]
public extern static bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw);
[DllImport("User32.dll")]
public extern static int GetSystemMetrics(int nIndex);
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public static IntPtr FindWindow(string windowName) {
return FindWindow(null,windowName);
}
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X,int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
public static void MakeTopMost (IntPtr fHandle) {
SetWindowPos(fHandle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
}
public static void MakeNormal (IntPtr fHandle) {
SetWindowPos(fHandle, HWND_NOTOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
}
public static void MakeChild (IntPtr aHandle, IntPtr bHandle) {
SetWindowPos(aHandle, bHandle, 0, 0, 0, 0, TOPMOST_FLAGS);
}
public static void SetOwner(IntPtr child, IntPtr parent) { // GWL_HWNDPARENT = -8
SetWindowLong(child, -8, (int)parent);
}
}
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
}
'@
Add-Type $code
#$app = Add-Type -MemberDefinition $code -Name Win32Util -ReferencedAssemblies System.Windows.Forms -Using System.Windows.Forms -PassThru
$global:firstWoWWindow = 0
function Launch-And-Position-WoW {
Param (
[int]$x,
[int]$y,
[int]$w,
[int]$h,
[string]$configWTF,
[bool]$alwaysOnTop
)
If (-not (Test-Path -Path ($WoWInstall + "\_retail_\WTF\" + $configWTF))) {
Write-Host "The file " $configWTF " does not exist, using default"
$configWTF = "config.wtf"
}
Write-Host "Starting WoW: " ($WoWInstall + "\_retail_\WoW.exe") ("-config " + $configWTF) " Working dir: " ($WoWInstall + "\_retail_\")
$wowProcess = Start-Process ($WoWInstall + "\_retail_\WoW.exe") -WorkingDirectory ($WoWInstall + "\_retail_\") -ArgumentList ("-config " + $configWTF) -PassThru
#$wowProcess = Start-Process notepad.exe -PassThru
# wait 15 secs for MainWindowHandle to exist
for ($i = 0; $i -lt 150 -AND $wowProcess.MainWindowHandle -eq 0; $i++) {Start-Sleep -m 100 }
$WoWWindowHandle = $wowProcess.MainWindowHandle
Write-Host "wowProcess" $wowProcess.Name "WoWWindowHandle: " + $WoWWindowHandle
Start-Sleep -m 100
# set the window style to frameless and captionless
if ($WoWBorderLess) {
$GWL_STYLE = -16
$style = [Win32Util]::GetWindowLong($WoWWindowHandle, $GWL_STYLE)
$r = [Win32Util]::SetWindowLong($WoWWindowHandle,$GWL_STYLE, $style -band -bnot 0xC40000) # 0xC40000 (no caption no frame)
Start-Sleep -m 100
}
# Try to calculate the size of the window border and caption including shadow
Write-Host ("Target Position: ", $x, $y, $w, $h)
$windowRect = New-Object RECT
$Return = [Win32Util]::GetWindowRect($WoWWindowHandle,[ref]$windowRect)
Write-Host "GetWindowRect: " $windowRect.Left $windowRect.Top $windowRect.Right $windowRect.Bottom
$clientRect = New-Object RECT
$Return = [Win32Util]::GetClientRect($WoWWindowHandle,[ref]$clientRect)
Write-Host "GetClientRect: " $clientRect.Left $clientRect.Top $clientRect.Right $clientRect.Bottom
$border = (($windowRect.Right - $windowRect.Left) - $clientRect.Right) / 2
$caption = (($windowRect.Bottom - $windowRect.Top) - $clientRect.Bottom - $border)
$x -= $border
$y -= $caption
$w += $border * 2
$h += $caption + $border
# resize the window twice to be sure it refreshes
$r = [Win32Util]::MoveWindow($WoWWindowHandle, $x, $y, $w-1, $h-1, $true)
Start-Sleep -m 200
$r = [Win32Util]::MoveWindow($WoWWindowHandle, $x, $y, $w, $h, $true)
Write-Host "MoveWindow result: " $r
if ($global:firstWoWWindow -eq 0) {
$global:firstWoWWindow = $WoWWindowHandle
Write-Host "setting first window handle: " $WoWWindowHandle
}
# make pip windows always on top if requested
if ($alwaysOnTop) {
#[Win32Util]::MakeChild($WoWWindowHandle, $global:firstWoWWindow)
#[Win32Util]::SetOwner($WoWWindowHandle, $global:firstWoWWindow)
[Win32Util]::MakeTopMost($WoWWindowHandle)
}
return $wowProcess
}
#Write-Host "ActiveWindowTrackingDelay: " ([System.Windows.Forms.SystemInformation]::ActiveWindowTrackingDelay)
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$screenSize = [System.Windows.Forms.SystemInformation]::PrimaryMonitorSize
Write-Host "screenSize: " $screenSize " (might be dpi scaled)"
$DPISetting = (Get-ItemProperty 'HKCU:\Control Panel\Desktop\WindowMetrics' -Name AppliedDPI).AppliedDPI
switch ($DPISetting) {
96 {$ActualDPI = 100}
120 {$ActualDPI = 125}
144 {$ActualDPI = 150}
192 {$ActualDPI = 200}
}
#$pwidth = ($($screenSize.Width) / 100) * $ActualDPI
#$pheight = ($($screenSize.Height) / 100) * $ActualDPI
Write-Host "ActualDPI scaling: " $ActualDPI
# Generate the layout
[int[][]]$layout = [int[][]]::new($WoWClients)
if ($LayoutStyle -eq "Layout5in3x3") {
$pipWidth = $screenSize.Width / 3
$pipWidth = ($pipWidth / 16) * 16 # make sure it divisible for 16:9 ratio
$pipHeight = ($pipWidth / 16 * 9)
$mainHeight = $screenSize.Height - $pipHeight - $subtractTaskbarHeight
$mainHeight = ($mainHeight / 9) * 9 # make sure it divisible for 16:9 ratio
$mainWidth = ($mainHeight / 9 * 16)
$layout[0] = @(0, 0, $mainWidth, $mainHeight)
for ($i = 0; $i -lt 3; $i++) {
$layout[$i+1] = @(($i * $pipWidth), $mainHeight, $pipWidth, $pipHeight)
}
$layout[4] = @(($screenSize.Width - $pipWidth), ($mainHeight-$pipHeight), $pipWidth, $pipHeight)
} elseif ($LayoutStyle -eq "Layout8in4x4") {
$pipWidth = $screenSize.Width / 4
$pipWidth = [Math]::floor($pipWidth / 16) * 16 # make sure it divisible for 16:9 ratio
$pipHeight = [Math]::floor($pipWidth / 16 * 9)
$mainHeight = $screenSize.Height - $pipHeight - $subtractTaskbarHeight
$mainHeight = [Math]::floor($mainHeight / 9) * 9 # make sure it divisible for 16:9 ratio
$mainWidth = [Math]::floor($mainHeight / 9 * 16)
$layout[0] = @(0, 0, $mainWidth, $mainHeight)
for ($i = 0; $i -lt 4; $i++) {
$layout[$i+1] = @(($i * $pipWidth), $mainHeight, $pipWidth, $pipHeight)
}
for ($i = 0; $i -lt 3; $i++) {
$layout[$i+5] = @($mainWidth, ($i * $pipHeight), $pipWidth, $pipHeight)
}
} elseif ($LayoutStyle -eq "LayoutNwithPIP") {
# if $LayoutStyle is "Layout5in4x4" or other bottom row layouts
$pipWidth = $screenSize.Width / 8
$pipWidth = [Math]::floor($pipWidth / 16) * 16 # make sure it divisible for 16:9 ratio
$pipHeight = [Math]::floor($pipWidth / 16 * 9)
$mainHeight = $screenSize.Height - $subtractTaskbarHeight
$mainWidth = $screenSize.Width
$layout[0] = @(0, 0, ($mainWidth), ($mainHeight))
for ($i = 0; $i -lt ($WoWClients-1); $i++) {
$layout[$i+1] = @(($mainWidth * 0.2), ($i * $pipHeight + ($mainHeight * 0.25)), $pipWidth, $pipHeight)
}
} else {
# if $LayoutStyle is "Layout5in4x4" or other bottom row layouts
$pipWidth = $screenSize.Width / ($WoWClients - 1)
$pipWidth = [Math]::floor($pipWidth / 16) * 16 # make sure it divisible for 16:9 ratio
$pipHeight = [Math]::floor($pipWidth / 16 * 9)
$mainHeight = $screenSize.Height - $pipHeight - $subtractTaskbarHeight
$mainHeight = [Math]::floor($mainHeight / 9) * 9 # make sure it divisible for 16:9 ratio
$mainWidth = [Math]::floor($mainHeight / 9 * 16)
$layout[0] = @(0, 0, $mainWidth, $mainHeight)
for ($i = 0; $i -lt ($WoWClients-1); $i++) {
$layout[$i+1] = @(($i * $pipWidth), $mainHeight, $pipWidth, $pipHeight)
}
}
Write-Host "Generated layout: " $layout
#Get-Process -Name "World of Warcraft" | Stop-Process
for ($i = 0; $i -lt $WoWClients; $i++) {
$rect = $layout[$i]
$alwaysOnTop = $i -gt 0
$wowProcess = Launch-And-Position-WoW -x $rect[0] -y $rect[1] -w $rect[2] -h $rect[3] -configWTF ("config" + ($i+1) + ".wtf") -alwaysOnTop $alwaysOnTop
}
#Start-Sleep 1
#Get-Process -Name "Notepad" | Stop-Process
#Get-Process -Name "World of Warcraft" | Stop-Process
#Read-Host "Existence is pain, press enter to exit."
Write-Host "Existence is pain. Goodbye!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment