
// ---------------------------------------------------------------------
//
// FrameWnd.c - Movie Player - QuickTime for Windows
//
//              Version 1.0
//
//              (c) 1988-1992 Apple Computer, Inc. All Rights Reserved.
//
// ---------------------------------------------------------------------


// Includes
// --------
#include <Windows.H>  // Required by Windows
#include <commdlg.h>  // Header file for common dlgs
#include <dlgs.h>     // Header file for common dlgs ids
#include <cderr.h>    // Header file for error ids
#include <memory.h>   // For memset()
#include <shellapi.h> // Required for drag and drop

#include <qtole.h> // Interface to qtole dll's

#include "common.h" // Interface to common.c

#include "player.h"  // Interface to other *.c files
#include "player.hr" // Defines used in *.rc files


// Message-Persistent Data
// -----------------------
static struct // Hungarian notation: g
  { HWND      hwndClient;          // MDI client window
    WORD      wNumMovies;          // Number of movie wnds
    BOOL      bUserAbortPrint;     // User abort print flag
    HWND      hwndCancelPrt;       // Handle of print cancel dlg
    HBITMAP   hAboutBitmap;        // Temp static storage of bitmap
                                   // displayed in about dialogs
    WORD      wTileCascadeArrange; // Indicates tiling, cascading or
                                   // icon arrange
    BOOL      bIconized;           // TRUE while frame wnd is iconized
    BOOL      bRestoring;          // TRUE if restoring iconized frame wnd
  } g;


// Exported callback functions
// ----------------------------
BOOL __export CALLBACK AboutDlgProc       (HWND, UINT, WPARAM, LPARAM);
BOOL __export CALLBACK CloseEnumProc      (HWND, LPARAM);
BOOL __export CALLBACK MovieEnumProc      (HWND, LPARAM);
BOOL __export CALLBACK PrintCancelDlgProc (HWND, UINT, WPARAM, LPARAM);
int  __export CALLBACK PrintAbortProc     (HDC, int);
UINT __export CALLBACK PrintDlgHookProc   (HWND, UINT, WPARAM, LPARAM);

// Internal Function Declarations
// ------------------------------
static LONG NEAR PlayerFrameCreate       (HWND);
static LONG NEAR PlayerFileCommands      (HWND, WPARAM, WORD);
static LONG NEAR PlayerWindowCommands    (HWND, WPARAM, WORD);
static LONG NEAR PlayerHelpCommands      (HWND, WPARAM, WORD);
static LONG NEAR LaunchMovieWnd          (LPSTR, LPSTR);
static VOID NEAR PlayerEnableMenus       (HWND, BOOL);
static VOID NEAR TellUserCommonDlgError  (DWORD);
static LONG NEAR ProcessDroppedFiles     (HWND, WPARAM);
static VOID NEAR DestroyHelpInstance     (HWND);

// -----------------------------------------------------------------------


// Function: PlayerFrameWndProc - Player Frame Window Procedure
// --------------------------------------------------------------------
// Parameters: As required by Microsoft Windows
//
// Returns:    Via DefFrameProc
// --------------------------------------------------------------------
LONG __export CALLBACK PlayerFrameWndProc
    (HWND hwndFrame, UINT message, WPARAM wParam, LPARAM lParam)

{
    WNDENUMPROC       lpfnEnumMovies; // -> callback funcion for
                                      // enumeration of movies
    HWND              hwndMovie;      // Temp handle of active movie wnd
    LPQTOLE_OLEDATA   lpOleData;      // -> ole data

    switch( message ) {
        case WM_CREATE:
            return PlayerFrameCreate( hwndFrame );

        case WM_PALETTECHANGED:
            if( g.wNumMovies &&
                ( lpfnEnumMovies = (WNDENUMPROC) MakeProcInstance
                ( (FARPROC) MovieEnumProc, PlayerQueryInstance()))) { // Tell the movie wnds to repaint
                EnumChildWindows( g.hwndClient, lpfnEnumMovies,
                    (LPARAM) message);
                FreeProcInstance( (FARPROC) lpfnEnumMovies );
            }

            return 0L;

        case WM_SIZE:
            if( wParam == SIZE_MINIMIZED ) {
                g.bIconized  = TRUE;
                g.bRestoring = FALSE;
            }
            else if( g.bIconized && 
                (( wParam == SIZE_RESTORED ) ||
                ( wParam == SIZE_MAXIMIZED ))) {
                g.bIconized  = FALSE;
                g.bRestoring = TRUE;
            }

            if( g.wNumMovies &&
                ( lpfnEnumMovies = (WNDENUMPROC) MakeProcInstance
                ( (FARPROC) MovieEnumProc, PlayerQueryInstance()))) { // Tell the movie wnds to reset their grow box bounds rect
                EnumChildWindows( g.hwndClient, lpfnEnumMovies, 
                    (LPARAM) message);
                FreeProcInstance( (FARPROC) lpfnEnumMovies );
            }

            if( g.bRestoring ) {
                g.bRestoring = FALSE;
            }

            break; // break to DefFrameProc


        case WM_INITMENUPOPUP:
            // Set check marks and enable menu items in popups
            if( !(BOOL) HIWORD( lParam ) &&
                ( hwndMovie = (HWND) SendMessage
                ( g.hwndClient, WM_MDIGETACTIVE, 0, 0l )) &&
                IsWindow( hwndMovie ))
                SendMessage( hwndMovie, WM_PLAYER_INITPOPUPS, wParam, lParam );

            return 0L;

        case WM_COMMAND:
            switch( wParam ) {
                case PLAYER_FILE_OPEN: // file menu popup
                case PLAYER_FILE_CLOSE:
                case PLAYER_FILE_PRTSETUP:
                case PLAYER_FILE_PRINT:
                case PLAYER_FILE_EXIT:
                    return PlayerFileCommands
                        ( hwndFrame, wParam, HIWORD (lParam));

                case PLAYER_WINDOW_TILE: // window menu popup
                case PLAYER_WINDOW_CASCADE:
                case PLAYER_WINDOW_ARRANGE:
                    return PlayerWindowCommands
                        ( hwndFrame, wParam, HIWORD (lParam));


                case PLAYER_HELP_PLAYERHELP: // help menu popup
                case PLAYER_HELP_USINGHELP:
                case PLAYER_HELP_ABOUTPLAYER:
                    return PlayerHelpCommands
                        ( hwndFrame, wParam, HIWORD( lParam ));

                default:
                    if( ( hwndMovie = (HWND) SendMessage
                        ( g.hwndClient, WM_MDIGETACTIVE, 0, 0L )) &&
                        IsWindow( hwndMovie ))
                        SendMessage( hwndMovie, WM_COMMAND, wParam, lParam );

                    break; // break to DefFrameProc
            } 

            break;

        // WM_USER messages

        case WM_PLAYER_CMDLINE:
            return LaunchMovieWnd( (LPSTR) lParam, NULL );

        case WM_PLAYER_MOVIEDELETED:
            // Decrement movie count. This is incremented in LaunchMovieWnd
            // when movie is created
            if( --g.wNumMovies <= 0 )
                PlayerEnableMenus( hwndFrame, FALSE );
            return 0L;

        // These next messages are posted by the ole callback function in MovieUtl.c
        case WM_PLAYER_OLE_OPTIONSDLG:
            PlayerGetOptions( NULL, (LPQTOLE_OPTIONSMOVIE) lParam );
            return 0L;

        case WM_PLAYER_OLE_PLAYOBJECT:
            QTOLE_PlayObject( PlayerQueryOleData(), lParam );
            return 0L;

        // end WM_USER messages


        // Standard drag and drop processing. Allows for multiple movies but
        // does not worry about position of drop
        case WM_DROPFILES:
            return ProcessDroppedFiles( hwndFrame, wParam );

        case WM_QUERYENDSESSION:
        case WM_CLOSE:
            if( g.wNumMovies &&
                ( lpfnEnumMovies = (WNDENUMPROC) MakeProcInstance
                ( (FARPROC) CloseEnumProc, PlayerQueryInstance()))) { // Give all movies a chance to stop the close
                EnumChildWindows( g.hwndClient, lpfnEnumMovies, 0L );
                FreeProcInstance( (FARPROC) lpfnEnumMovies );

                // If someone didn't want to close, don't kill the app
                if( NULL != GetWindow( g.hwndClient, GW_CHILD ))
                    return 0L;
            }

            // Tell qtole.dll that we are closing the server
            // Don't close if QTOLE_ClossingServerWnd returns FALSE;
            if( ( lpOleData = PlayerQueryOleData()) && 
                lpOleData->lpqtoleServer &&
                !QTOLE_ClosingServerWnd( lpOleData, message ))
                return 0L;

            break; // break to DefFrameProc

        case WM_DESTROY:
            DragAcceptFiles( hwndFrame, FALSE );

            // Destroy help instance
            DestroyHelpInstance( hwndFrame );

            // NULL the hwnd globals in playmain.c
            PlayerNoMoreWindow();

            PostQuitMessage( 0 );
            break;

    }

    return DefFrameProc
        ( hwndFrame, g.hwndClient, message, wParam, lParam );
}


// Function: PlayerFrameCreate - process WM_CREATE message
// --------------------------------------------------------------------
// Parameters: HWND hwndFrame;         Frame window
//
// Returns:    0L if OK, else returns -1L to kill app
// --------------------------------------------------------------------
static LONG NEAR PlayerFrameCreate( HWND hwndFrame )

