怎样写一个与Windows10 IE11兼容的标准BHO?
p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-bottom: .0001pt; text-align: justify; font-size: 10.5pt; font-family: "Calibri", "sans-serif" }
p.MsoHeader,li.MsoHeader,div.MsoHeader { margin: 0cm; margin-bottom: .0001pt; text-align: center; border: none; padding: 0cm; font-size: 9.0pt; font-family: "Calibri", "sans-serif" }
p.MsoFooter,li.MsoFooter,div.MsoFooter { margin: 0cm; margin-bottom: .0001pt; font-size: 9.0pt; font-family: "Calibri", "sans-serif" }
p.MsoAcetate,li.MsoAcetate,div.MsoAcetate { margin: 0cm; margin-bottom: .0001pt; text-align: justify; font-size: 9.0pt; font-family: "Calibri", "sans-serif" }
p.MsoListParagraph,li.MsoListParagraph,div.MsoListParagraph { margin: 0cm; margin-bottom: .0001pt; text-align: justify; text-indent: 21.0pt; font-size: 10.5pt; font-family: "Calibri", "sans-serif" }
span.Char { }
span.Char0 { }
span.Char1 { }
div.WordSection1 { }
ol { margin-bottom: 0cm }
ul { margin-bottom: 0cm }
怎样写一个与Windows10 IE11兼容的标准BHO?
环境:Windows10 x64(10240) IE11(x86环境类似)
作者:magictong
日期:2015/11/11
概述
其实Windows8刚出来的时候写过一篇关于BHO怎么与Win8 x86下IE11(增强保护模式开启)兼容的文章(传送门:http://blog.csdn.net/magictong/article/details/21280243),本文主要讨论的问题是Windows10 x86 &x64(是的x64也包含了)下BHO与IE11(增强保护模式开启)兼容的问题。
其方法和思路跟Windows8下是类似的,但是修改了一些实现方法,修复了之前那篇文章里面的bug,并且针对x64做了一些必要的处理,本文后面说到的系统和一些贴图都是来之于Windows10x64的10240版本(不再赘述)。
现象
看到这篇文章的人,上面这个图应该见过吧,网上很多的文章对于这个问题的解决方法是将IE的增强安全功能关掉,以解决此不兼容问题。当然对于第三方的插件来说,譬如网购插件,支付插件,这可能是唯一的方法,但是作为一个开发者,我们应该更多的思考怎么从技术上解决此问题,微软既然有此提示,说明也是有方法解决的。
第一步:兼容x64系统
其实如果是优先兼容x86系统,兼容x64系统是可以放到最后讲的,但是因为我们以x64系统为例讲,而且兼容x64系统的操作很简单,因此提到最前面说了。
其实秘密就是你要准备两个BHO组件(别问我是怎么知道的,反正就是这样o(∩_∩)o ),一个是x86下使用的(32位模块),一个是x64下使用的(64位模块),二者使用的CLSID,IID,LIBID都要完全一样,简单点处理就是可以把原始代码分x86平台和x64平台编译出两个模块来,然后分别注册,不用担心CLSID会冲突,在x64系统下,32位的COM组件的注册表在HKEY_CLASSES_ROOT\Wow6432Node\CLSID下面,x64位COM组件注册表才在HKEY_CLASSES_ROOT \CLSID下。
另外需要说明的是,如果你的IE没有开增强保护模式,那么你可以根据需要只准备一个BHO模块,也就没有本文说得要解决的这些问题了。
第二步:兼容增强保护模式
在x86下,兼容IE的增量保护模式,比较关键的一点是告诉系统(或者IE),BHO的实现对象(COM对象)是增强保护模式兼容的,也就是[2]里面提到的要将BHO的CLSID注册为一个特殊的组件类型库,也就是CATID_AppContainerCompatible类型库,类型库的概念,经常做COM开发的肯定清楚了,或者以前做过ActiveX开发也应该知道,为了和网页的安全性兼容,常把ActiveX控件注册到系统的某些安全类型库中去,否则有些网页下面JS可能调用不了这个ActiveX控件。
在[2]里面注册类型库的方式提到了动静两种方式,静态这种方式经验证是肯定可以的,但是有一个很不好的地方就是如果是Windows8以下的系统,因为没有这个类型库,直接注册失败导致整个BHO注册失败,这就无法接受了,除非你确定你的BHO只会在Windows8以上的系统注册。而动态的注册的方式(使用ICatRegister接口的RegisterClassImplCategories方法注册{59FB2056-D625-48D0-A944-1A85B5AB2640}类型库),我发现有bug,接口方法调用成功了,但是实际上没注册上,导致还是提升增强保护模式不兼容,后来仔细对比了一下动态注册和静态注册的注册表,发现动态注册的情况下,Implemented Categories下写了一串为0的GUID进去,也不知道是Windows10的bug还是什么情况,后来发现Windows8.1下面也有类似问题。
而静态的方法则可以正确的写入类型库信息。
动态注册的方式以前在Windows8下面使用确信可以成功,这个问题可以调试下到底是什么问题,不过既然知道最终的结果是写这个地方的注册表,我们自己来写注册表也是一样的,注意判断下系统是Windows8以上才进行该操作,代码如下(DllRegisterServer里面):
// 声明EPM兼容
//
WCHAR szClsGuid[64] = {0};
if (!::StringFromGUID2(CLSID_CBHOInjectJsPlugin, szClsGuid, 64))
break;
CAtlString strAppContainerCompatibleRegPath;
strAppContainerCompatibleRegPath.Format(
L"CLSID\\%s\\Implemented Categories\\{59FB2056-D625-48D0-A944-1A85B5AB2640}",szClsGuid);
CRegKey RegKey;
if (ERROR_SUCCESS != RegKey.Create(HKEY_CLASSES_ROOT,(LPCTSTR)strAppContainerCompatibleRegPath))
break;
反注册时,记得删除写入的注册表。
//////////////////////////////////////////////////////////////////////////
// 删除EPM兼容
//
WCHAR szClsGuid[64] = {0};
if (!::StringFromGUID2(CLSID_CBHOInjectJsPlugin, szClsGuid, 64))
break;
CAtlString strAppContainerRegPath;
strAppContainerRegPath.Format(L"CLSID\\%s", szClsGuid);
CRegKey RegKey;
if (ERROR_SUCCESS != RegKey.Open(HKEY_CLASSES_ROOT,(LPCTSTR)strAppContainerRegPath))
break;
if (ERROR_SUCCESS != RegKey.RecurseDeleteKey(L"ImplementedCategories"))
break;
第三步:兼容AppContainer完整性权限
做完第二步的事情之后,启动IE,出现了熟悉的启用,不启用提示条,果断启用,再看“管理加载项”里面状态已经是“已启用”了,但是感觉BHO的功能没生效,什么情况?
查看了IE进程的模块加载情况,发现BHO的模块并没有被加载,咦,又被微软忽悠了?调试了下发现,IE是有加载我们的BHO的动作的,但是加载失败了!深入调试发现,原来是因为IE在增强保护模式下时,进程的完整性权限是AppContainer,这种进程只能加载具有ALL APPLICATIONPACKAGES用户组的文件,好吧,注册的时候也给加上吧(Tips:测试时,可以手动添加下先,试试是否成功)!最终代码如下(注:有些代码太长,没有贴出):
//DllRegisterServer - Adds entries to the system registry
STDAPIDllRegisterServer(void)
{
// registers object, typelib and all interfaces in typelib
HRESULT hr = _AtlModule.DllRegisterServer();
if (Util::IsWindows8OrGreater())
{
// >= Windows 8
do
{
//////////////////////////////////////////////////////////////////////////
// 添加Appcontainer权限
//
TCHAR szModuleName[2 * MAX_PATH + 1] = _T("");
DWORD dwLen = ::GetModuleFileNameW(G_hModSelf, szModuleName, 2 * MAX_PATH);
if (dwLen < 2 * MAX_PATH)
{
TSWIN8AR::AddAllApplicationPackagesGroupToFile(szModuleName);
}
//////////////////////////////////////////////////////////////////////////
// 声明EPM兼容
//
WCHAR szClsGuid[64] = {0};
if (!::StringFromGUID2(CLSID_CBHOInjectJsPlugin, szClsGuid, 64))
break;
CAtlString strAppContainerCompatibleRegPath;
strAppContainerCompatibleRegPath.Format(
L"CLSID\\%s\\ImplementedCategories\\{59FB2056-D625-48D0-A944-1A85B5AB2640}", szClsGuid);
CRegKey RegKey;
if (ERROR_SUCCESS != RegKey.Create(HKEY_CLASSES_ROOT, (LPCTSTR)strAppContainerCompatibleRegPath))
break;
} while (0);
}
returnhr;
}
//DllUnregisterServer - Removes entries from the system registry
STDAPIDllUnregisterServer(void)
{
if (Util::IsWindows8OrGreater())
{
//>= Windows 8
do
{
//////////////////////////////////////////////////////////////////////////
// 删除EPM兼容
//
WCHAR szClsGuid[64] = {0};
if (!::StringFromGUID2(CLSID_CBHOInjectJsPlugin, szClsGuid, 64))
break;
CAtlString strAppContainerRegPath;
strAppContainerRegPath.Format(L"CLSID\\%s", szClsGuid);
CRegKey RegKey;
if (ERROR_SUCCESS != RegKey.Open(HKEY_CLASSES_ROOT,(LPCTSTR)strAppContainerRegPath))
break;
if (ERROR_SUCCESS != RegKey.RecurseDeleteKey(L"ImplementedCategories"))
break;
} while (0);
}
HRESULT hr = _AtlModule.DllUnregisterServer();
returnhr;
}
再看看效果,终于加载进来了。
注意
(1) 注册程序需要是管理员权限启动,否则注册会失败(除非你把UAC彻底关掉了)。
(2) 如果你的BHO组件放在一些特殊的目录,譬如系统目录,Program Files目录等等,因为这些目录本身处于ALL APPLICATIONPACKAGES用户组,那么拷贝过去的时候会自动继承,导致可能没有出现AppContainer兼容的问题。
(3) 完整代码下载:http://download.csdn.net/detail/magictong/9273691。
参考文档
[1] UnderstandingEnhanced Protected Mode http://blogs.msdn.com/b/ieinternals/archive/2012/03/23/understanding-ie10-enhanced-protected-mode-network-security-addons-cookies-metro-desktop.aspx
[2] 怎样写一个与Win8 IE11兼容的标准BHO? http://blog.csdn.net/magictong/article/details/21280243
怎样写一个与Windows10 IE11兼容的标准BHO?的更多相关文章
- 怎样写一个与Win8 IE11兼容的标准BHO?
怎样写一个与Win8 IE11兼容的标准BHO? 环境:Windows8.1 x86 IE11(其它环境未讨论) 作者:magictong 日期:2014/02/02 概述 微软在2013年6月份推出 ...
- 写一个trim函数,兼容IE firefox chrome(正则)
因为在获取输入框内容时,常常trim下多余的空格.而IE部分低端浏览器里的JavaScript版本不内置trim()这个清楚空格函数,而流行的浏览器里都兼容了,比如chrome,FF等.为了不让IE下 ...
- 写一个ajax程序就是如此简单
写一个ajax程序就是如此简单 ajax介绍: 1:AJAX全称为Asynchronous JavaScript and XML(异步JavaScript和XML),指一种创建交互式网页应用的网页开发 ...
- 操刀 requirejs,自己动手写一个
前沿 写在文章的最前面 这篇文章讲的是,我怎么去写一个 requirejs . 去 github 上fork一下,顺便star~ requirejs,众所周知,是一个非常出名的js模块化工具,可以让你 ...
- 写一个兼容性比较好的拖拽DEMO
写一个兼容性比较好的拖拽DEMO 查看Demo 思路 div盒子 鼠标按下事件onmousedown 鼠标移动事件onmousemove,获得鼠标的坐标,将div移动至鼠标的当前坐标 鼠标抬起事件om ...
- 『练手』手写一个独立Json算法 JsonHelper
背景: > 一直使用 Newtonsoft.Json.dll 也算挺稳定的. > 但这个框架也挺闹心的: > 1.影响编译失败:https://www.cnblogs.com/zih ...
- 用java写一个servlet,可以将放在tomcat项目根目录下的文件进行下载
用java写一个servlet,可以将放在tomcat项目根目录下的文件进行下载,将一个完整的项目进行展示,主要有以下几个部分: 1.servlet部分 Export 2.工具类:TxtFileU ...
- 一起学习造轮子(一):从零开始写一个符合Promises/A+规范的promise
本文是一起学习造轮子系列的第一篇,本篇我们将从零开始写一个符合Promises/A+规范的promise,本系列文章将会选取一些前端比较经典的轮子进行源码分析,并且从零开始逐步实现,本系列将会学习Pr ...
- 通过用jQuery写一个页面,我学到了什么
概述 前几天面试,hr发来一个测试文件,让我做做看.我一看,其实就是根据PSD需求写一个页面,再加上一些互动效果即可. 刚好我之前学了切图,jquery等知识还没练手过,于是高兴的答应了. 最后花了3 ...
随机推荐
- idea和androidstudio的首次git配置一些问题
网上都有很清楚的步骤 但是 都是教怎么使用 但是对第一次应用idea内部vcs的git 则很少有详细说明 首先要在网上创建个项目 然后本地git clone下来 不建议内部vcs的fetch from ...
- 一口一口吃掉Hibernate(四)——多对一单向关联映射
hibernate对于数据库的操作,全部利用面向对象的思维来理解和实现的.一般的单独表的映射,相信大家都没有问题,但是对于一些表之间的特殊关系,Hibernate提供了一些独特的方式去简化它. 今天就 ...
- 基于PHP的对接免费电子面单接口平台的案例-快宝开放平台
一.电子面单对接平台 电子面单对接平台分为两类: 1 .各大快递公司自有的电子面单接口开放平台:对接起来麻烦,需要每个快递公司分别调试接口,费时费力. 2 .第三方快递开放平台:如快宝开放平台(htt ...
- 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- CustomYieldInstruction 自定义中断指令
ActionScript3脚本引擎为了方便热更新逻辑开发,提供的从脚本继承Unity类库功能在一些情况下可以提供开发的便利. 这次来建立一个示例,演示一下如何在脚本中自定义协程中断指令 Unity中的 ...
- 关于Application_End 与 Application_Start事件触发情况的测试(待续)
测试项目搭建 定义一个简单的Mvc项目,有如下文件: (1) public class Startup { public void Configuration(IAppBuilder app) { a ...
- MongoDB 自动增长
MongoDB 没有像 SQL 一样有自动增长的功能, MongoDB 的 _id 是系统自动生成的12字节唯一标识. 但在某些情况下,我们可能需要实现 ObjectId 自动增长功能. 由于 Mon ...
- RunLoop总结:RunLoop的应用场景(五)
今天要介绍的RunLoop应用场景感觉很酷炫,我们可能不常用到,但是对于做Crash 收集的 SDK可能会用得比较频繁吧.相比关于RunLoop 可以让应用起死回生,大家都听说过,可是怎么实现呢?今天 ...
- Why Doesn't Python Have Switch/Case?
Why Doesn't Python Have Switch/Case? Tuesday, June 09, 2015 (permalink) Unlike every other programmi ...
- (Java)微信之个人公众账号开发(一)——进入开发者模式
本篇文章将教大家如何建立微信个人公众账号,(注意:后台全部是用javaweb相关技术开发),大家知道,现在微信公众账号分服务号和订阅号,现在我要讲的主要是个人微信公众账号的建立以及后台的开发,个人公众 ...
- RxJava操作符(06-错误处理)
转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51658235 本文出自:[openXu的博客] 目录: Catch Retry 源码下载 1 ...