是否可以在不使用 WMI 的情况下获取网络适配器的 PnPDeviceId?

2024-04-20

我一直在尝试使用 p/invoke setupapi 调用获取给定网络适配器的 PnPDeviceId,但没有成功。我不情愿地决定使用 WMI,如下所示:

public static string GetPnpDeviceId(string mac)
{
    ManagementObjectCollection mo = Management.GetCollection("Win32_NetworkAdapter", "PNPDeviceID", "MACAddress = '" + mac + "'");
    return GetFirstValueString(mo, "PNPDeviceID");
}

public static ManagementObjectCollection GetCollection(string WMIClass, string WMISelect="*", string WMIWhere="")
{

    string qry = "SELECT " + WMISelect + " FROM " + WMIClass + (WMIWhere == "" ? "" : " WHERE " + WMIWhere);
    ObjectQuery oq = new System.Management.ObjectQuery(qry);
    ManagementObjectSearcher query = new ManagementObjectSearcher(oq);
    ManagementObjectCollection queryCollection = query.Get();
    return queryCollection;
}

public static string GetFirstValueString(ManagementObjectCollection queryCollection, string WMIValue)
{
    foreach (ManagementObject mo in queryCollection)
    {
        object o = mo[WMIValue];
        return (string)o;
    }
    return "";
}

p/invoke api 似乎很难正确执行,但是对于这样一个简单的调用加载管理类(尤其是 Win32_NetworkAdapter 似乎)的开销似乎过多。谁能告诉我即使使用 p/invoke 这是否可能,或者更好地告诉我在哪里可以找到 api 调用中的值,我将从那里开始。


好吧,我自己解决了。虽然代码很多,但恕我直言,性能是值得的。 每次 WMI 调用大约需要 800 毫秒,而 pinvoke 调用大约需要 25 毫秒。无论如何,这是代码(粗略且准备好的-很少的评论):

class NetPnP
{
    internal static Guid GUID_DEVINTERFACE_NET = new Guid("CAC88484-7515-4C03-82E6-71A87ABAC361");

    public static string GetPnPDeviceId(NetworkInterface ni)
    {
        Guid classGuid = GUID_DEVINTERFACE_NET;
        IntPtr hwndParent = IntPtr.Zero;
        Int32 flags = Win32DeviceMgmt.DIGCF_DEVICEINTERFACE | Win32DeviceMgmt.DIGCF_PRESENT;
        IntPtr pDevInfoSet = IntPtr.Zero;
        IntPtr pNewDevInfoSet = IntPtr.Zero;
        try
        {
            pNewDevInfoSet = Win32DeviceMgmt.SetupDiGetClassDevs(ref classGuid, IntPtr.Zero, hwndParent, flags);//, pDevInfoSet, strMachineName, IntPtr.Zero);
            if (pNewDevInfoSet == IntPtr.Zero)
            {
                Logger.Log("Failed to get device information list");
                return "";
            }

            Int32 iRet;
            Int32 iMemberIndex = 0;
            do
            {
                Win32DeviceMgmt.SP_DEVINFO_DATA devInfoData = new Win32DeviceMgmt.SP_DEVINFO_DATA();
                devInfoData.ClassGuid = Guid.Empty;
                devInfoData.DevInst = 0;
                devInfoData.Reserved = UIntPtr.Zero;
                devInfoData.cbSize = Marshal.SizeOf(devInfoData);

                iRet = Win32DeviceMgmt.SetupDiEnumDeviceInfo(pNewDevInfoSet, iMemberIndex, ref devInfoData);
                if (iRet == 0)
                {
                    Int32 iLastError = Win32DeviceMgmt.GetLastError();
                    if (iLastError == Win32DeviceMgmt.ERROR_NO_MORE_FILES)
                    {
                        //Console.WriteLine("No more devices in list");
                        break;
                    }
                    else
                    {
                        iMemberIndex++;
                        continue;
                    }
                }
                string desc = GetDevicePropertyString(pNewDevInfoSet, devInfoData, SetupDiGetDeviceRegistryPropertyEnum.SPDRP_DEVICEDESC);
                if (ni.Description.Equals(desc)) return GetDeviceInstanceId(pNewDevInfoSet, devInfoData);
                string friendly = GetDevicePropertyString(pNewDevInfoSet, devInfoData, SetupDiGetDeviceRegistryPropertyEnum.SPDRP_FRIENDLYNAME);
                if (ni.Description.Equals(friendly)) return GetDeviceInstanceId(pNewDevInfoSet, devInfoData);

                iMemberIndex++;
            } while (true);
            return "";
        }
        finally
        {
            Win32DeviceMgmt.SetupDiDestroyDeviceInfoList(pNewDevInfoSet);
        }
    }

