Hang with InvokePattern - Invoke

Hi guys,

I'm having a problem with the invoke functionality.
I made a small test application which contains one button.

The code in the click event is the following:
Thread.Sleep(1000);
MessageBox.Show("MSGBOX1","MSGBOX1");

Now from my other application that uses UIAutomation, I click the button with this code:
InvokePattern ctrl_invokepattern = (InvokePattern)control.GetCurrentPattern(InvokePattern.Pattern);
ctrl_invokepattern.Invoke();
MessageBox.Show("Hmmm it doesn't get here?","MSGBOX2");

The code to click the button works, but the 'Invoke()' functions DOESN'T return?

So when the next line would be: click the OK button on MSGBOX1, this doesn't work!
I first have to manually click on the ok button of MSGBOX1 and then the code resumes execution...

Anyone know how this is caused and how it can be circumvented or be fixed in MSFT's code?

[1379 byte] By [NickAsseloos] at [2008-2-12]
# 1

hi,

I am working for UIautomation of some WPF application.

please give me some sample applications to automate WPF application. so that i can learn. plz.

plz help me.

waiting for your replay. :)

mail me : anubhav_kuhad@yahoo.com

akuhad at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 2

Not really enough information to know what you are trying to do, but see the Remarks for InvokePattern.Invoke, and check out the InvokePattern and ExpandCollapsePattern Menu Item Sample in the SDK.

PeterDonnelly-MSFT at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 3

peter,

thanks for replay.

Actually i have to write application in C# to test UI application implemented in WinFX(xaml).

I am good in c++ but not in c#.

So, I am searching for a good tutorial that tell me how to test simple xaml application using c#.

i just need two demo applicaion.

1. client ( with some button and combobox only in xaml)

2. tester ( test applicaiont .......... with this i can click on button and combobox.)

plz help me in this regard.

:) :) :) waiting .............for replay

akuhad at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 4

akuhad,

Sorry for the confusion; my previous reply was directed to the originator of this thread. For separate questions, you should start a new thread.

There is at present one SDK sample that demonstrates UI Automation in a WPF custom control -- see the documentation under Windows Presentation Foundation Samples / Technology Samples / Controls / Control Customization / NumericUpDown Custom Control with Theme and UI Automation Support Sample.

PeterDonnelly-MSFT at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 5

Hi guys,

Because of the cross post, the first post doesn't seem to be answered.
Does someone experience this problem and know what the problem is?

It is very easy to reproduce...

Thanks,
Nick

NickAsseloos at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 6

I have this issue.

App1 has a button "Button1" which when clicked calls MessageBox.Show()

App2 is the automater, it calls invoke on "Button1" and the MessageBox gets displayed.

Now my automater app is blocked until I manually click the MessageBox ok button. Is there some way to unblock the app and automate the clicking of the message box ok button?

Thanks,

-jim

jameshar at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 7

I'll try to restate the issue and suggest a workaround. Please correct me if I misunderstand the problem.

A target WinForms application contains a button that, when invoked by a UI Automation client, instantiates a modal dialog box. This dialog box blocks the automation thread and the Invoked event is not fired until the dialog box is dismissed.

This appears to be an issue in the design of the WinForms control as it is a widely reported issue with MSAA also.

One resolution could be to spin off a separate 'monitor' thread when the button in the target is clicked. This thread can then query or interact with the dialog box.

Hope this helps,

Karl

KarlBridge-Microsoft at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 8

Thanks that sorted it.

Cheers,

-jim

jameshar at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 9

I tried to create another thread to do "Invoke" just like the following

internalbool StartInvokeThread(InvokePattern invPattern)

{

workerThread = newThread(newParameterizedThreadStart(StartInvokeWorkerThread));

workerThread.Start(invPattern);

returntrue;

}

privatevoid StartInvokeWorkerThread(object invPattern)

{

(invPattern asInvokePattern).Invoke();

}

But it doesn't work. When the messageBox show up in response to "invoke", my "automator client app" is blocked until I manually click close button of the message box.

