I don\'t remember having any problem finding a window in older Windows OS\'s, but, I\'m not succeeding in Windows 8.1 Update 2 OS, using PowerShell v4.0.
The following code works fine for me, thanks to @zyq's advice
[System.Windows.Forms.MessageBox]::Show('Test', 'PowerShell Dialog',
[Windows.Forms.MessageBoxButtons]::OK,
[Windows.Forms.MessageBoxIcon]::Information,
[Windows.Forms.MessageBoxDefaultButton]::Button1,
[Windows.Forms.MessageBoxOptions]::ServiceNotification
)
$Win32API = Add-Type -Name Funcs -Namespace Win32 -PassThru -MemberDefinition @'
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, IntPtr lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(IntPtr lpClassName, string lpWindowName);
'@
$Win32API::FindWindow('#32770', 'PowerShell Dialog')
$Win32API::FindWindow([IntPtr]::Zero, 'PowerShell Dialog')
$Win32API::FindWindow('#32770', [IntPtr]::Zero)
$Win32API::FindWindow('Notepad', [IntPtr]::Zero)
I had a look at the C# implementation for this issue, and found 2 WNDCLASS structures: WNDCLASS_D AND WNDCLASS_I. The former is the traditional structure that uses strings as types, following the Win32 API. But the latter, uses IntPtr.Zero values for those WNDCLASS structure that take null string values. For this reason, specifying null string values will result in noting found because a null string value is not implicitly convertible to IntPtr.Zero.
First : not an answer but to help other people working on it, if you use the good class, for example here I code CalcFrame
wich is the real class of the main window of calc.exe
it works.
$fw::FindWindow("CalcFrame", $wname) # returns the right value for me if calc.exe is started.
Second : The following works for me ; accordind to Microsoft documentation the first parameter should be null, but accordin to PInvoke site you must pass IntPtr.Zero as the first parameter.
$sig = @"
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(IntPtr sClassName, String sAppName);
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
"@
$fw = Add-Type -Namespace Win32 -Name Funcs -MemberDefinition $sig -PassThru
$wname='Calculatrice' # any existing window name
$fw::FindWindow([IntPtr]::Zero, $wname ) # returns the Window Handle
$a = $fw::GetLastError()
$a
It seems that the method doesn't fail if, and only if, the ClassName
is also specified (cannot be null
) like in this example:
$sig=@'
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
'@
$w32 = Add-Type -Namespace Win32 -Name Funcs -MemberDefinition $sig -PassThru
$w32::FindWindow('ConsoleWindowClass', 'Windows PowerShell') # Windows PowerShell Console
If the ClassName is null
, then the JPBlanc's method works correctly, which specifies a different signature for the method.