home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / tutsamp / dcomdraw / guipaper.cpp < prev    next >
C/C++ Source or Header  |  1997-08-30  |  37KB  |  1,303 lines

  1. /*+==========================================================================
  2.   File:      GUIPAPER.CPP
  3.  
  4.   Summary:   Implementation file for the CGuiPaper C++ class. A GuiPaper
  5.              is a C++ object that displays mouse movement as free-form
  6.              drawing in the client area of a designated window (much like
  7.              common scribble sample programs except that COM technology is
  8.              used throughout to construct this functionality). CGuiPaper
  9.              is anchored to the Windows GUI (Graphical User Interface)
  10.              environment--it retains knowledge of window handles and
  11.              device contexts on the local machine. This GuiPaper object
  12.              relies on a virtual paper object for storage of the drawing
  13.              data. This virtual Paper object (a COPaper) is instantiated
  14.              as a COM object in a separate thread-safe out-of-process
  15.              server, DCDSERVE.
  16.  
  17.              For a comprehensive tutorial code tour of GUIPAPER's contents
  18.              and offerings see the tutorial DCOMDRAW.HTM file. For more
  19.              specific technical details on the internal workings see the
  20.              comments dispersed throughout the GUIPAPER source code.
  21.  
  22.   Classes:   CGuiPaper.
  23.  
  24.   Origin:    8-23-97: atrent - Editor inheritance from GUIBALL.CPP in the
  25.              CONCLIEN source. [Revised]
  26.  
  27. ----------------------------------------------------------------------------
  28.   This file is part of the Microsoft COM Tutorial Code Samples.
  29.  
  30.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  31.  
  32.   This source code is intended only as a supplement to Microsoft
  33.   Development Tools and/or on-line documentation.  See these other
  34.   materials for detailed information regarding Microsoft code samples.
  35.  
  36.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  37.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  38.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  39.   PARTICULAR PURPOSE.
  40. ==========================================================================+*/
  41.  
  42. /*--------------------------------------------------------------------------
  43.   We include WINDOWS.H for all Win32 applications.
  44.   We include OLE2.H because we will be calling the COM/OLE Libraries.
  45.   We include OLECTL.H because it has definitions for connectable objects.
  46.   We include COMMDLG.H because we will be using the Open File,
  47.     Choose Color, and potentially other Common dialogs.
  48.   We include TCHAR.H for general Unicode/Ansi prototype of utility
  49.     functions like _tsplitpath, etc.
  50.   We include APPUTIL.H because we will be building this application using
  51.     the convenient Virtual Window and Dialog classes and other
  52.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  53.   We include PAPINT.H and PAPGUIDS.H for the common Paper-related Interface
  54.     class, GUID, and CLSID specifications.
  55.   We include GUIPAPER.H because it has the C++ class used for GUI display
  56.     of the drawing Paper.
  57.   We include SINK.H because it has the C++ class used for the sink that
  58.     receives event notifications from the COPaper object in the server.
  59.   We include DCOMDRAW.H because it has class and resource definitions
  60.     specific to this DCOMDRAW application.
  61. ---------------------------------------------------------------------------*/
  62. #include <windows.h>
  63. #include <ole2.h>
  64. #include <olectl.h>
  65. #include <commdlg.h>
  66. #include <tchar.h>
  67. #include <apputil.h>
  68. #include <papint.h>
  69. #include <papguids.h>
  70. #include "guipaper.h"
  71. #include "sink.h"
  72. #include "dcomdraw.h"
  73.  
  74.  
  75. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  76.   Method:   CGuiPaper::CGuiPaper
  77.  
  78.   Summary:  Constructor.
  79.  
  80.   Args:     void
  81.  
  82.   Returns:  void
  83. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  84. CGuiPaper::CGuiPaper(void)
  85. {
  86.   m_hWnd       = NULL;
  87.   m_hInst      = NULL;
  88.   m_hDC        = NULL;
  89.   m_pISharePaper = NULL;
  90.   m_hPen       = NULL;
  91.   m_nInkWidth  = INK_THIN;
  92.   m_crInkColor = RGB(0,0,0);
  93.   m_bInkSaving = FALSE;
  94.   m_bInking    = FALSE;
  95.   m_bPainting  = FALSE;
  96.   m_OldPos.x   = 0;
  97.   m_OldPos.y   = 0;
  98.   m_pCOPaperSink = NULL;
  99.   m_dwPaperSink = 0;
  100.   m_bDirty     = FALSE;
  101.  
  102.   m_PenCur = PENCUR_OFF | PENCUR_THIN;
  103.   m_hPenCurN = NULL;
  104.   m_hPenCurT = NULL;
  105.   m_hPenCurM = NULL;
  106.   m_hPenCurF = NULL;
  107. }
  108.  
  109.  
  110. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  111.   Method:   CGuiPaper::~CGuiPaper
  112.  
  113.   Summary:  Destructor.
  114.  
  115.   Args:     void
  116.  
  117.   Returns:  void
  118. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  119. CGuiPaper::~CGuiPaper(void)
  120. {
  121.   BOOL bOk = TRUE;
  122.  
  123.   if (m_pISharePaper)
  124.   {
  125.     // Just to make sure, turn off Ink Saving.
  126.     m_bInkSaving = FALSE;
  127.  
  128.     // Make sure we unlock the paper object.
  129.     m_pISharePaper->Lock(FALSE);
  130.  
  131.     // Disconnect all Sinks--currently only one: PaperSink. This officially
  132.     // stops all PaperSink notifications.
  133.     DisconnectPaperSink();
  134.  
  135.     // Delete the Pen object.
  136.     if (m_hPen)
  137.       DeleteObject(m_hPen);
  138.  
  139.     // Release the reference to the PaperSink object.
  140.     RELEASE_INTERFACE(m_pCOPaperSink);
  141.  
  142.     // Release the main interface pointer copy held in CGuiPaper.
  143.     RELEASE_INTERFACE(m_pISharePaper);
  144.   }
  145. }
  146.  
  147.  
  148. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  149.   Method:   CGuiPaper::Init
  150.  
  151.   Summary:  Get CGuiPaper started. Make any subordinate objects, like
  152.             COPaper and CPapFile, and get them started.
  153.  
  154.   Args:     HINSTANCE hInst
  155.               Handle to the application instance.
  156.             HWND hWnd
  157.               Handle of the display window. Part of what makes CGuiPaper
  158.               a GUI kind of thing.
  159.  
  160.   Returns:  BOOL
  161.               TRUE for success; FALSE for fail.
  162. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  163. BOOL CGuiPaper::Init(
  164.        HINSTANCE hInst,
  165.        HWND hWnd)
  166. {
  167.   BOOL bOk = FALSE;
  168.   HRESULT hr;
  169.   BOOL bFirst;
  170.   COPaperSink* pCobSink = NULL;
  171.   HCURSOR hCurPrev;
  172.   HCURSOR hCurWait = LoadCursor(NULL, IDC_WAIT);
  173.  
  174.   if (hInst && hWnd)
  175.   {
  176.     m_hInst = hInst;
  177.     m_hWnd = hWnd;
  178.  
  179.     // Load the pen cursors.
  180.     m_hPenCurN = LoadCursor(m_hInst, TEXT("PenCurN"));
  181.     m_hPenCurT = LoadCursor(m_hInst, TEXT("PenCurT"));
  182.     m_hPenCurM = LoadCursor(m_hInst, TEXT("PenCurM"));
  183.     m_hPenCurF = LoadCursor(m_hInst, TEXT("PenCurF"));
  184.  
  185.     // Get and save our private display Device Context.
  186.     m_hDC = GetDC(m_hWnd);
  187.  
  188.     // Change cursor to the hour glass. Init could take awhile.
  189.     hCurPrev = SetCursor(hCurWait);
  190.  
  191.     // Call COM service to create a COPaper instance. We are not
  192.     // aggregating it so we ask for its ISharePaper interface directly.
  193.     hr = CoCreateInstance(
  194.            CLSID_SharePaper,
  195.            NULL,
  196.            CLSCTX_LOCAL_SERVER,
  197.            IID_ISharePaper,
  198.            (PPVOID)&m_pISharePaper);
  199.     if (SUCCEEDED(hr))
  200.     {
  201.       // Init the COPaper object.
  202.       GetClientRect(hWnd, &m_WinRect);
  203.       hr = m_pISharePaper->InitPaper(&m_WinRect, &bFirst);
  204.       if (SUCCEEDED(hr))
  205.       {
  206.         // Resize this client's window to match what the COPaper
  207.         // object returned for its size.
  208.         ResizeWin(m_WinRect.right, m_WinRect.bottom);
  209.  
  210.         // Create the COPaperSink object to receive COPaper events.
  211.         pCobSink = new COPaperSink(NULL, this);
  212.         if (NULL != pCobSink)
  213.         {
  214.           // Save a pointer to the COPaperSink IUnknown interface.
  215.           // AddRef because of this saved copy.
  216.           m_pCOPaperSink = pCobSink;
  217.           m_pCOPaperSink->AddRef();
  218.         }
  219.         else
  220.           hr = E_OUTOFMEMORY;
  221.       }
  222.  
  223.       bOk = SUCCEEDED(hr);
  224.     }
  225.     else
  226.       HrMsg(hWnd, TEXT(LOCAL_CREATE_ERR_STR), hr);
  227.  
  228.     // Set Cursor back to what it was.
  229.     SetCursor(hCurPrev);
  230.   }
  231.  
  232.   return (bOk);
  233. }
  234.  
  235.  
  236. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  237.   Method:   CGuiPaper::SetPenCur
  238.  
  239.   Summary:  Set the pen cursor.
  240.  
  241.   Args:     USHORT usPenCurNew
  242.               Or'd bits for the pen cursor.
  243.  
  244.   Returns:  HRESULT
  245.               Standard result code. NOERROR for success.
  246. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  247. HRESULT CGuiPaper::SetPenCur(
  248.           USHORT usPenCurNew)
  249. {
  250.   HRESULT hr = E_FAIL;
  251.   USHORT usPenCurW;
  252.  
  253.   usPenCurW = m_PenCur & (PENCUR_THIN | PENCUR_MEDIUM | PENCUR_THICK);
  254.  
  255.   switch (usPenCurNew)
  256.   {
  257.     case PENCUR_OFF:
  258.      hr = (m_PenCur & PENCUR_ON) ? NOERROR : E_FAIL;
  259.      m_PenCur = usPenCurW;
  260.      SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_hPenCurN);
  261.      break;
  262.     case PENCUR_ON:
  263.      hr = (m_PenCur & PENCUR_ON) ? E_FAIL: NOERROR;
  264.      m_PenCur = PENCUR_ON | usPenCurW;
  265.      switch (usPenCurW)
  266.      {
  267.        case PENCUR_THICK:
  268.          SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_hPenCurF);
  269.          break;
  270.        case PENCUR_MEDIUM:
  271.          SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_hPenCurM);
  272.          break;
  273.        case PENCUR_THIN:
  274.        default:
  275.          SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_hPenCurT);
  276.          break;
  277.      }
  278.      break;
  279.     case PENCUR_THICK:
  280.      hr = (usPenCurW & PENCUR_THICK) ? E_FAIL: NOERROR;
  281.      m_PenCur = (m_PenCur & PENCUR_ON);
  282.      m_PenCur |= PENCUR_THICK;
  283.      SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_hPenCurF);
  284.      break;
  285.     case PENCUR_MEDIUM:
  286.      hr = (usPenCurW & PENCUR_MEDIUM) ? E_FAIL: NOERROR;
  287.      m_PenCur = (m_PenCur & PENCUR_ON);
  288.      m_PenCur |= PENCUR_MEDIUM;
  289.      SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_hPenCurM);
  290.      break;
  291.     case PENCUR_THIN:
  292.      hr = (usPenCurW & PENCUR_THIN) ? E_FAIL: NOERROR;
  293.      m_PenCur = (m_PenCur & PENCUR_ON);
  294.      m_PenCur |= PENCUR_THIN;
  295.      SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_hPenCurT);
  296.      break;
  297.     default:
  298.      break;
  299.   }
  300.  
  301.   return hr;
  302. }
  303.  
  304.  
  305. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  306.   Method:   CGuiPaper::Lock
  307.  
  308.   Summary:  Lock the paper object for drawing by this client.
  309.  
  310.   Args:     BOOL bLock
  311.               TRUE => lock the paper. FALSE => unlock the paper.
  312.  
  313.   Returns:  HRESULT
  314.               Standard result code. NOERROR for success.
  315. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  316. HRESULT CGuiPaper::Lock(
  317.           BOOL bLock)
  318. {
  319.   HRESULT hr = NOERROR;
  320.   HMENU hMenu = ::GetMenu(m_hWnd);
  321.  
  322.   if (bLock)
  323.   {
  324.     // If we are not already locked for drawing then do so.
  325.     if (!m_bLocked)
  326.     {
  327.       hr = m_pISharePaper->Lock(TRUE);
  328.       if (SUCCEEDED(hr))
  329.       {
  330.         // Set Main Window Title.
  331.         SetWindowText(m_hWnd, TEXT(MAIN_WINDOW_MASTER_STR));
  332.         // Set the menu check marks.
  333.         ::CheckMenuItem(
  334.             hMenu,
  335.             IDM_DRAW_MASTER,
  336.             MF_BYCOMMAND | MF_CHECKED);
  337.         ::CheckMenuItem(
  338.             hMenu,
  339.             IDM_DRAW_SLAVE,
  340.             MF_BYCOMMAND | MF_UNCHECKED);
  341.         // Set the Pen cursor on.
  342.         SetPenCur(PENCUR_ON);
  343.         m_bLocked = TRUE;
  344.         // We have siezed control of the pen and can now allow ink saving.
  345.         m_bInkSaving = TRUE;
  346.         m_bDirty = TRUE;
  347.       }
  348.       else
  349.       {
  350.         // Set Main Window Title.
  351.         SetWindowText(m_hWnd, TEXT(MAIN_WINDOW_SLAVE_STR));
  352.         // Set the menu check marks.
  353.         ::CheckMenuItem(
  354.             hMenu,
  355.             IDM_DRAW_MASTER,
  356.             MF_BYCOMMAND | MF_UNCHECKED);
  357.         ::CheckMenuItem(
  358.             hMenu,
  359.             IDM_DRAW_SLAVE,
  360.             MF_BYCOMMAND | MF_CHECKED);
  361.         // Set the Pen cursor off.
  362.         SetPenCur(PENCUR_OFF);
  363.       }
  364.     }
  365.   }
  366.   else
  367.   {
  368.     // If we are not already unlocked for drawing then do so.
  369.     if (m_bLocked)
  370.     {
  371.       // AskSave();
  372.       hr = m_pISharePaper->Lock(FALSE);
  373.       if (SUCCEEDED(hr))
  374.       {
  375.         // Set Main Window Title.
  376.         SetWindowText(m_hWnd, TEXT(MAIN_WINDOW_SLAVE_STR));
  377.         // Set the menu check marks.
  378.         ::CheckMenuItem(
  379.             hMenu,
  380.             IDM_DRAW_MASTER,
  381.             MF_BYCOMMAND | MF_UNCHECKED);
  382.         ::CheckMenuItem(
  383.             hMenu,
  384.             IDM_DRAW_SLAVE,
  385.             MF_BYCOMMAND | MF_CHECKED);
  386.         // Set the Pen cursor off.
  387.         SetPenCur(PENCUR_OFF);
  388.         m_bLocked = FALSE;
  389.         m_bInkSaving = FALSE;
  390.         m_bDirty = FALSE;
  391.       }
  392.     }
  393.   }
  394.  
  395.   return hr;
  396. }
  397.  
  398.  
  399. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  400.   Method:   CGuiPaper::Master
  401.  
  402.   Summary:  Return TRUE if this client is the master client that owns
  403.             the drawing paper.
  404.  
  405.   Args:     void.
  406.  
  407.   Returns:  BOOL
  408.               TRUE => This client is master.  FALSE => Not master.
  409. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  410. BOOL CGuiPaper::Master(void)
  411. {
  412.   BOOL bMaster = m_bLocked && m_bInkSaving;
  413.  
  414.   return bMaster;
  415. }
  416.  
  417.  
  418. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  419.   Method:   CGuiPaper::ClearWin
  420.  
  421.   Summary:  Clear display window but don't erase drawn data.
  422.  
  423.   Args:     void.
  424.  
  425.   Returns:  HRESULT
  426.               Standard result code. NOERROR for success.
  427. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  428. HRESULT CGuiPaper::ClearWin(void)
  429. {
  430.   HRESULT hr = E_FAIL;
  431.   RECT  WinRect;
  432.  
  433.   if(!m_bInking)
  434.   {
  435.     // Get our window's client area rectangle.
  436.     GetClientRect(m_hWnd, &WinRect);
  437.  
  438.     // Fill that rectangle with pixels of default white paint.
  439.     FillRect(m_hDC, &WinRect, GETCLASSBRUSH(m_hWnd));
  440.  
  441.     hr = NOERROR;
  442.   }
  443.  
  444.   return hr;
  445. }
  446.  
  447.  
  448. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  449.   Method:   CGuiPaper::ResizeWin
  450.  
  451.   Summary:  Resize display window.
  452.  
  453.   Args:     LONG lWidth
  454.               New window width. Max X coord.
  455.             LONG lHeight
  456.               New window height. Max Y coord.
  457.  
  458.   Returns:  HRESULT
  459.               Standard result code. NOERROR for success.
  460. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  461. HRESULT CGuiPaper::ResizeWin(
  462.                      LONG lWidth,
  463.                      LONG lHeight)
  464. {
  465.   HRESULT hr = NOERROR;
  466.  
  467.   if(!m_bInking)
  468.   {
  469.     SetWindowPos(
  470.       m_hWnd,
  471.       HWND_TOP,
  472.       0,
  473.       0,
  474.       6+lWidth,
  475.       50+lHeight,
  476.       SWP_NOMOVE | SWP_NOZORDER);
  477.   }
  478.  
  479.   return hr;
  480. }
  481.  
  482.  
  483. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  484.   Method:   CGuiPaper::PaintWin
  485.  
  486.   Summary:  Repaints the current drawing in the drawing window.
  487.  
  488.   Args:     void
  489.  
  490.   Returns:  HRESULT
  491.               Standard result code. NOERROR for success.
  492. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  493. HRESULT CGuiPaper::PaintWin(void)
  494. {
  495.   HRESULT hr = E_FAIL;
  496.   COLORREF crInkColorTmp;
  497.   SHORT nInkWidthTmp;
  498.   BOOL bInkSavingTmp;
  499.   LONG i;
  500.   SHORT nInkType;
  501.   SHORT nX;
  502.   SHORT nY;
  503.   SHORT nInkWidth;
  504.   COLORREF crInkColor;
  505.  
  506.   if (m_pISharePaper && !m_bPainting && !m_bInking)
  507.   {
  508.     hr = NOERROR;
  509.     m_bPainting = TRUE;
  510.     // Save and restore ink color and width since redraw otherwise
  511.     // ends up changing these values in CGuiPaper.
  512.     crInkColorTmp = m_crInkColor;
  513.     nInkWidthTmp = m_nInkWidth;
  514.     bInkSavingTmp = m_bInkSaving;
  515.     m_bInkSaving = FALSE;
  516.     for (i = 0; SUCCEEDED(hr); i++)
  517.     {
  518.       hr = m_pISharePaper->GetInk(
  519.              i,
  520.              &nInkType,
  521.              &nX,
  522.              &nY,
  523.              &nInkWidth,
  524.              &crInkColor);
  525.       if (SUCCEEDED(hr))
  526.       {
  527.         switch (nInkType)
  528.         {
  529.           case INKTYPE_START:
  530.             m_nInkWidth = nInkWidth;
  531.             m_crInkColor = crInkColor;
  532.             InkStart(nX, nY);
  533.             break;
  534.           case INKTYPE_DRAW:
  535.             InkDraw(nX, nY);
  536.             break;
  537.           case INKTYPE_STOP:
  538.             InkStop(nX, nY);
  539.             break;
  540.           default:
  541.             break;
  542.         }
  543.       }
  544.     }
  545.     m_nInkWidth = nInkWidthTmp;
  546.     m_crInkColor = crInkColorTmp;
  547.     m_bInkSaving = bInkSavingTmp;
  548.     m_bPainting = FALSE;
  549.     hr = NOERROR;
  550.   }
  551.  
  552.   return hr;
  553. }
  554.  
  555.  
  556. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  557.   Method:   CGuiPaper::Erase
  558.  
  559.   Summary:  Erase content of the drawing paper and clear display window.
  560.  
  561.   Args:     void.
  562.  
  563.   Returns:  HRESULT
  564.               Standard result code. NOERROR for success.
  565. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  566. HRESULT CGuiPaper::Erase(void)
  567. {
  568.   HRESULT hr = E_FAIL;
  569.  
  570.   if (Master())
  571.   {
  572.     if (m_pISharePaper)
  573.       hr = m_pISharePaper->Erase();
  574.     if (SUCCEEDED(hr))
  575.     {
  576.       ClearWin();
  577.       m_bDirty = TRUE;
  578.     }
  579.   }
  580.   else
  581.     ClearWin();
  582.  
  583.   return hr;
  584. }
  585.  
  586.  
  587. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  588.   Method:   CGuiPaper::Resize
  589.  
  590.   Summary:  Resizes current drawing paper rectangle.
  591.  
  592.   Args:     LONG lWidth
  593.               New window width. Max X coord.
  594.             LONG lHeight
  595.               New window height. Max Y coord.
  596.  
  597.   Returns:  HRESULT
  598.               Standard result code. NOERROR for success.
  599. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  600. HRESULT CGuiPaper::Resize(
  601.                      LONG lWidth,
  602.                      LONG lHeight)
  603. {
  604.   HRESULT hr = NOERROR;
  605.  
  606.   if (Master())
  607.   {
  608.     if (m_pISharePaper)
  609.     {
  610.       hr = m_pISharePaper->Resize(lWidth, lHeight);
  611.       if (SUCCEEDED(hr))
  612.         m_bDirty = TRUE;
  613.     }
  614.   }
  615.   else
  616.     ResizeWin(lWidth, lHeight);
  617.  
  618.   if (SUCCEEDED(hr))
  619.   {
  620.     // Store the new window size.
  621.     m_WinRect.right = lWidth;
  622.     m_WinRect.bottom = lHeight;
  623.   }
  624.  
  625.   return hr;
  626. }
  627.  
  628.  
  629. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  630.   Method:   CGuiPaper::InkWidth
  631.  
  632.   Summary:  Changes current ink width and sets the visable pen cursor
  633.             based on the width.
  634.  
  635.   Args:     SHORT nInkWidth
  636.               New ink width in pixels.
  637.  
  638.   Returns:  HRESULT
  639.               Standard result code. NOERROR for success.
  640. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  641. HRESULT CGuiPaper::InkWidth(
  642.                      SHORT nInkWidth)
  643. {
  644.   HRESULT hr = E_FAIL;
  645.  
  646.   switch (nInkWidth)
  647.   {
  648.     case INK_THIN:
  649.       if (!(m_PenCur & (PENCUR_THIN)))
  650.         hr = SetPenCur(PENCUR_THIN);
  651.       break;
  652.     case INK_MEDIUM:
  653.       if (!(m_PenCur & (PENCUR_MEDIUM)))
  654.         hr = SetPenCur(PENCUR_MEDIUM);
  655.       break;
  656.     case INK_THICK:
  657.       if (!(m_PenCur & (PENCUR_THICK)))
  658.         hr = SetPenCur(PENCUR_THICK);
  659.       break;
  660.     default:
  661.       break;
  662.   }
  663.  
  664.   if (SUCCEEDED(hr))
  665.     m_nInkWidth = nInkWidth;
  666.  
  667.   return hr;
  668. }
  669.  
  670.  
  671. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  672.   Method:   CGuiPaper::InkColor
  673.  
  674.   Summary:  Changes current ink color.
  675.  
  676.   Args:     COLORREF crInkColor
  677.               RGB color ref value (eg, RGB(0,0,0) is black).
  678.  
  679.   Returns:  HRESULT
  680.               Standard result code. NOERROR for success.
  681. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  682. HRESULT CGuiPaper::InkColor(
  683.                      COLORREF crInkColor)
  684. {
  685.   m_crInkColor = crInkColor;
  686.  
  687.   return NOERROR;
  688. }
  689.  
  690.  
  691. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  692.   Method:   CGuiPaper::InkStart
  693.  
  694.   Summary:  Starts an ink drawing sequence in the current color.
  695.  
  696.   Args:     SHORT nX,
  697.               X coordinate in window rectangle of start point.
  698.             SHORT nY
  699.               Y coordinate in window rectangle of start point.
  700.  
  701.   Returns:  HRESULT
  702.               Standard result code. NOERROR for success.
  703. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  704. HRESULT CGuiPaper::InkStart(
  705.                      SHORT nX,
  706.                      SHORT nY)
  707. {
  708.   HRESULT hr = E_FAIL;
  709.  
  710.   // Start an ink drawing sequence only if one is not in progress.
  711.   if (!m_bInking)
  712.   {
  713.     // Remember start position.
  714.     m_OldPos.x = nX;
  715.     m_OldPos.y = nY;
  716.  
  717.     // Delete old pen.
  718.     if (m_hPen)
  719.       DeleteObject(m_hPen);
  720.  
  721.     // Create and select the new drawing pen.
  722.     m_hPen = CreatePen(PS_SOLID, m_nInkWidth, m_crInkColor);
  723.     SelectObject(m_hDC, m_hPen);
  724.  
  725.     hr = NOERROR;
  726.  
  727.     // Ask the Paper object to mark the start of the ink drawing
  728.     // sequence in the current ink color.
  729.     if (m_pISharePaper && m_bInkSaving)
  730.     {
  731.       hr = m_pISharePaper->InkStart(
  732.               nX,
  733.               nY,
  734.               m_nInkWidth,
  735.               m_crInkColor);
  736.       // Capture the Mouse.
  737.       SetCapture(m_hWnd);
  738.  
  739.       // We've modified the ink data--it is now "dirty" with
  740.       // respect to the compound file image. Set dirty flag.
  741.       m_bDirty = TRUE;
  742.     }
  743.  
  744.     // Set inking flag to TRUE.
  745.     m_bInking = TRUE;
  746.   }
  747.  
  748.   return hr;
  749. }
  750.  
  751.  
  752. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  753.   Method:   CGuiPaper::InkDraw
  754.  
  755.   Summary:  Draws and saves ink data during the currently active ink
  756.             drawing sequence.
  757.  
  758.   Args:     SHORT nX,
  759.               X coordinate in window rectangle of start point.
  760.             SHORT nY
  761.               Y coordinate in window rectangle of start point.
  762.  
  763.   Returns:  HRESULT
  764.               Standard result code. NOERROR for success.
  765. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  766. HRESULT CGuiPaper::InkDraw(
  767.                      SHORT nX,
  768.                      SHORT nY)
  769. {
  770.   if (m_bInking)
  771.   {
  772.     // Start this ink line at previous old position.
  773.     MoveToEx(m_hDC, m_OldPos.x, m_OldPos.y, NULL);
  774.  
  775.     // Assign new old position and draw the new line.
  776.     LineTo(m_hDC, m_OldPos.x = nX, m_OldPos.y = nY);
  777.  
  778.     // Ask the Paper object to save this data.
  779.     if (m_bInkSaving)
  780.       m_pISharePaper->InkDraw(nX, nY);
  781.   }
  782.  
  783.   return NOERROR;
  784. }
  785.  
  786.  
  787. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  788.   Method:   CGuiPaper::InkStop
  789.  
  790.   Summary:  Stops the currently active ink drawing sequence.
  791.  
  792.   Args:     SHORT nX,
  793.               X coordinate in window rectangle of start point.
  794.             SHORT nY
  795.               Y coordinate in window rectangle of start point.
  796.  
  797.   Returns:  HRESULT
  798.               Standard result code. NOERROR for success.
  799. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  800. HRESULT CGuiPaper::InkStop(
  801.                      SHORT nX,
  802.                      SHORT nY)
  803. {
  804.   if (m_bInking)
  805.   {
  806.     // Start this ink line at previous old position.
  807.     MoveToEx(m_hDC, m_OldPos.x, m_OldPos.y, NULL);
  808.  
  809.     // Draw the last line.
  810.     LineTo(m_hDC, nX, nY);
  811.  
  812.     // Turn off inking.
  813.     m_bInking = FALSE;
  814.  
  815.     // Ask the Paper object to mark the stop of the ink drawing sequence.
  816.     if (m_bInkSaving)
  817.     {
  818.       m_pISharePaper->InkStop(nX, nY);
  819.       // Free the mouse.
  820.       ReleaseCapture();
  821.     }
  822.   }
  823.  
  824.   return NOERROR;
  825. }
  826.  
  827.  
  828. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  829.   Method:   CGuiPaper::GetConnectionPoint
  830.  
  831.   Summary:  Internal private method to obtain a connection point interface.
  832.  
  833.   Args:     REFIID riid
  834.               IID of the requested connection point Interface.
  835.  
  836.   Returns:  IConnectionPoint*
  837.               Requested IConnectionPoint interface pointer. NULL if none.
  838. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  839. IConnectionPoint* CGuiPaper::GetConnectionPoint(
  840.                     REFIID riid)
  841. {
  842.   IConnectionPoint* pConnPoint = NULL;
  843.   IConnectionPointContainer* pConnPointContainer = NULL;
  844.   IConnectionPoint* pConnPt;
  845.   HRESULT hr;
  846.  
  847.   // First query the object for its Connection Point Container. This
  848.   // essentially asks the object in the server if it is connectable.
  849.   hr = m_pISharePaper->QueryInterface(
  850.          IID_IConnectionPointContainer,
  851.          (PPVOID)&pConnPointContainer);
  852.   if SUCCEEDED(hr)
  853.   {
  854.     // Find the requested Connection Point. This AddRef's the
  855.     // returned pointer.
  856.     hr = pConnPointContainer->FindConnectionPoint(riid, &pConnPt);
  857.     if (SUCCEEDED(hr))
  858.       pConnPoint = pConnPt;
  859.  
  860.     RELEASE_INTERFACE(pConnPointContainer);
  861.   }
  862.  
  863.   return pConnPoint;
  864. }
  865.  
  866.  
  867. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  868.   Method:   CGuiPaper::ConnectPaperSink
  869.  
  870.   Summary:  Connect the PaperSink to the server COPaper source.
  871.  
  872.   Args:     void
  873.  
  874.   Returns:  HRESULT
  875.               Standard result code. NOERROR for success.
  876. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  877. HRESULT CGuiPaper::ConnectPaperSink(void)
  878. {
  879.   HRESULT hr = E_FAIL;
  880.   DWORD dwKey;
  881.   IConnectionPoint* pConnPoint;
  882.  
  883.   if (!m_dwPaperSink)
  884.   {
  885.     // Get the Paper Sink connection point.
  886.     pConnPoint = GetConnectionPoint(IID_IPaperSink);
  887.     if (NULL != pConnPoint)
  888.     {
  889.       // Connect the object in the server to the Paper Sink in this client.
  890.       hr = pConnPoint->Advise(m_pCOPaperSink, &dwKey);
  891.       if (SUCCEEDED(hr))
  892.         m_dwPaperSink = dwKey;
  893.  
  894.       RELEASE_INTERFACE(pConnPoint);
  895.     }
  896.   }
  897.  
  898.   return hr;
  899. }
  900.  
  901.  
  902. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  903.   Method:   CGuiPaper::DisconnectPaperSink
  904.  
  905.   Summary:  Disconnect the PaperSink from the server COPaper source.
  906.  
  907.   Args:     void.
  908.  
  909.   Returns:  HRESULT
  910.               Standard result code. NOERROR for success.
  911. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  912. HRESULT CGuiPaper::DisconnectPaperSink(void)
  913. {
  914.   HRESULT hr = E_FAIL;
  915.   IConnectionPoint* pConnPoint;
  916.  
  917.   if (m_dwPaperSink)
  918.   {
  919.     // Get the Paper Sink connection point.
  920.     pConnPoint = GetConnectionPoint(IID_IPaperSink);
  921.     if (NULL != pConnPoint)
  922.     {
  923.       // Disconnect the object in the server from the Paper Sink in
  924.       // this client.
  925.       hr = pConnPoint->Unadvise(m_dwPaperSink);
  926.       if (SUCCEEDED(hr))
  927.         m_dwPaperSink = 0;
  928.  
  929.       RELEASE_INTERFACE(pConnPoint);
  930.     }
  931.   }
  932.  
  933.   return hr;
  934. }
  935.  
  936.  
  937. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  938.   Method:   CGuiPaper::Load
  939.  
  940.   Summary:  Load drawing data from the current compound file (local
  941.             or remote).
  942.  
  943.   Args:     void.
  944.  
  945.   Returns:  HRESULT
  946.               Standard result code. NOERROR for success.
  947. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  948. HRESULT CGuiPaper::Load(void)
  949. {
  950.   HRESULT hr = E_FAIL;
  951.   HCURSOR hCurWait = LoadCursor(NULL, IDC_WAIT);
  952.   HCURSOR hCurPrev;
  953.   RECT WinRect;
  954.  
  955.   if (NULL != m_pISharePaper)
  956.   {
  957.     // Change cursor to the hour glass.
  958.     hCurPrev = SetCursor(hCurWait);
  959.  
  960.     // Ask the COPaper object to load the paper data from its
  961.     // current compound file.
  962.     m_bPainting = TRUE;
  963.     hr = m_pISharePaper->Load(&WinRect);
  964.     m_bPainting = FALSE;
  965.     if (SUCCEEDED(hr))
  966.     {
  967.       if (WinRect.right == m_WinRect.right
  968.           || WinRect.bottom == m_WinRect.bottom)
  969.         PaintWin();
  970.       else
  971.       {
  972.         m_WinRect.right = WinRect.right;
  973.         m_WinRect.bottom = WinRect.bottom;
  974.         hr = ResizeWin(m_WinRect.right, m_WinRect.bottom);
  975.       }
  976.       m_bDirty = FALSE;
  977.     }
  978.  
  979.     // Set Cursor back to what it was.
  980.     SetCursor(hCurPrev);
  981.   }
  982.  
  983.   return hr;
  984. }
  985.  
  986.  
  987. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  988.   Method:   CGuiPaper::LoadLocal
  989.  
  990.   Summary:  Load drawing data from the local DCDSERVE server.
  991.  
  992.   Args:     void.
  993.  
  994.   Returns:  HRESULT
  995.               Standard result code. NOERROR for success.
  996. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  997. HRESULT CGuiPaper::LoadLocal(void)
  998. {
  999.   HRESULT hr;
  1000.   BOOL bFirst;
  1001.  
  1002.   // Make sure we unlock the paper object.
  1003.   Lock(FALSE);
  1004.  
  1005.   // Disconnect all Sinks--currently only one: PaperSink. This
  1006.   // officially stops all PaperSink notifications.
  1007.   hr = DisconnectPaperSink();
  1008.  
  1009.   // Release the main interface pointer copy held in CGuiPaper.
  1010.   // This causes destruction (in the server) of the current
  1011.   // COPaper object.
  1012.   RELEASE_INTERFACE(m_pISharePaper);
  1013.  
  1014.   // Call COM service to create a new COPaper instance. We are
  1015.   // not aggregating it so we ask for its IShare Paper interface
  1016.   // directly.
  1017.   hr = CoCreateInstance(
  1018.          CLSID_SharePaper,
  1019.          NULL,
  1020.          CLSCTX_LOCAL_SERVER,
  1021.          IID_ISharePaper,
  1022.          (PPVOID)&m_pISharePaper);
  1023.   if (SUCCEEDED(hr))
  1024.   {
  1025.     // Init the COPaper object.
  1026.     GetClientRect(m_hWnd, &m_WinRect);
  1027.     hr = m_pISharePaper->InitPaper(&m_WinRect, &bFirst);
  1028.     if (SUCCEEDED(hr))
  1029.     {
  1030.       // Reconnect all Sinks--currently only one: PaperSink.
  1031.       // This restores all PaperSink notifications.
  1032.       hr = ConnectPaperSink();
  1033.       if (SUCCEEDED(hr))
  1034.       {
  1035.         if (bFirst)
  1036.         {
  1037.           // Lock and load.
  1038.           Lock(TRUE);
  1039.           hr = Load();
  1040.         }
  1041.         else
  1042.         {
  1043.           Lock(FALSE);
  1044.           // If this is not first init then resize this client's window
  1045.           // to match what the COPaper object is using for its size.
  1046.           hr = ResizeWin(m_WinRect.right, m_WinRect.bottom);
  1047.           PaintWin();
  1048.         }
  1049.       }
  1050.     }
  1051.   }
  1052.  
  1053.   return hr;
  1054. }
  1055.  
  1056.  
  1057. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1058.   Method:   CGuiPaper::LoadRemote
  1059.  
  1060.   Summary:  Load the shared drawing from a DCDSERVE server on a remote
  1061.             machine that the user specifies by name in a dialog.
  1062.  
  1063.   Args:     void
  1064.  
  1065.   Returns:  HRESULT
  1066.               Standard result code. NOERROR for success.
  1067. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1068. HRESULT CGuiPaper::LoadRemote(void)
  1069. {
  1070.   HRESULT hr = NOERROR;
  1071.   BOOL bFirst;
  1072.   COPaperSink* pCobSink = NULL;
  1073.   HCURSOR hCurPrev;
  1074.   HCURSOR hCurWait = LoadCursor(NULL, IDC_WAIT);
  1075.   COSERVERINFO* pServerInfo = &g_ServerInfo;
  1076.   MULTI_QI qiRes;
  1077.   int iAns;
  1078.   CDlgLoadRemote dlgLoadRemote;
  1079.  
  1080.   // Ask user for the remote machine name. Cancel this whole load if
  1081.   // he cancels the dialog.
  1082.   iAns = dlgLoadRemote.ShowDialog(
  1083.            m_hInst,
  1084.            MAKEINTRESOURCE(IDD_LOAD_REMOTE),
  1085.            m_hWnd);
  1086.   // Ensure a remote machine name was specified by user.
  1087.   if (IDOK == iAns && pServerInfo->pwszName[0])
  1088.   {
  1089.     hr = E_FAIL;
  1090.     // Unload the existing COPaper object.
  1091.     if (m_pISharePaper)
  1092.     {
  1093.       // Ask User if save is desired.
  1094.       AskSave();
  1095.  
  1096.       // Change cursor to the hour glass.
  1097.       hCurPrev = SetCursor(hCurWait);
  1098.  
  1099.       // Clear the window of the previous drawing.
  1100.       ClearWin();
  1101.  
  1102.       // Make sure we unlock the paper object.
  1103.       Lock(FALSE);
  1104.  
  1105.       // Disconnect all Sinks--currently only one: PaperSink. This
  1106.       // officially stops all PaperSink notifications.
  1107.       hr = DisconnectPaperSink();
  1108.  
  1109.       // Release the main interface pointer copy held in CGuiPaper.
  1110.       // This causes destruction (in the server) of the current
  1111.       // COPaper object.
  1112.       RELEASE_INTERFACE(m_pISharePaper);
  1113.     }
  1114.  
  1115.     // Load a new COPaper from the server on a user-specifed remote machine.
  1116.  
  1117.     // Call COM service to create an instance of the remote COPaper
  1118.     // COM object. We are not aggregating this new object (viz, the
  1119.     // NULL parameter), so we ask for its IShareDraw interface directly.
  1120.     qiRes.pIID = &IID_ISharePaper;
  1121.     qiRes.pItf = NULL;
  1122.     qiRes.hr = 0;
  1123.     hr = CoCreateInstanceEx(
  1124.            CLSID_SharePaper,
  1125.            NULL,
  1126.            CLSCTX_REMOTE_SERVER,
  1127.            pServerInfo,
  1128.            1,
  1129.            &qiRes);
  1130.     if (SUCCEEDED(hr))
  1131.     {
  1132.       hr = qiRes.hr;
  1133.       if (SUCCEEDED(hr))
  1134.       {
  1135.         // Grab our copy of the returned interface pointer. An AddRef was
  1136.         // done by CoCreateInstanceEx on this interface pointer.
  1137.         m_pISharePaper = (ISharePaper*)qiRes.pItf;
  1138.  
  1139.         // Init the newly created COPaper object.
  1140.         GetClientRect(m_hWnd, &m_WinRect);
  1141.         hr = m_pISharePaper->InitPaper(&m_WinRect, &bFirst);
  1142.         if (SUCCEEDED(hr))
  1143.         {
  1144.           // Reconnect all Sinks--currently only one: PaperSink.
  1145.           // This restores all PaperSink notifications.
  1146.           hr = ConnectPaperSink();
  1147.           if (SUCCEEDED(hr))
  1148.           {
  1149.             if (bFirst)
  1150.             {
  1151.               // Lock and load.
  1152.               Lock(TRUE);
  1153.               hr = Load();
  1154.             }
  1155.             else
  1156.             {
  1157.               Lock(FALSE);
  1158.               // If this is not first init then resize this client's
  1159.               // window to match what the remote COPaper object is
  1160.               // using for its window size.
  1161.               hr = ResizeWin(m_WinRect.right, m_WinRect.bottom);
  1162.             }
  1163.             PaintWin();
  1164.           }
  1165.         }
  1166.       }
  1167.     }
  1168.  
  1169.     if (FAILED(hr))
  1170.     {
  1171.       HrMsg(m_hWnd, TEXT(REMOTE_CREATE_ERR_STR), hr);
  1172.  
  1173.       // If error with remote load then restore local drawing.
  1174.       hr = LoadLocal();
  1175.     }
  1176.  
  1177.     // Set Cursor back to what it was.
  1178.     SetCursor(hCurPrev);
  1179.   }
  1180.  
  1181.   return hr;
  1182. }
  1183.  
  1184.  
  1185. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1186.   Method:   CGuiPaper::Save
  1187.  
  1188.   Summary:  Calls on COPaper to save the current drawing's paper data in
  1189.             its current compound file.
  1190.  
  1191.   Args:     void.
  1192.  
  1193.   Returns:  HRESULT
  1194.               Standard result code. NOERROR for success.
  1195. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1196. HRESULT CGuiPaper::Save(void)
  1197. {
  1198.   HRESULT hr = E_FAIL;
  1199.   HCURSOR hCurWait = LoadCursor(NULL, IDC_WAIT);
  1200.   HCURSOR hCurPrev;
  1201.  
  1202.   if (NULL != m_pISharePaper)
  1203.   {
  1204.     // Change cursor to the hour glass.
  1205.     hCurPrev = SetCursor(hCurWait);
  1206.  
  1207.     // Ask the COPaper object to save itself to its current compound file.
  1208.     hr = m_pISharePaper->Save();
  1209.     if (SUCCEEDED(hr))
  1210.       m_bDirty = FALSE;
  1211.  
  1212.     // Set Cursor back to what it was.
  1213.     SetCursor(hCurPrev);
  1214.   }
  1215.  
  1216.   return hr;
  1217. }
  1218.  
  1219.  
  1220. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1221.   Method:   CGuiPaper::AskSave
  1222.  
  1223.   Summary:  Checks dirty flag (ie, if current displayed paper data was
  1224.             modified and is out of sync with the paper data stored in a
  1225.             compound file). If dirty, then ask user in simple dialog if he
  1226.             wants to save new data. If he says yes, then save the current
  1227.             paper data into the current compound file.
  1228.  
  1229.   Args:     void.
  1230.  
  1231.   Returns:  INT
  1232.               Value returned from the Win32 MessageBox function.
  1233. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1234. INT CGuiPaper::AskSave(void)
  1235. {
  1236.   int iAns = IDNO;
  1237.   TCHAR szTitle[MAX_STRING_LENGTH];
  1238.   TCHAR szAsk[MAX_STRING_LENGTH];
  1239.   TCHAR szMsg[MAX_PATH + MAX_STRING_LENGTH];
  1240.  
  1241.   // If current data is dirty then ask user if he wants to save it.
  1242.   if (m_bDirty)
  1243.   {
  1244.     if (LoadString(m_hInst, IDS_DRAWING_CHANGED, szTitle, MAX_STRING_LENGTH)
  1245.         && LoadString(m_hInst, IDS_ASK_SAVE, szAsk, MAX_STRING_LENGTH))
  1246.     {
  1247.       lstrcpy(szMsg, TEXT(MAIN_WINDOW_TITLE_STR));
  1248.       lstrcat(szMsg, szAsk);
  1249.       // Display AskSaveDlg to user. Ask if he wants to save.
  1250.       iAns = MessageBox(
  1251.                m_hWnd,
  1252.                szMsg,
  1253.                szTitle,
  1254.                MB_YESNOCANCEL | MB_ICONEXCLAMATION);
  1255.       if (IDYES == iAns)
  1256.       {
  1257.         // Tell COPaper to save itself to its current compound file.
  1258.         Save();
  1259.       }
  1260.     }
  1261.   }
  1262.  
  1263.   return iAns;
  1264. }
  1265.  
  1266.  
  1267. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1268.   Method:   CGuiPaper::PickColor
  1269.  
  1270.   Summary:  Uses the Choose Color common dialog to ask user for new
  1271.             Pen color. Return that new color.
  1272.  
  1273.   Args:     void.
  1274.  
  1275.   Returns:  COLORREF
  1276.               New chosen color.
  1277. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1278. COLORREF CGuiPaper::PickColor(void)
  1279. {
  1280.   COLORREF crNewColor = m_crInkColor;
  1281.   SHORT i;
  1282.  
  1283.   // Init the custom color array with gray colors.
  1284.   for (i=0; i<16; i++)
  1285.     m_acrCustColors[i] = RGB(i*16, i*16, i*16);
  1286.  
  1287.   // Init the Choose Color structure.
  1288.   m_ChooseColor.lStructSize = sizeof(CHOOSECOLOR);
  1289.   m_ChooseColor.hwndOwner = m_hWnd;
  1290.   m_ChooseColor.hInstance = (HWND) m_hInst;
  1291.   m_ChooseColor.rgbResult = m_crInkColor;
  1292.   m_ChooseColor.lpCustColors = (DWORD*) m_acrCustColors;
  1293.   m_ChooseColor.Flags = CC_PREVENTFULLOPEN | CC_RGBINIT;
  1294.   m_ChooseColor.lCustData = 0L;
  1295.   m_ChooseColor.lpfnHook = NULL;
  1296.   m_ChooseColor.lpTemplateName = NULL;
  1297.  
  1298.   if (ChooseColor(&m_ChooseColor))
  1299.     crNewColor = m_ChooseColor.rgbResult;
  1300.  
  1301.   return crNewColor;
  1302. }
  1303.