Hi,
In Bug #3930 http://bugs.winehq.org/show_bug.cgi?id=3930#c41 I conjectured that:
1. Since w2k, winmm hijacks the application's thread to play multimedia content. Wine does this as well with MCI_WAIT, but it should as well affect winmm:playSound, winmm:midi* and winmm:wave*.
2. Consequently, the players must implement a message loop and dispatch regular window messages using DispatchMessageA/W Currently, Wine does not. This IMHO has potential for dead locks. Music and animations can play for a long time and messages ought to be serviced.
I'm not familiar with windows messages at all. What do you think about the consequence?
Point 1 explains why tests reveal the current thread as the one executing all callbacks but one since w2k.
Point 2 should be testable by playing a long piece of video or music and prequeuing or injecting (how?) some windows events. How to test this in a convincing manner?
Would the obligation to service messages disappear if the players ran in their own thread (like w9x seems to do)?
Thanks for your help, Jörg Höhle
Hi Joerg,
- Consequently, the players must implement a message loop and
dispatch regular window messages using DispatchMessageA/W Currently, Wine does not. This IMHO has potential for dead locks. Music and animations can play for a long time and messages ought to be serviced.
I'm not familiar with windows messages at all. What do you think about the consequence?
Are you concerned about the applications introducing deadlocks by not servicing messages quickly enough, or about MCI introducing deadlocks by not processing messages in the current thread?
If the former, I'd say that it's possible that Microsoft would consider this to be a buggy app, and not an issue for us. It's common to require that applications continue to "pump" the message loop when calling some blocking function. Modal dialog boxes continue to do so, for example.
If the latter, this probably requires that MCI pump the message loop while it's processing.
Point 2 should be testable by playing a long piece of video or music and prequeuing or injecting (how?) some windows events. How to test this in a convincing manner?
Perhaps call SetTimer with a period shorter than the duration of something you're about to play, and show that the thread receives a WM_TIMER before playing is complete?
Would the obligation to service messages disappear if the players ran in their own thread (like w9x seems to do)?
The obligation to process messages within MCI? Possibly. Since nothing since Win9x seems to use threads, however, I wouldn't be surprised if some app expects that it can post messages from its callbacks. In other words, don't expect all applications to be "Win9x safe."
Hope that helps, --Juan
Hi,
Juan Lang wrote:
Are you concerned about the applications introducing deadlocks by not servicing messages quickly enough, or about MCI introducing deadlocks by not processing messages in the current thread?
I was concerned both about the MCI and the rest of winmm (midi*, wave*) API. We've a few bug reports about apps that hang but work with a native msvfw32.dll. I'm wondering if that could be related (erk, another dll that I'm not familiar with).
If the latter, this probably requires that MCI pump the message loop while it's processing.
The MCI API explcitly acknowledges some need for message pumping in the MCI_WAIT case via the mciSetYieldProc function. MSDN says that the MCI drivers must periodically call it. None of Wine's MCI drivers do.
It's unclear to me why it should be called. Once I read that it's used to be able to react to the Break key to abort an animation (few people care). Maybe it's also needed to continuously dispatch messages (refresh, resize, buttons etc.)?
I found no similar information about the wave* and midi* functions. Yet testing indicates that they also hijack the application's thread since w2k, possibly for as long as there's audio to play. Perhaps there's no documentation precisely because that changed since w2k, all winmm documentation predates that and in w9x another thread was used so there was no analogue to MCI_WAIT design issues. Who could shed some light?
It's common to require that applications continue to "pump" the message loop when calling some blocking function. Modal dialog boxes continue to do so, for example.
Indeed, one of my colleagues has written a mono-threading multi-windowing application. It rarely seems to hang, except when reading from CTAPI. It must be full of nested callbacks and calls to DispatchMessage.
What do you mean exactly by "message pumping"? There are a few places in Wine that call PeekMessage e.g. MCI_DefYieldProc, MMSYSTEM_MidiStream_MessageHandler, but to me it looks like an error when that is not accompanied by DispatchMessageA/W of all the messages that the local handler does not understand. I'd expect DispatchMessage, not PeekMessage to invoke all the callbacks. Isn't it an error for all loops executing on the app's thread?
I wouldn't be surprised if some app expects that it can post messages from its callbacks.
MSDN on waveOutProc explicitly allows Post[Thread]Message. wave* are forbidden (no waveOutWrite from within a WOM_DONE callback, no midiOutClose, but there are logs in Bugzilla that show otherwise).
MSDN documents MMSYSERR_HANDLEBUSY "The handle is being used simultaneously by another thread (for example, a callback thread)." I've never seen that error. Yet it means that they are considering detecting possible dead-locks and contentions.
Thank you, Jörg Höhle
None of Wine's MCI drivers do.
(snip)
Who could shed some light?
Have you looked at any open source MCI drivers? They may or may not be of the best quality, but at least one exists in my brief perusal: the MediaXW package, http://sourceforge.net/projects/mediaxw/
What do you mean exactly by "message pumping"? There are a few places in Wine that call PeekMessage e.g. MCI_DefYieldProc, MMSYSTEM_MidiStream_MessageHandler, but to me it looks like an error when that is not accompanied by DispatchMessageA/W of all the messages that the local handler does not understand. I'd expect DispatchMessage, not PeekMessage to invoke all the callbacks. Isn't it an error for all loops executing on the app's thread?
It's a broad topic, but yes, basically you want to call DispatchMessage on some messages periodically. See e.g. MsgWaitForMultipleHandles. --Juan
Hi,
Juan Lang wrote:
What do you mean exactly by "message pumping"?
It's a broad topic, but yes, basically you want to call DispatchMessage on some messages periodically. See e.g. MsgWaitForMultipleHandles.
Thanks for the link to http://blogs.msdn.com/b/oldnewthing/ in another thread. That day's top post http://blogs.msdn.com/b/oldnewthing/archive/2011/03/23/10144592.aspx gave the answer to another question I had faced during my redesign of the MCI MIDI player: How does WaitFor(threadHandle) react should the thread being waited for use CloseHandle(threadHandle) prior to exiting?
Back to message pumping, http://blogs.msdn.com/b/oldnewthing/archive/2011/03/04/10136703.aspx says: "Furthermore, it's a known quantity for programs that when you call GetMessage or PeekMessage, incoming sent messages are dispatched [...]" Looks like I was confused. The model of window events I have in mind is still influenced by how things work in AmigaOS; I'm not familiar with MS-Windows' behaviour. Now I know many things happen before GetMessage returns.
DispatchMessage is not always needed. Unfortunately, I don't grok yet when DispatchMessage is required.
http://blogs.msdn.com/b/oldnewthing/archive/2004/06/08/150929.aspx "Everybody who has messed with window messaging knows that GetMessage and PeekMessage retrieve queued messages, which are dispatched to windows via DispatchMessage."
None the clearer. If I just retrieved them (they were obviously "dispatched" to my queue), why must I dispatch again? I.e. what's the kind of work that the function calling GetMessage Should/can do vs. the work to be done by whatever function DispatchMessage eventually calls?
Regards, Jörg Höhle
Hi Joerg,
DispatchMessage is not always needed. Unfortunately, I don't grok yet when DispatchMessage is required.
http://blogs.msdn.com/b/oldnewthing/archive/2004/06/08/150929.aspx "Everybody who has messed with window messaging knows that GetMessage and PeekMessage retrieve queued messages, which are dispatched to windows via DispatchMessage."
None the clearer. If I just retrieved them (they were obviously "dispatched" to my queue), why must I dispatch again? I.e. what's the kind of work that the function calling GetMessage Should/can do vs. the work to be done by whatever function DispatchMessage eventually calls?
GetMessage removes a message from the input queue, PeekMessage allows you to examine the contents of the message queue, but neither actually delivers the message to the appropriate WndProc. That's what DispatchMessage does. They're separate either because of history or because of design, but in either case, they are separate ;)
PeekMessage is useful for message pumps: it allows you to retrieve specific messages from the queue that you wish to handle yourself, without retrieving messages the main application expects to receive.
There are many references out there on Win32, but if you were to consult a book, Charles Petzold's book Programming Windows is the classic guide: http://www.charlespetzold.com/pw5/index.html
--Juan
Den 08. april 2011 13:15, skrev Joerg-Cyril.Hoehle@t-systems.com:
DispatchMessage is not always needed. Unfortunately, I don't grok yet when DispatchMessage is required.
http://blogs.msdn.com/b/oldnewthing/archive/2004/06/08/150929.aspx "Everybody who has messed with window messaging knows that GetMessage and PeekMessage retrieve queued messages, which are dispatched to windows via DispatchMessage."
None the clearer. If I just retrieved them (they were obviously "dispatched" to my queue), why must I dispatch again?
No, they were *not* dispatched to your queue, they were queued (posted). DispatchMessage calls the appropriate window procedure, it is not used to queue messages.
Sending and queuing is *not* the same. The rule is basically:
- If the message was queued with Post*Message, then GetMessage/PeekMessage returns it and you should pass it to DispatchMessage. - If the message was sent with Send*Message, then GetMessage/PeekMessage handles (dispatches) it, does not return it, and thus DispatchMessage would never even see it.
Consider sent messages synchronous, and posted/queued messages as asynchronous. Windows may reorder queued (asynchronous) messages by message priority class, so that e.g. GetMessage may return a WM_PAINT only after all other (higher-priority) messages have been returned and dispatched.
I.e. what's the kind of work that the function calling GetMessage Should/can do vs. the work to be done by whatever function DispatchMessage eventually calls?
The function calling GetMessage isn't supposed to do anything beyond calling DispatchMessage.
On 4/9/11 12:43 PM, Ove Kaaven wrote:
The function calling GetMessage isn't supposed to do anything beyond calling DispatchMessage.
What about TranslateMessage()?
Chip
Den 09. april 2011 20:47, skrev Charles Davis:
On 4/9/11 12:43 PM, Ove Kaaven wrote:
The function calling GetMessage isn't supposed to do anything beyond calling DispatchMessage.
What about TranslateMessage()?
I didn't mean it all that literally, but fine, if you want to pick that nit... however, TranslateMessage is only useful if you plan to process text input, which is probably not usually the case for multimedia players anyway (perhaps except in modal dialog boxes, but they have their own independent message loop anyway, implemented in user32).