如何获取完整路径转为常量以修改DllImport的DLL搜索路径?
解决Steamworks.NET动态指定DLL搜索路径的问题
首先得明确为什么你之前的尝试行不通:
const字段必须是编译时常量,而SteamFolderPath()是运行时才能获取到的值,所以根本没法用来初始化const。- 虽然
static readonly是运行时初始化,但[DllImport]的第一个参数要求必须是编译时常量,所以这个方式也走不通。
那正确的做法是手动提前加载指定路径的DLL,这样CLR在解析[DllImport]的时候会优先使用已经加载到进程中的DLL实例,不管你在[DllImport]里写的是名称还是路径。
步骤1:修正Steam路径获取方法
先把你的路径获取逻辑改对,原来的代码里拼接了路径但返回的是原始的Steam安装路径,这会导致DLL路径错误。用Path.Combine来拼接路径更稳妥:
using System.IO; using Microsoft.Win32; public static string GetSteamAPIDllFullPath() { // 从注册表获取Steam安装路径 var steamInstallPath = Registry.GetValue( @"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Valve\Steam", "InstallPath", null) as string; // 处理Steam未安装的情况,fallback到默认名称让系统自动搜索 if (string.IsNullOrEmpty(steamInstallPath)) { return "steam_api64"; } // 拼接完整的DLL路径(注意要加上.dll后缀) return Path.Combine(steamInstallPath, "steamapps", "common", "mygame", "steam_api64.dll"); }
步骤2:在程序启动时手动加载DLL
在调用任何SteamAPI方法(比如SteamAPI_Init)之前,先加载你指定路径的DLL。这里要区分.NET Framework和.NET Core/.NET 5+的API:
using System; using System.Runtime.InteropServices; // 程序初始化阶段执行(比如游戏启动入口、Steam模块初始化前) public void InitializeSteamDll() { string dllPath = GetSteamAPIDllFullPath(); IntPtr dllHandle = IntPtr.Zero; try { #if NETFRAMEWORK // .NET Framework 使用LoadLibrary dllHandle = LoadLibrary(dllPath); if (dllHandle == IntPtr.Zero) { throw new System.ComponentModel.Win32Exception(); } #else // .NET Core/.NET 5+ 使用NativeLibrary.Load dllHandle = NativeLibrary.Load(dllPath); #endif } catch (Exception ex) { // 这里可以加日志记录,或者弹窗提示用户Steam未正确安装 Console.WriteLine($"加载Steam API DLL失败: {ex.Message}"); throw; } // 可选:如果需要在程序退出时卸载DLL,可以保存handle,之后调用NativeLibrary.Free或FreeLibrary // _steamDllHandle = dllHandle; } // .NET Framework需要声明LoadLibrary和FreeLibrary #if NETFRAMEWORK [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr LoadLibrary(string lpFileName); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool FreeLibrary(IntPtr hModule); #endif
步骤3:保持原有的DllImport代码不变
现在你原来的[DllImport]代码不需要修改,因为系统已经加载了你指定路径的DLL,CLR会直接找到它:
internal const string NativeLibraryName = @"steam_api64"; [DllImport(NativeLibraryName, EntryPoint = "SteamAPI_Init", CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool SteamAPI_Init();
关键原理
当你手动加载DLL后,Windows会把这个DLL实例缓存到进程的模块列表里。之后当CLR解析[DllImport]的名称时,会优先从已加载的模块中查找,而不是走默认的DLL搜索路径,这样就实现了指定自定义路径加载DLL的目的。
额外注意事项
- 一定要保证在调用任何SteamAPI方法之前完成DLL加载,否则会触发默认路径的搜索。
- 处理好异常情况:比如Steam未安装、游戏目录不存在等,避免程序直接崩溃。
- 如果是64位和32位兼容的场景,还要注意区分
steam_api64.dll和steam_api.dll,根据进程位数选择对应的DLL。
内容的提问来源于stack exchange,提问作者Ronohx
相关产品推荐
相关产品推荐

