2010-02-05 2 views
11

Tôi đã đăng ký cửa sổ với RegisterDeviceNotification và có thể nhận thành công DEV_BROADCAST_DEVICEINTERFACE thư. Tuy nhiên, trường dbcc_name trong cấu trúc trả về luôn trống. Các struct Tôi có được định nghĩa như vậy:Cách nhận tên thiết bị thân thiện từ DEV_BROADCAST_DEVICEINTERFACE và ID thiết bị thiết bị

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

Và tôi đang sử dụng Marshal.PtrToStructure trên lParam của thông điệp WM_DEVICECHANGE.

Điều này có đang hoạt động không?

Hoặc thậm chí tốt hơn ... Có cách nào khác để lấy tên thiết bị khi kết nối không?

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

tôi phát hiện ra như thế nào để có được những lĩnh vực dbcc_name để cư bằng cách làm này:

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

nhưng tôi vẫn cần một cách để có được một tên "thân thiện" từ những gì là int dbcc_name. Nó trông giống như sau:

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

Và tôi thực sự chỉ muốn nó nói gì? "Apple iPhone" (đó là thiết bị trong trường hợp này).

Trả lời

9

Vâng, như đã nói ở trên, tôi đã tìm ra cách để có được dbcc_name cư trú chính xác. Tôi thấy rằng đây là cách dễ nhất để lấy tên thiết bị:

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

THANKS !! Tôi đã cố gắng làm điều tương tự. –

0

Đó là khả năng bạn cần phải thay đổi điều này hơi

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

Đặt dbcc_size-255, và xây dựng các StringBuilder như hình dưới đây:

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

Sau đó vượt qua rằng cấu trúc trong, giá trị của dbcc_name nên được điền.

Edit: sau cười thầm 's nhận xét ... Tôi nghĩ về điều này một cách khác ...

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

Đặt dbcc_size-255, và mang nó từ đó ...

Chỉnh sửa # 2: Điều này thật thú vị ... hiện tại tôi không chắc lắm, tôi thấy bài viết này sử dụng RegisterDeviceNotification trên Codeproject và nó sử dụng khác erent cách RegisterDeviceNotification trong đó cấu trúc được marshalled vào một IntPtr và được sử dụng để gọi API ...

+0

Bạn không thể sắp xếp các trường là StringBuilder. Điều này không hoạt động. – snicker

+0

@Snicker: vừa mới nhận ra ... sẽ chỉnh sửa câu trả lời này thêm một chút .. – t0mm13b

+0

Tom. Chỉnh sửa của bạn vẫn không hoạt động. Bạn chỉ có thể sắp xếp các chuỗi thành LPStr, LPWStr, LPTStr, BStr hoặc ByValTStr. – snicker

2

Thông tin này cũng có thể được mua chính thức hơn thông qua SetupAPI.Vượt qua dbcc_name đến SetupDiOpenDeviceInterface và nhận tên thân thiện với SetupDiGetDeviceRegistryProperty đi qua trong SPDRP_FRIENDLYNAME.

Dưới đây là một số mã Delphi sẽ làm điều đó. (Xin lỗi, bạn sẽ phải dịch sang C# độc lập).

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; 

Cuối cùng ... nếu bạn cần một cách để nhận diện ra một thiết bị USB (không phải những gì bạn yêu cầu, nhưng thường này cũng là cần thiết), nhìn vào SetupDiGetDeviceInstanceId.

+0

Hơi muộn để trả lời. Một câu trả lời đã được chấp nhận với bảy phiếu bầu. –

+4

Nó không bao giờ là quá muộn cho một câu trả lời tốt hơn =) (Tôi thích một API chính thức hơn phân tích cú pháp chuỗi thủ công bất kỳ ngày nào) –

+0

@NathanSchubkegel nếu bạn có thể tìm thấy ai đó để dịch này sang C#, tôi sẽ thay đổi câu trả lời được chấp nhận. Đây sẽ là giải pháp hoàn toàn thích hợp hơn, mã tôi đăng ở trên có mùi và dựa vào thứ gì đó luôn ở cùng một vị trí trong sổ đăng ký (hoặc đăng ký hiện có), giải pháp winapi là tốt nhất – snicker