I'm trying to create a C#.NET 2.0 script to automate a workflow in a third party application written in Java.
I’m using the user32.dll functions to be able to interact with the Java app windows.
My problem is that the Java app windows are slow to completely load and my action sent through IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, UInt32 wParam, IntPtr lParam) sometimes are lost. Example: during the load of the main window, if I try to open a menu (at this moment I actually have a handle on the main window), my message just is lost and the menu never opens.
I found some answers on Stack Overflow telling that we could use the Process.WaitForInputIdle() method for that purpose but I discovered that this only works if the app is mono threaded which is not the case of my Java app. ( C# SendKeys Wait for Program to Load before sending )
I'm looking for something working the same idea but that supports multithread or any other idea you could have?!: )
Following the Mari9' idea I finally used the System.Diagnostic.PerformanceCounter() to watch the third party app process activity. Then it commes to 0, it means the process has done what it had to do and is able to execute the message I send it.
PerformanceCounter PC = new PerformanceCounter();
PC.CategoryName = "Process";
PC.CounterName = "% Processor Time";
PC.InstanceName = "<process name>";
Console.WriteLine(PC.NextValue().ToString());
I assume you have a way of detecting when the window you want to send input to is shown on screen, but sending input immediately does not work since the window is busy.
You could have a predefined/hardcoded wait interval (possibly customized for each Java window) - this is not very reliable, but may work well in a controlled environment (for instance if the app is used only on your computer).
If the appearance of the window changes reliably when loading is complete, you might capture a screenshot of the window and test to see if the right pixels are there, and repeat this until true before sending the message.
Another option is using Spy++ to see if any particular message is generated for a window when the loading is complete (eg. could be a repaint with certain parameters) and install a hook to detect those messages.
If the Java application uses native window controls (SWT), you could try to detect changes in the window texts/structure indicating that the load is complete.
If the window loading process is resource intensive you might also monitor the CPU usage of the java app, and wait for the end of the 'peak' before sending your message.
Related
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.
I have a C# .NET 2.0 application running on client kiosk machine (Windows XP) that occasionally puts up a window for user input. The other kiosk software seems to be interfering with it somehow because while it is running our window will not receive Mouse or Keyboard events despite it being the top window. When the other software is not running all works as expected. Does anyone have any insight as to what might be going on here?
Thanks
If in doubt - use Spy++ provided with Visual Studio to see what messages your window receives from the system.
If the other application blocks all input, it's not conforming to the Win32 API. That's why the low level hooks timeout was introduced in Vista and newer Win OS. Meaning a process would be kicked out of the low level hook chain, if it held onto a hook too long before calling CallNextHookEx() and not receive any low level hook messages anymore.
On Windows XP, there is no such limitation. A process can take as much time as they want to process a hooking message. The other program is either buggy, or evil. If it's essential that your application has input, then just close the other one programmatically or contact the author of it and explain the situation.
Take a look here
http://www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C
Using global keyboard hook should do just fine and some sources are included as well. Also, some user seem to solve similar problem by using ManagedSpyLib:
https://stackoverflow.com/a/8829286/1284902
After some digging, it is possible that the other windows forms program is utilizing a low level keyboard hook similar to one found here http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx. After following a link in that article, I came across a summary of that code snippet
For a concrete example of this, consider the (buggy) code in Figure 4. Using a low-level keyboard windows hook, the code intercepts all WM_KEYDOWN messages sent to any window and prints out the corresponding key.
Source: http://msdn.microsoft.com/en-us/magazine/cc163606.aspx
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);
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.
I have an application that I would like to write an automated test for. The automated test will mimic an Operator's usage of the application. I cannot change the source code of the application as it is "frozen" for review.
The application will display a pop-up (message) window informing the operator to click on a button after measurements are finished. The button is enabled some time after the message window is closed.
I need to know how to detect when the application enables this button. My research so far indicates that the application should broadcast a custom message to help the automated testing; but I cannot modify the source code.
Also, the application will enable radio buttons after the "Measurements Finished" button has been clicked, asking if the measurements were valid. I need to detect this also.
Summary:
How do I detect when a button
(control) is enabled in another
application?
How do I get the handle of the other
application?
I am using C# with MS Visual Express 2010 on Windows NT, Vista & 7. If you suggest tools, I need them to be free as the company has a very tight budget.
I think you could do the job using FindWindow API, passing title and receiving the handle.
Then, enumerating children components, you could find the button (if you catch its name, next time you can use it to be quicker) and get the enabled state.
I think you could use AutoIT software (script) or its logic.
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr FindWindow(string strClassName, int nptWindowName);
EDITED:
Check this link to find a simple way to do what you need.
I hope this helps you.