How to handle Win32 WndProc messages in .Net 6? - c#

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?

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.

Related

sharing mouse click and key press events through windows (or handles)

I have 3, and sometimes more duplicates of an executable, and what I would like to do is to reduce workforce by sharing mouse click and key press events through all applications, with C#.
I am able to get handle's of executables, so ideas might be based on acquired handles.
Also I have done some work to ease my work, all applications are arranged at same coordinates, with the same window size. So basically transparent mouse and key clicks which will interact with all windows (the top window, as well as background windows) would do the trick.
You need to sned Windows Messages from one application to the other, but that involves security configuration.
Here you have how to do it:
Communication between applications via Windows Messages
Here you have comments about security issues, and ideas for alternative solutions
Sending, receiving and processing a windows message between windows applications
Stacking the windows isn't necessary. Once you have the handle to all the windows that you want to interact with, P/Invoke the SendMessage API to send your click to each window at it's target coordinates.
If I had the need for such a thing, I would put a picture box on a form and capture the image of one of the windows (so I can see what I'm clicking), then process the PictureBox.Click event to calculate the coordinates to use in the P/Invoke call(s).
There are several other tricks you could use to make your life easier and click-sharing utility better, but this will get you started.

Sending Commands to a Windowless Command Line process (started from the C# Application)

I've got a command line application that starts up and does some work. During that time, it listens to keystrokes (s => show status). It's not the typical command prompt where you press 's' and <ENTER> - it's the type which reacts as soon as the key is pressed the status is shown.
Now I'm trying to "control" that command line application from a fancy GUI application by sending keystrokes. I've tried the more conventional approach of writing to the Process' StandardInput but that doesn't seem to have an effect at all. Also, because the actual process doesn't have a window (it's started with CreateNoWindow=true) I can't try the Win32 API for sending keystrokes to a window.
Is there any other way of doing it?
Fancy console applications are problematic.
They have a tendency to directly read the keyboard input, instead of going through stdin. They also have a tendency to directly control their console, instead of going through stdout.
AFAIK, there is no way to programmatically control these apps. If you really, really need to, I would explore something like AutoHotKey controlling the app on a private desktop (AHK uses a virtual keyboard/mouse driver). I'm not sure how you would read the results off the console, though; it may be possible to create an intermediate console app that's started by your program (in the private desktop) and starts the target app. The intermediate app would then share its console with the target app and use low-level I/O to detect changes.
Or you could use Detours to bend the target app to your will.
Well, I seem to have found an answer to my own question.
It's a real "kludged together" solution, but it works - and for all the intents and purposes of the application I'm building, it doesn't matter.
So, what I did was use two WinAPI functions called
static extern bool ShowWindow(IntPtr WindowHandle, int nCmdShow);
static extern bool SetForegroundWindow(IntPtr WindowHandle);
The first one can be used to Show/Hide a window by changing nCmdShow to 1 and 0 respectively. The other one puts the window (determined by WindowHandle) to the front. Combining these two together, I was able to programmaticly bring the console window up front, do a simple SendKeys.Send(); operation and then hide it again.
// Use a WIN API command to bring the command line to front
SetForegroundWindow(workerProcess.MainWindowHandle);
// Send a keystore to re-display the STATUS of the worker
SendKeys.Send("s");
// Hide the window again.
ShowWindow(workerProcess.MainWindowHandle, 0);
Now, it's a real kludge job, but it gets the job done. One potential pitfall would be if a user is using the computer for something else, and would nail that 1 in a 10000000 moment when the window is active with a 'q' - it would quit the worker program. But the application is intended to be used on dedicated machines that most likely won't even have monitors, keyboards or mice attached to them so it wouldn't be an issue.
Thanks to all who answered, since you did - in one way or another, steer me towards the right solution.
I found an even better way to accomplish the functionality without the theoretical risk of causing problems with simultaneous user input and window-switching.
The trick is to use the WinAPI functions called PostMessage to send up KeyDown (or KeyUp) message to the process which does the same thing. No need to bring the process window to the front and hide it immediately afterwards!
I'm sending the key-down command with key 'S' as the argument:
// 0x0100 - VM_KEYDOWN
// 0x0101 - VM_KEYUP
// 0x53 - S-key
PostMessage(workerProcess.MainWindowHandle, 0x0100, 0x53, 0);
PostMessage(workerProcess.MainWindowHandle, 0x0101, 0x53, 0);

Register to window messages using 'hwnd'

Assuming I have a valid hWnd to an active window (it was retrieved using ‘GetForegroundWindow’ or FindWindow, for example), can I register to windows message of this hWnd, from another application, of course? Is there any Win32 API for this, or a built-in C# method?
Example: In my console application I have a hWnd to the ‘Notepad’ window (running in the background). Can I register somehow to messages indicating the ‘Notepad’ window had moved, changed size, minimized, closed, etc.?
Thanks,
Elad
You have to inject a DLL into the process that owns the window. Use SetWindowsHookEx(), WH_CALLWNDPROC hook. You cannot write such a DLL using the C# language, the process won't have a CLR initialized and ready to run your code. Native code is required. Check this project.
If you just need to know about it moving or closing, then check out SetWinEventHook. You'll have to write a P/Invoke wrapper for this, since there's no equivalent in the .Net API. You can use this without needing to inject a DLL (use the WINEVENT_OUTOFCONTEXT
flag), so can keep everything in C# (and it also avoids the hassle of having to communicate between a separate DLL and your main process).
You'll likely want the events EVENT_OBJECT_LOCATIONCHANGE and EVENT_OBJECT_DESTROY. Note that you get these for all HWNDs on the thread you are listening to, so you'll need to filter by HWND in your callback.
Note that when you use WINEVENT_OUTOFCONTEXT, your own code will need to have a message loop running on the thread that calls SetWinEventHook. Also, the notifications that you receive are not delivered instantly, but with a slight delay (similar to PostMessage), but that may still be fast enough for your purposes that you can avoid doing an in-proc hook.
You can use the Accessible Event Watcher app (AccEvent) that's part of the Windows SDK to see what messages are available from notepad before you start writing code.

Find which MDI child just got focus Win32 API

I have a program that has a MDI host and I would like to be able to get which of it children just got focus, bassiclly I would like to make a window focus changed event for this application.
The application is a 3rd party and I don't have the source, I have the window handle to the main program and the MDI host part.
I know I'll have to use Win32 API just not sure which ones.
I am writing my application in C#
Thanks.
I guess what you're looking for is intercepting WM_SETFOCUS and WM_KILLFOCUS messages
The real problem is how are you going to do this. I guess the easiet way is to install a hook which is a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure. You're doing it by using SetWindowsHookEx winapi function with WH_CALLWNDPROC or WH_CALLWNDPROCRET types of hooks. There some are examples posted on codeproject; also there is one on msdn: How to set a Windows hook in Visual C# .NET
What is not really clear in your post is where your code running: in the same process with the MDI windows or is it a separate application\service? In case it is you would also need to inject your code into the remote process. Check this link for details on how you can do it: Three Ways to Inject Your Code into Another Process
hope this helps, regards

C# - Determine if user is moving a window

I am going to be checking if the user is moving any window around (my application does not have an interface) and respond accordingly. What do you think is the best way to do this? Can I determine if the user is clicking on a titlebar? Can I determine if a window is being moved? I then need to grab the hWnd of the window after I know it's being moved.
To get notifications for all windows, not just Windows Forms ones, you'll need to use a hook set by the SetWindowsHookEx() API function. You'll need a WH_CALLWNDPROC hook so you can see the WM_MOVE message that Windows sends to the window.
Unfortunately, that's a global hook. The code that implements the hook callback needs to be packaged into a DLL so that it can be injected into all target processes. That shoots a hole into your plans to use C# for this, you can't inject the CLR. The DLL must be written in unmanaged code.
This code project offers an approach, including the unmanaged injectable DLL you'll need.
here is a technique to spy on window handles. You can inspect all the handles which are open and wait for the move messages.
EDIT
.NET spy code.

Categories

Resources