Saturday, April 21, 2007

Calling Javascript from C#

Call JavaScript from C# code, passing parameters and returning results.

I came across a need to call JavaScript methods on HTML code inside a web page from a C# WinForms application. How could that language gap be bridged?

It turns out that Type.InvokeMember() does the trick when using a WebBrowser control to load a web page.

using mshtml;
...
private AxSHDocVw.AxWebBrowser axWebBrowser1;
...
/// 
/// Retrieves a reference to the HTML element containing a DIV.
/// JavaScript methods are implemented on this element itself.
/// 
/// A reference to the HTML element holding the JavaScript methods
private HTMLDivElementClass GetContainer()
{      
 HTMLDivElementClass container = null;   
 IHTMLDocument2 doc = axWebBrowser1.Document as IHTMLDocument2;
   
 if (null != doc)
 {
  foreach (IHTMLElement element in doc.all)
  {
   if (element.id == "My_Container")
   {
    container = element as HTMLDivElementClass;
    break;
   }
  }
 }
   
 return container;
}

/// 
/// Gets the text from the container 
/// 
/// A string containing the text of the container
private string GetText()
{
 string result = null;
 HTMLDivElementClass div = GetContainer();
 if (null != div)
 {
  Type type = div.GetType();
  result = (string) type.InvokeMember(
    "GetText", 
    BindingFlags.InvokeMethod, 
    null, 
    div, 
    null);
 }   
   
 return result;
}

The HTML page loaded in the WebBrowser control has a DIV element with an id of "My_Container", attached to which is a method called GetText(), which returns some arbitrary text.

Having acquired a reference to the DIV on which the JavaScript method is declared (using GetContainer()), the JavaScript method is called using the InvokeMember() method of the Type class instance; the return value is cast to a string.

Discussion

There is every reason why this should NOT work, but the implementers of the WebBrowser control decided that JavaScript methods living within the DOM should be accessible as first class object members at runtime (in this case, via IDispatch). Nice!

Result

C# code can call arbitrary JavaScript within an HTML page! The only limitation is that the return types of the JavaScript methods can be only simple types (even DateTime is too complex).

Labels: , , ,

Monday, September 19, 2005

Accurately detect Mozilla/Firefox, Netscape, Opera [etc.] from ASP.NET

intro: ASP.Net -- its Request.Browser object is useful for easy browser detection. Request.Browser uses the section of the machine.config XML file (and the optional web.config XML file) to match the current browser's UA (User-Agent) string with its matching capabilities.

problem: just like ASP's browscap.ini before it, nobody official is updating this info. Microsoft pawns the job off on Cyscape.com, which doesn't care about doing the world a service (it's busy selling its competing BrowserHawk product instead). As a result, machine.config is already woefully out-of-date and unaware of newer browsers like Mozilla/Firefox, Netscape 7, Safari, and Konqueror, so it tells Request.Browser that they are "Netscape 5" (though Safari and Konqueror are wholly unrelated rendering engines).

problem 2: I went searching and searching for a newer BrowserCaps section updated by someone else. I found some possibilites (linked below), but I didn't like that they don't identify Netscape as Gecko (extrapolating the Netscape brand's marketing version from the real Gecko engine's version). Since Gecko is the rendering engine underneath, that's what we webdevs should care about.

problem 3: By default, Opera lies to web servers that it is Internet Explorer. It sends a UA string like "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera x.x".

solution: ...so I rolled my own BrowserCaps section. I swiped a starting point (also linked below), and warmed up my RegEx chops for the rest. Besides identifying Netscape 6+ and Mozilla/Firebird as Gecko, my update also fixes detection of Konqueror (aka KHTML) and Safari (aka AppleWebKit), and detects Opera as itself. Finally, it (now) also corrects the EcmaScriptVersion and TagWriter properties for Opera 6+.

http://slingfive.com/pages/code/browserCaps/

Labels:

Thursday, May 05, 2005

How To Raise a "File Download" Dialog Box for a Known MIME Type

When you serve a document from a Web server, you might want to immediately prompt the user to save the file directly to the user's disk, without opening it in the browser. However, for known MIME (Multipurpose Internet Mail Extensions) types such as Microsoft Word ("application/ms-word"), the default behavior is to open the document in Internet Explorer. You can use the content-disposition header to override this default behavior. Its format is: Content-disposition: attachment; filename=fname.ext
[http://support.microsoft.com/kb/260519/EN-US/]

Labels:

Tuesday, December 07, 2004

Flash of Unstyled Content (FOUC)

[From BlueRobot]

What is a FOUC?

Some pages that use the CSS @import rule experience a curious display quirk in the Windows version of MS Internet Explorer: a momentary flash of unstyled page content. The unimaginative creature that I am, I call this phenomenon Flash of Unstyled Content or FOUC for short. [Read more about FOUC...]

Labels: