Board index » delphi » Problems with threads and drawing to canvas

Problems with threads and drawing to canvas

I am writing an app which uses a callback from a c++ dll - I have declared
all the exported functions from the dll as stdcall external - but the two
callback functions I have declared as cdecl ( since the are local to my
program? ) - does this sound correct? The problem seems to be related to
threads - the c++ dll is using threads - when it calls one of the callback
functions I wanted to create a new form to store the info it is passing
 which I can access ok ) but I get cannot draw to canvas errors sometimes -
I believe this is related to thread syncronisation - this happens if I
create the form locally within the callback function. However - if I declare
the form in the public section of the main form - then it works ok - until I
come to close down the app - then it won't close or respond in any way. Does
any one have any idea how I might resolve my problems - are my callback
functions declared incorrectly - or do I need to create a thread somehow
within the callback function?
Regards,
Mike
 

Re:Problems with threads and drawing to canvas


Quote
Mike Bruce wrote:
> I am writing an app which uses a callback from a c++ dll - I have declared
> all the exported functions from the dll as stdcall external - but the two
> callback functions I have declared as cdecl ( since the are local to my
> program? ) - does this sound correct? The problem seems to be related to
> threads - the c++ dll is using threads - when it calls one of the callback
> functions I wanted to create a new form to store the info it is passing
>  which I can access ok ) but I get cannot draw to canvas errors sometimes -
> I believe this is related to thread syncronisation - this happens if I
> create the form locally within the callback function. However - if I declare
> the form in the public section of the main form - then it works ok - until I
> come to close down the app - then it won't close or respond in any way. Does
> any one have any idea how I might resolve my problems - are my callback
> functions declared incorrectly - or do I need to create a thread somehow
> within the callback function?

Quite an adventure, Mike.

Your callback functions seem to be declared correctly, otherwise a bad
immediate crash is the most likely thing to occur. You should be able to
figure this out on a more theoretical basis, though. Take a look at the
C code, at the compiler options used to generate the DLL, etc. You
should be able to find the relevent info.

As to the form crashes... If your callback function gets called from
within the context of secondary threads, all VCL is off limits. VCL is
not thread safe. It can only be used in the single main application
thread. Failing to comply to this leads to all kinds of unpredictable
behaviour. The behaviour you have described above is indeed very
typical.

Look up Synchronize, or, if you prefer knowing what you are using, use
PostMessage to synchronize into the main application thread. Post
yourself the data you need in the form this way. Create your form in the
message handler, and give it the data.

Joris

Re:Problems with threads and drawing to canvas


Thanks for the info Joris - I have been offline for a few days thanks to the
Nimda thing - will read up on your suggestions.
Cheers,
Mike Bruce
"Joris Van Damme" <as.van.damme.jo...@planetinternet.be> wrote in message
news:3BA85529.3A00C902@planetinternet.be...
Quote
> Mike Bruce wrote:
> > I am writing an app which uses a callback from a c++ dll - I have
declared
> > all the exported functions from the dll as stdcall external - but the
two
> > callback functions I have declared as cdecl ( since the are local to my
> > program? ) - does this sound correct? The problem seems to be related to
> > threads - the c++ dll is using threads - when it calls one of the
callback
> > functions I wanted to create a new form to store the info it is passing
> >  which I can access ok ) but I get cannot draw to canvas errors
sometimes -
> > I believe this is related to thread syncronisation - this happens if I
> > create the form locally within the callback function. However - if I
declare
> > the form in the public section of the main form - then it works ok -
until I
> > come to close down the app - then it won't close or respond in any way.
Does
> > any one have any idea how I might resolve my problems - are my callback
> > functions declared incorrectly - or do I need to create a thread somehow
> > within the callback function?

> Quite an adventure, Mike.

> Your callback functions seem to be declared correctly, otherwise a bad
> immediate crash is the most likely thing to occur. You should be able to
> figure this out on a more theoretical basis, though. Take a look at the
> C code, at the compiler options used to generate the DLL, etc. You
> should be able to find the relevent info.

> As to the form crashes... If your callback function gets called from
> within the context of secondary threads, all VCL is off limits. VCL is
> not thread safe. It can only be used in the single main application
> thread. Failing to comply to this leads to all kinds of unpredictable
> behaviour. The behaviour you have described above is indeed very
> typical.

> Look up Synchronize, or, if you prefer knowing what you are using, use
> PostMessage to synchronize into the main application thread. Post
> yourself the data you need in the form this way. Create your form in the
> message handler, and give it the data.

> Joris

Re:Problems with threads and drawing to canvas


Joris,
Could I just ask you ( since I am not very clear on threads or thread
programming ) what do you mean by create my form in the message handler?
Which message handler do you mean ? Is it the application.messagehandler ?

I did try postmessage and just posted the data to the edit on a form - then
in the editonchange event I copied it to a grid which is what I wanted - but
it didn't work - nothing appeared. However - it did work when I used
sendmessage which I have a feeling I shouldn't be using ??

Mike Bruce
"Joris Van Damme" <as.van.damme.jo...@planetinternet.be> wrote in message
news:3BA85529.3A00C902@planetinternet.be...

