.NET Core非当前目录启动进程时DLL加载失败问题求助
解决非可执行目录启动时的DllNotFoundException问题
这个问题的核心在于Windows的DLL搜索机制:当你不从程序exe所在目录启动时,当前工作目录(CWD)不再指向exe目录,而Windows默认会优先从当前工作目录、系统目录、PATH环境变量指定的路径查找DLL。你的C++ DLL不在这些默认搜索路径里,因此抛出了System.DllNotFoundException异常。
下面是几个针对性的解决方案,按推荐程度排序:
1. 手动添加程序集目录到DLL搜索路径(最推荐)
通过调用Windows API SetDllDirectory,把.NET Core程序集所在目录(即exe的实际存放目录)加入DLL搜索路径的最优先级位置。这样不管当前工作目录是什么,系统都会优先去这个目录查找你的C++ DLL。
实现代码示例:
using System; using System.Runtime.InteropServices; class Program { // 导入Windows原生API [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern bool SetDllDirectory(string lpPathName); static void Main(string[] args) { // 获取程序集所在的绝对目录(也就是exe的目录) string exeDir = AppContext.BaseDirectory; // 设置DLL搜索路径 if (!SetDllDirectory(exeDir)) { // 可选:处理设置失败的情况,比如记录日志 int errorCode = Marshal.GetLastWin32Error(); Console.WriteLine($"Failed to set DLL search path. Error code: {errorCode}"); } // 后续调用依赖C++ DLL的方法即可正常执行 YourDllWrapper.CallDllMethod(); } }
2. 用绝对路径动态加载DLL
如果不想修改全局DLL搜索路径,可以通过LoadLibrary动态加载指定绝对路径的DLL,再通过函数地址调用方法。这种方式更灵活,适合需要加载不同版本DLL的场景。
示例代码:
using System; using System.Runtime.InteropServices; using System.IO; class Program { [DllImport("kernel32.dll", CharSet = CharSet.Unicode, 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); // 定义与C++函数匹配的委托 private delegate int AddNumbersDelegate(int a, int b); static void Main(string[] args) { // 拼接C++ DLL的绝对路径 string dllFullPath = Path.Combine(AppContext.BaseDirectory, "YourCppDll.dll"); IntPtr dllHandle = LoadLibrary(dllFullPath); if (dllHandle == IntPtr.Zero) { int errorCode = Marshal.GetLastWin32Error(); throw new System.ComponentModel.Win32Exception(errorCode); } // 获取目标函数的地址 IntPtr funcPtr = GetProcAddress(dllHandle, "AddNumbers"); if (funcPtr == IntPtr.Zero) { int errorCode = Marshal.GetLastWin32Error(); throw new System.ComponentModel.Win32Exception(errorCode); } // 转换为委托并调用 AddNumbersDelegate addNumbers = Marshal.GetDelegateForFunctionPointer<AddNumbersDelegate>(funcPtr); int result = addNumbers(10, 20); Console.WriteLine($"Result: {result}"); } }
3. 检查C++ DLL的依赖项完整性
有时候抛出DllNotFoundException不是主DLL找不到,而是它依赖的其他组件(比如VC运行时库msvcp140.dll、vcruntime140.dll等)缺失。你可以用Dependency Walker工具扫描你的C DLL,列出所有依赖项,然后把这些依赖文件一同放到程序目录,或者在预发布环境安装对应的VC++ Redistributable包。
4. 调整PATH环境变量(不推荐)
你可以在预发布环境中将程序exe所在目录添加到系统或用户的PATH环境变量中,但这种方式灵活性差,多个版本程序共存时容易引发冲突,仅作为备选方案。
内容的提问来源于stack exchange,提问作者Xavier
相关产品推荐
相关产品推荐

