通过代理C++托管dll,本地C++使用C# dll

3
这有点复杂,请耐心阅读。我有一个第三方程序(“目标”),它是用本地(仅限Win32)C++编写的。作为目标设计的一部分,它实现了一个dll插件系统。当本地DLL放置在程序的“ext”目录中时,目标会加载它们。然后,目标会相应地调用每个DLL提供的四个方法(Initialize、SendHook、RecvHook、Terminate)。正如您可能从函数名称中猜到的那样,这些插件在目标中挂钩某些函数。我没有目标的源代码。
其中一个插件很旧、有缺陷,而且令人困惑且相当丑陋。它是用Delphi编写的(当然编译为win32 DLL)。过去几周,我一直在增强并将该插件翻译成C#(我称之为“扩展”)。现在它已经完成,所以我把注意力转向让目标加载该扩展(它构建为类库)。
显然,目标(作为本地C++)无法直接加载扩展(托管C#)。因此,在调查后,似乎我只需要一个“代理”DLL(使用CLR支持编写的VC++)来加载我的扩展,然后负责将方法调用从目标传递到扩展。
"简单。"是吗?现在我比一只袋子里的变色龙更加困惑了。我看到一些关于使用COM的东西,这显然是我需要避免的,无论是从性能还是进程内存权限方面,因为扩展将调用一些方法(通过句柄传递给代理)。此外,我也看到了一些关于tlb和#import指令的东西。这似乎也不是正确的方法。
我发现了这篇文章https://sites.google.com/site/srinivasnzd/csincppviacpp-cli,它似乎终于走上了正确的轨道。事实上,我可以很好地从C++代理中调用我的托管C#。作为一个额外的奖励,它似乎(我还没有能够与实际目标进行测试)可以适当地调用它们的托管对应函数,虽然是通过代理。但现在问题开始出现了。"
  • 一个纯本地进程能否加载启用了CLR的DLL?我看到有人讨论基本上将启用CLR的代码制作成静态库,然后将其与纯本地代码链接以形成“部分托管、部分本地”代理DLL。但是在那一点上,困惑开始出现,我不确定该主题是否适用于我正在尝试做的事情。
  • 我该如何将DWORD地址转换为IntPtr(然后在C#端解除marshaling以获得函数指针)?
  • 我看到提到了AppDomains。这是我需要担心的事情吗?
  • 我假设我的代理DLL需要在同一文件夹中具有托管扩展DLL才能运行。我需要做些特殊的事情来加载它,还是CLR和链接器会处理它?
  • 除了输出DLL之外,我还得到了扩展名为“.exp”、“ilk”和“.lib”的文件。我假设这些是用于静态链接的,当我使用DLL时可以忽略它们?

我认为是那些在糖果袋中寻找变色龙的人让事情变得混乱了。 - dlev
1
可怜的变色龙不知道该变成什么颜色... - Xcelled
啊,我明白了。我想最后混淆的是我自己。 - dlev
这就是为什么我对Win32的古老语言感到非常害怕。这也是为什么我们需要停止使用像VB6和IE6这样的语言和程序。 - Linuxios
如果有帮助的话,请查看http://filterdotnet.codeplex.com/,看看他是如何将本地代码与托管代码链接起来的。具体来说,请查看源树中的`native/clr.cpp`,并查看`CorBindToRuntimeEx`及其相关方法以加载CLR。在这种情况下,我记得托管模块必须在GAC中。研究这段代码应该会帮助您回答至少一些问题,祝好运。顺便说一句,变色龙和彩虹糖的笑话真好笑 :) - Tom
1个回答

2
请看一下这个模板,它可以帮助你在不使用C++封装器的情况下导出C#代码。模板
不幸的是,没有DllExport属性,所以你需要使用C++封装器或修改IL代码来执行导出。
转发地址不是问题,但要注意C#端的函数指针,因为你总是需要确保有一个引用来将它们远离GC收集器。如果使用静态引用,则最容易 - GC无法看到非托管代码中函数指针的引用,因此可能会将其清理掉。
如果您有多个c#模块,则应用程序域将很重要 - 如果这些模块共享相同的代码,那么它将变得更加重要。
"exp"来自链接器,"ilk"和"lib"与链接器相关,因此我认为你不需要复制它们,但在调试时可能需要它们。

哇,我印象深刻...这正如广告所说的一样有效。然而,现在每当我尝试让扩展加载一个表单(当然是在另一个线程上),目标就会冻结。没有任何错误信息...在我开一个新问题之前有什么想法吗? - Xcelled
加载表单是什么意思?Windows表单吗? - weismat
是的,请看这里:https://dev59.com/P2XWa4cB1Zd3GeqPPKpO - Xcelled

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接