C# 如何从DEV_BROADCAST_DEVICEINTERFACE和设备实例ID获取友好的设备名称

C# 如何从DEV_BROADCAST_DEVICEINTERFACE和设备实例ID获取友好的设备名称,c#,winapi,guid,device-instance-id,C#,Winapi,Guid,Device Instance Id,我已向注册了一个窗口,可以成功接收消息。但是,返回的结构中的dbcc_name字段始终为空。我拥有的结构定义如下: [StructLayout(LayoutKind.Sequential)] public struct DEV_BROADCAST_DEVICEINTERFACE { public int dbcc_size; public int dbcc_devicetype; public int dbcc_reserved; public Guid dbcc

我已向注册了一个窗口,可以成功接收消息。但是,返回的结构中的
dbcc_name
字段始终为空。我拥有的结构定义如下:

[StructLayout(LayoutKind.Sequential)]
public struct DEV_BROADCAST_DEVICEINTERFACE
{
    public int dbcc_size;
    public int dbcc_devicetype;
    public int dbcc_reserved;
    public Guid dbcc_classguid;
    [MarshalAs(UnmanagedType.LPStr)]
    public string dbcc_name;
}
我在消息的LPRAM上使用了
Marshal.PtrToStructure

这样行吗

或者更好。。。是否有其他方法在连接时获取设备名称

编辑(2010年5月2日20:56GMT):

我通过以下操作了解了如何填充dbcc_name字段:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DEV_BROADCAST_DEVICEINTERFACE
{
    public int dbcc_size;
    public int dbcc_devicetype;
    public int dbcc_reserved;
    public Guid dbcc_classguid;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
    public string dbcc_name;
}
但是我仍然需要一种从int-dbcc_名称中获取“友好”名称的方法。如下所示:

\?\USB#参考05AC和PID(U 1294和MI#00#0#{6bdd1fc6-810f-11d0-bec7-08002be2092f}


我真的只想说“苹果iPhone”(这就是本例中的设备)。

你可能需要稍微改变一下

[StructLayout(LayoutKind.Sequential)] public struct DEV_BROADCAST_DEVICEINTERFACE { public int dbcc_size; public int dbcc_devicetype; public int dbcc_reserved; public Guid dbcc_classguid; [MarshalAs(UnmanagedType.LPStr)] public StringBuilder dbcc_name; } 然后传入该结构,应该填充
dbcc\u name
的值

编辑:窃笑者的评论之后……我以另一种方式思考了这个问题

public struct DEV_BROADCAST_DEVICEINTERFACE { public int dbcc_size; public int dbcc_devicetype; public int dbcc_reserved; public Guid dbcc_classguid; [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 255, ArraySubType = System.Runtime.InteropServices.UnmanagedType.LPArray)] public string dbcc_name; } 公共结构开发广播设备接口 { 公共int dbcc_尺寸; 公共int dbcc_设备类型; 公共int dbcc_保留; 公共Guid dbcc_类Guid; [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray,SizeConst=255,ArraySubType=System.Runtime.InteropServices.UnmanagedType.LPArray)] 公共字符串dbcc_名称; } 将
dbcc_size
设置为255,然后从那里开始


编辑#2:这很有趣……我现在不太确定,我发现这篇文章在上使用了
RegisterDeviceNotification
,它使用了一种不同的RegisterDeviceNotification方法,即将结构编组为
IntPtr
,并用于调用API…

好,如上所述,我发现了如何正确填充dbcc_名称。我发现这是获取设备名称的最简单方法:

