Delayed action

When you work with UIs, order of operations can be very important.  Windows’s UI works based on an event queue and a message pump that reads events from the queue and dispatches them.  And since the UI is single-threaded, this means that at any time, there could be pending events about to execute while you’re handling some UI code.

Sometimes you’ll get into a situation where you need to execute something, but not right away; you need it to happen after all of the pending events have processed.  Now, obviously, the best way to make something happen after everything in the queue has processed is to put something else onto the queue directly behind everything that’s currently in there.  But the tricky part is what happens when it comes back out.

Messages get posted to a HWND (window handle) and get dispatched to the associated window’s WndProc routine, where they’re handled based on their message type, which is a 2-byte integer value.  There are a bunch of reserved constant values with specific meanings to Windows. WM_PAINT, for example, tells a visual control to repaint itself.  But there’s also a reserved value called WM_USER.  Everything from this constant onward can be used as a user-defined message.

Delphi makes associating a message constant with a method of an object very easy; all you need to do is put a message directive after the declaration, with a value indicating the message type it should respond to.  But because messages get dispatched to a HWND, this will only work for a pretty narrow subset of objects.

Interestingly enough, there is a way built in to Delphi to post a message to the queue of the main (UI) thread, which will execute an arbitrary procedure when the message is read.  It’s the TThread.Queue routine.  Unfortunately, as the name implies, it only works correctly when used from another thread.  The documentation warns you not to call TThread.Queue from the main thread.  Looking through the code, I’m not completely sure what will happen if you do, but it looks like it will just execute your routine immediately instead of posting it to the event queue for delayed execution.

So the obvious solution if you want to queue something up from the main thread is a bit ugly: spawn a thread that calls TThread.Queue and then terminates.  But now you’re introducing all sorts of new things that can go wrong!

Well, I’d run into a need to do this a handful of times, and I’d always had a form or other control available that I could attach a message handler to… until last week.  I was inside an object that is not a visual control, but which creates a form, calls ShowModal on it, and then releases the form when it’s done.  Problem is, both that modal form and the base form that the current code was working with (but was not part of) displayed OpenGL contexts, and due to various factors the GL drawing state was getting corrupted.  So I needed some way to reset things, but I had to wait until the modal form was finished cleaning up.  The Release method works based on delayed action, to let a form finish any queued processing before destroying it, but that means that my reset code had to also execute delayed.

After thinking about it for a while, here’s what I came up with.  In 90 lines of code, it duplicates the functionality of TThread.Queue–taking an anonymous procedure with no arguments and queuing it up for delayed execution on the main thread–except that it works correctly when called from the main thread.

* The contents of this file are used with permission, subject to
* the Mozilla Public License Version 1.1 (the "License"); you may
* not use this file except in compliance with the License. You may
* obtain a copy of the License at
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
* This file was created by Mason Wheeler.  He can be reached for support at

unit delayedAction;


procedure DelayExec(const action: TProc);

   Windows, Messages, Generics.Collections, Classes, Forms;

   TDelayQueue = class
      FQueue: TThreadedQueue<TProc>;
      FHandle: HWND;
      procedure MainWndProc(var Msg: TMessage);
      procedure Dequeue;
     constructor Create;
     destructor Destroy; override;

{ TDelayQueue }

constructor TDelayQueue.Create;
   FHandle := AllocateHWnd(self.MainWndProc);
   FQueue := TThreadedQueue<TProc>.Create;

destructor TDelayQueue.Destroy;
   inherited Destroy;

procedure TDelayQueue.Dequeue;
   proc: TProc;
   proc := FQueue.PopItem();

procedure TDelayQueue.MainWndProc(var Msg: TMessage);
      if Msg.Msg = WM_USER then
      else DefWindowProc(FHandle, msg.Msg, msg.WParam, msg.LParam);

   delay: TDelayQueue;

procedure DelayExec(const action: TProc);
   PostMessage(delay.FHandle, WM_USER, 0, 0);

   delay := TDelayQueue.Create;

I figured I may as well share it. Feel free to use this if you’re ever in a situation where you need delayed execution.


  1. C Johnson says:

    Worth noting is the TApplication.OnIdle. That only executes once the app’s message queue goes empty. Just make sure you set done to true when done or you’ll seriously peg the cpu with an idle loop.

  2. Edwin says:

    Great! I had the exact need and had a similar idea during the development of LIVEditor, but I haven’t come up a neat implementation like yours, thanks!

    @C Johnson, TApplication.OnIdle is good, but doesn’t allow a clear organization of the code in this situation.

  3. Leif Uneus says:

    I think you can remove the TThreadedQueue by doing this instead:
    (Tested on XE3).

    Procedure DelayExec( const aProc: TProc);
    { Posts the anonymous TProc() to the message queue so it can call aProc()
    in the main thread. }
    {- Example:
    Proc: TProc absolute aProc;
    PProc: ^TProc;
    PProc^ := Proc;
    PostMessage( delay.FHandle,

    procedure TDelayQueue.MainWndProc(var Msg: TMessage);

    Procedure AnonProcPerform;
    {- Extracts the anonymous TProc and executes it. }
    PProc : ^TProc;
    Proc : TProc;
    PProc := Pointer(Msg.wParam);
    Proc := PProc^;

    if Msg.Msg = WM_USER then
    DefWindowProc(FHandle, msg.Msg, msg.WParam, msg.LParam);

  4. Max Vlasov says:

    Sorry for posting not exactly at the place it belongs, but that post was closed ( and this is the closest open about anonymous methods.

    The solution to the memory leak is looks promising from my pov. I added a comment about this at QC83259.

    The qc is still open, seems like everyone inside emb thinks this problem has no solution. Please, consider testing your cases and reopening comments to the post (it was linked in the stackoverflow post of the qc reporter) 🙂

    • Mason Wheeler says:

      Not sure how that got closed, but it’s reopened now.

      That fix looks like it will work as long as you don’t pass either of the anonymous methods generated in the procedure outside if it to be used at some point after the procedure returns. Otherwise you’ll end up with access violations. But it’s a good workaround.

  5. Remy Lebeau says:

    “It’s the TThread.Queue routine. Unfortunately, as the name implies, it only works correctly when used from another thread.”

    “The documentation warns you not to call TThread.Queue from the main thread. Looking through the code, I’m not completely sure what will happen if you do, but it looks like it will just execute your routine immediately instead of posting it to the event queue for delayed execution.”

    Yes, that is exactly what happens.

Leave a Reply