Давно писал, не помню уже, что и зачем, но до сих пор работает безупречно под всеми виндами.
memento mori
unit CP2101; interface uses Windows, SysUtils, Classes, Registry; const //Masks for the serial number and description CP210x_RETURN_SERIAL_NUMBER = $0; CP210x_RETURN_DESCRIPTION = $1; CP210x_RETURN_FULL_PATH = $2; //Masks for return values from the device CP210x_SUCCESS = $0; CP210x_DEVICE_NOT_FOUND = $FF; CP210x_INVALID_HANDLE = $1; CP210x_INVALID_PARAMETER = $2; CP210x_DEVICE_IO_FAILED = $3; //Maximum Length of Strings CP210x_MAX_DEVICE_STRLEN = 256; CP210x_MAX_PRODUCT_STRLEN = 126; CP210x_MAX_SERIAL_STRLEN = 63; CP210x_MAX_MAXPOWER = 250; INVALID_HANDLE_VALUE = $1; // GetDeviceVersion() return codes CP210x_CP2101_VERSION = $1; CP210x_CP2102_VERSION = $2; CP210x_CP2103_VERSION = $3; CP2102DLL = 'CP210x.DLL'; //CP2102RUNTIME = 'CP210xRuntime.dll'; type CP210x_STATUS = integer; TCP2102 = record SerNr : string[CP210x_MAX_SERIAL_STRLEN]; PortNr : integer; end; TCP210X = class private FList: TList; procedure EnumDevices; procedure GetDeviceData; function ConvertToString(const ConvertArray: array of Byte; ConvertLength: integer):string; function GetPortNumXP2000(Vid,Pid: WORD; serNum: String): Integer; function GetCount: Integer; function GetItems(Index: Integer): TCP2102; function Add(const SerNr: string; PortNr: Integer): Integer; overload; function Add(ACP2102: TCP2102): Integer; overload; public devNum : integer; //global variable to hold number of devices connected hUSBDevice : integer; //global handle that is set when connected with the CP210x device Status : integer; //status, value to set when communicating with the board to determine success property Count: Integer read GetCount; property Items[Index: Integer]: TCP2102 read GetItems; default; constructor Create(); destructor Destroy; override; procedure Clear; procedure FillDeviceList; end; function CP210x_GetNumDevices (var lpwdNumDevices:integer):Integer; stdcall; external CP2102DLL; function CP210x_GetProductString(dwDeviceNum:integer; var lpvDeviceString:integer; dwFlags:integer):Integer; stdcall; external CP2102DLL; function CP210x_Open(dwDevice:integer; var cyHandle:integer):Integer; stdcall; external CP2102DLL; function CP210x_Close(cyHandle:integer):Integer; stdcall; external CP2102DLL; function CP210x_Reset(cyHandle:integer):Integer; stdcall; external CP2102DLL; function CP210x_SetVid(cyHandle:integer; wVid:WORD):Integer; stdcall; external CP2102DLL; function CP210x_SetPid(cyHandle:integer; wPid:WORD):Integer; stdcall; external CP2102DLL; function CP210x_SetProductString(cyHandle:integer; var lpvProduct:integer; bLength:BYTE; bConvertToUnicode : BOOL = TRUE):Integer; stdcall; external CP2102DLL; function CP210x_SetSerialNumber( cyHandle:integer; var lpvSerialNumber:byte; bLength:WORD; bConvertToUnicode :BOOL = TRUE):Integer; stdcall; external CP2102DLL; function CP210x_SetSelfPower(cyHandle:integer; bSelfPower:BOOL):Integer; stdcall; external CP2102DLL; function CP210x_SetMaxPower(cyHandle:integer; bMaxPower:BYTE):Integer; stdcall; external CP2102DLL; function CP210x_SetDeviceVersion(cyHandle:integer; wVersion:integer):Integer; stdcall; external CP2102DLL; function CP210x_GetDeviceVid(cyHandle:integer; var lpwVid:WORD):Integer; stdcall; external CP2102DLL; function CP210x_GetDevicePid(cyHandle:integer; var lpwPid:WORD):Integer; stdcall; external CP2102DLL; function CP210x_GetDeviceProductString(cyHandle:integer; var lpProduct:Byte; var lpbLength:integer; bConvertToASCII:BOOL = TRUE):Integer; stdcall; external CP2102DLL; //function CP210x_GetDeviceSerialNumber(cyHandle:integer; var lpSerialNumber:byte; var lpbLength:Byte; bConvertToASCII:BOOL = TRUE):Integer; stdcall; external CP2102DLL; function CP210x_GetDeviceSerialNumber(cyHandle:integer;var lpSerialNumber: Byte; var lpbLength:Byte; bConvertToASCII:BOOL = TRUE):Integer; stdcall; external CP2102DLL; function CP210x_GetSelfPower(cyHandle:integer; var lpbSelfPower:integer):Integer; stdcall; external CP2102DLL; function CP210x_GetMaxPower(cyHandle:integer; var lpbPower:integer):Integer; stdcall; external CP2102DLL; function CP210x_GetDeviceVersion(cyHandle:integer; var lpwVersion:integer):Integer; stdcall; external CP2102DLL; //function CP210xRT_GetPartNumber(cyHandle:integer; var lpbPartNum:Word):Integer; stdcall; external 'CP210xRuntime.dll'; //function CP210x_GetDeviceProductString(cyHandle:integer; var lpProduct:integer; var lpbLength:WORD; bConvertToASCII:BOOL = TRUE) //function CP210x_GetDeviceSerialNumber(cyHandle:integer; var lpSerialNumber:byte; var lpbLength:WORD; bConvertToASCII:BOOL = TRUE) //function CP210xRT_GetDeviceProductString(cyHandle:integer;var lpProduct: Byte; var lpbLength: Byte; bConvertToASCII:BOOL = TRUE):Integer; stdcall; external CP2102RUNTIME; //function CP210xRT_GetDeviceSerialNumber(cyHandle:integer; // var lpSerialNumber:byte; // var lpbLength:Word; // bConvertToASCII:BOOL = TRUE // ):Integer; stdcall; external 'CP210xRuntime.dll'; implementation type PCP2102 = ^TCP2102; //function CP210xRT_GetDeviceProductString; external CP2102Runtime name 'CP210xRT_GetDeviceProductString'; procedure SilabsComPorts(out Port: TStringList); var Reg: TRegistry; List: TStringList; i: Integer; w: String; begin Reg := TRegistry.Create; List:= TStringList.Create; try Reg.RootKey:= HKEY_LOCAL_MACHINE; Reg.OpenKey('HARDWARE\DEVICEMAP\SERIALCOMM', false); Reg.GetValueNames(List); for i := 0 to List.Count - 1 do begin w:= copy(List.strings[i],9,7); if w = 'slabser' then begin //device vom Silicon Labs // cmbComPort.Items.Add(Reg.ReadString(List.Strings[i])); Port.Add(Reg.ReadString(List.Strings[i])); end; end; Reg.CloseKey; finally Reg.Free; List.Free; end; end; constructor TCP210X.Create; begin inherited; FList := TList.Create; hUSBDevice := INVALID_HANDLE_VALUE; FillDeviceList; end; destructor TCP210X.Destroy; begin Clear; FList.Free; inherited; end; function TCP210X.Add(const SerNr: string; PortNr: Integer): Integer; var AddPort: TCP2102; begin AddPort.SerNr := SerNr; AddPort.PortNr := PortNr; Result := Add (AddPort) end; function TCP210X.Add(ACP2102: TCP2102): Integer; var NewPt: PCP2102; begin GetMem (NewPt,SizeOf(TCP2102)); NewPt^ := ACP2102; Result := FList.Add(NewPt) end; procedure TCP210X.Clear; var I: Integer; begin for I := Count - 1 downto 0 do FreeMem (FList[I]); FList.Clear; end; function TCP210X.GetCount: Integer; begin Result := FList.Count; end; function TCP210X.GetItems(Index: Integer): TCP2102; begin Result := PCP2102(FList[Index])^ end; procedure TCP210X.GetDeviceData; var Vid, Pid : WORD; //Variables for the Vid, Pid and Serial Number (SN is a String of chars of length SerialLength) SerialString : array[0..CP210x_MAX_SERIAL_STRLEN] of Byte; SerialLength : Byte; i : integer; Port : integer; SerNr : string; begin SerNr := ''; Clear; for i := 0 to devNum - 1 do begin Status := CP210x_Open(i, hUSBDevice); If Status = CP210x_SUCCESS Then begin Status := CP210x_GetDeviceVid(hUSBDevice, Vid); If Status = CP210x_SUCCESS Then begin Status := CP210x_GetDevicePid(hUSBDevice, Pid); If Status = CP210x_SUCCESS Then begin Status := CP210x_GetDeviceSerialNumber(hUSBDevice, SerialString[0], &SerialLength, True); If Status = CP210x_SUCCESS Then begin SerNr := ConvertToString(SerialString[0], SerialLength); end; end; end; end; if(Pid = $34A5) then begin //Нужный нам Pid = 34A5 ? Port := GetPortNumXP2000(Vid, Pid, SerNr); if Port <> -1 then Add(SerNr, Port) else Beep(); end; CP210x_Close (hUSBDevice); end; end; procedure TCP210X.FillDeviceList; begin EnumDevices; if devNum > 0 then GetDeviceData; end; procedure TCP210X.EnumDevices; begin Status := CP210x_GetNumDevices(devNum); end; function TCP210X.ConvertToString(const ConvertArray: array of Byte; ConvertLength: integer):string; var ConvertString : string; i : integer; PByte : ^Byte; begin ConvertString := ''; PByte := @ConvertArray; For i := 0 to ConvertLength - 1 do begin if Chr(PByte^)=#0 then break; if PByte^ = 32 then ConvertString := ConvertString + Chr(95) else ConvertString := ConvertString + Chr(PByte^); inc(PByte); end; result := ConvertString; end; function TCP210X.GetPortNumXP2000(Vid,Pid: WORD; serNum: String): Integer; var HKLMKey, EnumKey, PortKey, VidPidKey :HKEY; VidPidString, prmStr : PChar; valtype : DWORD; p : pointer; portNum : integer; length_of : Cardinal; i: integer; begin for i := 0 to 1 do begin portNum := -1; GetMem(p, 100); if(ERROR_SUCCESS = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\', 0, KEY_READ, HKLMKey)) then begin // KEY_ALL_ACCESS if(ERROR_SUCCESS = RegOpenKey(HKLMKey, 'Enum\\USB\\', EnumKey)) then begin VidPidString := pChar('Vid_' + LowerCase(IntToHex(vid, 2)) + '&Pid_' + LowerCase(IntToHex(pid, 2)) + '&Mi_00\\' + serNum + '_00\\'); if(ERROR_SUCCESS = RegOpenKey(EnumKey, VidPidString, VidPidKey)) then begin if(ERROR_SUCCESS = RegOpenKey(VidPidKey, pChar('Device Parameters\\'), PortKey)) then begin if(ERROR_SUCCESS = RegQueryValueEx(PortKey, pChar('PortName'), nil, @valtype, p, @length_of)) then begin prmStr := p; prmStr[0] := '0'; prmStr[1] := '0'; prmStr[2] := '0'; portNum := StrToInt(string(prmStr)); end; RegCloseKey(PortKey); end; RegCloseKey(VidPidKey); end else begin VidPidString := pChar('Vid_' + LowerCase(IntToHex(vid, 2)) + '&Pid_' + LowerCase(IntToHex(pid, 2)) + '\\' + serNum); // '\\' + serNum if(ERROR_SUCCESS = RegOpenKey(EnumKey, VidPidString, VidPidKey)) then begin if(ERROR_SUCCESS = RegOpenKey(VidPidKey, pChar('Device Parameters'), PortKey)) then begin if(ERROR_SUCCESS = RegQueryValueEx(PortKey, pChar('PortName'), nil, @valtype, p, @length_of)) then begin prmStr := p; prmStr[0] := '0'; prmStr[1] := '0'; prmStr[2] := '0'; portNum := StrToInt(string(prmStr)); end; RegCloseKey(PortKey); end; RegCloseKey (VidPidKey); end; end; RegCloseKey(EnumKey); end; RegCloseKey(HKLMKey); end; RegCloseKey(HKEY_LOCAL_MACHINE); FreeMem(p); end; Result := portNum; end; end.