You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取完整路径转为常量以修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:12:22