![]() |
Problem mit Kommunikation mit Comport über WinApi
Hallo,
ich habe folgendes Problem: Ich möchte ein Märklin-Interface über einen Comport mittels Win-Api ansteuern. Das funktioniert soweit einwandfrei, aber nur, wenn ich zuvor einmal eine Verbindung mit einem alten C++ Programm hergestellt und wieder geschlossen habe. Bis zu einem Windows-Neustart gibt es dann keine Probleme mehr. Hier mal der Code für ein kleines Testprogramm. (Der Code ist aus dem eigentlichen Programm herauskopiert, es besteht aber dasselbe Problem)
Delphi-Quellcode:
Die Werte von DCB und TimeOut sind identisch mit denen des C++ Programmes.
procedure TForm1.Button1Click(Sender: TObject);
var Port : String; befehl : Char; ComHandle : THandle; DCB : TDCB; TimeOut : TCommTimeouts; i1,i2 : integer; begin Port := 'Com2'; ComHandle := CreateFile(pChar(Port), GENERIC_READ OR GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0); if ComHandle > 0 then begin DCB.DCBlength := SizeOf(DCB); DCB.ByteSize := 8; DCB.Parity := NoParity; DCB.StopBits := TWOSTOPBITS; DCB.BaudRate := 2400; GetCommTimeOuts(ComHandle, TimeOut); TimeOut.ReadIntervalTimeOut := 100; TimeOut.ReadTotalTimeoutMultiplier := 0; TimeOut.ReadTotalTimeoutConstant := 1; TimeOut.WriteTotalTimeoutMultiplier := 0; TimeOut.WriteTotalTimeoutConstant := 0; SetCommTimeouts(ComHandle, TimeOut); end; befehl := chr(97); // Befehl für globales Abschalten der Gleisspannung i1 := FileWrite(ComHandle, befehl, 1); sleep(2000); // Damit Meine langsamen Augen die Anzeige auf der Control Unit auch sehen befehl := chr(96); // Gleisspannung wieder freigeben i2 := FileWrite(ComHandle, befehl, 1); ShowMessage(IntToStr(ComHandle) + ', ' + IntToStr(i1) + ',' + IntTostr(i2)); // Nur zur Überprüfung FileClose(ComHandle); ComHandle := 0; end; Woran kann das liegen? Gruß Hlware |
AW: Problem mit Kommunikation mit Comport über WinApi
Zitat:
das kann garnicht sein: DCB umfasst 28 Felder, nur 5 davon setzt du neu. Ähnlich bei Timeout. Der Unterschied liegt also wohl in den 23 Feldern, die C++ setzt und dein Programm nicht. Z.B. sagst du garnichts über Handshaking. Also vergleiche die Werte in C++ und in deinem Programm. Gruss Reinhard |
AW: Problem mit Kommunikation mit Comport über WinApi
Außerdem gehört IMO das end; zu
Zitat:
|
AW: Problem mit Kommunikation mit Comport über WinApi
Zitat:
Leider kann ich die anderen Felder dort nicht überprüfen, da ich den Turbo C++ Explorer 2006 nicht mehr zum laufen bekomme und mir so nur der vorhandene Code und eine Alte .exe geblieben sind. Zitat:
Delphi-Quellcode:
eingebaut bevor DCB und TimeOuts gesetzt werden.
if ComHandle = INVALID_HANDLE_VALUE then ShowMessage(...
Gruß Hlware |
AW: Problem mit Kommunikation mit Comport über WinApi
Zitat:
Ohne diese Trennung entsteht der berüchtigte ![]() einen unentwirrbaren Klumpen aus Code. Ein kleine Änderung kann dann an anderer Stelle zu unerwünschten Nebeneffekten führen und man verbringt mehr Zeit mit Debuggen als mit Programmieren. :!: Es gibt nur eine saubere Lösung: Du brauchst eine eigene Klasse oder Komponente, die sich nur um die Ansteuerung der seriellen Schnittstelle kümmert. Glücklicherweise gibt es einige gute Komponenten für die serielle Schnittstelle. Du findest sie über die Suchfunktion oder vielleicht hat auch einer der Mitleser eine Empfehlung. |
AW: Problem mit Kommunikation mit Comport über WinApi
Empfehlen kann ich dafür die
![]() Ich habe die serielle Komponente (TAPDPort) in einigen Projekten am Laufen (darunter eins mit ~1500 Installationen) und es gab damit eigentlich noch nie Probleme. |
AW: Problem mit Kommunikation mit Comport über WinApi
Hallo,
Ich hab die Lösung für das Problem gefunden. Nach einigem Auslesen der DCB Felder vor und nach dem Setzen der Eigenschaften bin ich darauf gekommen. Es fehlte einfach ein
Delphi-Quellcode:
Damit ist natürlich klar warum es nicht gehen konnte.
SetCommState(ComHandle,DCB);
Zitat:
Eine Komponente benötige ich im Moment nicht, da mit meiner Klasse alles funktioniert was ich brauche, wenn ich halt das SetCommState nicht vergessen hätte. Vielen Dank für die Hilfe, Gruß Hlware |
AW: Problem mit Kommunikation mit Comport über WinApi
Zitat:
Könntest du vielleicht mal deinen Code hier poste zum ansteuern auslesen und senden der Ports??? |
AW: Problem mit Kommunikation mit Comport über WinApi
Falls er nicht antwortet (bedenke, hlware war seit über einem Jahr nicht mehr hier online/eingeloggt)
Entweder du nimmst eine der fertigen Komponenten (diese nehmen dir einiges/viel Arbeit ab). Ansonsten stehn im MSDN die Infos zu den nötigen APIs, für die Konfiguration des COM-Ports. Wenn man nur CreateFile und ReadFile/WriteFile nutzt, dann werden nur die Standardeinstellungen des entsprechenden Ports verwendet, welche nicht unbedingt passen müssen. Hier findest du die Infos: (auch mal Links nachsehn, was es noch für APIs gibt) ![]() Und nochmals was zum Code.
Delphi-Quellcode:
ist falsch, denn CreateFile liefert INVALID_HANDLE_VALUE, wenn das Öffnen nicht funktionierte,
if ComHandle > 0 then begin
also
Delphi-Quellcode:
gehört dort hin. (die zusätzliche Abfrage, mit der MessageBox, hilft da auch nichts)
if ComHandle <> INVALID_HANDLE_VALUE then begin
|
AW: Problem mit Kommunikation mit Comport über WinApi
Zitat:
Was bedeutet die Ausgabe?? 4294967295, -1, -1 das bekomme ich zurück : bei dem Code ich brauche also nur Create, Read und Write für meine Aufgabe?
Code:
unit main;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, SetupAPI; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var Port : String; befehl : Char; ComHandle : THandle; DCB : TDCB; TimeOut : TCommTimeouts; i1,i2 : integer; begin SetCommState(ComHandle,DCB); Port := 'Com5'; ComHandle := CreateFile(pChar(Port), GENERIC_READ OR GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0); //if ComHandle = INVALID_HANDLE_VALUE then begin ShowMessage('INVALID HANDLE VALUE '); end; if ComHandle <> INVALID_HANDLE_VALUE then begin //if ComHandle > 0 then begin DCB.DCBlength := SizeOf(DCB); DCB.ByteSize := 8; DCB.Parity := NoParity; DCB.StopBits := TWOSTOPBITS; DCB.BaudRate := 2400; GetCommTimeOuts(ComHandle, TimeOut); TimeOut.ReadIntervalTimeOut := 100; TimeOut.ReadTotalTimeoutMultiplier := 0; TimeOut.ReadTotalTimeoutConstant := 1; TimeOut.WriteTotalTimeoutMultiplier := 0; TimeOut.WriteTotalTimeoutConstant := 0; SetCommTimeouts(ComHandle, TimeOut); end; befehl := chr(97); // Befehl für globales Abschalten der Gleisspannung i1 := FileWrite(ComHandle, befehl, 1); sleep(2000); // Damit Meine langsamen Augen die Anzeige auf der Control Unit auch sehen befehl := chr(96); // Gleisspannung wieder freigeben i2 := FileWrite(ComHandle, befehl, 1); ShowMessage(IntToStr(ComHandle) + ', ' + IntToStr(i1) + ',' + IntTostr(i2)); // Nur zur Überprüfung FileClose(ComHandle); ComHandle := 0; end; end. |
AW: Problem mit Kommunikation mit Comport über WinApi
Zitat:
4294967295 = $FFFFFFFF = -1 (als Integer) = INVALID_HANDLE_VALUE Der Port konnte also nicht geöffnet werden. :zwinker: (wie gesagt, das >0 ist vollkommen falsch)
Delphi-Quellcode:
Und schon bekommt man auch die zugehörige Fehlermeldung geliefert.
H := CreateFile(...);
if H <> INVALID_HANDLE_VALUE then begin ... end else RaiseLastOSError; // oder ShowMessage(SysErrorMessage(GetLastError); Zitat:
Ansonsten mußt du den Port entsprechend konfigurieren. (was dir eben die entsprechenden Komponenten erleichtern) PS: Mit dem Befehl (als Char) bekommst du ab Delphi 2009 arge Probleme mit dem Unicode. Tipp: verwende besser den [delphi]-Tag für Quellcodes (der Button mit dem roten Helm). |
AW: Problem mit Kommunikation mit Comport über WinApi
Hallo,
Meine endgültige Lösung sah damals so aus: (Heute würde ich das Grundlegend anders aufbauen, aber es funktionierte)
Delphi-Quellcode:
Verwendet habe ich die Klasse dann so:
unit cComDigital;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls; type cCom = class public availablePorts : TStringList; procedure cComInitialize; function GethCom(): Thandle; procedure SethCom(hCom2 : THandle); procedure ReadAvailableComPorts(); function ConnectToComPort(Connect : Boolean; Port: String):Boolean; function DisconnectComPort(Port: String) : Boolean; function WriteDataToCOMPort(cByte: Integer):Boolean; private hCom: THandle; DCB: TDCB; TimeOut: TCommTimeouts; ChosenPort : String; function SetDCBproperties() : Boolean; function SetcComTimeOut() : Boolean; end; implementation // Klassenimplementierung cCom procedure cCom.cComInitialize; begin SethCom(0); end; procedure cCom.ReadAvailableComPorts; var TestHandle : THandle; i : integer; begin availablePorts := TStringList.Create; for i := 1 to 10 do begin TestHandle := CreateFile(PChar({'\\.\COM'}'COM'+IntToStr(i)),GENERIC_READ or GENERIC_WRITE,0,nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,LongInt(0)); if (TestHandle > 0) then begin availablePorts.Add('COM'+ IntToStr(i)); CloseHandle(TestHandle); end; end; end; function cCom.SetDCBproperties; begin if hCom > 0 then begin GetCommState(GethCom(),DCB); DCB.DCBlength := SizeOf(DCB); DCB.ByteSize := 8; DCB.Parity := NoParity; DCB.StopBits := TWOSTOPBITS; DCB.BaudRate := 2400; DCB.Flags := 5123; { Wenn 2 Pins belegt sind } //4113 DCB.EofChar := #0; DCB.ErrorChar := #0; DCB.EvtChar := #0; DCB.XoffChar := #0; DCB.XoffLim := 0; DCB.XonChar := #0; DCB.XonLim := 0; SetCommState(GethCom(),DCB); end; end; function cCom.SetcComTimeOut; begin if hCom > 0 then begin GetCommTimeOuts(GethCom(), TimeOut); TimeOut.ReadIntervalTimeOut := 100; TimeOut.ReadTotalTimeoutMultiplier := 0; TimeOut.ReadTotalTimeoutConstant := 250; TimeOut.WriteTotalTimeoutMultiplier := 0; TimeOut.WriteTotalTimeoutConstant := 200; SetCommTimeouts(hCom, TimeOut); end; end; function cCom.GethCom; begin GethCom := hCom; end; function cCom.ConnectToComPort(Connect: Boolean; Port : String) : Boolean; Var i : Integer; begin // Mit ComPort (hCom) verbinden if Connect = True then begin i := 0; while (GethCom <= 0) and (i < 10) do begin SethCom((CreateFile(pChar(Port), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0))); inc(i); end; if GethCom() = INVALID_HANDLE_VALUE then begin ShowMessage('Fehler '+IntToStr(GetLastError())+': Schnittstelle konnte nicht geöffnet werden!' + #13#10 + 'Bite die richtige Schnittstelle einstellen!'); ConnectToComPort := false; end else begin // Set DCB, Timeouts etc. if SetDCBproperties() then begin if SetcComTimeOut() then ConnectToComPort := true else begin ShowMessage('Fehler '+IntToStr(GetLastError())+': Timeouts konnten nicht gesetzt werden!'); ConnectToComPort := false; end; end else begin ShowMessage('Fehler '+IntToStr(GetLastError())+': Schnittstellen-Eigenschaften konnten nicht gesetzt werden!'); ConnectToComPort := false; end; end; end else begin FileClose(GethCom()); SethCom(0); end; end; function cCom.DisconnectComPort(Port: String):Boolean; begin ConnectToComPort(false,Port); end; function cCom.WriteDataToCOMPort(cByte: Integer) : Boolean; var i : integer; j : char; begin // Byte an Com Port schicken if GethCom > 0 then begin j := chr(cByte); i := FileWrite(GethCom(), j, 1); if i > 0 then WriteDataToCOMPort := True else WriteDataToCOMPort := False; end; end; procedure cCom.SethCom(hCom2: THandle); begin hCom := hCom2; end; end.
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject); begin cCom1 := cDigital.Create(); cCom1.cComInitialize; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin if cCom1.GethCom > 0 then begin FileClose(cCom1.GethCom); cCom1.SethCom(0); end; end; |
AW: Problem mit Kommunikation mit Comport über WinApi
Zitat:
Habe Delphi 7 daher egal.. Ok das heisst ich benutze zum Beispiel von den Comport die komponente zum einstellen der werte und dann benutze ich create , read, write, close, zum öffnen schließen lesen und schreiben habe jetzt folgende Hinweise und warnungen kompilierne tut er keine fehler nur hinweise warnungen
Delphi-Quellcode:
[Warnung] main.pas(38): Unsicherer Typ 'PChar'
[Hinweis] main.pas(72): Auf 'ComHandle' zugewiesener Wert wird niemals benutzt [Warnung] main.pas(36): Variable 'ComHandle' ist möglicherweise nicht initialisiert worden |
AW: Problem mit Kommunikation mit Comport über WinApi
Hallo,
Habe einen wichtigen Teil vergessen.
Delphi-Quellcode:
Das mein Code Probleme mit Unicode machen könnte kann durchaus sein, er ist damals auf Turbo Delphi 2006 entstanden.
procedure TForm1.ActionConnectToComExecute(Sender: TObject);
Var Portname : String; begin // ConnectToComPort; PortName := 'Com'+IntToStr(ComPortNr); if ActionConnectToCom.Checked then Begin // Checkbox im Menü if cCom1.ConnectToComPort(true, PortName) then StatusBar1.Panels[1].Text := PortName + ' Handle: ' + IntToStr(cCom1.GethCom) // Statusmeldung else ActionConnectToCom.Checked := false; end else begin cCom1.DisconnectComPort('Com2'); StatusBar1.Panels[1].Text := 'Disconnnect' + 'Handle: ' + IntToStr(cCom1.GethCom); end; end; Tut mir leid, dass er nicht so gut kommentiert ist, dass hielt ich früher noch nicht für nötig. Ich hoffe es hilft etwas weiter |
AW: Problem mit Kommunikation mit Comport über WinApi
Zitat:
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:47 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz