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

如何用C#检测游戏是否支持DirectX?

检测游戏是否使用DirectX的C#实现方法

为什么你提供的ChatGPT代码无效

你贴出的代码仅获取游戏主程序的文件版本号,完全没有涉及DirectX相关的检测逻辑,自然无法判断游戏是否依赖DirectX。以下是几种可行的检测方案:


方案1:解析游戏主程序的PE导入表(最准确)

游戏若使用DirectX,其主程序的PE导入表中会包含d3d9.dll、d3d11.dll、d3d12.dll、dxgi.dll等DirectX核心库的引用。通过解析PE文件的导入表,可直接判断游戏是否依赖DirectX,不受库文件位置的限制。

代码实现

using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;

public static class DirectXDetector
{
    // DirectX相关核心库列表
    private static readonly string[] DirectXDlls = { "d3d9.dll", "d3d10.dll", "d3d10_1.dll", "d3d11.dll", "d3d12.dll", "dxgi.dll", "dinput8.dll", "dsound.dll" };

    public static bool IsGameUsingDirectX(string gameExePath)
    {
        if (!File.Exists(gameExePath))
            return false;

        try
        {
            using var fs = new FileStream(gameExePath, FileMode.Open, FileAccess.Read);
            using var reader = new BinaryReader(fs);

            // 读取DOS头
            var dosHeader = reader.ReadStructure<IMAGE_DOS_HEADER>();

            // 跳转到PE签名位置
            fs.Seek(dosHeader.e_lfanew, SeekOrigin.Begin);
            var peSignature = reader.ReadUInt32();
            if (peSignature != 0x00004550) // 验证PE文件标识"PE\0\0"
                return false;

            // 读取PE文件头
            var peHeader = reader.ReadStructure<IMAGE_FILE_HEADER>();

            // 读取可选头(兼容64位程序,32位可改用IMAGE_OPTIONAL_HEADER32)
            var optionalHeader = reader.ReadStructure<IMAGE_OPTIONAL_HEADER64>();

            // 定位导入表目录
            var importDirectory = optionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
            if (importDirectory.VirtualAddress == 0 || importDirectory.Size == 0)
                return false;

            // 将虚拟地址转换为文件偏移
            var importTableOffset = RvaToFileOffset(fs, peHeader, optionalHeader, importDirectory.VirtualAddress);
            if (importTableOffset == -1)
                return false;

            fs.Seek(importTableOffset, SeekOrigin.Begin);

            // 遍历导入表中的每个DLL引用
            while (true)
            {
                var importDescriptor = reader.ReadStructure<IMAGE_IMPORT_DESCRIPTOR>();
                if (importDescriptor.OriginalFirstThunk == 0 && importDescriptor.FirstThunk == 0)
                    break;

                // 获取DLL名称的文件偏移
                var nameOffset = RvaToFileOffset(fs, peHeader, optionalHeader, importDescriptor.Name);
                if (nameOffset == -1)
                    continue;

                var currentPos = fs.Position;
                fs.Seek(nameOffset, SeekOrigin.Begin);
                var dllName = reader.ReadCString();
                fs.Seek(currentPos, SeekOrigin.Begin);

                // 检查是否为DirectX相关库
                if (DirectXDlls.Any(dll => dllName.Equals(dll, StringComparison.OrdinalIgnoreCase)))
                    return true;
            }

            return false;
        }
        catch
        {
            return false;
        }
    }

    // 将虚拟地址(RVA)转换为文件偏移
    private static long RvaToFileOffset(FileStream fs, IMAGE_FILE_HEADER peHeader, IMAGE_OPTIONAL_HEADER64 optionalHeader, uint rva)
    {
        var sectionCount = peHeader.NumberOfSections;
        // 跳转到节表起始位置
        fs.Seek(dosHeader.e_lfanew + 4 + Marshal.SizeOf(peHeader), SeekOrigin.Begin);

        for (int i = 0; i < sectionCount; i++)
        {
            var sectionHeader = reader.ReadStructure<IMAGE_SECTION_HEADER>();
            if (rva >= sectionHeader.VirtualAddress && rva < sectionHeader.VirtualAddress + sectionHeader.VirtualSize)
            {
                return rva - sectionHeader.VirtualAddress + sectionHeader.PointerToRawData;
            }
        }
        return -1;
    }

    // 读取C风格字符串
    private static string ReadCString(this BinaryReader reader)
    {
        var buffer = new System.Text.StringBuilder();
        char c;
        while ((c = reader.ReadChar()) != '\0')
        {
            buffer.Append(c);
        }
        return buffer.ToString();
    }

    // 读取二进制数据为结构体的扩展方法
    private static T ReadStructure<T>(this BinaryReader reader)
    {
        var buffer = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
        var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        try
        {
            return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
        }
        finally
        {
            handle.Free();
        }
    }