private static string GetDeviceName(DEV_BROADCAST_DEVICEINTERFACE dvi)
{
    string[] Parts = dvi.dbcc_name.Split('#');
    if (Parts.Length >= 3)
    {
        string DevType = Parts[0].Substring(Parts[0].IndexOf(@"?\") + 2);
        string DeviceInstanceId = Parts[1];
        string DeviceUniqueID = Parts[2];
        string RegPath = @"SYSTEM\CurrentControlSet\Enum\" + DevType + "\\" + DeviceInstanceId + "\\" + DeviceUniqueID;
        RegistryKey key = Registry.LocalMachine.OpenSubKey(RegPath);
        if (key != null)
        {
            object result = key.GetValue("FriendlyName");
            if (result != null)
                return result.ToString();
            result = key.GetValue("DeviceDesc");
            if (result != null)
                return result.ToString();
        }
    }
    return String.Empty;
}

这些信息也可以通过更正式的方式获得。将
dbcc_name
传递到
setupdIOpendenDeviceInterface
并使用
SetupDiGetDeviceRegistryProperty
传入
SPDRP_FRIENDLYNAME
获取友好名称

这里有一些Delphi代码可以实现这一点。(对不起,你必须独立翻译成C。)

函数convertdbcnametofriendlyname(adeviceinterfacedbcname:string):string;
变量
DeviceInfo句柄:HDEVINFO;
DeviceInfo数据:SP_DeviceInfo_数据;
设备接口数据:SP_设备_接口_数据;
deviceInstanceId:字符串;
成员索引:基数;
开始
结果:='';
//创建一个新的空“设备信息集”
DeviceInfo句柄:=SetupDiCreateDeviceInfo列表(零,0);
如果DeviceInfo句柄无效\u句柄\u值,则
开始
尝试
//将“aDeviceInterfaceDbccName”添加到设备信息集中
FillChar(deviceInterfaceData),SizeOf(deviceInterfaceData),0;
deviceInterfaceData.cbSize:=SizeOf(deviceInterfaceData);
如果SetupDiOpenDeviceInterface(DeviceInfo句柄,PChar(AdeviceInterfacedBCName),0,@deviceInterfaceData),则
开始
尝试
//迭代设备信息集
//(虽然我只希望它包含一项)
memberIndex:=0;
尽管如此
开始
//获取与下一个memberIndex对应的设备信息
FillChar(DeviceInfo数据),SizeOf(DeviceInfo数据),0;
DeviceInfo.cbSize:=SizeOf(DeviceInfo数据);
如果未设置DienumDeviceInfo(DeviceInfo句柄、memberIndex、DeviceInfo数据),则
开始
//当SetupDiEnumDeviceInfo返回false时,枚举数将耗尽
打破
结束
其他的
开始
公司(会员索引),;
结束;
//获取设备信息的友好名称
如果TryGetDeviceFriendlyName(DeviceInfo句柄、DeviceInfo数据、{out}friendlyName),则
开始
结果:=friendlyName;
打破
结束;
结束;
最后
SetupDiDeletedDeviceInterfaceData(DeviceInfo句柄、deviceInterfaceData);
结束;
结束;
最后
SetupDiDestroyDeviceInfo列表(DeviceInfo句柄);
结束;
结束;
结束;
函数TryGetDeviceFriendlyName(
var AdeviceInfo句柄:HDEVINFO;
var AdeviceInfo数据:SP_DEVINFO_数据;
out-aFriendlyName:string):布尔值;
变量
valueBuffer:字节数组;
regProperty:红衣主教;
propertyRegDataType:DWord;
friendlyNameByteSize:红衣主教;
成功:布尔;
开始
aFriendlyName:='';
结果:=假;
//获取友好设备名称的大小
regProperty:=SPDRP_FRIENDLYNAME;
friendlyNameByteSize:=0;
SetupDiGetDeviceRegistryProperty(
AdeviceInfo句柄,//句柄到设备信息集
AdeviceInfo数据,//指向SP_DEVINFO_数据结构的指针
regProperty,//要检索的属性
propertyRegDataType,//指向接收属性数据类型的变量的指针
nil,//指向接收属性的PropertyBuffer的指针
0,//PropertyBuffer缓冲区的大小(以字节为单位)。
friendlyNameByteSize);//指向接收所需大小的PropertyBuffer的变量的指针
//为友好设备名准备缓冲区(加上空终止符的空间)
SetLength(valueBuffer,friendlyNameByteSize+sizeof(char));
成功:=SetupDiGetDeviceRegistrProperty(
AdeviceHandle,
AdeviceInfo数据,
regProperty,
propertyRegDataType,
@valueBuffer[0],
friendlyNameByteSize,
friendlyNameByteSize);
如果成功的话
开始
//确保仅使用“friendlyNameByteSize”字节。
//确保字符串以null结尾。
PChar(@valueBuffer[friendlyNameByteSize])^:=char(0);
private static string GetDeviceName(DEV_BROADCAST_DEVICEINTERFACE dvi)
{
    string[] Parts = dvi.dbcc_name.Split('#');
    if (Parts.Length >= 3)
    {
        string DevType = Parts[0].Substring(Parts[0].IndexOf(@"?\") + 2);
        string DeviceInstanceId = Parts[1];
        string DeviceUniqueID = Parts[2];
        string RegPath = @"SYSTEM\CurrentControlSet\Enum\" + DevType + "\\" + DeviceInstanceId + "\\" + DeviceUniqueID;
        RegistryKey key = Registry.LocalMachine.OpenSubKey(RegPath);
        if (key != null)
        {
            object result = key.GetValue("FriendlyName");
            if (result != null)
                return result.ToString();
            result = key.GetValue("DeviceDesc");
            if (result != null)
                return result.ToString();
        }
    }
    return String.Empty;
}
function ConvertDbccNameToFriendlyName(aDeviceInterfaceDbccName : string) : string;
var
  deviceInfoHandle : HDEVINFO;
  deviceInfoData : SP_DEVINFO_DATA;
  deviceInterfaceData : SP_DEVICE_INTERFACE_DATA;
  deviceInstanceId : string;
  memberIndex : Cardinal;
begin
  result := '';

  // Create a new empty "device info set"
  deviceInfoHandle := SetupDiCreateDeviceInfoList(nil, 0);
  if deviceInfoHandle <> INVALID_HANDLE_VALUE then
  begin
    try
      // Add "aDeviceInterfaceDbccName" to the device info set
      FillChar(deviceInterfaceData, SizeOf(deviceInterfaceData), 0);
      deviceInterfaceData.cbSize := SizeOf(deviceInterfaceData);
      if SetupDiOpenDeviceInterface(deviceInfoHandle, PChar(aDeviceInterfaceDbccName),     0, @deviceInterfaceData) then
      begin
        try
          // iterate over the device info set
          // (though I only expect it to contain one item)
          memberIndex := 0;
          while true do
          begin
            // get device info that corresponds to the next memberIndex
            FillChar(deviceInfoData, SizeOf(deviceInfoData), 0);
            deviceInfoData.cbSize := SizeOf(deviceInfoData);
            if not SetupDiEnumDeviceInfo(deviceInfoHandle, memberIndex, deviceInfoData) then
            begin
              // The enumerator is exhausted when SetupDiEnumDeviceInfo returns false
              break;
            end
            else
            begin
              Inc(memberIndex);
            end;

            // Get the friendly name for that device info
            if TryGetDeviceFriendlyName(deviceInfoHandle, deviceInfoData, {out} friendlyName) then
            begin
              result := friendlyName;
              break;
            end;
          end;
        finally
          SetupDiDeleteDeviceInterfaceData(deviceInfoHandle, deviceInterfaceData);
        end;
      end;
    finally
      SetupDiDestroyDeviceInfoList(deviceInfoHandle);
    end;
  end;
end;

function TryGetDeviceFriendlyName(
  var aDeviceInfoHandle : HDEVINFO;
  var aDeviceInfoData : SP_DEVINFO_DATA;
  out aFriendlyName : string) : boolean;
var
  valueBuffer : array of byte;
  regProperty : Cardinal;
  propertyRegDataType : DWord;
  friendlyNameByteSize : Cardinal;
  success : boolean;
begin
  aFriendlyName := '';
  result := false;

  // Get the size of the friendly device name
  regProperty := SPDRP_FRIENDLYNAME;
  friendlyNameByteSize := 0;
  SetupDiGetDeviceRegistryProperty(
    aDeviceInfoHandle,     // handle to device information set
    aDeviceInfoData,       // pointer to SP_DEVINFO_DATA structure
    regProperty,           // property to be retrieved
    propertyRegDataType,   // pointer to variable that receives the data type of the property
    nil,                   // pointer to PropertyBuffer that receives the property
    0,                     // size, in bytes, of the PropertyBuffer buffer.
    friendlyNameByteSize); // pointer to variable that receives the required size of PropertyBuffer

  // Prepare a buffer for the friendly device name (plus space for a null terminator)
  SetLength(valueBuffer, friendlyNameByteSize + sizeof(char));

  success := SetupDiGetDeviceRegistryProperty(
    aDeviceInfoHandle,
    aDeviceInfoData,
    regProperty,
    propertyRegDataType,
    @valueBuffer[0],
    friendlyNameByteSize,
    friendlyNameByteSize);

  if success then
  begin
    // Ensure that only 'friendlyNameByteSize' bytes are used.
    // Ensure that the string is null-terminated.
    PChar(@valueBuffer[friendlyNameByteSize])^ := char(0);

    // Get the returned value as a string
    aFriendlyName := StrPas(PChar(@valueBuffer[0]));
  end;

  result := success;
end;