1. Home
  2. Computing & Technology
  3. Delphi Programming
Sending messages to non-windowed applications
Page 2: How to send messages to non-windowed applications
 Win prizes by sharing code!
Do you have some Delphi code you want to share? Are you interested in winning a prize for your work?
Delphi Programming Quickies Contest
 More of this Feature
• Page 1: How Delphi dispatches messages in windowed applications
• Page 3: Obtaining a unique message identifier. DeallocateHWND bug
 Join the Discussion
"Post your views, comments, questions and doubts to this article."
Discuss!
 Related Resources
• Message handing with Delphi
• Windows API and Delphi
• Threading in Delphi
• Console Delphi application

Now that you know how Delphi dispatches messages in windowed applications, it's time to trick Windows in thinking we have a window in a non-windowed application.

How to send messages to non-windowed applications
Isn't there a way to trick Windows in thinking we have a window? We could create one but having tens of windows displayed all across the screen just for the purpose of intercepting Windows messages is inaesthetical and unpractical. What if we could create a window but mark it in such way so it is not displayed on the screen? We could reach our goal of having a window procedure and at the same time don't fill the screen with dummy empty windows.

Again Delphi VCL addresses this very specific need by providing a convenient wrapper that handles all the low-level API calls. It provides two functions that must be used in pairs: AllocateHWND and DeallocateHWND. First one accepts a single parameter that is our window procedure and the second one does the cleanup when we no longer need the invisible window.

Signal threads application screenshot

We have created a sample application that shows the usage of AllocateHWND/DeallocateHWND functions. To simulate a non-windowed application we will use a TThread descendent, defined as follows:

TTestThread = class(TThread)
private
  FSignalShutdown: boolean;
  { hidden window handle }
  FWinHandle: HWND;                       
protected
  procedure Execute; override;
  { our window procedure }
  procedure WndProc(var msg: TMessage);   
public
  constructor Create;
  destructor Destroy; override;
  procedure PrintMsg;
end;

Creating the hidden window
In the TTestThread constructor we create our hidden window which is destroyed in the TTestThread destructor:

constructor TTestThread.Create;
begin
  FSignalShutdown := False;
  {
  create the hidden window, store it's 
  handle and change the default window 
  procedure provided by Windows with our 
  window procedure 
  }
  FWinHandle := AllocateHWND(WndProc);
  inherited Create(False);
end;

destructor TTestThread.Destroy;
begin
  { destroy the hidden window 
    and free up memory }
  DeallocateHWnd(FWinHandle);
  inherited;
end;

To test for the message routing we use a simple boolean (FSignalShutdown) that we initially set to False in the constructor and will hopefully be set to True in the window procedure (WndProc) upon receiving our message.

The window procedure
In order to keep things simple we have implemented a bare-bone window procedure as follows:

procedure TTestThread.WndProc(var msg: TMessage);
begin
  if Msg.Msg = WM_SHUTDOWN_THREADS then
    { 
     if the message id is WM_SHUTDOWN_THREADS
     do our own processing
    }
    FSignalShutdown := True 
    else
    {
     for all other messages call 
     the default window procedure 
    }
    Msg.Result := DefWindowProc(FWinHandle, Msg.Msg, 
                                Msg.wParam, Msg.lParam);
end;

This procedure is called for each and every Windows message, so we need to filter out only those that are interesting, in this case WM_SHUTDOWN_THREADS. For all other messages that are not handled by our application remember to call the default Windows procedure. Even if this is not so important for our non-visible non-interactive window it is a good practice and missing this step may yield to unpredictable behaviors.

Message identifier?
If applications were to use arbitrary message id's their operation would soon interfere and messages meant for one application would be interpreted in unknown and unwanted ways by others.

To prevent this Windows provides a way for each application or related applications to obtain a unique message identifier. How? Find on the next page...

Next page > Obtaining a unique message identifier. The DeallocateHWND bug. > Page 1, 2, 3

Explore Delphi Programming
About.com Special Features

Stay connected and entertained with reviews on tips on the latest HDTVs, cellphones and more. More >

Easy ways to connect two computers for networking purposes. More >

  1. Home
  2. Computing & Technology
  3. Delphi Programming

©2009 About.com, a part of The New York Times Company.

All rights reserved.