(What im trying to do)
Im creating a web test in vsts 2008, unfortunately, it cant record messagebox and when this pops up you have to manually click it for the test to continue running. This is what im trying to automate. forcibly close the messagebox (at least).
(What i've already done so far)
in one program/process i have been able to automate the closing of messagebox (take note, its only on one application).
To do this i implemented this method
private static void Setup(string caption, uint uTimeout){
//if (hHook != IntPtr.Zero) // throw new NotSupportedException("multiple calls are not supported");hookTimeout = uTimeout;
hookCaption = caption !=
null ? caption : "";hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, hookProc,
IntPtr.Zero, AppDomain.GetCurrentThreadId());}
Now this method is only good when your dealing with a controled environment. where you could modify the code of what your testing.
So what happens is when i call the method
Setup("myCaption", 1000);
MessageBox.Show("hello world", "myCaption");
the message box closes after 1000 miliseconds. but this is only the 1st step the real problem begins here.
hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, hookProc, IntPtr.Zero, AppDomain.GetCurrentThreadId());
what should i pass to the parameter in order to detect proceses/threads outside the application? obviously it wont be GetCurrentThreadId();
(What im trying to achive...at the very least)
Create a listener (maybe a console app) run the .exe.
And everytime a messagebox shows up from any applications (e.g. internet explorer, windows forms), ill be able to close using the setup("myCaption",1000);
Any ideas are greatly appreciated...
AlanPosted Nov 16, 2008, 2:00 PM
The only type of global hook that can you can create from a managed process without unmanaged assistance is a low level hook.
To create a low level keyboard hook you'd need code such as this:
[DllImport("kernel32.dll")]
static extern IntPtr GetModuleHandle(string lpModuleName);
const int WH_KEYBOARD_LL = 13;
// ...
Process current = Process.GetCurrentProcess())
ProcessModule module = current.MainModule;
IntPtr hModule = GetModuleHandle(module.ModuleName);
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hModule, 0);
The easiest way to programatically click a button is by sending the corresponding keyboard shortcut to the MessageBox using the System.Windows.Forms.SendKey class or its unmanaged equivalent keybd_event.
To use the SendKeys class from a console application you need to add a reference to System.Windows.Forms.dll to the project and then include the following using directive:
using System.Windows.Forms;
So, if you have a Yes/No/Cancel MessageBox:
SendKeys.SendWait("%Y"); // clicks Yes
SendKeys.SendWait("%N"); // clicks No
SendKeys.SendWait("{ESC}"); // clicks Cancel
SendKeys.SendWait("%{F4}"); // closes the box
SendKeys sends keys to the window which currently has the input focus which should always be the case with a standard MessageBox.
Kai HungPosted Nov 16, 2008, 6:12 AM
About the link you gave me, i tried it and works like a charm! thanks!
but now that i can detect whenever a messagebox pops out... is there any way i can code it in c# where i can programatically click a button? (e.g. Yes, No, Cancel)
i have tried to use SendMessage() and End dialog() but all it does is to close the messagebox
Kai HungPosted Nov 15, 2008, 10:12 PM
Thanks for the reply... that linked you showed me helped clear a lot of things out.
But im just really curious, if i set the threadID to '0' then obviously the 3rd parameter cant be '0' (according to msdn), what should be assigned in the methods 3rd parameter?
AlanPosted Nov 15, 2008, 6:55 PM
To associate the hook procedure with all applications running on the desktop, the 'dwThreadId' parameter of SetWindowsHookEx should be set to zero.
You might also like to look at the thread below for another way to detect when a MessageBox is displayed without using a hook:
http://www.c-sharpcorner.com/Forums/ShowMessages.aspx?ThreadID=49851