I'm using .Net 6 and the PInvoke nuget package to access the Win32 API and I'm creating a Win32 window in the following way:
IntPtr windowHandle = User32.CreateWindowEx(User32.WindowStylesEx.WS_EX_TOOLWINDOW,
"static",
"Window Title",
User32.WindowStyles.WS_OVERLAPPEDWINDOW |
User32.WindowStyles.WS_VISIBLE,
0,
0,
800,
800,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero);
When the window becomes visible on screen I have the same situation as this guy The window renders fine, but is unresponsive to the user. When I mouse-over the window, the mouse pointer becomes the loading circle.
I believe the unresponsivness is due to window events and messages not being handled. I would like to somehow override or hook into the WndProc method of the Win32 window to handle messages, as apparently the User32.GetMessage() does not return all messages.
In WPF you can add a hook to the HwndHost to handle the WndProc messages. How do I get the WndProc messages in .Net 6 without using WPF?
CodePudding user response:
TL;DR: essentially the unresponsiveness is due to your code not processing the Windows Message Pump for the offending window.
As mentioned in your line "You need to get the messages for the window and dispatch them accordingly". i.e. GetMessage
, TranslateMessage
, DispatchMessage
, all inside a while
loop otherwise known as The Message Loop.
I would like to somehow override or hook into the WndProc method of the Win32 window to handle messages, as apparently...
That's not how it works. If you create a window in your process then the onus is on you to provide and act on The Message Loop. Otherwise you will experience exactly what you are seeing now - a frozen window. "Hook" is not the correct term here.
e.g.
User32.MSG msg;
while (User32.GetMessage(msg, hWnd, null, null) > 0)
{
User32.TranslateMessage(msg);
User32.DispatchMessage(msg);
}
I suspect your app is a console app which by default does not contain a Windows Message Pump. That's one reason why you shouldn't use the Console App project wizard to create something that will expose a GUI. Whilst it is possible to make a console app display a GUI, it's generally easier to pick a project wizard tailored for GUIs in the first place. [%]
In WPF you can add a hook to the HwndHost to handle the WndProc messages...
Don't forget, WPF uses Direct3D as a render surface and apart from the application window, there are no child WIN32 windows to speak of. This is easily shown by pointing tools like Spy at a WPF app. When Microsoft designed WPF they needed a way for Microsoft UI Automation to interact with child elements. It does so without having to worry about child windows.
% Footnote
Speaking of squeezing GUIs into something that at first glance today might look like a console app, this was kind of how things were done in Windows apps written in C
prior to C
. C apps, could spin up and serve a window all in a single main()
entry point, however no console window as such appeared so the console comparison isn't quite true.
C apps didn't have alot of guidance. Some might not have had a resource table for things like icons, keyboard accelerators, string tables but they were GUI apps nonetheless.
Microsoft Visual C changed things with MFC (then again years later with ATL, WTL) distinct GUI project types and encapsulated much from the developer particularly The Message Pump code in addition to providing default icons, keyboard accelerators, string tables.
So making a C# GUI app using a console project wizard is akin to a bare-bones C GUI app.
Therefore you need your message pump.