home *** CD-ROM | disk | FTP | other *** search
/ Programming Windows 95 / Programming Windows 95.iso / code / CHAP18 / MDIDEMO.C next >
Encoding:
C/C++ Source or Header  |  1996-01-01  |  18.5 KB  |  498 lines

  1. /*--------------------------------------------------------
  2.    MDIDEMO.C -- Multiple Document Interface Demonstration
  3.                 (c) Charles Petzold, 1996
  4.   --------------------------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include <stdlib.h>
  8. #include "mdidemo.h"
  9.  
  10. LRESULT CALLBACK FrameWndProc  (HWND, UINT, WPARAM, LPARAM) ;
  11. BOOL    CALLBACK CloseEnumProc (HWND, LPARAM) ;
  12. LRESULT CALLBACK HelloWndProc  (HWND, UINT, WPARAM, LPARAM) ;
  13. LRESULT CALLBACK RectWndProc   (HWND, UINT, WPARAM, LPARAM) ;
  14.  
  15.           // structure for storing data unique to each Hello child window
  16.  
  17. typedef struct tagHELLODATA
  18.      {
  19.      UINT     iColor ;
  20.      COLORREF clrText ;
  21.      }
  22.      HELLODATA, *LPHELLODATA ;
  23.  
  24.           // structure for storing data unique to each Rect child window
  25.  
  26. typedef struct tagRECTDATA
  27.      {
  28.      short cxClient ;
  29.      short cyClient ;
  30.      }
  31.      RECTDATA, *LPRECTDATA ;
  32.  
  33.           // global variables
  34.  
  35. char      szFrameClass[] = "MdiFrame" ;
  36. char      szHelloClass[] = "MdiHelloChild" ;
  37. char      szRectClass[]  = "MdiRectChild" ;
  38. HINSTANCE hInst ;
  39. HMENU     hMenuInit, hMenuHello, hMenuRect ;
  40. HMENU     hMenuInitWindow, hMenuHelloWindow, hMenuRectWindow ;
  41.  
  42. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  43.                     PSTR szCmdLine, int iCmdShow)
  44.      {
  45.      HACCEL      hAccel ;
  46.      HWND        hwndFrame, hwndClient ;
  47.      MSG         msg ;
  48.      WNDCLASSEX  wndclass ;
  49.  
  50.      hInst = hInstance ;
  51.  
  52.      if (!hPrevInstance) 
  53.           {
  54.                     // Register the frame window class
  55.  
  56.           wndclass.cbSize        = sizeof (wndclass) ;
  57.           wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  58.           wndclass.lpfnWndProc   = FrameWndProc ;
  59.           wndclass.cbClsExtra    = 0 ;
  60.           wndclass.cbWndExtra    = 0 ;
  61.           wndclass.hInstance     = hInstance ;
  62.           wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  63.           wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  64.           wndclass.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1) ;
  65.           wndclass.lpszMenuName  = NULL ;
  66.           wndclass.lpszClassName = szFrameClass ;
  67.           wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION) ;
  68.  
  69.           RegisterClassEx (&wndclass) ;
  70.  
  71.                     // Register the Hello child window class
  72.  
  73.           wndclass.cbSize        = sizeof (wndclass) ;
  74.           wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  75.           wndclass.lpfnWndProc   = HelloWndProc ;
  76.           wndclass.cbClsExtra    = 0 ;
  77.           wndclass.cbWndExtra    = sizeof (HANDLE) ;
  78.           wndclass.hInstance     = hInstance ;
  79.           wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  80.           wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  81.           wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  82.           wndclass.lpszMenuName  = NULL ;
  83.           wndclass.lpszClassName = szHelloClass ;
  84.           wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION) ;
  85.  
  86.           RegisterClassEx (&wndclass) ;
  87.  
  88.                     // Register the Rect child window class
  89.  
  90.           wndclass.cbSize        = sizeof (wndclass) ;
  91.           wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  92.           wndclass.lpfnWndProc   = RectWndProc ;
  93.           wndclass.cbClsExtra    = 0 ;
  94.           wndclass.cbWndExtra    = sizeof (HANDLE) ;
  95.           wndclass.hInstance     = hInstance ;
  96.           wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  97.           wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  98.           wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  99.           wndclass.lpszMenuName  = NULL ;
  100.           wndclass.lpszClassName = szRectClass ;
  101.           wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION) ;
  102.  
  103.           RegisterClassEx (&wndclass) ;
  104.           }
  105.                // Obtain handles to three possible menus & submenus
  106.  
  107.      hMenuInit  = LoadMenu (hInst, "MdiMenuInit") ;
  108.      hMenuHello = LoadMenu (hInst, "MdiMenuHello") ;
  109.      hMenuRect  = LoadMenu (hInst, "MdiMenuRect") ;
  110.  
  111.      hMenuInitWindow  = GetSubMenu (hMenuInit,   INIT_MENU_POS) ;
  112.      hMenuHelloWindow = GetSubMenu (hMenuHello, HELLO_MENU_POS) ;
  113.      hMenuRectWindow  = GetSubMenu (hMenuRect,   RECT_MENU_POS) ;
  114.  
  115.                // Load accelerator table
  116.  
  117.      hAccel = LoadAccelerators (hInst, "MdiAccel") ;
  118.  
  119.                // Create the frame window
  120.  
  121.      hwndFrame = CreateWindow (szFrameClass, "MDI Demonstration",
  122.                                WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  123.                                CW_USEDEFAULT, CW_USEDEFAULT,
  124.                                CW_USEDEFAULT, CW_USEDEFAULT,
  125.                                NULL, hMenuInit, hInstance, NULL) ;
  126.  
  127.      hwndClient = GetWindow (hwndFrame, GW_CHILD) ;
  128.  
  129.      ShowWindow (hwndFrame, iCmdShow) ;
  130.      UpdateWindow (hwndFrame) ;
  131.  
  132.                // Enter the modified message loop
  133.  
  134.      while (GetMessage (&msg, NULL, 0, 0))
  135.           {
  136.           if (!TranslateMDISysAccel (hwndClient, &msg) &&
  137.               !TranslateAccelerator (hwndFrame, hAccel, &msg))
  138.                {
  139.                TranslateMessage (&msg) ;
  140.                DispatchMessage (&msg) ;
  141.                }
  142.           }
  143.                // Clean up by deleting unattached menus
  144.  
  145.      DestroyMenu (hMenuHello) ;
  146.      DestroyMenu (hMenuRect) ;
  147.  
  148.      return msg.wParam ;
  149.      }
  150.  
  151. LRESULT CALLBACK FrameWndProc (HWND hwnd, UINT iMsg, WPARAM wParam,
  152.                                                      LPARAM lParam)
  153.      {
  154.      static HWND         hwndClient ;
  155.      CLIENTCREATESTRUCT  clientcreate ;
  156.      HWND                hwndChild ;
  157.      MDICREATESTRUCT     mdicreate ;
  158.  
  159.      switch (iMsg)
  160.           {
  161.           case WM_CREATE :          // Create the client window
  162.  
  163.                clientcreate.hWindowMenu  = hMenuInitWindow ;
  164.                clientcreate.idFirstChild = IDM_FIRSTCHILD ;
  165.  
  166.                hwndClient = CreateWindow ("MDICLIENT", NULL,
  167.                               WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
  168.                               0, 0, 0, 0, hwnd, (HMENU) 1, hInst,
  169.                               (LPSTR) &clientcreate) ;
  170.                return 0 ;
  171.  
  172.           case WM_COMMAND :
  173.                switch (wParam)
  174.                     {
  175.                     case IDM_NEWHELLO :       // Create a Hello child window
  176.  
  177.                          mdicreate.szClass = szHelloClass ;
  178.                          mdicreate.szTitle = "Hello" ;
  179.                          mdicreate.hOwner  = hInst ;
  180.                          mdicreate.x       = CW_USEDEFAULT ;
  181.                          mdicreate.y       = CW_USEDEFAULT ;
  182.                          mdicreate.cx      = CW_USEDEFAULT ;
  183.                          mdicreate.cy      = CW_USEDEFAULT ;
  184.                          mdicreate.style   = 0 ;
  185.                          mdicreate.lParam  = 0 ;
  186.  
  187.                          hwndChild = (HWND) SendMessage (hwndClient,
  188.                                         WM_MDICREATE, 0,
  189.                                         (LPARAM) (LPMDICREATESTRUCT) &mdicreate) ;
  190.                          return 0 ;
  191.  
  192.                     case IDM_NEWRECT :        // Create a Rect child window
  193.  
  194.                          mdicreate.szClass = szRectClass ;
  195.                          mdicreate.szTitle = "Rectangles" ;
  196.                          mdicreate.hOwner  = hInst ;
  197.                          mdicreate.x       = CW_USEDEFAULT ;
  198.                          mdicreate.y       = CW_USEDEFAULT ;
  199.                          mdicreate.cx      = CW_USEDEFAULT ;
  200.                          mdicreate.cy      = CW_USEDEFAULT ;
  201.                          mdicreate.style   = 0 ;
  202.                          mdicreate.lParam  = 0 ;
  203.  
  204.                          hwndChild = (HWND) SendMessage (hwndClient,
  205.                                         WM_MDICREATE, 0,
  206.                                         (LPARAM) (LPMDICREATESTRUCT) &mdicreate) ;
  207.                          return 0 ;
  208.  
  209.                     case IDM_CLOSE :          // Close the active window
  210.  
  211.                          hwndChild = (HWND) SendMessage (hwndClient,
  212.                                                   WM_MDIGETACTIVE, 0, 0) ;
  213.  
  214.                          if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0))
  215.                               SendMessage (hwndClient, WM_MDIDESTROY,
  216.                                            (WPARAM) hwndChild, 0) ;
  217.                          return 0 ;
  218.  
  219.                     case IDM_EXIT :           // Exit the program
  220.  
  221.                          SendMessage (hwnd, WM_CLOSE, 0, 0) ;
  222.                          return 0 ;
  223.  
  224.                                    // messages for arranging windows
  225.                     case IDM_TILE :
  226.                          SendMessage (hwndClient, WM_MDITILE, 0, 0) ;
  227.                          return 0 ;
  228.  
  229.                     case IDM_CASCADE :
  230.                          SendMessage (hwndClient, WM_MDICASCADE, 0, 0) ;
  231.                          return 0 ;
  232.  
  233.                     case IDM_ARRANGE :
  234.                          SendMessage (hwndClient, WM_MDIICONARRANGE, 0, 0) ;
  235.                          return 0 ;
  236.  
  237.                     case IDM_CLOSEALL :       // Attempt to close all children
  238.  
  239.                          EnumChildWindows (hwndClient, &CloseEnumProc, 0) ;
  240.                          return 0 ;
  241.  
  242.                     default :            // Pass to active child...
  243.  
  244.                          hwndChild = (HWND) SendMessage (hwndClient,
  245.                                                   WM_MDIGETACTIVE, 0, 0) ;
  246.  
  247.                         if (IsWindow (hwndChild))
  248.                              SendMessage (hwndChild, WM_COMMAND,
  249.                                           wParam, lParam) ;
  250.  
  251.                         break ;        // ...and then to DefFrameProc
  252.                     }
  253.                break ;
  254.  
  255.           case WM_QUERYENDSESSION :
  256.           case WM_CLOSE :                     // Attempt to close all children
  257.  
  258.                SendMessage (hwnd, WM_COMMAND, IDM_CLOSEALL, 0) ;
  259.  
  260.                if (NULL != GetWindow (hwndClient, GW_CHILD))
  261.                     return 0 ;
  262.  
  263.                break ;   // I.e., call DefFrameProc 
  264.  
  265.           case WM_DESTROY :
  266.                PostQuitMessage (0) ;
  267.                return 0 ;
  268.           }
  269.                // Pass unprocessed messages to DefFrameProc (not DefWindowProc)
  270.  
  271.      return DefFrameProc (hwnd, hwndClient, iMsg, wParam, lParam) ;
  272.      }
  273.  
  274. BOOL CALLBACK CloseEnumProc (HWND hwnd, LPARAM lParam)
  275.      {
  276.      if (GetWindow (hwnd, GW_OWNER))         // Check for icon title
  277.           return 1 ;
  278.  
  279.      SendMessage (GetParent (hwnd), WM_MDIRESTORE, (WPARAM) hwnd, 0) ;
  280.  
  281.      if (!SendMessage (hwnd, WM_QUERYENDSESSION, 0, 0))
  282.           return 1 ;
  283.  
  284.      SendMessage (GetParent (hwnd), WM_MDIDESTROY, (WPARAM) hwnd, 0) ;
  285.           return 1 ;
  286.      }
  287.  
  288. LRESULT CALLBACK HelloWndProc (HWND hwnd, UINT iMsg, WPARAM wParam,
  289.                                                         LPARAM lParam)
  290.      {
  291.      static COLORREF clrTextArray[] = { RGB (0,   0, 0), RGB (255, 0,   0),
  292.                                         RGB (0, 255, 0), RGB (  0, 0, 255),
  293.                                         RGB (255, 255, 255) } ;
  294.      static HWND     hwndClient, hwndFrame ;
  295.      HDC             hdc ;
  296.      HMENU           hMenu ;
  297.      LPHELLODATA     lpHelloData ;
  298.      PAINTSTRUCT     ps ;
  299.      RECT            rect ;
  300.  
  301.      switch (iMsg)
  302.           {
  303.           case WM_CREATE :
  304.                          // Allocate memory for window private data
  305.  
  306.                lpHelloData = (LPHELLODATA) HeapAlloc (GetProcessHeap (),
  307.                                                       HEAP_ZERO_MEMORY, 
  308.                                                       sizeof (HELLODATA)) ;
  309.                lpHelloData->iColor  = IDM_BLACK ;
  310.                lpHelloData->clrText = RGB (0, 0, 0) ;
  311.                SetWindowLong (hwnd, 0, (long) lpHelloData) ;
  312.  
  313.                          // Save some window handles
  314.  
  315.                hwndClient = GetParent (hwnd) ;
  316.                hwndFrame  = GetParent (hwndClient) ;
  317.                return 0 ;
  318.  
  319.           case WM_COMMAND :
  320.                switch (wParam)
  321.                     {
  322.                     case IDM_BLACK :
  323.                     case IDM_RED :
  324.                     case IDM_GREEN :
  325.                     case IDM_BLUE :
  326.                     case IDM_WHITE :
  327.                                    // Change the text color
  328.  
  329.                          lpHelloData = (LPHELLODATA) GetWindowLong (hwnd, 0) ;
  330.  
  331.                          hMenu = GetMenu (hwndFrame) ;
  332.  
  333.                          CheckMenuItem (hMenu, lpHelloData->iColor,
  334.                                                MF_UNCHECKED) ;
  335.                          lpHelloData->iColor = wParam ;
  336.                          CheckMenuItem (hMenu, lpHelloData->iColor,
  337.                                                MF_CHECKED) ;
  338.  
  339.                          lpHelloData->clrText =
  340.                                clrTextArray[wParam - IDM_BLACK] ;
  341.  
  342.                          InvalidateRect (hwnd, NULL, FALSE) ;
  343.                     }
  344.                return 0 ;
  345.  
  346.           case WM_PAINT :
  347.                          // Paint the window
  348.  
  349.                hdc = BeginPaint (hwnd, &ps) ;
  350.  
  351.                lpHelloData = (LPHELLODATA) GetWindowLong (hwnd, 0) ;
  352.                SetTextColor (hdc, lpHelloData->clrText) ;
  353.  
  354.                GetClientRect (hwnd, &rect) ;
  355.  
  356.                DrawText (hdc, "Hello, World!", -1, &rect,
  357.                          DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
  358.  
  359.                EndPaint (hwnd, &ps) ;
  360.                return 0 ;
  361.  
  362.           case WM_MDIACTIVATE :
  363.  
  364.                          // Set the Hello menu if gaining focus
  365.  
  366.                if (lParam == (LPARAM) hwnd)
  367.                     SendMessage (hwndClient, WM_MDISETMENU,
  368.                                (WPARAM) hMenuHello, (LPARAM) hMenuHelloWindow) ;
  369.  
  370.                          // Check or uncheck menu item
  371.  
  372.                lpHelloData = (LPHELLODATA) GetWindowLong (hwnd, 0) ;
  373.                CheckMenuItem (hMenuHello, lpHelloData->iColor,
  374.                         (lParam == (LPARAM) hwnd) ? MF_CHECKED : MF_UNCHECKED) ;
  375.  
  376.                          // Set the Init menu if losing focus
  377.  
  378.                if (lParam != (LPARAM) hwnd)
  379.                     SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuInit,
  380.                                  (LPARAM) hMenuInitWindow) ;
  381.  
  382.                DrawMenuBar (hwndFrame) ;
  383.                return 0 ;
  384.  
  385.           case WM_QUERYENDSESSION :
  386.           case WM_CLOSE :
  387.                if (IDOK != MessageBox (hwnd, "OK to close window?", "Hello",
  388.                                        MB_ICONQUESTION | MB_OKCANCEL))
  389.                     return 0 ;
  390.  
  391.                break ;   // I.e., call DefMDIChildProc
  392.  
  393.           case WM_DESTROY :
  394.                lpHelloData = (LPHELLODATA) GetWindowLong (hwnd, 0) ;
  395.                HeapFree (GetProcessHeap (), 0, lpHelloData) ;
  396.                return 0 ;
  397.           }
  398.                // Pass unprocessed message to DefMDIChildProc
  399.  
  400.      return DefMDIChildProc (hwnd, iMsg, wParam, lParam) ;
  401.      }
  402.  
  403. LRESULT CALLBACK RectWndProc (HWND hwnd, UINT iMsg, WPARAM wParam,
  404.                                                        LPARAM lParam)
  405.      {
  406.      static HWND  hwndClient, hwndFrame ;
  407.      HBRUSH       hBrush ;
  408.      HDC          hdc ;
  409.      LPRECTDATA   lpRectData ;
  410.      PAINTSTRUCT  ps ;
  411.      int          xLeft, xRight, yTop, yBottom ;
  412.      short        nRed, nGreen, nBlue ;
  413.  
  414.      switch (iMsg)
  415.           {
  416.           case WM_CREATE :
  417.                          // Allocate memory for window private data
  418.  
  419.                lpRectData = (LPRECTDATA) HeapAlloc (GetProcessHeap (),
  420.                                                     HEAP_ZERO_MEMORY, 
  421.                                                     sizeof (RECTDATA)) ;
  422.  
  423.                SetWindowLong (hwnd, 0, (long) lpRectData) ;
  424.  
  425.                          // Start the timer going
  426.  
  427.                SetTimer (hwnd, 1, 250, NULL) ;
  428.  
  429.                          // Save some window handles
  430.  
  431.                hwndClient = GetParent (hwnd) ;
  432.                hwndFrame  = GetParent (hwndClient) ;
  433.                return 0 ;
  434.  
  435.           case WM_SIZE :            // If not minimized, save the window size
  436.  
  437.                if (wParam != SIZE_MINIMIZED)
  438.                     {
  439.                     lpRectData = (LPRECTDATA) GetWindowLong (hwnd, 0) ;
  440.  
  441.                     lpRectData->cxClient = LOWORD (lParam) ;
  442.                     lpRectData->cyClient = HIWORD (lParam) ;
  443.                     }
  444.  
  445.                break ;        // WM_SIZE must be processed by DefMDIChildProc
  446.  
  447.           case WM_TIMER :           // Display a random rectangle
  448.  
  449.                lpRectData = (LPRECTDATA) GetWindowLong (hwnd, 0) ;
  450.  
  451.                xLeft   = rand () % lpRectData->cxClient ;
  452.                xRight  = rand () % lpRectData->cxClient ;
  453.                yTop    = rand () % lpRectData->cyClient ;
  454.                yBottom = rand () % lpRectData->cyClient ;
  455.                nRed    = rand () & 255 ;
  456.                nGreen  = rand () & 255 ;
  457.                nBlue   = rand () & 255 ;
  458.  
  459.                hdc = GetDC (hwnd) ;
  460.                hBrush = CreateSolidBrush (RGB (nRed, nGreen, nBlue)) ;
  461.                SelectObject (hdc, hBrush) ;
  462.  
  463.                Rectangle (hdc, min (xLeft, xRight), min (yTop, yBottom),
  464.                                max (xLeft, xRight), max (yTop, yBottom)) ;
  465.  
  466.                ReleaseDC (hwnd, hdc) ;
  467.                DeleteObject (hBrush) ;
  468.                return 0 ;
  469.  
  470.           case WM_PAINT :           // Clear the window
  471.  
  472.                InvalidateRect (hwnd, NULL, TRUE) ;
  473.                hdc = BeginPaint (hwnd, &ps) ;
  474.                EndPaint (hwnd, &ps) ;
  475.                return 0 ;
  476.  
  477.           case WM_MDIACTIVATE :     // Set the appropriate menu
  478.                if (lParam == (LPARAM) hwnd)
  479.                     SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuRect,
  480.                                  (LPARAM) hMenuRectWindow) ;
  481.                else
  482.                     SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuInit,
  483.                                  (LPARAM) hMenuInitWindow) ;
  484.  
  485.                DrawMenuBar (hwndFrame) ;
  486.                return 0 ;
  487.  
  488.           case WM_DESTROY :
  489.                lpRectData = (LPRECTDATA) GetWindowLong (hwnd, 0) ;
  490.                HeapFree (GetProcessHeap (), 0, lpRectData) ;
  491.                KillTimer (hwnd, 1) ;
  492.                return 0 ;
  493.           }
  494.                // Pass unprocessed message to DefMDIChildProc
  495.  
  496.      return DefMDIChildProc (hwnd, iMsg, wParam, lParam) ;
  497.      }
  498.