【发布时间】:2011-07-08 23:09:43
【问题描述】:
短版:通过 Internet Explorer 加载到网页中的 MFC ActiveX 控件如何保证其关联的 DLL 是从其自己的目录加载的,而不是选择可能已经存在的同名 DLL被加载到进程中?
长版,带有血淋淋的细节:我有一个应用程序 myapp.exe,它使用一组 DLL:one.dll、two.dll 和 three.dll。
MFC ActiveX 控件也使用相同的 DLL,该控件公开一些与 myapp.exe 相同的功能,因此有一个 mycontrol.ocx 也与这些 DLL 链接。 ActiveX 控件与application/myapp MIME 类型相关联,因此IE 将使用它来显示使用myapp.exe 创建的文档。
可以同时安装 myapp.exe 的版本 1 和 2,但只有最新版本的 mycontrol.ocx(版本 2)与 application/myapp MIME 类型相关联:
c:\Program Files\MyApp\Version 1\
myapp.exe
mycontrol.ocx
one.dll
two.dll
three.dll
c:\Program Files\MyApp\Version 2\
myapp.exe
mycontrol.ocx <-- registered with the MIME type
one.dll
two.dll
three.dll
这就是它变得困难的地方:myapp.exe 具有用于显示 Web 内容的嵌入式 Internet Explorer 控件。您可以运行myapp.exe 的版本1,将嵌入的Internet Explorer 指向application/myapp 文档,IE 将加载mycontrol.ocx 的版本2 来查看它。这应该没问题,但不是:
Windows 加载mycontrol.ocx,发现它依赖于one.dll,并且在这个过程中已经有一个one.dll,并将mycontrol.ocx的导入表指向已经加载的(版本 1) one.dll,而不是加载 one.dll 的版本 2。这失败了,因为 mycontrol.ocx 的版本 2 使用了 one.dll 的版本 2 中的新 API,而版本 1 中没有。
我该如何阻止它这样做?如果one.dll 尚未加载,Windows 会在c:\Program Files\MyApp\Version 2 中查找它,一切都会好起来的。 (而且我不能为每个版本的软件重命名我的所有模块!)
失败的解决方案 #1:我给了 mycontrol.ocx 一个清单,为所有 DLL 指定了 <file ...> 元素,但这不起作用。 one.dll 从 Version 2 目录加载,但 two.dll 没有。我认为这是因为 two.dll 正在加载,因为 one.dll 引用它,而 one.dll 没有这样的清单。
失败的解决方案 #2:所以我向 所有 DLL 添加了一个清单,每个 DLL 都在 <file ...> 元素中列出了它的依赖关系。但这完全破坏了myapp.exe,因为 MFC 现在将每个 DLL 视为具有自己的激活上下文,这是不对的 - 整个进程(在 myapp.exe 的情况下)或整个实例都应该有一个 MFC 上下文控制(在mycontrol.exe的情况下)。我不能为每个模块都有一个新的激活上下文;我需要一个用于整个mycontrol.ocx 及其附带的 DLL。
我将所有清单更改为使用相同的 name= 属性,希望这会将它们全部置于相同的上下文中,但这没有任何效果。
失败的解决方案#3:我给了myapp.exe一个清单,上面写着<file name="mycontrol.ocx"/>,希望强制版本1的应用程序使用版本1的控件,这很好。但这会失败,因为当 Internet Explorer 加载 mycontrol.ocx 时,它会使用 mycontrol.ocx 的第 2 版的完整路径调用 LoadLibrary,并且当使用完整路径加载模块时,清单重定向不起作用。
我不能做的事情:我不能更改加载控件的代码,因为是 Internet Explorer 做的(通过 MIME 类型)。
我们将不胜感激地收到任何解决方案、建议或简单的同情信息。
【问题讨论】:
-
#2 上面最有意义,但我不知道您所说的“MFC 现在将每个 DLL 视为它自己的激活上下文,这是不对的”。什么是激活上下文?为什么重要?
标签: windows dll mfc activex manifest