{
    CLIENTCREATESTRUCT  clientcreate;  // MDI client create struct
    char                szCaption[50]; // caption buffer;


    szCaption[0] = '\0';
    if( LoadString( PlayerQueryResources(), PLAYER_STRING_CAPTION,
        szCaption, sizeof( szCaption )))
        SetWindowText( hwndFrame, szCaption );
    // No point in trying for an error message here since it probably won't
    // load either.

    // disable menu items until a movie is created
    g.wNumMovies = 0;
    PlayerEnableMenus( hwndFrame, FALSE );

    DragAcceptFiles( hwndFrame, TRUE );

    clientcreate.hWindowMenu =
        GetSubMenu( GetMenu( hwndFrame ), MENU_WINDOW_POS );
    clientcreate.idFirstChild = PLAYER_CLIENT_FIRSTCHILD;

    if( !(g.hwndClient = CreateWindow("MDICLIENT", NULL,
        WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE |
        WS_HSCROLL | WS_VSCROLL,
        0, 0, 0, 0, hwndFrame, ( HMENU) 1,
        PlayerQueryInstance(), (LPVOID) &clientcreate )))
        return -1L; // return -1 to kill app
    else
        return  0L;
}


// Function: PlayerFileCommands - Process WM_COMMAND, File popup messages
// --------------------------------------------------------------------
// Parameters: HWND   hwndFrame;      Frame window
//             WORD   wIDItem;        Menu or control id
//             WORD   wNotifyCode;    notification message
//
// Returns:    LONG   generally 0L
// --------------------------------------------------------------------
static LONG NEAR PlayerFileCommands
                    (HWND hwndFrame, WPARAM wIDItem, WORD wNotifyCode )

