在C#中使用MSHTML的高级支持接口
原文出处 Using MSHTML Advanced Hosting Interfaces, CodeProject
下载源代码:IDocHostUIHandler(79KB)
摘要
本文向你演示了如何使用IDocHostUIHandler之类MSHTML的高级接口。
概览
本文将向你展示如何在 .NET 下使用 MSHTML 的高级支持接口,特别是其中的 IDocHostUIHandler 接口。这一系列的接口可以帮助你自由调整 Microsoft 的 Web Browser Control (Web 浏览控制)用户界面。你可以在 Web Browser 中显示个人的定制上下文菜单。而我将向你演示如何使用 IDocHostUIHandler 这个接口,而不是自己重写一个同样的接口。额外的,我还将演示如何接收 Web 页面中的文档( Document )元素发出的事件。
问题的产生
将一个 Web Browser 控制放在一个 Form 上从而实现完整的浏览器功能,是一件非常轻松的事。但在你的应用程序里,也许你希望能更充分地控制用户与 Web 控制间的交互。比如当你的应用程序使用了基于 DHTML (动态 HTML )的用户界面时, IE 的标准上下文菜单便实在是配不上它了。而一个叫作 IDocHostUIHandler 的接口则能为你提供改变所有这些的能力。
实现 IDocHostUIHandler 接口
你的应用程序必须实现一个 IDocHostUIHandler 接口,之后再使用 ICustomDoc::SetUIHandler() 方法告诉 MSHTML 你已经实现并希望使用这个接口。 IDocHostUIHandler 接口包含在 Platform SDK 的 Internet Development SDK 中,并由 MsHtmlHst.IDL 所定义。
对于在 C# 中引入这些接口,我曾经见过的一种方法是手工地在源码中写出其接口的定义。而我准备使用另一种方法:创建包含所需接口的类型库来声明它,之后再通过 TLBImp 工具创建一个 Interop 程序集。这样你就不需要自己定义参数的封送过程了。
首先,要创建一个包含了所需接口声明的 IDL 文件,当然地你也需要给生成的类型库提供一个 UUID 。该 IDL 文件的全部内容如下(MsHtmHstInterop.idl),而我们只需要其中的一部分接口:
[ uuid(47F05070-FD66-45cc-AD99-74260F94A16B)]library MsHtmHstInterop{ import "MsHtmHst.idl"; enum tagDOCHOSTUIDBLCLK; enum tagDOCHOSTUIFLAG; enum tagDOCHOSTUITYPE; interface ICustomDoc; interface IDocHostShowUI; interface IDocHostUIHandler; interface IDocHostUIHandler2; interface IHostDialogHelper;};
在上述的这个 IDL 文件中,我已经包括了 MSHTML 所有的高级支持接口及其枚举类型。
下一步是利用这个 IDL 文件,通过 MIDL 这个 Platform SDK 工具生成对应的类型库 TLB 文件。
midl MsHtmHstInterop.idl /tlb bin\MsHtmHstInterop.tlb
接下来,我们再利用该 TLB 文件,通过 TLBImp 工具生成对应的 Interop 程序集。
tlbimp bin\MsHtmHstInterop.tlb /out:bin\MsHtmHstInterop.dll
现在我们就可以在我们的 C# 程序里直接通过一个 using 语句使用这个程序集来访问这些接口了。
using MsHtmHstInterop; //节选自HtmlUI.cs
实现
在这个演示程序里,我将在 Form 上放置一个 Web Browser 控制,并由该 form 类实现 IDocHostUIHandler 接口。
要将 IDocHostUIHandler 的个人实现挂接到 MSHTML 上,我们首先需要获得 ICustomDoc 接口,然后再将个人实现的 IDocHostUIHandler 接口作为参数,调用 ICustomDoc 接口的 SetUIHandler() 方法。
//节选自HtmlUI.cs中HtmlUIForm的constructor
public HtmlUIForm()
{
InitializeComponent();
this.WebBrowser.DocumentComplete +=
new DWebBrowserEvents2_DocumentCompleteEventHandler(this.WebBrowser_DocumentComplete);
object flags = 0;
object targetFrame = String.Empty;
object postData = String.Empty;
object headers = String.Empty;
this.WebBrowser.Navigate("about:blank",
ref flags,
ref targetFrame,
ref postData,
ref headers);
ICustomDoc cDoc = (ICustomDoc)this.WebBrowser.Document;
cDoc.SetUIHandler((IDocHostUIHandler)this);
this.WebBrowser.Navigate(@"res://HtmlUI.exe/Sample1.htm",
ref flags,
ref targetFrame,
ref postData,
ref headers);
}
以上就是所有要做的了。当然地, form 必须实现 IDocHostUIHandler 接口的所有方法。
资源里的 HTML 文件
也许你注意到了,在我的代码里使用了一个资源: protocol 。这是一个简易方法,用以将 HTML 文件及其他的支持文件打包进你的 EXE 文件中。这种方法还有几个优点:用户无法轻易地更改你的应用程序界面;你也不必为把其他的文件打包进你的安装程序包里大费周张。你所要做的仅是创建一个资源定义文件 :HtmlUI.rc
Sample1.htm HTML "Sample1.htm"
之后它会被编译为一个 RES 文件,然后你再通过 /win32res 这个编译开关将该 RES 文件加入你的程序集中。
处理文档事件
如果你的应用程序拥有一个基于 DHTML 的用户界面,那你需要捕捉页面中元素发出的事件,以使其功能更完善。在你运行我这个演示程序时,将会看到:当点击页面中的按钮后,会弹出一个消息对话框,这个对话框是从 C# 应用程序中触发的,而非页面中的脚本。以下即是其代码:
//节选自HtmlUI.cs******* void WebBrowser_DocumentComplete(object sender, AxSHDocVw.DWebBrowserEvents2_DocumentCompleteEvent e){ // 获取文档对象 IHTMLDocument2 doc = (IHTMLDocument2)this.WebBrowser.Document; // 获取按钮的一个引用reference HTMLButtonElement button = (HTMLButtonElement)doc.all.item("theButton", null); // 将事件处理器通过事件接口进行绑定 ((HTMLButtonElementEvents2_Event)button).onclick += new HTMLButtonElementEvents2_onclickEventHandler(this.Button_onclick);} ******* bool Button_onclick(IHTMLEventObj e){ MessageBox.Show("Alert from the app: Received theButton.onclick!"); return true;}
生成应用程序
我已经把一个 Make 文件包括在源代码包里了,这样你可以在命令行方式下通过 NMake 命令行工具生成本文的这个演示程序。注意 TLBImp MsHtml.TLB 这步可能会多要点时间才能完成。