YorSubs
YorSubs

Reputation: 4050

PowerShell calculate pixel height of Start Bar

I want to place windows on my screen at various positions. I can calculate the dimensions of the screen as below (these are arrays if have multi-display setups):

$widths = (Get-WmiObject -Class Win32_DesktopMonitor | Select-Object ScreenWidth).ScreenWidth
$heights = (Get-WmiObject -Class Win32_DesktopMonitor | Select-Object ScreenHeight).ScreenHeight

To properly place windows, I need to also calculate the height of the Start bar. Does anyone know how to programmatically collect the Start bar height using PowerShell?

I would also like to know how to caculate the position of the Start bar (so that I know if it is placed at the top, bottom, left, right of the screen) if possible?

Upvotes: 0

Views: 838

Answers (2)

YorSubs
YorSubs

Reputation: 4050

Just to share some uses for the info that @Theo gave me above, I wanted to make a function that could position PowerShell consoles. This currently does not cope with multi-monitor setups (if anyone wants to extend functionality to that, I would be glad to see that!).

I keep them as lll and rrr and fff ("full size") for quick access and keep them in my Custom-Tools Module that is available to all of my console sessions. fff relies on the $host.UI.RawUI method which is not as accurate as setting the ConsolePosition (I trim off 1 character from the height as sometimes it does not fit this way) but I'm pretty happy with the ability to flip console settings very easily in this way.

function Global:Set-ConsolePosition ($x, $y, $w, $h) {
    # Note: the DLL code below should not be indented from the left-side
    Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")] 
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int W, int H); '
    # Do the Add-Type outside of the function as repeating it in a session can cause errors
    $consoleHWND = [Console.Window]::GetConsoleWindow();
    $consoleHWND = [Console.Window]::MoveWindow($consoleHWND, $x, $y, $w, $h);
    # $consoleHWND = [Console.Window]::MoveWindow($consoleHWND,75,0,600,600);
    # $consoleHWND = [Console.Window]::MoveWindow($consoleHWND,-6,0,600,600);
}
function lll {
    Add-Type -AssemblyName System.Windows.Forms
    $Screen = [System.Windows.Forms.Screen]::PrimaryScreen
    $width = $Screen.WorkingArea.Width   # .WorkingArea ignores the taskbar, .Bounds is whole screen
    $height = $Screen.WorkingArea.Height
    $w = $width/2 + 13
    $h = $height + 8
    $x = -7
    $y = 0
    Set-ConsolePosition $x $y $w $h

    $MyBuffer = $Host.UI.RawUI.BufferSize
    $MyWindow = $Host.UI.RawUI.WindowSize
    $MyBuffer.Height = 9999
    "`nWindowSize $($MyWindow.Width)x$($MyWindow.Height) (Buffer $($MyBuffer.Width)x$($MyBuffer.Height))"
    "Position : Left:$x Top:$y Width:$w Height:$h`n"
}
function rrr {
    Add-Type -AssemblyName System.Windows.Forms
    $Screen = [System.Windows.Forms.Screen]::PrimaryScreen
    $width = $Screen.WorkingArea.Width   # .WorkingArea ignores the taskbar, .Bounds is whole screen
    $height = $Screen.WorkingArea.Height
    $w = $width/2 + 13
    $h = $height + 8
    $x = $w - 20
    $y = 0
    Set-ConsolePosition $x $y $w $h

    $MyBuffer = $Host.UI.RawUI.BufferSize
    $MyWindow = $Host.UI.RawUI.WindowSize
    $MyBuffer.Height = 9999
    "`nWindowSize $($MyWindow.Width)x$($MyWindow.Height) (Buffer $($MyBuffer.Width)x$($MyBuffer.Height))"
    "Position : Left:$x Top:$y Width:$w Height:$h`n"
}
function fff {
    Set-ConsolePosition -7 0 600 600
    if ($Host.Name -match "console") {
        $MaxHeight = $host.UI.RawUI.MaxPhysicalWindowSize.Height - 1
        $MaxWidth = $host.UI.RawUI.MaxPhysicalWindowSize.Width
        $MyBuffer = $Host.UI.RawUI.BufferSize
        $MyWindow = $Host.UI.RawUI.WindowSize
        $MyWindow.Height = $MaxHeight
        $MyWindow.Width = $Maxwidth
        $MyBuffer.Height = 9999
        $MyBuffer.Width = $Maxwidth
        # $host.UI.RawUI.set_bufferSize($MyBuffer)
        # $host.UI.RawUI.set_windowSize($MyWindow)
        $host.UI.RawUI.BufferSize = $MyBuffer
        $host.UI.RawUI.WindowSize = $MyWindow
        "`nWindowSize $($MyWindow.Width)x$($MyWindow.Height) (Buffer $($MyBuffer.Width)x$($MyBuffer.Height))`n"
    }
}

