Contact   •   Products   •   Search

Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs

Calling JavaScript functions in the Web Browser Control


I’ve been working on a sample application that needs to load some generated display content into the Web Browser control and I’ve been wanting to interact with this content. One of the things I want to do is use some transitions like modal overlays and activity displays while pages load – in other words do some Ajax based UI functionality but with data that is provided by the host application.

The process for this goes something like this:

  • Bring up the form
  • Based on parameters provided as input render the form with HTML content
  • Interact with the page (like reload the display as changes are made or stuff data into the dom)

One of the operations that need to occur are re-freshes as new data is loaded so I like to display modal overlay. So in my page I have some script code that uses jQuery and my internal script library with something simple like this:

<div id="modalDialog" style="width: 100px; height: 100px;">
    <img id="loadingImg" src="loading.gif" />
</div>
<
script type="text/javascript"> function showOverlay(hide) { if (!hide) $("#modalDialog").modalDialog(); else $("#modalDialog").modalDialog("hide"); return "Rick" && just to demonstrate ret parameter } </script>

So, is it possible to call this script function in the page? Absolutely. As you probably know global functions are actually defined on the DOM’s window object so you can access scripts through the document.parentWindow  property of the DOM.

Now if you’re using Winforms .NET and the Web Browser control there’s a WebBrowser.Document property, but it doesn’t have a parentWindow property. The Document object .NET exposes is only a wrapper around the ‘real’ DOM COM object that Internet Explorer uses internally. The COM object is what we need to access in order to get at script code.

In order to do this we need to get the COM document object and then use Reflection to walk the hierarchy to do what essentially amounts to:

oWebBrowser.Document.DomDocument.parentWindow.showOverlay(false);

Here’s what this looks like inside of a small test form that contains only the Web Browser control and a button:

private void Form1_Load(object sender, EventArgs e)
{
    this.Browser.Navigate(@"C:\temp\html\_preview.htm");
}
private void btnOverlay_Click(object sender, EventArgs e)
{
    // This code is much easier than what I came up with – thanks to Jarle in comments
    // who pointed out the uhm obvious  
    object result = this.Browser.InvokeScript("showOverlay", false);

    MessageBox.Show(result.ToString());

    //// *** Get the COM DOM object (not the .NET Wrapper)
    //object doc = this.Browser.Document.DomDocument;

    //// *** Now you can use Reflection on the COM DOM
    //object win = wwUtils.GetPropertyCom(doc, "parentWindow");

    //// *** Call the JavaScript function and capture the result value
    //object result = wwUtils.CallMethodCom(win, "showOverlay", false);

    //MessageBox.Show(result.ToString());
}

The browser is navigated to testpage on startup and the interactive page is loaded. Then when the button is clicked the the overlay is displayed on top of it. The result looks something like this:

 ScriptedDOM

.NET makes this very easy as it has a Browser.Document.InvokeScript() function that can execute any script on the page with parameters and return a result value easily.

Originally I had completely missed this though and instead used COM Interop as you can see in the commented code. Jarle pointed out the obvious in the comments – bit again by the vast functionality in the framework. I was looking for a way to access the Window property of the document, which is where scripts normally are ‘attached’. Alas, Microsoft used Document.InvokeScript, which is in any case much cleaner than having to create a manual wrapper.

Egg on my face. It isn’t the first time I’ve made a simple solution difficult :-}… But I’m keeping this up here for (my own) reference especially in light of some of the complications in the following section.

You can download the .NET sample code from here.

A few gotchas for FoxPro

When I looked into this again I actually was working on a sample FoxPro piece for a conference presentation which has the same requirements. No matter what I tried though I could not get the function call to work calling the document.parentWindow or document.script object. Whenever I would call the method I’d get a method not found error.

After a bunch of experimenting and by accident creating a real simple function that had an all lower case name, I figure out that this is a bug/feature of the way FoxPro does COM interop with COM objects. Specifically it deals with casing and the fact that Visual FoxPro forces all COM functions called to lower case. Since JavaScript is case sensitive, the correct case is required in order for a function to be executed. This means effectively that FoxPro can only call lower case Javascript functions. The other issue is that you HAVE TO pass at least one parameter to the called JavaScript function even if that function does not take a parameter. Again this is an oddity in how VFP translates the COM interfaces to to call this dynamic function and passes it one parameter. This shouldn’t be a problem as you can just ignore the parameter in the JavaScript function.

