You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++/CLI中运行时动态加载C# DLL?

解决方案与回答

一、C++/CLI动态加载C#类库的最佳方案

你之前尝试的LoadLibrary()无效,是因为它仅支持加载原生PE格式的DLL,而C#类库是托管程序集,需要使用.NET原生的反射(Reflection)机制——这也是最适合当前场景的方案:C++/CLI本身支持托管代码,可以直接调用.NET的程序集加载API,无需手动导出函数或处理函数指针,完美适配实例方法和接口调用。

具体步骤与代码示例:

  1. 从环境变量/注册表读取C# DLL的路径
  2. 使用System::Reflection::Assembly::LoadFrom加载托管程序集
  3. 获取目标类型,创建实例并转换为对应的C#接口(接口调用比后期绑定更简洁可靠)
#include <msclr\gcroot.h>
#include <System\Reflection\Assembly.h>
#include <System\Type.h>
#include <System\Activator.h>

using namespace System;
using namespace System::Reflection;
using namespace msclr;

// 定义托管接口的C++/CLI别名(与C#端ISomeClass对应)
using ISomeClass = ClassLibrary::ISomeClass;

int main()
{
    // 1. 从环境变量读取DLL路径(示例,也可读取注册表)
    const wchar_t* dllPathEnv = _wgetenv(L"CUSTOM_CS_DLL_PATH");
    if (dllPathEnv == nullptr)
    {
        // 处理路径不存在的异常情况
        return 1;
    }
    String^ dllPath = gcnew String(dllPathEnv);

    try
    {
        // 2. 加载C#类库程序集
        Assembly^ assembly = Assembly::LoadFrom(dllPath);

        // 3. 获取SomeClass类型
        Type^ someClassType = assembly->GetType(L"ClassLibrary.SomeClass");

        // 4. 创建实例并转换为ISomeClass接口
        gcroot<ISomeClass^> pSomeClass = (ISomeClass^)Activator::CreateInstance(someClassType);

        // 5. 按接口定义调用方法
        int result = pSomeClass->Add(5, 7);
        // 若需调用SomeClass的实例方法(如单参数Add),可直接转换为具体类型
        gcroot<ClassLibrary::SomeClass^> pConcreteClass = (ClassLibrary::SomeClass^)Activator::CreateInstance(someClassType);
        pConcreteClass->Add(5);
    }
    catch (Exception^ ex)
    {
        // 处理加载或调用异常(如程序集不存在、类型找不到等)
        Console::WriteLine(ex->Message);
        return 1;
    }

    return 0;
}

注意:确保C++/CLI项目引用了System.dll,且编译时启用CLR支持(项目属性→常规→公共语言运行时支持)。

二、无需提前知晓DLL路径的替代方案

如果不想硬编码或存储路径,可以利用.NET的程序集探测规则自动查找:

  • 同目录部署:将C#类库及其依赖DLL放在C++/CLI可执行文件的同一目录下,.NET加载器会自动探测到
  • 配置文件指定探测路径:在C++/CLI项目的app.config中添加<probing>元素,指定额外探测目录:
    <configuration>
      <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
          <probing privatePath="Libs;CSharpAssemblies" />
        </assemblyBinding>
      </runtime>
    </configuration>
    
  • AssemblyResolve事件:注册AppDomain::CurrentDomain->AssemblyResolve事件,当加载器找不到依赖时,动态提供程序集路径(适合复杂部署场景)

三、是否值得研究修改加载时链接的方法?

不值得。这类方法针对的是原生C++ DLL的导入表修改,而C#类库是托管程序集,与原生DLL的加载机制完全不同。这种hack式方法维护成本极高,还容易破坏.NET的程序集加载逻辑,远不如直接使用.NET原生的反射加载方案简洁可靠。

四、依赖的C# DLL是否需要单独加载?

不需要。.NET的程序集加载器会自动处理依赖关系:

  • 只要依赖DLL位于主程序集的同一目录、配置文件指定的探测路径,或能通过AssemblyResolve事件找到,加载主C# DLL时,加载器会自动递归加载所有依赖的托管程序集
  • 无需手动调用LoadFrom加载每个依赖项

内容的提问来源于stack exchange,提问作者Gytis Dokšas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 18:12:44