SetupDiGetDeviceRegistryProperty因ERROR_INVALID_DATA而失败

时间:2014-06-22 22:19:25

标签: c# winapi interop

我试图获取显示名称,因为它们出现在"屏幕分辨率"窗口(Win8.1 x64)。

首先我尝试了EnumDisplayDevices

var deviceInfo = new DISPLAY_DEVICEW();
uint i = 0;
while (true)
{
    if (!NativeMethods.EnumDisplayDevices(null, i++, deviceInfo, 0))
    {
        break;
    }
    PrintDeviceInfo(deviceInfo);

    NativeMethods.EnumDisplayDevices(deviceInfo.DeviceName, 0, deviceInfo, EDD_GET_DEVICE_INTERFACE_NAME);
    PrintDeviceInfo(deviceInfo);
}

第二次调用EnumDisplayDevices(带EDD_GET_DEVICE_INTERFACE_NAME)确实产生了显示名称,因为它显示在我的主显示屏上(在DISPLAY_DEVICEW.DeviceString中)。但是对于我的HDMI连接电视,该字段包含通用PnP监视器,而不是 SAMSUNG ,因为它出现在"屏幕分辨率"窗口。也许它通过HDMI连接的事实在某种程度上是相关的?

然后我尝试了安装API

var hdevinfo = NativeMethods.SetupDiGetClassDevs(ref GUID_DEVINTERFACE_MONITOR, null, IntPtr.Zero, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (hdevinfo == INVALID_HANDLE_VALUE) return;
var spDeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
uint memberIndex = 0;
while (true)
{
    bool success = NativeMethods.SetupDiEnumDeviceInterfaces(hdevinfo, null, ref GUID_DEVINTERFACE_MONITOR, memberIndex++, spDeviceInterfaceData);
    if (!success)
    {
        break;
    }
    PrintInterfaceData(spDeviceInterfaceData);

    uint requiredSize;
    var devInfoData = new SP_DEVINFO_DATA();

    NativeMethods.SetupDiGetDeviceInterfaceDetail(hdevinfo, spDeviceInterfaceData, IntPtr.Zero, 0, out requiredSize, devInfoData);
    PrintDevInfoData(devInfoData);

    var interfaceDetail = Marshal.AllocHGlobal((int)requiredSize);
    var cbSize = (Marshal.SizeOf(typeof(uint)) + Marshal.SystemDefaultCharSize);
    Marshal.WriteInt32(interfaceDetail, 0, cbSize);
    NativeMethods.SetupDiGetDeviceInterfaceDetail(hdevinfo, spDeviceInterfaceData, interfaceDetail, requiredSize, IntPtr.Zero, null);
    var dynamicType = GetDeviceInterfaceDetailDataType(requiredSize);
    var interfaceDetailStruct = Marshal.PtrToStructure(interfaceDetail, dynamicType);
    Marshal.FreeHGlobal(interfaceDetail);
    PrintInterfaceDetail(interfaceDetailStruct);

    uint propertyRegDataType;
    NativeMethods.SetupDiGetDeviceRegistryProperty(hdevinfo, devInfoData, SPDRP_FRIENDLYNAME, out propertyRegDataType, null, 0, out requiredSize);
    Console.WriteLine(Marshal.GetLastWin32Error());
}

查看来自不同方法的返回值,一切似乎都有效,但最后一次调用SetupDiGetDeviceRegistryProperty失败了ERROR_INVALID_DATA(也就是说,该方法返回false并且GetLastWin32Error得到13)。根据{{​​3}},这意味着设备不存在所请求的属性,或者属性数据无效

我实际上循环了所有可能的SPDRP值(0-24)并且它们都导致相同的失败。只是为了澄清,我希望方法失败,但是设置ERROR_INSUFFICIENT_BUFFER并设置requiredSize(后者只保留其先前的值,因为非托管代码不会更改它)。

这里是SetupDiGetDeviceRegistryProperty的签名(所有其他方法按预期工作):

[StructLayout(LayoutKind.Sequential)]
public class SP_DEVINFO_DATA
{
    public uint cbSize = (uint) Marshal.SizeOf(typeof (SP_DEVINFO_DATA));
    public Guid ClassGuid;
    public uint DevInst;
    public IntPtr Reserved;
}
[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SetupDiGetDeviceRegistryProperty(
    IntPtr deviceInfoSet,
    SP_DEVINFO_DATA deviceInfoData, 
    uint property, 
    out uint propertyRegDataType, 
    byte[] propertyBuffer, 
    uint propertyBufferSize, 
    out uint requiredSize);

1 个答案:

答案 0 :(得分:-1)

看起来我正在寻找的是impossible

  

没有受支持的方式来计算您提到的ID   以编程方式。从来没有为设计目标提供方法   用于标记与屏幕具有相同ID的监视器的应用程序   分辨率控制面板使用