目录

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搜集总结并生成,仅供参考