home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / classlib / cclient.cpp < prev    next >
C/C++ Source or Header  |  1996-05-21  |  19KB  |  833 lines

  1. /*
  2.  * CCLIENT.CPP
  3.  * Sample Code Class Libraries
  4.  *
  5.  * Implementation of the CClient class that handles an SDI or MDI
  6.  * client area window.
  7.  *
  8.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  9.  *
  10.  * Kraig Brockschmidt, Microsoft
  11.  * Internet  :  kraigb@microsoft.com
  12.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  13.  */
  14.  
  15.  
  16. #include <windows.h>
  17. #include "classlib.h"
  18. #include <dbgout.h>
  19.  
  20.  
  21. /*
  22.  * CClient::CClient
  23.  * CClient::~CClient
  24.  *
  25.  * Constructor Parameters:
  26.  *  hInst           HINSTANCE of the application.
  27.  *  pFR             PCFrame of the frame object.
  28.  */
  29.  
  30. CClient::CClient(HINSTANCE hInst, PCFrame pFR)
  31.     : CWindow(hInst)
  32.     {
  33.     m_pFR=pFR;
  34.     m_cDoc=0;
  35.     m_pDocLast=NULL;
  36.     m_hListDocs=NULL;
  37.     m_pAdv=NULL;
  38.     return;
  39.     }
  40.  
  41.  
  42. CClient::~CClient(void)
  43.     {
  44.     if (NULL!=m_hListDocs)
  45.         DestroyWindow(m_hListDocs);
  46.  
  47.     if (NULL!=m_pAdv)
  48.         delete m_pAdv;
  49.  
  50.     return;
  51.     }
  52.  
  53.  
  54.  
  55.  
  56.  
  57. /*
  58.  * CClient::Init
  59.  *
  60.  * Purpose:
  61.  *  Creates a client area window sensitive to SDI or MDI
  62.  *  (compile-time) as well as performng other internal
  63.  *  initialization.
  64.  *
  65.  * Parameters:
  66.  *  hMenuWindow     HWND of the Window menu on the frame.
  67.  *  pRect           LPRECT containing the desired window rectangle.
  68.  *
  69.  * Return Value:
  70.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  71.  */
  72.  
  73. BOOL CClient::Init(HMENU hMenuWindow, LPRECT pRect)
  74.     {
  75.     HWND                hWndFrame;
  76.     LPTSTR              pszClass;
  77.     DWORD               dwStyle;
  78.     CLIENTCREATESTRUCT  ccs;
  79.  
  80.     hWndFrame=m_pFR->Window();
  81.  
  82.    #ifdef MDI
  83.     ccs.hWindowMenu =hMenuWindow;
  84.     ccs.idFirstChild=ID_MDICHILDMIN;
  85.     pszClass=TEXT("mdiclient");
  86.     dwStyle=MDIS_ALLCHILDSTYLES;
  87.    #else
  88.     //SDI
  89.     pszClass=SZCLASSSDICLIENT;
  90.     dwStyle=0L;
  91.    #endif
  92.  
  93.     m_hWnd=CreateWindow(pszClass, pszClass, dwStyle | WS_CHILD
  94.         | WS_CLIPCHILDREN | WS_VISIBLE | WS_CLIPSIBLINGS
  95.         , pRect->left, pRect->top, pRect->right-pRect->left
  96.         , pRect->bottom-pRect->top, hWndFrame, NULL, m_hInst
  97.         , &ccs);
  98.  
  99.     if (NULL==m_hWnd)
  100.         return FALSE;
  101.  
  102.     //Create the hidden listbox for managing our list of documents
  103.     m_hListDocs=CreateWindow(TEXT("listbox"), TEXT("Document List")
  104.         , WS_POPUP | LBS_OWNERDRAWFIXED, 0, 0, 100, 100
  105.         , HWND_DESKTOP, NULL, m_hInst, NULL);
  106.  
  107.     if (NULL==m_hListDocs)
  108.         return FALSE;
  109.  
  110.     /*
  111.      * Create an advise sink for the frame.  If this fails, then
  112.      * we'll just do without it.
  113.      */
  114.     m_pAdv=new CDocumentAdviseSink(m_pFR);
  115.  
  116.     return TRUE;
  117.     }
  118.  
  119.  
  120.  
  121.  
  122.  
  123. /*
  124.  * CClient::CreateDoc (Internal)
  125.  * CClient::CreateCDocument (Virtual)
  126.  *
  127.  * Purpose:
  128.  *  Constructs a new document.  This function is overridable so an
  129.  *  app can use the default CClient but create a derived document
  130.  *  class.
  131.  *
  132.  * Parameters:
  133.  *  None
  134.  *
  135.  * Return Value:
  136.  *  PCDocument      Pointer to the new document object.
  137.  */
  138.  
  139. PCDocument CClient::CreateDoc(void)
  140.     {
  141.     PCDocument  pDoc;
  142.  
  143.     pDoc=CreateCDocument();
  144.     m_pDocLast=pDoc;
  145.  
  146.     return pDoc;
  147.     }
  148.  
  149. PCDocument CClient::CreateCDocument(void)
  150.     {
  151.     return new CDocument(m_hInst, m_pFR, m_pAdv);
  152.     }
  153.  
  154.  
  155.  
  156. /*
  157.  * CClient::Frame
  158.  * CClient::DocumentCount
  159.  * CClient::DocumentList
  160.  *
  161.  * Purpose:
  162.  *  Trivial members to provide public access to various members.
  163.  */
  164.  
  165. PCFrame CClient::Frame(void)
  166.     {
  167.     return m_pFR;
  168.     }
  169.  
  170. UINT CClient::DocumentCount(void)
  171.     {
  172.     return m_cDoc;
  173.     }
  174.  
  175. HWND CClient::DocumentList(void)
  176.     {
  177.     return m_hListDocs;
  178.     }
  179.  
  180.  
  181.  
  182.  
  183. /*
  184.  * CClient::TranslateAccelerator
  185.  *
  186.  * Purpose:
  187.  *  Provides an isolated system accelerator translation as necessary
  188.  *  for the client window.  In MDI this calls TranslateMDISysAccel
  189.  *  but is a NOP in SDI.
  190.  *
  191.  * Parameters:
  192.  *  pMsg            LPMSG to the message from GetMessage
  193.  *
  194.  * Return Value:
  195.  *  BOOL            TRUE if the accelerator was translated and
  196.  *                  processed, FALSE otherwise.
  197.  */
  198.  
  199. BOOL CClient::TranslateAccelerator(LPMSG pMsg)
  200.     {
  201.    #ifdef MDI
  202.     return TranslateMDISysAccel(m_hWnd, pMsg);
  203.    #else
  204.     return FALSE;
  205.    #endif
  206.     }
  207.  
  208.  
  209.  
  210.  
  211.  
  212. /*
  213.  * CClient::DefFrameProc
  214.  *
  215.  * Purpose:
  216.  *  Encapsulates which default message procedure to call for a frame
  217.  *  window: SDI (DefWindowProc) or MDI (DefFrameProc).
  218.  *
  219.  * Parameters:
  220.  *  hWnd            HWND of the frame
  221.  *  iMsg            UINT of the message
  222.  *  wParam          WPARAM of the message
  223.  *  lParam          LPARAM of the message
  224.  *
  225.  * Return Value:
  226.  *  LRESULT         Return value for the message.
  227.  */
  228.  
  229. LRESULT CClient::DefaultFrameProc(HWND hWnd, UINT iMsg, WPARAM wParam
  230.     , LPARAM lParam)
  231.     {
  232.    #ifdef MDI
  233.     return (DefFrameProc(hWnd, m_hWnd, iMsg, wParam, lParam));
  234.    #else
  235.     return (DefWindowProc(hWnd, iMsg, wParam, lParam));
  236.    #endif
  237.     }
  238.  
  239.  
  240.  
  241.  
  242.  
  243. /*
  244.  * CClient::OnWindowCommand
  245.  *
  246.  * Purpose:
  247.  *  Handles Window menu commands for MDI situations.  This is a NOP
  248.  *  in SDI.
  249.  *
  250.  * Parameters:
  251.  *  uCommand        UINT command to execute:
  252.  *                      WM_MDICASCADE
  253.  *                      WM_MDITILE
  254.  *                      WM_MDIICONARRANGE
  255.  *
  256.  *  uOption         UINT optional parameter for WM_MDITILE, either
  257.  *                  MDITILE_HORIZONTAL or MDITILE_VERTICAL.
  258.  *
  259.  * Return Value:
  260.  *  None
  261.  */
  262.  
  263. void CClient::OnWindowCommand(UINT uCommand, UINT uOption)
  264.     {
  265.     SendMessage(m_hWnd, uCommand, (WPARAM)uOption, 0L);
  266.     return;
  267.     }
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274.  
  275. /*
  276.  * CClient::OnSize
  277.  *
  278.  * Purpose:
  279.  *  Handles resizing the client window when the frame is resized.
  280.  *
  281.  * Parameters:
  282.  *  x, y            UINT new location of the window.
  283.  *  cx, cy          UINT new dimensions of the window.
  284.  *
  285.  * Return Value:
  286.  *  None
  287.  */
  288.  
  289. void CClient::OnSize(UINT x, UINT y, UINT cx, UINT cy)
  290.     {
  291.     SetWindowPos(m_hWnd, NULL, x, y, cx, cy
  292.         , SWP_NOZORDER | SWP_NOACTIVATE);
  293.     return;
  294.     }
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301. /*
  302.  * CClient::NewDocument
  303.  *
  304.  * Purpose:
  305.  *  Creates a new blank document in the client space.  See
  306.  *  CloseDocument for the opposite effect.
  307.  *
  308.  * Parameters:
  309.  *  fVisible        BOOL indicating if the document is to be visible
  310.  *                  or not.
  311.  *
  312.  * Return Value:
  313.  *  PCDocument      Pointer to the new document object.
  314.  */
  315.  
  316. PCDocument CClient::NewDocument(BOOL fVisible)
  317.     {
  318.     MDICREATESTRUCT mcs;
  319.     HWND            hWndDoc;
  320.     PCDocument      pDoc, pDocTemp;
  321.     DOCUMENTINIT    di;
  322.     BOOL            fCreate=TRUE;
  323.    #ifdef MDI
  324.     DWORD           dw;
  325.    #endif
  326.  
  327.    #ifdef MDI
  328.     //In MDI we create a new CDocument
  329.     pDoc=CreateDoc();  //This could create a derived class...
  330.    #else
  331.     //In SDI we close the one we have and create a new one.
  332.     pDoc=ActiveDocument();
  333.  
  334.     if (NULL!=pDoc)
  335.         CloseDocument(pDoc);
  336.  
  337.     pDoc=CreateDoc();
  338.    #endif
  339.  
  340.     if (NULL==pDoc)
  341.         return NULL;
  342.  
  343.     if (fCreate)
  344.         {
  345.         /*
  346.          * We implement this by having the client window actually
  347.          * create the windows instead of using the CDocument
  348.          * initializer.  Reason being is that we ask the client to
  349.          * actually create the window using WM_MDICREATE (which works
  350.          * for our SDI client as well. Since we need to conditionally
  351.          * compile for MDI or SDI here, we create a window before
  352.          * calling the document constructor.
  353.          */
  354.  
  355.         mcs.szTitle=TEXT("");
  356.         mcs.szClass=SZCLASSDOCUMENT;
  357.         mcs.hOwner =m_hInst;
  358.         mcs.lParam =(LPARAM)pDoc;
  359.  
  360.         mcs.x =CW_USEDEFAULT;
  361.         mcs.cx=CW_USEDEFAULT;
  362.         mcs.y =CW_USEDEFAULT;
  363.         mcs.cy=CW_USEDEFAULT;
  364.  
  365.         /*
  366.          * Set the style of the window, controlling visiblity.
  367.          * WS_CLIPCHILDREN is important to prevent unnecessary
  368.          * flashing of document contents that we'll usually fill
  369.          * with some editor window.
  370.          */
  371.        #ifdef MDI
  372.         mcs.style=WS_CHILD | WS_SYSMENU | WS_CAPTION
  373.             | WS_CLIPSIBLINGS| WS_THICKFRAME | WS_MINIMIZEBOX
  374.             | WS_MAXIMIZEBOX| WS_CLIPCHILDREN
  375.             | ((fVisible) ? WS_VISIBLE : 0L);
  376.  
  377.         //If the current document is maxmized, maximize this one
  378.        #ifdef WIN32
  379.         pDocTemp=ActiveDocument();
  380.  
  381.         if (NULL!=pDocTemp)
  382.             {
  383.             dw=GetWindowLong(pDocTemp->Window(), GWL_STYLE);
  384.             mcs.style |= (dw & WS_MAXIMIZE);
  385.             }
  386.        #else
  387.         pDocTemp=NULL;
  388.         dw=SendMessage(m_hWnd, WM_MDIGETACTIVE, 0, 0L);
  389.  
  390.         if (HIWORD(dw))
  391.             mcs.style |= WS_MAXIMIZE;
  392.        #endif //WIN32
  393.  
  394.        #else
  395.         mcs.style=WS_CHILD | WS_CLIPCHILDREN
  396.             | ((fVisible) ? WS_VISIBLE : 0L);
  397.        #endif //MDI
  398.  
  399.         //Tell the Client window to create the child
  400.         hWndDoc=(HWND)(UINT)SendMessage(m_hWnd, WM_MDICREATE, 0
  401.             , (LONG)&mcs);
  402.  
  403.  
  404.         di.idsMin=IDS_STANDARDDOCMIN;
  405.         di.idsMax=IDS_STANDARDDOCMAX;
  406.         di.hWndDoc=hWndDoc;
  407.  
  408.         if (!pDoc->Init(&di))
  409.             {
  410.             if (m_pDocLast==pDoc)
  411.                 m_pDocLast=NULL;
  412.  
  413.             SendMessage(m_hWnd, WM_MDIDESTROY, (WPARAM)hWndDoc, 0L);
  414.             delete pDoc;
  415.             return NULL;
  416.             }
  417.         }
  418.  
  419.     m_cDoc++;
  420.  
  421.     /*
  422.      * Add this document to the end of our list.  This list is
  423.      * maintained strictly in the order of creation.
  424.      */
  425.     SendMessage(m_hListDocs, LB_ADDSTRING, 0, (LONG)pDoc);
  426.  
  427.     //Update menus and gizmos for the new document if visible
  428.     if (fVisible)
  429.         m_pFR->UpdateToolbar();
  430.  
  431.     return pDoc;
  432.     }
  433.  
  434.  
  435.  
  436.  
  437.  
  438.  
  439.  
  440. /*
  441.  * CClient::ActiveDocument
  442.  *
  443.  * Purpose:
  444.  *  Returns the active document window (encapsulates WM_MDIGETACTIVE)
  445.  *
  446.  * Parameters:
  447.  *  None
  448.  *
  449.  * Return Value:
  450.  *  PCDocument      Pointer to the active document object.
  451.  */
  452.  
  453. PCDocument CClient::ActiveDocument(void)
  454.     {
  455.     PCDocument  pDoc=NULL;
  456.     HWND        hWnd;
  457.  
  458.     hWnd=(HWND)(UINT)SendMessage(m_hWnd, WM_MDIGETACTIVE, 0, 0L);
  459.  
  460.     if (NULL!=hWnd)
  461.         pDoc=(PCDocument)SendMessage(hWnd, DOCM_PDOCUMENT, 0, 0L);
  462.     else
  463.         pDoc=m_pDocLast;
  464.  
  465.     return pDoc;
  466.     }
  467.  
  468.  
  469.  
  470.  
  471. /*
  472.  * CClient::ShowDocument
  473.  *
  474.  * Purpose:
  475.  *  Shows or hides a document.
  476.  *
  477.  * Parameters:
  478.  *  pDoc            PCDocument to show or hide.
  479.  *  fShow           BOOL indicating whether to show or hide the
  480.  *                  document.
  481.  *
  482.  * Return Value:
  483.  *  BOOL            Previous shown state of the document.
  484.  */
  485.  
  486. BOOL CClient::ShowDocument(PCDocument pDoc, BOOL fShow)
  487.     {
  488.     BOOL        fRet;
  489.  
  490.     if (NULL==pDoc)
  491.         return FALSE;
  492.  
  493.     fRet=IsWindowVisible(pDoc->Window());
  494.  
  495.     ShowWindow(pDoc->Window(), fShow ? SW_SHOW : SW_HIDE);
  496.  
  497.     MDIREFRESHMENU(m_hWnd);     //Macro in book1632.h
  498.     DrawMenuBar(m_pFR->Window());
  499.  
  500.     SendMessage(m_hWnd, WM_MDIACTIVATE, (WPARAM)pDoc->Window(), 0L);
  501.  
  502.     //Update toolbar if we're changing a document's visibility
  503.     if (fShow != fRet)
  504.         m_pFR->UpdateToolbar();
  505.  
  506.     return fRet;
  507.     }
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514. /*
  515.  * CClient::SDIVerify
  516.  *
  517.  * Purpose:
  518.  *  In MDI, this is a NOP, but in SDI checks if the user has dirtied
  519.  *  and wants to save the current document before blasting it away.
  520.  *
  521.  * Parameters:
  522.  *  None
  523.  *
  524.  * Return Value:
  525.  *  BOOL            TRUE if the operation calling us can proceed,
  526.  *                  FALSE to abort the operation.
  527.  */
  528.  
  529. BOOL CClient::SDIVerify(void)
  530.     {
  531.    #ifdef MDI
  532.     return TRUE;
  533.    #else
  534.     PCDocument      pDoc;
  535.  
  536.     pDoc=ActiveDocument();
  537.  
  538.     /*
  539.      * In SDI, we'll erase the current, so verify if we have one
  540.      * before continuing.  If we don't have any document, then we
  541.      * don't have a problem.
  542.      */
  543.  
  544.     if (NULL==pDoc)
  545.         return TRUE;
  546.  
  547.     return FCleanVerify(pDoc);
  548.    #endif
  549.     }
  550.  
  551.  
  552.  
  553.  
  554.  
  555.  
  556. /*
  557.  * CClient::CloseDocument
  558.  *
  559.  * Purpose:
  560.  *  Closes a document created with NewDocument.
  561.  *
  562.  * Parameters:
  563.  *  pDoc            PCDocument of the document to close.
  564.  *
  565.  * Return Value:
  566.  *  UINT            New count of open documents.
  567.  */
  568.  
  569. UINT CClient::CloseDocument(PCDocument pDoc)
  570.     {
  571.     HWND        hWndT;
  572.     UINT        i;
  573.  
  574.     if (NULL==pDoc)
  575.         return m_cDoc;
  576.  
  577.     /*
  578.      * Again, since the client window controlled document creation
  579.      * we destroy the document window here instead of asking the
  580.      * document to do it for us.  Once we're rid of the window then
  581.      * we can use the destructor.
  582.      */
  583.  
  584.     hWndT=pDoc->Window();
  585.  
  586.     //Don't delete unowned windows.
  587.     if (GetParent(hWndT)!=m_hWnd)
  588.         return m_cDoc;
  589.  
  590.     //Remove this document from our list.
  591.     for (i=0; i < m_cDoc; i++)
  592.         {
  593.         PCDocument  pDocTemp;
  594.  
  595.         if (LB_ERR==SendMessage(m_hListDocs, LB_GETTEXT
  596.             , i, (LONG)&pDocTemp))
  597.             continue;
  598.  
  599.         if (pDoc==pDocTemp)
  600.             SendMessage(m_hListDocs, LB_DELETESTRING, i, 0L);
  601.         }
  602.  
  603.     m_cDoc--;
  604.  
  605.     //Update window text.  Maxed MDI windows handled automatically.
  606.    #ifdef MDI
  607.     m_pFR->WindowTitleSet(NULL, TRUE);
  608.    #else
  609.     m_pFR->WindowTitleSet(NULL, FALSE);
  610.    #endif
  611.  
  612.     if (m_pDocLast==pDoc)
  613.         m_pDocLast=NULL;
  614.  
  615.     //Let the document clean up first, then we can nuke the window.
  616.     SendMessage(m_hWnd, WM_MDIDESTROY, (WPARAM)hWndT, 0L);
  617.     delete pDoc;
  618.  
  619.     return m_cDoc;
  620.     }
  621.  
  622.  
  623.  
  624.  
  625.  
  626.  
  627.  
  628. /*
  629.  * CClient::QueryCloseAllDocuments
  630.  *
  631.  * Purpose:
  632.  *  Ask every document window we have in us if we can close them
  633.  *  down.  We use this when exiting the entire application.
  634.  *
  635.  * Parameters:
  636.  *  fClose          BOOL indicating if we should query close on the
  637.  *                  documents or acutally close them.
  638.  *  fSaveChanges    BOOL indicating if we should prompt for saving
  639.  *                  changes before closing.
  640.  *
  641.  * Return Value:
  642.  *  BOOL            TRUE if we can close, FALSE otherwise.
  643.  */
  644.  
  645. BOOL CClient::QueryCloseAllDocuments(BOOL fClose, BOOL fSaveChanges)
  646.     {
  647.     UINT        i;
  648.     UINT        cDoc;
  649.     PCDocument  pDoc;
  650.  
  651.     cDoc=(UINT)SendMessage(m_hListDocs, LB_GETCOUNT, 0, 0L);
  652.  
  653.     for (i=0; i < cDoc; i++)
  654.         {
  655.         if (LB_ERR!=SendMessage(m_hListDocs, LB_GETTEXT, 0
  656.             , (LONG)&pDoc))
  657.             {
  658.             if (fClose)
  659.                 {
  660.                 if (fSaveChanges)
  661.                     {
  662.                     if (!FCleanVerify(pDoc))
  663.                         return FALSE;
  664.                     }
  665.  
  666.                 CloseDocument (pDoc);
  667.                 }
  668.             else
  669.                 {
  670.                 if (!(BOOL)SendMessage(pDoc->Window(), WM_QUERYENDSESSION
  671.                     , 0, 0))
  672.                     return FALSE;
  673.                 }
  674.             }
  675.         }
  676.  
  677.     return TRUE;
  678.     }
  679.  
  680.  
  681.  
  682.  
  683.  
  684.  
  685. /*
  686.  * CClient::FCleanVerify
  687.  *
  688.  * Purpose:
  689.  *  Checks if the document under scrutiny is dirty or not.  If so,
  690.  *  then we ask the user if they want to save it.  If not, then we
  691.  *  just return TRUE.  Note that a hidden document is always considered
  692.  *  clean.
  693.  *
  694.  * Parameters:
  695.  *  pDoc            PCDocument under consideration.
  696.  *
  697.  * Return Value:
  698.  *  BOOL            TRUE if the document is clean, saved, or the user
  699.  *                  doesn't want to save it.  FALSE if the user
  700.  *                  presses Cancel or the document was not saved.
  701.  */
  702.  
  703. BOOL CClient::FCleanVerify(PCDocument pDoc)
  704.     {
  705.     TCHAR           szFile[CCHPATHMAX];
  706.     LPTSTR          psz=szFile;
  707.  
  708.     if (NULL==pDoc)
  709.         return TRUE;
  710.  
  711.     if (!IsWindowVisible(pDoc->Window()))
  712.         return TRUE;
  713.  
  714.     //Nothing to do if we're clean.
  715.     if (!pDoc->FDirtyGet())
  716.         return TRUE;
  717.  
  718.     //Get the filename and send to the frame for asking the question.
  719.     *psz=0;
  720.     pDoc->FilenameGet(psz, CCHPATHMAX);
  721.  
  722.     return m_pFR->AskAndSave(psz);
  723.     }
  724.  
  725.  
  726.  
  727.  
  728.  
  729.  
  730. /*
  731.  * SDIClientWndProc
  732.  *
  733.  * Purpose:
  734.  *  SDI client window class that will create one document for us,
  735.  *  emulating the functions of an MDI client but with only one doc.
  736.  */
  737.  
  738. LRESULT APIENTRY SDIClientWndProc(HWND hWnd, UINT iMsg
  739.     , WPARAM wParam, LPARAM lParam)
  740.     {
  741.     HWND                hWndDoc;
  742.     LPMDICREATESTRUCT   pMCS;
  743.     RECT                rc;
  744.  
  745.     hWndDoc=(HWND)GetWindowLong(hWnd, CLIENTWL_HWNDDOC);
  746.  
  747.     switch (iMsg)
  748.         {
  749.         case WM_CREATE:
  750.             SetWindowLong(hWnd, CLIENTWL_HWNDDOC, 0L);
  751.             break;
  752.  
  753.         case WM_SIZE:
  754.             if (NULL!=hWndDoc)
  755.                 {
  756.                 //Change the document window to match
  757.                 SetWindowPos(hWndDoc, NULL, 0,  0, LOWORD(lParam)
  758.                     , HIWORD(lParam), SWP_NOMOVE | SWP_NOZORDER
  759.                     | SWP_NOACTIVATE);
  760.                 }
  761.             break;
  762.  
  763.  
  764.         case WM_MDICREATE:
  765.             pMCS=(LPMDICREATESTRUCT)lParam;
  766.  
  767.             //We only ate one *visible* document in SDI cases.
  768.             if (NULL!=hWndDoc && (WS_VISIBLE & pMCS->style))
  769.                 return (LONG)(UINT)hWndDoc;
  770.  
  771.             /*
  772.              * For our one visible window, we set this as the active
  773.              * window.  For hidden windows, we return their window
  774.              * handle but don't change the 'active' window we store.
  775.              *
  776.              * Note that we force SDI documents to fill the client
  777.              * area.
  778.              */
  779.  
  780.             GetClientRect(hWnd, &rc);
  781.  
  782.             hWndDoc=CreateWindowEx(WS_EX_NOPARENTNOTIFY
  783.                 , pMCS->szClass, pMCS->szTitle, pMCS->style
  784.                 , rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top
  785.                 , hWnd, (HMENU)ID_DOCUMENT, (HINSTANCE)pMCS->hOwner
  786.                 , pMCS);
  787.  
  788.  
  789.             if (WS_VISIBLE & pMCS->style)
  790.                 {
  791.                 ShowWindow(hWndDoc, SW_SHOW);
  792.                 SetWindowLong(hWnd, CLIENTWL_HWNDDOC
  793.                     , (LONG)(UINT)hWndDoc);
  794.                 }
  795.  
  796.             return (LONG)(UINT)hWndDoc;
  797.  
  798.  
  799.         case WM_MDIACTIVATE:
  800.             /*
  801.              * Make the new window the active one.  The NEWMDIACTIVE
  802.              * macro is wParam in Win16, lParam in Win32.
  803.              */
  804.             SetWindowLong(hWnd, CLIENTWL_HWNDDOC,(LONG)NEWMDIACTIVE);
  805.             break;
  806.  
  807.  
  808.         case WM_MDIGETACTIVE:
  809.             return (LONG)(UINT)hWndDoc;
  810.  
  811.  
  812.         case WM_MDIDESTROY:
  813.             //The only windows we should destroy are children of us.
  814.             if (GetParent((HWND)wParam)==hWnd)
  815.                 {
  816.                 DestroyWindow((HWND)wParam);
  817.  
  818.                 /*
  819.                  * If this is the visible window, clear out the
  820.                  * window word.
  821.                  */
  822.                 if ((HWND)wParam==hWndDoc)
  823.                     SetWindowLong(hWnd, CLIENTWL_HWNDDOC, 0L);
  824.                 }
  825.             break;
  826.  
  827.         default:
  828.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  829.         }
  830.  
  831.     return 0L;
  832.     }
  833.