How I prevent my "automator client app" from blocking when modal dialog box pops up in response to "invoke"?

Any sample code will be appreciated.

Thanks,
FY

farn_yu at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 10
Hi, everybody here,

I am also searching for ideas, how can I use UI Automation to click a message box away?
Or can I define somewhere more globally to exit all the messageboxes shown?

Thanks in advance!
Miamix

Miamix at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 11
Hi there. I was having a similar issue involving modal dialogs. My issue was that it involved my UI automation driving an external program. The external program in question started automatically as a minimized system tray icon. Once the UI was visible I would drive the UI which opened a second form which was modal. While it would call the InvokePattern.Invoke method it would not return since the Invoke() method was blocking. This rendered the rest of the automation inert until manual intervention.

I hope that this code is helpful to folks. farn_yu: I would imagine that you need to do something with the Modal window, either make it go away or have your automation code perform actions on the UI within the Modal window. Or call AutomationElement.SetFocus() to go back to the parent form if possible.

I'm not entirely happy with the solution but it works for now. I pieced it together from other forum posts within the UI Automation forum and from this existing thread located here:

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1205648&SiteID=1

My solution was something similar to the following:

Code Snippet

// your using statements may differ
using System.Diagnostics;
using System.Threading;
using System.Windows.Automation;
using System.Runtime.InteropServices;

namespace foo
{
class bar
{
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();

//Search for a elment just by name starting from root
private static AutomationElement GetElement(AutomationElement root, string name, bool recursive)
{
PropertyCondition condName = new PropertyCondition(AutomationElement.NameProperty, name);
return root.FindFirst(recursive ? TreeScope.Descendants : TreeScope.Children, condName);
}
//Search for the first occurance of a given type of control
private static AutomationElement GetElement(AutomationElement root, ControlType controlType)
{
PropertyCondition condType = new PropertyCondition(AutomationElement.ControlTypeProperty, controlType);
return root.FindFirst(TreeScope.Descendants, condType);
}

static void Main(string[] args)
{
ProcessStartInfo psInfo = new ProcessStartInfo(@"C:\foo\bar\baz.exe");
Process prov = Process.Start(psInfo);
Thread.Sleep(1000);

// get the system tray item
AutomationElement aeTray = GetElement(AutomationElement.RootElement, "Baz", true);
InvokePattern ipTrayClick = (InvokePattern)aeTray.GetCurrentPatter(InvokePattern.Pattern);

// Here we just double click to bring the tray item UI to the foreground.
// Future Note to Self: Context Menu controls are children of the Desktop.
ipTrayClick.Invoke();
ipTrayClick.Invoke();

// get the form for the UI and button control
AutomationElement aeBazForm = GetElement(AutomationElement.RootElement, "Baz-o-matic", true);
AutomationElement aeButtonGroup = GetElement(aeBazForm, "ModalGroup", true);
AutomationElement aeModalButton = GetElement(aeButtonGroup, "SpawnModal", true);

// create the pattern and then spin it into a non-blocking thread
InvokePattern ipSpawnModalButton = (InvokePattern)aeModalButton.GetCurrentPattern(InvokePattern.Pattern);
ThreadStart tsInvokeModalDelegate = new ThreadStart(ipSpawnModalButton.Invoke);
Thread tModal = new Thread(tsInvokeModalDelegate);
tModal.Start();

// this is a silly kludge which you probably won't need
Thread.Sleep(500);

// This works because the modal form when opened has foreground focus
// by default. This may not be the case in everyones situations. YMMV.
AutomationElement aeModalForm = AutomationElement.FromHandle(GetForegroundWindow());

/* At this point you should be able to read over the controls present
in the form. A caveat however: when spinning this new thread and
invoking the desired pattern. This will make that new Modal Form
"invisible" from tools like UISpy. When manually closed, and then
manually Invoked (from the same thread) the Modal Form will be
present as a child of the parent form. That might complicate and
annoy while developing your automation. The discovery of controls or
elements within the child Modal Form should be as normal by the
FindFirst() and FindAll() methods. Just FYI. */

// close the Modal, this sample code is done.
AutomationElement aeModalTitleBar = GetElement(aeModalForm, ControlType.TitleBar);
AutomationElement aeCloseExitButton = GetElement(aeModalTitleBar, "Close", true);

// invoke the close, we're done
InvokePattern ipCloseButtonClick = (InvokePattern)aeCloseExitbutton.GetCurrentPattern(InvokePattern.Pattern);
ipCloseButtonClick.Invoke();

}

}

}


