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!