Skip to content

Instantly share code, notes, and snippets.

@dudewheresmycode
Created March 15, 2025 16:57
Show Gist options
  • Save dudewheresmycode/8fc5d100a0ef44fad8bb684fa82dc403 to your computer and use it in GitHub Desktop.
Save dudewheresmycode/8fc5d100a0ef44fad8bb684fa82dc403 to your computer and use it in GitHub Desktop.
# Define the P/Invoke signatures
Add-Type @"
using System;
using System.Runtime.InteropServices;
using System.Text;
public class WindowTools {
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT {
public int X;
public int Y;
}
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPLACEMENT {
public uint length;
public uint flags;
public uint showCmd;
public POINT ptMinPosition;
public POINT ptMaxPosition;
public RECT rcNormalPosition;
}
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll")]
public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
[DllImport("user32.dll")]
public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);
public delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);
[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
[DllImport("user32.dll")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
public const int LOGPIXELSX = 88;
public const int LOGPIXELSY = 90;
}
public class Shcore {
[DllImport("shcore.dll")]
public static extern int GetScaleFactorForMonitor(IntPtr hmon, out int pScale);
}
"@
Add-Type -AssemblyName System.Windows.Forms
# Constants for DPI
$MONITOR_DEFAULTTONEAREST = 2
function Get-DisplayDPI {
$hDC = [WindowTools]::GetDC([IntPtr]::Zero)
if ($hDC -eq [IntPtr]::Zero) {
Write-Error "Failed to get device context"
return
}
$dpiX = [WindowTools]::GetDeviceCaps($hDC, [WindowTools]::LOGPIXELSX)
$dpiY = [WindowTools]::GetDeviceCaps($hDC, [WindowTools]::LOGPIXELSY)
[WindowTools]::ReleaseDC([IntPtr]::Zero, $hDC)
return @{
DPI_X = $dpiX
DPI_Y = $dpiY
}
}
# Function to get the window handle by title
function Get-WindowHandleByTitle {
param (
[string]$windowTitle
)
$windowHandle = [IntPtr]::Zero
$callback = {
param (
[IntPtr]$hWnd,
[IntPtr]$lParam
)
$length = [WindowTools]::GetWindowTextLength($hWnd)
if ($length -gt 0) {
$builder = New-Object Text.StringBuilder $length
[WindowTools]::GetWindowText($hWnd, $builder, $builder.Capacity + 1) | Out-Null
$currentTitle = $builder.ToString()
Write-Host $currentTitle
if ($currentTitle -eq $windowTitle) {
$script:windowHandle = $hWnd
return $false
}
}
return $true
}
$enumProc = [WindowTools+EnumWindowsProc]$callback
[WindowTools]::EnumWindows($enumProc, [IntPtr]::Zero) | Out-Null
return $windowHandle
}
# Function to get the window position and size
function Get-WindowPositionAndSize {
param (
[IntPtr]$windowHandle
)
$rect = New-Object WindowTools+RECT
if (-not [WindowTools]::GetWindowRect($windowHandle, [ref]$rect)) {
Write-Error "Failed to get window rectangle"
return
}
$width = $rect.Right - $rect.Left
$height = $rect.Bottom - $rect.Top
$monitorHandle = [WindowTools]::MonitorFromWindow($windowHandle, $MONITOR_DEFAULTTONEAREST)
if ($monitorHandle -eq [IntPtr]::Zero) {
Write-Error "Failed to get monitor handle"
return
}
$scaleFactor = 0
$result = [Shcore]::GetScaleFactorForMonitor($monitorHandle, [ref]$scaleFactor)
if ($result -ne 0) {
Write-Error "Failed to get scale factor for monitor"
return
}
$scaleFactor = $scaleFactor / 100.0
[PSCustomObject]@{
left = $rect.Left
right = $rect.Right
top = $rect.Top
width = $width
height = $height
# FullScreen = $isFullScreen
scaleFactor = [math]::Round($scaleFactor, 3)
}
}
function Get-MonitorForWindow {
param (
[Drawing.Rectangle]$rect
)
Add-Type -AssemblyName System.Windows.Forms
$monitor = [System.Windows.Forms.Screen]::FromRectangle($rect)
if ($monitor) {
# Get the graphics object from the screen
# $graphics = [System.Drawing.Graphics]::FromHwnd($monitor.Handle)
$displayDPI = Get-DisplayDPI
[PSCustomObject]@{
name = $monitor.DeviceName
primary = $monitor.Primary
x = $monitor.Bounds.X
y = $monitor.Bounds.Y
# dpiX = $graphics.DpiX
# dpiY = $graphics.DpiY
height = $monitor.Bounds.Height
width = $monitor.Bounds.Width
dpiX = $displayDPI.DPI_X
dpiY = $displayDPI.DPI_Y
workingAreaX = $monitor.WorkingArea.X
workingAreaY = $monitor.WorkingArea.Y
workingAreaWidth = $monitor.WorkingArea.Width
workingAreaHeight = $monitor.WorkingArea.Height
}
# $graphics.Dispose()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment