`

浏览器集成教学--在浏览器程序中添加宏支持

阅读更多

浏览器集成教学--在浏览器程序中添加宏支持

这个教程提供在浏览器程序中添加宏支持的方法,你会看到如何给MFC的程序添加宏支持。这篇文章也讨论了如何扩展VC6中的CHtmlView的功能,如何实现MDI结构的浏览器,以及如何分析DHTML的文档结构。

单击这里下载本文的代码

本文分为以下部分

  1. 前提和需求
  2. 介绍
  3. 活动脚本
  4. 为应用程序添加脚本支持
  5. 安全性
  6. CHtmlView的增强
  7. 脚本示例
  8. 结论
  9. 参考

前提和需求

在阅读本文之前,建议先

  • 对微软基础类(MFC)和组件对象模型(COM)有所了解
  • 熟悉活动模板库(ATL)
  • 安装了微软的因特网探索者(IE)6.0或者更高版本
  • 开发环境中具有IE6.0或者更高版本的头文件和库文件

介绍

集成浏览器控件对于快速的应用程序开发(RAD)是一个强有力的工具;你可以使用动态HTML(DHTML),或者可扩展的标记语言(XML)显示你的用户界面。一个通常的用途是用它来显示表单,然后通过分析表单网页和处理递交事件来处理表单。但是,如果你要分析表单页面的话,分析的方式完全依赖于页面的结构,也就是说,如果在应用程序中通过IE提供的接口分析网页,那么为了每个网页结构,你要编写和编译一次代码。这在应用程序和表单网页一起发布的情况下是完全没有问题的,但是对于表单网页位于远程服务器上,并且有时候会修改的情况,或者想使应用程序对其他网站有效,就必须同时修改并且重新发布应用程序。为了避免反复修改应用程序,可以使用——

活动脚本

使用活动脚本可以编写灵活的处理代码而无需重新编译程序。你可能已经在很多应用程序中见到过活动脚本,例如IE、Microsoft Office和Visual Studio。在平台SDK(Platform SDK)的微软窗口脚本技术(Microsoft Windows Script Technologies)部分的微软窗口脚本接口介绍(Microsoft Windows Script Interfaces Introduction)一文中,介绍了活动脚本的概念、背景、架构和调用步骤。

如果需要示例代码,可以在微软知识库(KB)中查找kbAXScript关键字。下面是一些示例

本文的示例代码是基于MFC6的,所以采用了Q168214中提供的代码。

为应用程序添加脚本支持

自动化对象

为了实现脚本支持,我们需要让应用程序具有自动化服务器支持。实现这个支持的最简单的办法是使用MFC的应用程序向导(Application Wizard)创建IEAutomation MDI应用程序时,在MDI向导第三步选中Automation支持。

向导自动产生的CHtmlView派生类CIEAutomationView并不是一个自动化对象,所以在建立示例工程时,我把CIEAutomationView的定义和实现文件删除,然后删除类向导中CIEAutomationView的信息,重新创建CIEAutomationView类,在创建的时候指定基类是CHtmlView并且支持自动化。

CIEAutomationView中的脚本解释器是从Q168214的示例代码修改的,去掉了一些对象,增加了DOM扩展对象的实现。

Scripter对象

脚本引擎对象,可以用名字Scripter访问。提供创建对象的方法。

WebBrowser对象

浏览器控件对象,可以用名字WebBrowser访问。可以用来访问文档对象模型。查看源代码功能也被增强了以显示文档对象模型。需要更多信息的话,可以查看文末的参考。

External对象

DOM扩展对象,可以用名字External访问。用于扩展浏览器的文档对象模型的对象。在本示例中,我也同时用这个对象转发了WebBrowser对象的事件。尽管大部分功能都实现了,但是自动完成功能似乎还有点问题,看起来和IShellUIHelper的未公开方法AutoCompleteAttatch有关。(实际上,浏览器控件需要实现IDocHostUIHandler::GetHostInfo,参考http://blog.joycode.com/jiangsheng/archive/2004/01/08/11037.aspx

类型库支持

脚本中需要对象的类型库信息来访问对象的属性、方法和事件。默认情况下,直接从CComTarget派生的类是无法通过类向导添加和删除事件的,CComTargetEx类“模拟”了ActiveX的部分特性,并且欺骗了类向导来做到这一点。在给对象添加类型信息时,参考了Q185720 HOWTO: Provide Type Information From an MFC Automation Server中的方法,把应用程序的类型库添加到资源。

安全性

尽管自动化浏览器可以提供更多的灵活性,但是这也把应用程序的一部分暴露给用户。例如,用户可能修改脚本使得应用程序不能正常工作。另外,如果用户可以查看脚本,那么就可以了解程序结构,并且能够借此攻击没有慎重设计的站点。

使用脚本创建对象也可能有安全性问题。某些对象不是安全的,例如恶意的或者不正确使用的COM对象。

如果扩展了DOM,使得网页上的脚本可以访问应用程序的功能,那么需要确保脚本是安全的,或者来自于可以信赖的站点。下面的函数用于访问DOM中Window的扩展属性之前检查安全性。

BOOL CIEAutomationView::CanAccessExternal()
{
// if the dispatch we have is safe,
// we allow access
if (IsExternalDispatchSafe())
return TRUE;

// the external dispatch is not safe, so we check
// whether the current zone allows for scripting
// of objects that are not safe for scripting
if (m_spHtmlDoc == NULL)
return FALSE;

CComPtr<IInternetHostSecurityManager> spSecMan;
m_spHtmlDoc->QueryInterface(IID_IInternetHostSecurityManager,
(void **) &spSecMan);
if (spSecMan == NULL)
return FALSE;

HRESULT hr = spSecMan->ProcessUrlAction(URLACTION_ACTIVEX_OVERRIDE_OBJECT_SAFETY,
NULL, 0, NULL, 0, 0, PUAF_DEFAULT);
if (hr == S_OK)
return TRUE;
return FALSE;
}
默认设置下,一般网页上的脚本可以访问同一站点上的网页。

CHtmlView的增强

使用高级宿主特性

使用高级宿主特性的好处可以参见我翻译的CSDN文档中心文章自定义浏览器。在本文的示例代码中,我使用这个特性扩展了DHTML文档结构模型(DOM)使得网页中的脚本可以访问应用程序。离线浏览功能的实现也可以参考这篇文章。

为了可以在MFC6的CHtmlView基础上使用高级宿主特性自定义浏览器,需要重载默认的控件客户站点(这个代码只在MFC6中有必要,MFC7的CHtmlView已经支持了高级宿主特性)。因为MFC6不能重载CWnd的虚函数CreateControlSite来创建自定义的客户站点,所以使用Q236312 HOWTO: Disable the Default Pop-up Menu for CHtmlView这篇文章中的方法,重载默认的控件客户站点管理器。然后在重载过的默认控件客户站点中保存控件宿主的指针

CCustomControlSite::CCustomControlSite(COleControlContainer *pCnt)
:COleControlSite(pCnt)
{
 m_pCustomImpl=NULL;
 CWnd* pWnd=pCnt->m_pWnd;
 if(pWnd){
  if(pWnd->IsKindOf(RUNTIME_CLASS(CIEAutomationView))){
  CIEAutomationView* pView=(CIEAutomationView*)pWnd;
  m_pCustomImpl=pView;
 } 
}

这样可以在控件客户站点的IDocHostUIHandler2实现中调用控件宿主的相应处理,例如

HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler2::GetHostInfo( DOCHOSTUIINFO* pInfo )
{
 METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler2)
 if(pThis->m_pCustomImpl){
  return pThis->m_pCustomImpl->GetHostInfo(pInfo );
 }
 return S_OK;
}

高级宿主特性的应用之一就是扩展DOM,使得网页上的脚本可以使用window.external访问DOM扩展对象。IE实现的DOM扩展对象具有menuArguments属性和IShellUIHelper接口。

控制新的窗口

默认情况下,浏览器收到创建新窗口请求时,会在IE中打开新的窗口。你可以处理NewWindow2事件来在自己指定的窗口中打开请求的页面。

void CIEAutomationView::OnNewWindow2(LPDISPATCH* ppDisp, BOOL* Cancel) 
{ 
 // Get a pointer to the application object. 
 CWinApp* pApp = AfxGetApp(); 
 // Get the correct document template. 
 POSITION pos = pApp->GetFirstDocTemplatePosition(); 
 CDocTemplate* pDocTemplate = pApp->GetNextDocTemplate( pos ); 
 // Create a new frame. 
 CFrameWnd* pFrame = pDocTemplate->CreateNewFrame( 
  GetDocument(), 
  (CFrameWnd*)AfxGetMainWnd() ); 
 // Activate the frame. 
 pDocTemplate->InitialUpdateFrame( pFrame, NULL ); 
 CIEAutomationView* pView = (CIEAutomationView*)pFrame->GetActiveView(); 
 // Pass pointer of WebBrowser object. 
 pView->SetRegisterAsBrowser( TRUE ); 
 *ppDisp = pView->GetApplication(); 
} 

如果需要更多信息,参见Q184876 HOWTO: Use the WebBrowser Control NewWindow2 Event。。

MDI浏览器

本文的示例代码是基于浏览器的,为了省事起见,直接在MFC的MFCIE示例上进行了修改,改成了MDI结构。MFCIE本身就是一个简单的浏览器,但是在把代码从主框架转移到子框架之后出了一点小问题,动态建立的收藏夹菜单不见了。这是由于MDI框架的菜单替换机制在框架激活时恢复了默认菜单造成的,所以我重载了CDocument::GetDefaultMenu,以在MDI框架的菜单替换的时候恢复我修改过的菜单(参见Q145857 How to Use Multiple Menus in MFC App That Uses GetDefaultMenu)。为了在子框架的创建过程中获得文档指针来修改文档中保存的菜单,可以从创建结构获得MDI创建上下文。

MDICREATESTRUCT * pMDICreateStruct=(MDICREATESTRUCT * )lpCreateStruct->lpCreateParams;
CCreateContext *pCreateContext=(CCreateContext *)pMDICreateStruct->lParam;
pMenu =((CIEAutomationDoc *)pCreateContext->m_pCurrentDoc)->m_menuDefault.GetSubMenu(3);

收藏夹

MFCIE示例中演示了如何建立一个收藏夹菜单,但是在移植工具栏里面的显示收藏夹命令到MDI子框架的时候碰见一个问题,动态创建的收藏夹菜单的位置不固定。但是通过查找新增的“添加到收藏夹”命令的位置,可以确定这个菜单的位置。添加到收藏夹和管理收藏夹的功能是通过创建ShellUIHelper对象实现的。

自动完成

为了使用方便,我在应用程序中也添加了自动完成功能。地址栏的自动完成功能的实现比较简单,调用系统的API SHAutoComplete就可以了。在我自己扩展了DOM的情况下,表单的自动完成似乎有些问题。

需要更多信息的话,可以参考我翻译的CSDN文档中心文章在应用程序中集成自动完成功能

访问需要授权的站点

某些站点在访问时需要验证用户身份,但是默认情况下浏览器控件在无法验证用户身份时并不提示用户输入用户名和密码。通过在控件的客户站点实现IServiceProvider接口,并且同时实现IAuthenticate接口,使得应用程序具有输入身份验证信息的功能。更多信息参见微软知识库文章Q329802 错误:通过IAuthenticate进行的代理身份验证可能会在安全URL上失败

常用命令处理

为了使用方便,增加了调用查找对话框、查看源代码和设置Internet选项的功能。这是通过查询浏览器控件的IOleCommandTarget接口,执行命令组CGID_WebBrowser的命令实现的。实现这类命令的方法不只一种,例如可以载入inetcpl.cpl,调用函数LaunchInternetControlPanel来实现打开Internet选项使用IMarkupServices接口执行查找、定位和选择,以及使用流来获得/设置网页的内容。在示例代码中,演示了如何分析文档结构,以及如何编辑选定的网页元素的HTML代码或者框架的源文件。

MFC6BUG的修复

尽管应用程序已经可以具有比较完整的功能,但是为了让应用程序能够长期正常工作,需要修复MFC6中包含的一些问题。我在这里只列出文章标题,有兴趣的话可以去查看微软知识库文章或者本文的代码

脚本示例

WebBrowser.Navigate "About:<H1><B>This is a test</B></h1>"
Dim msword 
Set msword = Scripter.HostCreateObject("Word.Basic")
msword.appshow
msword.filenew
msword.Insert "hello"
Sub External_BeforeNavigate2(pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel)
MsgBox URL
End Sub
如果你为WebBrowser对象的事件编写脚本,你会发现这些事件处理代码不会被执行,这是因为CHtmlView处理了这些事件。你可以在你的CHtmlView派生类的处理代码中触发自定义对象的相应事件。在示例代码中,我转发了BeforeNavigate2事件到自定义对象的事件。

结论

给应用程序添加脚本支持可以大幅度提高程序的灵活性和可扩展性。虽然为此会牺牲一些性能、安全性和增加一些代码量,但是很多时候这种牺牲是值得的。

尽管我在示例代码没有转发DocumentComplete事件,但是这仅仅是基于安全性考虑。自动化浏览器可以很容易地实现广告窗口过滤、自动填写表单,页面分析等脚本。如何编写这些脚本取决于你自己的需要。

参考


http://blog.csdn.net/jiangsheng/archive/2003/11/09/3795.aspx

分享到:
评论

相关推荐

    mac Axure浏览器插件Axure-extension-for-Chrome-0.6.2

    本文将详细介绍“mac Axure浏览器插件Axure-extension-for-Chrome-0.6.2”以及如何在Mac上的Chrome浏览器中安装和使用它。 首先,"Axure-extension-for-Chrome-0.6.2"是一款专为Chrome浏览器设计的Axure扩展程序,...

    浏览器集成VLC视频插件

    VLC Media Player是一款流行的开源多媒体播放器,它支持多种视频格式和流媒体协议,使得在浏览器中播放不同类型的视频文件成为可能。 首先,VLC插件的安装是集成的关键步骤。用户需要访问VLC官方网站下载适用于各自...

    ie8.0浏览器- 893-2909 浏览器

    ie8.0浏览器-893-2909 ie8.0浏览器-893-2909

    WinFormWebView2-自用-个性化浏览器-桌面程序开发-程序源码

    这是集成了WebView2的内核浏览器桌面程序,类似Edge,Chrome浏览器,使用VisualStudio2019开发工具编写来的,项目正常编译可套,请放心下载。 可以看配套的指导文章:...

    CSDN·浏览器助手-3.0.5.zip

    CSDN浏览器助手插件 由CSDN官方开发,集成一键呼出搜索、万能快捷工具、个性化标签页和底层免广告四大功能,让您在工作学习场景中,告别繁琐复杂的切换,快速解决问题,打造专属你的效率神器! 描述: 一款集成本地...

    vrml浏览器插件--vrml语言学校资料

    一种vrml浏览器插件,把编辑好的vrml文件直接右击打开,在选择打开程序时选择IE浏览器,在浏览器弹出的窗口中点允许改插件运行就可以看到三维图像了。

    世上最小的浏览器---kakeeware

    最小 浏览器 世界上 kakeeware

    safari浏览器 - Dolly Dream - 博客大巴.mht

    safari浏览器 - Dolly Dream - 博客大巴.mhtsafari浏览器 - Dolly Dream - 博客大巴.mhtsafari浏览器 - Dolly Dream - 博客大巴.mhtsafari浏览器 - Dolly Dream - 博客大巴.mht

    C#做的触摸屏浏览器--vs2008版本

    “C#做的触摸屏浏览器--vs2008版本”指的是一个使用C#编程语言在Visual Studio 2008环境下开发的专门针对触摸屏设备的网络浏览器应用。C#是一种面向对象的编程语言,常用于Windows应用开发,包括桌面应用和移动应用...

    使电脑浏览器变成手机的App浏览器(修改电脑浏览器UA)user-agent

    例如,在 2345Explorer 浏览器中,我们使用 `--user-agent="Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus OneBuild/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"` 来指定 ...

    一款功能强大的浏览器-----Flock

    出处:四大浏览器之一的Netscape的进化版 语言:英语 特点:可快速导航至热门网站; 丰富的搜索引擎(可手动添加删除); 改进的收藏夹功能。

    易语言多标签CEF浏览器库web浏览器 支持html5网页访问

    CEF是一款开源的框架,它允许开发者在自己的应用程序中嵌入Web浏览器功能,支持HTML5网页的访问。易语言CEF浏览器库使得易语言用户能够方便地在自己的程序中实现网页浏览、网页交互等功能。 CEF浏览器库的优势在于...

    浏览器调用VLC插件

    浏览器调用VLC插件是指在HTML5技术的支持下,在主流浏览器中嵌入VLC插件,以便播放多媒体文件。下面将详细介绍浏览器调用VLC插件的实现过程和相关技术。 注册VLC插件 在PC机器中,需要注册VLC插件以便浏览器可以...

    火山CEF3浏览器模块

    "CEF3浏览器模块0401.vcip"可能是项目的一个版本或构建包,它可能包含了编译好的库文件、头文件以及必要的配置信息,使得其他开发者可以方便地在自己的项目中集成火山CEF3浏览器模块。 总的来说,火山CEF3浏览器...

    OWASP Mantra Janus渗透测试专用浏览器【集成多种常用工具】

    这是OWASP出品的渗透测试专用浏览器,集成了常用的很多工具

    Node.js-browser-run-在浏览器环境中运行代码的最简单方法

    `browser-run`是基于Node.js开发的一个轻量级命令行应用程序,它的主要功能是在浏览器环境中执行JavaScript代码。这个工具允许开发者快速地查看代码在浏览器中的行为,而无需构建复杂的本地开发环境或者手动刷新...

    Android-一个App内嵌浏览器

    在Android应用开发中,内嵌浏览器(In-App Browser)是一种常见的功能,它允许用户在应用程序内部浏览网页,而无需跳转到外部浏览器。本文将详细介绍Android中的内嵌浏览器实现,特别是基于WappBrowser的实践。 ...

    浏览器elasticsearch-head插件安装方法.rar

    但是附件内浏览器可以直接安装拓展程序,方便快捷,可用,谢谢使用。由于谷歌浏览器下载elasticsearch-head插件需要,所以下载不是很方便。但是附件内浏览器可以直接安装拓展程序,方便快捷,可用,谢谢使用。

    QT开源网页浏览器otter-browser的源代码

    Otter Browser 水獭浏览器 水獭浏览器 - 模仿opera12界面, 基于qt5的webkit浏览器. 等于个人制作山寨版Safari, 支持二代半引擎, 苹果WebEngine/谷歌Blink. 作者: 波兰 Emdek 恩德克 代码可用,本人亲测,qt5.5+vs...

    QQ浏览器如何导入其他浏览器的收藏夹-.docx

    QQ浏览器是一款广受欢迎的网页浏览工具,它支持多种功能,包括导入其他浏览器的收藏夹。在不同的浏览器中,导入收藏夹的过程可能略有不同,但基本步骤相似,主要涉及导出和导入两个环节。以下是几个常见浏览器导入...

Global site tag (gtag.js) - Google Analytics