C-调用-Cpp-的动态库-dll放子目录里
C# 调用 Cpp 的动态库 dll(放子目录里)
以下结果内容均由AI大模型生成,仅供参考
要在 C# 中调用位于 lib2 子目录的 C++ DLL(A.dll 依赖 B.dll 和 C.dll ),需通过 Windows API 修改 DLL 搜索路径。以下是完整实现方案:
一、核心步骤
声明 Windows API
使用 SetDllDirectory 修改 DLL 搜索路径:
using System;
using System.IO;
using System.Runtime.InteropServices;
class NativeLoader
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool SetDllDirectory(string lpPathName);
}
初始化加载路径
在程序启动时设置路径(如 Main 方法开头):
static void Main()
{
// 获取 exe 所在目录的 lib2 子目录
string dllDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "lib2");
// 设置 DLL 搜索路径
if (!NativeLoader.SetDllDirectory(dllDir))
{
int error = Marshal.GetLastWin32Error();
throw new Exception($"设置 DLL 路径失败 (错误代码: {error})");
}
// 后续调用 A.dll 的代码...
}
若修改不了main 方法,可以这样使用
静态构造函数方案(兼容旧版 .NET)
在首次调用 DLL 相关功能前触发路径设置:
public class NativeApiWrapper
{
static NativeApiWrapper()
{
SetDllDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"));
}
[DllImport("A.dll")]
public static extern int YourFunction();
}
调用方式
// 首次访问时自动初始化
int result = NativeApiWrapper.YourFunction();
通过 DllImport 调用 DLL
直接使用相对路径声明(系统会自动在 lib2 中查找依赖):
class NativeMethods
{
[DllImport("A.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int YourFunctionInA(int param);
}
// 调用示例
int result = NativeMethods.YourFunctionInA(123);
二、关键注意事项
依赖项处理
所有 DLL(A/B/C)必须同时放入 lib2 目录
无需单独加载 B.dll/C.dll ,系统会自动解析 A.dll 的依赖链
路径验证
添加路径检查确保目录存在:
if (!Directory.Exists(dllDir))
{
Directory.CreateDirectory(dllDir); // 可选:自动创建目录
// 或 throw new DirectoryNotFoundException("lib2 目录不存在");
}
备选方案
若需同时指定多个路径,改用 AddDllDirectory:
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr AddDllDirectory(string lpPathName);
// 初始化时调用
IntPtr dirHandle = AddDllDirectory(dllDir);
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
三、目录结构示例
YourApp.exe
└── lib2/
├── A.dll
├── B.dll
└── C.dll
四、常见问题解决
错误 126 (MOD_NOT_FOUND):检查 lib2 内是否缺少 B.dll 或 C.dll
错误 193:DLL 架构不匹配(需同为 x86 或 x64)
依赖冲突:用 Dependency Walker 检查依赖树
通过此方案,系统加载器会自动处理嵌套依赖关系,无需手动加载每个 DLL。完整代码示例可参考 Microsoft DLL 搜索文档 。
以上内容均由AI搜集总结并生成,仅供参考.
SetDllDirectory 和 AddDllDirectory 详解
1. 函数定义与作用
SetDllDirectory
用于临时修改当前进程的 DLL 搜索路径,将指定目录插入默认搜索顺序中。调用后,DLL 加载顺序变为:
① 应用程序目录
② SetDllDirectory 指定的目录
③ 系统目录(如 C:\Windows\System32)
④ 16位系统目录(C:\Windows\System)
⑤ Windows 目录(如 C:\Windows)
⑥ PATH 环境变量中的目录 134。
特点:
每次调用会覆盖前一次设置的目录。
传递 NULL 可恢复默认搜索顺序,传递空字符串 “” 会移除当前目录的搜索权限。
AddDllDirectory
用于向当前进程的 DLL 搜索路径添加新目录(不覆盖已有设置),支持同时添加多个目录。添加的目录会在系统目录之后、Windows 目录之前被搜索 2。
2. 是否影响系统环境变量 PATH?
不会影响。这两个函数:
仅修改当前进程及其子进程的 DLL 搜索逻辑 1。
不更改全局 PATH 环境变量,系统 PATH 始终保持不变 13。
修改在进程退出后自动失效,无持久性影响。
3. 典型使用场景
隔离依赖库:将 DLL 放入 lib2 子目录,通过 SetDllDirectory 指定路径,避免与系统目录冲突。
多版本共存:用 AddDllDirectory 添加多个自定义路径,加载不同版本的依赖库 2。
4. C# 调用示例
using System;
using System.IO;
using System.Runtime.InteropServices;
class DllLoader
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool SetDllDirectory(string path);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr AddDllDirectory(string path);
public static void LoadDlls()
{
string libPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "lib2");
// 方法1:用 SetDllDirectory 设置单一目录
SetDllDirectory(libPath); // 后续加载 A.dll 时会搜索 lib2 目录
// 方法2:用 AddDllDirectory 添加多个目录(需 Windows 8+)
IntPtr dirHandle = AddDllDirectory(libPath); // 返回的句柄可用于后续移除目录
}
}
// 主程序调用
static void Main()
{
DllLoader.LoadDlls();
// 调用 A.dll 中的函数(A.dll 会自动在 lib2 目录下查找 B.dll 、C.dll )
}
关键说明:
SetDllDirectory 适用于简单场景,AddDllDirectory 更灵活但需较新系统支持 12。
若需彻底避免路径冲突,建议结合 LoadLibraryEx 的 LOAD_LIBRARY_SEARCH_USER_DIRS 标志使用 2。
以上内容均由AI搜集总结并生成,仅供参考