C
C#2y ago
arion

FindWindow by lpClassName. Is there an event based alternative to polling?

The code summarises the issue pretty well:
private static async Task InitializePollingLoop()
{
while (true)
{
await Task.Delay(100);

var hWnd = User32.FindWindow("Xaml_WindowedPopupClass", null);

if (hWnd == IntPtr.Zero) continue;

Console.WriteLine("Found a window at {0}", hWnd);

var style = User32.GetWindowLong(hWnd, User32.WindowLongIndexFlags.GWL_EXSTYLE);
style |= (int)User32.SetWindowLongFlags.WS_EX_TRANSPARENT | (int)User32.SetWindowLongFlags.WS_EX_LAYERED;
var retVal = User32.SetWindowLong(hWnd, User32.WindowLongIndexFlags.GWL_EXSTYLE, (User32.SetWindowLongFlags)style);
if (retVal == 0)
{
var error = Marshal.GetLastWin32Error();
Console.WriteLine("Error setting window style: {0}", new Win32Exception(error));
}

}
}
private static async Task InitializePollingLoop()
{
while (true)
{
await Task.Delay(100);

var hWnd = User32.FindWindow("Xaml_WindowedPopupClass", null);

if (hWnd == IntPtr.Zero) continue;

Console.WriteLine("Found a window at {0}", hWnd);

var style = User32.GetWindowLong(hWnd, User32.WindowLongIndexFlags.GWL_EXSTYLE);
style |= (int)User32.SetWindowLongFlags.WS_EX_TRANSPARENT | (int)User32.SetWindowLongFlags.WS_EX_LAYERED;
var retVal = User32.SetWindowLong(hWnd, User32.WindowLongIndexFlags.GWL_EXSTYLE, (User32.SetWindowLongFlags)style);
if (retVal == 0)
{
var error = Marshal.GetLastWin32Error();
Console.WriteLine("Error setting window style: {0}", new Win32Exception(error));
}

}
}
User32 comes from the Nuget package "PInvoke.User32" Setting the window requires administrator or you will get a Win32Error on 'retVal', the code addresses an issue on Windows11 My question is, is there some sort of Event based alternative to polling to find that window handle? The main focus of the question is the first 3 lines of actual code:
await Task.Delay(100);

var hWnd = User32.FindWindow("Xaml_WindowedPopupClass", null);

if (hWnd == IntPtr.Zero) continue;
await Task.Delay(100);

var hWnd = User32.FindWindow("Xaml_WindowedPopupClass", null);

if (hWnd == IntPtr.Zero) continue;
1 Reply
arion
arion2y ago
Found an event based solution:
var hHandle = User32.SetWinEventHook(User32.WindowsEventHookType.EVENT_OBJECT_SHOW,
User32.WindowsEventHookType.EVENT_OBJECT_SHOW, IntPtr.Zero, LpfnWinEventProc, 0, 0,
User32.WindowsEventHookFlags.WINEVENT_OUTOFCONTEXT);
var hHandle = User32.SetWinEventHook(User32.WindowsEventHookType.EVENT_OBJECT_SHOW,
User32.WindowsEventHookType.EVENT_OBJECT_SHOW, IntPtr.Zero, LpfnWinEventProc, 0, 0,
User32.WindowsEventHookFlags.WINEVENT_OUTOFCONTEXT);
private static void LpfnWinEventProc(IntPtr hookHandle, User32.WindowsEventHookType @event, IntPtr hwnd, int idobject, int idchild, int dweventthread, uint dwmseventtime)
{
try
{
if (User32.GetClassName(hwnd) != "Xaml_WindowedPopupClass") return;

SetTransparent(hwnd);
}
catch {} // Some Race Conditions occur here for GCing the window handle
}
private static void LpfnWinEventProc(IntPtr hookHandle, User32.WindowsEventHookType @event, IntPtr hwnd, int idobject, int idchild, int dweventthread, uint dwmseventtime)
{
try
{
if (User32.GetClassName(hwnd) != "Xaml_WindowedPopupClass") return;

SetTransparent(hwnd);
}
catch {} // Some Race Conditions occur here for GCing the window handle
}