    static String GetDeviceInstanceId(IntPtr DeviceInfoSet, Win32DeviceMgmt.SP_DEVINFO_DATA DeviceInfoData)
    {
        StringBuilder strId = new StringBuilder(0);
        Int32 iRequiredSize = 0;
        Int32 iSize = 0;
        Int32 iRet = Win32DeviceMgmt.SetupDiGetDeviceInstanceId(DeviceInfoSet, ref DeviceInfoData, strId, iSize, ref iRequiredSize);
        strId = new StringBuilder(iRequiredSize);
        iSize = iRequiredSize;
        iRet = Win32DeviceMgmt.SetupDiGetDeviceInstanceId(DeviceInfoSet, ref DeviceInfoData, strId, iSize, ref iRequiredSize);
        if (iRet == 1)
        {
            return strId.ToString();
        }

        return String.Empty;
    }

    static String GetDevicePropertyString(IntPtr DeviceInfoSet, Win32DeviceMgmt.SP_DEVINFO_DATA DeviceInfoData, SetupDiGetDeviceRegistryPropertyEnum property)
    {
        byte[] ptrBuf = GetDeviceProperty(DeviceInfoSet, DeviceInfoData, property);
        return ptrBuf.ToStrAuto();
    }

    static Guid GetDevicePropertyGuid(IntPtr DeviceInfoSet, Win32DeviceMgmt.SP_DEVINFO_DATA DeviceInfoData, SetupDiGetDeviceRegistryPropertyEnum property)
    {
        byte[] ptrBuf = GetDeviceProperty(DeviceInfoSet, DeviceInfoData, property);
        return new Guid(ptrBuf);
    }

    static byte[] GetDeviceProperty(IntPtr DeviceInfoSet, Win32DeviceMgmt.SP_DEVINFO_DATA DeviceInfoData, SetupDiGetDeviceRegistryPropertyEnum property)
    {
        StringBuilder strId = new StringBuilder(0);
        byte[] ptrBuf= null;
        UInt32 RegType;
        UInt32 iRequiredSize = 0;
        UInt32 iSize = 0;
        bool iRet = Win32DeviceMgmt.SetupDiGetDeviceRegistryProperty(DeviceInfoSet, ref DeviceInfoData,
            (uint)property, out RegType, ptrBuf, iSize, out iRequiredSize);
        ptrBuf = new byte[iRequiredSize];
        iSize = iRequiredSize;
        iRet = Win32DeviceMgmt.SetupDiGetDeviceRegistryProperty(DeviceInfoSet, ref DeviceInfoData,
            (uint)property, out RegType, ptrBuf, iSize, out iRequiredSize);
        if (iRet)
        {
            return ptrBuf;
        }

        return new byte[0];
    }

}

public static class ByteArrayEx
{   
    public static string ToStrAuto(this byte[] bytes)
    {
        string ret = "";


        IntPtr unmanagedPointer = Marshal.AllocHGlobal(bytes.Length);
        try
        {
            Marshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
            // Call unmanaged code
            ret = Marshal.PtrToStringAuto(unmanagedPointer);
        }
        finally
        {
            Marshal.FreeHGlobal(unmanagedPointer);
        }
        return ret;
    }
}
public class Win32DeviceMgmt
{
    internal static Int32 ERROR_NO_MORE_FILES = 259;

    internal static Int32 LINE_LEN = 256;

    internal static Int32 DIGCF_DEFAULT = 0x00000001;  // only valid with DIGCF_DEVICEINTERFACE
    internal static Int32 DIGCF_PRESENT = 0x00000002;
    internal static Int32 DIGCF_ALLCLASSES = 0x00000004;
    internal static Int32 DIGCF_PROFILE = 0x00000008;
    internal static Int32 DIGCF_DEVICEINTERFACE = 0x00000010;

    internal static Int32 SPINT_ACTIVE = 0x00000001;
    internal static Int32 SPINT_DEFAULT = 0x00000002;
    internal static Int32 SPINT_REMOVED = 0x00000004;

    [StructLayout(LayoutKind.Sequential)]
    internal struct SP_DEVINFO_DATA
    {
        /// <summary>
        /// Size of structure in bytes
        /// </summary>
        public Int32 cbSize;
        /// <summary>
        /// GUID of the device interface class
        /// </summary>
        public Guid ClassGuid;
        /// <summary>
        /// Handle to this device instance
        /// </summary>
        public Int32 DevInst;
        /// <summary>
        /// Reserved; do not use. 
        /// </summary>
        public UIntPtr Reserved;
    };

    [StructLayout(LayoutKind.Sequential)]
    internal struct SP_DEVICE_INTERFACE_DATA
    {
        /// <summary>
        /// Size of the structure, in bytes
        /// </summary>
        public Int32 cbSize;
        /// <summary>
        /// GUID of the device interface class
        /// </summary>
        public Guid InterfaceClassGuid;
        /// <summary>
        /// 
        /// </summary>
        public Int32 Flags;
        /// <summary>
        /// Reserved; do not use.
        /// </summary>
        public IntPtr Reserved;

    };


    [DllImport("setupapi.dll")]
    internal static extern IntPtr SetupDiGetClassDevsEx(ref Guid ClassGuid, [MarshalAs(UnmanagedType.LPStr)]String enumerator, IntPtr hwndParent, Int32 Flags, IntPtr DeviceInfoSet, [MarshalAs(UnmanagedType.LPStr)]String MachineName, IntPtr Reserved);
    [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
    internal static extern IntPtr SetupDiGetClassDevs(           // 1st form using a ClassGUID only, with null Enumerator
       ref Guid ClassGuid,
       IntPtr Enumerator,
       IntPtr hwndParent,
       int Flags
    );
    [DllImport("setupapi.dll")]
    internal static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);