Quote
> Mike Bruce wrote:
> > I am writing an app which uses a callback from a c++ dll - I have
declared
> > all the exported functions from the dll as stdcall external - but the
two
> > callback functions I have declared as cdecl ( since the are local to my
> > program? ) - does this sound correct? The problem seems to be related to
> > threads - the c++ dll is using threads - when it calls one of the
callback
> > functions I wanted to create a new form to store the info it is passing
> >  which I can access ok ) but I get cannot draw to canvas errors
sometimes -
> > I believe this is related to thread syncronisation - this happens if I
> > create the form locally within the callback function. However - if I
declare
> > the form in the public section of the main form - then it works ok -
until I
> > come to close down the app - then it won't close or respond in any way.
Does
> > any one have any idea how I might resolve my problems - are my callback
> > functions declared incorrectly - or do I need to create a thread somehow
> > within the callback function?

> Quite an adventure, Mike.

> Your callback functions seem to be declared correctly, otherwise a bad
> immediate crash is the most likely thing to occur. You should be able to
> figure this out on a more theoretical basis, though. Take a look at the
> C code, at the compiler options used to generate the DLL, etc. You
> should be able to find the relevent info.

> As to the form crashes... If your callback function gets called from
> within the context of secondary threads, all VCL is off limits. VCL is
> not thread safe. It can only be used in the single main application
> thread. Failing to comply to this leads to all kinds of unpredictable
> behaviour. The behaviour you have described above is indeed very
> typical.

> Look up Synchronize, or, if you prefer knowing what you are using, use
> PostMessage to synchronize into the main application thread. Post
> yourself the data you need in the form this way. Create your form in the
> message handler, and give it the data.

> Joris

Re:Problems with threads and drawing to canvas


Quote
Mike Bruce wrote:
> Joris,
> Could I just ask you ( since I am not very clear on threads or thread
> programming ) what do you mean by create my form in the message handler?
> Which message handler do you mean ? Is it the application.messagehandler ?

You wanted to use VCL stuff as a concequence of a callback getting
called inside the context of a secondary thread, wright?

VCL stuff is off limits in secondary threads. It is completely not
threadsafe. So what you need here is to trigger some code in the context
of the 'main' thread, from within the context of a secondary thread.
Now, remember the 'main' thread is essentially a message loop. Only
thing it does is pop a message off out of the message stack and handle
that message. Posting or sending messages is done with a threadsafe
win32 api function.

So, there's you solution. The callback function that executes in the
context of the secondary thread can use postmessage to put a message on
the message stack. Some time later, the main thread will pop this
message out of the stack and respond to it.

Quote
> I did try postmessage and just posted the data to the edit on a form - then
> in the editonchange event I copied it to a grid which is what I wanted - but
> it didn't work - nothing appeared. However - it did work when I used
> sendmessage which I have a feeling I shouldn't be using ??

There are two good ways of handling messages. You can do it by
'subclassing', which, essentially, means that you replace a pointer to a
window specific general message handler function with a pointer to your
own code that can in turn call the old code. This is probably not what
you want here.

A 'cleaner' way to do it is to inherit from a TWinControl and add your
particular message handler in the declaration (and of course
implementation) part. Since you already have at least one 'form' window
around, usually, a 'form' window is used for this. Here's an example

const

  {this is the message code, any value from WM_USER and upwards will do}
  WM_MYMESSAGE = WM_USER + 0;    

type

  TForm1 = class(TForm)
  private
    procedure MyMessageHandler(var a: TMessage); message WM_MYMESSAGE;
  end;

implementation

procedure TForm1.MyMessageHandler(var a: TMessage);
begin
  {do the VCL stuff here, in the context of the main application thread}
  Vcl.Whatever;
end;

procedure Callback;
begin
  {this gets called in the context of a secondary thread, but needs to
cause the Vcl.Whatever action somehow}
  PostMessage(Form1.Handle,WM_MYMESSAGE,0,0);
end;

Note that this requires that Callback somehow needs to know the handle
of the window the message needs to be posted to. Sometimes this is dead
easy (eg a single instance window, present throughout the course of the
application). Sometimes this is a synchronization issue by itself (eg
threads that have to lazily die in idle time after their 'containing'
window is vanished).

The difference between PostMessage and SendMessage is simple.
PostMessage guarantees that you do not have to wait for the message to
be handled and cannot deadlock. Another advantage therefore is that no
processing power is wasted on true multi processor machines. A
disadvantage is that you cannot get any return value or any feedback as
to when or how the message got handled from this function. SendMessage
is exactly the opposite: it returns after the message got handled.

BTW, the use of PostMessage and SendMessage this way is quite standard
to the rest of the world. Synchronize is more popular to Delphi users
though. The VCL creates a dedicated window when it creates its first
thread. Synchronize, underneath, boils down to a sendmessage to this
window. It's the same principle, only, you can't 'see' what you are
really doing (which is crucially important in all multithreaded design),
and consequently you can't tailor it to any specific needs afterwards.

Hope this helps,

Joris

Other Threads