/****************************************************************************** Copyright (C) Microsoft Corporation 1985-1991. All rights reserved. Title: avitask.c - Background task that actually manipulates AVI files. *****************************************************************************/ #include "graphic.h" void FAR PASCAL DebugBreak(void); BOOL FAR PASCAL mciaviCloseFile(NPMCIGRAPHIC npMCI); BOOL FAR PASCAL mciaviOpenFile(NPMCIGRAPHIC npMCI); #if defined(WIN32) || !defined(DEBUG) #define StackTop() (void *)0 #define StackMin() (void *)0 #define StackBot() (void *)0 #define StackMark() #define StackTest() TRUE #else #define STACK _based(_segname("_STACK")) #define StackTop() *((UINT STACK *)10) #define StackMin() *((UINT STACK *)12) #define StackBot() *((UINT STACK *)14) #define StackMark() *((UINT STACK*)StackBot()) = 42 #define StackTest() *((UINT STACK*)StackBot()) == 42 #endif /*************************************************************************** ***************************************************************************/ #ifndef WIN32 #pragma optimize("", off) void FAR SetPSP(UINT psp) { _asm { mov bx,psp mov ah,50h int 21h } } #pragma optimize("", on) #endif /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api void | mciaviTask | This function is the background task which plays * AVI files. It is called as a result of the call to mmTaskCreate() * in DeviceOpen(). When this function returns, the task is destroyed. * * @parm DWORD | dwInst | instance data passed to mmCreateTask - contains * a pointer to an instance data block. * ***************************************************************************/ void FAR PASCAL _LOADDS mciaviTask(DWORD dwInst) { NPMCIGRAPHIC npMCI; npMCI = (NPMCIGRAPHIC) dwInst; // Set this task's error mode to the same as the parent's. SetErrorMode(npMCI->uErrorMode); DPF2(("MCIAVI: Bkgd Task hTask=%04X\n", GetCurrentTask())); DPF2(("MCIAVI: Stack: %04X %04X %04X\n", StackTop(), StackMin(), StackBot())); /* Task state is TASKBEINGCREATED at fn. entry, then goes to TASKINIT. */ Assert(npMCI && npMCI->wTaskState == TASKBEINGCREATED); npMCI->wTaskState = TASKINIT; #ifndef WIN32 // // in order to make this task, more like a "thread" we want to use the // same PSP as our parent, so we can share file handles and things. // // when we get created hTask is a PSP // npMCI->pspTask = GetCurrentPDB(); // save our PSP #endif npMCI->hTask = GetCurrentTask(); npMCI->dwTaskError = 0; /* Open the file */ if (!mciaviOpenFile(npMCI)) { // NOTE: IsTask() returns FALSE when hTask==0 // Set hTask to 0 BEFORE setting wTaskState. Our creator is polling // the state of wTaskState... // npMCI->wTaskState = TASKABORT; // npMCI->hTask = 0; // This stops others using this task thread. DPF1(("Failed to open AVI file\n")); goto exit; } while (IsTask(npMCI->hTask)) { npMCI->wTaskState = TASKIDLE; DPF2(("MCIAVI: Idle\n")); DPF2(("MCIAVI: Stack: %04X %04X %04X\n", StackTop(), StackMin(), StackBot())); StackMark(); /* Block until task is needed. The task count could */ /* be anything at the exit of playfile or recordfile */ /* so continue to block until the state really changes. */ while (npMCI->wTaskState == TASKIDLE) { mmTaskBlock(npMCI->hTask); } mciaviMessage(npMCI, npMCI->wTaskState); AssertSz(StackTest(), "Stack overflow"); if (npMCI->wTaskState == TASKCLOSE) { break; } } exit: mciaviTaskCleanup(npMCI); } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api WORD | mciaviTaskCleanup | called when the background task * is being destroyed. This is where critical cleanup goes. * ***************************************************************************/ void FAR PASCAL mciaviTaskCleanup(NPMCIGRAPHIC npMCI) { #ifndef WIN32 // // restore our PSP back to normal before exit. // if (npMCI->pspTask) { SetPSP(npMCI->pspTask); } #endif #ifdef USEAVIFILE // // we must do this so COMPOBJ will shut down right. // FreeAVIFile(npMCI); #endif // // call a MSVideo shutdown routine. // // // Signal the foreground task that we're all done. // This must be absolutely the last thing we do. // npMCI->hTask = 0; npMCI->wTaskState = TASKCLOSED; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api void | mciaviMessage | this function handles a message from the * background task. * ***************************************************************************/ void NEAR PASCAL mciaviMessage(NPMCIGRAPHIC npMCI, UINT msg) { UINT wNotification; switch (msg) { case TASKREADINDEX: Assert(0); break; /* Check to see if we just got closed */ case TASKCLOSE: DPF1(("MCIAVI: Closing\n")); // hold critsec during close in case someone comes in to // eg DeviceRealize during the close when things are half-deleted. EnterCrit(npMCI); mciaviCloseFile(npMCI); LeaveCrit(npMCI); /* The htask must be set to NULL, otherwise CloseDevice() will */ /* get stuck. */ // NOTE: IsTask() returns FALSE when hTask==0 // npMCI->hTask = 0; // npMCI->wTaskState = TASKABORT; return; case TASKRELOAD: DPF(("MCIAVI: Loading new file....\n")); mciaviCloseFile(npMCI); npMCI->dwTaskError = 0; npMCI->wTaskState = TASKINIT; if (!mciaviOpenFile(npMCI)) { // !!! mciaviOpenNew() !!!!!!!!!!!!!!!!!!!!! npMCI->wTaskState = TASKCLOSE; // npMCI->hTask = 0; return; } break; // We've been woken up to play.... case TASKSTARTING: DPF2(("MCIAVI: Now busy\n")); /* Reset to no error */ npMCI->dwTaskError = 0; wNotification = mciaviPlayFile(npMCI); if ((wNotification != MCI_NOTIFY_FAILURE) || ((npMCI->dwFlags & MCIAVI_WAITING) == 0)) GraphicDelayedNotify(npMCI, wNotification); break; default: DPF(("MCIAVI: Unknown task state!!!! (%d)\n", msg)); break; } } #ifdef WIN32 /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api int | GetPrioritySeparation | Find the foreground process priority * boost * * @rdesc Returns 0, 1 or 2 * ***************************************************************************/ DWORD GetPrioritySeparation(void) { static DWORD Win32PrioritySeparation = 0xFFFFFFFF; /* If we're not initialized get the current separation */ if (Win32PrioritySeparation == 0xFFFFFFFF) { HKEY hKey; Win32PrioritySeparation = 2; // This is the default /* Code copied from shell\control\main\prictl.c */ if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\PriorityControl"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) { DWORD Type; DWORD Length; Length = sizeof(Win32PrioritySeparation); /* Read the value which is the priority boost given to forground processes */ if (RegQueryValueEx( hKey, TEXT("Win32PrioritySeparation"), NULL, &Type, (LPBYTE)&Win32PrioritySeparation, &Length ) != ERROR_SUCCESS) { Win32PrioritySeparation = 2; } RegCloseKey(hKey); } } return Win32PrioritySeparation; } #endif // WIN32 /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api void| aviTaskYield | This function yields in the picky way windows * wants us to. * * basicly we Dispatch any messages in our que that belong to a window. * * NOTE we should not remove * ***************************************************************************/ void NEAR PASCAL aviTaskYield(void) { MSG msg; #ifdef WIN32 DWORD PrioritySeparation; // // Do our own kind of 'yield'. The reason for doing the // Peekmessage on Windows 3.1 was that if you didn't call // it Windows would think you were spinning out of control. // For Windows NT if you call PeekMessage 100 times without // getting anything your priority is lowered which would mess // up our tinkering with the priority here. // PrioritySeparation = GetPrioritySeparation(); if (PrioritySeparation != 0) { SetThreadPriority(GetCurrentThread(), PrioritySeparation == 1 ? THREAD_PRIORITY_BELOW_NORMAL : // minus 1 THREAD_PRIORITY_LOWEST); // minus 2 Sleep(0); // Causes reschedule decision SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); } else { Sleep(0); // Let other threads in } #else // // if we were MCIWAVE we would do this.... // //if (PeekMessage(&msg, NULL, 0, WM_MM_RESERVED_FIRST-1, PM_REMOVE)) if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { DPF(("aviTaskYield: got message %04X to window %04X\n", msg.message, msg.hwnd)); DispatchMessage(&msg); } #endif // WIN32 }