Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Problem mit TComPort in dll (https://www.delphipraxis.net/210088-problem-mit-tcomport-dll.html)

iphi 28. Feb 2022 08:50

Problem mit TComPort in dll
 
Hallo,

ich versuche gerade verzweifelt die TComPort-Komponente mit ihrem Event Handler in einer dll zum Laufen zu bringen. Und ja, ich habe in der dll eine eigene Message-Loop am Laufen. Zum Test habe ich in der dll zusätzlich einen Timer erzeugt, der auch munter vor sich hin tickt. Nur der Com-Port löst keinen Event bei einlaufenden Daten aus. ???

Hier mein Code:
Der eigentliche dll-code:
Delphi-Quellcode:
library TestDLL;

uses
  SysUtils,
  Classes,
  Windows,
  UCom in 'UCom.pas';

function _Init: boolean; export; cdecl;
begin
{$IFDEF DEBUG_CON}
FreeConsole;
AllocConsole;
writeln('UserDLL function "Init" called');
{$ENDIF}
DecimalSeparator:='.';
Result:=DoInit;
end;

procedure _Close; export; cdecl;
begin
DoClose;
{$IFDEF DEBUG_CON}
writeln('UserDLL function "Close" called');
writeln('Hit return to continue...');
//readln;
FreeConsole;
{$ENDIF}
end;

function _Do:boolean; export; cdecl;
begin
{$IFDEF DEBUG_CON}
writeln('UserDLL function "Do" called.');
{$ENDIF}
result:=DoIt;
end;

exports _Init;
exports _Close;
exports _Do;

begin
end.
Die UCom-Unit:
Delphi-Quellcode:
unit UCom;

interface

uses Classes, Messages, Windows, SysUtils, CPort, ExtCtrls;

type
  THandler=Class
  procedure ComData(Sender: TObject; Count: Integer);
  procedure TimerTick(sender: TObject);
  end;

type
  TMessageLoopThread = class(TThread)
  private
    procedure WndProc(var Msg:TMessage);
  protected
    procedure Execute; override;
  public
    MsgLoopHandle: HWND;
    constructor Create(ThreadPriority: TThreadPriority);
  end;

function DoInit: boolean;
function DoIt: boolean;
Procedure DoClose;

implementation

var
  CP: TComPort;
  handler: THandler;
  MsgLoop: TMessageLoopThread;
  MsgLoopActive: boolean;

  Timer: TTimer;

const DEBUG=true;

constructor TMessageLoopThread.Create(ThreadPriority: TThreadPriority);
begin
  inherited Create(true);
  Priority := ThreadPriority;
  FreeOnTerminate := true;
  MsgLoopActive:=true;
  Suspended:=false;
end;

procedure TMessageLoopThread.Execute;
var msg:Tmsg;
begin
if DEBUG then Writeln('message loop started');
MsgLoopHandle:=allocatehwnd(WndProc); //Windowhandle für Messages
try
 //[weitere Initialisierungen]
 while getMessage(msg,0,0,0) do    //warten auf Message solange nicht WM_QUIT
   begin
     DispatchMessage(msg);           //verteilen auf das entsprechende Fenster (gibt hier allerdings eh nur eins)
   end;
finally
 Deallocatehwnd(MsgLoopHandle);
end;
if DEBUG then Writeln('message loop stopped');
MsgLoopActive:=false;
end;

procedure TMessageLoopThread.WndProc(var Msg:TMessage);
begin
  dispatch(msg);
end;

procedure THandler.ComData(Sender: TObject; Count: Integer);
var
    s: string;
begin
CP.ReadStr(s,count);
write('>>COMHANDLER>> ',s);
end;

var nt: integer=0;
procedure THandler.TimerTick(sender: TObject);
begin
 writeln('Timer: ',nt);
 inc(nt);
end;

function DoInit: boolean;
begin
Handler:=THandler.Create;
MsgLoop:=TMessageLoopThread.Create(TPNormal);
Timer:=TTimer.Create(nil);
Timer.OnTimer:=Handler.TimerTick;
Timer.Interval:=2000;
Timer.Enabled:=true;
CP:=TComPort.Create(nil);
CP.Port:='COM4';
CP.FlowControl.FlowControl:=fcHardware;
CP.FlowControl.ControlDTR:=dtrEnable;
CP.BaudRate:=br115200;
CP.DataBits:=dbEight;
CP.StopBits:=sbOneStopBit;
CP.Parity.Bits:=prNone;
CP.TriggersOnRxChar:=true;
CP.OnRxChar:=Handler.ComData;
Try CP.Open; except end;
if CP.Connected then
  writeln ('DLL connected')
  else
  writeln('DLL NOT connected');
end;

function DoIt: boolean;
begin
if CP.Connected then
  CP.WriteStr('++ver'#13#10);
end;

Procedure DoClose;
begin
Timer.Enabled:=false;
FreeAndNil(Timer);
PostMessage(MsgLoop.MsgLoopHandle,WM_QUIT,0,0);
CP.Close;
FreeAndNil(CP);
while MsgLoopActive do sleep(10);
FreeAndNil(Handler);
end;

end.
Wie gesagt, der Timer ist nur dazu da, die Funktion der MessageLoop zu checken.
Die Funktion DoIt sendet einen String zum Com-Port raus, auf den sofort ein anderer String als Antwort zurück kommt. Ich sehe am angeschlossenen Gerät, dass die Antwort tatsächlich gesendet wird. Der Handler ComData wird aber nicht aufgerufen.

Ich habe exakt denselben ComPort-Code mal direkt in eine GUI gepackt, CP ebenfalls dynamisch erzeugt wie in der dll. Da funktioniert es wie erwartet.

Hat jemand eine Idee, was da schief geht?
Wahrscheinlich sehe ich den Wald vor lauter Bäumen nicht. Danke für Eure Hilfe!

peterbelow 28. Feb 2022 14:15

AW: Problem mit TComPort in dll
 
versuch mal, die TComPort-Komponente innerhalb des threads zu erzeugen.

iphi 28. Feb 2022 15:15

AW: Problem mit TComPort in dll
 
Danke für die Idee, ändert aber leider nichts.
Der ComPort-Handler wird leider nach wie vor nicht ausgelöst.

Die TComPort-Komponente wurde schon länger nicht mehr weiterentwickelt. Gibt es da vielleicht was neueres, mit dem ich mehr Glück haben könnte?

TurboMagic 28. Feb 2022 19:54

AW: Problem mit TComPort in dll
 
Schon Mal TComPortDrv V3.0 aus GetIt probiert?

EmWieMichael 1. Mär 2022 06:30

AW: Problem mit TComPort in dll
 
Die Ergebnisse von DoIt und DoInit sind undefiniert.

iphi 1. Mär 2022 14:54

AW: Problem mit TComPort in dll
 
Zitat:

Schon Mal TComPortDrv V3.0 aus GetIt probiert?
Geht das in Delphi7?

Zitat:

Die Ergebnisse von DoIt und DoInit sind undefiniert.
Weiß ich, soweit bin ich nicht gekommen. Ist für das beschriebene Problem aber belanglos.

iphi 1. Mär 2022 15:54

AW: Problem mit TComPort in dll
 
Habs gefunden.

Delphi-Quellcode:
CP.SyncMethod:=smNone;

...muss gesetzt sein, dann gehts. :-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:56 Uhr.

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