{
    HWND           hwndMovie;                 // Handle of movie window
    OPENFILENAME   ofn;                       // OPENFILENAME struct
    UINT           cbString;                  // Length of filter string
    char           szMoviePath[256];          // Movie file path
                                              // Must be at least 256 bytes
    char           szMovieName[MAX_NAME_LEN]; // Movie file name
    char           szFilter[256];             // Movie file filter str
    LPSTR          lpTemp;                    // Temp -> to string
    LPSTR          lpSave;                    // Temp -> to string
    char           chReplace;                 // String separator used in filter string
    DWORD          dwError;                   // Common dlg error return
    PRINTDLG       pd;                        // Print common dlg struct
    ABORTPROC      lpPrintAbortProc;          // Print abort proc
    DLGPROC        lpPrtCancelProc;           // Print cancel dlg proc
    WORD           wIDError;                  // Resource errror string id
    int            nError;                    // Error return;

    static DWORD   nFilterIndex;


    typedef UINT ( CALLBACK * PRINTDLGHOOKPROC ) ( HWND, UINT, WPARAM, LPARAM );


    switch( wIDItem ) {
        case PLAYER_FILE_OPEN:
            memset( &ofn, 0, sizeof( OPENFILENAME ));
            szMoviePath[0] = '\0';

            if( !(cbString = LoadString( PlayerQueryResources(),
                PLAYER_STRING_OPENMOVIEFILTER,
                szFilter, sizeof( szFilter ))))
                return 0L;

            // See 3.1 SDK manuals, vol. 1 for examples of common dlg processing
            lpTemp = szFilter + lstrlen( szFilter );
            chReplace = *AnsiPrev( szFilter, lpTemp );
            lpTemp = szFilter;
            while( *lpTemp ) {
                if( *lpTemp == chReplace ) { // Need to increment pointer past chReplace before
                                             // setting to NULL. Otherwise AnsiNext thinks it is
                                             // at end of string and quits
                    lpSave = lpTemp;
                    lpTemp = AnsiNext( lpTemp );
                    *lpSave = '\0';
                }
                else
                    lpTemp = AnsiNext( lpTemp );
            }

            ofn.lStructSize    = sizeof( OPENFILENAME );
            ofn.hwndOwner      = hwndFrame;
            ofn.lpstrFilter    = szFilter;
            ofn.nFilterIndex   = nFilterIndex;
            ofn.lpstrFile      = szMoviePath;
            ofn.nMaxFile       = sizeof( szMoviePath );
            ofn.lpstrFileTitle = szMovieName;
            ofn.nMaxFileTitle  = sizeof( szMovieName );
            ofn.Flags          = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST |
                OFN_HIDEREADONLY;

            if( GetOpenFileName( &ofn )) {
                nFilterIndex = ofn.nFilterIndex;
                LaunchMovieWnd( szMoviePath, szMovieName );
            }  
            else if( dwError = CommDlgExtendedError() ) { // Tell the user about the error
                TellUserCommonDlgError( dwError );
            }

            return 0L;

        case PLAYER_FILE_CLOSE:
            if( ( hwndMovie = (HWND) SendMessage
                ( g.hwndClient, WM_MDIGETACTIVE, 0, 0L )) &&
                IsWindow( hwndMovie ))
                SendMessage( hwndMovie, WM_CLOSE, 0, 0L );

            return 0L;

        case PLAYER_FILE_PRTSETUP:
            memset( &pd, 0, sizeof( PRINTDLG ));

            pd.lStructSize = sizeof( PRINTDLG );
            pd.hwndOwner   = hwndFrame;
            pd.Flags       = PD_PRINTSETUP;

            if( ( PrintDlg( &pd ) == 0 ) &&
                ( dwError = CommDlgExtendedError() )) { // Tell the user about the error
                TellUserCommonDlgError( dwError );
            }

            return 0L;

        case PLAYER_FILE_PRINT:
            memset( &pd, 0, sizeof( PRINTDLG ));

            pd.lStructSize = sizeof( PRINTDLG );
            pd.hwndOwner   = hwndFrame;
            pd.Flags       = PD_RETURNDC |
                PD_ENABLEPRINTHOOK | PD_ENABLEPRINTTEMPLATE;
            pd.hInstance   = PlayerQueryResources();
            pd.lpPrintTemplateName = MAKEINTRESOURCE( CUSTOM_DLG_COMN_PRINT );
            if( !( pd.lpfnPrintHook =  (PRINTDLGHOOKPROC) 
                MakeProcInstance( (FARPROC) PrintDlgHookProc,
                PlayerQueryInstance()))) {
                CommonTellUser( PlayerQueryResources(), 
                    PLAYER_STRING_NOMEMORY, NULL, MB_OK );
                return 0L;
            }

            if( PrintDlg( &pd ) != 0 ) {
                lpPrtCancelProc = (DLGPROC) MakeProcInstance
                    ( (FARPROC) PrintCancelDlgProc, PlayerQueryInstance() );

                lpPrintAbortProc = (ABORTPROC) MakeProcInstance
                    ( (FARPROC) PrintAbortProc, PlayerQueryInstance() );

                if( !lpPrtCancelProc || !lpPrintAbortProc ) {
                    CommonTellUser( PlayerQueryResources(),
                        PLAYER_STRING_NOMEMORY, NULL, MB_OK );
                    return 0L;
                }

                g.bUserAbortPrint = FALSE;
                nError   = 0;
                wIDError = 0;

                if( !(g.hwndCancelPrt =
                    CreateDialog( PlayerQueryResources(),
                    MAKEINTRESOURCE( PLAYER_DLG_PRINTCANCEL ),
                    hwndFrame, lpPrtCancelProc ))) {
                    wIDError = PLAYER_STRING_CANCELDLG;
                }
                else {
                    EnableWindow( hwndFrame, FALSE ); // disable frame window
                    if( SetAbortProc( pd.hDC, lpPrintAbortProc ) <= 0 )
                        wIDError = PLAYER_STRING_ABORTPROC;
                    else {
                        if( hwndMovie = (HWND) SendMessage
                            ( g.hwndClient, WM_MDIGETACTIVE, 0, 0L ))
                            nError = (int) SendMessage( hwndMovie,
                            WM_PLAYER_PRINTFRAME, 0,
                            (LPARAM) (LPPRINTDLG) &pd );
                        if( ( nError < 0 ) &&
                            ( nError & SP_NOTREPORTED ) &&
                            !g.bUserAbortPrint ) {
                            switch( nError ) {
                                case SP_APPABORT:
                                case SP_USERABORT:
                                    break;
                                case SP_OUTOFDISK:
                                    wIDError = PLAYER_STRING_PRT_OUTOFDISK;
                                    break;
                                case SP_OUTOFMEMORY:
                                    wIDError = PLAYER_STRING_PRT_NOMEMORY;
                                    break;
                                case SP_ERROR: // fall through
                                default:
                                    wIDError = PLAYER_STRING_PRT_GENERROR;
                                    break;
                            }
                        }
                    }

                    EnableWindow( hwndFrame, TRUE ); // reenable frame window

                    if( g.hwndCancelPrt )
                        DestroyWindow( g.hwndCancelPrt );
                }

                if( wIDError )
                    CommonTellUser( PlayerQueryResources(), wIDError,
                    PLAYER_STRING_PRT_CAPTION, MB_OK );

                FreeProcInstance( (FARPROC) lpPrtCancelProc );
                FreeProcInstance( (FARPROC) lpPrintAbortProc );

                if( pd.hDC != NULL )
                    DeleteDC( pd.hDC );
                if( pd.hDevMode != NULL )
                    GlobalFree( pd.hDevMode );
                if( pd.hDevNames != NULL )
                    GlobalFree( pd.hDevNames );

            }
            else if( dwError = CommDlgExtendedError() ) { // Tell the user about the error
                TellUserCommonDlgError( dwError );
            }

            return 0L;

        case PLAYER_FILE_EXIT:
            SendMessage( hwndFrame, WM_CLOSE, 0, 0L );
            return 0L;
    }

    return 0L; // should never get here

}


// Function: PlayerWindowCommands - Process WM_COMMAND, Window popup messages
// --------------------------------------------------------------------
// Parameters: HWND   hwndFrame;      Frame window
//             WORD   wIDItem;        Menu or control id
//             WORD   wNotifyCode;    notification message
//
// Returns:    LONG   generally 0L
// --------------------------------------------------------------------
static LONG NEAR PlayerWindowCommands
                    (HWND hwndFrame, WPARAM wIDItem, WORD wNotifyCode )

// Tile and cascade are implemented using modifications of
// the standard MDI processing in order to preserve the size
// and aspect ratio of the movies. The modifications are implemented
// in MovieWnd.c on the basis of the value of g.wTileCascadeArrange

