I have a problem that code inside my dll is acting different compared to the same code within a normal application. After some debugging I found that the thread's OnTerminate is never called within the dll.
type
TTest = class
private
public
procedure threadStart();
procedure threadEnd(Sender: TObject);
procedure lines(value: String);
end;
procedure TTest.threadStart();
var aThread : TThread;
begin
aThread :=
TThread.CreateAnonymousThread(
procedure
begin
lines('start')
end
);
aThread.FreeOnTerminate := True;
aThread.OnTerminate := self.threadEnd;
aThread.Start;
end;
procedure TTest.threadEnd;
begin
lines('end')
end;
procedure TTest.lines(value: String);
var MyText: TStringlist;
begin
MyText:= TStringlist.create;
MyText.Add(value);
MyText.SaveToFile('.\filename.txt');
MyText.Free
end;
If I run this code from a normal VLC Delphi Application, I get end in the text file. If I run the same code from a dll (loading it either static or dynamic into a VLC Application), I get start in the text file.
My question: Why? Or better asked, how can I let my dll act the same way as my VLC. Current version I'm using is XE7.
The TThread.OnTerminate
event is triggered in the context of the main UI thread via a call to TThread.Synchronize()
, which stores requests in a queue that the main UI thread checks periodically, executing pending requests when available.
If the DLL and EXE are compiled with Runtime Packages enabled, they share a single copy of the RTL (and thus require you to deploy rtl.bpl
with your app). When the EXE checks the RTL's Synchronize()
queue, it will see pending requests from both EXE and DLL.
However, if they are not sharing a single RTL, then they will be compiled with separate copies of the RTL that are not linked to each other. By default, there is nothing in the EXE that checks and processes pending requests from the DLL's Synchronize()
queue, only from the EXE's Synchronize()
queue. To address that, you have to export a function from the DLL that calls the CheckSynchronize()
function of the DLL's RTL, and then make the EXE call that exported DLL function periodically, such as in a timer.
Otherwise, the other way to get around this problem is to bypass the Synchronize()
call that triggers the OnTerminate
event, by overriding the thread's virtual DoTerminate()
method (which you cannot do with TThread.CreateAnonymousThread()
). You can have DoTerminate()
call OnTerminate
directly, or just do what you need inside of DoTerminate()
itself. But either way, you have to make sure this code is thread safe, as DoTerminate()
runs in the context of the worker thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With