philly_tee
asked on
Comport DLL-type interface with streaming data
Hi all,
I have been tasked with creating a DLL-like system that interacts with a device connected to a Com Port, which is constantly streaming data. The DLL will be used by other developers using all different languages. Thinking about it, 'Device Driver' springs to mind.
Anyway, my problem is that by nature, DLLs are a request -> response type setup, whereby as soon as a DLL function returns, the state is lost. I have a TComPort component on a form in the DLL, which probably isn't the best idea, and If a modally shoow the form everything works fine. Ideally i'd like to not use the form at all, but so far haven't been able to get it to work.
What I need, is a way of constantly collecting the streaming data from the com port, and then passing that back to the parent application without the parent application having to constantly call a DLL function. I have callbacks working fine, which allows me to trigger events for the parent application, I just can't think of a way to keep the innards of the DLL active so as to be always listening to the com port.
I know nothing about making device drivers, had a quick look at how to build activex controls (gave up), and thought I could write a full app with COM automation for the parent app but trying to stay away from that.
Your suggestions please?
Thanks
Philip
I have been tasked with creating a DLL-like system that interacts with a device connected to a Com Port, which is constantly streaming data. The DLL will be used by other developers using all different languages. Thinking about it, 'Device Driver' springs to mind.
Anyway, my problem is that by nature, DLLs are a request -> response type setup, whereby as soon as a DLL function returns, the state is lost. I have a TComPort component on a form in the DLL, which probably isn't the best idea, and If a modally shoow the form everything works fine. Ideally i'd like to not use the form at all, but so far haven't been able to get it to work.
What I need, is a way of constantly collecting the streaming data from the com port, and then passing that back to the parent application without the parent application having to constantly call a DLL function. I have callbacks working fine, which allows me to trigger events for the parent application, I just can't think of a way to keep the innards of the DLL active so as to be always listening to the com port.
I know nothing about making device drivers, had a quick look at how to build activex controls (gave up), and thought I could write a full app with COM automation for the parent app but trying to stay away from that.
Your suggestions please?
Thanks
Philip
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
firat of all reading is not everything:) test and debug test and debug.... :)
sample... look into Borland\Delphi\Demos\Threa ds
I will post something here with comport but I cant promise to do it today... you know saturday, carnival:)
ziolko.
sample... look into Borland\Delphi\Demos\Threa
I will post something here with comport but I cant promise to do it today... you know saturday, carnival:)
ziolko.
ASKER
Ok I've had a play and managed to get it to work in a stardard app. As soon as I convert the thread stuff to dll I don't get callbacks from the ComPort.... Not sure if the thread is closing down as soon as initport is finishing??
I'm using a component I found somewhere in my travels... TComPort by Dirk Claessens.
Heres my code:
I'm using a component I found somewhere in my travels... TComPort by Dirk Claessens.
Heres my code:
DLL:
library Project1;
uses
SysUtils,
Classes,
Forms,
uThread in 'uThread.pas';
var
ComThread : TComThread;
{$R *.res}
procedure InitPort(clientFunc : TCallBackFunction); stdcall;
begin
ComThread := TComThread.Create(True, clientFunc);
end;
procedure OpenPort; stdcall;
begin
ComThread.Resume;
end;
exports InitPort, OpenPort;
end.
unit uThread;
interface
uses
Classes, ComPort, Dialogs;
type
TCallBackFunction = procedure(data : string);
TComThread = class(TThread)
ComPort1 : TComPort;
private
{ Private declarations }
CallBackProc : TCallBackFunction;
Temp : String;
Procedure SendBackData;
procedure ComPort1ReceiveCallBack(Data: String);
protected
procedure Execute; override;
public
constructor Create(CreateSuspended : Boolean; ReturnProc : TCallBackFunction);
end;
implementation
procedure TComThread.ComPort1ReceiveCallBack(Data: String);
begin
// Put the data into a variable as I don't know how to get it to the callback caller any other way
Temp := Data;
Synchronize(SendBackData);
end;
constructor TComThread.Create(CreateSuspended: Boolean; ReturnProc : TCallBackFunction);
begin
Inherited Create(CreateSuspended);
CallBackProc := ReturnProc;
ComPort1 := TComPort.Create(ComPort1);
ComPort1.Port := 'COM4';
ComPort1.Baud := 57600;
ComPort1.ReceiveCallBack := ComPort1ReceiveCallBack;
end;
procedure TComThread.Execute;
begin
ComPort1.Open;
end;
procedure TComThread.SendBackData;
begin
// Call the parent app's callback function and give it some data
CallBackProc(Temp);
end;
end.
Calling Application:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, unit2;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
ComThread : TComThread;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure reply(Data : String);
begin
// This is the callback function which is called by the dll.
Form1.Memo1.Lines.Append(Data);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
// Get the dll to create it's thread, pass in the callback function
ComThread := TComThread.Create(True, reply);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
// Open the com port and start receiving data
ComThread.Resume;
end;
end.
Hi,
I don't have TComPort component so I used timer instead:
DLL:
library COMDLL;
uses
SysUtils,
Classes,
Forms,
uComThread in 'uComThread.pas';
var
ComThread : TComThread;
{$R *.res}
procedure OpenPort(CallBack : TCallBackFunction); stdcall;
begin
if not Assigned(ComThread) then
ComThread := TComThread.Create(False, CallBack);
end;
procedure ClosePort;stdcall;
begin
FreeAndNil(ComThread);
end;
exports
OpenPort name 'OpenPort',
ClosePort name 'ClosePort';
end.
uComThread.pas:
unit uComThread;
interface
uses
Classes, {ComPort, }Dialogs, Windows, ExtCtrls;
type
TCallBackFunction = procedure(Data: PChar);stdcall;
TComThread = class(TThread)
private
// FComPort: TComPort;
FTimer: TTImer;
CallBackProc : TCallBackFunction;
FBuffer: PChar;
procedure SendBackData;
procedure ComPort1ReceiveCallBack(Da ta: string);
procedure Timer1Timer(Sender: TObject);
function ProcessMessage(var Msg: TMsg):Boolean;
procedure ProcessMessages;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended : Boolean; ReturnProc : TCallBackFunction);reintro duce;
destructor Destroy;override;
end;
implementation
uses SysUtils;
procedure TComThread.ComPort1Receive CallBack(D ata: String);
begin
ReallocMem(FBuffer, Length(Data) + 1);
StrPCopy(FBuffer, Data);
Synchronize(SendBackData);
end;
constructor TComThread.Create(CreateSu spended: Boolean; ReturnProc : TCallBackFunction);
begin
inherited Create(CreateSuspended);
FTimer := TTimer.Create(nil);
FTimer.OnTimer := Timer1Timer;
FTimer.Interval := 1000;
FTimer.Enabled := True;
CallBackProc := ReturnProc;
{ FComPort := TComPort.Create(ComPort1);
FComPort.Port := 'COM4';
FComPort.Baud := 57600;
FComPort.ReceiveCallBack := ComPort1ReceiveCallBack;}
end;
destructor TComThread.Destroy;
begin
CallBackProc := nil;
// FreeAndNil(FComPort);
inherited Destroy;
end;
procedure TComThread.Execute;
begin
// FComPort.Open;
while not Terminated do begin
ProcessMessages;
Sleep(1);
end;
end;
function TComThread.ProcessMessage( var Msg: TMsg): Boolean;
begin
Result := False;
if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
begin
Result := True;
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end;
procedure TComThread.ProcessMessages ;
var Msg: TMsg;
begin
while ProcessMessage(Msg) do ;
end;
procedure TComThread.SendBackData;
begin
if Assigned(CallBackProc) then
CallBackProc(FBuffer);
end;
procedure TComThread.Timer1Timer(Sen der: TObject);
begin
ComPort1ReceiveCallBack('i t is now ' + FormatDateTime('hh:mm:ss', Now));
end;
end.
and EXE:
unit fMainForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject); private
{ Private declarations }
public
{ Public declarations }
end;
TCallBackFunction = procedure(Data: PChar);stdcall;
var
Form1: TForm1;
procedure OpenPort(CallBack : TCallBackFunction); stdcall;
procedure ClosePort;stdcall;
implementation
{$R *.dfm}
procedure OpenPort;external 'COMDLL.DLL' name 'OpenPort';
procedure ClosePort;external 'COMDLL.DLL' name 'ClosePort';
procedure reply(Data : PChar);stdcall;
begin
Form1.Memo1.Lines.Add(Data );
end;
procedure TForm1.Button1Click(Sender : TObject);
begin
OpenPort(@reply);
end;
procedure TForm1.Button2Click(Sender : TObject);
begin
ClosePort;
end;
end.
ziolko.
I don't have TComPort component so I used timer instead:
DLL:
library COMDLL;
uses
SysUtils,
Classes,
Forms,
uComThread in 'uComThread.pas';
var
ComThread : TComThread;
{$R *.res}
procedure OpenPort(CallBack : TCallBackFunction); stdcall;
begin
if not Assigned(ComThread) then
ComThread := TComThread.Create(False, CallBack);
end;
procedure ClosePort;stdcall;
begin
FreeAndNil(ComThread);
end;
exports
OpenPort name 'OpenPort',
ClosePort name 'ClosePort';
end.
uComThread.pas:
unit uComThread;
interface
uses
Classes, {ComPort, }Dialogs, Windows, ExtCtrls;
type
TCallBackFunction = procedure(Data: PChar);stdcall;
TComThread = class(TThread)
private
// FComPort: TComPort;
FTimer: TTImer;
CallBackProc : TCallBackFunction;
FBuffer: PChar;
procedure SendBackData;
procedure ComPort1ReceiveCallBack(Da
procedure Timer1Timer(Sender: TObject);
function ProcessMessage(var Msg: TMsg):Boolean;
procedure ProcessMessages;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended : Boolean; ReturnProc : TCallBackFunction);reintro
destructor Destroy;override;
end;
implementation
uses SysUtils;
procedure TComThread.ComPort1Receive
begin
ReallocMem(FBuffer, Length(Data) + 1);
StrPCopy(FBuffer, Data);
Synchronize(SendBackData);
end;
constructor TComThread.Create(CreateSu
begin
inherited Create(CreateSuspended);
FTimer := TTimer.Create(nil);
FTimer.OnTimer := Timer1Timer;
FTimer.Interval := 1000;
FTimer.Enabled := True;
CallBackProc := ReturnProc;
{ FComPort := TComPort.Create(ComPort1);
FComPort.Port := 'COM4';
FComPort.Baud := 57600;
FComPort.ReceiveCallBack := ComPort1ReceiveCallBack;}
end;
destructor TComThread.Destroy;
begin
CallBackProc := nil;
// FreeAndNil(FComPort);
inherited Destroy;
end;
procedure TComThread.Execute;
begin
// FComPort.Open;
while not Terminated do begin
ProcessMessages;
Sleep(1);
end;
end;
function TComThread.ProcessMessage(
begin
Result := False;
if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
begin
Result := True;
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end;
procedure TComThread.ProcessMessages
var Msg: TMsg;
begin
while ProcessMessage(Msg) do ;
end;
procedure TComThread.SendBackData;
begin
if Assigned(CallBackProc) then
CallBackProc(FBuffer);
end;
procedure TComThread.Timer1Timer(Sen
begin
ComPort1ReceiveCallBack('i
end;
end.
and EXE:
unit fMainForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject); private
{ Private declarations }
public
{ Public declarations }
end;
TCallBackFunction = procedure(Data: PChar);stdcall;
var
Form1: TForm1;
procedure OpenPort(CallBack : TCallBackFunction); stdcall;
procedure ClosePort;stdcall;
implementation
{$R *.dfm}
procedure OpenPort;external 'COMDLL.DLL' name 'OpenPort';
procedure ClosePort;external 'COMDLL.DLL' name 'ClosePort';
procedure reply(Data : PChar);stdcall;
begin
Form1.Memo1.Lines.Add(Data
end;
procedure TForm1.Button1Click(Sender
begin
OpenPort(@reply);
end;
procedure TForm1.Button2Click(Sender
begin
ClosePort;
end;
end.
ziolko.
but if you get rid of timer and un-comment comport stuff it should work.
note about ProcessMessages in uComThread, test it with connection to port normally it is not needed but if I remember correctly it might be needed with COM, just not sure so test it yourself
ziolko
note about ProcessMessages in uComThread, test it with connection to port normally it is not needed but if I remember correctly it might be needed with COM, just not sure so test it yourself
ziolko
ASKER
Thanks for the code. Timer works fine (not that we ever doubted that), however I stall can't get the callbacks from the com port.
constructor TComThread.Create(CreateSu spended: Boolean; ReturnProc : TCallBackFunction);
begin
inherited Create(CreateSuspended);
FComPort := TComPort.Create(nil);
FComPort.Port := 'COM4';
FComPort.Baud := 57600;
CallBackProc := ReturnProc;
FComPort.ReceiveCallBack := ComPort1ReceiveCallBack;
FComPort.OnPortOpen := Timer1Timer;
FComPort.Open;
end;
OnPortOpen is firing, but nothing from the callback function.
I can see through a port monitor (portmon) that initialisation data transfer occurs, but no actual data from the connected device.
Works fine if I do a test app with the same comport config.
Any ideas?
Philip
constructor TComThread.Create(CreateSu
begin
inherited Create(CreateSuspended);
FComPort := TComPort.Create(nil);
FComPort.Port := 'COM4';
FComPort.Baud := 57600;
CallBackProc := ReturnProc;
FComPort.ReceiveCallBack := ComPort1ReceiveCallBack;
FComPort.OnPortOpen := Timer1Timer;
FComPort.Open;
end;
OnPortOpen is firing, but nothing from the callback function.
I can see through a port monitor (portmon) that initialisation data transfer occurs, but no actual data from the connected device.
Works fine if I do a test app with the same comport config.
Any ideas?
Philip
will take a look at this one more.
do you use ComPort from Sourceforge.net?
ziolko.
do you use ComPort from Sourceforge.net?
ziolko.
ASKER
Thanks. Appreciate all the time you're spending on this!
I use TComPort by Dirk Claessens... available at http://users.pandora.be/dirk.claessens2/downloads/tcomport.zip
But I'll use anything if it works, so if you get the one mentioned above to work with all this then I'll switch. I have actually used the one you mentioned before but lost it along the way and found this other one instead.
Points upped to 500 as this is obviously a fair bit more involved than I thought it would be.
Regards
Philip
I use TComPort by Dirk Claessens... available at http://users.pandora.be/dirk.claessens2/downloads/tcomport.zip
But I'll use anything if it works, so if you get the one mentioned above to work with all this then I'll switch. I have actually used the one you mentioned before but lost it along the way and found this other one instead.
Points upped to 500 as this is obviously a fair bit more involved than I thought it would be.
Regards
Philip
ok, let's stay with component you use, i'l ldownload it and try to get it working
ziolko.
ziolko.
hmm I'm a bit confused should work, make sure that you have same settings on ComPort in DLL as in your test EXE.
did you try to debug DLL?
ziolko.
did you try to debug DLL?
ziolko.
ASKER
I've checked and double checked the settings... will check again tonight when I get home from work.
I've traced dll execution through the create and execute procs, all fine there, but haven't been able to work out why the comport callback won't fire.
Sounds like you've got it working fine there?
I've traced dll execution through the create and execute procs, all fine there, but haven't been able to work out why the comport callback won't fire.
Sounds like you've got it working fine there?
put breakpoint in procedure TComThread.ComPort1Receive CallBack(D ata: String); and see if it fires at all.
btw. do you have to send anything through com port to get any response or once connected you should receive data?
ziolko.
btw. do you have to send anything through com port to get any response or once connected you should receive data?
ziolko.
ASKER
Ok,
I've traced it all the way through TComThread.Execute (ComPort unit) to the line that is
WAIT_OBJECT_0 + 1: Synchronize( EventHandler )
(line 657)
At which line, I hit F8 to step another line, and it never comes back.
Tracing (F7) through that line i end up at line 9583 of the Classes unit...
WaitForSingleObject(SyncPr oc.Signal, INFINITE);
Never get past this line.
I've traced it all the way through TComThread.Execute (ComPort unit) to the line that is
WAIT_OBJECT_0 + 1: Synchronize( EventHandler )
(line 657)
At which line, I hit F8 to step another line, and it never comes back.
Tracing (F7) through that line i end up at line 9583 of the Classes unit...
WaitForSingleObject(SyncPr
Never get past this line.
ASKER
Oh and the device connected to the port is constantly streaming data, no need to send any data to get a response...
if you reached this: WAIT_OBJECT_0 + 1: Synchronize( EventHandler ) it means theres something coming to com port
so something is wrong in firing events, don't debug Synchronize() with F7 instead put break point in TCommThread.EventHandler; in ComPort.pas
and see if it comes to FOnReceive( CharsToRead ) line, if it comes there with F7 you should go to TComPort.ReceiveNotify() within this mthod you should reach FReceiveCallBack( TempBuf ) line then with F7 you should jump to TComThread.ComPort1Receive CallBack() ;
in other words program flow should be:
TCommThread.EventHandler
TComPort.ReceiveNotify()
TComThread.ComPort1Receive CallBack()
check where this flow is broken and we'll see what can be done about it:)
ziolko.
so something is wrong in firing events, don't debug Synchronize() with F7 instead put break point in TCommThread.EventHandler; in ComPort.pas
and see if it comes to FOnReceive( CharsToRead ) line, if it comes there with F7 you should go to TComPort.ReceiveNotify() within this mthod you should reach FReceiveCallBack( TempBuf ) line then with F7 you should jump to TComThread.ComPort1Receive
in other words program flow should be:
TCommThread.EventHandler
TComPort.ReceiveNotify()
TComThread.ComPort1Receive
check where this flow is broken and we'll see what can be done about it:)
ziolko.
ASKER
Breakpoint on line ClearCommError( hCom, ErrorMask, @ComStat ); (590), nothing at all.
Although when I fire closeport.... which calls FreeAndNil(ComThread);, it does fire TCommThread.EventHandler;. .. goes through to if Assigned( FOnReceive ) then, which apparently is unassigned at that point. Commenting out that line give an AV on the next line ...FOnReceive( CharsToRead );, read of address 00000000
Fun and games! :-)
Although when I fire closeport.... which calls FreeAndNil(ComThread);, it does fire TCommThread.EventHandler;.
Fun and games! :-)
ASKER
Ok this is just getting weird... maybe I'm doomed or something! (Or maybe It's trying to tell me I can't program and to find another job...)
I commented out synchronize in.... WAIT_OBJECT_0 + 1: {Synchronize(}EventHandler //)
And added ShowMessage(Data); in
procedure TComThread.ComPort1Receive CallBack(D ata: String);
begin
ShowMessage(Data);
ReallocMem(FBuffer, Length(Data) + 1);
And with alot of complaining It spat some data out to my memo. As soon as I remove the ShowMessage, nothing.
Also throws an exception in the graphics unit (canvas does not allow drawing) after about the second piece of data is received. (related to the show message I assume??)
Actually, just played a bit more, put the synchronise back in. That cures the graphics error and data still coming out (with no complaining)... so that explains the exception.
So now, if I put in the showmessage, I get data, if I take it out... I dont.
I have confirmed that all 3 lines
ReallocMem(FBuffer, Length(Data) + 1);
StrPCopy(FBuffer, Data);
Synchronize(SendBackData);
in procedure TComThread.ComPort1Receive CallBack(D ata: String);
are being compiled.
I commented out synchronize in.... WAIT_OBJECT_0 + 1: {Synchronize(}EventHandler
And added ShowMessage(Data); in
procedure TComThread.ComPort1Receive
begin
ShowMessage(Data);
ReallocMem(FBuffer, Length(Data) + 1);
And with alot of complaining It spat some data out to my memo. As soon as I remove the ShowMessage, nothing.
Also throws an exception in the graphics unit (canvas does not allow drawing) after about the second piece of data is received. (related to the show message I assume??)
Actually, just played a bit more, put the synchronise back in. That cures the graphics error and data still coming out (with no complaining)... so that explains the exception.
So now, if I put in the showmessage, I get data, if I take it out... I dont.
I have confirmed that all 3 lines
ReallocMem(FBuffer, Length(Data) + 1);
StrPCopy(FBuffer, Data);
Synchronize(SendBackData);
in procedure TComThread.ComPort1Receive
are being compiled.
>>Breakpoint on line ClearCommError( hCom, ErrorMask, @ComStat ); (590), nothing at all.
you mean it hangs there??
try also change it a bit:
if not ClearCommError( hCom, ErrorMask, @ComStat ) then
ShowMessage(SysErrorMessge (GetLastEr ror))
ziolko.
you mean it hangs there??
try also change it a bit:
if not ClearCommError( hCom, ErrorMask, @ComStat ) then
ShowMessage(SysErrorMessge
ziolko.
ASKER
Now that I put the showmessage into ComPort1ReceiveCallBack it is breaking on ClearComError.
Without the showmessage, It doesn't get anywhere near it... so doesn't even get a chance to hang.
Without the showmessage, It doesn't get anywhere near it... so doesn't even get a chance to hang.
oops sorry missed your comment (20821994), didn't refresh my webbrowser.
by "don't debug Synchronize() with F7" I meant don't try to step in with F7 not remove Synchronize :)
without Synchonization you'll always get AVs.. a lot of them:)
>>So now, if I put in the showmessage, I get data, if I take it out... I dont.
that's very strange strange, try to put Sleep() instead on ShowMessage, I know this is not a nice solution but I'm courious if it works.
if you have some spare time you can try comport from courceforge:
http://sourceforge.net/project/showfiles.php?group_id=76595&package_id=77312&release_id=380733
ziolko.
by "don't debug Synchronize() with F7" I meant don't try to step in with F7 not remove Synchronize :)
without Synchonization you'll always get AVs.. a lot of them:)
>>So now, if I put in the showmessage, I get data, if I take it out... I dont.
that's very strange strange, try to put Sleep() instead on ShowMessage, I know this is not a nice solution but I'm courious if it works.
if you have some spare time you can try comport from courceforge:
http://sourceforge.net/project/showfiles.php?group_id=76595&package_id=77312&release_id=380733
ziolko.
ASKER
>> by "don't debug Synchronize() with F7" I meant don't try to step in with F7 not remove Synchronize :)
without Synchonization you'll always get AVs.. a lot of them:)
Yup I know, just experimenting...
Sleep(1), 1000 and 5000 did nothing. I also tried MessageBox instead of Showmessage. didn't work either.
Seems our beloved comport has a fetish for showmessage.
Will try SF comport now.
without Synchonization you'll always get AVs.. a lot of them:)
Yup I know, just experimenting...
Sleep(1), 1000 and 5000 did nothing. I also tried MessageBox instead of Showmessage. didn't work either.
Seems our beloved comport has a fetish for showmessage.
Will try SF comport now.
one more thing,
you said that if you call ShowMessage() in TComThread.ComPort1Receive CallBack then you have data, you mean data is calledback from DLL to EXE? if so is what you've been expecting or just some trash?
ziolko.
you said that if you call ShowMessage() in TComThread.ComPort1Receive
ziolko.
ASKER
Yes, data is passed back to the EXE from DLL and put in memo. Data is exactly what I was expecting.
this is just wild guess but...
procedure TComThread.ComPort1Receive CallBack(D ata: String);
begin
ProcessMessages;
ReallocMem(FBuffer, Length(Data) + 1);
StrPCopy(FBuffer, Data);
Synchronize(SendBackData);
end;
ziolko.
procedure TComThread.ComPort1Receive
begin
ProcessMessages;
ReallocMem(FBuffer, Length(Data) + 1);
StrPCopy(FBuffer, Data);
Synchronize(SendBackData);
end;
ziolko.
ASKER
Really, really weird.
Now, It won't work even if I put showmessage in... (I un-installed component to install SF one... both have same classname. reinstalled this one after uninstalling sf one again (to try ProcessMessages).
But, If I remove Synchronize from both Synchronize(SendBackData); and WAIT_OBJECT_0 + 1: Synchronize(EventHandler) it works fine.
As soon as I put synchronize back in on either of those lines it stops.
Any chance it could be something to do with a thread (main) taking all the execution time and not releasing it?
Now, It won't work even if I put showmessage in... (I un-installed component to install SF one... both have same classname. reinstalled this one after uninstalling sf one again (to try ProcessMessages).
But, If I remove Synchronize from both Synchronize(SendBackData);
As soon as I put synchronize back in on either of those lines it stops.
Any chance it could be something to do with a thread (main) taking all the execution time and not releasing it?
I thought about it (removing synchronize) I was afraid that it will lock itself but I did small test and I had no problems.
also if you don't use synchronization at all you'll get AV sooner or later.
>>Any chance it could be something to do with a thread (main) taking all the execution time and not releasing it?
I don't think so, it's rather problem of of calling synchronize twice
Synchronize(EventHandler) - that's first synchronize and EventHandler calls FOnReceive( CharsToRead ) which calls TComThread.ComPort1Receive CallBack and tshi calls Synchronize(SendBackData), this way it's synchronize within synchronize
so try also this:
ReallocMem(FBuffer, Length(Data) + 1);
StrPCopy(FBuffer, Data);
SendBackData;
ziolko.
also if you don't use synchronization at all you'll get AV sooner or later.
>>Any chance it could be something to do with a thread (main) taking all the execution time and not releasing it?
I don't think so, it's rather problem of of calling synchronize twice
Synchronize(EventHandler) - that's first synchronize and EventHandler calls FOnReceive( CharsToRead ) which calls TComThread.ComPort1Receive
so try also this:
ReallocMem(FBuffer, Length(Data) + 1);
StrPCopy(FBuffer, Data);
SendBackData;
ziolko.
ASKER
Tried that, with Synchronize(EventHandler), no go.
Removed Synchronize from EventHandler, works fine.
Added Synchronize to SendBackData, no go.
2nd one appears to work ok, but as you say, no synchronization will result in an AV sooner or later so I'm a little uneasy about leaving it like that....
Removed Synchronize from EventHandler, works fine.
Added Synchronize to SendBackData, no go.
2nd one appears to work ok, but as you say, no synchronization will result in an AV sooner or later so I'm a little uneasy about leaving it like that....
you can synchronize it your self but try sourceforge comport with sync method smWindowSync if it fails we'll get rid of Synchronize() and do it other way.
ziolko.
ziolko.
>>you can synchronize it yourself
jeeez that would require sync with VCL main thread... I need a break
ziolko.
jeeez that would require sync with VCL main thread... I need a break
ziolko.
ASKER
I had a play with sourceforge CP, but stepping through the create proc it got to proc end and then jumped back to
FComPort.ReceiveCallBack := ComPort1ReceiveCallBack;
over and over.
I even commented out the callback line and it still kept going back to it. This is all getting way weird.
Might use another copy of Delphi on a second PC here and get another compiler's opinion.
Break sounds good. I'm off to bed. Enjoy the rest of your afternoon.
FComPort.ReceiveCallBack := ComPort1ReceiveCallBack;
over and over.
I even commented out the callback line and it still kept going back to it. This is all getting way weird.
Might use another copy of Delphi on a second PC here and get another compiler's opinion.
Break sounds good. I'm off to bed. Enjoy the rest of your afternoon.
note that CP from SF has different events, you should use OnRxChar and within handler call Read or ReadStr, also it has some more properties (ControlDTR, ControlRTS... ) to set so firstly make it work in simple EXE
get some good sleep:)
ziolko.
get some good sleep:)
ziolko.
ASKER
Hmmm this can't be right... looks like it's working!
I even have Synchronize around Sendbackdata!
Using SF comport...
Two main things there that got it to work. I was using the ComDataPacket coz I couldn't workout how to get data out of the comport direct. your last comment help me get rid of the datapacket and use onRXChar (which i looked at originally but there was only a count passed in... didn't think to look on the port itself.
Also... you were talking about smWindowSync up there ^... didn't mean much at the time, but just happened to be looking at comports properties and noticed smThreadSync. Changed it to window and she springs to life. only works with window sync.
And I've even got data going from the app thru dll to the comport (opposite direction)...
Hit button, calls dll func SendData, that calls SendData in thread, which calls comports writestr function.
No synchronize anywhere in there which I believe I do not need.
So in summary, either I've really screwed something up which has made it work, or the old comport had issues with synchronization??
I even have Synchronize around Sendbackdata!
Using SF comport...
Two main things there that got it to work. I was using the ComDataPacket coz I couldn't workout how to get data out of the comport direct. your last comment help me get rid of the datapacket and use onRXChar (which i looked at originally but there was only a count passed in... didn't think to look on the port itself.
Also... you were talking about smWindowSync up there ^... didn't mean much at the time, but just happened to be looking at comports properties and noticed smThreadSync. Changed it to window and she springs to life. only works with window sync.
And I've even got data going from the app thru dll to the comport (opposite direction)...
Hit button, calls dll func SendData, that calls SendData in thread, which calls comports writestr function.
No synchronize anywhere in there which I believe I do not need.
So in summary, either I've really screwed something up which has made it work, or the old comport had issues with synchronization??
>>either I've really screwed something up which has made it work
this happens sometimes if you make some changes and forget to build (not just compile) both EXE and DLL
>>he old comport had issues with synchronization??
SF comport is a bit more advanced than the other one, but if you choose smThreadSync on SF CP it should work pretty much the same as other one. I always used SF component with window sync and never couldn't be arsed to work out what happens with other settings, why bother if it works fine for me:)
ziolko.
this happens sometimes if you make some changes and forget to build (not just compile) both EXE and DLL
>>he old comport had issues with synchronization??
SF comport is a bit more advanced than the other one, but if you choose smThreadSync on SF CP it should work pretty much the same as other one. I always used SF component with window sync and never couldn't be arsed to work out what happens with other settings, why bother if it works fine for me:)
ziolko.
ASKER
Hmmm true.
Well thanks for all your help on this and for not giving up after the first little bit.
I'll accept your first post as that technically was the answer to my question, but for anyone reading this, everything above helped in one way or another.
Thanks again for all your help.
Regards
Philip
Well thanks for all your help on this and for not giving up after the first little bit.
I'll accept your first post as that technically was the answer to my question, but for anyone reading this, everything above helped in one way or another.
Thanks again for all your help.
Regards
Philip
ASKER
Thanks again. Looks forward to working with you again in the future! :-)
>>Well thanks for all your help on this and for not giving up after the first little bit.
why would I give up?
I'm glad it works because I started to have doubts about what I did in earlier projects:)
sorry it took that long
ziolko.
why would I give up?
I'm glad it works because I started to have doubts about what I did in earlier projects:)
sorry it took that long
ziolko.
ASKER
Well you technically answered my question in the first post, so you could quite rightly have left it at that, and ignored all the sub-questions I bombarded you with :-)
>> sorry it took that long
No need to apologise, if you weren't there I'd still be searching the net and have made no progress!
>> sorry it took that long
No need to apologise, if you weren't there I'd still be searching the net and have made no progress!
>>Well you technically answered my question in the first post
it's not only about answering Qs it's about solving problems too:)
>>ignored all the sub-questions I bombarded you with :-)
I don't ignore sub-questions... well at least until someone wants to solve 2 different problems in single Q:)
ziolko.
it's not only about answering Qs it's about solving problems too:)
>>ignored all the sub-questions I bombarded you with :-)
I don't ignore sub-questions... well at least until someone wants to solve 2 different problems in single Q:)
ziolko.
ASKER
I'm a bit (ok very) rusty on threads... spent the last hour reading up on them but I think I'll have to read a bit more yet. You wouldn't happen to have a small example or a decent tutorial lying around somewhere would you?
Thanks again,
Philip