{
    g.wTileCascadeArrange = wIDItem;

    switch( wIDItem ) { // Modify the tile using the WM_WINDOWPOSCHANGING message in 
                        // the movie window processing to set the original aspect
                        // ratio and, if possible, size of the movies
        case PLAYER_WINDOW_TILE:
            SendMessage( g.hwndClient, WM_MDITILE, 0, 0L );
            break;

        // Modify the cascade using the WM_GETMINMAXINFO message in 
        // the movie window processing to preserve the current size
        // of the movies
        case PLAYER_WINDOW_CASCADE:
            SendMessage( g.hwndClient, WM_MDICASCADE, 0, 0L );
            break;

        // This is standard MDI. 
        case PLAYER_WINDOW_ARRANGE:
            SendMessage( g.hwndClient, WM_MDIICONARRANGE, 0, 0L );
            break;
    }

    g.wTileCascadeArrange = 0;

    return 0L; 

}


// Function: PlayerHelpCommands - Process WM_COMMAND, Help popup messages
// --------------------------------------------------------------------
// Parameters: HWND   hwndFrame;      Frame window
//             WORD   wIDItem;        Menu or control id
//             WORD   wNotifyCode;    notification message
//
// Returns:    LONG   generally 0L
// --------------------------------------------------------------------
static LONG NEAR PlayerHelpCommands
                    (HWND hwndFrame, WPARAM wIDItem, WORD wNotifyCode )

{
    char       szHelp[MAX_PATH_LEN]; // Help file path
    DLGPROC    lpDlgProc;            // -> dialog proc

    switch( wIDItem ) {
        case PLAYER_HELP_PLAYERHELP:
            CommonGetLocalizedHelpFile
                ( PLAYER_ROOT_NAME, szHelp, PlayerQueryInstance() );

            if( szHelp[0] )
                WinHelp( hwndFrame, (LPCSTR) szHelp, HELP_CONTENTS, 0L );
            else
                CommonTellUser( PlayerQueryResources(),
                PLAYER_STRING_NOHELPFILE,
                PLAYER_STRING_CAPTION, MB_OK );

            return 0L;

        case PLAYER_HELP_USINGHELP:
            WinHelp( hwndFrame, "WINHELP.HLP", HELP_CONTENTS, 0L );
            return 0L;

        case PLAYER_HELP_ABOUTPLAYER:
            if( ( g.hAboutBitmap = LoadBitmap( PlayerQueryResources(),
                MAKEINTRESOURCE( PLAYER_PLAYER_BITMAP ))) &&
                ( lpDlgProc = (DLGPROC) MakeProcInstance
                ( (FARPROC) AboutDlgProc, PlayerQueryInstance()))) {
                DialogBox( PlayerQueryResources(),
                    MAKEINTRESOURCE( PLAYER_DLG_ABOUTPLAYER ),
                    hwndFrame, lpDlgProc );
                FreeProcInstance( (FARPROC) lpDlgProc );
            }
            else
                CommonTellUser( PlayerQueryResources(),
                PLAYER_STRING_NOMEMORY,
                PLAYER_STRING_CAPTION, MB_OK );
            if( g.hAboutBitmap )
                DeleteObject( g.hAboutBitmap );
            g.hAboutBitmap = NULL;

            return 0L;
    }

    return 0L; // should never get here

}

//// the following are some utility routines

// Function: CloseEnumProc - Close all enumerate proc
// --------------------------------------------------------------------
// Parameters: As required by Microsoft Windows
//
// Returns:    Always TRUE to enumerate all windows
// --------------------------------------------------------------------
BOOL __export CALLBACK CloseEnumProc( HWND hwnd, LPARAM lParam )

{
    char   szClassName[40]; // Temp buffer for class name

    // Check class name since there are several classes of child windows
    if( !GetClassName( hwnd, szClassName, sizeof( szClassName )) ||
        lstrcmpi( szClassName, PLAYER_MOVIE_CLASS ))
        return TRUE;

    // If  someone doesn't want to close, stop enumeration
    if( !SendMessage( hwnd, WM_QUERYENDSESSION, 0, 0L ))
        return FALSE;

    SendMessage( GetParent( hwnd ), WM_MDIDESTROY, (WPARAM) hwnd, 0L );

    return TRUE;
}

// Function: MovieEnumProc - Tells all movie wnds to do something
// --------------------------------------------------------------------
// Parameters: As required by Microsoft Windows
//
// Returns:    Always TRUE to enumerate all windows
// --------------------------------------------------------------------
BOOL __export CALLBACK MovieEnumProc( HWND hwnd, LPARAM lParam )

{
    char    szClassName[40]; // Temp buffer for class name

    // Check class name since there are several classes of child windows
    if( !GetClassName( hwnd, szClassName, sizeof( szClassName )) ||
        lstrcmpi( szClassName, PLAYER_MOVIE_CLASS ))
        return TRUE;

    if( LOWORD( lParam ) == WM_PALETTECHANGED )
        // Tell the movies to repaint. The background is fixed up in the
        // paint processing
        InvalidateRect( hwnd, NULL, FALSE );
    else if( LOWORD( lParam ) == WM_SIZE ) {
        SendMessage( hwnd, WM_PLAYER_UPDATEGBBOUNDSRECT, 0, 0L );
        // Tell movies to stop if we are iconizing and to restart
        // if restoring
        if( g.bIconized || g.bRestoring )
            SendMessage( hwnd, WM_PLAYER_PLAYTHEMOVIE,
            (WPARAM ) g.bRestoring, 0L );
    }

    return TRUE;
}


