Question [Functions]API Windows-gestion de fenêtre

Plus d'informations
il y a 17 ans 4 mois #3156 par Laurent Dardenne
Une série de fonctions Win32 permettant de manipuler , entre autre, la fenêtre de la console PowerShell.

La dernière version du package des API Windows, ce trouve ici .

Fonctions implémentées :

function ShowWindowAsync([IntPtr] $hWnd, [Int32] $nCmdShow)
function SetActiveWindow([IntPtr] $hWnd)
function SendMessage([IntPtr] $hWnd, [Int32] $message, [Int32] $wParam, [Int32] $lParam)
function GetConsoleWindow()
function BringWindowToTop([IntPtr] $hWnd)
function SetWindowPos([IntPtr] $hWnd, [IntPtr] $hWndInsertAfter, [Int32] $X, [Int32] $Y, [Int32] $cx, [Int32] $cy, [UInt32] $uFlags)
function SetFocus([IntPtr] $hWnd)
function SwitchToThisWindow([IntPtr] $hWnd, [Boolean] $fAltTab=$false)
function SetForegroundWindow([IntPtr] $hWnd)
function GetWindowRect([IntPtr] $hWnd, [REF] $lpRect)
function FindWindow([String] $lpClassName, [string] $lpWindowName)
function MoveWindow([IntPtr] $hWnd, [Int32] $X, [Int32] $Y, [Int32] $nWidth, [Int32] $nHeight,[Int32] $bRepaint)

Tools :

function Set-ForegroundWindow ([IntPtr] $MyHandle=$((Get-Process –id $pid).MainWindowHandle))
Function Set-ConsoleIcon([string] $iconFile)
function Show-PowerShell() ! Utilise un variable globale
function Hide-PowerShell() ! Utilise un variable globale
function Minimize-PowerShell() ! Utilise un variable globale


Exemples :
[code:1]
#Exemple 1
#Cache la fenêtre de PowerShell
$myWindowHandle = (Get-Process -Id $pid).MainWindowHandle
#Cache la fenêtre PowerShell
Hide-PowerShell
sleep 2
#Restaure la fenêtre PowerShell
Show-PowerShell;

#Exemple 2
#exécute un process qui se place au premier plan en prenant le focus
$MyHandle=(Get-Process –id $pid).MainWindowHandle
Start-process \"C:\dev\DebugView\Dbgview.exe\" -WindowStyle Minimized
#Restaure la fenêtre de PowerShell au premier plan
SetActiveWindow $MyHandle
SetForegroundWindow $MyHandle
SwitchToThisWindow $MyHandle $true

#Exemple 2-1
#Sans minimiser la fenêtre du nouveau processus.
&\"C:\dev\DebugView\Dbgview.exe\"
start-sleep -m 200
Set-ForegroundWindow

#Exemple 2-2
#On minimise la fenêtre du nouveau processus.
$psi = new-object system.diagnostics.processStartInfo
$psi.FileName=\"C:\dev\DebugView\Dbgview.exe\"
$psi.Arguments=\"\"
$psi.LoadUserProfile=$false
$psi.UseShellExecute=$True
$psi.WindowStyle=[System.Diagnostics.ProcessWindowStyle]::Minimized
$proc = [system.diagnostics.process]::«»start($psi)
Set-ForegroundWindow

