6

我有一个要添加全屏后处理效果的程序。我没有该程序的源代码(它是专有的,尽管开发人员确实向我发送了一份调试符号的副本,.map 格式)。我有编写和工作的效果代码,没有问题。

我现在的问题是将两者联系起来。

到目前为止,我已经尝试了两种方法:

使用 Detours 修改原程序的导入表。这很好用并且保证稳定,但是我与之交谈过的用户对此并不满意,它需要安装(除了提取档案之外),并且存在一些问题,如果使用 Detours 修补程序在条款下是有效的最终用户许可协议。因此,该选项已失效。

另一种选择是传统的 DLL 替换。我已经包装了 OpenGL (opengl32.dll),我需要程序来加载我的 DLL 而不是系统副本(只需将其放入具有正确名称的程序文件夹中,这很容易)。

然后我需要我的 DLL 来加载 Cg 框架和运行时(依赖于 OpenGL)和其他一些东西。当 Cg 加载时,它会调用我的一些函数,这些函数调用 Cg 函数,并且我往往会出现堆栈溢出和无限循环。我需要能够在子目录中包含 Cg DLL 并仍然使用它们的功能(不确定是否可以让我的 DLL 导入表指向子目录中的 DLL)或者我需要动态链接它们(我' d宁愿不这样做,只是为了简化构建过程),迫使他们参考系统文件(不是我的自定义替换)。

整个链条是: 程序加载 DLL A(名为 opengl32.dll)。DLL A 加载 Cg.dll 并动态链接 (GetProcAddress) 到 sysdir/opengl32.dll。我现在需要 Cg.dll 来引用 sysdir/opengl32.dll,而不是DLL A。

这将如何完成? 编辑:如果不使用 GetProcAddress ,这将如何轻松完成?如果没有其他工作,我愿意退回到那个,但如果可能的话,我宁愿不这样做。

Edit2:我刚刚在 MSDN 文档中偶然发现了 SetDllDirectory 函数(在完全不相关的搜索中)。乍一看,这看起来像我需要的。是这样,还是我判断错误?(现在去测试它)

Edit3:我通过做一些不同的事情解决了这个问题。我没有删除 OpenGL32.dll,而是将我的 DLL 重命名为 DInput.dll。它不仅具有必须导出一个函数而不是超过 120 个函数的优点(对于程序、Cg 和 GLEW),我不必担心函数会重新运行(我可以像往常一样链接到 OpenGL) . 为了接听我需要拦截的电话,我使用了 Detours。总而言之,它工作得更好。不过,这个问题仍然是一个有趣的问题(希望将来对其他试图做疯狂事情的​​人有用)。两个答案都很好,所以我还不确定选哪个...

4

2 回答 2

1

SetDllDirectory 可能不起作用。Cg.dll 可能只是链接到 OpenGL.dll。当操作系统加载 Cg.dll 时,它看到已经有一个使用该名称(您的)加载的模块,因此它将 Cg 与该名称链接,而不是去寻找其他副本。也就是说,SetDllDirectory 修改的搜索顺序甚至从未发挥作用,因为操作系统不进行任何搜索。

我怀疑您最好的选择确实是检测对您的库的重入调用。当您检测到一个,而不是进行自定义处理时,将调用直接转发到真正的 OpenGL 库,由于调用 LoadLibrary,然后为每个库的函数调用 GetProcAddress,您可以引用该库。

于 2010-05-03T20:09:15.133 回答
1

您可以使用激活上下文的魔力来尝试解决您的问题。

很大程度上取决于系统中的第 3 方组件已经有清单的天气 - 以及对这些清单的多少篡改可能构成违反许可证的行为。

为了解决 dll 版本控制问题,Windows XP 获得了一种称为激活上下文的技术。有时称为并行程序集,甚至是像应用程序隔离这样可怕的东西

总结大量阅读到一个小空间:清单是可以描述程序集或描述对程序集的依赖关系的 XML 数据块。程序集是一个清单,加上它的 dll。

存在的原因是程序集可以采用简单的 dll。“comctl32.dll”及其版本号(v6),并创建一个更大更唯一名称的东西,以便可以将多个版本的简单dll安全地安装在同一个地方。组件旨在安装在C:\Windows\WinSxS.

当清单文件描述程序集中的 dll 时,它称为程序集清单。并且通常与 dll 具有不同的名称。

当清单文件描述 dll 或 exe 使用的程序集时,它称为应用程序清单,并且通常作为 RT_MANIFEST 资源嵌入 - 在 res id 为 1 的 EXE 中,在 res id 为 2 的 Dll 中 - 或在磁盘上作为一个名为“appname.exe.manifest”/“dllname.dll.2.manifest”的文件。应用程序清单定义了一个叫做激活上下文的东西——它基本上是一个命名空间,windows 将在其中搜索东西。每个清单都会创建一个激活上下文。每个激活上下文都有一个简单的 dll 名称到程序集的映射。

因此,如果您使用 opengl32.dll 文件创建程序集并为 app.exe 引用(本地 opengl32.dll)文件创建激活上下文,那么所有剩余的 dll 都可以(并且将)继续使用尽管名称非常相似,但系统 opengl32.dll 文件coff

问题是,应用程序清单的 res-id - 1 - 意味着它用于创建进程默认激活上下文 - 所以所有没有自己显式清单(Cg?)的 dll 都将搜索进程默认空间并找到那个 opengl32.dll

因此,您必须为尚未嵌入的每个dll创建清单,确保简单地不引用您的 opengl32.dll 程序集,这应该允许然后恢复到默认搜索顺序并在正常的 system32 位置找到它。

这意味着您的 opengl32.dll 不能在 exe 的文件夹中,因为该文件夹是在 system32 之前搜索 dll 的(您依赖于挂钩的事实)。

系统在搜索程序集时采用的相当简单的搜索顺序拯救了我们。首先它在 WinSxS 中搜索。你的 Opengl32.dll 不会在那里,安装有一个难题。然后它在 exe 的文件夹中搜索具有程序集名称的子文件夹,然后它在 exe 的文件夹中直接搜索程序集清单。

这意味着您可以创建一个程序集 - 称为:“OpenGLHook”并且您的文件夹结构如下所示:

\appfolder\
  app.exe
  app.exe.manifest                  - contains a dependentAssembly node to OpenGLHook
  OpenGLHook\OpenGLHook.manifest    - contains a file name=opengl32.dll
  OpenGLHook\opengl32.dll           - your hook dll
  yourimpl.dll                      - your implementation dll that linkgs to cg.dll
  cg.dll                            - cg libraries
  cg.dll.2.manifest                 - a stub manifest you put together to ensure cg
                                      doesnt use the app default activation ctx.

嗯,祝你好运吗?

于 2010-05-03T22:09:46.060 回答