    // PE结构常量与定义
    private const int IMAGE_DIRECTORY_ENTRY_IMPORT = 1;

    [StructLayout(LayoutKind.Sequential)]
    private struct IMAGE_DOS_HEADER
    {
        public ushort e_magic;
        public ushort e_cblp;
        public ushort e_cp;
        public ushort e_crlc;
        public ushort e_cparhdr;
        public ushort e_minalloc;
        public ushort e_maxalloc;
        public ushort e_ss;
        public ushort e_sp;
        public ushort e_csum;
        public ushort e_ip;
        public ushort e_cs;
        public ushort e_lfarlc;
        public ushort e_ovno;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        public ushort[] e_res;
        public ushort e_oemid;
        public ushort e_oeminfo;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
        public ushort[] e_res2;
        public int e_lfanew;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct IMAGE_FILE_HEADER
    {
        public ushort Machine;
        public ushort NumberOfSections;
        public uint TimeDateStamp;
        public uint PointerToSymbolTable;
        public uint NumberOfSymbols;
        public ushort SizeOfOptionalHeader;
        public ushort Characteristics;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct IMAGE_OPTIONAL_HEADER64
    {
        public ushort Magic;
        public byte MajorLinkerVersion;
        public byte MinorLinkerVersion;
        public uint SizeOfCode;
        public uint SizeOfInitializedData;
        public uint SizeOfUninitializedData;
        public uint AddressOfEntryPoint;
        public uint BaseOfCode;
        public ulong ImageBase;
        public uint SectionAlignment;
        public uint FileAlignment;
        public ushort MajorOperatingSystemVersion;
        public ushort MinorOperatingSystemVersion;
        public ushort MajorImageVersion;
        public ushort MinorImageVersion;
        public ushort MajorSubsystemVersion;
        public ushort MinorSubsystemVersion;
        public uint Win32VersionValue;
        public uint SizeOfImage;
        public uint SizeOfHeaders;
        public uint CheckSum;
        public ushort Subsystem;
        public ushort DllCharacteristics;
        public ulong SizeOfStackReserve;
        public ulong SizeOfStackCommit;
        public ulong SizeOfHeapReserve;
        public ulong SizeOfHeapCommit;
        public uint LoaderFlags;
        public uint NumberOfRvaAndSizes;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public IMAGE_DATA_DIRECTORY[] DataDirectory;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct IMAGE_DATA_DIRECTORY
    {
        public uint VirtualAddress;
        public uint Size;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct IMAGE_IMPORT_DESCRIPTOR
    {
        public uint OriginalFirstThunk;
        public uint TimeDateStamp;
        public uint ForwarderChain;
        public uint Name;
        public uint FirstThunk;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct IMAGE_SECTION_HEADER
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[] Name;
        public uint VirtualSize;
        public uint VirtualAddress;
        public uint SizeOfRawData;
        public uint PointerToRawData;
        public uint PointerToRelocations;
        public uint PointerToLinenumbers;
        public ushort NumberOfRelocations;
        public ushort NumberOfLinenumbers;
        public uint Characteristics;
    }
}

使用示例

bool usesDirectX = DirectXDetector.IsGameUsingDirectX(@"C:\Games\ExampleGame\Game.exe");
Console.WriteLine(usesDirectX ? "游戏使用DirectX" : "游戏未使用DirectX");

方案2:检查游戏目录中的DirectX相关库

部分游戏会将DirectX依赖库打包在自身目录中,可直接遍历目录查找相关DLL:

using System.IO;
using System.Linq;

public static bool CheckGameDirectoryForDirectX(string gameDirectory)
{
    if (!Directory.Exists(gameDirectory))
        return false;

    var directXDlls = new[] { "d3d9.dll", "d3d11.dll", "d3d12.dll", "dxgi.dll" };
    return directXDlls.Any(dll => File.Exists(Path.Combine(gameDirectory, dll)));
}

注意:该方法局限性大,若游戏调用系统自带的DirectX库,会出现误判。


方案3:枚举运行中游戏的已加载模块

若游戏正在运行,可通过枚举进程的已加载模块检测:

using System.Diagnostics;

public static bool CheckRunningGameForDirectX(string processName)
{
    var processes = Process.GetProcessesByName(processName);
    if (processes.Length == 0)
        return false;

    var directXModules = new[] { "d3d9.dll", "d3d11.dll", "d3d12.dll", "dxgi.dll" };
    foreach (var process in processes)
    {
        try
        {
            foreach (ProcessModule module in process.Modules)
            {
                if (directXModules.Any(m => module.ModuleName.Equals(m, StringComparison.OrdinalIgnoreCase)))
                    return true;
            }
        }
        catch // 无权限访问进程模块时跳过
        {
            continue;
        }
    }
    return false;
}

注意:需要游戏处于运行状态,且程序需足够权限访问进程模块。


内容的提问来源于stack exchange,提问作者AC Studio

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 13:24:53