Application.ShowForm =>System.InvalidOperationException

Class library usage, coding and language questions.
ssp
Posts: 4
Joined: Thu Dec 20, 2007 2:56 pm

Application.ShowForm =>System.InvalidOperationException

Post by ssp » Thu Dec 20, 2007 3:07 pm

Hello,

I try to automate a Winforms form using the Application.ShowForm method. But this results in a System.InvalidOperationException:
Additional information: Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement BrowserForm erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.
I also tried it using a delegate. E.G.:

Code: Select all

delegate Ranorex.Form ShowFormDelegate(System.Windows.Forms.Form i_form);

...

m_clientForm = (Ranorex.Form)browser.Invoke(new ShowFormDelegate(Application.ShowForm), browser);
where m_clientForm is a Ranorex.Form and browser is a System.Windows.Forms.Form.

Unfortunately the result is the same:
A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll

Additional information: Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement BrowserForm erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.
The call stack of the exception:
> System.Windows.Forms.dll!System.Windows.Forms.Control.Handle.get() + 0xdf bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.SetVisibleCore(bool value = true) + 0xcb bytes
System.Windows.Forms.dll!System.Windows.Forms.Form.SetVisibleCore(bool value = true) + 0xb7 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.Visible.set(bool value) + 0xe bytes
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason = -1, System.Windows.Forms.ApplicationContext context = {System.Windows.Forms.ApplicationContext}) + 0xee bytes
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x53 bytes
System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.Form mainForm) + 0x2e bytes
RanorexNet.dll!Ranorex.Application.ShowForm.AnonymousMethod() + 0x2c bytes
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(object state) + 0x2f bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x81 bytes
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(object state) + 0x6c bytes
What am I doing wrong?

Thanks,

Stefan

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Thu Dec 20, 2007 4:55 pm

Please explain what do you want to do and post your code lines.

Gabor
Ranorex Team

ssp
Posts: 4
Joined: Thu Dec 20, 2007 2:56 pm

Post by ssp » Thu Dec 20, 2007 5:30 pm

Background information:
I want to automate an .net Control embedded in an html-page in internet explorer (like a java applet).
To gain more control over the test runs I am trying to integrate the web browser control in my test project. So instead of calling

Code: Select all

Application.Start("C:\\Program Files\\Internet Explorer\\iexplore.exe " +  url);

(which works just fine) I've put a web browser control on a form and I am now trying to automate this form.
The reason behind this is that I can catch events from the internet explorer (like "Navigated") and use them to synchronize my test runs (instead of Application.Sleep for an estimated time).

The code:
I have a Windows Forms class called BrowserForm (hosting the IE-control) and now I am trying to automate this form:

But (as written above) neither:

Code: Select all

           BrowserForm browser = new BrowserForm();
            browser.DocumentURL = new Uri(url);

            m_clientForm = Application.ShowForm(browser);

nor

Code: Select all

            BrowserForm browser = new BrowserForm();
            browser.DocumentURL = new Uri(url);

            m_clientForm = (Ranorex.Form)browser.Invoke(new ShowFormDelegate(Application.ShowForm), browser);
works. I only get an exception.

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Thu Dec 20, 2007 5:53 pm

OK, please consider that the classes in the Ranorex namespace are not inherited from the classes in System.Windows.Forms.
So you cannot cast a System.Windows.Forms Form to Ranorex.Form.

But you can embed your explorer control in the test application and automate it in the same process.

Jenö
Ranorex Team

ssp
Posts: 4
Joined: Thu Dec 20, 2007 2:56 pm

Post by ssp » Fri Dec 21, 2007 9:10 am

