<Don Wilcox> wrote in message news:✉forums.embarcadero.com...
> I am encountering a problem with using Synchronize
> to update the UI.
Starting in BCB6, when TThread::Synchronize() was re-written to support
Linux, TThread::Synchronize() stopped working inside of a DLL natively and
now requires extra work on the DLL's and main Application's parts in order
to function correctly. A DLL is a self-contained module, thus the DLL and
main Application has separate copies of the internal queue used by
TThread::Synchronize(), and those copies are are not shared with each other.
When the main Application processing pending TThread::Synchronize()
requests, it can only see the requests that are made by its own threads. It
cannot see the requests that are made by the DLL's threads.
This design change introduced in BCB 6 also affects the TThread::Notify()
method added in later BCB versions as well.
In order to process the DLL requests, you will have to export an extra
function from your DLL that calls the DLL's copy of the CheckSynchronize()
function, and then have your main Application call that new DLL function
periodically, eg:
{code:cpp}
bool __export CheckSync()
{
return CheckSynchronize();
}
{code}
{code:cpp}
// a TTimer::OnTimer event handler
void __fastcall TForm1::SyncTimerElapsed(TObject *Sender)
{
CheckSync();
}
{code}
> What I have is a thread that is instantiated in a DLL:
Your DLL code is quite dangerous in general. You are passing VCL object
pointers across the DLL boundary. That can only safely work if the
Application and DLL are compiled with the exact same RTL and VCL versions.
As soon as you start mixing versions, you are asking for a lot of trouble.
A better design is to have the main Application pass the TListView's HWND to
the DLL instead of the TListView pointer itself (and have the DLL return the
TThread's ID or Handle instead of the TThread pointer itself, or better
nothing about the Thread at all). In fact, doing it this way, you do not
need to use Synchronize() at all. You can use SendMessage() instead, and
let the OS handle the synchronizing for you, eg:
{code:cpp}
#include <vcl.h>
#pragma hdrstop
#include <Classes.hpp>
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*
lpReserved)
{
return 1;
}
class LVThread : public TThread
{
public:
LVThread(HWND alv) : TThread(false), lv(alv), l(0) { }
protected:
void __fastcall Execute()
{
while (!Terminated)
{
Sleep(1000);
LV_ITEM item = {0};
item.mask = LVIF_IMAGE | LVIF_GROUPID;
item.iItem := ListView_GetItemCount(lv);
item.iImage = -1;
item.iGroupId = -1;
if( ListView_InsertItem(lv, &item) > -1 )
ListView_SetItemText(lv, item.iItem, 0, String("Line " +
IntToStr(l++)).c_str());
}
}
private:
HWND lv;
int l;
};
LVThread *Thread = NULL;
bool __export Start(HWND lv)
{
if( Thread == NULL )
Thread = new LVThread(lv);
return true;
}
bool __export Stop()
{
if( Thread != NULL )
{
Thread->Terminate();
Thread->WaitFor();
delete Thread;
Thread = NULL;
}
return true;
}
{code}
Otherwise, in order to share VCL object pointers across the DLL boundary
safely, both the main Application and the DLL have to be compiled with
Runtime Packages enabled, or else the DLL has to be changed into a Package
itself.
> When I run the application, the items only show up when I move the mouse
> to keep the message pump going.
I am surprised if that works at all, since the main Application does not
have access to the DLL's synchronize queue.
--
Remy Lebeau (TeamB)