The following can be done from the command window:

oBrowser = CREATEOBJECT("InternetExplorer.Application") obrowser.Visible = .t. oBrowser.Navigate("C:\wwapps\Conf\FoxWebServices\FoxCode\html\_preview.htm") oBrowser.Document.parentWindow.showoverlay(.F.) ? oBrowser.Document.parentWindow.showoverlay(.F.) ? oBrowser.Document.Script.showOverlay(.T.)

Note that in order for this to work with the script shown above the function name has to be changed to showoverlay() in JavaScript!

Works in the Web Browser Control or InternetExplorer.Application

As you can see in the FoxPro snippet this approach also works with the InternetExplorer.Application browser automation as well as in the Web Browser control. As long as you have access to the DOM document this approach should work regardless how the Web browser is hosted. Note that if you run in Internet Explorer though with scripts from the local machine (ie. not a Web Url) you will get a security warning every time you load the page. You have to allow scripts in the yellow warning bar at the top first before they can be accessed. This makes script access in the IE browser a lot less useful. The Web Browser control doesn’t have this limitation as it assumes you have whatever rights your application already has (or doesn’t have).

Nice

Because of the Fox case issue I had actually thought that this feature didn’t work any longer – suspected some sort of security hack – but it turns out the issue is merely a COM translation issue.  This will come in handy especially in .NET as I need to update some code that does some fairly heavy duty HTML editing code. With the ability to run some of that code in script in the browser and taking advantage of jQuery this will be a lot easier!

Make Donation
Posted in COM  .NET  WinForms  


Feedback for this Post

 
# re: Calling JavaScript functions in the Web Browser Control
by Steve September 28, 2008 @ 5:37am
How are you using this and why? I'm just curious why you wouldn't use use a web browser.
# re: Calling JavaScript functions in the Web Browser Control
by Rick Strahl September 28, 2008 @ 2:43pm
@Steve - the test data I used (which is amazon Web Service data) is probably a really bad example, but I use the Web Browser control for locally generated content in just about any desktop application I create. And yes I build many of those too in addition to Web apps - I don't believe that everything should run as a Web application - at least not yet <s>.

One prominent example is Help Builder which uses the Web Browser control for preview rendering and HTML Editing. That would be a horrible candidate for a pure Web application.

It's very useful to have access to script code inside of the *locally generated* HTML that gets displayed in the Web Browser control if you're doing complex things like say HTML editing where things need to get injected into the page dynamically.
# re: Calling JavaScript functions in the Web Browser Control
by Jarle September 28, 2008 @ 11:20pm
Hi.

I also needed to execute javascript code within the WebBrowser control and I used the code webBrowser.Document.InvokeScript("JavaScriptFunctionName", new object[1] { parameter1 }), and it worked fine.
# re: Calling JavaScript functions in the Web Browser Control
by Rick Strahl September 29, 2008 @ 1:20am
@Jarle - Duh - I completely missed this method since I'd been doing this through COM in the first place (in another environment).

Obviously using Document.InvokeScript() is the better solution - same approach.

(egg on my face). Move along - nothing to see here.
# re: Calling JavaScript functions in the Web Browser Control
by Suprotim Agarwal September 29, 2008 @ 6:35am
Yes. webBrowser.Document.InvokeScript is the way to go. I had posted an article on this a few weeks ago over here:

http://www.dotnetcurry.com/ShowArticle.aspx?ID=194
# re: Calling JavaScript functions in the Web Browser Control
by MikeS October 01, 2008 @ 5:43am
Hey Rick,

Do you know if it is possible to do this with jquery too? From what I've read on your article about jquery, there are no functions to call do I'm doubting it.
# re: Calling JavaScript functions in the Web Browser Control
by Rick Strahl October 01, 2008 @ 6:07am
@Mike - not sure what you mean. You can only access global scope functions in the document, but with COM it might be possible to walk all the way into parentWindow.$ to effectively use jQuery from C#. Haven't tried that but it should be possible using COM and Reflection since it's all there in the interfaces.