// Function: LaunchMovieWnd - tell hwndClient to launch a movie wnd
// --------------------------------------------------------------------
// Parameters: LPSTR     lpMoviePath      Path of movie file
//             LPSTR     lpName           File name of movie file
//
// Returns:    LONG    0L if OK, else nonzero
// --------------------------------------------------------------------
static LONG NEAR LaunchMovieWnd( LPSTR lpMoviePath, LPSTR lpName )

{
    MDICREATESTRUCT    mdicreate; // mdi create struct
    HWND               hwndMovie; // Temp handle of window

    if( !lpMoviePath[0] )
        return -1L;

    if( lpName == NULL ) {
        lpName = lpMoviePath + lstrlen( lpMoviePath );
        lpName = AnsiPrev( lpMoviePath, lpName );
        while( *lpName && (*lpName != '\\') && (lpName != lpMoviePath))
            lpName = AnsiPrev( lpMoviePath, lpName );
        if( *lpName == '\\' )
            lpName = AnsiNext( lpName );
    }

    mdicreate.szClass = PLAYER_MOVIE_CLASS;
    mdicreate.szTitle = AnsiLower( lpName );
    mdicreate.hOwner  = PlayerQueryInstance();
    mdicreate.x       = CW_USEDEFAULT;
    mdicreate.y       = CW_USEDEFAULT;
    mdicreate.cx      = CW_USEDEFAULT;
    mdicreate.cy      = CW_USEDEFAULT;
    mdicreate.style   = 0;
    mdicreate.lParam  = (LPARAM) lpMoviePath;

    if( !( hwndMovie = (HWND) SendMessage
        ( g.hwndClient, WM_MDICREATE, 0,
        (LPARAM) (LPMDICREATESTRUCT) &mdicreate ))) {
        return -1L;
    }
    else {
        if(++g.wNumMovies == 1 )
            PlayerEnableMenus( PlayerQueryFrameWindow(), TRUE );
        return 0L;
    }
}

// Function: ProcessDroppedFiles - Process the WM_DROPFILES message
// --------------------------------------------------------------------
// Parameters: HWND     hwndFrame         Frame window handle
//             WPARAM   wParam            Message wParam
//
// Returns:    LONG     Always 0L;
// --------------------------------------------------------------------
static LONG NEAR ProcessDroppedFiles( HWND hwndFrame, WPARAM wParam )

{
    int           i;                        // Temp counter
    int           nNumFiles;                // Temp number of dropped files
    UINT          uBytes;                   // Temp len of drop file path
    char          szDropFile[MAX_PATH_LEN]; // Temp drop file path

    if( nNumFiles = DragQueryFile( (HDROP) wParam, 0xffff,
        (LPSTR) NULL, 0 )) { // Create processing requires that frame window has
                             // nonzero dimensions so first restore iconized wnd
        if( IsIconic( hwndFrame ))
            ShowWindow( hwndFrame, SW_SHOWNORMAL );

        for( i=0; i < nNumFiles; i++ ) {
            uBytes = DragQueryFile( (HDROP) wParam, i,
                (LPSTR) szDropFile, sizeof( szDropFile ));
            if( uBytes > 0 )
                LaunchMovieWnd( szDropFile, NULL );
        }
    }

    DragFinish( (HDROP) wParam );

    return 0L;
}


// Function: DestroyHelpInstance - Tell windows that instance is done with
//                                 help. This is called as a function so that
//                                 szHelp[] is not an automatic var. in the
//                                 winproc
// --------------------------------------------------------------------
// Parameters: HWND     hwndFrame         Frame window handle
//
// Returns:    VOID
// --------------------------------------------------------------------
static VOID NEAR DestroyHelpInstance( HWND hwndFrame )

{
    char    szHelp[MAX_PATH_LEN]; // Help file name

    WinHelp( hwndFrame, CommonGetLocalizedHelpFile
        ( PLAYER_ROOT_NAME, szHelp, PlayerQueryResources() ),
        HELP_QUIT, NULL );
    return;
}


// Function: AboutDlgProc - About dialog proc
// --------------------------------------------------------------------
// Parameters: As required by Microsoft Windows
//
// Returns:    As required by Microsoft Windows
// --------------------------------------------------------------------
BOOL __export CALLBACK AboutDlgProc
    ( HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam )

{
    BITMAP       bm;          // Temp bitmap struct
    HWND         hwndCntrl;   // Handle of rect control that is painted
    HDC          hdestDC;     // hdc of control rect
    HDC          hmemDC;      // Memory dc
    RECT         rcdestRect;  // Rect of control
    HBITMAP      hbitmapSave; // Prev bitmap
    PAINTSTRUCT  ps;          // Paint struct

    switch( msg ) {
        case WM_COMMAND:
            EndDialog( hdlg, 0 );
            return TRUE;

        case WM_PAINT:
            // Don't bother with error messages since only effect is that
            // bitmap will not appear in dialog
            if( !BeginPaint( hdlg, &ps ))
                return FALSE;
            EndPaint( hdlg, &ps );

            if( !g.hAboutBitmap ||
                !( hwndCntrl = GetDlgItem( hdlg, PLAYER_ABOUT_BMPFRAME )))
                return FALSE;

            InvalidateRect( hwndCntrl, NULL, TRUE );
            UpdateWindow( hwndCntrl );

            if( !(hdestDC = GetDC( hwndCntrl )))
                return FALSE;

            if( hmemDC = CreateCompatibleDC( hdestDC )) {
                if( hbitmapSave = SelectObject( hmemDC, g.hAboutBitmap )) {
                    GetObject( g.hAboutBitmap, sizeof( BITMAP ), &bm );
                    GetClientRect( hwndCntrl, &rcdestRect );

                    BitBlt( hdestDC,
                        ( rcdestRect.right - bm.bmWidth ) / 2,
                        ( rcdestRect.bottom - bm.bmHeight ) / 2,
                        bm.bmWidth, bm.bmHeight, hmemDC, 0, 0, SRCCOPY );

                    SelectObject( hmemDC, hbitmapSave );
                }

                DeleteDC( hmemDC );
            } 

            ReleaseDC( hwndCntrl, hdestDC );

            return FALSE;

        default:
            return FALSE;
    }

    return FALSE;
}


// Function: PrintAbortProc - Print abort proc
// --------------------------------------------------------------------
// Parameters: As required by Microsoft Windows
//
// Returns:    As required by Microsoft Windows
// --------------------------------------------------------------------
int __export CALLBACK PrintAbortProc( HDC hdc, int nCode )

