MS Office2016留下的坑

时间:2022-09-03 06:40:16

背景
  问题源自论坛用户反馈,他用管家有几年了,之前使用IE都很正常,没有任何问题,但是最近突然发现,启动IE时,就会出现系统错误提示:无法启动此程序,因为计算机中丢失 api-ms-win-core-path-l1-1-0.dll。尝试重新安装该程序以解决此问题。点确定之后,IE依然可以使用,但是中途或者新建Tab的时候可能还会弹出来。
  MS Office2016留下的坑
  看到这个DLL的名字,突然想起了一年前,lorne跟过的一个问题,微软Office2016函数转发器的bug(参考[1]),但是从这个提示来看,并不是同一个问题,但是可能跟Office2016有关系,问了下用户,果然在最近安装了最新的Office2016。
  但是据用户说,退出管家之后,就没有问题了,在用户的机器上面实验,确实如此,这就奇怪了,管家的模块并不依赖这个特殊的DLL,而且从弹框来看,应该是某个模块的导入表里面有这个DLL的依赖。

跟进
  最近用户刚好有时间,机器是闲置的,因此抽出时间看看这个问题的原因是什么。
  1、首先在用户的机器上面全盘搜索了一下,确实没有api-ms-win-core-path-l1-1-0.dll这个模块,看来系统也不是瞎提示o(∩_∩)o 。那到底是哪个模块依赖这个DLL呢,先取了一个IE的dump,然后重启IE,用ProcessMonitor监控发现跟OChelper.dll有关系,十有八九是OChelper.dll静态依赖了api-ms-win-core-path-l1-1-0.dll。
  MS Office2016留下的坑
  2、把上面抓到的dump打开看了下,发现有一个线程正在请求Com接口,请求进程内接口是需要加载DLL,线程确实卡在了Load某个动态库的地方,这个动态库就是OChelper.dll,这里也印证了上面的思路。顺便看了下接口的CLSID和接口IID,发现IE是在把OChelper.dll当成BHO进行加载,并且正在请求IObjectWithSite接口。

  0:000:x86> du 0604b5b4
  0604b5b4 "C:\Program Files (x86)\Microsoft"
  0604b5f4 " Office\root\Office16\OCHelper.d"
  0604b634 "ll"
  0:018:x86> dt 567bff94 GUID
  TSWebMon!GUID
  {fc4801a3-2ba9-11cf-a229-00aa003d7352}
    +0x000 Data1 : 0xfc4801a3
    +0x004 Data2 : 0x2ba9
    +0x006 Data3 : 0x11cf
    +0x008 Data4 : [8] "???"

  0:018:x86> dt 0604c638 GUID
  TSWebMon!GUID
  {31d09ba0-12f5-4cce-be8a-2923e76605da}
    +0x000 Data1 : 0x31d09ba0
    +0x004 Data2 : 0x12f5
     +0x006 Data3 : 0x4cce
    +0x008 Data4 : [8] "???"

  MS Office2016留下的坑
  MS Office2016留下的坑

  3、OChelper.dll到底是何方神圣,从目录来看,它应该是Office2016的组件,而且还是一个BHO组件(参考[4]),到用户的注册表浏览了一下,确实被注册成了BHO,但是用户机器上面,默认是不加载这个BHO的。结合用户最近刚装的Office2016,问题逐渐明了。检查了OCHelperd.ll的导入表,静态依赖了api-ms-win-core-path-l1-1-0.dll,但是用户机器上面肯定是没有这个DLL的,也就是说,任何进程(不管什么原因)加载OCHelperd.ll,实际上都会报错的。
  MS Office2016留下的坑
  MS Office2016留下的坑

   4、回到最开始的问题,为什么用户把管家退出就不报错了呢?后来通过管家的注入模块(注入到IE里面)的逻辑,发现管家有两个模块的BHO加载逻辑会触发IE去加载其它的BHO,导致IE去拉起OCHelper.dll。而退出管家之后,因为注入模块不注入IE了,因此问题就不暴露了。但是管家注入模块使用的BHO加载逻辑并不是非常特殊的操作,而且整个逻辑使用了多年,因为这个问题去修改得不偿失。

  5、那么禁掉用户的OCHelper.dll是否可行呢?试了下不管是干掉OCHelper.dll的组件注册表还是把OCHelper.dll删掉或者改名,都可以解决这个问题。而且用户使用Office2016也没有什么影响(也不应该有什么影响,否则早就出问题了),后来在网上查了下,这个OCHelper模块跟微软Office2016发布时同步的一个新技术有关系——ClickToRun,其实也不算什么新技术,国内的一些游戏厂商在几年前就出过边下边玩的功能,基本原理就是让用户尽快得体验到必要功能,因此只下载必要的模块(需要啥下载啥),其它的模块在后台慢慢再下载。这里微软的思想也一样,就是不需要用户一口气把几百M上G的安装包下载下来再安装个2-30分钟,而且几分钟之类就可以使用基本功能(依赖高速带宽,譬如你想快点打开一个word文档,可能几分钟就可以看到word文档的内容了,但是呢编辑等高级功能还得再等等)。

  6、从这个技术的特点来看,有可能是用户在下载组件之后,运行时库没有下载成功,或者运行库的安装包没有下载成功,或者是,因为当时用不到这个组件,因此一直没有去加载安装运行时库。后来找了几个Office2016的环境看了下,并没有这个用户的问题,看看可能是极个别的个例。

解决方案
  1、微软的推荐方案是安装VS2015的运行时库(参考[3]),这个没有让用户试,但是应该也是可以解决的,把所有缺失的DLL都补齐肯定是可以解决的,但是建议不要一个一个的去补。
  2、如果全网大面积的出现该问题,建议是排除IE不加载C:\Program Files (x86)\Microsoft Office\root\Office16\OCHelper.dll这个模块,之前管家就是使用的该方案,通过远程控制排除IE对某些模块的加载(当然这个得依赖客户端之前已经部署了该功能)。
  3、对于这个用户,经过详细询问后,其实他平时也就是用Office写写文档,PPT,没用什么高级功能,因此把他的OCHelper.dll这个文件给屏蔽了,对于这个用户来说,这其实是最简单,成本最小的方法。

坑在哪里
  总结一下,这个问题其实感觉是Office2016的新功能留的坑(标题的由来),或者叫bug也行,在这个用户这里OCHelper可能永远也没机会被加载,问题也就不会发现,但是不小心就被我们踩了!

参考文档
  [1] http://km.oa.com/group/23764/articles/show/249213 微软Office2016的惊天bug
  [2] http://answers.microsoft.com/zh-hans/ie/forum/ie8-windows_7/%E5%90%AF%E5%8A%A8ie%E6%8A%A5%E9%94%99api-ms-win/ed4c563e-51af-4704-9beb-9f45d918897b 启动IE报错api-ms-win-core-path-l1-1-0.dll 丢失
  [3] http://www.crifan.com/win7_can_not_launch_application_for_computer_missing_api_ms_win_crt_runtime_1_1_0_dll/ Win7中出错:无法启动此程序,因为计算机中丢失api-ms-win-crt-runtime-|1-1-0.dll
  [4] http://www.systemlookup.com/CLSID/72557-OCHelper_dll.html

  [5] http://soft.yesky.com/office/138/33691138.shtml 新Office安装采用Click-to-Run v2.0技术

  [6] http://searchenterprisedesktop.techtarget.com/definition/Microsoft-Click-To-Run Microsoft Click-To-Run
  [7] https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.ole.interop.iobjectwithsite.aspx IObjectWithSite Interface