Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.14.84] |
|
Сообщ.
#1
,
|
|
|
Перечисление последовательных портов
Вообще говоря, это просто сервис: показать список имеющихся COM портов, для выбора. На мой взгляд проще всего это сделать через WMI. Для этого сначала требуется получить (не создать!) COM-объект по URI 'winmgmts:\\.\root\CIMV2' и запросить у него список портов, с помощью запроса. '\\.' на самом деле здесь текуший компьютер, можно указать имя другой рабочей станции, но это уже требует привилегий администратора. Далее у WMI надо запросить список портов, делается это запросом к объекту Win32_SerialPort: 'SELECT * FROM Win32_SerialPort', который возвращает коллекцию, описывающую именно serial ports. Остается только пройти по коллекции и обратиться к свойствам ее элементов, в частности caption выдает читаемое имя порта, а DeviceID - его имя, COM1, COM2 и т.д. Разумеется, в современных версиях Delphi удобно создать нумератор для прохода по этой коллекции. Собственно, это все, что нужно сделать, исходник короткий, я соединяюсь с WMI поздним связыванием, поэтому моуль получился автономным: unit EnumSerialPorts; { Модуль перечисления последовательных портов. Используется WMI, берется минимальная информация. $Author: Roman $ $Date:: 2012-02-21 15:37:00#$ } interface uses SysUtils, Generics.Collections, ActiveX; type TSerialPortInfo = record Caption: string; DeviceID: string; MaxBaudRate: cardinal; ProviderType: string; end; TSerialPortEnum = class(TEnumerable<TSerialPortInfo>) strict private FWMIService: Variant; protected function DoGetEnumerator: TEnumerator<TSerialPortInfo>; override; type TPortEnum = class(TEnumerator<TSerialPortInfo>) strict private FEnum: IEnumVARIANT; FCurrentElem: OleVariant; protected function DoGetCurrent: TSerialPortInfo; override; function DoMoveNext: Boolean; override; public constructor Create(Enum: IEnumVariant); destructor Destroy; override; end; public constructor Create; destructor Destroy; override; end; implementation uses COMObj, Variants; //стандартные флаги для запроса const wbemFlagForwardOnly = $20; wbemFlagBidirectional = $0; wbemFlagReturnImmediately = $10; wbemFlagReturnWhenComplete = $0; wbemQueryFlagPrototype = $2; wbemFlagUseAmendedQualifiers = $20000; function GetVariantEnumerator(obj: Variant): IEnumVariant; var Enum: IUnknown; begin Enum := obj._NewEnum; OleCheck(Enum.QueryInterface(IEnumVariant, Result)); end; function GetObject(const ObjName: WideString): Variant; var Temp: IDispatch; begin OleCheck(CoGetObject(PWideString(ObjName), nil, IDispatch, @Temp)); Result := Temp; end; { TSerialPortList } const strMonName: WideString = 'winmgmts:\\.\root\CIMV2'; strQueryList: WideString = 'SELECT * FROM Win32_SerialPort'; constructor TSerialPortEnum.Create; begin inherited; FWMIService := GetObject(strMonName); end; destructor TSerialPortEnum.Destroy; begin FWMIService := Unassigned; inherited; end; function TSerialPortEnum.DoGetEnumerator: TEnumerator<TSerialPortInfo>; var Items: OleVariant; begin Items := FWMIService.ExecQuery(strQueryList, 'WQL', wbemFlagForwardOnly); Result := TPortEnum.Create(GetVariantEnumerator(Items)); end; { TSerialPortList.TPortEnum } constructor TSerialPortEnum.TPortEnum.Create(Enum: IEnumVariant); begin inherited Create; FEnum := Enum; end; destructor TSerialPortEnum.TPortEnum.Destroy; begin FEnum := nil; inherited; end; function TSerialPortEnum.TPortEnum.DoGetCurrent: TSerialPortInfo; begin Result.Caption := FCurrentElem.Caption; Result.DeviceID := FCurrentElem.DeviceID; Result.MaxBaudRate := FCurrentElem.MaxBaudRate; Result.ProviderType := FCurrentElem.ProviderType; end; function TSerialPortEnum.TPortEnum.DoMoveNext: Boolean; var Fetched: Cardinal; begin Result := (FEnum.Next(1, FCurrentElem, Fetched) = S_OK); end; end. Пример использования: var PortInfo: TSerialPortInfo; PortEnum: TSerialPortEnum; begin PortEnum := TSerialPortEnum.Create; try for PortInfo in PortEnum do ComboBox1.Items.Add(PortInfo.DeviceID); finally PortEnum.Free; end; |
Сообщ.
#2
,
|
|
|
Интересно, а FindFirst/FindNext порты перечисляет? Ни разу не пробовал, но пайпы и мэйлслоты точно прекрасно перечисляет
|
Сообщ.
#3
,
|
|
|
Тоже стало интересно. Накодил:
procedure EnumComPorts(Ports: TStrings); procedure GetComPort(i: Integer); var sr: TSearchRec; begin if FindFirst('\.\COM' + IntToStr(i), FILE_ATTRIBUTE_NORMAL, sr) = 0 then begin repeat Ports.Add(sr.Name); Inc(i); GetComPort(i); until FindNext(sr) <> 0; FindClose(sr); end; end; begin GetComPort(1); end; Пример: EnumComPorts(Memo1.Lines); |
Сообщ.
#4
,
|
|
|
Filka
это не коректный код. вполне возможна ситуация,когда существует ком2, но не существует ком1 |
Сообщ.
#5
,
|
|
|
Цитата jack128 @ это не коректный код. вполне возможна ситуация,когда существует ком2, но не существует ком1 Это да. Правда, у мя работает. Но только с ком1 (хотя комов - четыре). Но это, думаю, сути не меняет. Вообще, код конечно пользительный, но его изменить надо бы, ИМХО.. |
Сообщ.
#6
,
|
|
|
procedure EnumComPorts(Ports: TStrings); const PortsCount = 255; var PortNumber: Integer; procedure GetComPort(i: Integer); var sr: TSearchRec; begin if FindFirst('\.\COM' + IntToStr(i), FILE_ATTRIBUTE_NORMAL, sr) = 0 then begin repeat Ports.Add(sr.Name); Inc(i); PortNumber := i; GetComPort(i); until FindNext(sr) <> 0; FindClose(sr); end; end; begin PortNumber := 1; while PortNumber < PortsCount do begin GetComPort(PortNumber); Inc(PortNumber); end; end; Пример: EnumComPorts(Memo1.Lines); |