Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Auflistung aller 'verfügbaren' Comports (https://www.delphipraxis.net/85992-auflistung-aller-verfuegbaren-comports.html)

DelphiManiac 7. Feb 2007 15:37


Auflistung aller 'verfügbaren' Comports
 
Hallo,

ich habe folgendes Problem, ich nutzte die Komonente TComport aus dem Package bzw der Unit CPort.
Das ist eine Komponente die den Zugriff auf die Comports kapselt.

Es gibt hier eine Funktion die sich EnumComPorts nennt, ihr übergibt man eine Stringlist und bekommt sie gefüllt mit den
im System vorhandenen Comports zurück.

Beispiel:
Delphi-Quellcode:
var
 ComPorts:TStringList;
begin
..
Comports:=TStringList.Create;
EnumComPorts(Comports); // Gibt mir die vorhandenen Comports zurück
..
Das ist ja auch super, nur wenn ich mir jetzt die Comports in eine Auswahl a la Combobox oder Listbox lade habe ich folgendes Prob.
Es werden anscheinend alle Comports (die das System in der Registry hat) angezeigt, auch die die vielleicht schon durch ein anderes Programm in Benutztung sind (sehr unschön). Denn was bringt mir COM1 wenn sie belegt ist.

Ich wollte euch fragen, wie die Ports am Besten rausfiltern kann.
Bzw. ob ich eine andere Methode dafür nutzte.

hier der Funktion
EnumComports
Delphi-Quellcode:

procedure EnumComPorts(Ports: TStrings);
var
  KeyHandle: HKEY;
  ErrCode, Index: Integer;
  ValueName, Data: string;
  ValueLen, DataLen, ValueType: DWORD;
  TmpPorts: TStringList;
begin
  ErrCode := RegOpenKeyEx(
    HKEY_LOCAL_MACHINE,
    'HARDWARE\DEVICEMAP\SERIALCOMM',
    0,
    KEY_READ,
    KeyHandle);

  if ErrCode <> ERROR_SUCCESS then
    raise EComPort.Create(CError_RegError, ErrCode);

  TmpPorts := TStringList.Create;
  try
    Index := 0;
    repeat
      ValueLen := 256;
      DataLen := 256;
      SetLength(ValueName, ValueLen);
      SetLength(Data, DataLen);
      ErrCode := RegEnumValue(
        KeyHandle,
        Index,
        PChar(ValueName),
{$IFDEF DELPHI_4_OR_HIGHER}
        Cardinal(ValueLen),
{$ELSE}
        ValueLen,
{$ENDIF}
        nil,
        @ValueType,
        PByte(PChar(Data)),
        @DataLen);

      if ErrCode = ERROR_SUCCESS then
      begin
        SetLength(Data, DataLen - 1);
        TmpPorts.Add(Data);
        Inc(Index);
      end
      else
        if ErrCode <> ERROR_NO_MORE_ITEMS then
          raise EComPort.Create(CError_RegError, ErrCode);

    until (ErrCode <> ERROR_SUCCESS) ;

    TmpPorts.Sort;
    Ports.Assign(TmpPorts);
  finally
    RegCloseKey(KeyHandle);
    TmpPorts.Free;
  end;

end;
Vielen Dank

Der_Unwissende 7. Feb 2007 15:52

Re: Auflistung aller 'verfügbaren' Comports
 
Zitat:

Zitat von DelphiManiac
Das ist ja auch super, nur wenn ich mir jetzt die Comports in eine Auswahl a la Combobox oder Listbox lade habe ich folgendes Prob.
Es werden anscheinend alle Comports (die das System in der Registry hat) angezeigt, auch die die vielleicht schon durch ein anderes Programm in Benutztung sind (sehr unschön). Denn was bringt mir COM1 wenn sie belegt ist.

Ich wollte euch fragen, wie die Ports am Besten rausfiltern kann.
Bzw. ob ich eine andere Methode dafür nutzte.

Hi,
also an sich möchte ich hier (wieder?) die TComPort-Komponente pushen und sagen, dass das ja eigentlich genau das ist, was ich auch erwarten würde. Die listet alle vorhandenen Ports auf.
Natürlich kannst Du schauen ob ein Port schon belegt ist (versuche den einfach zu öffnen, während jmd. anderes das getan hat), aber das schützt Dich auch nur bedingt. Hängt an COM1 ein Gerät das angeschaltet ist, aber dessen Software noch nicht gestartet wurde, so hast Du auch das Problem, dass COM1 als "frei" erkannt werden würde. Wie gesagt, das einfache Filtern kannst Du ohne Probleme durchführen indem Du einfach jeden Port den Du findest öffnest. Klappt das ohne Probleme ist der nicht in Verwendung.

Hast Du ein Identifikations-Kommando zur Verfügung, so kannst Du natürlich so auch gleich automatisch alle Geräte ermitteln, die Du anbieten möchtest. Der Weg dürfte dann auch klar sein, Du versuchst einfach alle Ports zu öffnen und sendest auf jedem dieses Kommando, kommt eine (erwartete) Antwort, wird das richtige dranhängen. Der Weg ist allerdings riskanter, da Du natürlich nicht weißt was dein Kommando bei fremden Geräten auslöst. Zudem kommt dann das Problem der Unterscheidung zweier Baugleicher Geräte hinzu.

Gruß Der Unwissende

DelphiManiac 7. Feb 2007 16:53

Re: Auflistung aller 'verfügbaren' Comports
 
@Der_Unwissende:

Hi lange nix voneinander gehört

mich interessieren hierbei nur die Comports, die die Windows API auch wirklich öffnen kann.
D.h. es kann ja noch eine virtuelle Comport Leiche in der Registry stehen z.B.: Com10,
diese aber gar nicht mehr im System ist (USB auf RS232 ist ausgesteckt), dann wäre es nicht sinvoll diese anzuzeigen.
Bzw. wenn ein Programm die Schnittstelle belegt, dann brauch diese auch nicht in meiner Liste.

Ich habe es jetzt so gelöst:
Ich filtere die Liste und gucke ob die API darauf zugreifen kann, wenn nicht, dann entferne ich den Por aus der Liste.

Delphi-Quellcode:
  for I := 0 to _PList.Count - 1 do // Stringlist mit zB.['COM1','COM3',...]
  begin
    hPort := CreateFile( PChar( _PList.Strings[i] ),
      GENERIC_READ or GENERIC_WRITE,
      0,
      nil,
      OPEN_EXISTING,
      0,
      0 );
    if ( hPort = INVALID_HANDLE_VALUE ) then
      _PList.Delete(i);
    CloseHandle( hPort );
  end;
Ich denke so kann man es machen, oder?
Gruß
DelphiManiac

DP-Maintenance 7. Feb 2007 20:11

DP-Maintenance
 
Dieses Thema wurde von "sakura" von "Object-Pascal / Delphi-Language" nach "Windows API / MS.NET Framework API" verschoben.

Reinhard Kern 8. Feb 2007 01:01

Re: Auflistung aller 'verfügbaren' Comports
 
Zitat:

Zitat von DelphiManiac
...
mich interessieren hierbei nur die Comports, die die Windows API auch wirklich öffnen kann.
D.h. es kann ja noch eine virtuelle Comport Leiche in der Registry stehen z.B.: Com10,
diese aber gar nicht mehr im System ist (USB auf RS232 ist ausgesteckt), dann wäre es nicht sinvoll diese anzuzeigen.
Bzw. wenn ein Programm die Schnittstelle belegt, dann brauch diese auch nicht in meiner Liste.
...
Ich denke so kann man es machen, oder?
Gruß
DelphiManiac

Hallo,

ich habe an meinem Entwicklungssystem verschiedene Programmiergeräte, z.B. von Microchip an COM1. COM1 ist aber frei, wenn die Entwicklungsumgebung von Microchip nicht läuft, und selbst wenn sie läuft, belegt sie COM1 nur, wenn ich im Menu "Programmer Enable" wähle. Das gilt in ähnlicher Form für alle Programme, die COM-Ports benutzen, einschliesslich meiner eigenen. Es gibt daher praktisch keine Möglichkeit festzustellen, ob ein COM-Port "benutzt" wird, nicht einmal wenn man alle auf dem Rechner installierten Programme starten würde.

Gruss Reinhard

DelphiManiac 8. Feb 2007 12:19

Re: Auflistung aller 'verfügbaren' Comports
 
@Reinhard Kern:

Hallo,

ja aber wenn ich versuche über CreateFile den Port zu öffnen und dieses nicht klappt,
Beispiel weil, bei mir ein In Circuit Debugger am Port hängt, der den Port für sich reserviert (geöffnet) hat,
dann kann ich diesen Port(der ja aktuell nicht zurverfügung steht) aus meiner Schnittstellenauswahl löschen.

Gruß
DelphiManiac

DelphiManiac 8. Feb 2007 12:22

Re: Auflistung aller 'verfügbaren' Comports
 
@Der_Unwissende

Hallo,
ja ich verstehe deine Idee, aber mein anliegen hier ist viel einfacher,
ich will ja nicht wissen ob am Port das dranhängt was ich vermute (irgendein Gerät mit dem ich kommunizieren will) sondern,
ich interessiere mich in erster Linie nur für die vorhandenen Ports, die ich auch bedienen (also öffnen) kann. Geht dieses nicht, so macht es auch an der Stelle keinen Sinn diesen Port aufzuführen.

Gruß
DelphiManiac

Robert Marquardt 8. Feb 2007 12:43

Re: Auflistung aller 'verfügbaren' Comports
 
Da hilft nur der Versuch den COM-Port mit CreateFile und exklusivem Zugriff probeweise zu oeffnen.
Leichen von virtuellen COM-Ports sollte es eigentlich nicht geben.

Gehstock 8. Feb 2007 13:53

Re: Auflistung aller 'verfügbaren' Comports
 
Ich mach dat so
Delphi-Quellcode:
var
  i:integer;
begin

  ComPort.Items.Clear; //combobox
  for I := 1 to 30 do
    begin
    iComNum := I;
    if OpenCom(False) then
    begin
      ComPort.Items.Add(Format('COM%d',[I]));
      CloseCom;
    end;
    Application.ProcessMessages;
  end;   // for
  ComPort.ItemIndex := ComPort.Items.Count-1;
end;

Delphi-Quellcode:
function OpenCom(Mode:boolean) : boolean;
var
dw : dword;
begin
 result:=FALSE;
  if hCom<>INVALID_HANDLE_VALUE then CloseCom;
  if FlgOvrlp then dw:=FILE_FLAG_OVERLAPPED
  else dw:=FILE_ATTRIBUTE_NORMAL;
  hCom:=CreateFile(PChar('\\?\COM'+IntToStr(iComNum)),GENERIC_READ or GENERIC_WRITE,0,nil,OPEN_EXISTING,dw,0);
  if hCom<>INVALID_HANDLE_VALUE then begin
   SetupComm(hCom,$20000,$20000); //8192, 8192); // Rd , Wr
   if GetComDCB then begin
    if Mode then DCB.Flags := (DCB.Flags and $ffff8000) or $0001
    else DCB.Flags := (DCB.Flags and $ffff8000) or $0011;  //$1011;
    DCB.ByteSize := 8;
    DCB.Parity := 0;
    DCB.StopBits := 0;
    DCB.BaudRate := iComBaud;
    if SetComDCB then begin
     ComTimeouts.ReadIntervalTimeout:=20; //0
     ComTimeouts.ReadTotalTimeoutMultiplier:=1; //0
     ComTimeouts.ReadTotalTimeoutConstant:=200; //200
     ComTimeouts.WriteTotalTimeoutMultiplier:=0;//MAXDWORD;
     ComTimeouts.WriteTotalTimeoutConstant:=0;//MAXDWORD;
     if SetComTimeouts then begin
      iOldComOpen:=iComNum;
      iOldComBaud:=iComBaud;
      if Mode then begin
       sleep(75);
       EscapeComFunction(SETRTS);
       sleep(25);
       EscapeComFunction(SETDTR);
      end
      else begin
       sleep(75);
       EscapeComFunction(SETRTS);
      end;
//      sleep(300);
//      PurgeCom(PURGE_TXCLEAR or PURGE_RXCLEAR);
      result := TRUE;
     end;
    end;
   end;
  end;
end;

shmia 8. Feb 2007 14:10

Re: Auflistung aller 'verfügbaren' Comports
 
Zitat:

Zitat von DelphiManiac
Ich filtere die Liste und gucke ob die API darauf zugreifen kann, wenn nicht, dann entferne ich den Por aus der Liste.
Delphi-Quellcode:
  for I := 0 to _PList.Count - 1 do // Stringlist mit zB.['COM1','COM3',...]

Würde schon gehen; nur musst du die Liste zum Löschen rückwärts durchlaufen, da sich beim Löschen auch die Indizies ändern. :warn:


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:40 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz