Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 获取当前USB电源状态_C#_Winapi_Usb_Power Management_Wdm - Fatal编程技术网

C# 获取当前USB电源状态

C# 获取当前USB电源状态,c#,winapi,usb,power-management,wdm,C#,Winapi,Usb,Power Management,Wdm,我一直在尝试读取USB端口D0/D1/D2/D3的当前电源状态。我还没有找到多少关于如何访问实际状态的信息。下面是对这个问题的描述。它有一整节是关于改变的,但真的不知道怎么读。我在Windows和硬件层面的工作经验很少,所以如果这是显而易见的,请原谅 我还发现这个用C编写的Microsoft调试应用程序名为。如果安装并打开USB目录树,则为各个端口显示的第一个信息是其电源状态 e、 g 它有,但文件超过5000行,我不能很好地导航C代码,告诉我如何实际读取电源状态 我正在尝试将其实现到一个C应用

我一直在尝试读取USB端口D0/D1/D2/D3的当前电源状态。我还没有找到多少关于如何访问实际状态的信息。下面是对这个问题的描述。它有一整节是关于改变的,但真的不知道怎么读。我在Windows和硬件层面的工作经验很少,所以如果这是显而易见的,请原谅

我还发现这个用C编写的Microsoft调试应用程序名为。如果安装并打开USB目录树,则为各个端口显示的第一个信息是其电源状态

e、 g

它有,但文件超过5000行,我不能很好地导航C代码,告诉我如何实际读取电源状态


我正在尝试将其实现到一个C应用程序中,但任何语言的帮助都将不胜感激

在大量挖掘USBView源代码之后,我发现您需要执行以下操作:

使用获取设备信息集的句柄

IntPtr DeviceInfo集=SetupDiGetClassDevsref classGuid,null,IntPtr.Zero,0x00000002 | 0x00000010

其中,USB设备的classGuid为A5DCBF10-6530-11D2-901F-00C04FB951ED

使用获取单个设备信息

SetupDienumDeviceInfo设备信息集、索引、引用设备信息数据

其中,DeviceInfo DATA是SP_DEVINFO_数据结构的实例,其值为cbSize inicializace至28。然后,设备信息将存储在此结构中。 从index=0开始,然后递增,直到方法返回false和Marshal.GetLastWin32Error返回259 ERROR\u NO\u MORE\u项以获取所有设备

然后使用SetupDiGetDeviceRegistryProperty检索power属性

您可以:

A.传入CM_POWER_数据,然后应使用ref CM_POWER_数据替换DllImport方法签名中的字节[]

B.传入一个字节数组,然后将字节数组解析为CM_POWER_数据代码,事实证明该代码非常擅长

这里我展示了选项B——传入字节数组。功率数据将在数据变量中。已跳过转换

  //sizeof evaluates to 56, if you want to hardcode it
  byte[] data = new byte[Marshal.SizeOf<CM_POWER_DATA>()];

  SetupDiGetDeviceRegistryProperty(
                    deviceInfoSet,
                    ref deviceInfoData,
                    0x0000001E, //the property SPDRP_DEVICE_POWER_DATA
                    out uint type,
                    data,
                    data.Length, 
                    out uint size)
                );
