Einzelnen Beitrag anzeigen

iphi

Registriert seit: 13. Feb 2009
262 Beiträge
 
Delphi 7 Personal
 
#1

Problem mit TComPort in dll

  Alt 28. Feb 2022, 08:50
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!
  Mit Zitat antworten Zitat