Reputation: 9920
The following code brings the window to the foreground, if the MainWindowHandle
is not 0.
How can I bring a window to the front that has MainWindowHandle
= 0?
This is for the Microsoft Excel - Compatibility Checker window that shows a GUI but does not have an icon in the task bar and has MainWindowHandle
= 0.
I have no other instances of Excel running.
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class Tricks {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
}
"@
$excel = (Get-Process | Where-Object { $_.ProcessName -eq 'EXCEL' }).MainWindowHandle
[void] [Tricks]::SetForegroundWindow($excel)
In Windows Task Manager, I can right click on 'Microsoft Excel - Compatibility Checker' and click on "Bring To Front" and that works. How can I mimic this functionality in Powershell?
Upvotes: 1
Views: 1826
Reputation: 9920
Thanks to IInspectable for pointing me in the right direction.
This code gets the real MainWindowHandle
value:
$TypeDef2 = @"
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Api
{
public class WinStruct
{
public string WinTitle {get; set; }
public int MainWindowHandle { get; set; }
}
public class ApiDef
{
private delegate bool CallBackPtr(int hwnd, int lParam);
private static CallBackPtr callBackPtr = Callback;
private static List<WinStruct> _WinStructList = new List<WinStruct>();
[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(CallBackPtr lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
private static bool Callback(int hWnd, int lparam)
{
StringBuilder sb = new StringBuilder(256);
int res = GetWindowText((IntPtr)hWnd, sb, 256);
_WinStructList.Add(new WinStruct { MainWindowHandle = hWnd, WinTitle = sb.ToString() });
return true;
}
public static List<WinStruct> GetWindows()
{
_WinStructList = new List<WinStruct>();
EnumWindows(callBackPtr, IntPtr.Zero);
return _WinStructList;
}
}
}
"@
Add-Type -TypeDefinition $TypeDef2 -Language CSharpVersion3
$excelInstance = [Api.Apidef]::GetWindows() | Where-Object { $_.WinTitle.ToUpper() -eq "Microsoft Excel - Compatibility Checker".ToUpper() }
So now using this correct value, I can call the SetForegroundWindow()
function:
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class Tricks {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
}
"@
[void] [Tricks]::SetForegroundWindow($excelInstance.MainWindowHandle)
I wrote a detailed blog about this on my website.
I've put up a full example on GitHub of how to create an Excel file, edit it and run the above code in a different thread which you have to do because the Excel popup blocks the main thread.
Upvotes: 2