The remainder of this chapter presents code that implements a script-channel monitor. This script-channel monitor responds to the following commands:
Command | Description |
!b <text> | Break command. This command tells the application to stop the movie and display the text string <text>. |
!g <frame> | Goto command. This command tells the application to jump to frame number <frame>. |
!l <frame> | Loop command. This command tells the application to enter a loop, returning to frame number <frame> until a Continue button (displayed in a small child window) is pressed. |
!c <text> | Close command. This command tells the application to display the text string <text> and then exit. |
Each command begins with an exclamation point (!); this makes it easy for the callback function to recognize commands. When the callback function encounters a script-channel command that it recognizes, it copies the command text and calls another function, Parse, to check the command syntax and break the script command into the window-message format. It then sends the resulting window message and parameters to the main message handler function.
The callback function is shown in the following code fragment:
#define MAX_SCRIPT 1023
char szScriptText[MAX_SCRIPT+1];
BOOL FAR PASCAL
MyFrameHook(MMPID idMovie, WORD wMsg, WORD wParam, LONG lParam)
{
WORD wMsgOut, wParamOut;
LONG lParamOut;
/* If another callback function is hooked, call it first.
*/
if(lpfnCallback)
(*lpfnCallback)(idMovie, wMsg, wParam, lParam);
switch(wMsg)
{
case MMP_HOOK_FRAME :
return FALSE;
case MMP_HOOK_SCRIPT :
// Check the script-channel text. If there's no text, or the
// command is not recognized, let the Movie Player handle it.
if(lParam == NULL || *((LPSTR)lParam) != '!')
return FALSE;
if(lstrlen((LPSTR)lParam) > MAX_SCRIPT)
return FALSE;
// Copy the script-channel text.
lstrcpy(szScriptText, (LPSTR)lParam);
// Convert the script-channel text to message format.
// If the parsing succeeds, carry out the command.
AnsiLower(szScriptText);
if(Parse(szScriptText, &wMsgOut, &wParamOut, &lParamOut))
{
if(bFullScreen && hFullWnd)
DoCommand(hFullWnd, wMsgOut, wParamOut, lParamOut);
else
DoCommand(hMainWnd, wMsgOut, wParamOut, lParamOut);
return TRUE; // Application handled it.
}
else
return FALSE; // Let Movie Player handle it.
break;
default:
return FALSE;
}
}
The following DoCommand function, called in the previous frame-hook function, handles script-channel commands:
LONG DoCommand(HWND hWnd, int iMessage, WORD wParam, LONG lParam)
{
switch(iMessage)
{
case WM_MMPLAY_GOTO:
if(wParam)
mmpGoToFrame(idMovie, wParam, MMP_DRAW_FRAME);
break;
case WM_MMPLAY_BREAK:
MessageBox(hWnd, (LPSTR)lParam, szAppName, MB_OK);
break;
case WM_MMPLAY_LOOP:
// The wLoopState flag indicates the current state of the loop.
switch(wLoopState)
{
// If the flag is LOOP_CLEAR, the movie is just entering
// the loop. Display the "Continue" button and begin
// the loop.
case LOOP_CLEAR:
CreateWindow(szKeytestName, szKeytestName,
WS_CHILD | WS_VISIBLE | WS_DLGFRAME | WS_SYSMENU |
WS_CAPTION,
10, 10, 100, 60, hWnd, NULL, hInst, 0L);
wLoopState = LOOP_WAIT;
mmpGoToFrame(idMovie, wParam, MMP_DRAW_FRAME);
break;
// If the flag is LOOP_WAIT, the movie is in the loop.
// The flag remains LOOP_WAIT until the user presses the
// Continue button.
case LOOP_WAIT:
mmpGoToFrame(idMovie, wParam, MMP_DRAW_FRAME);
break;
// If the flag is LOOP_CONTINUE, exit the loop.
case LOOP_CONTINUE:
wLoopState = LOOP_CLEAR;
break;
}
break;
case WM_MMPLAY_CLOSE:
MessageBox(hWnd, (LPSTR)lParam, szAppName, MB_OK);
PostQuitMessage(1);
break;
}
return 0L;
}
An application can insert the callback function into the playback after opening the Movie Player instance. Notice how the following code fragment records the current callback-function address in a global variable before calling mmpSetFrameHook:
lpfnCallback = mmpGetFrameHook(idMovie);
if(lpfnMyCallback = MakeProcInstance(MyFrameHook, hInst))
mmpSetFrameHook(idMovie, lpfnMyCallback);
The application unhooks its frame function before exiting. The following code fragment shows the WM_DESTROY block of the main message handler:
case WM_DESTROY :
mmpSetFrameHook(idMovie, lpfnCallback); // Restore previous callback.
FreeProcInstance(lpfnMyCallback);
if(!mmpClose(idMovie, 0))
PrintError(idMovie, "Failed to stop Movie Player.");
WriteFlags();
break;