如何在其他项目引用C#类库时自动关联依赖的C++ DLL?
解决C#类库引用C++ DLL后,下游项目无需手动复制DLL的方法
针对你遇到的问题——引用封装了C++ DLL的C#类库时,下游项目找不到A_Cpp.dll的情况,以下是几种无需手动复制的解决方案:
方案一:将C++ DLL嵌入C#类库,运行时自动释放
- 在
UsingCppDllProject项目中,选中Ref_Cpp/A_Cpp.dll,右键设置属性:- 生成操作:嵌入的资源
- 复制到输出目录:不复制
- 修改
MyPortingClass,添加静态构造函数,在类首次加载时将嵌入的DLL释放到可访问路径:
namespace UsingCppDllProject { public class MyPortingClass { private static string _dllPath; private delegate int AddNumberDelegate(int firstNum, int secondNum); private static AddNumberDelegate _addNumberFunc; static MyPortingClass() { // 拼接嵌入资源的完整名称(命名空间+目录+文件名) string resourceName = "UsingCppDllProject.Ref_Cpp.A_Cpp.dll"; // 获取C#类库所在目录 string assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); _dllPath = Path.Combine(assemblyDir, "Ref_Cpp", "A_Cpp.dll"); // 创建目标目录并释放DLL文件 Directory.CreateDirectory(Path.GetDirectoryName(_dllPath)); using (Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) { using (FileStream fileStream = new FileStream(_dllPath, FileMode.Create)) { resourceStream.CopyTo(fileStream); } } // 动态加载DLL并绑定函数 IntPtr dllHandle = LoadLibrary(_dllPath); if (dllHandle == IntPtr.Zero) { throw new System.ComponentModel.Win32Exception(); } IntPtr funcPtr = GetProcAddress(dllHandle, "AddNumber"); if (funcPtr == IntPtr.Zero) { throw new System.ComponentModel.Win32Exception(); } _addNumberFunc = Marshal.GetDelegateForFunctionPointer<AddNumberDelegate>(funcPtr); } public int Do_AddFunction(int num1, int num2) { return _addNumberFunc(num1, num2); } [DllImport("kernel32.dll")] private static extern IntPtr LoadLibrary(string dllToLoad); [DllImport("kernel32.dll", CharSet = CharSet.Ansi)] private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); } }
这种方式会在类首次被调用时自动释放C++ DLL到类库所在目录,下游项目引用类库后无需额外操作。
方案二:通过生成事件自动复制C++ DLL,下游项目自动同步
- 在
UsingCppDllProject项目属性的「生成事件」标签中,在「后期生成事件命令行」添加:
xcopy "$(ProjectDir)Ref_Cpp\A_Cpp.dll" "$(OutputDir)Ref_Cpp\" /Y /I
该命令会在类库编译完成后,自动将Ref_Cpp下的A_Cpp.dll复制到类库输出目录(Release/Debug)的Ref_Cpp子目录中。
2. 下游项目引用UsingCppDllProject时,确保引用的「复制本地」属性为True(默认值),这样类库输出目录下的所有文件(包括Ref_Cpp/A_Cpp.dll)会自动同步到下游项目的输出目录,DllImport的相对路径就能正确定位到文件。
方案三:动态构造DLL路径并加载
放弃固定的DllImport字符串,通过程序集目录动态获取C++ DLL路径,使用系统API加载DLL并绑定函数:
namespace UsingCppDllProject { public class MyPortingClass { private delegate int AddNumberDelegate(int firstNum, int secondNum); private AddNumberDelegate _addNumberFunc; public MyPortingClass() { // 获取C#类库所在目录,拼接C++ DLL路径 string assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string dllPath = Path.Combine(assemblyDir, "Ref_Cpp", "A_Cpp.dll"); // 加载DLL IntPtr dllHandle = LoadLibrary(dllPath); if (dllHandle == IntPtr.Zero) { throw new System.ComponentModel.Win32Exception(); } // 获取函数地址并绑定委托 IntPtr funcPtr = GetProcAddress(dllHandle, "AddNumber"); if (funcPtr == IntPtr.Zero) { throw new System.ComponentModel.Win32Exception(); } _addNumberFunc = Marshal.GetDelegateForFunctionPointer<AddNumberDelegate>(funcPtr); } public int Do_AddFunction(int num1, int num2) { return _addNumberFunc(num1, num2); } [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] private static extern IntPtr LoadLibrary(string lpFileName); [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); } }
这种方式不受DllImport常量限制,只要C++ DLL与C#类库的相对位置不变,下游项目就能正常调用。
内容的提问来源于stack exchange,提问作者jhKim
相关产品推荐
相关产品推荐