OK, please consider that the classes in the Ranorex namespace are not inherited from the classes in System.Windows.Forms.
So you cannot cast a System.Windows.Forms Form to Ranorex.Form.
I am aware of that. And I am not casting a Windows.Forms.Form to a Ranorex.Form (at least I can't see that). The line

Code: Select all

(Ranorex.Form)browser.Invoke(new ShowFormDelegate(Application.ShowForm), browser)
calls the ShowForm method of the ranorex.application using a delegate in the same thread of the Windows.Form. Since ShowForm returns a Ranorex.Form the delegate call should return a Ranorex.Form, too. The cast is necessary because the invoke method of the Windows.Form.Form returns an object.

But you can embed your explorer control in the test application and automate it in the same process.
This is exactly what I am trying to do. But it is not working, because of the System.InvalidOperationException.

It looks like ShowForm is called from a different thread than the one which created the Windows.Forms.Form. I tried to overcome that using a delegate and the Invoke method, but so far without luck.
I could provide you a test project.

Stefan

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Fri Dec 21, 2007 10:59 am

Hi Stefan!

The problem is that your BrowserForm is constructed in the main thread (the one that calls new BrowserForm();) and that Application.ShowForm tries to show and access the constructed BrowserForm from another thread. This is not allowed by the windows infrastructure.

There are two options on how to create the BrowserForm: from the main thread or from a separate thread.
If you create the BrowserForm from the main thread, you can easily access all properties and methods of the BrowserForm, but actions in the main thread will block the BrowserForm and vice versa.
If you construct the BrowserForm from a separate thread, both forms run independently, but you need to Invoke all methods/properties accessing the other form either by using Ranorex or the Form.Invoke method.

The following example uses the second technique. The CreateFormButton_Click method starts a thread that constructs and runs a new form. Then it waits till the new form is constructed (by use of a ManualResetEvent) and creates a RanorexNet.Form from the Handle of the newly created form. It then uses Ranorex to set the title of the newly created form.

Code: Select all

private void CreateFormButton_Click(object sender, EventArgs e)
{
    formCreated = new ManualResetEvent(false);

    Thread thread = new Thread(new ThreadStart(CreateAndShowForm));
    thread.IsBackground = false;
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();

    formCreated.WaitOne();
    formCreated.Close();
    formCreated = null;

    Form theCreatedForm = new Form(lastCreatedFormHandle);
    theCreatedForm.Text = "MyNewlyCreatedForm";
}

private ManualResetEvent formCreated;
private IntPtr lastCreatedFormHandle = IntPtr.Zero;

private void CreateAndShowForm()
{
    Form1 createdForm = new Form1();
    createdForm.webBrowser1.Url = new Uri("http://www.google.at/");
    lastCreatedFormHandle = createdForm.Handle;
    formCreated.Set();
    System.Windows.Forms.Application.Run(createdForm);
}
If you set the IsBackground property of the created thread to true, the constructed form will be closed if the main thread (that calls the CreateFormButton_Click method) exits.

We will adapt the Application.ShowForm method for the next release to make it easier to use.

Alex
Ranorex Support Team
Last edited by Support Team on Wed Jan 02, 2008 1:30 pm, edited 1 time in total.

ssp
Posts: 4
Joined: Thu Dec 20, 2007 2:56 pm

Post by ssp » Fri Dec 21, 2007 4:04 pm

Hi Alex,

thanks, now I can start the form and automate it.

I have still some problems stopping the form thread, but this has to wait after the holidays.

Happy holidays!

Stefan

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Wed Jan 02, 2008 4:31 pm

Happy new year!

If you set the IsBackground property of the created thread to false (see the supplied example above), you must close the form (or manually abort the form process) in order to end the process.

Otherwise (IsBackground = true) the form thread is aborted (and the form discarded) when all the foreground threads of the application have exited and the process exits therefore.

Alex
Ranorex Support Team

nikivancic
Posts: 10
Joined: Sun Oct 05, 2008 5:31 pm
Location: Bellingham, WA, USA
Contact:

A slightly different view of the same problem

Post by nikivancic » Sun Oct 05, 2008 9:44 pm

I just posted the similar question in the context of the WebTesting (using WebSpy), so I do not believe that the answer provided here solves all problems related to the use of the Microsoft's WebBrowser control embedded in a Windows Forms application. The example shown here is rather "ugly" (meaning this in a benevolent way), since being able to get the the WebDocument from the embedded instance of the WebControl:

// Starting Internet Explorer
WebDocument webDoc = WebDocument.OpenDocument
("www.ranorex.com/products/overview.html", true);

would be a lot nicer - the OpenDocument method should be able to take the reference to the embedded browser instance as the argument.

In addition, it is not at all clear how can the WebSpy be used to generate the RanoreXpath strings off that embedded browser.

Can you please elaborate?

Nik

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Mon Oct 06, 2008 9:57 am

There is such a method: the WebDocument.GetDocument(Control) method returns the WebDocument corresponding to the passed web browser control (embedded or stand-alone IE). You can then use the WebDocument.Navigate(string) method to load a new URL.

You cannot use the WebSpy with an embedded browser, nor can you use it with a stand-alone one. The WebSpy has itself an embedded browser, but the generated RanoreXPaths will be the same in your integrated browser. So, just spy the web page you try to automate with RanorexWebSpy and use the RanoreXPaths in your automation application with your own browser.

Another way is to use RanorexSpyPro with which you can directly inspect your own embedded web browser. Just drag the cross-hair to the web elements in your browser and the property grid will show the corresponding RanoreXPath.

Regards,
Alex
Ranorex Support Team

nikivancic
Posts: 10
Joined: Sun Oct 05, 2008 5:31 pm
Location: Bellingham, WA, USA
Contact:

Perfect response, thank you Alex

Post by nikivancic » Mon Oct 06, 2008 2:58 pm

:D :D :D

Just what I was hoping for and even sooner than I expected. This experience matches my impressions about your product - terrific.

Nik

P.S. Is there a document that describes the Ranorex API?

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Mon Oct 06, 2008 3:15 pm

The Ranorex API documentation is included in the Ranorex setup (in the /Doc folder of the Ranorex installation). Or you can browse the API doc online here.

Regards,
Alex
Ranorex Support Team

nikivancic
Posts: 10
Joined: Sun Oct 05, 2008 5:31 pm
Location: Bellingham, WA, USA
Contact:

RanorexSpyPro?

Post by nikivancic » Mon Oct 06, 2008 4:03 pm

Hi, Alex

You referenced the RanorexSpyPro as the solution for direct inspection of the embedded IE control - can you please get me a reference to that tool. I found RanorexSpy and RanorexWebSpy, but could not find the RanorexSpyPro.

Thanks in advance

Nik

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Tue Oct 07, 2008 9:59 am

RanorexSpyPro is installed by default, there's a shortcut in the Ranorex start menu. There is no documentation for RanorexSpyPro in particular, please refer to the documentation of RanorexSpy.

Regards,
Alex
Ranorex Support Team

nikivancic
Posts: 10
Joined: Sun Oct 05, 2008 5:31 pm
Location: Bellingham, WA, USA
Contact:

Post by nikivancic » Tue Oct 07, 2008 6:38 pm

Thanks again for such prompt explanation.

Regards

Nik