{
    MSG     msg; // Message struct

    while( !g.bUserAbortPrint &&
        PeekMessage( &msg, NULL, NULL, NULL, PM_REMOVE )) {
        if( !g.hwndCancelPrt ||
            !IsDialogMessage( g.hwndCancelPrt, &msg )) {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
    }

    return !g.bUserAbortPrint;
}

// Function: PrintCancelDlgProc - User cancel printing dlg proc
// --------------------------------------------------------------------
// Parameters: As required by Microsoft Windows
//
// Returns:    As required by Microsoft Windows
// --------------------------------------------------------------------
BOOL __export CALLBACK PrintCancelDlgProc
    ( HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam )

{
    char    szName[MAX_NAME_LEN + 1]; // Buffer for movie name

    switch( msg ) {
        case WM_INITDIALOG:
            SetFocus( GetDlgItem( hdlg, IDCANCEL ));
            SetDlgItemText( hdlg, PRINT_CANCEL_MOVIENAME,
                PlayerQueryActiveMovieName( szName ));
            return TRUE;

        case WM_COMMAND:
            return ( g.bUserAbortPrint = TRUE );

        case WM_DESTROY:
            g.hwndCancelPrt = NULL;
            break;
    }

    return FALSE;
}

// Function: PrintDlgHookProc - Custom print common dlg hook function
// --------------------------------------------------------------------
// Parameters: As required by Microsoft Windows
//
// Returns:    As required by Microsoft Windows
// --------------------------------------------------------------------
UINT __export CALLBACK PrintDlgHookProc
                (HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam )

{ // The dialog ids are defined in dlgs.h
  // Array of ids of controls to be hidden
    static int nIDs[] = {grp1, rad1, rad2, rad3, stc2, edt1, 
                         stc3, edt2, chx1, chx2, pshHelp };
    UINT   i; // Temp counter


    if( message == WM_INITDIALOG ) {
        for( i=0; i < ( sizeof( nIDs ) / sizeof( nIDs[0] )); i++ )
            ShowWindow( GetDlgItem( hdlg, nIDs[i] ), SW_HIDE );

        return TRUE;
    }
    else
        return FALSE;
}


// Function: PlayerEnableMenus - Disables menu items when there
//                               are no movies
// --------------------------------------------------------------------
// Parameters: HWND       hwndFrame      Handle of frame window
//             BOOL       bEnable        Enabling flag
//
// Returns:    VOID
// --------------------------------------------------------------------
static VOID NEAR PlayerEnableMenus( HWND hwndFrame, BOOL bEnable )

{
    UINT    fFlag;      // Temp enabling flag
    HMENU   hmenuFrame; // Handle to main menu of frame window
    UINT    i;          // Index

    static UINT uMenuIDs[] = {PLAYER_FILE_CLOSE,
                              PLAYER_FILE_PRINT,

                              PLAYER_EDIT_COPY,
                              PLAYER_EDIT_OPTIONS,
                              PLAYER_EDIT_CANCELSEL,

                              PLAYER_MOVIE_GETINFO,
                              PLAYER_MOVIE_STOPATEND,
                              PLAYER_MOVIE_LOOP,
                              PLAYER_MOVIE_BACKANDFORTH,
                              PLAYER_MOVIE_PLAYSELONLY,
                              PLAYER_MOVIE_HALFSIZE,
                              PLAYER_MOVIE_NORMALSIZE,
                              PLAYER_MOVIE_DOUBLESIZE,
                              PLAYER_MOVIE_SHOWPOSTER,

                              PLAYER_WINDOW_TILE,
                              PLAYER_WINDOW_CASCADE,
                              PLAYER_WINDOW_ARRANGE
                             };


    if( !( hmenuFrame = GetMenu( hwndFrame )))
        return;

    fFlag = (bEnable ? MF_ENABLED : MF_GRAYED ) | MF_BYCOMMAND;
    for( i=0; i < sizeof( uMenuIDs ) / sizeof( uMenuIDs[0] ); i++ )
        EnableMenuItem( hmenuFrame, uMenuIDs[i], fFlag );

    DrawMenuBar( hwndFrame );

    return;
}

// Function: TellUserCommonDlgError - Tell the user about the common dlg
//                                    error
// --------------------------------------------------------------------
// Parameters: DWORD       dwError      error code returned by common dlg
//
// Returns:    VOID
// --------------------------------------------------------------------
static VOID NEAR TellUserCommonDlgError( DWORD dwError )

{
    WORD          wIDErrorString; // String id

    // Not much here now, can make this as explicit as desired
    // Now returns text of error id, i.e. "CDERR_INITIALIZATION"
    // Not all messages are explicitly included

    switch( dwError ) {
        case CDERR_FINDRESFAILURE: 
            wIDErrorString = PLAYER_STRING_CDLG_FINDRESFAIL;
            break;
        case CDERR_INITIALIZATION:
            wIDErrorString = PLAYER_STRING_CDLG_INITFAIL;
            break;
        case CDERR_LOADRESFAILURE:
            wIDErrorString = PLAYER_STRING_CDLG_LOADRESFAIL;
            break;           
        case CDERR_LOCKRESFAILURE:
            wIDErrorString = PLAYER_STRING_CDLG_LOCKRESFAIL;
            break;
        case CDERR_MEMALLOCFAILURE:
            wIDErrorString = PLAYER_STRING_CDLG_MEMALLOCFAIL;
            break;
        case CDERR_MEMLOCKFAILURE:
            wIDErrorString = PLAYER_STRING_CDLG_MEMLOCKFAIL;
            break;
        case CDERR_STRUCTSIZE:
            wIDErrorString = PLAYER_STRING_CDLG_STRUCTSIZE;
            break;
        case FNERR_INVALIDFILENAME:
            wIDErrorString = PLAYER_STRING_CDLG_BADFILENAME;
            break;
        case PDERR_INITFAILURE:
            wIDErrorString = PLAYER_STRING_CDLG_PRTINITFAIL;
            break;
        case PDERR_LOADDRVFAILURE:
            wIDErrorString = PLAYER_STRING_CDLG_LOADDRVFAIL;
            break;
        case PDERR_NODEFAULTPRN:
            wIDErrorString = PLAYER_STRING_CDLG_NODEFPRINTER;
            break;
        case PDERR_NODEVICES:
            wIDErrorString = PLAYER_STRING_CDLG_NODEVICES;
            break;
        case PDERR_PRINTERNOTFOUND:
            wIDErrorString = PLAYER_STRING_CDLG_NOFINDPNTR;
            break;
        case PDERR_SETUPFAILURE:
            wIDErrorString = PLAYER_STRING_CDLG_SETUPFAIL;
            break;
        default:
            wIDErrorString = PLAYER_STRING_CDLG_GENFAILURE;
            break;
    }

    if( wIDErrorString == PLAYER_STRING_CDLG_GENFAILURE )
        CommonTellUser( PlayerQueryResources(),
        PLAYER_STRING_CDLG_GENFAILURE,
        PLAYER_STRING_CDLG_CAP, MB_OK, dwError );
    else
        CommonTellUser( PlayerQueryResources(),
        PLAYER_STRING_CDLG_FORMAT, PLAYER_STRING_CDLG_CAP,
        MB_OK, wIDErrorString );
    return;

}


//  The remaining functions are the query functions called by other modules

// Function: PlayerQueryClientWindow - Query Client Window Handle
// --------------------------------------------------------------------
// Parameters: None.
//
// Returns:    HWND g.hwndClient;        MDI client window handle
// --------------------------------------------------------------------
HWND FAR PlayerQueryClientWindow( VOID )

{
    return g.hwndClient;
}

// Function: PlayerQueryNumMovies - Query number of movies
// --------------------------------------------------------------------
// Parameters: None.
//
// Returns:    HWND g.wNumMovies;        Number of movies
// --------------------------------------------------------------------
WORD FAR PlayerQueryNumMovies( VOID )

{
    return g.wNumMovies;
}

// Function: PlayerQueryMDIAction - Query tile, cascade or icon arrange.
// --------------------------------------------------------------------
// Parameters: None.
//
// Returns:    WORD   wTileCascadeArrange    MDI action menu id
// --------------------------------------------------------------------
WORD FAR PlayerQueryMDIAction( VOID )

{
    return g.wTileCascadeArrange;
}

