/*
 *
 *  PROGRAM  : BlandMDI.c
 *
 *  PURPOSE  : Show example of a minimal MDI application
 *
 *  FUNCTIONS:
 *
 *      WinMain() - Calls the initialization function
 *                  and processes message loop
 *
 *      BlandFrameWndProc() - Window function for the "frame"
 *                  window, which controls the menu
 *                  and contains the MDI client window
 *
 *      BlandMDIChildWndProc()- Window function for the individual
 *                  child windows
 *
 *      CloseAllChildren - Destroys all MDI child windows.
 *
 *      CommandHandler() - Processes the "frame" window's
 *                  WM_COMMAND messages.
 *
 * Copyright 1991 Microsoft Corporation. All rights reserved.
 */


/*--------------------  #includes  -------------------------------*/

#include "blandmdi.h"


/*--------------------  global variables  -------------------------*/

// global variables used in this module or among more than one module

HANDLE hInst;                   // Program instance handle
HWND hwndFrame     = NULL;      // Handle to main window
HWND hwndMDIClient = NULL;      // Handle to MDI client
LONG styleDefault  = 0;         // Default style bits for child windows


/*---------------------  function prototypes  -----------------------*/

// Forward declarations of helper functions in this module

VOID NEAR PASCAL CommandHandler  (HWND,WORD);
VOID NEAR PASCAL CloseAllChildren(VOID);


/*---------------  BlandFrameWndProc()  -------------------------------*/
/*
 *
 *  FUNCTION   : BlandFrameWndProc (hwnd, msg, wParam, lParam )
 *
 *  PURPOSE    : The window function for the "frame" window, which controls
 *               the menu and encompasses all the MDI child windows. Does
 *               the major part of the message processing. Specifically, in
 *               response to:
 *
 *               WM_CREATE : Creates and displays the "frame".
 *
 *               WM_COMMAND: Passes control to a command-handling function.
 *
 *               WM_CLOSE  : Quits the app. 
 *
 *               WM_DESTROY: Destroys frame window and quits app.
 *
 *  NOTE: If cases are added for WM_MENUCHAR, WM_NEXTMENU, WM_SETFOCUS,
 *        and WM_SIZE, note that these messages should be passed on
 *        to DefFrameProc even if we handle them.  See the SDK Reference
 *        entry for DefFrameProc
 */


LONG FAR PASCAL BlandFrameWndProc ( hwnd, msg, wParam, lParam )

register HWND hwnd;
WORD          msg;
register WORD wParam;
LONG          lParam;

{
    switch (msg)
        {
        case WM_CREATE:
            {
            CLIENTCREATESTRUCT ccs;

            // Find window menu where children will be listed 
            ccs.hWindowMenu  = GetSubMenu (GetMenu(hwnd),WINDOWMENU);
            ccs.idFirstChild = IDM_WINDOWCHILD;

            // Create the MDI client 
            hwndMDIClient = CreateWindow ("mdiclient",
                NULL,
                WS_CHILD | WS_CLIPCHILDREN,
                0,
                0,
                0,
                0,
                hwnd,
                0,
                hInst,
                (LPSTR)&ccs);
            ShowWindow (hwndMDIClient,SW_SHOW);
            break;
            }

        case WM_COMMAND:
            // Direct all menu selection or accelerator commands to 
            // the CommandHandler function
            CommandHandler (hwnd,wParam);
            break;

        case WM_CLOSE:
            DestroyWindow (hwnd);
            break;

        case WM_DESTROY:
            PostQuitMessage (0);
            break;

        default:
            // use DefFrameProc() instead of DefWindowProc(), since there
            // are things that have to be handled differently because of MDI
            
            return DefFrameProc (hwnd,hwndMDIClient,msg,wParam,lParam);
        }
    return 0;
}


/*--------------------BlandMDIChildWndProc  ----------------------*/
/*
 *
 *  FUNCTION: BlandMDIChildWndProc ( hwnd, msg, wParam, lParam )  
 *
 *  NOTE: If cases are added for WM_CHILDACTIVATE, WM_GETMINMAXINFO,
 *        WM_MENUCHAR, WM_MOVE, WM_NEXTMENU, WM_SETFOCUS, WM_SIZE,
 *        or WM_SYSCOMMAND, these messages should be passed on
 *        to DefMDIChildProc even if we handle them. See the SDK
 *        Reference entry for DefMDIChildProc
 *
 */