    [DllImport("setupapi.dll")]
    internal static extern Int32 SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, IntPtr DeviceInfoData, IntPtr InterfaceClassGuid, Int32 MemberIndex, ref  SP_DEVINFO_DATA DeviceInterfaceData);

    [DllImport("setupapi.dll")]
    internal static extern Int32 SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, Int32 MemberIndex, ref  SP_DEVINFO_DATA DeviceInterfaceData);

    [DllImport("setupapi.dll")]
    internal static extern Int32 SetupDiClassNameFromGuid(ref Guid ClassGuid, StringBuilder className, Int32 ClassNameSize, ref Int32 RequiredSize);

    [DllImport("setupapi.dll")]
    internal static extern Int32 SetupDiGetClassDescription(ref Guid ClassGuid, StringBuilder classDescription, Int32 ClassDescriptionSize, ref Int32 RequiredSize);

    [DllImport("setupapi.dll")]
    internal static extern Int32 SetupDiGetDeviceInstanceId(
        IntPtr DeviceInfoSet, 
        ref SP_DEVINFO_DATA DeviceInfoData, 
        StringBuilder DeviceInstanceId, 
        Int32 DeviceInstanceIdSize, 
        ref Int32 RequiredSize);

    /// <summary>
    /// The SetupDiGetDeviceRegistryProperty function retrieves the specified device property.
    /// This handle is typically returned by the SetupDiGetClassDevs or SetupDiGetClassDevsEx function.
    /// </summary>
    /// <param Name="DeviceInfoSet">Handle to the device information set that contains the interface and its underlying device.</param>
    /// <param Name="DeviceInfoData">Pointer to an SP_DEVINFO_DATA structure that defines the device instance.</param>
    /// <param Name="Property">Device property to be retrieved. SEE MSDN</param>
    /// <param Name="PropertyRegDataType">Pointer to a variable that receives the registry data Type. This parameter can be NULL.</param>
    /// <param Name="PropertyBuffer">Pointer to a buffer that receives the requested device property.</param>
    /// <param Name="PropertyBufferSize">Size of the buffer, in bytes.</param>
    /// <param Name="RequiredSize">Pointer to a variable that receives the required buffer size, in bytes. This parameter can be NULL.</param>
    /// <returns>If the function succeeds, the return value is nonzero.</returns>
    [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern bool SetupDiGetDeviceRegistryProperty(
        IntPtr DeviceInfoSet,
        ref SP_DEVINFO_DATA DeviceInfoData,
        uint Property,
        out UInt32 PropertyRegDataType,
        byte[] PropertyBuffer,
        uint PropertyBufferSize,
        out UInt32 RequiredSize
        );

    // Device Property
    [StructLayout(LayoutKind.Sequential)]
    internal struct DEVPROPKEY
    {
        public Guid fmtid;
        public UInt32 pid;
    }

    [DllImport("kernel32.dll")]
    internal static extern Int32 GetLastError();
}
/// <summary>
/// Flags for SetupDiGetDeviceRegistryProperty().
/// </summary>
enum SetupDiGetDeviceRegistryPropertyEnum : uint
{
    SPDRP_DEVICEDESC = 0x00000000, // DeviceDesc (R/W)
    SPDRP_HARDWAREID = 0x00000001, // HardwareID (R/W)
    SPDRP_COMPATIBLEIDS = 0x00000002, // CompatibleIDs (R/W)
    SPDRP_UNUSED0 = 0x00000003, // unused
    SPDRP_SERVICE = 0x00000004, // Service (R/W)
    SPDRP_UNUSED1 = 0x00000005, // unused
    SPDRP_UNUSED2 = 0x00000006, // unused
    SPDRP_CLASS = 0x00000007, // Class (R--tied to ClassGUID)
    SPDRP_CLASSGUID = 0x00000008, // ClassGUID (R/W)
    SPDRP_DRIVER = 0x00000009, // Driver (R/W)
    SPDRP_CONFIGFLAGS = 0x0000000A, // ConfigFlags (R/W)
    SPDRP_MFG = 0x0000000B, // Mfg (R/W)
    SPDRP_FRIENDLYNAME = 0x0000000C, // FriendlyName (R/W)
    SPDRP_LOCATION_INFORMATION = 0x0000000D, // LocationInformation (R/W)
    SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000E, // PhysicalDeviceObjectName (R)
    SPDRP_CAPABILITIES = 0x0000000F, // Capabilities (R)
    SPDRP_UI_NUMBER = 0x00000010, // UiNumber (R)
    SPDRP_UPPERFILTERS = 0x00000011, // UpperFilters (R/W)
    SPDRP_LOWERFILTERS = 0x00000012, // LowerFilters (R/W)
    SPDRP_BUSTYPEGUID = 0x00000013, // BusTypeGUID (R)
    SPDRP_LEGACYBUSTYPE = 0x00000014, // LegacyBusType (R)
    SPDRP_BUSNUMBER = 0x00000015, // BusNumber (R)
    SPDRP_ENUMERATOR_NAME = 0x00000016, // Enumerator Name (R)
    SPDRP_SECURITY = 0x00000017, // Security (R/W, binary form)
    SPDRP_SECURITY_SDS = 0x00000018, // Security (W, SDS form)
    SPDRP_DEVTYPE = 0x00000019, // Device Type (R/W)
    SPDRP_EXCLUSIVE = 0x0000001A, // Device is exclusive-access (R/W)
    SPDRP_CHARACTERISTICS = 0x0000001B, // Device Characteristics (R/W)
    SPDRP_ADDRESS = 0x0000001C, // Device Address (R)
    SPDRP_UI_NUMBER_DESC_FORMAT = 0X0000001D, // UiNumberDescFormat (R/W)
    SPDRP_DEVICE_POWER_DATA = 0x0000001E, // Device Power Data (R)
    SPDRP_REMOVAL_POLICY = 0x0000001F, // Removal Policy (R)
    SPDRP_REMOVAL_POLICY_HW_DEFAULT = 0x00000020, // Hardware Removal Policy (R)
    SPDRP_REMOVAL_POLICY_OVERRIDE = 0x00000021, // Removal Policy Override (RW)
    SPDRP_INSTALL_STATE = 0x00000022, // Device Install State (R)
    SPDRP_LOCATION_PATHS = 0x00000023, // Device Location Paths (R)
    SPDRP_BASE_CONTAINERID = 0x00000024  // Base ContainerID (R)
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否可以在不使用 WMI 的情况下获取网络适配器的 PnPDeviceId? 的相关文章

随机推荐

