从 Java 应用程序中的非托管本机C++库加载未注册的 .NET 程序集



我正在使用一个 Java 应用程序,该应用程序可以使用可能包含本机代码的自定义包进行扩展,因此除了添加扩展 jar 的能力外,我无法控制 Java 环境。

在本例中,我需要能够从 Java 扩展调用 C# 代码。 这是以前使用免注册 COM 从纯本机上下文中使用的 C# 代码 - 工作正常。 现在我需要能够使相同的代码可以从这个 Java 上下文中使用,但遇到了一个问题,即似乎没有办法控制应该在哪里找到 DLL。 要求将 DLL 安装到 JRE/JDK bin 目录中显然不是一种选择,并且要求将 DLL 注册到 GAC 中并不理想。

目前,我希望所有DLL依赖项都将打包到扩展jar中,并在运行时需要时加载(无需手动安装步骤(。

我希望我可以使用激活上下文 API 来使其工作,并测试了此代码的许多变体,其中 DLL 位于 D:\somepath\:

ACTCTX actctx = {sizeof(actctx)};
actctx.lpSource = "D:\somepath\dll.manifest";
actctx.lpAssemblyDirectory = "D:\somepath\";
actctx.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
HANDLE hActCtx = CreateActCtx(&actctx);
ULONG_PTR ulpCookie = 0;
ActivateActCtx(hActCtx, &ulpCookie);
CoCreateInstance(...);

清单包含一个依赖项程序集,其中包含程序集的详细信息,该程序集包含调用CoCreateInstance引用的 C# 类。

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity name="[assemblyname]" processorArchitecture="msil" publicKeyToken="[token]" version="[version]" />
</dependentAssembly>
</dependency>
</assembly>

还尝试使用 mt.exe 从 DLL 转储这种格式的清单:

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="[assemblyname]" version="[version]" publicKeyToken="[token]" processorArchitecture="msil"/>
<clrClass clsid="..." progid="..." threadingModel="Both" name="..." runtimeVersion="v4.0.30319"/>
...
<file name="[assemblyname].dll" hashalg="SHA1"/>
</assembly>

CreateActCtx 和 ActivateActCtx的调用是成功的,但CoCreateInstance调用总是失败,返回0x80070002,除非我将 DLL 放在C:\Program Files\Java 中。

是否有任何解决方案(除了使用 GAC 之外(允许完全非托管的 C++ DLL 从任意已知位置的 DLL 加载和创建 C# 类的实例?

我正在处理具有类似要求的应用程序,即我需要从非托管客户端进程(用 C++ 编写(激活一个免注册的托管 COM 服务器(位于用 C#/.net v4.8 编写的 DLL(,并且 C# DLL 应位于C++应用程序目录之外的目录中。

截至目前,托管 COM 服务器 DLL 的免注册 COM 服务器激活仅适用于我

  • 使用自定义激活上下文(CreateActCtx/ActivateActCtx 等(激活 COM 服务器,actctx.lpAssemblyDirectory = ...设置为 COM DLL 目录和

  • 更改 .NET 端的程序集探测算法,以便它能够找到我的 C# DLL,默认情况下它不会这样做。

关于后者,我目前通过为C++ EXE添加一个应用程序配置文件来做到这一点,我在其中使用了开发模式,并且还将DEVPATH环境变量设置为与"actctx.lpAssemblyDirectory"相同的值。 这对我有用,因为我只需要在开发过程中将 C# DLL 目录放在 C++ EXE 目录之外。

请注意,还有其他选项可用于更改 .net 程序集探测算法。例如,您可以

  • 添加应用程序配置文件并指定其他 sub(!(-要搜索的目录。仅适用于应用程序目录的相对路径/实际子目录
  • 添加一个自定义的 .net 程序集解析程序(请参阅 AssemblyResolve( - 在实际尝试查找 C# COM 服务器程序集之前,需要由 .net 运行时加载该解析程序。不过,我还没有研究如何使这项工作...

也许(如果这是您的选择(看看.Net DllExport,它允许您从.net程序集导出.net方法作为DLL函数。这使您能够与 .net 程序集进行交互,就像与本机 DLL 交互一样(使用 LoadLibrary、GetProcAddress 等(。

相关内容

  • 没有找到相关文章