1:请问同一台电脑上的两个USB口,连接了两个相同的设备。可以通过API区分开两设备分别对应得是哪个USB口吗?也就是说可以用API来得出USB口的唯一标识吗?2:假设问题1成立。那如果我一根USB线上接了三个设备(Hid设备、Flash芯片、声卡),插到电脑上一个USB口。那这三个设备里分别都有对应此USB口的唯一标识信息吗?若有,如何用API得到呢? 谢谢!

解决方案 »

  1.   

    USB连到电脑上其实是映射成COM口的,你可以在"设备管理器"里看一下,这样连多个设备的时候每个设置就对于COM几COM几了
      

  2.   

    谢谢大家的回答。to
      hjkto: 不知能否帮小弟找下那篇帖子?
      
      lhylhy:不知能否具体些?
      

  3.   

    to wzwcn:
      谢谢你的回答。不知能否给点具体的提示。比方给段核心代码看下?
      

  4.   


    鄙视 #2 这类回复,
    至少给出你的方案吧。
    类似以上的回复,是说明你知道的多呢?还是说明你也不知道呢?lz,如果你的USB 是用于COM设备,通过一个 什么USBSeries的驱动的话,
    #1楼是正解。
    如果是,2个鼠标……呵呵,没有研究过,当偶是飘过的一片雾水好了。
      

  5.   

    to iamduo:
      谢谢你的回复。我目前的情况是: 一根USB线上接了三个设备(Hid设备、Flash芯片、声卡)。
      

  6.   

    在#1 说的地方能看到设备吗?
    如果有,好办一点,用注册表的方式可以得到。
    如果没有,我没撤,或者需要研究一下那些个Device(Windows.pas)可能是方向。
      

  7.   


    你没见楼主说的是Hid设备、Flash芯片、声卡? 这些设备会映射成COM口?1楼说的"USB连到电脑上其实是映射成COM口的", 这个USB难道是特指Serial-USB设备?
      

  8.   

    usb映射成com口的设备其实是一般都是偷懒的结果,当年我曾在一个公司里,那个公司就曾经把一个usb转接口塞到设备中。要了解这方面内容好像有个驱动开发网资料比较多。
      

  9.   

    GetLogicalDriveStrings
    GetDriveType
    GetVolumeInformation用上面三个API函数即可解决你的问题一。
    如果需要相关代码我也可以详细给你写出。
      

  10.   


    interfaceuses Windows, SysUtils, SetupApi, CfgMgr32;const
      IOCTL_STORAGE_GET_DEVICE_NUMBER = 2953344;
      
    type
      DEVICE_TYPE = DWORD;
      
      STORAGE_DEVICE_NUMBER = record
        DeviceType: DEVICE_TYPE;
        DeviceNumber: ULONG;
        PartitionNumber: ULONG;
      end;
      PSTORAGE_DEVICE_NUMBER = ^STORAGE_DEVICE_NUMBER;/// <summary>
    /// 根据盘符取硬件编号, 包括PID,VID,序列号
    /// </summary>
    /// <param name="Drive"></param>
    /// <returns></returns>
    function GetHardwardIDs(const Drive: Char): string;/// <summary>
    /// 根据设备号取设备实例,函数名是GetDeviceInstanceByDeviceNumber的简称
    /// </summary>
    /// <param name="Num"></param>
    /// <returns></returns>
    function GetDevInstByNum(Num: Integer): DEVINST;/// <summary>
    /// 根据盘符取设备号
    /// </summary>
    /// <param name="ADrive"></param>
    /// <returns></returns>
    function GetDeviceNumberByDrive(const ADrive: Char): Integer;implementation/// <summary>
    /// 根据设备路径获取设备号
    /// </summary>
    /// <param name="DevicePath">设备路径</param>
    /// <returns>失败返回-1</returns>
    function GetDeviceNumberByPath(const DevicePath: string): Integer;
    var
      h: THandle;
      sdn: STORAGE_DEVICE_NUMBER;  dwBytesReturned: DWORD;
      Res: BOOL;
    begin
      Result := -1;  h := CreateFile(PChar(DevicePath),
                           0,
                           FILE_SHARE_READ or FILE_SHARE_WRITE,
                           nil, OPEN_EXISTING, 0, 0);  if ( h <> INVALID_HANDLE_VALUE ) then
      begin
        dwBytesReturned := 0;
        res := DeviceIoControl(h,
                               IOCTL_STORAGE_GET_DEVICE_NUMBER,
                               nil, 0, @sdn, sizeof(sdn),
                               dwBytesReturned, nil);
        if (res) then
          Result := sdn.DeviceNumber;    CloseHandle(h);//关闭句柄
      end;
    end;//
    function GetDevInstByNum(Num: Integer): DEVINST;
    const
      USBGUID: TGUID = '{53f56307-b6bf-11d0-94f2-00a0c91efb8b}';
    var
    //  USBGuid: TGUID;
      USBHandle: HDEVINFO;  Devn: Integer;
      DevData: TSPDevInfoData;
      interfaceData: TSPDeviceInterfaceData;
      detailData: PSPDeviceInterfaceDetailData;
      BytesReturned: DWORD;  DevicePath: String;
    begin
      Result := INVALID_HANDLE_VALUE;  USBHandle := SetupDiGetClassDevsA(@USBGuid, nil, 0, DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE);  if USBHandle = Pointer(INVALID_HANDLE_VALUE) then Exit;  Devn := 0;
      while True do
      begin
        interfaceData.cbSize := SizeOf(TSPDeviceInterfaceData);    if not SetupDiEnumDeviceInterfaces(USBHandle, Nil, USBGuid, Devn, interfaceData) then
          Break;    DevData.cbSize := SizeOf(DevData);
        BytesReturned := 0;
        SetupDiGetDeviceInterfaceDetailA(USBHandle, @interfaceData, Nil, 0, BytesReturned, @DevData);    if (BytesReturned <> 0) And (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
        begin
          detailData := AllocMem(BytesReturned);
          try
            detailData.cbSize := SizeOf(TSPDeviceInterfaceDetailData);
            if SetupDiGetDeviceInterfaceDetailA(USBHandle, @interfaceData, detailData, BytesReturned, BytesReturned, @DevData) Then
            begin
              DevicePath := StrPas(PChar(@detailData.DevicePath));          if Num = GetDeviceNumberByPath(DevicePath) then
              begin
                Result := DevData.DevInst;
                Break;
              end;
            end;
            
          finally
            FreeMem(detailData);
          end;//try finally end
        end;
        Inc(Devn);
      end;
      SetupDiDestroyDeviceInfoList(USBHandle);
    end;function GetDeviceNumberByDrive(const ADrive: Char): Integer;
    const
      DevicePath = '\\?\%s:';
    begin
      Result := GetDeviceNumberByPath(Format(DevicePath, [ADrive]));
    end;function GetHardwardIDs(const Drive: Char): string;
    var
      Buffer: array[0..MAX_PATH- 1] of Char;
      hDevInst, DevInstParent: DEVINST;
      Num: Integer;
    begin
      Result := '';
      
      //根据设备取得设备号
      Num := GetDeviceNumberByDrive(Drive);
      if Num = -1 then Exit;  hDevInst := GetDevInstByNum(Num);
      if hDevInst = INVALID_HANDLE_VALUE then Exit;
        FillChar(Buffer, MAX_PATH, 0);
      CM_Get_Parent(DevInstParent, hDevInst, 0);
      CM_Get_Device_ID(DevInstParent, Buffer, MAX_PATH, 0);
      
      Result := StrPas(Buffer);
    end;initialization
      LoadSetupApi;
      CfgMgr32.LoadConfigManagerApi;finalization
      Setupapi.UnloadSetupApi;
      CfgMgr32.UnloadConfigManagerApi;
    end.这是我帮你找到的,看看能不能用到,如果不能,就帮不了你了
      

  11.   

    //编译环境:                                                                  
    //  1、本单元使用了jcl代码库中的Setupapi及CfgMgr32单元                        
    //     http://sourceforge.net/projects/jcl/                                   
    //     http://jvcl.sourceforge.net/                                           
    //  2、Delphi 7.0                  
      

  12.   

    可以的,不过要看你的驱动,通过驱动信息,去识别!还需要lz说说,包括你的usb的下位机和上位机是怎么实现通信的,如果是模拟串口的话,1#说的没错!如果是标准usb总线通信的话,驱动写好了吗。如果驱动写好了,你这个问题也就不是问题了!
      

  13.   

    十分感谢大家的回答。其实我只是个做delphi应用层的,不怎么懂硬件这块。我目前了解到的情况应该是这样的:一根USB线连了三个设备。其中Hid设备硬件厂商给我一份协议,只要找到设备句柄,按照协议标准往下WriteFile就可以了;Flash设备,硬件厂商跟我说用直接打开物理磁盘,然后他给我指针的做法来弄。而声卡那块,则要我用原始winAPI来弄。这些具体的实现应该都没什么大问题,我现在的问题是如何把一根usb线上的三个设备关联起来。因为上层软件允许插多跟usb线。要是以三个设备为一组,那么也就是说上层软件允许插多组这样的设备。我要把这个组区分开来,以便上层软件控制。再一次谢谢大家
      

  14.   

    我这两天在网上看到一篇C++的文章如下:
    http://hi.baidu.com/combojiang/blog/item/035b332456a2eb074c088dca.html (一)
    http://hi.baidu.com/combojiang/blog/item/7953d6d7a31edbdba144dfcb.html (二)我把他翻译成Delphi的了,想试试可以不可以满足我的需求。但现在的问题是我调用GetRootHubName时返回得总是空值。不知道问题出在哪里?关键代码如下:
    function TForm1.GetRootHubName(AHostController: THandle): PChar;
    var
      bSuccess: Boolean;
      nBytes: ULONG;
      rootHubName: USB_ROOT_HUB_NAME;
      rootHubNameW: PUSB_ROOT_HUB_NAME;
      rootHubNameA: PChar;  procedure GetRootHubNameError;
      begin
        if Assigned(rootHubNameW) then
        begin
          Dispose(rootHubNameW);
          rootHubNameW := nil;
        end;
      end;begin
      Result := nil;
      rootHubNameW := nil;
      rootHubNameA := nil;
      
      bSuccess := DeviceIoControl(AHostController,
        IOCTL_USB_GET_ROOT_HUB_NAME,
        0,
        0,
        @rootHubName,
        SizeOf(rootHubName),
        nBytes,
        nil);  if not bSuccess then
      begin
        GetRootHubNameError;
        Exit;
      end;  nBytes := rootHubName.ActualLength;
      New(rootHubNameW);  bSuccess := DeviceIoControl(AHostController,
        IOCTL_USB_GET_ROOT_HUB_NAME,
        0,
        0,
        rootHubNameW,
        nBytes,
        nBytes,
        nil);  if not bSuccess then
      begin
        GetRootHubNameError;
        Exit;
      end;  rootHubNameA := WideStrToMultiStr(rootHubName.RootHubName);
      Dispose(rootHubNameW);
      Result := rootHubNameA;
    end;
    var
      IOCTL_USB_GET_ROOT_HUB_NAME,
      IOCTL_GET_HCD_DRIVERKEY_NAME: DWORD; type  PUSB_ROOT_HUB_NAME = ^USB_ROOT_HUB_NAME;
      USB_ROOT_HUB_NAME = packed record
        ActualLength: ULONG;
        RootHubName: array [0..0] of WCHAR;
      end;
    function CTL_CODE( _DeviceType, _Function, _Method, _Access:DWORD ):DWORD;  implementationfunction CTL_CODE( _DeviceType, _Function, _Method, _Access:DWORD ):DWORD;
    begin
      Result:= (_DeviceType SHL 16) or (_Access SHL 14) or (_Function SHL 2) or _Method;
    end;initializationIOCTL_USB_GET_ROOT_HUB_NAME :=
      CTL_CODE(FILE_DEVICE_USB, USB_IOCTL_INDEX + 3, METHOD_BUFFERED, FILE_ANY_ACCESS);end.
      

  15.   

    // 可以明确USB设备插在那个USB总线上
    // 不同类的设备,即使没有UID,也可以根据返回的不同名称区分不同的设备。
      

  16.   

    to lfchen:
      不知可否具体些?万分感谢!
      

  17.   

    真能扯啊,不是所有usb设备都是转com口用的
      

  18.   

    帮我看看你usb移动硬盘式com几的
      

  19.   

    哈哈 "wzwcn" 同学也不算瞎掰了,因为他可能只做过 USB->COM 的设备 采用于CDC驱动或专用的USB转COM驱动楼主是有这么一个设备 接上PC 后 枚举成三个设备? 一个HID 一个 MassStorage 一个USB 声卡?此时你可以调用设备管理函数 枚举全部设备或仅仅 USB 类型设备 找出你需要的设备列表就行了这些函数在 SetupApi.pas 单元中,网上很好找例如下函数把 接在PC上的WM手机枚举出来var
      ii: Integer;
      gd: TGUID;
      hdi: hDevInfo;
      pszText: array[0..255] of char;
      DeviceInfoData: TSPDevInfoData;
    begin
      ii := 0;
      Result := 0;
      gd := StringToGUID('{4D36E972-E325-11CE-BFC1-08002BE10318}');
      DeviceInfoData.cbSize := SizeOf(TSPDevInfoData);
      hdi := SetupDiGetClassDevs(@gd, PChar('USB'), 0, DIGCF_PRESENT);
      if (hdi <> Pointer(INVALID_HANDLE_VALUE)) then
      begin
           while SetupDiEnumDeviceInfo(hdi, ii, DeviceInfoData) do
           begin
             ConstructDeviceName(hdi, DeviceInfoData, pszText, DWord(nil));         if  Pos('Mobile-based',pszText) > 0 then
             begin
                 Result := 1;
                 if CheckMBDState(DeviceInfoData.DevInst) <> CM_PROB_DISABLED then
                 Result := 2;
             end;         if Result > 0 then break;
             Inc(ii);
           end;
      end;
      SetupDiDestroyDeviceInfoList(hdi);
    end;
      

  20.   

    上层软件只能跟设备的驱动程序打交道,或者说,即,你的上层软件要分别使用三个设备的驱动程序来与之通讯。尽管USB协议本身有标准,但具体厂家做设备驱动的时候却不仅相同,可能采用不同的芯片,即便采用相同的芯片,也可能有自己的DDK实现。有的实现的比较低级,比如用CREATEFILE之类的接口,有的再次封装成更高级一些的驱动。可以说,除了HID、U盘之类的通用设备可以采用系统的默认设备以外,其它设备,比如扫描仪、打印机都要安装自己的驱动程序。与这些设备通讯,自然要了解他们的驱动程序所提供的API接口,并分别操作之。你看一下他们的接口,是可以分开各自不同的设备的,这点毋庸置疑。我的担心是,如果你的三个设备为一组,系统插了N组你的设备,那么级联之后,你该如何操作。呵呵,希望不是这么复杂。
      

  21.   

    唉一个月过去了。别的搞得差不多了,又要回头来搞这个破东东了。杯具啊yubsh 兄 你说得没错,我郁闷得就是需要插N组设别,就是需要级联。
      

  22.   

    咦?俺啥时候变两条裤衩了先贴个图吧(这Csdn发个图,忒费事了)。Bus Hound 这个软件 可以很好的 把我的三个设备分类出来。不知道他怎么实现的。