Find out why application thread messages go missing with TSaveDialog
Asked Answered
C

1

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.

Chaussure answered 31/8, 2017 at 14:8 Comment(2)
You can use SetWindowsHookEx() to install a thread-specific WH_GETMESSAGE hook in the UI threadDiscriminative
@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.Chaussure
B
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?

Balderas answered 31/8, 2017 at 14:31 Comment(6)
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..Glossographer
@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.Balderas
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.Chaussure
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.Chaussure
@Geoff you're out of VCL when you call an api dialog. ;)Glossographer
@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.Chaussure

© 2022 - 2024 — McMap. All rights reserved.