Last active
May 30, 2024 20:58
-
-
Save DejayRezme/1f3fa4eab895cb51b8ea57e54136b75b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
##################################################################################### | |
# | |
# 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