各种guid和属性的常量

    public const uint SPDRP_DEVICEDESC = (0x00000000);  // DeviceDesc (R/W)
    public const uint SPDRP_HARDWAREID = (0x00000001);  // HardwareID (R/W)
    public const uint SPDRP_COMPATIBLEIDS = (0x00000002);  // CompatibleIDs (R/W)
    public const uint SPDRP_UNUSED0 = (0x00000003);  // unused
    public const uint SPDRP_SERVICE = (0x00000004);  // Service (R/W)
    public const uint SPDRP_UNUSED1 = (0x00000005);  // unused
    public const uint SPDRP_UNUSED2 = (0x00000006);  // unused
    public const uint SPDRP_CLASS = (0x00000007);  // Class (R--tied to ClassGUID)
    public const uint SPDRP_CLASSGUID = (0x00000008);  // ClassGUID (R/W)
    public const uint SPDRP_DRIVER = (0x00000009);  // Driver (R/W)
    public const uint SPDRP_CONFIGFLAGS = (0x0000000A);  // ConfigFlags (R/W)
    public const uint SPDRP_MFG = (0x0000000B);  // Mfg (R/W)
    public const uint SPDRP_FRIENDLYNAME = (0x0000000C);  // FriendlyName (R/W)
    public const uint SPDRP_LOCATION_INFORMATION = (0x0000000D);  // LocationInformation (R/W)
    public const uint SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = (0x0000000E);  // PhysicalDeviceObjectName (R)
    public const uint SPDRP_CAPABILITIES = (0x0000000F);  // Capabilities (R)
    public const uint SPDRP_UI_NUMBER = (0x00000010);  // UiNumber (R)
    public const uint SPDRP_UPPERFILTERS = (0x00000011);  // UpperFilters (R/W)
    public const uint SPDRP_LOWERFILTERS = (0x00000012);  // LowerFilters (R/W)
    public const uint SPDRP_BUSTYPEGUID = (0x00000013);  // BusTypeGUID (R)
    public const uint SPDRP_LEGACYBUSTYPE = (0x00000014);  // LegacyBusType (R)
    public const uint SPDRP_BUSNUMBER = (0x00000015);  // BusNumber (R)
    public const uint SPDRP_ENUMERATOR_NAME = (0x00000016);  // Enumerator Name (R)
    public const uint SPDRP_SECURITY = (0x00000017);  // Security (R/W, binary form)
    public const uint SPDRP_SECURITY_SDS = (0x00000018);  // Security (W, SDS form)
    public const uint SPDRP_DEVTYPE = (0x00000019);  // Device Type (R/W)
    public const uint SPDRP_EXCLUSIVE = (0x0000001A);  // Device is exclusive-access (R/W)
    public const uint SPDRP_CHARACTERISTICS = (0x0000001B);  // Device Characteristics (R/W)
    public const uint SPDRP_ADDRESS = (0x0000001C);  // Device Address (R)
    public const uint SPDRP_UI_NUMBER_DESC_FORMAT = (0X0000001D);  // UiNumberDescFormat (R/W)
    public const uint SPDRP_DEVICE_POWER_DATA = (0x0000001E);  // Device Power Data (R)
    public const uint SPDRP_REMOVAL_POLICY = (0x0000001F);  // Removal Policy (R)
    public const uint SPDRP_REMOVAL_POLICY_HW_DEFAULT = (0x00000020);  // Hardware Removal Policy (R)
    public const uint SPDRP_REMOVAL_POLICY_OVERRIDE = (0x00000021);  // Removal Policy Override (RW)
    public const uint SPDRP_INSTALL_STATE = (0x00000022);  // Device Install State (R)
    public const uint SPDRP_LOCATION_PATHS = (0x00000023);  // Device Location Paths (R)
    public const uint SPDRP_BASE_CONTAINERID = (0x00000024);  // Base ContainerID (R)

    public const uint SPDRP_MAXIMUM_PROPERTY = (0x00000025);  // Upper bound on ordinals


    public const string GUID_DEVINTERFACE_USB_HUB = "f18a0e88-c30c-11d0-8815-00a0c906bed8";
    public const string GUID_DEVINTERFACE_USB_DEVICE = "A5DCBF10-6530-11D2-901F-00C04FB951ED";
    public const string GUID_DEVINTERFACE_USB_HOST_CONTROLLER = "3ABF6F2D-71C4-462a-8A92-1E6861E6AF27";
    public const string GUID_USB_WMI_STD_DATA = "4E623B20-CB14-11D1-B331-00A0C959BBD2";
    public const string GUID_USB_WMI_STD_NOTIFICATION = "4E623B20-CB14-11D1-B331-00A0C959BBD2";

    public const string GUID_USB_WMI_DEVICE_PERF_INFO = "66C1AA3C-499F-49a0-A9A5-61E2359F6407";
    public const string GUID_USB_WMI_NODE_INFO = "{9C179357-DC7A-4f41-B66B-323B9DDCB5B1}";
    public const string GUID_USB_WMI_TRACING = "3a61881b-b4e6-4bf9-ae0f-3cd8f394e52f";
    public const string GUID_USB_TRANSFER_TRACING = "{681EB8AA-403D-452c-9F8A-F0616FAC9540}";
    public const string GUID_USB_PERFORMANCE_TRACING = "{D5DE77A6-6AE9-425c-B1E2-F5615FD348A9}";
    public const string GUID_USB_WMI_SURPRISE_REMOVAL_NOTIFICATION = "{9BBBF831-A2F2-43B4-96D1-86944B5914B3}";
结构和枚举:

public enum DEVICE_POWER_STATE {
    PowerDeviceUnspecified,
    PowerDeviceD0,
    PowerDeviceD1,
    PowerDeviceD2,
    PowerDeviceD3,
    PowerDeviceMaximum
}

public enum SYSTEM_POWER_STATE {
    PowerSystemUnspecified,
    PowerSystemWorking,
    PowerSystemSleeping1,
    PowerSystemSleeping2,
    PowerSystemSleeping3,
    PowerSystemHibernate,
    PowerSystemShutdown,
    PowerSystemMaximum
}

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct SP_DEVINFO_DATA {
    public UInt32 cbSize;
    public Guid ClassGuid;
    public UInt32 DevInst;
    public IntPtr Reserved;
}

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct CM_POWER_DATA {
    public uint PD_Size;
    public DEVICE_POWER_STATE PD_MostRecentPowerState;
    public uint PD_Capabilities;
    public uint PD_D1Latency;
    public uint PD_D2Latency;
    public uint PD_D3Latency;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
    public DEVICE_POWER_STATE[] PD_PowerStateMapping;
    public SYSTEM_POWER_STATE PD_DeepestSystemWake;
}
DllImports

[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetupDiGetDeviceRegistryPropertyA(
        IntPtr DeviceInfoSet,
        ref SP_DEVINFO_DATA DeviceInfoData,
        uint Property,
        out RegistryDataType PropertyRegDataType,
        byte[] PropertyBuffer,
        //ref CM_POWER_DATA PropertyBuffer,
        uint PropertyBufferSize,
        out UInt32 RequiredSize
    );


    [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SetupDiGetClassDevsA(
                                          ref Guid ClassGuid,
                                          [MarshalAs(UnmanagedType.LPTStr)] string Enumerator,
                                          IntPtr hwndParent,
                                          uint Flags
                                         );


    [DllImport("setupapi.dll", SetLastError=true)]
    private static extern bool SetupDiEnumDeviceInfo(
                                            IntPtr DeviceInfoSet, 
                                            uint MemberIndex, 
                                            ref SP_DEVINFO_DATA DeviceInfoData
                                            );
各种各样的功能,使检索更华丽,更易于使用。主要的一个,也是我上面描述的一个,是第一个——GetInfoWithSetupDi。您需要将GUID\u DeviceInterface\u USB\u设备传递给它

    /// <summary>
    /// Gets information about devices in the device class including power state.
    /// </summary>
    /// <param name="classGuid">The GUID of the class in which to get information about devices from.</param>
    /// <returns></returns>
    public static List<DeviceInfo> GetInfoWithSetupDi(Guid classGuid) {
        List<DeviceInfo> deviceInfos = new List<DeviceInfo>();

        IntPtr deviceInfoSet = SetupDiGetClassDevsA(ref classGuid, null, IntPtr.Zero, 0x00000002 | 0x00000010);           

        uint index = 0;
        int error = 0;

        while (error == 0) {
            DeviceInfo curDevice = new DeviceInfo {
                //Initializing SP_DEVINFO_DATA to be passed to SetupDiEnumDeviceInfo.
                deviceInfoData = new SP_DEVINFO_DATA {
                    cbSize = 28
                }
            };

            //Retrieves the information about the specified device.
            bool success = SetupDiEnumDeviceInfo(deviceInfoSet, index, ref curDevice.deviceInfoData);
            index++;
            error = Marshal.GetLastWin32Error();

            if (error == 259)
                { break; }

            if (!success)
                { throw new Exception("Native method call error: " + error.ToString()); }

            //Only add device after it was at least successfully retrieved.
            deviceInfos.Add(curDevice);

            //Retrieving individual information.
            RegistryData localGetData(uint property) => GetData(deviceInfoSet, curDevice.deviceInfoData, property);

            curDevice.hardwareId = (string[]) localGetData(SPDRP_HARDWAREID).parsed;
            try {
                curDevice.description = (string)localGetData(SPDRP_DEVICEDESC).parsed;
            } catch {
                curDevice.description = "Description not set.";
            }               
            curDevice.cmPowerData = MarshallingUtils.FromBytes<CM_POWER_DATA>(
                localGetData(SPDRP_DEVICE_POWER_DATA).data
            );
        }

        return deviceInfos;           
    }


    /// <summary>
    /// Gets the required size in bytes for the given property.
    /// </summary>
    /// <param name="deviceInfoSet">A handle to the set of devices.</param>
    /// <param name="property">The property for which the get the required size.</param>
    private static uint GetRequiredSize(IntPtr deviceInfoSet, uint Property) {
        SP_DEVINFO_DATA deviceInfoData = new SP_DEVINFO_DATA {
            cbSize = 28
        };

        ThrowErrorIfNotSuccessful(SetupDiEnumDeviceInfo(deviceInfoSet, 0, ref deviceInfoData));

        return GetRequiredSize(deviceInfoSet, Property, deviceInfoData);
    }


    /// <summary>
    /// Gets the required size in bytes for the given property.
    /// </summary>
    /// <param name="deviceInfoSet">A handle to the set of devices.</param>
    /// <param name="property">The property for which the get the required size.</param>
    /// <param name="deviceInfoData">Info of a device.</param>
    /// <returns></returns>
    private static uint GetRequiredSize(IntPtr deviceInfoSet, uint property, SP_DEVINFO_DATA deviceInfoData) {
        ThrowErrorIfNotSuccessful(
            SetupDiGetDeviceRegistryPropertyA(
                deviceInfoSet,
                ref deviceInfoData,
                property,
                out RegistryDataType type,
                new byte[1000],
                1000,
                out uint size)
            );

        return size;
    }


    /// <summary>
    /// Gets the property using SetupDi of the device on the given index in the given device class.
    /// </summary>
    /// <param name="classGuid">The GUID of the device class.</param>
    /// <param name="index">The index of the device.</param>
    /// <param name="property">The property to retrieve.</param>
    /// <returns></returns>
    public static RegistryData GetData(Guid classGuid, uint index, uint property) {
        IntPtr deviceInfoSet = SetupDiGetClassDevsA(ref classGuid, null, IntPtr.Zero, 0x00000002 | 0x00000010);

        SP_DEVINFO_DATA deviceInfoData = new SP_DEVINFO_DATA {
            cbSize = 28
        };

        ThrowErrorIfNotSuccessful(SetupDiEnumDeviceInfo(deviceInfoSet, index, ref deviceInfoData));

        return GetData(deviceInfoSet, deviceInfoData, property);
    }


    /// <summary>
    /// Gets the specified property using SetupDi of the device described in deviceInfoData in the given device info set.
    /// The size is retrieved automatically.
    /// </summary>
    /// <param name="deviceInfoSet">A handle to the device info set.</param>
    /// <param name="deviceInfoData">Description of the device.</param>
    /// <param name="property">The property to retrieve.</param>
    /// <returns></returns>
    public static RegistryData GetData(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, uint property) {
        uint size = GetRequiredSize(deviceInfoSet, property, deviceInfoData);

        return GetData(deviceInfoSet, deviceInfoData, property, size);
    }


    /// <summary>
    /// Gets the specified property using SetupDi of the device described in deviceInfoData in the given device info set.
    /// </summary>
    /// <param name="deviceInfoSet">A handle to the device info set.</param>
    /// <param name="deviceInfoData">Description of the device.</param>
    /// <param name="property">The property to retrieve.</param>
    /// <returns></returns>
    public static RegistryData GetData(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, uint property, uint size) {
        byte[] data = new byte[size];

        ThrowErrorIfNotSuccessful(
            SetupDiGetDeviceRegistryPropertyA(
                deviceInfoSet,
                ref deviceInfoData,
                property,
                out RegistryDataType type,
                data,
                size,
                out uint dummysize)
            );

        return new RegistryData(type, data);
    }

    /// <summary>
    /// Method used to wrap native DLL calls. Throws the last system error when the call is unsuccessful.
    /// </summary>
    /// <param name="success">Return value of the native method. ( Usually used as ThrowErrorIfNotSuccessful(MethodCall()); )</param>
    private static void ThrowErrorIfNotSuccessful(bool success) {
        if (!success) {
            throw new Exception("Native method call error: " + Marshal.GetLastWin32Error().ToString());
        }
    }
还有一个用来保存信息的类

public class DeviceInfo {
    public SP_DEVINFO_DATA deviceInfoData;
    public string[] hardwareId;
    public string description;
    public CM_POWER_DATA cmPowerData;
}

花2分钟找出答案。它在文件中,方法名为AcquireDevicePowerState,它从registry@Franck我仍然无法找出所需数据的来源..您不能读取文件吗?实际上有两行代码,一行从注册表读取,另一行有一个开关返回一个或另一个值。它使用SetupDiGetDeviceRegistryProperty从注册表中读取一个普通API方法和。只要传递正确的参数,就可以开始了。
    /// <summary>
    /// Gets information about devices in the device class including power state.
    /// </summary>
    /// <param name="classGuid">The GUID of the class in which to get information about devices from.</param>
    /// <returns></returns>
    public static List<DeviceInfo> GetInfoWithSetupDi(Guid classGuid) {
        List<DeviceInfo> deviceInfos = new List<DeviceInfo>();

        IntPtr deviceInfoSet = SetupDiGetClassDevsA(ref classGuid, null, IntPtr.Zero, 0x00000002 | 0x00000010);           

        uint index = 0;
        int error = 0;

        while (error == 0) {
            DeviceInfo curDevice = new DeviceInfo {
                //Initializing SP_DEVINFO_DATA to be passed to SetupDiEnumDeviceInfo.
                deviceInfoData = new SP_DEVINFO_DATA {
                    cbSize = 28
                }
            };

            //Retrieves the information about the specified device.
            bool success = SetupDiEnumDeviceInfo(deviceInfoSet, index, ref curDevice.deviceInfoData);
            index++;
            error = Marshal.GetLastWin32Error();

            if (error == 259)
                { break; }

            if (!success)
                { throw new Exception("Native method call error: " + error.ToString()); }

            //Only add device after it was at least successfully retrieved.
            deviceInfos.Add(curDevice);

            //Retrieving individual information.
            RegistryData localGetData(uint property) => GetData(deviceInfoSet, curDevice.deviceInfoData, property);

            curDevice.hardwareId = (string[]) localGetData(SPDRP_HARDWAREID).parsed;
            try {
                curDevice.description = (string)localGetData(SPDRP_DEVICEDESC).parsed;
            } catch {
                curDevice.description = "Description not set.";
            }               
            curDevice.cmPowerData = MarshallingUtils.FromBytes<CM_POWER_DATA>(
                localGetData(SPDRP_DEVICE_POWER_DATA).data
            );
        }

        return deviceInfos;           
    }


    /// <summary>
    /// Gets the required size in bytes for the given property.
    /// </summary>
    /// <param name="deviceInfoSet">A handle to the set of devices.</param>
    /// <param name="property">The property for which the get the required size.</param>
    private static uint GetRequiredSize(IntPtr deviceInfoSet, uint Property) {
        SP_DEVINFO_DATA deviceInfoData = new SP_DEVINFO_DATA {
            cbSize = 28
        };

        ThrowErrorIfNotSuccessful(SetupDiEnumDeviceInfo(deviceInfoSet, 0, ref deviceInfoData));

        return GetRequiredSize(deviceInfoSet, Property, deviceInfoData);
    }


    /// <summary>
    /// Gets the required size in bytes for the given property.
    /// </summary>
    /// <param name="deviceInfoSet">A handle to the set of devices.</param>
    /// <param name="property">The property for which the get the required size.</param>
    /// <param name="deviceInfoData">Info of a device.</param>
    /// <returns></returns>
    private static uint GetRequiredSize(IntPtr deviceInfoSet, uint property, SP_DEVINFO_DATA deviceInfoData) {
        ThrowErrorIfNotSuccessful(
            SetupDiGetDeviceRegistryPropertyA(
                deviceInfoSet,
                ref deviceInfoData,
                property,
                out RegistryDataType type,
                new byte[1000],
                1000,
                out uint size)
            );

        return size;
    }


    /// <summary>
    /// Gets the property using SetupDi of the device on the given index in the given device class.
    /// </summary>
    /// <param name="classGuid">The GUID of the device class.</param>
    /// <param name="index">The index of the device.</param>
    /// <param name="property">The property to retrieve.</param>
    /// <returns></returns>
    public static RegistryData GetData(Guid classGuid, uint index, uint property) {
        IntPtr deviceInfoSet = SetupDiGetClassDevsA(ref classGuid, null, IntPtr.Zero, 0x00000002 | 0x00000010);

        SP_DEVINFO_DATA deviceInfoData = new SP_DEVINFO_DATA {
            cbSize = 28
        };

        ThrowErrorIfNotSuccessful(SetupDiEnumDeviceInfo(deviceInfoSet, index, ref deviceInfoData));

        return GetData(deviceInfoSet, deviceInfoData, property);
    }


    /// <summary>
    /// Gets the specified property using SetupDi of the device described in deviceInfoData in the given device info set.
    /// The size is retrieved automatically.
    /// </summary>
    /// <param name="deviceInfoSet">A handle to the device info set.</param>
    /// <param name="deviceInfoData">Description of the device.</param>
    /// <param name="property">The property to retrieve.</param>
    /// <returns></returns>
    public static RegistryData GetData(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, uint property) {
        uint size = GetRequiredSize(deviceInfoSet, property, deviceInfoData);

        return GetData(deviceInfoSet, deviceInfoData, property, size);
    }


    /// <summary>
    /// Gets the specified property using SetupDi of the device described in deviceInfoData in the given device info set.
    /// </summary>
    /// <param name="deviceInfoSet">A handle to the device info set.</param>
    /// <param name="deviceInfoData">Description of the device.</param>
    /// <param name="property">The property to retrieve.</param>
    /// <returns></returns>
    public static RegistryData GetData(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, uint property, uint size) {
        byte[] data = new byte[size];

        ThrowErrorIfNotSuccessful(
            SetupDiGetDeviceRegistryPropertyA(
                deviceInfoSet,
                ref deviceInfoData,
                property,
                out RegistryDataType type,
                data,
                size,
                out uint dummysize)
            );

        return new RegistryData(type, data);
    }

    /// <summary>
    /// Method used to wrap native DLL calls. Throws the last system error when the call is unsuccessful.
    /// </summary>
    /// <param name="success">Return value of the native method. ( Usually used as ThrowErrorIfNotSuccessful(MethodCall()); )</param>
    private static void ThrowErrorIfNotSuccessful(bool success) {
        if (!success) {
            throw new Exception("Native method call error: " + Marshal.GetLastWin32Error().ToString());
        }
    }
public static class MarshallingUtils {
    public static byte[] GetBytes<T>(T str) where T : struct {
        int size = Marshal.SizeOf(str);
        byte[] arr = new byte[size];

        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(str, ptr, true);
        Marshal.Copy(ptr, arr, 0, size);
        Marshal.FreeHGlobal(ptr);
        return arr;
    }

    public static T FromBytes<T>(byte[] arr) where T : struct {
        T str = new T();

        int size = Marshal.SizeOf(str);
        IntPtr ptr = Marshal.AllocHGlobal(size);

        Marshal.Copy(arr, 0, ptr, size);

        str = (T)Marshal.PtrToStructure(ptr, str.GetType());
        Marshal.FreeHGlobal(ptr);

        return str;
    }
}
public struct RegistryData {
    public readonly RegistryDataType type;
    public readonly byte[] data;
    public readonly object parsed;

    public RegistryData(RegistryDataType type, byte[] data) {
        this.type = type;
        this.data = data;
        this.parsed = ParseData(type, data);
    }


    public static string ParseString(byte[] data) {
        string s = "";
        foreach (byte b in data) {
            if (b == 0) {
                break;
            }
            s += (char)b;
        }
        return s;
    }


    public static string[] ParseMultiString(byte[] data) {
        List<string> list = new List<string>();
        string current = "";
        bool terminator = false;

        foreach (byte b in data) {
            if (b == 0) {
                if (terminator) {
                    break;
                }
                else {
                    terminator = true;
                    //Start a new string.
                    list.Add(current);
                    current = "";
                }
            }
            else {
                terminator = false;
                current += (char)b;
            }
        }
        return list.ToArray();
    }


    private static object ParseData(RegistryDataType type, byte[] data) {
        switch (type) {
            case RegistryDataType.REG_SZ:
                return (object)ParseString(data);

            case RegistryDataType.REG_MULTI_SZ:
                return (object)ParseMultiString(data);

            default: return null;
        }
    }


    public override string ToString() {
        switch (type) {
            case RegistryDataType.REG_SZ: return (string)parsed;
            case RegistryDataType.REG_MULTI_SZ: return String.Join(";", (List<string>)parsed);
            default: return null;
        }
    }
}
public enum RegistryDataType {
    REG_NONE = (0),   // No value type
    REG_SZ = (1),   // Unicode nul terminated string
    REG_EXPAND_SZ = (2),   // Unicode nul terminated string
                           // = (with environment variable references)
    REG_BINARY = (3),   // Free form binary
                        //REG_DWORD = (4),   // 32-bit number
    REG_DWORD_LITTLE_ENDIAN = (4),   // 32-bit number = (same as REG_DWORD)
    REG_DWORD_BIG_ENDIAN = (5),   // 32-bit number
    REG_LINK = (6),   // Symbolic Link = (unicode)
    REG_MULTI_SZ = (7),   // Multiple Unicode strings
    REG_RESOURCE_LIST = (8),   // Resource list in the resource map
    REG_FULL_RESOURCE_DESCRIPTOR = (9),  // Resource list in the hardware description
    REG_RESOURCE_REQUIREMENTS_LIST = (10),
    //REG_QWORD = (11),  // 64-bit number
    REG_QWORD_LITTLE_ENDIAN = (11),  // 64-bit number = (same as REG_QWORD)
}
public class DeviceInfo {
    public SP_DEVINFO_DATA deviceInfoData;
    public string[] hardwareId;
    public string description;
    public CM_POWER_DATA cmPowerData;
}