5

Developing with RAD Studio (Delphi) v10.2.1 (Tokyo release 1) on Windows 10 "Creators Update" 64bit, but 32bit development.

The application is VCL with multiple background threads, each using Indy TidHTTP to fetch network resources. Synchronisation between the main thread and the background threads is implemented using message queues (PostThreadMessage calls). This is complicated enough that offering direct code here would be difficult and messy, so I'm starting with a verbal description.

What is supposed to happen: Open a file with links to external resources, this generates the HTTP requests and hands them out to background processing, then waits for incoming messages on the application message queue to say the resources have been downloaded. The application messages are matched in event code assigned to TApplication.OnMessage (which, I suspect, is where my problem lies).

It works. Everything goes smoothly most of the time. But if I open a TSaveDialog - even if I cancel the dialog rather than actually doing anything - then messages go missing off the application message queue.

Through a process of writing log messages (it's impossible to debug directly because that upsets the timing required to cause the problem) I've worked out that the background threads are indeed posting the messages (and getting a positive response from PostThreadMessage), but they never appear on my TApplication.OnMessage event code.

I've seen that some sneaky code in various libraries will set up their own PeekMessage/TranslateMessage/DispatchMessage loops, but not all of them remember to check if there is a TApplication.OnMessage event. But I've just searched through the VCL code and the dozen or so third party libraries I'm using and have not found any instances of this that would be getting hit in this case (as far as I can tell).

Note: I am using madExcept, Indy, FastReport, AddictSpell, SynEdit, VclStyleUtils (amongst a few other less known libraries)

Note 2: I am wondering if it might be related to with Delphi 10.2.1 or Windows 10 Creator's update, since I am also seeing some other odd behaviour (long delays with the first exception or first TOpenDialog - but only on some applications) that definitely didn't happen with 10.1 (I didn't use 10.2.0). ... But this may be (probably is) something different.

So my question is: What can I do about this?

Any suggestions on how to find/verify that there is some other code stealing the application messages? Anything else I should search for other than PeekMessage?

Is there another way to intercept the application message queue messages that might let me avoid the problem?

If no better options show themselves I may have to abandon using application thread messages and implement my own messaging/synchronisation system, which I'd rather not do after getting this other working very well the rest of the time.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
GeoffW
  • 145
  • 1
  • 7
  • You can use `SetWindowsHookEx()` to install a thread-specific `WH_GETMESSAGE` hook in the UI thread – Remy Lebeau Aug 31 '17 at 16:15
  • @Remy thanks for that. Such a hook would offer a way to let me keep the messaging centralised around the thread-id which may be neater than having to introduce window handles. – GeoffW Sep 01 '17 at 01:38

1 Answers1

7

You mention PostThreadMessage. Look no further. You can't use this unless you control all message loops that might pull off thread messages, and you don't. The modal file dialog message loop is out of your control. It will pull off thread messages intended for a different message loop, and not know what to do with them.

The solution is simple enough. Post messages to a window rather than a thread. That way all sane message loops (the modal file dialog's message loop is sane) will dispatch the messages to the intended recipient window.

In Delphi terms this would involve using AllocateHWnd or similar to create a hidden window to receive the messages.

Raymond Chen has covered this topic here: Why do messages posted by PostThreadMessage disappear?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • The bold part in the question seems to suggest that messages go amiss even after the dialog has been cancelled. Or perhaps I'm misunderstanding.. – Sertac Akyuz Aug 31 '17 at 14:50
  • @SertacAkyuz I took that to mean that the dialog was opened and then cancelled, and still some events went missing. Anyway, PTM is a problem with no doubt. – David Heffernan Aug 31 '17 at 14:54
  • Sertac, the nature of the problem makes it difficult to tell exactly when the messages start getting through again, but they do definitely start again after the dialog is gone. David's explanation fits. – GeoffW Aug 31 '17 at 14:55
  • David, your explanation makes sense. I guess I always thought the VCL would make sure OnMessage got called. Now I know better. It is a bit sad, all I needed before was a thread-id, it didn't matter who was sending or receiving, now I have to modify the code to distinguish between the main thread and the other threads. Such is programming. Many thanks. – GeoffW Aug 31 '17 at 14:58
  • 1
    @Geoff you're out of VCL when you call an api dialog. ;) – Sertac Akyuz Aug 31 '17 at 15:00
  • @Sertac, Yes, I really should have thought of that - I won't tell you how long it took me just to work out what was happening, let alone the why it was happening. – GeoffW Aug 31 '17 at 15:08