/****************************************************************************** Copyright (C) Microsoft Corporation 1985-1991. All rights reserved. Title: graphic.c - Multimedia Systems Media Control Interface driver for AVI. *****************************************************************************/ #include "graphic.h" //#include "dispdib.h" #include "cnfgdlg.h" #include #ifdef EXPIRE #include #endif #include "avitask.h" #ifdef DEBUG #define static #endif // // This is the version number of MSVIDEO.DLL we need in order to run // build 81 is when we added the VideoForWindowsVersion() function to // MSVIDEO.DLL // // in build 85 // we removed the ICDecompressOpen() function and it became a macro. // we added a parameter to ICGetDisplayFormat() // we make DrawDibProfileDisplay() take a parameter // // in build 108 // Added ICOpenFunction() to open a hic using a function directly, // without calling ICInstall // Added some more ICDRAW_ messages // // in build 109 // Addded ICMessage() to compman // removed ICDrawSuggest() made it a macro. // Added ICMODE_FASTDECOMPRESS to ICLocate() // // Under NT the first build is sufficient !!! Is this true now? // #ifdef WIN32 #define MSVIDEO_VERSION (0x01000000) // 1.00.00.00 #else #define MSVIDEO_VERSION (0x010a0000l+109) // 1.10.00.109 #endif /* statics */ static INT swCommandTable = -1; #ifdef WIN32 static SZCODE szDisplayDibLib[] = TEXT("DISPDB32.DLL"); #else static SZCODE szDisplayDibLib[] = TEXT("DISPDIB.DLL"); #endif /* * files should be UNICODE. function names should not */ static SZCODEA szDisplayDib[] = "DisplayDib"; static SZCODEA szDisplayDibEx[] = "DisplayDibEx"; #ifdef WIN32 STATICDT SZCODE szMSVideo[] = TEXT("MSVFW32"); // With GetModuleHandle #else static SZCODE szMSVideo[] = TEXT("MSVIDEO"); #endif BOOL gfEvil; // TRUE if we cant close cuz dialog box is up BOOL gfEvilSysMenu; // TRUE if we cant close cuz system menu is up NPMCIGRAPHIC npMCIList; // list of all open instances. /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api void | GraphicInit | This function is called when the DriverProc * gets a DRV_LOAD message. * ***************************************************************************/ BOOL FAR PASCAL GraphicInit(void) { InitializeDebugOutput("MCIAVI"); if (!GraphicWindowInit()) return FALSE; swCommandTable = mciLoadCommandResource(ghModule, TEXT("mciavi"), 0); return TRUE; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicDrvOpen | This function is called when the DriverProc * gets a DRV_OPEN message. This happens each time that a new movie * is opened thru MCI. * * @parm LPMCI_OPEN_DRIVER_PARMS | lpOpen | Far pointer to the standard * MCI open parameters * * @rdesc Returns the mci device id. The installable driver interface will * pass this ID to the DriverProc in the dwDriverID parameter on all * subsequent messages. To fail the open, return 0L. * ***************************************************************************/ DWORD PASCAL GraphicDrvOpen(LPMCI_OPEN_DRIVER_PARMS lpOpen) { /* Specify the custom command table and the device type */ lpOpen->wCustomCommandTable = swCommandTable; lpOpen->wType = MCI_DEVTYPE_DIGITAL_VIDEO; /* Set the device ID to the MCI Device ID */ return (DWORD) (UINT)lpOpen->wDeviceID; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api void | GraphicFree | This function is called when the DriverProc * gets a DRV_FREE message. This happens when the drivers open count * reaches 0. * ***************************************************************************/ void PASCAL GraphicFree(void) { if (swCommandTable != -1) { mciFreeCommandResource(swCommandTable); swCommandTable = -1; } #ifdef WIN32 /* * unregister class so we can re-register it next time we are loaded */ GraphicWindowFree(); #endif } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicDelayedNotify | This is a utility function that * sends a notification saved with GraphicSaveCallback to mmsystem * which posts a message to the application. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data. * * @parm UINT | wStatus | The type of notification to use can be one of * MCI_NOTIFY_SUCCESSFUL, MCI_NOTIFY_SUPERSEDED, MCI_NOTIFY_ABORTED * or MCI_NOTIFY_FAILURE (see MCI ispec.) * ***************************************************************************/ void FAR PASCAL GraphicDelayedNotify(NPMCIGRAPHIC npMCI, UINT wStatus) { /* Send any saved notification */ if (npMCI->hCallback) { // If the system menu is the only thing keeping us from closing, bring // it down and then close. if (gfEvilSysMenu) SendMessage(npMCI->hwnd, WM_CANCELMODE, 0, 0); // If a dialog box is up, and keeping us from closing, we can't send the // notify or it will close us. if (!gfEvil) mciDriverNotify(npMCI->hCallback, npMCI->wDevID, wStatus); npMCI->hCallback = NULL; } } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicImmediateNotify | This is a utility function that * sends a successful notification message to mmsystem if the * notification flag is set and the error field is 0. * * @parm UINT | wDevID | device ID. * * @parm LPMCI_GENERIC_PARMS | lpParms | Far pointer to an MCI parameter * block. The first field of every MCI parameter block is the * callback handle. * * @parm DWORD | dwFlags | Parm. block flags - used to check whether the * callback handle is valid. * * @parm DWORD | dwErr | Notification only occurs if the command is not * returning an error. * ***************************************************************************/ void FAR PASCAL GraphicImmediateNotify(UINT wDevID, LPMCI_GENERIC_PARMS lpParms, DWORD dwFlags, DWORD dwErr) { if (!LOWORD(dwErr) && (dwFlags & MCI_NOTIFY)) { //Don't have an npMCI - see GraphicDelayedNotify //if (gfEvil) //SendMessage(npMCI->hwnd, WM_CANCELMODE, 0, 0); // If a dialog box is up, and keeping us from closing, we can't send the // notify or it will close us. if (!gfEvil) // !!! EVIL !!! mciDriverNotify((HANDLE) (UINT)lpParms->dwCallback, wDevID, MCI_NOTIFY_SUCCESSFUL); } } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicSaveCallback | This is a utility function that saves * a new callback in the instance data block. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data. * * @parm HANDLE | hCallback | callback handle * ***************************************************************************/ void NEAR PASCAL GraphicSaveCallback (NPMCIGRAPHIC npMCI, HANDLE hCallback) { /* If there's an old callback, kill it. */ GraphicDelayedNotify(npMCI, MCI_NOTIFY_SUPERSEDED); /* Save new notification callback window handle */ npMCI->hCallback = hCallback; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicClose | This function closes the movie and * releases the instance data. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD PASCAL GraphicClose (NPMCIGRAPHIC npMCI) { DWORD dwRet = 0L; NPMCIGRAPHIC p; if (npMCI) { dwRet = DeviceClose (npMCI); Assert(dwRet == 0); // If the system menu is the only thing keeping us from closing, bring // it down and then close. if (gfEvilSysMenu) SendMessage(npMCI->hwnd, WM_CANCELMODE, 0, 0); if (gfEvil) { DPF(("************************************************\n")); DPF(("** EVIL: Failing the close because we'd die **\n")); DPF(("************************************************\n")); LeaveCrit(npMCI); return MCIERR_DRIVER_INTERNAL; } /* If the default window still exists, close and destroy it. */ if (IsWindow(npMCI->hwndDefault)) { if (!DestroyWindow(npMCI->hwndDefault)) dwRet = MCIERR_DRIVER_INTERNAL; } if (npMCI->szFilename) { LocalFree((HANDLE) (npMCI->szFilename)); } // // find this instance on the list // if (npMCI == npMCIList) { npMCIList = npMCI->npMCINext; } else { for (p=npMCIList; p && p->npMCINext != npMCI; p=p->npMCINext) ; Assert(p && p->npMCINext == npMCI); p->npMCINext = npMCI->npMCINext; } #ifdef WIN32 // Delete the critical section object LeaveCriticalSection(&npMCI->CritSec); DeleteCriticalSection(&npMCI->CritSec); #endif /* Free the instance data block allocated in GraphicOpen */ LocalFree((HANDLE)npMCI); } return dwRet; } DWORD NEAR PASCAL FixFileName(NPMCIGRAPHIC npMCI, LPCTSTR lpName) { TCHAR ach[256]; ach[(sizeof(ach)/sizeof(TCHAR)) - 1] = TEXT('\0'); #ifndef WIN32 _fstrncpy(ach, (LPTSTR) lpName, (sizeof(ach)/sizeof(TCHAR)) - (1*sizeof(TCHAR))); #else wcsncpy(ach, (LPTSTR) lpName, (sizeof(ach)/sizeof(TCHAR)) - (1*sizeof(TCHAR))); #endif // // treat any string that starts with a '@' as valid and pass it to the // device any way. // if (ach[0] != '@') { if (!mmioOpen(ach, NULL, MMIO_PARSE)) return MCIERR_FILENAME_REQUIRED; } npMCI->szFilename = (NPTSTR) LocalAlloc(LPTR, sizeof(TCHAR) * (lstrlen(ach) + 1)); if (!npMCI->szFilename) { return MCIERR_OUT_OF_MEMORY; } lstrcpy(npMCI->szFilename, ach); return 0L; } /************************************************************************** ***************************************************************************/ #define SLASH(c) ((c) == TEXT('/') || (c) == TEXT('\\')) //#define SLASH(c) ((c) == '/' || (c) == '\\') // Filename Ascii?? STATICFN LPCTSTR FAR FileName(LPCTSTR szPath) { LPCTSTR sz; sz = &szPath[lstrlen(szPath)]; for (; sz>szPath && !SLASH(*sz) && *sz!=TEXT(':');) sz = CharPrev(szPath, sz); return (sz>szPath ? sz + 1 : sz); } /**************************************************************************** ****************************************************************************/ STATICFN DWORD NEAR PASCAL GetMSVideoVersion() { HANDLE h; extern DWORD FAR PASCAL VideoForWindowsVersion(void); // // don't call VideoForWindowsVersion() if it does not exist or KERNEL // will kill us with a undef dynalink error. // if ((h = GetModuleHandle(szMSVideo)) && GetProcAddress(h, (LPSTR) MAKEINTATOM(2))) return VideoForWindowsVersion(); else return 0; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicOpen | This function opens a movie file, * initializes an instance data block, and creates the default * stage window. * * @parm NPMCIGRAPHIC FAR * | lpnpMCI | Far pointer to a near pointer * to instance data block to be filled in by this function. * * @parm DWORD | dwFlags | Flags for the open message. * * @parm LPMCI_DGV_OPEN_PARMS | Parameters for the open message. * * @parm UINT | wDeviceID | The MCI Device ID for this instance. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD PASCAL GraphicOpen (NPMCIGRAPHIC FAR * lpnpMCI, DWORD dwFlags, LPMCI_DGV_OPEN_PARMS lpOpen, UINT wDeviceID) { NPMCIGRAPHIC npMCI; DWORD dwStyle; HWND hWnd; HWND hWndParent; DWORD dwRet; if (dwFlags & MCI_OPEN_SHAREABLE) { if (lpOpen->lpstrElementName == NULL || lpOpen->lpstrElementName[0] != '@') { return MCIERR_UNSUPPORTED_FUNCTION; } } // // check the verion of MSVIDEO.DLL before going any further // if we run a "new" version of MCIAVI on a old MSVIDEO.DLL // then bad things will happen. We assume all MSVIDEO.DLLs // will be backward compatible so we check for any version // greater than the expected version. // DPF(("Video For Windows Version %d.%02d.%02d.%02d\n", HIBYTE(HIWORD(GetMSVideoVersion())), LOBYTE(HIWORD(GetMSVideoVersion())), HIBYTE(LOWORD(GetMSVideoVersion())), LOBYTE(LOWORD(GetMSVideoVersion())) )); if (GetMSVideoVersion() < MSVIDEO_VERSION) { TCHAR achError[128]; TCHAR ach[40]; LoadString(ghModule, MCIAVI_BADMSVIDEOVERSION, achError, sizeof(achError)/sizeof(TCHAR)); LoadString(ghModule, MCIAVI_PRODUCTNAME, ach, sizeof(ach)/sizeof(TCHAR)); MessageBox(NULL,achError,ach, #ifdef BIDI MB_RTL_READING | #endif MB_OK|MB_SYSTEMMODAL|MB_ICONEXCLAMATION); return MCIERR_DRIVER_INTERNAL; } #ifndef WIN32 #pragma message("Support passing in MMIOHANDLEs with OPEN_ELEMENT_ID?") #endif if (lpOpen->lpstrElementName == NULL) { // they're doing an "open new". // !!! handle this, probably by not actually reading a file. // ack. } /* Be sure we have a real, non-empty filename, not an id. */ if ((!(dwFlags & MCI_OPEN_ELEMENT)) || (lpOpen->lpstrElementName == NULL) || (*(lpOpen->lpstrElementName) == '\0')) return MCIERR_UNSUPPORTED_FUNCTION; // Allocate an instance data block. Code ASSUMES Zero Init. if (!(npMCI = (NPMCIGRAPHIC) LocalAlloc(LPTR, sizeof (MCIGRAPHIC)))) return MCIERR_OUT_OF_MEMORY; #ifdef WIN32 // init the per-device critsec InitializeCriticalSection(&npMCI->CritSec); npMCI->lCritRefCount = 0; #endif // now hold the critical section for the rest of the open EnterCrit(npMCI); #ifdef DEBUG npMCI->mciid = MCIID; #endif // // add this device to our list // npMCI->npMCINext = npMCIList; npMCIList = npMCI; npMCI->wMessageCurrent = MCI_OPEN; // Allocate some space for the filename // Copy the filename into the data block dwRet = FixFileName(npMCI, lpOpen->lpstrElementName); if (dwRet != 0L) { // note we hold the critical section into GraphicClose, and // release it just before deleting it within GraphicClose. This is // because we need to hold it during the call to DeviceClose. GraphicClose(npMCI); return dwRet; } // Create the default window - the caller may // supply style and parent window. if (dwFlags & MCI_DGV_OPEN_PARENT) hWndParent = lpOpen->hWndParent; else hWndParent = NULL; if (dwFlags & MCI_DGV_OPEN_WS) { // CW_USEDEFAULT can't be used with popups or children so // if the user provides the style, default to full-screen. dwStyle = lpOpen->dwStyle; hWnd = // Note: The CreateWindow/Ex call is written this way as on Win32 // CreateWindow is a MACRO, and hence the call must be contained // within the preprocessor block. #ifdef BIDI CreateWindowEx(WS_EX_BIDI_SCROLL | WS_EX_BIDI_MENU |WS_EX_BIDI_NOICON, szClassName, FileName(npMCI->szFilename), dwStyle, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), hWndParent, NULL, ghModule, (LPTSTR)npMCI); #else CreateWindow( szClassName, FileName(npMCI->szFilename), dwStyle, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), hWndParent, NULL, ghModule, (LPTSTR)npMCI); #endif } else { dwStyle = WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; if (GetProfileInt("mciavi", "CreateVisible", 0)) { DPF0(("Creating the window visible\n")); dwStyle |= WS_VISIBLE; } else { DPF0(("Creating the window INvisible\n")); } hWnd = #ifdef BIDI CreateWindowEx(WS_EX_BIDI_SCROLL | WS_EX_BIDI_MENU |WS_EX_BIDI_NOICON, szClassName, FileName(npMCI->szFilename), dwStyle, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, hWndParent, NULL, ghModule, (LPTSTR)npMCI); #else CreateWindow( szClassName, FileName(npMCI->szFilename), dwStyle, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, hWndParent, NULL, ghModule, (LPTSTR)npMCI); #endif } if (!hWnd) { // see above - we release and delete the critsec within GraphicClose DPF0(("Failed to create the window\n")); GraphicClose(npMCI); return MCIERR_CREATEWINDOW; } /* Fill in some more of the instance data. ** The rest of the fields are filled in in DeviceOpen. */ npMCI->hCallingTask = GetCurrentTask(); npMCI->hCallback = NULL; npMCI->wDevID = wDeviceID; npMCI->hwndDefault = hWnd; npMCI->hwnd = hWnd; npMCI->dwTimeFormat = MCI_FORMAT_FRAMES; npMCI->dwSpeedFactor = 1000; npMCI->dwVolume = MAKELONG(500, 500); npMCI->lTo = 0L; npMCI->dwFlags = MCIAVI_PLAYAUDIO | MCIAVI_SHOWVIDEO; npMCI->dwOptionFlags = ReadConfigInfo() | MCIAVIO_STRETCHTOWINDOW; // perform device-specific initialization dwRet = DeviceOpen(npMCI, dwFlags); if (dwRet != 0) { // see above - we release and delete the critsec within GraphicClose GraphicClose(npMCI); return dwRet; } *lpnpMCI = npMCI; npMCI->wMessageCurrent = 0; LeaveCrit(npMCI); return 0L; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicLoad | This function supports the MCI_LOAD command. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the Load message. * * @parm LPMCI_DGV_LOAD_PARMS | lpLoad | Parameters for the LOAD message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicLoad(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_LOAD_PARMS lpLoad) { #ifndef LOADACTUALLYWORKS return MCIERR_UNSUPPORTED_FUNCTION; #else DWORD dw; if (!(dwFlags & MCI_LOAD_FILE)) return MCIERR_MISSING_PARAMETER; dw = FixFileName(npMCI, lpLoad->lpfilename); if (dw) return dw; dw = DeviceLoad(npMCI); return dw; #endif } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicSeek | This function sets the current frame. The * device state after a seek is MCI_MODE_PAUSE * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the seek message. * * @parm LPMCI_DGV_SEEK_PARMS | lpSeek | Parameters for the seek message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicSeek (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_SEEK_PARMS lpSeek) { LONG lTo; BOOL fTest = FALSE; /* Do some range checking then pass onto the device-specific routine. */ if (dwFlags & MCI_TEST) { dwFlags &= ~(MCI_TEST); fTest = TRUE; } switch (dwFlags & (~(MCI_WAIT | MCI_NOTIFY))) { case MCI_TO: lTo = ConvertToFrames(npMCI, lpSeek->dwTo); break; case MCI_SEEK_TO_START: lTo = 0; break; case MCI_SEEK_TO_END: lTo = npMCI->lFrames; break; case 0: return MCIERR_MISSING_PARAMETER; default: if (dwFlags & ~(MCI_TO | MCI_SEEK_TO_START | MCI_SEEK_TO_END | MCI_WAIT | MCI_NOTIFY)) return MCIERR_UNRECOGNIZED_KEYWORD; else return MCIERR_FLAGS_NOT_COMPATIBLE; break; } if (!IsWindow(npMCI->hwnd)) return MCIERR_NO_WINDOW; if (lTo < 0 || lTo > npMCI->lFrames) return MCIERR_OUTOFRANGE; if (fTest) return 0L; GraphicDelayedNotify (npMCI, MCI_NOTIFY_ABORTED); if (dwFlags & MCI_NOTIFY) { GraphicSaveCallback(npMCI, (HANDLE) (UINT)lpSeek->dwCallback); } /* Clear the 'repeat' flags */ npMCI->dwFlags &= ~(MCIAVI_REPEATING); return DeviceSeek(npMCI, lTo, dwFlags); } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicCue | This function gets the movie ready to play, * but leaves it paused. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the cue message. * * @parm LPMCI_DGV_CUE_PARMS | lpCue | Parameters for the cue message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicCue(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_CUE_PARMS lpCue) { LONG lTo; DWORD dwRet = 0L; if (dwFlags & MCI_DGV_CUE_INPUT) return MCIERR_UNSUPPORTED_FUNCTION; if (dwFlags & MCI_DGV_CUE_NOSHOW) return MCIERR_UNSUPPORTED_FUNCTION; if (dwFlags & MCI_TO) { lTo = ConvertToFrames(npMCI, lpCue->dwTo); if (lTo < 0L || lTo > npMCI->lFrames) return MCIERR_OUTOFRANGE; } /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L; GraphicDelayedNotify(npMCI, MCI_NOTIFY_ABORTED); if (dwFlags & MCI_NOTIFY) { GraphicSaveCallback(npMCI, (HANDLE) (UINT)lpCue->dwCallback); } /* Clear the 'repeat' flags */ npMCI->dwFlags &= ~(MCIAVI_REPEATING); /* Set up to play to end of file */ npMCI->lTo = npMCI->lFrames; dwRet = DeviceCue(npMCI, lTo, dwFlags); return dwRet; } #ifndef WIN32 #ifdef EXPIRE // // return the current date.... // // dx = year // ah = month // al = day // #pragma optimize("", off) DWORD DosGetDate(void) { if (0) return 0; _asm { mov ah,2ah int 21h mov ax,dx mov dx,cx } } #pragma optimize("", on) #endif #endif /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicPlay | This function starts playback of the movie. If * the reverse flag is specified, the movie plays backwards. If the fast * or slow flags are specified the movie plays faster or slower. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the play message. * * @parm LPMCI_DGV_PLAY_PARMS | lpPlay | Parameters for the play message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicPlay (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_PLAY_PARMS lpPlay ) { LONG lTo, lFrom; DWORD dwRet; #ifdef EXPIRE #pragma message("Remove the expiration code after Beta ships") if (DosGetDate() >= EXPIRE) { return MCIERR_AVI_EXPIRED; } #endif if (!(dwFlags & (MCI_MCIAVI_PLAY_FULLSCREEN | MCI_MCIAVI_PLAY_WINDOW)) && (npMCI->dwOptionFlags & MCIAVIO_USEVGABYDEFAULT)) { if (npMCI->dwOptionFlags & MCIAVIO_ZOOMBY2) dwFlags |= MCI_MCIAVI_PLAY_FULLBY2; else dwFlags |= MCI_MCIAVI_PLAY_FULLSCREEN; } if (dwFlags & (MCI_MCIAVI_PLAY_FULLSCREEN | MCI_MCIAVI_PLAY_FULLBY2)) { #if 0 if (ghDISPDIB == NULL) { UINT w; w = SetErrorMode(SEM_NOOPENFILEERRORBOX); #ifndef WIN32 if ((ghDISPDIB = LoadLibrary(szDisplayDibLib)) > HINSTANCE_ERROR) #else if ((ghDISPDIB = LoadLibrary(szDisplayDibLib)) != NULL) #endif { (FARPROC)DisplayDibProc = GetProcAddress(ghDISPDIB, szDisplayDib); (FARPROC)DisplayDibExProc = GetProcAddress(ghDISPDIB, szDisplayDibEx); } else ghDISPDIB = (HINSTANCE)-1; SetErrorMode(w); DPF(("ghDISPDIB=0x%04x, DisplayDibProc=0x%08lx\n", ghDISPDIB, DisplayDibProc)); } if (DisplayDibProc == NULL) return MCIERR_AVI_NODISPDIB; #endif } else { if (!IsWindow(npMCI->hwnd)) return MCIERR_NO_WINDOW; npMCI->dwFlags |= MCIAVI_NEEDTOSHOW; } /* Range checks : 0 < 'from' <= 'to' <= last frame */ if (dwFlags & MCI_TO) { lTo = ConvertToFrames(npMCI, lpPlay->dwTo); if (lTo < 0L || lTo > npMCI->lFrames) return MCIERR_OUTOFRANGE; } else if (dwFlags & MCI_DGV_PLAY_REVERSE) lTo = 0; else lTo = npMCI->lFrames; dwFlags |= MCI_TO; if (dwFlags & MCI_FROM) { lFrom = ConvertToFrames(npMCI, lpPlay->dwFrom); if (lFrom < 0L || lFrom > npMCI->lFrames) return MCIERR_OUTOFRANGE; } else if (dwRet = DevicePosition(npMCI, &lFrom)) return dwRet; /* check 'to' and 'from' relationship. */ if (lTo < lFrom) dwFlags |= MCI_DGV_PLAY_REVERSE; if ((lFrom < lTo) && (dwFlags & MCI_DGV_PLAY_REVERSE)) return MCIERR_OUTOFRANGE; /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L; /* We want any previous playing to be aborted if and only if a 'from' ** parameter is specified. If only a new 'to' parameter is specified, ** we can just change the 'to' value, and play will stop at the ** proper time. */ /* set the 'to' position after we've stopped, if we're stopping. */ if (dwFlags & MCI_FROM) { /* If MCI_FROM flag is specified then reset the starting location */ DeviceStop(npMCI, MCI_WAIT); npMCI->lFrom = lFrom; } else { /* We still set the "From" variable, so that we'll correctly ** play from the current position. ** !!! Should this be done instead by updating lFrom to be the ** current position when playback ends? */ npMCI->lFrom = lFrom; } /* If we're changing the "to" position, abort any pending notify. */ if (lTo != npMCI->lTo) { GraphicDelayedNotify (npMCI, MCI_NOTIFY_ABORTED); } /* Don't set up notify until here, so that the seek won't make it happen*/ if (dwFlags & MCI_NOTIFY) { GraphicSaveCallback(npMCI, (HANDLE) (UINT)lpPlay->dwCallback); } /* Set up the 'repeat' flags */ npMCI->dwFlags &= ~(MCIAVI_REPEATING); if (dwFlags & MCI_DGV_PLAY_REPEAT) { /* If from position isn't given, repeat from either the beginning or ** end of file as appropriate. */ npMCI->lRepeatFrom = (dwFlags & MCI_FROM) ? lFrom : ((dwFlags & MCI_DGV_PLAY_REVERSE) ? npMCI->lFrames : 0); } /* Go ahead and actually play... */ return DevicePlay(npMCI, lTo, dwFlags); } /*************************************************************************** * * @doc INTERNAL MCIWAVE * * @api DWORD | GraphicStep | This function steps through several frames * of a movie. If the reverse flag is set, then the step is backwards. * If the step count is not specified then it defaults to 1. If the * step count plus the current position exceeds the movie length, the * step is out of range. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the step message. * * @parm LPMCI_DGV_STEP_PARMS | lpStep | Parameters for the step message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicStep (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_STEP_PARMS lpStep) { LONG lFrameCur; LONG lFrames; DWORD dwRet; BOOL fReverse; BOOL fSeekExactOff; fReverse = (dwFlags & MCI_DGV_STEP_REVERSE) == MCI_DGV_STEP_REVERSE; // Default to 1 frame step if frame count is not specified if (dwFlags & MCI_DGV_STEP_FRAMES) { lFrames = (LONG) lpStep->dwFrames; if (fReverse) { if (lFrames < 0) return MCIERR_FLAGS_NOT_COMPATIBLE; } } else lFrames = 1; lFrames = fReverse ? -lFrames : lFrames; /* stop before figuring out whether frame count is within range, */ /* unless the TEST flag is set. */ if (!(dwFlags & MCI_TEST)) { if (dwRet = DeviceStop(npMCI, MCI_WAIT)) return dwRet; } if (dwRet = DevicePosition(npMCI, &lFrameCur)) return dwRet; if ((lFrames + lFrameCur > npMCI->lFrames) || (lFrames + lFrameCur < 0)) return MCIERR_OUTOFRANGE; if (!IsWindow(npMCI->hwnd)) return MCIERR_NO_WINDOW; /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L; GraphicDelayedNotify (npMCI, MCI_NOTIFY_ABORTED); /* Clear the 'repeat' flags */ npMCI->dwFlags &= ~(MCIAVI_REPEATING); if (dwFlags & MCI_NOTIFY) { GraphicSaveCallback(npMCI, (HANDLE) (UINT)lpStep->dwCallback); } fSeekExactOff = (npMCI->dwOptionFlags & MCIAVIO_SEEKEXACT) == 0; npMCI->dwOptionFlags |= MCIAVIO_SEEKEXACT; npMCI->dwFlags |= MCIAVI_NEEDTOSHOW; if (fSeekExactOff) { /* If we were not in seek exact mode, make seek finish ** before we turn seek exact back off. */ dwRet = DeviceSeek(npMCI, lFrames + lFrameCur, dwFlags | MCI_WAIT); npMCI->dwOptionFlags &= ~(MCIAVIO_SEEKEXACT); } else dwRet = DeviceSeek(npMCI, lFrames + lFrameCur, dwFlags); return dwRet; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicStop | This function stops playback of the movie. * After a stop the state will be MCI_MODE_STOP. The frame counter * is not reset. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the stop message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicStop (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { if (!IsWindow(npMCI->hwnd)) return MCIERR_NO_WINDOW; if (dwFlags & MCI_DGV_STOP_HOLD) return MCIERR_UNSUPPORTED_FUNCTION; /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L; GraphicDelayedNotify (npMCI, MCI_NOTIFY_ABORTED); /* Do we need to handle notify here? */ return DeviceStop(npMCI, dwFlags); } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicPause | Pauses movie playback. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicPause(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { if (!IsWindow(npMCI->hwnd)) return MCIERR_NO_WINDOW; /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L; if (dwFlags & MCI_NOTIFY) { GraphicSaveCallback(npMCI, (HANDLE) (UINT)lpParms->dwCallback); } return DevicePause(npMCI, dwFlags); } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicResume | This function resumes playback of a paused * movie. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicResume (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { DWORD dwRet; UINT wMode; // Resume is only allowed if MCIAVI is paused or playing wMode = DeviceMode(npMCI); if (wMode != MCI_MODE_PAUSE && wMode != MCI_MODE_PLAY) return MCIERR_NONAPPLICABLE_FUNCTION; if (!IsWindow(npMCI->hwnd)) return MCIERR_NO_WINDOW; /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L; if (dwFlags & MCI_NOTIFY) { GraphicSaveCallback(npMCI, (HANDLE) (UINT)lpParms->dwCallback); } dwRet = DeviceResume(npMCI, dwFlags & MCI_WAIT); return dwRet; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicStatus | This function returns numeric status info. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the status message. * * @parm LPMCI_STATUS_PARMS | lpPlay | Parameters for the status message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicStatus (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_STATUS_PARMS lpStatus) { DWORD dwRet = 0L; if (dwFlags & (MCI_DGV_STATUS_DISKSPACE)) return MCIERR_UNSUPPORTED_FUNCTION; if (dwFlags & MCI_STATUS_ITEM) { lpStatus->dwReturn = 0L; if ((dwFlags & MCI_TRACK) && !((lpStatus->dwItem == MCI_STATUS_POSITION) || (lpStatus->dwItem == MCI_STATUS_LENGTH))) return MCIERR_FLAGS_NOT_COMPATIBLE; if ((dwFlags & MCI_STATUS_START) && (lpStatus->dwItem != MCI_STATUS_POSITION)) return MCIERR_FLAGS_NOT_COMPATIBLE; if (dwFlags & MCI_DGV_STATUS_REFERENCE) return MCIERR_FLAGS_NOT_COMPATIBLE; switch (lpStatus->dwItem) { case MCI_STATUS_POSITION: if (dwFlags & MCI_TRACK) { /* POSITION with TRACK means return the start of the */ /* track. */ if (lpStatus->dwTrack != 1) dwRet = MCIERR_OUTOFRANGE; else /* return start frame of track (always 0) */ lpStatus->dwReturn = 0L; } else if (dwFlags & MCI_STATUS_START) // POSITION with START means return the starting playable // position of the media. lpStatus->dwReturn = 0L; else { /* Otherwise return current frame */ dwRet = DevicePosition(npMCI, (LPLONG) &lpStatus->dwReturn); lpStatus->dwReturn = ConvertFromFrames(npMCI, (LONG) lpStatus->dwReturn); } break; case MCI_STATUS_LENGTH: if (dwFlags & MCI_TRACK && lpStatus->dwTrack != 1) { /* LENGTH with TRACK means return the length of track */ lpStatus->dwReturn = 0L; dwRet = MCIERR_OUTOFRANGE; } lpStatus->dwReturn = ConvertFromFrames(npMCI, npMCI->lFrames); break; case MCI_STATUS_NUMBER_OF_TRACKS: case MCI_STATUS_CURRENT_TRACK: lpStatus->dwReturn = 1L; break; case MCI_STATUS_READY: /* Return TRUE if device can receive commands */ if (DeviceMode(npMCI) != MCI_MODE_NOT_READY) lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); else lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); dwRet = MCI_RESOURCE_RETURNED; break; case MCI_STATUS_MODE: { WORD wMode; wMode = DeviceMode(npMCI); lpStatus->dwReturn = MAKEMCIRESOURCE(wMode, wMode); dwRet = MCI_RESOURCE_RETURNED; } break; case MCI_DGV_STATUS_PAUSE_MODE: if (DeviceMode(npMCI) != MCI_MODE_PAUSE) dwRet = MCIERR_NONAPPLICABLE_FUNCTION; else { lpStatus->dwReturn = MAKEMCIRESOURCE(MCI_MODE_PLAY, MCI_MODE_PLAY); dwRet = MCI_RESOURCE_RETURNED; } break; case MCI_STATUS_MEDIA_PRESENT: lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); dwRet = MCI_RESOURCE_RETURNED; break; case MCI_DGV_STATUS_FORWARD: if (npMCI->dwFlags & MCIAVI_REVERSE) lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); else lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); dwRet = MCI_RESOURCE_RETURNED; break; case MCI_DGV_STATUS_HWND: lpStatus->dwReturn = (DWORD)(UINT)npMCI->hwnd; if (!IsWindow(npMCI->hwnd)) dwRet = MCIERR_NO_WINDOW; break; case MCI_DGV_STATUS_HPAL: // lpStatus->dwReturn = (DWORD) (UINT) DrawDibGetPalette(npMCI->hdd); lpStatus->dwReturn = 0; if (npMCI->nVideoStreams == 0) { dwRet = MCIERR_UNSUPPORTED_FUNCTION; } else { dwRet = ICSendMessage(npMCI->hicDraw, ICM_DRAW_GET_PALETTE, 0, 0); if (dwRet == ICERR_UNSUPPORTED) { dwRet = MCIERR_UNSUPPORTED_FUNCTION; } else { lpStatus->dwReturn = dwRet; dwRet = 0; } } DPF2(("Status HPAL returns: %lu\n", lpStatus->dwReturn)); break; case MCI_STATUS_TIME_FORMAT: lpStatus->dwReturn = MAKEMCIRESOURCE(npMCI->dwTimeFormat, npMCI->dwTimeFormat + MCI_FORMAT_RETURN_BASE); dwRet = MCI_RESOURCE_RETURNED; break; case MCI_DGV_STATUS_AUDIO: lpStatus->dwReturn = (npMCI->dwFlags & MCIAVI_PLAYAUDIO) ? (MAKEMCIRESOURCE(MCI_ON, MCI_ON_S)) : (MAKEMCIRESOURCE(MCI_OFF, MCI_OFF_S)); dwRet = MCI_RESOURCE_RETURNED | MCI_RESOURCE_DRIVER; break; case MCI_DGV_STATUS_WINDOW_VISIBLE: if (npMCI->hwnd && IsWindowVisible(npMCI->hwnd)) lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); else lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); dwRet = MCI_RESOURCE_RETURNED; break; case MCI_DGV_STATUS_WINDOW_MINIMIZED: if (npMCI->hwnd && IsIconic(npMCI->hwnd)) lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); else lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); dwRet = MCI_RESOURCE_RETURNED; break; case MCI_DGV_STATUS_WINDOW_MAXIMIZED: if (npMCI->hwnd && IsZoomed(npMCI->hwnd)) lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); else lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); dwRet = MCI_RESOURCE_RETURNED; break; case MCI_DGV_STATUS_SAMPLESPERSEC: case MCI_DGV_STATUS_AVGBYTESPERSEC: case MCI_DGV_STATUS_BLOCKALIGN: case MCI_DGV_STATUS_BITSPERSAMPLE: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; case MCI_DGV_STATUS_BITSPERPEL: if (npMCI->psiVideo) lpStatus->dwReturn = ((LPBITMAPINFOHEADER)npMCI->psiVideo->lpFormat)->biBitCount; else dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; #ifndef WIN32 #pragma message("Are we going to support brightness/color/contrast/tint?") #endif case MCI_DGV_STATUS_BRIGHTNESS: case MCI_DGV_STATUS_COLOR: case MCI_DGV_STATUS_CONTRAST: case MCI_DGV_STATUS_TINT: case MCI_DGV_STATUS_GAMMA: case MCI_DGV_STATUS_SHARPNESS: case MCI_DGV_STATUS_FILE_MODE: case MCI_DGV_STATUS_FILE_COMPLETION: case MCI_DGV_STATUS_KEY_INDEX: case MCI_DGV_STATUS_KEY_COLOR: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; case MCI_DGV_STATUS_FILEFORMAT: // Fall through to Unsupported case... // lpStatus->dwReturn = MAKEMCIRESOURCE(MCI_DGV_FF_AVI, // MCI_DGV_FF_AVI); // dwRet = MCI_RESOURCE_RETURNED | MCI_RESOURCE_DRIVER; // break; // case MCI_DGV_STATUS_BASS: case MCI_DGV_STATUS_TREBLE: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; case MCI_DGV_STATUS_VOLUME: { WORD wLeftVolume, wRightVolume; // Be sure volume is up to date.... DeviceGetVolume(npMCI); wLeftVolume = LOWORD(npMCI->dwVolume); wRightVolume = LOWORD(npMCI->dwVolume); switch (dwFlags & (MCI_DGV_STATUS_LEFT | MCI_DGV_STATUS_RIGHT)) { case MCI_DGV_STATUS_LEFT: lpStatus->dwReturn = (DWORD) wLeftVolume; break; case 0: lpStatus->dwReturn = (DWORD) wRightVolume; break; default: lpStatus->dwReturn = ((DWORD) wLeftVolume + (DWORD) wRightVolume) / 2; break; } } break; case MCI_DGV_STATUS_MONITOR: lpStatus->dwReturn = (DWORD) MAKEMCIRESOURCE(MCI_DGV_MONITOR_FILE, MCI_DGV_FILE_S); dwRet = MCI_RESOURCE_RETURNED | MCI_RESOURCE_DRIVER; break; case MCI_DGV_STATUS_SEEK_EXACTLY: lpStatus->dwReturn = (npMCI->dwOptionFlags & MCIAVIO_SEEKEXACT) ? (MAKEMCIRESOURCE(MCI_ON, MCI_ON_S)) : (MAKEMCIRESOURCE(MCI_OFF, MCI_OFF_S)); dwRet = MCI_RESOURCE_RETURNED | MCI_RESOURCE_DRIVER; break; case MCI_DGV_STATUS_SIZE: /* We haven't reserved any space, so return zero. */ lpStatus->dwReturn = 0L; break; case MCI_DGV_STATUS_SMPTE: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; case MCI_DGV_STATUS_UNSAVED: lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); dwRet = MCI_RESOURCE_RETURNED; break; case MCI_DGV_STATUS_VIDEO: lpStatus->dwReturn = (npMCI->dwFlags & MCIAVI_SHOWVIDEO) ? (MAKEMCIRESOURCE(MCI_ON, MCI_ON_S)) : (MAKEMCIRESOURCE(MCI_OFF, MCI_OFF_S)); dwRet = MCI_RESOURCE_RETURNED | MCI_RESOURCE_DRIVER; break; case MCI_DGV_STATUS_SPEED: lpStatus->dwReturn = npMCI->dwSpeedFactor; break; case MCI_DGV_STATUS_FRAME_RATE: { DWORD dwTemp; dwTemp = npMCI->dwMicroSecPerFrame; /* If they haven't specifically asked for the "nominal" ** rate of play, adjust by the current speed. */ if (!(dwFlags & MCI_DGV_STATUS_NOMINAL)) dwTemp = muldiv32(dwTemp, 1000L, npMCI->dwSpeedFactor); if (dwTemp == 0) lpStatus->dwReturn = 1000; else /* Our return value is in "thousandths of frames/sec", ** and dwTemp is the number of microseconds per frame. ** Thus, we divide a billion microseconds by dwTemp. */ lpStatus->dwReturn = muldiv32(1000000L, 1000L, dwTemp); break; } case MCI_DGV_STATUS_AUDIO_STREAM: lpStatus->dwReturn = 0; if (npMCI->nAudioStreams) { int stream; for (stream = 0; stream < npMCI->streams; stream++) { if (SH(stream).fccType == streamtypeAUDIO) ++lpStatus->dwReturn; if (stream == npMCI->nAudioStream) break; } } break; case MCI_DGV_STATUS_VIDEO_STREAM: case MCI_DGV_STATUS_AUDIO_INPUT: case MCI_DGV_STATUS_AUDIO_RECORD: case MCI_DGV_STATUS_AUDIO_SOURCE: case MCI_DGV_STATUS_VIDEO_RECORD: case MCI_DGV_STATUS_VIDEO_SOURCE: case MCI_DGV_STATUS_VIDEO_SRC_NUM: case MCI_DGV_STATUS_MONITOR_METHOD: case MCI_DGV_STATUS_STILL_FILEFORMAT: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; case MCI_AVI_STATUS_FRAMES_SKIPPED: lpStatus->dwReturn = npMCI->lSkippedFrames; break; case MCI_AVI_STATUS_AUDIO_BREAKS: lpStatus->dwReturn = npMCI->lAudioBreaks; break; case MCI_AVI_STATUS_LAST_PLAY_SPEED: lpStatus->dwReturn = npMCI->dwSpeedPercentage; break; default: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; } /* end switch (item) */ } else if (dwFlags & MCI_DGV_STATUS_REFERENCE) { if (lpStatus->dwReference > (DWORD) npMCI->lFrames) dwRet = MCIERR_OUTOFRANGE; else if (npMCI->psiVideo) { lpStatus->dwReference = MovieToStream(npMCI->psiVideo, lpStatus->dwReference); lpStatus->dwReturn = FindPrevKeyFrame(npMCI, npMCI->psiVideo, lpStatus->dwReference); lpStatus->dwReturn = StreamToMovie(npMCI->psiVideo, lpStatus->dwReturn); } else { lpStatus->dwReturn = 0; } } else /* item flag not set */ dwRet = MCIERR_MISSING_PARAMETER; if ((dwFlags & MCI_TEST) && (LOWORD(dwRet) == 0)) { /* There is no error, but the test flag is on. Return as little ** as possible. */ dwRet = 0; lpStatus->dwReturn = 0; } return dwRet; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicInfo | This function returns alphanumeric information. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the info. message. * * @parm LPMCI_INFO_PARMS | lpPlay | Parameters for the info message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicInfo(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_INFO_PARMS lpInfo) { DWORD dwRet = 0L; TCHAR ch = TEXT('\0'); BOOL fTest = FALSE; if (!lpInfo->lpstrReturn) return MCIERR_PARAM_OVERFLOW; if (dwFlags & MCI_TEST) fTest = TRUE; dwFlags &= ~(MCI_WAIT | MCI_NOTIFY | MCI_TEST); switch (dwFlags) { case 0L: return MCIERR_MISSING_PARAMETER; case MCI_INFO_FILE: if (!npMCI) return MCIERR_UNSUPPORTED_FUNCTION; if (lpInfo->dwRetSize < (DWORD)(lstrlen(npMCI->szFilename) + 1)) { ch = npMCI->szFilename[lpInfo->dwRetSize]; npMCI->szFilename[lpInfo->dwRetSize] = '\0'; dwRet = MCIERR_PARAM_OVERFLOW; } lstrcpy (lpInfo->lpstrReturn, npMCI->szFilename); if (ch) npMCI->szFilename[lpInfo->dwRetSize] = ch; break; case MCI_INFO_PRODUCT: #ifdef DEBUG #include "..\verinfo\usa\verinfo.h" wsprintf(lpInfo->lpstrReturn, TEXT("VfW %d.%02d.%02d"), MMVERSION, MMREVISION, MMRELEASE); #else /* !!! Not returning PARAM_OVERFLOW here but I am above - lazy eh */ LoadString(ghModule, MCIAVI_PRODUCTNAME, lpInfo->lpstrReturn, (UINT)lpInfo->dwRetSize); #endif break; case MCI_DGV_INFO_TEXT: if (!npMCI) return MCIERR_UNSUPPORTED_FUNCTION; if (IsWindow(npMCI->hwnd)) GetWindowText(npMCI->hwnd, lpInfo->lpstrReturn, LOWORD(lpInfo->dwRetSize)); else dwRet = MCIERR_NO_WINDOW; break; case MCI_INFO_VERSION: /* !!! Not returning PARAM_OVERFLOW here but I am above - lazy eh */ LoadString(ghModule, MCIAVI_VERSION, lpInfo->lpstrReturn, (UINT)lpInfo->dwRetSize); break; case MCI_DGV_INFO_USAGE: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; case MCI_DGV_INFO_ITEM: switch (lpInfo->dwItem) { case MCI_DGV_INFO_AUDIO_QUALITY: case MCI_DGV_INFO_VIDEO_QUALITY: case MCI_DGV_INFO_STILL_QUALITY: case MCI_DGV_INFO_AUDIO_ALG: case MCI_DGV_INFO_VIDEO_ALG: case MCI_DGV_INFO_STILL_ALG: default: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; } break; default: dwRet = MCIERR_FLAGS_NOT_COMPATIBLE; break; } if (fTest && (LOWORD(dwRet) == 0)) { /* There is no error, but the test flag is on. Return as little ** as possible. */ dwRet = 0; if (lpInfo->dwRetSize) lpInfo->lpstrReturn[0] = '\0'; } return dwRet; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicSet | This function sets various options. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the set message. * * @parm LPMCI_SET_PARMS | lpSet | Parameters for the set message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicSet (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_SET_PARMS lpSet) { DWORD dwRet = 0L; DWORD dwAction; if (dwFlags & MCI_DGV_SET_FILEFORMAT) return MCIERR_UNSUPPORTED_FUNCTION; if (dwFlags & MCI_DGV_SET_STILL) return MCIERR_UNSUPPORTED_FUNCTION; dwAction = dwFlags & (MCI_SET_TIME_FORMAT | MCI_SET_VIDEO | MCI_SET_AUDIO | MCI_DGV_SET_SEEK_EXACTLY | MCI_DGV_SET_SPEED ); dwFlags &= (MCI_SET_ON | MCI_SET_OFF | MCI_TEST ); /* First, check if the parameters are all okay */ if (!dwAction) return MCIERR_UNSUPPORTED_FUNCTION; if (dwAction & MCI_SET_TIME_FORMAT) { if (lpSet->dwTimeFormat != MCI_FORMAT_FRAMES && lpSet->dwTimeFormat != MCI_FORMAT_MILLISECONDS) return MCIERR_UNSUPPORTED_FUNCTION; } if ((dwAction & MCI_SET_AUDIO) && (lpSet->dwAudio != MCI_SET_AUDIO_ALL)) { return MCIERR_UNSUPPORTED_FUNCTION; } if (dwAction & MCI_DGV_SET_SPEED) { if (lpSet->dwSpeed > 100000L) return MCIERR_OUTOFRANGE; } switch (dwFlags & (MCI_SET_ON | MCI_SET_OFF)) { case 0: if (dwAction & (MCI_SET_AUDIO | MCI_SET_VIDEO | MCI_DGV_SET_SEEK_EXACTLY)) return MCIERR_MISSING_PARAMETER; break; case MCI_SET_ON | MCI_SET_OFF: return MCIERR_FLAGS_NOT_COMPATIBLE; default: if (dwAction & (MCI_DGV_SET_SPEED | MCI_SET_TIME_FORMAT)) return MCIERR_FLAGS_NOT_COMPATIBLE; break; } /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L; /* Now, actually carry out the command */ if (dwAction & MCI_SET_TIME_FORMAT) npMCI->dwTimeFormat = lpSet->dwTimeFormat; if (dwAction & MCI_SET_VIDEO) { npMCI->dwFlags &= ~(MCIAVI_SHOWVIDEO); if (dwFlags & MCI_SET_ON) { npMCI->dwFlags |= MCIAVI_SHOWVIDEO; InvalidateRect(npMCI->hwnd, NULL, FALSE); } } if (dwAction & MCI_DGV_SET_SEEK_EXACTLY) { npMCI->dwOptionFlags &= ~(MCIAVIO_SEEKEXACT); if (dwFlags & MCI_SET_ON) npMCI->dwOptionFlags |= MCIAVIO_SEEKEXACT; } if (dwAction & MCI_DGV_SET_SPEED) { dwRet = DeviceSetSpeed(npMCI, lpSet->dwSpeed); } if (dwRet == 0L && (dwAction & MCI_SET_AUDIO)) { dwRet = DeviceMute(npMCI, dwFlags & MCI_SET_OFF ? TRUE : FALSE); } return dwRet; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicSetAudio | This function sets various audio options. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the set audio message. * * @parm LPMCI_SET_PARMS | lpSet | Parameters for the set audio message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicSetAudio (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMS lpSet) { DWORD dwRet = 0L; if (npMCI->nAudioStreams == 0) { return MCIERR_UNSUPPORTED_FUNCTION; } if ((dwFlags & MCI_DGV_SETAUDIO_ITEM) && (lpSet->dwItem == MCI_DGV_SETAUDIO_VOLUME) && (dwFlags & MCI_DGV_SETAUDIO_VALUE)) { WORD wLeft, wRight; if (dwFlags & (MCI_DGV_SETAUDIO_ALG | MCI_DGV_SETAUDIO_QUALITY | MCI_DGV_SETAUDIO_RECORD | MCI_DGV_SETAUDIO_CLOCKTIME)) return MCIERR_UNSUPPORTED_FUNCTION; if (lpSet->dwValue > 1000L) return MCIERR_OUTOFRANGE; if (dwFlags & MCI_TEST) return 0L; // Be sure volume is up to date.... DeviceGetVolume(npMCI); wLeft = LOWORD(npMCI->dwVolume); wRight = HIWORD(npMCI->dwVolume); if (!(dwFlags & MCI_DGV_SETAUDIO_RIGHT)) wLeft = (WORD) lpSet->dwValue; if (!(dwFlags & MCI_DGV_SETAUDIO_LEFT)) wRight = (WORD) lpSet->dwValue; dwRet = DeviceSetVolume(npMCI, MAKELONG(wLeft, wRight)); } else if ((dwFlags & MCI_DGV_SETAUDIO_ITEM) && (lpSet->dwItem == MCI_DGV_SETAUDIO_STREAM) && (dwFlags & MCI_DGV_SETAUDIO_VALUE)) { if (dwFlags & (MCI_DGV_SETAUDIO_ALG | MCI_DGV_SETAUDIO_QUALITY | MCI_DGV_SETAUDIO_RECORD | MCI_DGV_SETAUDIO_LEFT | MCI_DGV_SETAUDIO_CLOCKTIME | MCI_DGV_SETAUDIO_RIGHT)) return MCIERR_UNSUPPORTED_FUNCTION; if (lpSet->dwValue > (DWORD) npMCI->nAudioStreams || lpSet->dwValue == 0) return MCIERR_OUTOFRANGE; if (dwFlags & MCI_TEST) return 0L; dwRet = DeviceSetAudioStream(npMCI, (WORD) lpSet->dwValue); } else if (dwFlags & (MCI_DGV_SETAUDIO_ITEM | MCI_DGV_SETAUDIO_VALUE | MCI_DGV_SETAUDIO_ALG | MCI_DGV_SETAUDIO_QUALITY | MCI_DGV_SETAUDIO_RECORD | MCI_DGV_SETAUDIO_LEFT | MCI_DGV_SETAUDIO_CLOCKTIME | MCI_DGV_SETAUDIO_RIGHT)) return MCIERR_UNSUPPORTED_FUNCTION; switch (dwFlags & (MCI_SET_ON | MCI_SET_OFF)) { case MCI_SET_ON: if (!(dwFlags & MCI_TEST)) dwRet = DeviceMute(npMCI, FALSE); break; case MCI_SET_OFF: if (!(dwFlags & MCI_TEST)) dwRet = DeviceMute(npMCI, TRUE); break; case MCI_SET_ON | MCI_SET_OFF: dwRet = MCIERR_FLAGS_NOT_COMPATIBLE; break; default: if (!(dwFlags & MCI_DGV_SETAUDIO_ITEM)) dwRet = MCIERR_MISSING_PARAMETER; break; } return dwRet; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicSetVideo | This function sets various Video options. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the set video message. * * @parm LPMCI_SET_PARMS | lpSet | Parameters for the set video message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicSetVideo (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_SETVIDEO_PARMS lpSet) { DWORD dwRet = 0L; if (dwFlags & (MCI_DGV_SETVIDEO_OVER | MCI_DGV_SETVIDEO_RECORD | MCI_DGV_SETVIDEO_SRC_NUMBER | MCI_DGV_SETVIDEO_QUALITY | MCI_DGV_SETVIDEO_ALG | MCI_DGV_SETVIDEO_STILL | MCI_DGV_SETVIDEO_CLOCKTIME )) return MCIERR_UNSUPPORTED_FUNCTION; if (dwFlags & MCI_DGV_SETVIDEO_ITEM) { switch (lpSet->dwItem) { case MCI_DGV_SETVIDEO_PALHANDLE: if (dwFlags & MCI_DGV_SETVIDEO_VALUE) { if (lpSet->dwValue && lpSet->dwValue != MCI_AVI_SETVIDEO_PALETTE_HALFTONE && #if 1 !IsGDIObject((HPALETTE) lpSet->dwValue)) #else GetObjectType((HPALETTE) lpSet->dwValue) != OBJ_PAL) #endif return MCIERR_AVI_BADPALETTE; } if (!(dwFlags & MCI_TEST)) dwRet = DeviceSetPalette(npMCI, ((dwFlags & MCI_DGV_SETVIDEO_VALUE) ? (HPALETTE) lpSet->dwValue : NULL)); break; case MCI_DGV_SETVIDEO_STREAM: if (!(dwFlags & MCI_DGV_SETVIDEO_VALUE)) return MCIERR_UNSUPPORTED_FUNCTION; if (lpSet->dwValue == 0 || lpSet->dwValue > (DWORD)npMCI->nVideoStreams + npMCI->nOtherStreams) return MCIERR_OUTOFRANGE; if (dwFlags & MCI_SET_ON) DPF(("SetVideoStream to #%d on\n", (int)lpSet->dwValue)); else if (dwFlags & MCI_SET_OFF) DPF(("SetVideoStream to #%d off\n", (int)lpSet->dwValue)); else DPF(("SetVideoStream to #%d\n", (int)lpSet->dwValue)); if (!(dwFlags & MCI_TEST)) { dwRet = DeviceSetVideoStream(npMCI, (UINT)lpSet->dwValue, !(dwFlags & MCI_SET_OFF)); } break; case MCI_AVI_SETVIDEO_DRAW_PROCEDURE: if (DeviceMode(npMCI) != MCI_MODE_STOP) return MCIERR_UNSUPPORTED_FUNCTION; if (npMCI->hicDrawDefault) { if (npMCI->hicDrawDefault != (HIC) -1) ICClose(npMCI->hicDrawDefault); npMCI->hicDrawDefault = 0; npMCI->dwFlags &= ~(MCIAVI_USERDRAWPROC); } if (lpSet->dwValue) { if (IsBadCodePtr((FARPROC) lpSet->dwValue)) { DPF(("Bad code pointer!!!!\n")); return MCIERR_OUTOFRANGE; //!!!MCIERR_BAD_PARAM; } npMCI->hicDrawDefault = ICOpenFunction(streamtypeVIDEO, FOURCC_AVIDraw,ICMODE_DRAW,(FARPROC) lpSet->dwValue); if (!npMCI->hicDrawDefault) { return MCIERR_INTERNAL; } DPF(("Successfully set new draw procedure....\n")); npMCI->dwFlags |= MCIAVI_USERDRAWPROC; } npMCI->dwFlags |= MCIAVI_NEEDDRAWBEGIN; InvalidateRect(npMCI->hwnd, NULL, FALSE); return 0; default: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; } } else if (dwFlags & (MCI_SET_ON | MCI_SET_OFF)) { switch (dwFlags & (MCI_SET_ON | MCI_SET_OFF)) { case MCI_SET_ON: if (!(dwFlags & MCI_TEST)) { InvalidateRect(npMCI->hwnd, NULL, FALSE); npMCI->dwFlags |= MCIAVI_SHOWVIDEO; } break; case MCI_SET_OFF: if (!(dwFlags & MCI_TEST)) npMCI->dwFlags &= ~(MCIAVI_SHOWVIDEO); break; case MCI_SET_ON | MCI_SET_OFF: dwRet = MCIERR_FLAGS_NOT_COMPATIBLE; break; } } else dwRet = MCIERR_MISSING_PARAMETER; return dwRet; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicSignal | This function sets signals. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the set PositionAdvise message. * * @parm LPMCI_SIGNAL_PARMS | lpSignal | Parameters for the signal * message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicSignal(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_SIGNAL_PARMS lpSignal) { DWORD dwRet = 0L; DWORD dwUser; DWORD dwPosition; DWORD dwPeriod; dwUser = (dwFlags & MCI_DGV_SIGNAL_USERVAL) ? lpSignal->dwUserParm : 0L; if (dwFlags & MCI_DGV_SIGNAL_CANCEL) { if (dwFlags & (MCI_DGV_SIGNAL_AT | MCI_DGV_SIGNAL_EVERY | MCI_DGV_SIGNAL_POSITION)) return MCIERR_FLAGS_NOT_COMPATIBLE; if (!npMCI->dwSignals) return MCIERR_NONAPPLICABLE_FUNCTION; if (dwUser && (npMCI->signal.dwUserParm != dwUser)) return MCIERR_NONAPPLICABLE_FUNCTION; if (!(dwFlags & MCI_TEST)) --npMCI->dwSignals; } else { if ((npMCI->dwSignals != 0) && (dwUser != npMCI->signal.dwUserParm)) { /* !!! Should we allow more than one signal? */ return MCIERR_DGV_DEVICE_LIMIT; } if (dwFlags & MCI_DGV_SIGNAL_AT) { /* Use position passed in */ dwPosition = ConvertToFrames(npMCI, lpSignal->dwPosition); if (dwPosition > (DWORD) npMCI->lFrames) return MCIERR_OUTOFRANGE; } else { /* Get current position */ DevicePosition(npMCI, (LPLONG) &dwPosition); } if (dwFlags & MCI_DGV_SIGNAL_EVERY) { dwPeriod = (DWORD) ConvertToFrames(npMCI, lpSignal->dwPeriod); if (dwPeriod == 0 || (dwPeriod > (DWORD) npMCI->lFrames)) return MCIERR_OUTOFRANGE; } else { /* It's a one-time signal */ dwPeriod = 0L; } if (dwFlags & MCI_TEST) return 0; npMCI->signal.dwPosition = dwPosition; npMCI->signal.dwPeriod = dwPeriod; npMCI->signal.dwUserParm = dwUser; npMCI->signal.dwCallback = lpSignal->dwCallback; npMCI->dwSignalFlags = dwFlags; /* The signal isn't really activated until we do this. */ if (!npMCI->dwSignals) ++npMCI->dwSignals; } return 0L; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicList | This function supports the MCI_LIST command. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the List message. * * @parm LPMCI_DGV_LIST_PARMS | lpList | Parameters for the list message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicList(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_LIST_PARMS lpList) { return MCIERR_UNSUPPORTED_FUNCTION; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicGetDevCaps | This function returns device * capabilities * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the GetDevCaps message. * * @parm LPMCI_GETDEVCAPS_PARMS | lpCaps | Parameters for the GetDevCaps * message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicGetDevCaps (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_GETDEVCAPS_PARMS lpCaps ) { DWORD dwRet = 0L; if (dwFlags & MCI_GETDEVCAPS_ITEM) { switch (lpCaps->dwItem) { case MCI_GETDEVCAPS_CAN_RECORD: case MCI_GETDEVCAPS_CAN_EJECT: case MCI_GETDEVCAPS_CAN_SAVE: case MCI_DGV_GETDEVCAPS_CAN_LOCK: case MCI_DGV_GETDEVCAPS_CAN_STR_IN: case MCI_DGV_GETDEVCAPS_CAN_FREEZE: case MCI_DGV_GETDEVCAPS_HAS_STILL: lpCaps->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); dwRet = MCI_RESOURCE_RETURNED; break; case MCI_DGV_GETDEVCAPS_CAN_REVERSE: case MCI_GETDEVCAPS_CAN_PLAY: case MCI_GETDEVCAPS_HAS_AUDIO: case MCI_GETDEVCAPS_HAS_VIDEO: case MCI_GETDEVCAPS_USES_FILES: case MCI_GETDEVCAPS_COMPOUND_DEVICE: case MCI_DGV_GETDEVCAPS_PALETTES: case MCI_DGV_GETDEVCAPS_CAN_STRETCH: case MCI_DGV_GETDEVCAPS_CAN_TEST: lpCaps->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); dwRet = MCI_RESOURCE_RETURNED; break; case MCI_GETDEVCAPS_DEVICE_TYPE: lpCaps->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_DIGITAL_VIDEO, MCI_DEVTYPE_DIGITAL_VIDEO); dwRet = MCI_RESOURCE_RETURNED; break; case MCI_DGV_GETDEVCAPS_MAX_WINDOWS: case MCI_DGV_GETDEVCAPS_MAXIMUM_RATE: case MCI_DGV_GETDEVCAPS_MINIMUM_RATE: default: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; } } else dwRet = MCIERR_MISSING_PARAMETER; if ((dwFlags & MCI_TEST) && (LOWORD(dwRet) == 0)) { /* There is no error, but the test flag is on. Return as little ** as possible. */ dwRet = 0; lpCaps->dwReturn = 0; } return (dwRet); } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicWindow | This function controls the stage window * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the window message. * * @parm LPMCI_DGV_WINDOW_PARMS | lpPlay | Parameters for the window message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicWindow (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_WINDOW_PARMS lpWindow) { DWORD dwRet = 0L; int i = 0; HWND hWndNew; if (dwFlags & MCI_DGV_WINDOW_HWND) { // Set a new stage window. If the parameter is NULL, then // use the default window. Otherwise, hide the default // window and use the given window handle. if (!lpWindow->hWnd) hWndNew = npMCI->hwndDefault; else hWndNew = lpWindow->hWnd; if (!IsWindow(hWndNew)) return MCIERR_NO_WINDOW; /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L; // only change if the new window handle is different from the current // stage window handle if (hWndNew != npMCI->hwnd) { dwRet = DeviceSetWindow(npMCI, hWndNew); if (npMCI->hwnd != npMCI->hwndDefault && IsWindow(npMCI->hwndDefault)) ShowWindow(npMCI->hwndDefault, SW_HIDE); } } /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return dwRet; if (!dwRet) { if (IsWindow(npMCI->hwnd)) { if (dwFlags & MCI_DGV_WINDOW_STATE) ShowWindow (npMCI->hwnd, lpWindow->nCmdShow); if (dwFlags & MCI_DGV_WINDOW_TEXT) SetWindowText(npMCI->hwnd, lpWindow->lpstrText); } else dwRet = MCIERR_NO_WINDOW; } return dwRet; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicPut | This function sets the offset and extent * of the animation within the client area of the stage window. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the put message. * * @parm LPMCI_DGV_RECT_PARMS | lpDestination | Parameters for the * destination message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicPut ( NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms) { BOOL frc; RECT rc; if (dwFlags & (MCI_DGV_PUT_FRAME | MCI_DGV_PUT_VIDEO)) return MCIERR_UNSUPPORTED_FUNCTION; frc = (dwFlags & MCI_DGV_RECT) == MCI_DGV_RECT; if (!IsWindow(npMCI->hwnd)) return MCIERR_NO_WINDOW; switch (dwFlags & (MCI_DGV_PUT_SOURCE | MCI_DGV_PUT_DESTINATION | MCI_DGV_PUT_WINDOW)) { case 0L: return MCIERR_MISSING_PARAMETER; case MCI_DGV_PUT_SOURCE: // If a rectangle is supplied, use it. if (frc) { rc.left = lpParms->ptOffset.x; rc.top = lpParms->ptOffset.y; rc.right = lpParms->ptOffset.x + lpParms->ptExtent.x; rc.bottom = lpParms->ptOffset.y + lpParms->ptExtent.y; if (lpParms->ptExtent.x <= 0) { rc.right = rc.left + (npMCI->rcDest.right - npMCI->rcDest.left); } if (lpParms->ptExtent.y <= 0) { rc.bottom = rc.top + (npMCI->rcDest.bottom - npMCI->rcDest.top); } } else { /* Reset to default */ rc = npMCI->rcMovie; } break; case MCI_DGV_PUT_DESTINATION: // If a rectangle is supplied, use it. if (frc) { rc.left = lpParms->ptOffset.x; rc.top = lpParms->ptOffset.y; rc.right = lpParms->ptOffset.x + lpParms->ptExtent.x; rc.bottom = lpParms->ptOffset.y + lpParms->ptExtent.y; if (lpParms->ptExtent.x <= 0) { rc.right = rc.left + (npMCI->rcDest.right - npMCI->rcDest.left); } if (lpParms->ptExtent.y <= 0) { rc.bottom = rc.top + (npMCI->rcDest.bottom - npMCI->rcDest.top); } } else { /* Reset to size of stage window */ GetClientRect(npMCI->hwnd, &rc); } break; case MCI_DGV_PUT_WINDOW: if (dwFlags & MCI_TEST) return 0L; // De-minimize their window, so we don't end up with // a giant icon.... if (IsIconic(npMCI->hwnd)) ShowWindow(npMCI->hwnd, SW_RESTORE); // If a rectangle is supplied, use it. if (frc) { RECT rcOld; rc.left = lpParms->ptOffset.x; rc.right = lpParms->ptOffset.x + lpParms->ptExtent.x; rc.top = lpParms->ptOffset.y; rc.bottom = lpParms->ptOffset.y + lpParms->ptExtent.y; if (dwFlags & MCI_DGV_PUT_CLIENT) { AdjustWindowRect(&rc, GetWindowLong(npMCI->hwnd, GWL_STYLE), FALSE); } // Default to just moving if width, height == 0.... GetWindowRect(npMCI->hwnd, &rcOld); if (lpParms->ptExtent.x <= 0) { rc.right = rc.left + (rcOld.right - rcOld.left); } if (lpParms->ptExtent.y <= 0) { rc.bottom = rc.top + (rcOld.bottom - rcOld.top); } MoveWindow(npMCI->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); } else { // !!! What should we do if there's no rectangle? /* Reset to "natural" size? */ rc = npMCI->rcMovie; if (npMCI->dwOptionFlags & MCIAVIO_ZOOMBY2) SetRect(&rc, 0, 0, rc.right*2, rc.bottom*2); AdjustWindowRect(&rc, GetWindowLong(npMCI->hwnd, GWL_STYLE), FALSE); SetWindowPos(npMCI->hwnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); } // Premiere 1.0 depends on the window always being visible // after a PUT_WINDOW command. Make it so. ShowWindow(npMCI->hwnd, SW_RESTORE); return 0L; default: return MCIERR_FLAGS_NOT_COMPATIBLE; } if (dwFlags & MCI_DGV_PUT_CLIENT) return MCIERR_FLAGS_NOT_COMPATIBLE; /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L; return DevicePut(npMCI, &rc, dwFlags); } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicWhere | This function returns the current * source and destination rectangles, in offset/extent form. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the query source message. * * @parm LPMCI_DGV_RECT_PARMS | lpParms | Parameters for the message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicWhere(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms) { RECT rc; if (dwFlags & (MCI_DGV_WHERE_FRAME | MCI_DGV_WHERE_VIDEO)) return MCIERR_UNSUPPORTED_FUNCTION; // !!! WHERE_WINDOW? switch (dwFlags & (MCI_DGV_WHERE_SOURCE | MCI_DGV_WHERE_DESTINATION | MCI_DGV_WHERE_WINDOW)) { case 0L: return MCIERR_MISSING_PARAMETER; case MCI_DGV_WHERE_SOURCE: if (dwFlags & MCI_DGV_WHERE_MAX) { lpParms->ptOffset.x = npMCI->rcMovie.left; lpParms->ptOffset.y = npMCI->rcMovie.top; lpParms->ptExtent.x = npMCI->rcMovie.right - npMCI->rcMovie.left; lpParms->ptExtent.y = npMCI->rcMovie.bottom - npMCI->rcMovie.top; } else { lpParms->ptOffset.x = npMCI->rcSource.left; lpParms->ptOffset.y = npMCI->rcSource.top; lpParms->ptExtent.x = npMCI->rcSource.right - npMCI->rcSource.left; lpParms->ptExtent.y = npMCI->rcSource.bottom - npMCI->rcSource.top; } break; case MCI_DGV_WHERE_DESTINATION: if (dwFlags & MCI_DGV_WHERE_MAX) { /* Return size of window */ GetClientRect(npMCI->hwnd, &rc); lpParms->ptOffset.x = 0; lpParms->ptOffset.y = 0; lpParms->ptExtent.x = rc.right; lpParms->ptExtent.y = rc.bottom; } else { /* Return current destination size */ lpParms->ptOffset.x = npMCI->rcDest.left; lpParms->ptOffset.y = npMCI->rcDest.top; lpParms->ptExtent.x = npMCI->rcDest.right - npMCI->rcDest.left; lpParms->ptExtent.y = npMCI->rcDest.bottom - npMCI->rcDest.top; } break; case MCI_DGV_WHERE_WINDOW: if (dwFlags & MCI_DGV_WHERE_MAX) { /* Return maximum size of window */ GetClientRect(npMCI->hwnd, &rc); lpParms->ptOffset.x = 0; lpParms->ptOffset.y = 0; lpParms->ptExtent.x = GetSystemMetrics(SM_CXSCREEN); lpParms->ptExtent.y = GetSystemMetrics(SM_CYSCREEN); } else { /* Return size of window */ GetWindowRect(npMCI->hwnd, &rc); lpParms->ptOffset.x = rc.left; lpParms->ptOffset.y = rc.top; lpParms->ptExtent.x = rc.right - rc.left; lpParms->ptExtent.y = rc.bottom - rc.top; } break; default: return MCIERR_FLAGS_NOT_COMPATIBLE; } return 0L; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicRealize | This function realizes the current palette * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicRealize(NPMCIGRAPHIC npMCI, DWORD dwFlags) { /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L; npMCI->fForceBackground = (dwFlags & MCI_DGV_REALIZE_BKGD) != 0; return DeviceRealize(npMCI); } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | GraphicUpdate | This function refreshes the current frame. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the message. * * @parm LPMCI_DGV_UPDATE_PARMS | lpParms | Parameters for the message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicUpdate(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS lpParms) { RECT rc; rc.left = lpParms->ptOffset.x; rc.top = lpParms->ptOffset.y; rc.right = lpParms->ptOffset.x + lpParms->ptExtent.x; rc.bottom = lpParms->ptOffset.y + lpParms->ptExtent.y; if (!(dwFlags & MCI_DGV_UPDATE_HDC)) { InvalidateRect(npMCI->hwnd, (dwFlags & MCI_DGV_RECT) ? &rc : NULL, TRUE); UpdateWindow(npMCI->hwnd); return 0; } /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L; /* It's ok to pass a NULL rect to DeviceUpdate() */ #ifndef WIN32 #pragma message("!!! Fix update parms!") #endif return DeviceUpdate (npMCI, dwFlags, lpParms->hDC, (dwFlags & MCI_DGV_RECT) ? &rc : NULL); } DWORD FAR PASCAL GraphicConfig(NPMCIGRAPHIC npMCI, DWORD dwFlags) { DWORD dwOptions = npMCI->dwOptionFlags; if (!(dwFlags & MCI_TEST)) { gfEvil++; if (ConfigDialog(NULL, npMCI)) { #ifdef DEBUG // // in DEBUG always reset the dest rect because the user may // have played with the DEBUG DrawDib options and we will // need to call DrawDibBegin() again. // if (TRUE) { #else if ((npMCI->dwOptionFlags & (MCIAVIO_STUPIDMODE|MCIAVIO_ZOOMBY2)) != (dwOptions & (MCIAVIO_STUPIDMODE|MCIAVIO_ZOOMBY2)) ) { #endif npMCI->lFrameDrawn = (- (LONG) npMCI->wEarlyRecords) - 1; SetWindowToDefaultSize(npMCI); SetRectEmpty(&npMCI->rcDest); //This will force a change! ResetDestRect(npMCI); } } else { npMCI->dwOptionFlags = dwOptions; } gfEvil--; } return 0L; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | mciSpecial | This function handles all the MCI * commands that don't require instance data such as open. * * @parm UINT | wDeviceID | The MCI device ID * * @parm UINT | wMessage | The requested action to be performed. * * @parm DWORD | dwFlags | Flags for the message. * * @parm DWORD | lpParms | Parameters for this message. * * @rdesc Error Constant. 0L on success * ***************************************************************************/ DWORD NEAR PASCAL mciSpecial (UINT wDeviceID, UINT wMessage, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { NPMCIGRAPHIC npMCI = 0L; DWORD dwRet; /* since there in no instance block, there is no saved notification */ /* to abort. */ switch (wMessage) { case MCI_OPEN_DRIVER: if (dwFlags & (MCI_OPEN_ELEMENT | MCI_OPEN_ELEMENT_ID)) dwRet = GraphicOpen (&npMCI, dwFlags, (LPMCI_DGV_OPEN_PARMS) lpParms, wDeviceID); else dwRet = 0L; mciSetDriverData (wDeviceID, (UINT)npMCI); break; case MCI_GETDEVCAPS: dwRet = GraphicGetDevCaps(NULL, dwFlags, (LPMCI_GETDEVCAPS_PARMS)lpParms); break; case MCI_CONFIGURE: if (!(dwFlags & MCI_TEST)) ConfigDialog(NULL, NULL); dwRet = 0L; break; case MCI_INFO: dwRet = GraphicInfo(NULL, dwFlags, (LPMCI_DGV_INFO_PARMS)lpParms); break; case MCI_CLOSE_DRIVER: dwRet = 0L; break; default: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; } GraphicImmediateNotify (wDeviceID, lpParms, dwFlags, dwRet); return (dwRet); } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | mciDriverEntry | This function is the MCI handler * * @parm UINT | wDeviceID | The MCI device ID * * @parm UINT | wMessage | The requested action to be performed. * * @parm DWORD | dwFlags | Flags for the message. * * @parm DWORD | lpParms | Parameters for this message. * * @rdesc Error Constant. 0L on success * ***************************************************************************/ DWORD PASCAL mciDriverEntry (UINT wDeviceID, UINT wMessage, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { NPMCIGRAPHIC npMCI = 0L; DWORD dwRet = MCIERR_UNRECOGNIZED_COMMAND; BOOL fDelayed = FALSE; BOOL fNested = FALSE; /* All current commands require a parameter block. */ if (!lpParms && (dwFlags & MCI_NOTIFY)) return (MCIERR_MISSING_PARAMETER); npMCI = (NPMCIGRAPHIC) (UINT)mciGetDriverData(wDeviceID); if (!npMCI) return mciSpecial(wDeviceID, wMessage, dwFlags, lpParms); /* * grab this device's critical section */ EnterCrit(npMCI); if (npMCI->wMessageCurrent) { fNested = TRUE; if (wMessage != MCI_STATUS && wMessage != MCI_GETDEVCAPS && wMessage != MCI_INFO) { DPF(("Warning!!!!!\n")); DPF(("Warning!!!!! MCIAVI reentered: received %x while processing %x\n", wMessage, npMCI->wMessageCurrent)); DPF(("Warning!!!!!\n")); DPF(("Warning!!!!!\n")); // Assert(0); // LeaveCrit(npMCI); // return MCIERR_DEVICE_NOT_READY; } } else npMCI->wMessageCurrent = wMessage; switch (wMessage) { case MCI_CLOSE_DRIVER: /* Closing the driver causes any currently saved notifications */ /* to abort. */ GraphicDelayedNotify(npMCI, MCI_NOTIFY_ABORTED); // note that GraphicClose will release and delete the critsec dwRet = GraphicClose(npMCI); mciSetDriverData(wDeviceID, 0L); npMCI = NULL; break; case MCI_PLAY: dwRet = GraphicPlay(npMCI, dwFlags, (LPMCI_PLAY_PARMS)lpParms); fDelayed = TRUE; break; case MCI_CUE: dwRet = GraphicCue(npMCI, dwFlags, (LPMCI_DGV_CUE_PARMS)lpParms); fDelayed = TRUE; break; case MCI_STEP: dwRet = GraphicStep(npMCI, dwFlags, (LPMCI_DGV_STEP_PARMS)lpParms); fDelayed = TRUE; break; case MCI_STOP: dwRet = GraphicStop(npMCI, dwFlags, lpParms); break; case MCI_SEEK: dwRet = GraphicSeek (npMCI, dwFlags, (LPMCI_SEEK_PARMS)lpParms); fDelayed = TRUE; break; case MCI_PAUSE: dwRet = GraphicPause(npMCI, dwFlags, lpParms); fDelayed = TRUE; break; case MCI_RESUME: dwRet = GraphicResume(npMCI, dwFlags, lpParms); fDelayed = TRUE; break; case MCI_SET: dwRet = GraphicSet(npMCI, dwFlags, (LPMCI_DGV_SET_PARMS)lpParms); break; case MCI_STATUS: dwRet = GraphicStatus(npMCI, dwFlags, (LPMCI_DGV_STATUS_PARMS)lpParms); break; case MCI_INFO: dwRet = GraphicInfo (npMCI, dwFlags, (LPMCI_DGV_INFO_PARMS)lpParms); break; case MCI_GETDEVCAPS: dwRet = GraphicGetDevCaps(npMCI, dwFlags, (LPMCI_GETDEVCAPS_PARMS)lpParms); break; case MCI_REALIZE: dwRet = GraphicRealize(npMCI, dwFlags); break; case MCI_UPDATE: dwRet = GraphicUpdate(npMCI, dwFlags, (LPMCI_DGV_UPDATE_PARMS)lpParms); break; case MCI_WINDOW: dwRet = GraphicWindow(npMCI, dwFlags, (LPMCI_DGV_WINDOW_PARMS)lpParms); break; case MCI_PUT: dwRet = GraphicPut(npMCI, dwFlags, (LPMCI_DGV_RECT_PARMS)lpParms); break; case MCI_WHERE: dwRet = GraphicWhere(npMCI, dwFlags, (LPMCI_DGV_RECT_PARMS)lpParms); break; case MCI_CONFIGURE: dwRet = GraphicConfig(npMCI, dwFlags); break; case MCI_SETAUDIO: dwRet = GraphicSetAudio(npMCI, dwFlags, (LPMCI_DGV_SETAUDIO_PARMS) lpParms); break; case MCI_SETVIDEO: dwRet = GraphicSetVideo(npMCI, dwFlags, (LPMCI_DGV_SETVIDEO_PARMS) lpParms); break; case MCI_SIGNAL: dwRet = GraphicSignal(npMCI, dwFlags, (LPMCI_DGV_SIGNAL_PARMS) lpParms); break; case MCI_LIST: dwRet = GraphicList(npMCI, dwFlags, (LPMCI_DGV_LIST_PARMS) lpParms); break; case MCI_LOAD: dwRet = GraphicLoad(npMCI, dwFlags, (LPMCI_DGV_LOAD_PARMS) lpParms); break; case MCI_RECORD: case MCI_SAVE: case MCI_CUT: case MCI_COPY: case MCI_PASTE: case MCI_UNDO: case MCI_DELETE: case MCI_CAPTURE: case MCI_QUALITY: case MCI_MONITOR: case MCI_RESERVE: case MCI_FREEZE: case MCI_UNFREEZE: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; /* Do we need this case? */ default: dwRet = MCIERR_UNRECOGNIZED_COMMAND; break; } if (!fDelayed || (dwFlags & MCI_TEST)) { /* We haven't processed the notify yet. */ if (npMCI && (dwFlags & MCI_NOTIFY) && (!LOWORD(dwRet))) /* Throw away the old notify */ GraphicDelayedNotify(npMCI, MCI_NOTIFY_SUPERSEDED); /* And send the new one out immediately. */ GraphicImmediateNotify(wDeviceID, lpParms, dwFlags, dwRet); } /* If there's an error, don't save the callback.... */ if (fDelayed && dwRet != 0 && (dwFlags & MCI_NOTIFY)) npMCI->hCallback = 0; // // see if we need to tell the DRAW device about moving. // MPlayer is sending the status and position command alot // so this is a "timer" // // !!!do we need to do it this often? // if (npMCI && (npMCI->dwFlags & MCIAVI_WANTMOVE)) CheckWindowMove(npMCI, FALSE); if (npMCI && !fNested) npMCI->wMessageCurrent = 0; // free critical section for this device - if we haven't deleted it // GraphicClose may have released and deleted it if we were deleting // the device instance. if (npMCI) { LeaveCrit(npMCI); } return dwRet; } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api LONG | ConvertToFrames | Convert from the current time format into * frames. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwTime | Input time. * ***************************************************************************/ STATICFN LONG NEAR PASCAL ConvertToFrames(NPMCIGRAPHIC npMCI, DWORD dwTime) { if (npMCI->dwTimeFormat == MCI_FORMAT_FRAMES) { return (LONG) dwTime; } else { if (npMCI->dwMicroSecPerFrame > 1000) { /* This needs to round down--muldiv32 likes to round off. */ return (LONG) muldivrd32(dwTime, 1000L, npMCI->dwMicroSecPerFrame); } else { return (LONG) muldivru32(dwTime, 1000L, npMCI->dwMicroSecPerFrame); } } } /*************************************************************************** * * @doc INTERNAL MCIAVI * * @api DWORD | ConvertFromFrames | Convert from frames into the current * time format. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm LONG | lFrame | Frame number to convert. * ***************************************************************************/ DWORD NEAR PASCAL ConvertFromFrames(NPMCIGRAPHIC npMCI, LONG lFrame) { if (npMCI->dwTimeFormat == MCI_FORMAT_FRAMES) { return (DWORD)lFrame; } else { if (npMCI->dwMicroSecPerFrame > 1000) return muldivru32(lFrame, npMCI->dwMicroSecPerFrame, 1000L); else return muldivrd32(lFrame, npMCI->dwMicroSecPerFrame, 1000L); } }