Cómo conseguir amable nombre de dispositivo de DEV_BROADCAST_DEVICEINTERFACE y el IDENTIFICADOR de Instancia de Dispositivo

He registrado una ventana con RegisterDeviceNotification y capaz de recibir DEV_BROADCAST_DEVICEINTERFACE mensajes. Sin embargo, la dbcc_name campo en el devuelve struct siempre está vacío. La estructura que tengo es definido como tal:

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

Y estoy usando Marshal.PtrToStructure en el LParam de la WM_DEVICECHANGE mensaje.

Se debe trabajar?

O mejor aún… ¿hay una forma alternativa de obtener el nombre de un dispositivo en la conexión?

EDITAR (02/05/2010 20:56GMT):

He encontrado la manera de obtener la dbcc_name campo a rellenar por hacer esto:

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

pero aún necesita una manera de conseguir un nombre descriptivo de lo que es de tipo int dbcc_name. El siguiente aspecto:

\?\USB#VID_05AC&PID_1294&MI_00#0#{6bdd1fc6-810f-11d0-bec7-08002be2092f}

Y en realidad, yo sólo quiero que diga «el iPhone de Apple» (que es lo que el dispositivo es en este caso).

OriginalEl autor snicker | 2010-02-05

3 Kommentare

  1. 9

    Bien, como se señaló anteriormente he encontrado la manera de obtener dbcc_name para rellenar correctamente. Me pareció que esta era la manera más fácil para obtener el nombre del dispositivo:

    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;
    }
    GRACIAS!! He estado tratando de hacer la misma cosa.

    OriginalEl autor snicker

  2. 2

    Esta información también puede ser adquirido de manera más formal a través de SetupAPI. Pasar dbcc_name a SetupDiOpenDeviceInterface y obtener el nombre descriptivo con SetupDiGetDeviceRegistryProperty pasando en SPDRP_FRIENDLYNAME.

    Aquí un poco de código de Delphi que lo va a hacer. (Lo siento, vas a tener que traducir a C# de forma independiente).

    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;

    Por último… si usted necesita una manera para identificar un dispositivo USB (no lo que usted pidió, pero comúnmente esto también es necesario), buscar en SetupDiGetDeviceInstanceId.

    Un poco tarde para responder. Una respuesta ya ha sido aceptado con siete votos.
    Nunca es demasiado tarde para una mejor respuesta =) (yo prefiero formal de la API a través de manual de análisis de cadenas cualquier día)
    si usted puede encontrar a alguien para traducir a C#, voy a cambiar el aceptado respuesta. Esto sería absolutamente preferible la solución, el código que he publicado anteriormente es maloliente y se basa en algo que siempre está en la misma ubicación en el registro (o el registro existente en todos), un winapi es la mejor solución
    Así es esto en C#?

    OriginalEl autor Nathan Schubkegel

  3. 0

    Es probable que usted tendrá que cambiar esta ligeramente

    [StructLayout(LayoutKind.Secuencial)] 
    public struct DEV_BROADCAST_DEVICEINTERFACE 
    { 
    public int dbcc_size; 
    public int dbcc_devicetype; 
    public int dbcc_reserved; 
    público Guid dbcc_classguid; 
    [MarshalAs(UnmanagedType.LPStr)] 
    público StringBuilder dbcc_name; 
    } 
    

    Conjunto de la dbcc_size a 255, y la construcción de la StringBuilder como se muestra a continuación:

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

    A continuación, pasar de la estructura, el valor de dbcc_name debe ser pobladas.

    Edición: después de risita‘s comentario…yo pensaba que de esta otra manera…

    público struct DEV_BROADCAST_DEVICEINTERFACE 
    { 
    public int dbcc_size; 
    public int dbcc_devicetype; 
    public int dbcc_reserved; 
    público Guid dbcc_classguid; 
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 255, ArraySubType = Sistema.En tiempo de ejecución.InteropServices.UnmanagedType.LPArray)] 
    public string dbcc_name; 
    } 
    

    Conjunto de la dbcc_size a 255, y tomar desde allí…

    Edición#2: Esto es interesante…no estoy tan seguro ahora, he encontrado este artículo que utiliza RegisterDeviceNotification en Codeproject y se utiliza una forma diferente de RegisterDeviceNotification en que la estructura se calcula en un IntPtr y se utiliza para llamar a la API…

    Usted no puede convertir los campos que se StringBuilders. Esto no funciona.
    acabo de darme cuenta…la edición de esta respuesta un poco más..
    Tom. Su edición aún no funciona. Usted sólo puede mariscal de cadenas para LPStr, LPWStr, LPTStr, BStr, o ByValTStr.
    has probado a cambiar el atributo’ [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr, SizeConst = 255, ArraySubType = Sistema.En tiempo de ejecución.InteropServices.UnmanagedType.LPStr)]’
    Mismos resultados. Sin Nombre

    OriginalEl autor t0mm13b

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea