eldondano
eldondano

Reputation: 167

Powershell - SetForegroundWindow

With a powershell code I try to change the position of a window (is works correctly) and put this windows "Always on top".

Please find below my code:

Import-Module C:/install/WASP/wasp.dll

for($i=1; $i -le 300000; $i++)
{
    $allWindow = Select-Window MyCheck*
    if($allWindow)
    {
        foreach ($currentWindow in $allWindow) 
        {
            $positionWindow = WindowPosition $currentWindow
            foreach ($currentPosition in $positionWindow) 
            {
                #if we find the correct windows
                if ( $currentWindow.title -match "\([0-9]*\)#" )
                {
                    #write-host "@@##@@"$currentWindow.title",(@@#@@)"$currentPosition.x",(@@#@@)"$currentPosition.y",(@@#@@)"$currentPosition.width",(@@#@@)"$currentPosition.height",(@@#@@)"$currentWindow.title",(@@#@@)"$currentWindow.IsActive

                    $id = $currentWindow.title.Substring($currentWindow.title.IndexOf("(")+1, $currentWindow.title.IndexOf(")")-$currentWindow.title.IndexOf("(")-1)
                    $allHUDWindow = Select-Window * | where {$_.Title -match "\($id\).*.txt"}
                    #If we find the second window, we have to superimpose $currentHUDWindow to $currentWindow
                    if($allHUDWindow)
                    {
                        foreach ($currentHUDWindow in $allHUDWindow) 
                        {

                            #I need to set $currentHUDWindow "Always on top"
                            Set-WindowActive $currentHUDWindow
                            Set-WindowPosition -X ($currentPosition.x-10) -Y ($currentPosition.y-30) -WIDTH ($currentPosition.width+20) -HEIGHT ($currentPosition.height+30) -Window $currentHUDWindow
                        }
                    }
                }
            }
        }
    }
} 

Currenlty, I call "Set-WindowActive $currentHUDWindow" but I need to apply also this kind of function :

 [DllImport("user32.dll")]
 [return: MarshalAs(UnmanagedType.Bool)]
 public static extern bool SetForegroundWindow(IntPtr hWnd);

I try to added this function to my code and called SetForegroundWindow($currentHUDWindow). But I encountered an error.

Could you please help me ?

I need to put the window $currentHUDWindow on top !

Thanks

Upvotes: 6

Views: 21970

Answers (2)

DaMaxContent
DaMaxContent

Reputation: 254

You have to make sure that you are following the rules for setting a foreground window. You can find them here

If you are looking to circumvent this, the linked post has a method for getting around it, but it's written in C#.

I have translated that code from C# over to PowerShell, and I even expanded the C++ enums to PowerShell, and linked where you can find them at:

function ShowWindow( $hwnd ){

    $constants = @{
        ShowWindowCommands = @{ #from https://pinvoke.net/default.aspx/Enums/ShowWindowCommands.html
            Hide = 0; #completely hides the window
            Normal = 1; #if min/max'd, restores to original size and position
            ShowMinimized = 2; #activates and minimizes window
            Maximize = 3; #activates and maximizes window
            ShowMaximized = 3; #activates and maximizes window
            ShowNoActivate = 4; #shows a window in its most recent size and position without activating it
            Show = 5; #activates the window and displays it in its current size and position
            Minimize = 6; #minimizes and activates the next top-level window
            ShowMinNoActive = 7; #minimizes and activates no windows"
            ShowNA = 8; #shows a window in its current size and position without activating it
            Restore = 9; #activates and displays window. if min/max'd, restores to original size and position
            ShowDefault = 10; #sets the window to its default show state
            ForceMinimize = 11; #Windows 2000/XP-only feature. minimize window even if thread is hung
        };
        WindowLongParam = { #from https://www.pinvoke.net/default.aspx/Constants/GWL%20-%20GetWindowLong.html
            SetWndProc = -4; #sets new address for procedure (can't be changed unless the window belongs to the same thread)
            SetHndInst = -6; #sets a new application instance handle
            SetHndParent = -8 #unsepecified
            SetId = -12 #sets a new identifier of the child window
            SetStyle = -16 #sets a new window style
            SetExtStyle = -20 #sets a new extended window style
            SetUserData = -21 #sets the user data associated with the window
            #there's a few more of these that are positive for the dialog box procedure
        };
        WindowsStyles = {
            #see https://learn.microsoft.com/en-us/windows/win32/winmsg/window-styles
            # and
            #  http://pinvoke.net/default.aspx/Constants.Window%20styles
            # for more... (there's a lot)
            Minimize = 0x20000000; #hexadecimal of 536870912
        }
    }

    $sigs = '[DllImport("user32.dll", EntryPoint="GetWindowLong")]
    public static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
    [DllImport("user32.dll")]
    public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    [DllImport("User32.dll")]
    public static extern int GetWindowThreadProcessId(IntPtr hWnd, int lpdwProcessId);
    [DllImport("user32.dll")]
    public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
    [DllImport("user32.dll", SetLastError=true)]
    public static extern bool BringWindowToTop(IntPtr hWnd);
    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();'

    $type = Add-Type -MemberDefinition $sigs -Name WindowAPI5 -IgnoreWarnings -PassThru
    
    $type::ShowWindow( $hwnd, $constants.ShowWindowCommands.Minimize )
    $type::ShowWindow( $hwnd, $constants.ShowWindowCommands.Restore )

    [int] $currentlyFocusedWindowProcessId = $type::GetWindowThreadProcessId($type::GetForegroundWindow(), 0)
    [int] $appThread = [System.AppDomain]::GetCurrentThreadId()

    if( $currentlyFocusedWindowProcessId -ne $appThread ){
    
        $type::AttachThreadInput( $currentlyFocusedWindowProcessId, $appThread, $true )
        $type::BringWindowToTop( $hwnd )
        $type::ShowWindow( $hwnd, $constants.ShowWindowCommands.Show )
        $type::AttachThreadInput( $currentlyFocusedWindowProcessId, $appThread, $false )

    } else {
        $type::BringWindowToTop( $hwnd )
        $type::ShowWindow( $hwnd, $constants.ShowWindowCommands.Show )
    }

}

NOTE: I have kept GetWindowLong and its associated constants in the code

If you notice, I did not use variables or the function. I found the calls from the C# code to be useless in PowerShell, but decided to leave the defs for them in case someone wants to use them.

Upvotes: 1

CB.
CB.

Reputation: 60928

This is how P/invoke and use SetForegroundWindow

Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class SFW {
     [DllImport("user32.dll")]
     [return: MarshalAs(UnmanagedType.Bool)]
     public static extern bool SetForegroundWindow(IntPtr hWnd);
  }
"@


$h =  (get-process NOTEPAD).MainWindowHandle # just one notepad must be opened!
[SFW]::SetForegroundWindow($h)

Upvotes: 20

Related Questions