XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Runtime.InteropServices;
using System.Text;

namespace XFESystem.DriverOracle;

internal sealed record PciDevice(string InstanceId, string[] HardwareIds, uint Bus, uint Device, uint Function);

internal static class WindowsPci
{
    [StructLayout(LayoutKind.Sequential)]
    private struct DeviceInfo { public uint Size; public Guid ClassGuid; public uint Instance; public nuint Reserved; }
    private static readonly Guid DisplayClass = new("4d36e968-e325-11ce-bfc1-08002be10318");
    [DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    private static extern nint SetupDiGetClassDevsW(ref Guid classGuid, string? enumerator, nint parent, uint flags);
    [DllImport("setupapi.dll", SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetupDiEnumDeviceInfo(nint set, uint index, ref DeviceInfo data);
    [DllImport("setupapi.dll", SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetupDiGetDeviceRegistryPropertyW(nint set, ref DeviceInfo data, uint property, out uint type, byte[] buffer, uint bytes, out uint needed);
    [DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetupDiGetDeviceInstanceIdW(nint set, ref DeviceInfo data, StringBuilder identifier, uint capacity, out uint needed);
    [DllImport("setupapi.dll", SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetupDiDestroyDeviceInfoList(nint set);

    public static PciDevice[] Exact5090()
    {
        Guid display = DisplayClass; nint set = SetupDiGetClassDevsW(ref display, null, 0, 2 /* DIGCF_PRESENT */);
        if (set == -1) throw new InvalidOperationException("Read-only display PCI enumeration failed: " + Marshal.GetLastWin32Error());
        var devices = new List<PciDevice>();
        try
        {
            for (uint index = 0; ; index++)
            {
                var data = new DeviceInfo { Size = (uint)Marshal.SizeOf<DeviceInfo>() };
                if (!SetupDiEnumDeviceInfo(set, index, ref data))
                {
                    if (Marshal.GetLastWin32Error() == 259) break;
                    throw new InvalidOperationException("Display enumeration failed: " + Marshal.GetLastWin32Error());
                }
                byte[] hardware = Property(set, ref data, 1 /* SPDRP_HARDWAREID */, 7);
                string[] ids = Encoding.Unicode.GetString(hardware).Split('\0', StringSplitOptions.RemoveEmptyEntries);
                if (!ids.Any(id => id.StartsWith(@"PCI\VEN_10DE&DEV_2B85&", StringComparison.OrdinalIgnoreCase) || id.Equals(@"PCI\VEN_10DE&DEV_2B85", StringComparison.OrdinalIgnoreCase))) continue;
                uint bus = BitConverter.ToUInt32(Property(set, ref data, 0x15 /* SPDRP_BUSNUMBER */, 4));
                uint address = BitConverter.ToUInt32(Property(set, ref data, 0x1C /* SPDRP_ADDRESS */, 4));
                var instance = new StringBuilder(1024);
                if (!SetupDiGetDeviceInstanceIdW(set, ref data, instance, 1024, out _)) throw new InvalidOperationException("Cannot read the matched PCI instance.");
                devices.Add(new(instance.ToString(), ids, bus, address >> 16, address & 0xFFFF));
            }
        }
        finally { if (!SetupDiDestroyDeviceInfoList(set)) throw new InvalidOperationException("Cannot release read-only PCI enumeration state."); }
        return devices.ToArray();
    }

    private static byte[] Property(nint set, ref DeviceInfo data, uint property, uint expectedType)
    {
        byte[] buffer = new byte[4096];
        if (!SetupDiGetDeviceRegistryPropertyW(set, ref data, property, out uint type, buffer, (uint)buffer.Length, out uint needed) ||
            type != expectedType || needed > buffer.Length || needed == 0 || (expectedType == 4 && needed != 4))
            throw new InvalidOperationException("Cannot read the bounded PCI identity property " + property + ": " + Marshal.GetLastWin32Error());
        return buffer[..(int)needed];
    }
}