windows-nt/Source/XPSP1/NT/multimedia/media/mciwave/support.c
2020-09-26 16:20:57 +08:00

266 lines
6.8 KiB
C

/*******************************Module*Header*********************************\
* Module Name: support.c
*
* MultiMedia Systems MCIWAVE DLL
*
* Created: 27-Feb-1992
* Author: ROBINSP
*
* History:
*
* Copyright (c) 1985-1996 Microsoft Corporation
*
\******************************************************************************/
#define UNICODE
#include <windows.h>
#include <mciwave.h>
STATICDT CRITICAL_SECTION CritSec;
#if DBG
STATICDT UINT cCritSec = 0;
DWORD dwCritSecOwner = 0;
#endif
/*************************************************************************
*
* Cut-down critical section stuff
*
* This critical section is used to simulate windows tasking
* The owner of the critical section runs exclusively in this
* DLL.
*
* At the front of each function request the critical section is
* grabbed and only release on mmYield or TaskBlock.
*
* Extra 'tasks' (threads) per device hold the critical section when
* they are working.
*
* This method has been used to simplify porting the code from
* windows. A rewrite would use a different mechanism.
*
************************************************************************/
VOID InitCrit(VOID)
{
InitializeCriticalSection(&CritSec);
}
VOID DeleteCrit(VOID)
{
DeleteCriticalSection(&CritSec);
}
#if DBG
VOID DbgEnterCrit(UINT ln, LPCSTR lpszFile)
{
BOOL fPossibleWait;
if (dwCritSecOwner) {
dprintf3(("Critical section owned by thread %x", dwCritSecOwner));
fPossibleWait = TRUE;
} else {
fPossibleWait = FALSE;
}
EnterCriticalSection(&CritSec);
if (fPossibleWait) {
dprintf2(("...entered critical section after possible wait"));
}
if (!cCritSec++) {
// This is the first time into the critcal section
dwCritSecOwner = GetCurrentThreadId();
dprintf3(("...entered critical section (%d) at line %d in file %s", cCritSec, ln, lpszFile));
} else {
dprintf1(("Reentering critical section, count = %d", cCritSec));
WinAssert(0);
// Note: if the memory allocation stuff starts to be synchronised
// then this assertion becomes invalid.
}
}
#else
VOID EnterCrit(VOID)
{
EnterCriticalSection(&CritSec);
}
#endif
VOID LeaveCrit(VOID)
{
#if DBG
if (!--cCritSec) {
// Relinquishing control of the critcal section
dwCritSecOwner = 0;
dprintf2(("...relinquished critical section (%d)",cCritSec));
} else {
dprintf3(("Leaving critical section, count = %d", cCritSec));
}
#endif
LeaveCriticalSection(&CritSec);
}
/*************************************************************************
*
* @doc MCIWAVE
*
* @func UINT | TaskBlock | This function blocks the current
* task context if its event count is 0.
*
* @rdesc Returns the message value of the signal sent.
*
************************************************************************/
UINT TaskBlock(VOID)
{
MSG msg;
dprintf3(("Thread %x blocking", GetCurrentThreadId()));
LeaveCrit();
/*
* Loop until we get the message we want
*/
for (;;) {
/*
* Retrieve any message for task
*/
GetMessage(&msg, NULL, 0, 0);
/*
* If the message is for a window dispatch it
*/
if (msg.hwnd != NULL) {
DispatchMessage(&msg);
} else {
if (msg.message != WM_USER &&
msg.message != WTM_STATECHANGE) {
dprintf1(("Got thread message %8X", msg.message));
}
//
// Because MCIWAVE background task can't cope with getting
// random(?) messages like MM_WIM_DATA because it thinks that
// WM_USER IS its MM_WIM_DATA. Let the expected WM_USER
// messages go through, but trap the MM_WIM_DATA so that
// MCIWAVE's buffers don't get all messed up.
//
if (msg.message != MM_WIM_DATA)
break;
}
}
dprintf3(("TaskBlock returning with message 0x%x", msg.message));
EnterCrit();
return msg.message;
}
/*************************************************************************
*
* @doc MCIWAVE
*
* @func BOOL | TaskSignal | This function signals the specified
* task, incrementing its event count and unblocking
* it.
*
* @parm HANDLE | h | Task handle. For predictable results, get the
* task handle from <f mmGetCurrentTask>.
*
* @parm UINT | Msg | Signal message to send.
*
* @rdesc Returns TRUE if the signal was sent, else FALSE if the message
* queue was full.
*
* @xref mmTaskBlock mmTaskCreate
*
* @comm For predictable results, must only be called from a task
* created with <f mmTaskCreate>.
*
************************************************************************/
BOOL TaskSignal(DWORD h, UINT Msg)
{
#ifdef DBG
BOOL fErr;
dprintf2(("Signalling Thread %x", (ULONG)h));
fErr = PostThreadMessage(h, Msg, 0, 0);
if (!fErr) {
dprintf1(("Error %d signalling Thread %x", GetLastError(), (ULONG)h));
}
return(fErr);
#else
return PostThreadMessage(h, Msg, 0, 0);
#endif
}
/*************************************************************************
*
* @doc MCIWAVE
*
* @func VOID | TaskWaitComplete | This function waits for the
* specified task to terminate.
*
* @parm HANDLE | h | Task handle. For predictable results, get the
* task handle from <f mmGetCurrentTask>.
*
* @rdesc No return code
*
************************************************************************/
VOID TaskWaitComplete(HANDLE h)
{
UINT Rc;
LeaveCrit();
/* Wait (no timeout) for thread to complete */
Rc = WaitForSingleObject(h, INFINITE);
if (Rc != 0) {
dprintf(("Error terminating thread - WaitForSingleObject returned non-zero !!!"));
}
/* Note that the handle must be freed by us */
CloseHandle(h);
EnterCrit();
}
#if DBG
/*************************************************************************
*
* @doc MCIWAVE
*
* @func VOID | mmYield | This function checks that we are in the
* critical section before Yielding. If we are then the
* critical section is reentered after yielding.
*
* @parm <t>PWAVEDESC<d> | pwd |
* Pointer to the wave device descriptor.
*
* @rdesc No return code
*
************************************************************************/
VOID mmDbgYield(
PWAVEDESC pwd,
UINT ln,
LPCSTR lpszFile)
{
if (GetCurrentThreadId() != dwCritSecOwner) {
dprintf1(("mmYield called while not in the critical section from line %d in file %s", ln, lpszFile));
}
CheckIn();
LeaveCrit();
CheckOut();
Sleep(10);
EnterCrit();
}
#endif