Upvotes: 0

Theo
Theo

Reputation: 61068

Instead of using WMI, you should be safe using the $Screen.WorkingArea you can retrieve using for instance [System.Windows.Forms.Screen]::PrimaryScreen.

Having said that, the function below will get you the dimensions and position of the TaskBar for a certain screen:

Add-Type -AssemblyName System.Windows.Forms

function Get-TaskBarDimensions {
    param (
        [System.Windows.Forms.Screen]$Screen = [System.Windows.Forms.Screen]::PrimaryScreen
    )        

    $device = ($Screen.DeviceName -split '\\')[-1]
    if ($Screen.Primary) { $device += ' (Primary Screen)' }

    if ($Screen.Bounds.Equals($Screen.WorkingArea)) {
        Write-Warning "Taskbar is hidden on device $device or moved to another screen."
        return
    }


    # calculate heights and widths for the possible positions (left, top, right and bottom)
    $ScreenRect  = $Screen.Bounds
    $workingArea = $Screen.WorkingArea
    $left        = [Math]::Abs([Math]::Abs($ScreenRect.Left) - [Math]::Abs($WorkingArea.Left))
    $top         = [Math]::Abs([Math]::Abs($ScreenRect.Top) - [Math]::Abs($workingArea.Top))
    $right       = ($ScreenRect.Width - $left) - $workingArea.Width
    $bottom      = ($ScreenRect.Height - $top) - $workingArea.Height

    if ($bottom -gt 0) {
        # TaskBar is docked to the bottom
        return [PsCustomObject]@{
            X        = $workingArea.Left
            Y        = $workingArea.Bottom
            Width    = $workingArea.Width
            Height   = $bottom
            Position = 'Bottom'
            Device   = $device
        }
    }
    if ($left -gt 0) {
        # TaskBar is docked to the left
        return [PsCustomObject]@{
            X        = $ScreenRect.Left
            Y        = $ScreenRect.Top
            Width    = $left
            Height   = $ScreenRect.Height
            Position = 'Left'
            Device   = $device
        }
    }
    if ($top -gt 0) {
        # TaskBar is docked to the top
        return [PsCustomObject]@{
            X        = $workingArea.Left
            Y        = $ScreenRect.Top
            Width    = $workingArea.Width
            Height   = $top
            Position = 'Top'
            Device   = $device
        }
    }
    if ($right -gt 0) {
        # TaskBar is docked to the right
        return [PsCustomObject]@{
            X        = $workingArea.Right
            Y        = $ScreenRect.Top
            Width    = $right
            Height   = $ScreenRect.Height
            Position = 'Right'
            Device   = $device
        }
    }
}

To get the TaskBar dimensions for the Primary screen only:

Get-TaskBarDimensions

To get the TaskBar dimensions for all connected screens:

[System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
    Get-TaskBarDimensions $_
}

This will return an object with the following properties:

X        : 0
Y        : 1160
Width    : 1920
Height   : 40
Position : Bottom
Device   : DISPLAY1 (Primary Screen)

Or -in case the taskbar is hidden or not present on that screen- a warning like:

Taskbar is hidden on device DISPLAY2 or moved to another screen.

Upvotes: 1

Related Questions