#Exemple 2-3
#On utilise un cmdlet dédié qui minimise la fenêtre du nouveau processus.
$MyHandle=(Get-Process –id $pid).MainWindowHandle
if ($PscxVersion -eq \"1.1.1.0\"«»)
{
Start-process \"C:\dev\DebugView\Dbgview.exe\" -WindowStyle Minimized >$null
Set-ForegroundWindow #$MyHandle
}
else
{ cmd.exe /C Start www.codeplex.com/PowerShellCX}

#Exemple 3
#On crée un nouveau shell PS
$MyHandle=([diagnostics.process]::«»start(\"PowerShell.exe\", $null)).id
#On démarre un process qui prend le \"focus\"
Start-process \"C:\dev\DebugView\Dbgview.exe\" -WindowStyle Minimized >$null
#On place cette fois ci le focus sur la nouvelle session PS précédement créée.
Set-ForegroundWindow $MyHandle

#Exemple 3-1
$MyHandle=([diagnostics.process]::«»start(\"PowerShell.exe\", $null)).id
#On démarre, en lui donnant une taille de fenêtre maximum, un process qui prend le \"focus\"
Start-process \"C:\dev\DebugView\Dbgview.exe\" -WindowStyle Maximized
#On place le focus sur la nouvelle session PS précédement créée.
Set-ForegroundWindow $MyHandle

#Certaines applications peuvent mémoriser leur position, comme le fait Dbgview.exe, dans ce cas le paramètre
#-WindowStyle peut sembler ne pas avoir le comportement adéquate. C'est l'application qui une fois chargée se redessine
# avec les anciennes coordonnées mémorisées (dans la registry ou dans un fichier de configuration).
#Dans ce cas on appel la fonction Minimize-PowerShell()
[/code:1]<br><br>Message édité par: Laurent Dardenne, à: 30/05/10 18:01

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 17 ans 4 mois #3190 par Laurent Dardenne
Au menu du jour :
[code:1]
# -- Menu
function GetSystemMenu([IntPtr] $hWnd, [Boolean] $bRevert)
{ #Obtient le handle du menu system d'une fenêtre
$parameterTypes = [IntPtr],[Boolean]
$parameters = $hWnd,$bRevert

Invoke-Win32 \&quot;user32.dll\&quot; ([IntPtr]) \&quot;GetSystemMenu\&quot; $parameterTypes $parameters
}

function GetMenuItemCount([IntPtr] $hMenu)
{ #Renvoi le nombre d'items dans le menu spécifié
$parameterTypes = [IntPtr]
$parameters = $hMenu

Invoke-Win32 \&quot;user32.dll\&quot; ([Int32]) \&quot;GetMenuItemCount\&quot; $parameterTypes $parameters
}

function AppendMenu([IntPtr] $hMenu, [UInt32] $uFlags, [UInt32] $uIDNewItem,[String] $lpNewItem)
{ #Supprime une entrée de menu.

$parameterTypes = [IntPtr], [UInt32], [UInt32],[String]
$parameters = $hMenu, $uFlags, $uIDNewItem, $lpNewItem

Invoke-Win32 \&quot;user32.dll\&quot; ([Boolean]) \&quot;AppendMenu\&quot; $parameterTypes $parameters
# $MF_STRING = 0
# $MF_BITMAP = 4
# $MF_OWNERDRAW = 256
}

function RemoveMenu([IntPtr] $hMenu, [Int32] $uPosition, [Int32] $uFlags)
{ #Supprime une entrée de menu.

$parameterTypes = [IntPtr],[Int32],[Int32]
$parameters = $hMenu,$uPosition,$uFlags

Invoke-Win32 \&quot;user32.dll\&quot; ([Boolean]) \&quot;RemoveMenu\&quot; $parameterTypes $parameters

#Valeur des menus, il est possible de les utiliser pour $uPosition
# $SC_SIZE = 61440;
# $SC_MOVE = 61456;
# $SC_MINIMIZE = 61472;
# $SC_MAXIMIZE = 61488;
# $SC_RESTORE = 61728;
# $SC_SEPARATOR = 61455;
# $SC_CLOSE = 61536;
# Menu \&quot;Modifier\&quot;
# $SC_DEFAULT = 61792;
# Menu \&quot;Propriétés\&quot;

#Valeur de Uflags
# $MF_BYCOMMAND = 0
# $MF_BYPOSITION = 1024

}
[/code:1]
Permet de supprimer puis de recréer le menu système \&quot;Fermer\&quot; d'une fenêtre, l'instruction PowerShell exit reste valide :
[code:1]
#Struct menuinfo: msdn.microsoft.com/en-us/library/ms647578(VS.85).aspx
#Constante utilsées par les API de gestion des menus
$MF_BYCOMMAND = 0
$MF_BYPOSITION = 1024

$SC_CLOSE = 61536
#Récupère le handle de la fenêtre de PS
$MyHandle=(Get-Process –id $pid).MainWindowHandle
#Récupère le handle du menu system de PS
$hSystemMenuPS= GetSystemMenu $MyHandle $False
#Récupère le nombre d'entrées du menu système de PS
$NbMenuItem= GetMenuItemCount $hSystemMenuPS

#Supprime le menu Close par sa position, s'il n'y a eu aucune modification
#RemoveMenu $hSystemMenuPS ($NbMenuItem - 4) $MF_BYPOSITION

#Supprime le menu Close par son nom
#RemoveMenu $hSystemMenuPS $SC_CLOSE $MF_BYCOMMAND
#Supprime le premier menu
#RemoveMenu $hSystemMenuPS ($NbMenuItem - 1) $MF_BYPOSITION

#Supprime le menu Close par son nom
#Le bouton \&quot;X\&quot; semble rester valide mais ce n'est pas le cas,
# un refresh de la fenêtre le redessinera grisé.
Remove-CloseMenu $hSystemMenuPS

# fait qq chose ...

#Ajoute, en fin de liste, une entrée de menu appelant
#l'event Close ( WM_SYSCOMMAND Notification)
Add-CloseMenu $hSystemMenuPS
[/code:1]
[edit]
Une nouveauté de la version 2 facilite les appels Win32 :
www.leeholmes.com/blog/PowerShellPInvokeWalkthrough.aspx

Message édité par: Laurent Dardenne, à: 21/01/09 17:14

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 16 ans 11 mois #4452 par Laurent Dardenne
La dernière version du package des API Windows, ce trouve ici .

[code:1]#Nouvelles fonctions
#Functions Windows
function GetWindowLong([IntPtr] $hWnd, [Int32] $nIndex)
function SetWindowLong([IntPtr] $hWnd, [Int32] $nIndex, [Int32] $dwNewLong)

#Functions Menu

function GetMenuState([IntPtr] $hMenu, [UInt32] $uId, [UInt32] $uFlags)
function InsertMenu([IntPtr] $hMenu,[UInt32] $Position, [UInt32] $Flags, [UInt32] $NewId,[String] $Item )
function DestroyMenu([IntPtr] $hMenu)
function DrawMenuBar([IntPtr] $hMenu)

#Function Tools
function Remove-MinimizeMenu([IntPtr] $hMenu)
function Add-MinimizeMenu([IntPtr] $hMenu)
function StayOnTop([IntPtr] $hWnd, [switch] $OFF)[/code:1]
Modifications:
-le handle de la fenêtre de PS est désormais en constante et est automatiquement déclaré lors du
chargement en dotsource du package : . .\packageWindowsFunctions.

Set-Variable PSWindowHandle -value ((Get-Process -Id $pid).MainWindowHandle) -option Constant

-La fonction Set-cstApiWindows est automatiquement déclarée lors du chargement en dotsource du package.
Elle contient de nouvelles constantes.
Deux nouveaux membres ont été ajoutés, une fonction Add et une propriété Name
La fonction Add facilite la saisie au lieu de
[code:1]
$cApiWindows.SWP_NOSIZE + $cApiWindows.SWP_NOMOVE + $cApiWindows.SWP_NOZORDER + $cApiWindows.SWP_NOACTIVATE + $cApiWindows.SWP_SHOWWINDOW
#On a
$cApiWindows.Add(\&quot;SWP_NOSIZE\&quot;,\&quot;SWP_NOMOVE\&quot;,\&quot;SWP_NOZORDER\&quot;,\&quot;SWP_NOACTIVATE\&quot;,\&quot;SWP_SHOWWINDOW\&quot;«»)[/code:1]
La propriété Name contient le nom de la variable d'origine car $this à pour nom \&quot;this\&quot;.
[code:1]
...
$Code=\&quot;`$obj| add-member -memberType Scriptproperty -Name Name -value {`\&quot;$VariableName`\&quot;} -SecondValue {Throw `\&quot;La propriété $VariableName est en lecture seule.`\&quot;}\&quot;
invoke-expression $Code
...
[/code:1]
On ne peut donc pas en cas d'erreur dans un traitement indiqué quelle variable est concernée :
[code:1]
...
if ($this.\&quot;$_\&quot; -eq $null)
{Throw \&quot;Le nom de propriété $_ n'existe pas pour la variable $($this.Name).\&quot;}
...
[/code:1]<br><br>Message édité par: Laurent Dardenne, à: 24/03/09 19:25

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 16 ans 9 mois #4704 par Laurent Dardenne
Pour info, la gestion des erreurs des API Win32 via l'appel à
[code:1][System.Runtime.InteropServices.Marshal]::GetLastWin32Error()[/code:1]
Ne fonctionne pas avec le script Invoke-Win32, car par défaut ce script construit l'attribut DllImportAttribute avec la valeur par défaut pour le champ SetLastError :

true pour indiquer que l'appelé appellera SetLastError ; sinon false. La valeur par défaut est false, sauf en Visual Basic.

Le marshaleur runtime appelle GetLastError et met en mémoire cache la valeur retournée pour empêcher qu'elle soit remplacée par d'autres appels API. Pour récupérer le code d'erreur, vous pouvez appeler GetLastWin32Error.

Comme dans ce ce cas la valeur n'est pas mise en cache on récupére n'importe quoi comme code erreur.
J'ai essayé de modifier le script d'origine mais sans résultat probant

De plus dans l'appel suivant
[code:1] $ret=SetActiveWindow $WindowHandle
If ($ret -eq $null)
...
[/code:1]
$ret contient un pointeur qui ne peut être comparé avec la valeur $Null de PowerShell mais seulement avec [intPtr]::Zero ou 0.
Dans ce contexte le $null de PowerShell n'est pas identique au null du C#.

Donc la gestion des erreurs Win32 avec un script PS V1 n'est pas pour le moment possible.
Et vous en conviendrez c'est un peu gênant.
[edit]
Voir aussi : blogs.msdn.com/b/oldnewthing/archive/2015/08/19/10636096.aspx

Message édité par: Laurent Dardenne, à: 22/08/15 15:53

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Temps de génération de la page : 0.098 secondes
Propulsé par Kunena