Как получить понятное имя устройства из DEV_BROADCAST_DEVICEINTERFACE и ID экземпляра устройства - PullRequest
11 голосов
/ 05 февраля 2010

Я зарегистрировал окно с RegisterDeviceNotification и могу успешно получать DEV_BROADCAST_DEVICEINTERFACE сообщения. Однако поле 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;
}

И я использую Marshal.PtrToStructure для LParam сообщения WM_DEVICECHANGE .

Должно ли это работать?

Или даже лучше ... Есть ли альтернативный способ получить имя устройства при подключении?

РЕДАКТИРОВАТЬ (02/05/2010 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_name. Это выглядит следующим образом:

\? \ USB # VID_05AC & PID_1294 ​​& MI_00 # 0 # {6bdd1fc6-810f-11d0-BEC7-08002BE2092F}

И я действительно хочу сказать «Apple iPhone» (в данном случае это устройство).

Ответы [ 3 ]

10 голосов
/ 08 февраля 2010

Ну, как уже было сказано выше, я узнал, как получить dbcc_name для правильного заполнения. Я обнаружил, что это был самый простой способ получить имя устройства:

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;
}
2 голосов
/ 11 декабря 2013

Эта информация также может быть получена более формально через SetupAPI . Передайте dbcc_name на SetupDiOpenDeviceInterface и получите понятное имя с SetupDiGetDeviceRegistryProperty, передавая SPDRP_FRIENDLYNAME.

Вот некоторый код Delphi, который сделает это. (Извините, вам придется самостоятельно переводить на C #).

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;

Наконец ... если вам нужен способ уникальной идентификации устройства USB (не то, что вы просили, но обычно это также необходимо), посмотрите на SetupDiGetDeviceInstanceId.

0 голосов
/ 05 февраля 2010

Вероятно, вам нужно немного изменить это

[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_size на 255 и создайте StringBuilder, как показано ниже:

DEV_BROADCAST_DEVICEINTERFACE dbd = new DEV_BROADCAST_DEVICEINTERFACE;
dbd.dbcc_size = 255;
dbd.dbcc_name = new StringBuilder(dbd.dbcc_size);

Затем передайте эту структуру, значение dbcc_name должно быть заполнено.

Редактировать: после snicker * Комментарий 1015 * ... Я думал об этом по-другому ...

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;
}

Установите dbcc_size на 255 и возьмите его оттуда ...

Редактировать # 2: Это интересно ... Я не уверен, я нашел эту статью, которая использует RegisterDeviceNotification для Codeproject и использует другой способ RegisterDeviceNotification в том, что структура маршалируется в IntPtr и используется для вызова API ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...