Wednesday, November 29, 2006

Unsafe to use TApplication.OnMessage in VCL.Net

Recently, I have been called to investigate some strange problem that causes program to misbehave.

To cut the long story short, it turns out that their application depends on the dispatching of TApplication.OnMessage event. If this is disturbed their program misbehaves.

TApplication.OnMessage is part of the Borland VCL framework. So how can a framework be so fragile to be disturbed?

My investigation led me to the bowel of the message pump of Borland's VCL and this looks like this in pseudo code:

TApplication.ProcessMessage()
if PeekMessage( ...., PM_REMOVE ) then
begin
if Assigned(FOnMessageHandler) FOnMessageHandler( ..... );
Do some other processing;
TranslateMessage( ... );
DispatchMessage( .... );
end;
This is the only place that the OnMessage event is fired and this is the weakness of the VCL framework. Why?

If you do not call TApplication.ProcessMessage() but instead using their Windows unit's GetMessage(), TranslateMessage() and DispatchMessage() (which are mapped down to P/Invoke using the Win32 API), you can prevent OnMessage being fired and yet your Windows messages are still correctly dispatched.

For example, if you either in your Delphi code or in some managed or unmanaged (for example a COM component), introduces a modal loop like this:

     while someFlag || GetMessage( .... )!= -1
{
if ( msg.message == ..... )
break;
else
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
Using standard Win32 API constructs that are commonly used by non-Delphi developers would immediately defeat the VCL's framework with respect to the OnMessage dispatching. To avoid this you must call TApplication.ProcessMessage() but even then you still cannot prevent other component from interfering with the VCL.

As said, this could be introduced by calling Win32 API that introduces a modal loop like a message box, or someone's code that has been designed with no knowledge of VCL. Such harmless usage immediately rendering that component incompatible with VCL or render your application's dependency on this feature useless.

This highlights the fragility of the VCL framework.

So the advice is that do not rely on TApplication.OnMessage(). Furthermore this event allows you to steal messages because it is called before the message is dispatched to the rightful owner.

No comments:

Post a Comment