LONG FAR PASCAL BlandMDIChildWndProc ( hwnd, msg, wParam, lParam )

register HWND hwnd;
WORD          msg;
register WORD wParam;
LONG          lParam;

{
    // Since this is a generic MDI app, the children don't handle
    // and messages in non-default ways
    return DefMDIChildProc (hwnd, msg, wParam, lParam);
}



/*-----------------  CommandHandler  -------------------------------*/
/*
 *
 *  FUNCTION   : CommandHandler ()
 *                    
 *  PURPOSE    : Processes all "frame" WM_COMMAND messages.       
 *                     
 */

VOID NEAR PASCAL CommandHandler ( hwnd, wParam )
register HWND hwnd;
register WORD wParam;

{
    switch (wParam)
        {
        case IDM_FILENEW:
            // Make an empty MDI child window 
            MakeNewChild (NULL);
            break;

        case IDM_FILEEXIT:
            // Close application 
            SendMessage (hwnd, WM_CLOSE, 0, 0L);
            break;

        case IDM_WINDOWTILE:
            // Tile MDI windows 
            SendMessage (hwndMDIClient, WM_MDITILE, 0, 0L);
            break;

        case IDM_WINDOWCASCADE:
            // Cascade MDI windows 
            SendMessage (hwndMDIClient, WM_MDICASCADE, 0, 0L);
            break;

        case IDM_WINDOWICONS:
            // Auto - arrange MDI icons 
            SendMessage (hwndMDIClient, WM_MDIICONARRANGE, 0, 0L);
            break;

        case IDM_WINDOWCLOSEALL:
            CloseAllChildren();
            break;

        default:
            // This is essential, since there are frame WM_COMMANDS generated
            // by the MDI system for activating child windows via the
            // window menu.
            DefFrameProc(hwnd, hwndMDIClient, WM_COMMAND, wParam, 0L);
        }
}

/*-------------------  CloseAllChildren  -----------------------------*/
/*
 *
 *  FUNCTION   : CloseAllChildren ()       
 *                 
 *  PURPOSE    : Destroys all MDI child windows.
 *
 */


VOID NEAR PASCAL CloseAllChildren (VOID)
{
    register HWND hwndT;

    // As long as the MDI client has a child, destroy it 
    while ( hwndT = GetWindow (hwndMDIClient, GW_CHILD))
        {
        // Skip the icon title windows 
        while (hwndT && GetWindow (hwndT, GW_OWNER))
            hwndT = GetWindow (hwndT, GW_HWNDNEXT);
        if (hwndT)
            SendMessage (hwndMDIClient, WM_MDIDESTROY, (WORD)hwndT, 0L);
        else
            break;
        }
}



/*-----------------------  WinMain  ----------------------------------*/
/*
 *
 *  FUNCTION   : WinMain(HANDLE, HANDLE, LPSTR, int) 
 *                     
 *  PURPOSE    : Creates the "frame" window, does some initialization and  
 *     enters the message loop.         
 *              
 */


int NEAR PASCAL WinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow)

HANDLE hInstance;
HANDLE hPrevInstance;
LPSTR  lpszCmdLine;
int    nCmdShow;
{
    MSG msg;

    hInst = hInstance;

    // If this is the first instance of the app. register window classes 
    if (!hPrevInstance)
       if (!InitializeApplication ())
         return 0;

    // Create the frame and do other initialization
    if (!InitializeInstance (lpszCmdLine, nCmdShow))
       return 0;

    // Enter main message loop 
    while (GetMessage (&msg, NULL, 0, 0))
        // If a keyboard message is for the MDI, let the MDI client
        // take care of it.  Otherwise, just handle the message as usual
        if ( !TranslateMDISysAccel (hwndMDIClient, &msg))
            {
            TranslateMessage (&msg);
            DispatchMessage (&msg);
            }
    return 0;
}