The question is - why would you want to do this? It'd be much easier to create a function in the document and hten have IT do the work. Even if you have to add the script into the DOM yourself for that matter.
# re: Calling JavaScript functions via Invokescript
by Chandan October 08, 2008 @ 7:24am
Hi,
I have this javascript code.

function submit_form(f)
{
/* Added on 20010313 by Felix Yu */
/*if (f.type.selectedIndex==0)
{
alert('¤½¶}©Û¼Ð¤½§i¬d¸ß¼È®ÉÃö³¬,½Ð¨Ï¥Î[¨Ì¼ÐªºÄݩʬd¸ß]©Î[¨Ì³æ¦ì¦WºÙ¬d¸ß],ÁÂÁÂ!');
return false;
}
*********************************/
if(uploadcheck())
{
if (flag_chk==false)
{
flag_chk=true;
//alert("¤w¶Ç°e");
f.submit();
return true;
}
else
{
//alert("¸ê®Æ³B²z¤¤¡A½Ðµy«á");
return false;
}
}
else
return false;

}

<input type="button" value="Search" onClick="submit_form(this.form)">



I have to call the invokescript function by passing a parameter this.form....what shall be the statement for invokescript along with the form parameter?...Can anyone please help?
# re: Calling JavaScript functions in the Web Browser Control
by Chandan October 08, 2008 @ 8:34am
How do I pass a form object via the invokefunction?
# re: Calling JavaScript functions in the Web Browser Control
by Sam January 03, 2009 @ 2:26am
I would like to know how to get at data generated by a javascript function that doesn't have a return value. For instance when there is javascript that is used to show some data, but it doesn't have a return value.
In this case I'm getting a null value for the object variable (in your provided sample code).
How do I access the data that the javascript is displaying on the page? Is it in a frame? Or somewhere else?
Any help very much appreciated.
Thanks,

-Sam.
# re: Calling JavaScript functions in the Web Browser Control
by TheGuy February 17, 2009 @ 11:48am
Chandan,

try making a javascript function in your page that does it for you, something like:

function SubmitMyForm(){
if( submit_form( document.theform_or_however_u_reference_it ) )
magical_submit_btn_click_func();

}


Then use Document.InvokeScript("SubmitMyForm"...);

I'm not a javascript/web guy, but that's my guess/suggestion.
# re: Calling JavaScript functions in the Web Browser Control
by Matt Stark March 01, 2009 @ 1:44pm
Hey Rick - Are you aware of a way to call a C# method from JavaScript from within the page running inside the Web Browser control?

Ideally I'd like to respond to a JavaScript click event in C# from the Windows Form.
# re: Calling JavaScript functions in the Web Browser Control
by Rick Strahl March 01, 2009 @ 2:46pm
@Matt - I believe you can call a JavaScript function as described above and pass a reference of a C# object. Attach that to the document as a global variable and you should then be able to call methods on that object from JavaScript code. Haven't tried this, but this used to work for me with FoxPro code in the past.

This assumes the Web Browser control is running in a security environment that allows this however.
# re: Calling JavaScript functions in the Web Browser Control
by Steve February 18, 2010 @ 4:23pm
I'm trying to scrape some data in the wb control after a "Next Page" uses some Ajax to load a fresh batch of data. However it's "not there" (Page 1 data still is).

Do you know of a way to access this? Plus, on a W2K machine the Ajax appears not to kick in and paging is done "normally". Thought of trying to disable js. Or perhaps there is a jQuery function that can read the dynamically loaded data...?
# re: Calling JavaScript functions in the Web Browser Control
by Tim Swanson March 15, 2010 @ 1:29pm
There's a typo in your first C# code snippet.

object result = this.Browser.InvokeScript("showOverlay", false);


should be

object result = this.Browser.Document.InvokeScript("showOverlay", false);