This may not work for all scenarios and may require further tweaking to meet your criteria. Particularly with regards to the thread which wasn't disposed of, etc.
cadams at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 12
Hi, Cadams,

thanks very much for the listing. I know you can click a modal dialog away by using another thread. But I really don't know how can you click a message box away.
Message box can not be identified by name, or not?

Miamix

Miamix at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 13

Your welcome. I did some thinking about your post and here's my suggestion. If your responsible for the MessageBox appearing; ie: it appears due to an action you perform via your automation. If that's the case then the pattern/technique should be the same. I don't know the full details of your problem but I think that overall technique should be same:

  • Spin the action that creates the MessageBox to another thread.
  • Find the MessageBox and find the Controls on the window.
  • Then perform a click operation on the Button control for that message box.
  • Then go on with the rest of your automation.

I made a quick test application with a button control which has a MessageBox.Show() call. Examining the properties of the MessageBox dialogue shows that it has: IsModal=True. Since you know how to do the different thread trick; just use that and you'll be fine. The behavior/pattern is the same.

If you need to find the name of the MessageBox you can do that via the following means. Use: Spyxx.exe or Uispy.exe. They should be included either in Visual Studio or within the .NET Framework SDK; take a look and see if you have them already first. They can show you the various properties of a given window or UI element, etc. If you check the MSDN downloads section or in their past articles you can find another tool called: ManagedSpy. It is provided as a Visual Studio project/solution, so you'll need to compile it after downloading. It has the neat ability that you can make changes to them whilst the program is running, outside of a debugger. Very handy for setting a form to be visible or changing the hidden property. Using those tools you can see all the properties and items you need to indentify the MessageBox uniquely. Once you can identify the MessageBox you should be able to operate on it just fine as long as your not having the blocking issues. Note: doing a search from the root (the desktop) can inccur a performance hit, just FYI. Try to use as much unique information as possible if you do use the GetElement() function. Either the ControlType, the TitleBar, etc. If you choose to use GetElement().

I should take this opportunity to add a correction for my previous code sample. This error has been bugging me since I posted it originally sometime ago:

I mention that when spinning the thread it will make such UI forms invisible to UISpy. THIS IS WRONG. I was getting intermittent behavior while refactoring my original solution and making a generalized solution suitable for public distrobution. Sometimes it wouldn't be visibile within UISpy. Please beware of this, you may or may not experience this problem. After tinkering I was able to get my automaiton to function and find the Modal Form as created within another thread perfectly fine and be able to verify it with UISpy as I stepped it through in a debugger. Just mind yourself if you run into this problem. I wish I knew the cause or how to resolve it.

cadams at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...
# 14
Hi, cadams,

thanks very much for your rapid answer.

Perhaps first a short description for my case. I tried to use UIAutomation for Automated GUI Unit Tests. The Messages Boxes are for example shown when an exception is thrown. But I don't want that it blocked the running of the tests.

I did not know how to find the "OK" button on any potential message boxes shown in the test process and click all them away.

I used UISpy to have a look as u suggested. The Message Box has the AutomationID as an empty string. How have you found the button in your test application actually?

I'm now not work on this subject, will have a detailed look into it as soon as I have time.

Thanks once again!

Miamix

Miamix at 2007-10-7 > top of Msdn Tech,Software Development for Windows Vista,Microsoft UI Automation...

Software Development for Windows Vista

Site Classified