::: 델파이 Tip&Trick :::

델파이 Tip&Trick 성격에 맞지 않는 광고,비방,질문의 글은 즉시 삭제하며
내용을 복사하여 사용할 경우 반드시 이곳(http://www.howto.pe.kr)을 출처로 명시하여 주세요


Category

  김영대(2008-11-04 11:56:10, Hit : 11663, Vote : 1459
 http://www.howto.pe.kr
 사용중인 USB 포트의 장치정보 구하기

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

const
  FILE_DEVICE_UNKNOWN      = $00000022;
  FILE_DEVICE_USB          = FILE_DEVICE_UNKNOWN;
  USB_IOCTL_INTERNAL_INDEX = $0000;
  USB_IOCTL_INDEX          = $00ff;
  METHOD_BUFFERED          = 0;
  FILE_ANY_ACCESS          = 0;

  IOCTL_USB_GET_NODE_INFORMATION = ((FILE_DEVICE_USB shl 16) or
                                    ((USB_IOCTL_INDEX+3) shl 2) or
                                    METHOD_BUFFERED or
                                    (FILE_ANY_ACCESS shl 14));

  IOCTL_USB_GET_NODE_CONNECTION_INFORMATION = ((FILE_DEVICE_USB shl 16) or
                                               ((USB_IOCTL_INDEX+4) shl 2) or
                                               METHOD_BUFFERED or
                                               (FILE_ANY_ACCESS shl 14));

  IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION = ((FILE_DEVICE_USB shl 16) or
                                                   ((USB_IOCTL_INDEX+5) shl 2) or
                                                   METHOD_BUFFERED or
                                                   (FILE_ANY_ACCESS shl 14));

  IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME = ((FILE_DEVICE_USB shl 16) or
                                                  ((USB_IOCTL_INDEX+9) shl 2) or
                                                  METHOD_BUFFERED or
                                                  (FILE_ANY_ACCESS shl 14));

  IOCTL_GET_HCD_DRIVERKEY_NAME = ((FILE_DEVICE_USB shl 16) or
                                  ((USB_IOCTL_INDEX+10) shl 2) or
                                  METHOD_BUFFERED or
                                  (FILE_ANY_ACCESS shl 14));

  USB_REQUEST_GET_DESCRIPTOR                = $06;
  USB_STRING_DESCRIPTOR_TYPE                = $03;
  USB_CONFIGURATION_DESCRIPTOR_TYPE         = $02;

type
  TUnicodeName = record
    Length: DWORD;
    UnicodeName: array[0..255] of Byte;
  end;

  TNodeType = record
    ConnectionIndex: DWORD;
    Length: DWORD;
    UnicodeName: array[0..255] of byte
  end;

  THubDescriptor = record
    Length: Byte;
    HubType: Byte;
    PortCount: Byte;
    Characteristics: array[0..1] of Byte;
    PowerOnToPowerGood: Byte;
    HubControlCurrent: Byte;
    RemoveAndPowerMask: array[0..63] of Byte;
  end;

  TNodeInformation = record
    NodeType: DWORD;
    NodeDescriptor: THubDescriptor;
    HubIsBusPowered: Byte;
  end;

  TDeviceDescriptor = record
    Length: Byte;
    DescriptorType: Byte;
    USBSpec: array[0..1] of Byte;
    DeviceClass: Byte;
    DeviceSubClass: Byte;
    DeviceProtocol: Byte;
    MaxPacketSize0: Byte;
    VendorID: Word;//array[0..1] of Byte;
    ProductID: Word; //array[0..1] of Byte;
    DeviceRevision: array[0..1] of byte;
    ManufacturerStringIndex: byte;
    ProductStringIndex: Byte;
    SerialNumberStringIndex: Byte;
    ConfigurationCount: Byte;
  end;

  TEndPointDescriptor = record
    Length: Byte;
    DescriptorType: Byte;
    EndpointAddress: Byte;
    Attributes: Byte;
    MaxPacketSize: WORD;
    PollingInterval: Byte;
  end;

  TUSBPipeInfo = record
    EndPointDescriptor: TEndpointDescriptor;
    ScheduleOffset: DWORD;
  end;

  TNodeConnectionInformation = record
    ConnectionIndex: DWORD;
    ThisDevice: TDeviceDescriptor;
    CurrentConfiguration: Byte;
    LowSpeed: Byte;
    DeviceIsHub: Byte;
    DeviceAddress: array[0..1] of Byte;
    NumberOfOpenEndPoints: array[0..3] of Byte;
    ThisConnectionStatus: array[0..3] of Byte;
    PipeList: array[0..31] of TUSBPipeInfo;
  end;

  TSetupPacket = record
    bmRequest: Byte;
    bRequest: Byte;
    wValue: array[0..1] of Byte;
    wIndex: array[0..1] of Byte;
    wLength: array[0..1] of Byte;
  end;

  TDescriptorRequest = record
    ConnectionIndex: DWORD;
    SetupPacket: TSetupPacket;
    ConfigurationDescriptor: array[0..2047] of Byte;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function GetDeviceName1(hDevice: THandle; IOCTL_Code: DWORD): string;
var
  i: Integer;
  NameBuffer: TUnicodeName;
  BytesReturned: DWORD;
begin
  Result:='';
  if DeviceIoControl(hDevice,IOCTL_Code,@NameBuffer,SizeOf(NameBuffer),@NameBuffer,SizeOf(NameBuffer),BytesReturned,nil) then begin
    i:=0;
    while NameBuffer.UnicodeName[i]<>0 do begin
      Result:=Result+Chr(NameBuffer.UnicodeName[i]);
      Inc(i,2);
    end;
  end else
    Result:=Format('Error: %s (%d)',[SysErrorMessage(GetLastError),GetLastError]);
end;

function GetDeviceName2(hDevice: THandle; PortIndex: DWORD; IOCTL_Code: DWORD): string;
var
  i: Integer;
  NameBuffer: TNodeType;
  BytesReturned: DWORD;
begin
  Result:='';
  NameBuffer.ConnectionIndex:=PortIndex;
  if DeviceIoControl(hDevice,IOCTL_Code,@NameBuffer,SizeOf(NameBuffer),@NameBuffer,SizeOf(NameBuffer),BytesReturned,nil) then begin
    i:=0;
    while NameBuffer.UnicodeName[i]<>0 do begin
      Result:=Result+Chr(NameBuffer.UnicodeName[i]);
      Inc(i,2);
    end;
  end else
    Result:=Format('Error: %s (%d)',[SysErrorMessage(GetLastError),GetLastError]);
end;

function GetNodeInformation(hDevice: THandle; var Information: TNodeInformation): Integer;
var
  BytesReturned: DWORD;
begin
  if DeviceIoControl(hDevice,IOCTL_USB_GET_NODE_INFORMATION,nil,0,@Information,SizeOf(Information),BytesReturned,nil) and (BytesReturned<=256) then
    Result:=0
  else
    Result:=GetLastError;
end;

function GetNodeConnection(hDevice: THandle; PortIndex: DWORD; var Connection: TNodeConnectionInformation): Integer;
var
  BytesReturned: DWORD;
begin
  Zeromemory(@Connection,SizeOf(Connection));
  Connection.ConnectionIndex:=PortIndex;
  if not DeviceIoControl(hDevice,IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,@Connection,SizeOf(Connection),@Connection,SizeOf(Connection),BytesReturned,nil) and (BytesReturned<=256) then
    Result:=GetLastError
  else
    Result:=0;
end;

function GetStringDescriptor(HubHandle: THandle; PortIndex: DWORD; var LanguageID: Word; Index: Byte; var Str: shortstring): integer;
var
  Packet: TDescriptorRequest;
  BytesReturned: DWORD;
  Success: boolean;
begin
  Str:='';
  Result:=0;
  if (LanguageID=0) then begin
    Packet.ConnectionIndex:=PortIndex;
    Packet.SetupPacket.bmRequest:=$80;
    Packet.SetupPacket.bRequest:=USB_REQUEST_GET_DESCRIPTOR;
    Packet.SetupPacket.wValue[1]:=USB_STRING_DESCRIPTOR_TYPE;
    Packet.SetupPacket.wLength[0]:=8;
    {Success:=}DeviceIoControl(HubHandle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,@Packet,
                        sizeof(Packet),@Packet,sizeof(Packet),BytesReturned,nil);
    {if not Success then
      Result:=GetLastError;}
    LanguageID:=Packet.ConfigurationDescriptor[2]+(Packet.ConfigurationDescriptor[3] shl 8);
  end;
  Packet.ConnectionIndex:=PortIndex;
  Packet.SetupPacket.bmRequest:=$80;
  Packet.SetupPacket.bRequest:=USB_REQUEST_GET_DESCRIPTOR;
  Packet.SetupPacket.wValue[1]:=USB_STRING_DESCRIPTOR_TYPE;
  Packet.SetupPacket.wValue[0]:=Index;
  Packet.SetupPacket.wIndex[0]:=LanguageID and $FF;
  Packet.SetupPacket.wIndex[1]:=(LanguageID shr 8) and $FF;
  Packet.SetupPacket.wLength[0]:=255;
  Success:=DeviceIoControl(HubHandle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,@Packet,
                sizeof(Packet),@Packet,sizeof(Packet),BytesReturned,nil);
  if not Success then
    Result:=GetLastError
  else begin
    ZeroMemory(@Packet.ConfigurationDescriptor[2],255);
    Packet.ConnectionIndex:=PortIndex;
    Packet.SetupPacket.bmRequest:=$80;
    Packet.SetupPacket.bRequest:=USB_REQUEST_GET_DESCRIPTOR;
    Packet.SetupPacket.wValue[1]:=USB_STRING_DESCRIPTOR_TYPE;
    Packet.SetupPacket.wValue[0]:=Index;
    Packet.SetupPacket.wIndex[0]:=LanguageID and $FF;
    Packet.SetupPacket.wIndex[1]:=(LanguageID shr 8) and $FF;
    Packet.SetupPacket.wLength[0]:=255;
    Success:=DeviceIoControl(HubHandle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,@Packet,
                   sizeof(Packet),@Packet,sizeof(Packet),BytesReturned,nil);
    if not Success then
      Result:=GetLastError
    else
      Str:=WideCharToString(PWideChar(@Packet.ConfigurationDescriptor[2]));
  end;
end;

function GetConfigurationDescriptor(HubHandle: THandle; PortIndex: DWORD; var MaxPower: WORD; var ClassID: integer): Integer;
var
  Packet: TDescriptorRequest;
  BytesReturned: DWORD;
  Success: boolean;
  LowByte: Byte;
  BufferPtr: Byte;
begin
  Result:=0;
  ClassID:=-1;
  MaxPower:=0;
  with Packet do begin
    ConnectionIndex:=PortIndex;
    SetupPacket.bmRequest:=$80;
    SetupPacket.bRequest:=USB_REQUEST_GET_DESCRIPTOR;
    SetupPacket.wValue[0]:=0;
    SetupPacket.wValue[1]:=USB_CONFIGURATION_DESCRIPTOR_TYPE;
    SetupPacket.wIndex[0]:=0;
    SetupPacket.wIndex[1]:=0;
    SetupPacket.wLength[0]:=18;
  end;
  Success:=DeviceIoControl(HubHandle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
                          @Packet,SizeOf(TDescriptorRequest),@Packet,SizeOf(TDescriptorRequest),BytesReturned,nil);
  if not Success then begin
    Result:=GetLastError;
    Exit;
  end;
  with Packet do begin
    ConnectionIndex:=PortIndex;
    SetupPacket.bmRequest:=$80;
    SetupPacket.bRequest:=USB_REQUEST_GET_DESCRIPTOR;
    SetupPacket.wValue[0]:=0;
    SetupPacket.wValue[1]:=USB_CONFIGURATION_DESCRIPTOR_TYPE;
    SetupPacket.wIndex[0]:=0;
    SetupPacket.wIndex[1]:=0;
    SetupPacket.wLength[0]:=Packet.ConfigurationDescriptor[2];
    SetupPacket.wLength[1]:=Packet.ConfigurationDescriptor[3];
  end;
  Success:=DeviceIoControl(HubHandle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
                          @Packet,SizeOf(TDescriptorRequest),@Packet,SizeOf(TDescriptorRequest),BytesReturned,nil);
  if not Success then begin
    Result:=GetLastError;
    Exit;
  end;

  MaxPower:=Packet.ConfigurationDescriptor[8]*2;
  BufferPtr:=9;
  while (Packet.ConfigurationDescriptor[BufferPtr]<>0) do begin
    if Packet.ConfigurationDescriptor[BufferPtr+1]=4 then begin
      LowByte:=Packet.ConfigurationDescriptor[BufferPtr+5];
      if ((LowByte>9) and (LowByte<255)) then
        LowByte:=11;
      if (LowByte=255) then
        LowByte:=10;
      ClassID:=LowByte;
      Break;
    end;
    Inc(BufferPtr,9);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i, j, k: Integer;
  hHCD, hRH: THandle;
  Node: TNodeInformation;
  HCDName, RootHubName: string;
  SA: TSecurityAttributes;

  NodeConnection: TNodeConnectionInformation;
  LanguageID: Word;
  KeyName, Product, Manufacturer, Serial: shortstring;
  MaxPower: Word;
begin
  Memo1.Clear;

  SA.nLength := Sizeof(SECURITY_ATTRIBUTES);
  SA.lpSecurityDescriptor := nil;
  SA.bInheritHandle := False;

  LanguageID := 0;
  for i := 0 to 9 do
  begin
    HCDName := Format('HCD%d',[i]);
    hHCD := CreateFile(PChar(Format('\\.\%s',[HCDName])),
                       GENERIC_WRITE,
                       FILE_SHARE_WRITE,
                       @SA,
                       OPEN_EXISTING,
                       0,
                       0);
    if hHCD = INVALID_HANDLE_VALUE then continue;
    Memo1.Lines.Add(Format('Host Controller %d',[i]));

    KeyName := GetDeviceName1(hHCD,IOCTL_GET_HCD_DRIVERKEY_NAME);
    RootHubName := GetDeviceName1(hHCD, IOCTL_USB_GET_NODE_INFORMATION);
    hRH := CreateFile(PChar(Format('\\.\%s',[RootHubName])),
                      GENERIC_WRITE,
                      FILE_SHARE_WRITE,
                      @SA,
                      OPEN_EXISTING,
                      0,
                      0);
    if hRH = INVALID_HANDLE_VALUE then
    begin
      CloseHandle(hHCD);
      continue;
    end;
    if GetNodeInformation(hRH, Node) <> ERROR_SUCCESS then
    begin
      CloseHandle(hRH);
      CloseHandle(hHCD);
      continue;
    end;
    Memo1.Lines.Add('   Root Hub');

    // 각 HID의 port 정보를 읽는다
    for j := 1 to Node.NodeDescriptor.PortCount do
    begin
      if GetNodeConnection(hRH, j, NodeConnection) <> ERROR_SUCCESS then continue;
      if NodeConnection.ThisConnectionStatus[0] <> 1 then
      begin
        Memo1.Lines.Add(Format('      Port[%d]: No device connected',[j])); // 사용하지 않음
        continue;
      end;

      if Boolean(NodeConnection.DeviceIsHub) then continue;

      KeyName := GetDeviceName2(hRH,j,IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME);
      if GetStringDescriptor(hRH,j,LanguageID,NodeConnection.ThisDevice.ProductStringIndex,Product)=0 then
        Memo1.Lines.Add(Format('      Port[%d]: %s',[j, Product])) // 제품 이름
      else
        Memo1.Lines.Add(Format('      Port[%d]: <unknown>',[j]));

      Memo1.Lines.Add(Format('         Product ID: %.4x',[NodeConnection.ThisDevice.ProductID]));
      Memo1.Lines.Add(Format('         Vendor ID: %.4x',[NodeConnection.ThisDevice.VendorID]));
      Memo1.Lines.Add(Format('         Version: %d.%d',[NodeConnection.ThisDevice.USBSpec[1], NodeConnection.ThisDevice.USBSpec[0]]));

      KeyName := GetDeviceName2(hRH,j,IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME);
      if GetStringDescriptor(hRH,j,LanguageID,NodeConnection.ThisDevice.ManufacturerStringIndex,Manufacturer)=0 then
        Memo1.Lines.Add(Format('         Manufacturer: %s',[Manufacturer]));
      KeyName := GetDeviceName2(hRH,j,IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME);
      if GetStringDescriptor(hRH,j,LanguageID,NodeConnection.ThisDevice.SerialNumberStringIndex,Serial)=0 then
        Memo1.Lines.Add(Format('         Serial: %s',[Serial]));

      k := -1;
      GetConfigurationDescriptor(hRH,j,MaxPower,k);
      Memo1.Lines.Add(Format('         Power Consumption: %d mA',[MaxPower]));
    end;

    CloseHandle(hRH);
    CloseHandle(hHCD);
    Memo1.Lines.Add('');
  end;
end;

end.





971   [윈도우즈 API] 작업 표시줄에 보이는 프로그램의 아이콘 정보  김영대 2008/12/09 5960 1438
970   [윈도우즈 API] 실행 파일의 아이콘 바꾸기  김영대 2008/11/27 7460 1382
969   [네트웍/인터넷] TClientSocket 에 Local IP 바인딩하기  김영대 2008/11/25 6253 1502
968   [알고리즘] Boyer-Moore-Horspool Text Searching  김영대 2008/11/24 5012 1349
967   [일반/컴포넌트] Tab, Shift+Tab 키 이벤트 사용하기  김영대 2008/11/21 4887 1386
966   [일반/컴포넌트] TStringList vs. THashedStringList  김영대 2008/11/04 5199 1371
965   [시스템] 프로세스가 원도우즈 원격 터미널에서 실행중인지 검사  김영대 2008/11/04 5174 1477
964   [시스템] 원도우즈 도메인 이름 구하기  김영대 2008/11/04 5699 1347
  [시스템] 사용중인 USB 포트의 장치정보 구하기  김영대 2008/11/04 11663 1459
962   [일반/컴포넌트] Treeview의 수평 스크롤바 감추고 스크롤 막기  김영대 2006/03/22 5428 1235
961   [윈도우즈 API] 바탕화면의 모든 창 최소화하기  김영대 2006/02/28 5370 1286
960   [일반/컴포넌트] 일정시간 경과후 없어지는 MessageBox  김영대 2006/02/28 6411 1599
959   [시스템] System의 Idle 상태를 알아내는 API  김영대 2006/02/28 6042 1441
958   [일반/컴포넌트] ListBox에 Edit 올려 항목 편집하기  김영대 2006/02/28 4759 1206
957   [일반/컴포넌트] 폼 흔들기  김영대 2006/02/28 5227 1194
956   [일반/컴포넌트] 마우스로 ProgressBar의 Position 바꾸기  김영대 2006/02/28 4805 1249
955   [일반/컴포넌트] ListBox 드래그하여 아이템 이동하기  김영대 2006/02/28 4852 1181
954   [시스템] 폼의 Move/Resize 시작,종료 이벤트 감지하기  김영대 2006/02/28 5139 1354
953   [COM/OLE] IE의 속성을 변경하여 뛰우기  김영대 2006/02/28 5224 1226
952   [윈도우즈 API] 세로 글꼴 제거한 FontDialog  김영대 2006/02/28 5127 1344
951   [시스템] CPU 이름 구하기2  김영대 2005/09/13 5597 1343
950   [네트웍/인터넷] IP Helper API 를 이용한 네트워크 카드 Enable/Disable 시키기  김영대 2005/09/10 6019 1314
949   [일반/컴포넌트] 폼에 자석효과 주기 (Delphi 6 이하)  김영대 2005/08/04 5963 1292
948   [일반/컴포넌트] 객체의 valid검사 Assigned() 대체  김영대 2005/07/29 4717 1246
947   [시스템] 시스템 대기모드/화면 보호기/모니터 끄기 이벤트 감지하기  김영대 2005/07/21 6752 1482
946   [시스템] 윈도우즈 GUI 기본 폰트정보 구하기  김영대 2005/07/14 5428 1346
945   [시스템] 윈도우즈 입력도구모음의 한/영 토글하기  김영대 2005/06/24 5218 1372
944   [COM/OLE] ActiveForm의 OnDestroy 대용  김영대 2005/04/21 5237 1226
943   [일반/컴포넌트] ListView의 타이틀 폰트 바꾸기  김영대 2005/03/31 5152 1233
942   [일반/컴포넌트] 일정시간 경과후 없어지는 MessageDlg/ShowMessage  김영대 2005/03/26 5820 1268
941   [일반/컴포넌트] 프로그램의 bitmap을 MS 그림판으로 편집하여 다시 불러오기  김영대 2005/03/22 5153 1323
940   [일반/컴포넌트] RichEdit 2.0 줄간격 조정  김영대 2005/02/11 7191 1270
939   [COM/OLE] 탐색기에서 파일을 선택하여 ActiveX(ActiveFortm)에 Drag&Drop 하기  김영대 2005/01/06 7529 1267
938   [윈도우즈 API] TDownloadURL를 사용한 파일 다운받기  김영대 2004/12/26 6365 1262
937   [COM/OLE] TWebBrowser에 직접 HTML 소스코드 넣기  김영대 2004/12/26 6017 1266
936   [윈도우즈 API] 윈도우즈 시스템 전체에서 사용자의 마우스와 키보드 입력이 있는지 검사하기  김영대 2004/12/26 6038 1350
935   [일반/컴포넌트] 다이얼로그 박스가 이미 떠있는지 검사하여 강제로 닫기  김영대 2004/12/22 5030 1212
934   [윈도우즈 API] URLDownloadToFile()를 사용한 파일 다운받기  김영대 2004/12/15 7615 1383
933   [COM/OLE] 내 프로그램에서 선택한 text를 다른 프로그램에 Drag&Drop으로 주기  김영대 2004/12/10 5360 1099
932   [COM/OLE] 다른 프로그램에서 선택한 text를 내 프로그램에서 Drag&Drop으로 받기  김영대 2004/12/09 5503 1206

1 [2][3][4][5][6][7][8][9][10]..[25] [다음 10개]
 

Copyright 1999-2017 Zeroboard / skin by zero