  • 没有地图的地理编码

    我可以在没有地图的情况下使用 Google 地图地理编码 API 吗 我有一个带有自动完成功能的文本框 Google Maps API Place 我希望在用户输入街道号码后 我会得到邮政编码 问候 自动完成是允许在没有地图的情况下使用 G
  • 如何通过 PHP 获取字符串形式的 HTML 页面?

    我正在通过 PHP 从网页中获取一些信息simple php dom和卷曲 问题是页面构建不正确 因此 DOM 对象包含错误信息 如何获取 HTML 文件作为 PHP var 中的字符串 以便我可以通过它运行正则表达式 Curl 不起作用
  • 为页面创建新应用程序

    我有一个个人 FB 帐户 从那里我创建了一个新页面来介绍我的博客网站 我在我的网站上下载了一个适用于我的 WordPress 主题的小部件 以便我可以链接两个帐户以进行自动更新 该小部件要求我通过创建新应用程序提供应用程序 ID 和密钥 当
  • FMDB SQLite 问题:查询的行数?

    有谁知道如何在使用 FMDB 时返回查询计数 如果我执行Query select count from sometable were 我会得到一个空的FMResultSet 如何获取查询的行数 我是否需要执行 select from som
  • 使用 XMLHttpRequest 不使用 jQuery 将 JSON 数据发送到 PHP

    我正在尝试使用 XMLHttpRequest 对象从表单发送 JSON 数据 我可以使用以下函数发送数据 FireBug 中没有显示任何错误 并且 FireBug 可以很好地显示请求中的 JSON 数据 但是 我将数据发送到echo php
  • iOS 8 中的嵌套 UICollectionViews、自动布局和旋转

    我开始在一个大型项目中使用 AutoLayout 并对它感到非常惊讶 但是 现在我必须调整项目以适应旋转和尺寸类别 并且我在让视图正确运行方面遇到了很大的麻烦 基本问题是我有UICollectionViews with 再次包含 UICol
  • JS 数组显示的用户个人资料图片不正确 - 如何解决此问题?

    抱歉 这篇文章很长 但我不确定如果没有所有代码 问题是否会出现 我正在使用 parse com 和 JavaScript SDK 下面的代码是我的用户个人资料页面的一部分 它在屏幕上向他们显示他们的个人资料图片并允许他们更改它 更改个人资料
  • WatiN UnauthorizedAccessException 错误

    使用 NUnit 和 WatiN 运行任何测试时 我收到 UnauthorizedAccessException 错误 Test Test IndexTests Can Do failed WatiN Core Exceptions Ele
  • 禁用/启用 div 中的所有元素[重复]

    这个问题在这里已经有答案了 如何快速禁用 启用任何 div 中的所有元素 输入 链接和 jQ 按钮 链接没有 禁用 属性 因此您必须更加努力 my div find input prop disabled true my div a cli
  • 在 SQL-CLR 触发器或存储过程中创建套接字

    我在 SQL Server 2008 中有一个 SQL CLR 触发器 它向套接字服务器发送消息 它工作正常 但我需要 TCP 客户端保持与其通信的服务器的连接 为了做到这一点 我必须创建一些保持活动状态的线程 因此 我创建了一个线程 将消
  • 在 Puppeteer 中连接浏览器

    是否可以将浏览器连接到 puppeteer 而无需在 puppeteer 中实例化它 例如 像普通用户一样运行 chromium 实例 然后将其连接到代码中的 puppeteer 实例 答案是 是 和 否 您可以使用以下方式连接到现有的co
  • 选中复选框并存储在数组中 javascript

    任何人都可以告诉我如何检查并将复选框选中的值添加到数组中 单击时获取选中的值并将其存储在 JavaScript 中的数组中 这是我的代码 function ajax city var xmlhttp try xmlhttp new XMLH
  • jQuery 动画数字计数器从零到值

    我创建了一个脚本来将数字从零动画化到它的值 Working jQuery Counter 0 animate Counter Single text duration 1000 easing swing step function Sing
  • 如何禁用 EditText 中的 SwiftKey(第三方键盘)行为?

    我在 Android 应用程序中使用标准的 EditText 控件 此 EditText 的输入只能从应用程序的内置键盘插入 When SwiftKey 第三方键盘应用程序 安装在设备上 它会导致奇怪的行为 例如光标跳动 并在某些文本下方添
  • Windows 自动化 telnet

    我想运行一组通常在 telnet 中运行的命令 来自 c 例如我想运行以下命令 using System using System Diagnostics namespace InteractWithConsoleApp class Pro
  • 隐藏在ios 9中的附件栏

    嗨有人可以帮我吗 我想在 ios 9 中隐藏键盘上的附件栏 它的工作发现直到 ios 8 但在 ios 9 我无法隐藏附件栏我厌倦了这段代码但它不工作 for UIView possibleFormView in keyboardWindo
  • 外部 API 的 CORS 问题 - 通过 PostMan 工作,但不能使用 Axios 进行 HTTP 请求 [重复]

    这个问题在这里已经有答案了 正在开发一个涉及汽车数据的新 Laravel 项目 并找到了一个免费的查找 API http www carqueryapi com documentation api usage 一个示例端点是 https w
  • 发送和接收短信以验证手机号码

    我正在尝试在不使用第三方的情况下进行手机号码验证 为此 我的逻辑是这样的 用户输入带有国家 地区代码的手机号码 当他们点击验证按钮时 意图将使用随机唯一 ID 向用户定义的手机号码发送一条短信 之后应用程序广播将等待 2 分钟 当它收到短信
  • Android 中的 Javascript“document.cookie”?

    我需要帮助如何正确使用 javascript 文档 cookie 或者 如何在 Android 网络浏览器中从 javascript 编写 cookie 我已确保在设置中启用了 cookie 当我检查时 通过使用 navigator coo
  • 是否可以在不使用 WMI 的情况下获取网络适配器的 PnPDeviceId?

    我一直在尝试使用 p invoke setupapi 调用获取给定网络适配器的 PnPDeviceId 但没有成功 我不情愿地决定使用 WMI 如下所示 public static string GetPnpDeviceId string