Thanks for this post. It was exactly what I was looking for.
# re: Calling JavaScript functions in the Web Browser Control
by mishi March 19, 2010 @ 1:39pm
Hi Rick,
Thanks for the post. I'm facing an issue with getting the document object from the web browser control. This works if the document I navigate to is on the disk (local or UNC path). However if I have this hosted in IIS and provide the url as http://localhost/mytest.htm I cannot get the document object. I am launching this from an activeX control that is embeded within an aspx page.

I am using C++ (since our legacy activeX is in C++) and the code is something like:
COleVariant* pvarURL = new COleVariant( _plugInDetails.pluginURL.c_str() );
COleVariant* pvarEmpty = new COleVariant;
_browser.Navigate2( pvarURL, pvarEmpty, pvarEmpty, pvarEmpty, pvarEmpty );
delete pvarURL;
delete pvarEmpty;

LPDISPATCH spDisp = _browser.GetDocument();
//this line immediately returns NULL - if this url is of the form http://xyz. If the url is on disk all goes well.


Any ideas? Btw the activeX control is marked safe for scripting and initializing.

Thanks
# re: Calling JavaScript functions in the Web Browser Control
by Gilberto Ruiz May 20, 2010 @ 11:13am
Hi, Rick.

this post was very usefull to me.

But I need do something before I gonna crazy!

In a web page, I have the follow script :

<A onclick=javascript:objTop.frameQueryBy.fnShowCaseDetails(11,12) onMouseOver="javascript:objTop.frameQueryBy.fnReclassificar('N','N'); Fprot(0 , 'NSNNNSSNSNNS' );>click here</a>

I need that my vfp code run the onMouseOver code.

I try to run the 2 functions on it but not work.

tks

Gilberto - Brazil
# re: Calling JavaScript functions in the Web Browser Control
by Yasir Godil August 30, 2010 @ 5:24am
Is this possible to load a page in Web browser control and then let user right click every control and perform some action available on menu. I must be able to know which button on menu was clicked and what was the ID or Name of the html control on which user right clicked ?
# re: Calling JavaScript functions in the Web Browser Control
by Expert Comment September 10, 2010 @ 3:18am
You can ClientScriptManager clss method RegisterClientScriptBlock or RegisterStartupScript method to invoke JavaScript Method.

Refer to below links for more details about the same.

http://www.a2zmenu.com/CSharp/Calling%20JavaScript%20function%20from%20CSharp.aspx
# re: Calling JavaScript functions in the Web Browser Control
by Abupama January 06, 2011 @ 8:06pm
yes nice post.
You can also call C# object methods from javascript in Microsoft webbrowser control.
by using window.external object...
http://bimbim.in/post/2011/01/06/C-Sharp-Calling-Dotnet-function-from-JavaScript-and-Accessing-HTML-element-from-Dotnet-with-Web-browser-control.aspx
# re: Calling JavaScript functions in the Web Browser Control
by Peter E. December 09, 2014 @ 9:17am
Hi,
I read this thread with interest, but I have one big concern.
All this will only work with the Visual Studio Browser Control, therefore the website will be embedded within the forms application.

But my problem is, that I have to find a solution to control a web application provided from an other company. And they won't like to embed their application within a forms app.

I'm seeking for a solution to control a standalone instance of IE 11. I found that with "SHDocVw.dll" and "msthml" I might do this job with this piece of code:

SHDocVw.InternetExplorerMedium IE = null;
IWebBrowserApp wb = null;
 
...
IE = new SHDocVw.InternetExplorerMedium();
IE.Visible = true;
 
...
string URL = txtURL.Text; // text input field with the URL to navigate
wb = (IWebBrowserApp)IE;
wb.Navigate(URL, ref Empty, ref Empty, ref Empty, ref Empty);
 
..
 
mshtml.HTMLDocument _document = (mshtml.HTMLDocument)IE.Document;
object result = _document.parentWindow.execScript("showOverlay();", "javascript");


But I don't get the result from the JavaScript back!
After searching in the web, I found in a Delphi forum that "parentWindow.execScript" doesn't return result codes in any case!

Has somebody a solution for this?

BR
Peter
 


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2014