RSS 2.0 Feed
脚本(Scripting)
摘要:同自动化浏览器(http://blog.joycode.com/jiangsheng/archive/2005/10/20/65489.aspx)相比,自动化浏览器控件(WebBrowser Control) 在应用程序中更加常用。从Outlook的预览窗格到Maxthon这样的基于IE引擎的浏览器,从无界面的HTML分析器到Norton Antivirusd的主界面,浏览器控件在众多领域被用作各种各样的用途。这也使得有必要根据具体的用户需求自定义浏览器控件的行为。 在应用程序中加入浏览器控件 集成浏览器控件的最简单的方法是找一个支持ActiveX的集成开发环境,在工具箱中加入Microsoft Web Browser这个控件,往表单上拖一个这个控件就可以完成工作。你甚至可以用集成开发环境添加ActiveX的事件处理函数。如果要直接导入ActiveX的话,建议使用mehrcpp的vbMHWB控件(http://www.codeproject.com/atl/vbmhwb.asp)。这个控件在浏览器控件的基础上进行了扩展,暴露了很多底层接口。 通常导入ActiveX就可以满足大部分需求  ,但是有些类库中也集成了浏览器控件,并且提供了更多的功能,例如MFC的CHTMLView和CDHtmlDialog,ATL的HTML Control,以及.Net 2.0中的Windows.Forms.WebBrowser。如果使用Visual C++来进行非托管编程,那么建议使用MFC或者ATL的封装类,或者使用vbMHWB控件。托管编程中当然首选Windows.Forms.WebBrowser。除非这些类的BUG影响到了应用程序的开发,否则建议使用这些功能更加强大的封装类。 在使用浏览器控件及其封装类的时候要注意一些已知问题 最后一个包含浏览器的窗口关闭时会话信息可能会丢失(http://support.microsoft.com/kb/311072) MFC6.0版本的CHTMLView中一些方法没有释放获得的BSTR字符串,造成内存泄漏(http://support.microsoft.com/kb/241750)。 MFC6.0版本的CHTMLView缺少WS_CLIPCHILDREN风格,使得其中的浏览器控件重画不正常(http://support.microsoft.com/kb/220021) Windows.Forms.WebBrowser的WebBrowserSite类不能通过重载来自定义其行为(https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=115198) 常见任务 在集成浏览器控件之后,可以完成基本的网页浏览,但是对于不同的任务,也需要进一步的处理,例如设置控件的属性、为控件添加事件处理、操作HTML文档等等。 修改浏览器控件的属性 这在集成开发环境中可以很容易地设置,也可以自己实现容器来设置,但是CHTMLView这样的封装类没有这个选项(http://support.microsoft.com/kb/197921)。 链接目标解析。对于用浏览器控件来做浏览器的场合来说,需要将浏览器的RegisterAsBrowser属性设置为true。这使得Internet Explorer在解析HTML链接的target属性指定的目标窗口时可以找到这个窗口。 禁用拖放。对于使用浏览器控件来做预览窗格的场合来说,需要将浏览器的RegisterAsDropTarget属性设置为false。这使得窗口不接受拖进来的文件和链接。 禁用消息框。对于用浏览器控件来做HTML分析器的场合来说,有时需要屏蔽脚本产生的消息框以避免阻塞程序运行。这可以通过设置浏览器的Silent属性来实现,或者实现IDocHostShowUI::ShowMessage。 捕获浏览器控件的事件 集成开发环境中可以也很容易地添加浏览器的事件处理函数。比较常用的事件包括 NewWindow2或者NewWindow3事件。默认情况下,浏览器控件中创建的新窗口会是一个Internet Explorer的窗口。这通常不是预期的行为,对于浏览器程序来说更是这样。需要处理浏览器的NewWindow2或者NewWindow3(在Windows XP SP2或者Windows 2003 SP1之后可用)事件来让新的浏览器窗口在应用程序提供的窗口中运行。 WindowClosing事件。浏览器控件需要处理WindowClosing事件来在浏览器控件被脚本关闭时关闭浏览器控件的宿主窗口(http://support.microsoft.com/kb/253219)。 BeforeNavigate2事件。可以在自己的网页中加入自定义的协议,之后在BeforeNavigate2事件中扫描URL来进行网页和应用程序之间的交互(http://www.microsoft.com/msj/0100/c/c0100.aspx)。当然,自定义的网络协议也可以用Asynchronous Pluggable Protocol来处理(参见http://support.microsoft.com/kb/303740),vbMHWB控件就实现了这个功能。但是更加常用的是在弹出广告过滤器程序中用BeforeNavigate2来判断在NewWindow2事件中创建的窗口是否需要关闭。 操作MSHTML文档 通常HTML分析和浏览器自动化程序都需要分析网页的结构,找到需要操作的元素。这需要对网页的结构进行分析,找到目标元素的标识方法。 一些常用的操作包括: 设置HTML元素的属性,例如html、style、value等等。注意有些属性是只读的,甚至是程序无法访问的(例如input元素在类型为文件时其value属性不可访问)。 分析网页的结构来保存网页数据,例如拆取Web 页一文介绍的方案(http://www.microsoft.com/china/msdn/Archives/workshop/scrape.asp) 处理HTML元素的事件。这需要分析浏览器控件中的MSHTML文档对象,定位被操作的元素,以及在元素的连接点上挂接自定义的事件处理程序(http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/mshtml/tutorials/sink.asp)。 添加/删除HTML元素。注意设置有时设置outHtml属性并不能正确创建元素(http://support.microsoft.com/kb/185140),一个的方法是用HTMLDocument对象的CreateElememt方法。 调用HTML元素的方法,这和在脚本中操作HTML类似。可操作的元素/接口可以参考Interfaces and Scripting Objects(http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/mshtml/reference/ifaces/interface.asp),操作方法可以参考Introduction to Dynamic HTML(http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/mshtml/reference/ifaces/interface.asp) 以上的功能都可以通过直接在网页中加入脚本实现(http://support.microsoft.com/kb/185128),而且脚本也可以通过应用程序实现的扩展接口来和应用程序本身交互。另外,脚本还可以被用来自定义一些事件,例如在需要重载自定义的ShowModalDialog的时候就可以用IDispatchEx给window对象添加一个属性,其值为一个自定义的ShowModalDialog函数(http://groups.google.com/group/microsoft.public.inetsdk.programming.webbrowser_ctl/browse_thread/thread/e5eeb4a9111b16af/4bc2709aeb2bb444?lnk=raot),也可以用加入脚本的办法来捕获网页中的错误(http://support.microsoft.com/kb/317024)。  在页面包含框架的时候,可能需要跨框架访问HTML文档。可以通过查询框架元素所支持的IWebBrowser2接口或者IHTMLWindow2接口来访问框架中的文档(http://support.microsoft.com/kb/196340),但是也有可能因为安全设置而无法访问(http://support.microsoft.com/kb/167796)。 在浏览器控件中显示其它类型的文档时,可以用IWebBrowser2的document属性来访问ActiveX文档,例如在显示Microsoft Word时,IWebBrowser2的document属性就是Word的文档对象,在显示文件夹的时候,IWebBrowser2的document属性就是文件夹对象等等。 扩展浏览器的宿主 浏览器控件在创建时会查询ActiveX容器的IOleClientSite的实现的如下接口:IDocHostUIHandler, IDocHostUIHandler2 and IDocHostShowUI。 虽然在无法自定义ActiveX容器的情况下可以用ICustomDoc::SetUIHandler来挂接IDocHostUIHandler到浏览器控件,但是这样也会造成内存泄漏(http://support.microsoft.com/kb/893629)。一些类库,例如MFC、ATL和.Net类库都实现了IDocHostUIHandler接口。 除了专门用于浏览器用途的程序之外,通常都需要自定义浏览器控件的上下文菜单。这需要实现IDocHostUIHandler::ShowContextMenu。通常的实现包括完全禁用上下文菜单、完全替换上下文菜单、以及修改部分上下文菜单。经常被从上下文菜单中移除的菜单项包含查看源代码、刷新和属性。一种替代的方案是在容器中过滤右键消息(http://support.microsoft.com/kb/231578)。 与浏览器相比,一些Internet Explorer的宿主功能在浏览器控件中并不是默认启用。在某些场合,默认启用的宿主功能可能并非预期。这时需要实现IDocHostUIHandler::GetHostInfo。可以通过实现IDocHostUIHandler::GetHostInfo来自定义的功能包括: 自动完成功能。对于用浏览器控件来做浏览器的场合来说,这个功能是有必要启用的。启用的方法是设置DOCHOSTUIFLAG_ENABLE_FORMS_AUTOCOMPLETE位 如果浏览器中的链接网址包含非ASCII的字符,那么需要实现IDocHostUIHandler::GetHostInfo,并且在返回的DOCHOSTUIINFO结构中设置dwFlags成员的DOCHOSTUIFLAG_URL_ENCODING_ENABLE_UTF8位。这使得网址会在发送之前用UTF-8编码。 3D边框、滚动条,禁用文字选择功能和禁用页面上的脚本。 对于使用浏览器控件来做HTML编辑器的场合来说,有时需要修改默认的页面样式。这都需要实现IDocHostUIHandler::GetHostInfo(http://support.microsoft.com/kb/328803)。注意在有些版本的IE中IDocHostUIHandler::GetHostInfo只在MSHTML被初始化的时候被调用,所以如果你需要在MSHTML被初始化之后使你的修改生效,你需要浏览到一个Word之类的非HTML Active document文档,之后再浏览回来。 在使用浏览器控件来做数据录入界面的场合,需要更改浏览器控件默认的Tab键处理使得用户可以使用Tab键切换到容器中的其他控件。这需要实现IDocHostUIHandler::TranslateAccelerator来自定义浏览器控件的快捷键处理。对于MFC这样用消息钩子来做消息预处理的可自定义容器来说,也可以用PreTranslateMessage来过滤F5键盘消息,而不是实现IDocHostUIHandler::TranslateAccelerator。 在脚本中调用应用程序对浏览器控件的扩展,这需要实现IDocHostUIHandler::GetExternal。使用.Net的WebBrowser控件的话设置ObjectForScripting属性就可以了。 对于用浏览器控件来做HTML分析器的场合来说,有时需要屏蔽脚本产生的消息框。这需要实现IDocHostShowUI::ShowMessage,或者设置浏览器的Silent属性。 另外,浏览器也会查询IOleClientSite来获得其它的服务信息,例如 IOleCommandTarget,查询控件的容器是否提供替代的命令处理,见拙作Hook DHTML Commands一文(http://blog.joycode.com/jiangsheng/archive/2005/07/09/58754.aspx) IServiceProvider。此接口被用于查询用户对如下接口的实现: IInternetSecurityManager ,用户可实现此接口来自定义浏览器控件的安全相关选项(http://msdn.microsoft.com/workshop/security/szone/overview/impl_secmanager.asp) IDownloadMamanger ,用户可实现此接口来自定义浏览器控件的下载过程 IAuthenticate,用户可实现此接口来自定义一些登录界面(http://support.microsoft.com/kb/329802) INewWindowManager,用户可实现此接口来重载Windows XP SP2和Windows 2003 SP1中新增的弹出窗口管理器的行为 其他控制 对于用浏览器控件来做HTML分析器的场合来说,有时需要禁用浏览器的脚本、ActiveX或者图片下载。这可以通过在容器中实现IDispatch,处理DISPID_AMBIENT_DLCONTROL来做到(http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/overview/Overview.asp)。 看来离线浏览的控制并不能用这种方法来控制(http://support.microsoft.com/kb/247336)。不过你可以自己编写一个HTTP层传递 BINDF_OFFLINEOPERATION标志 (http://groups-beta.google.com/group/microsoft.public.inetsdk.programming.mshtml_hosting/msg/76bf4910a289d4b3) 在浏览器控件中java小程序可能不能正常运行,如果使用Sun JVM1.4之后的版本,可以用SetEnvironmentVariable 来设置JAVA_PLUGIN_WEBCONTROL_ENABLE为1来启用Sun JVM。 默认情况下在页面载入时会有点击声。屏蔽点击声的一个方法是在程序运行时修改注册表键(http://support.microsoft.com/kb/201901),另一个方法是将浏览器控件隐藏,在调用Navigate2之后再显示,但是这也需要锁定控件的更新区域(LockWindowUpdate)以避免闪烁。在IE7中,也可以调用 CoInternetSetFeatureEnabled函数,传递FEATURE_DISABLE_NAVIGATION_SOUNDS来禁用浏览时的声音。 在需要使用代理服务器时,有可能需要在应用程序中使用非默认的代理服务器设置。这可以通过调用UrlMkSetSessionOption来实现。...[阅读全文]

posted @ | Feedback (2) | Filed Under [ .Net Framework HTML编程(IE Programming) 集成开发环境(IDE) 脚本(Scripting) 类库(Library) 平台SDK(Platform SDK) ]

摘要:Office Live Blog 5号宣布Office Live的测试者暂时不再需要产品密钥来进行注册,但是注册仍然需要一个美国地址和一个信用卡帐户。从站点内容来看,OfficeLive目前的测试版面向的用户是中小企业,提供5个邮箱、30兆空间和免费国际域名(嗯,注册了一个http://jiangsheng.net),以及FrontPage(OK,我知道这玩意现在叫Office SharePoint Designer )和Outlook的功能。 尽管站点的AJAX脚本经常出错(比如在编辑页面输入+号保存之后会消失,上传文件有时会失败),但是整个界面还是比较友好的,类似FrontPage的站点管理用起来很方便,而且类似Office助手的工具栏使得用户可以很快上手。...[阅读全文]

posted @ | Feedback (9) | Filed Under [ 随笔 用户界面 程序人生(Programming on the fly) 脚本(Scripting) ]

摘要:Hook DHTML Commands 浏览器在执行很多命令之前都会允许容器来替换默认的处理。在执行一些默认的命令之前,系统会查询用户对IDocHostUIHandler的实现对象的IOleCommandTarget接口,调用默认(NULL)或者CGID_DocHostCommandHandler命令组的命令。如果容器的对应命令处理返回S_OK。那么默认的处理就不会被调用。 下面列出一些可以在容器中自定义的操作:(这些常量的定义位于docobj.h中) OLECMDID_PRINT,默认命令组 OLECMDID_SHOWSCRIPTERROR, CGID_DocHostCommandHandler命令组 OLECMDID_FOCUSVIEWCONTROLSQUERY, CGID_DocHostCommandHandler命令组 OLECMDID_SHOWPAGEACTIONMENU, CGID_DocHostCommandHandler命令组 MFC提供了一些比较容易扩展的类和宏,这样可以很容易地在扩展容器来实现新的接口。这里使用CCmdTarget类提供的GetInterfaceHook虚函数来进行扩展。 //This sample is based on MFC sample DHTMLExplore. //a button is inserted into explore.htm: //<BUTTON class=hotElement id=print accesskey="P"><U>P</U>rint</BUTTON> //to invoke the print command #include <afxole.h> #include <mshtmcid.h> ///////////////////////////////////////////////////////////////////////////// // CDHtmlExploreDlg dialog class CDHtmlExploreDlg; //customize the CBrowserControlSite class to implement IOleCommandTarget. //the IDocHostUIHandler interface is implemented in CBrowserControlSite, //an internal control site class declared within afxdhtml.h class CDHtmlExploreControlSite: public CBrowserControlSite , public IOleCommandTarget CDHtmlExploreControlSite( COleControlContainer* pCtrlCont, CDHtmlExploreDlg *pHandler) : CBrowserControlSite(pCtrlCont,pHandler){}; protected: // Implementation ......[阅读全文]

posted @ | Feedback (6) | Filed Under [ 用户界面 HTML编程(IE Programming) 集成开发环境(IDE) 脚本(Scripting) 类库(Library) 平台SDK(Platform SDK) 语言(Language) ]

摘要:http://www.csdn.net/develop/read_article.asp?id=21702 最近这篇文章长长短短,写了两个礼拜吧。写这篇文章的主要原因是想把网页分析做得更加灵活。这篇文章的基础是我以前为一个EBS游戏写的外挂,可以自动修改网页内容(主要是表单)和定时submit表单(有的网站的submit有时间限制)。以前的代码是用VC来写的,和网页的修改同步很不方便。很多功能,例如表单的自动填写和递交依赖于表单的结构,网页结构一变的话,就需要重新编译代码。所以这次重写的时候(那个EBS又改版了),想考虑做成类似于Outlook的邮件规则。但是在编写的时候,发现这样的规则编写起来实在是太繁琐了。其实这些规则用VB来写脚本的话,可能就几句话,例如判断浏览完成之后判断URL,自动填写和递交表单。 这是我使用VBS的原因。在程序中集成脚本解释器之后,网站改版的时候改脚本就可以了,虽然使用门槛要高些(要会编写脚本)。主要碰见的技术问题是脚本中的浏览器的事件处理代码不能执行(CHtmlView捕获了事件,所以要在CHtmlView里面转发事件)移植MFCIE的代码到MDI的时候的菜单出现很多问题,主要是MDI的菜单替换,以及插入MDI系统菜单之后收藏夹的位置变化移植部分MFC7的代码到MFC6,中间还结合了一大堆修复MFC6BUG的代码,真是faint无法直接创建支持事件的CCmdTaget类(ActiveX好像可以……)MFC的类向导不支持自动化中的默认参数上面两个问题使得我不得不手动改ODL文件,结果造成无数问题……ODL还是能不改就不改吧关闭窗口时出现非法操作(最后捕获了WindowClosing事件,Cancel掉了系统的处理之后自己关闭)调用IE的表单的自动完成的时候,没做成功。好像和隐藏方法IShellUIHelper::AutoCompleteAttatch有关。编辑网页源代码时文档结构的刷新有问题,被编辑的节点的Child集合在SetOutHTML之后长度变成0了,最后是刷新整个文档结构树才解决。IE的BUG?...[阅读全文]

posted @ | Feedback (4) | Filed Under [ CSDN 随笔 用户界面 HTML编程(IE Programming) 程序人生(Programming on the fly) 调试技巧(Debugging) 集成开发环境(IDE) 脚本(Scripting) 组件开发(Component Development) ]

摘要:用笔记本用多了,PC键盘用起来不是很习惯了。 在我的一篇文章脚本化浏览器(http://blog.csdn.net/jiangsheng/archive/2003/11/09/3795.aspx 或者http://www.csdn.net/develop/Article/21/21702.shtm,CSDN文档中心正在调整,源代码下载连接暂时不可用)中描述了如何在应用程序中集成脚本引擎和添加宏支持。在添加支持的时候需要注意的是,宏的运行环境——VBS脚本引擎——目前只支持变体数据类型。这造成的一个结果就是当应用程序触发一个事件的时候,如果其参数并不都是变体数据类型,那么用户编写的宏不是总会被调用。解决的方法是总是声明应用程序事件的参数为变体数据类型。 虽然BOOL类型的事件参数在VBS中不被支持,但是也要说一下VC6的一个BUG。MFC的向导会错误地在自动化类中为VARIANT_BOOL类型的事件参数生成一个4字节BOOL类型的事件函数参数。这样的自动化对象在VB这样的双字节BOOL类型宿主中运行的时候会造成访问越界。参见微软知识库文章Q199315 FIX: Method with BOOL* Parameter Type Overwriting Memory in Visual Basic 。解决的方法是按照文中的方法手动修改类向导生成的代码,或者升级到VC.Net。 一些闲话…… MDC2004上发的PocketPC杂志很不错,可惜还没有进入中国市场。在MDC2004上碰见一个新西兰的MVP,居然可以熟练地用筷子吃面……发现博客堂的个人blog的Google Page Rank普遍提升到了5。但是在Google的网页目录中还是找不到博客堂。找了找我的blog的引用,发现在一个BLOG虚拟交易市场Blogshare似乎可以很容易的看到blog之间的连接。里面我的blog已经上市了……连刚开的CSDNBlog都有。速度真快啊。...[阅读全文]

posted @ | Feedback (1) | Filed Under [ 随笔 HTML编程(IE Programming) 程序人生(Programming on the fly) 脚本(Scripting) 类库(Library) 平台SDK(Platform SDK) ]

摘要:http://www.openlab.com.cn/~comy/jsscV1.0/sc.htm ?...[阅读全文]

posted @ | Feedback (26) | Filed Under [ 随笔 程序人生(Programming on the fly) 脚本(Scripting) ]