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 / perdraw / drawpage.cpp < prev    next >
C/C++ Source or Header  |  1997-09-12  |  68KB  |  1,894 lines

  1. /*+==========================================================================
  2.   File:      DRAWPAGE.CPP
  3.  
  4.   Summary:   Implementation file for the CODrawPage COM Object Class (for
  5.              connectable, persistent CODrawPage COM Objects). CODrawPage
  6.              encapsulates into a COM object the behavior of an persistent
  7.              electronic page of white drawing paper. The client can use
  8.              the native IDrawPage interface to draw free-form ink lines on
  9.              a virtual paper surface. No GUI behavior is provided within
  10.              CODrawPage--it only provides the semantics of the virtual
  11.              drawing paper and manages the ink data for the drawing done
  12.              there by clients. CODrawPages are self-persistent in compound
  13.              file storages and can can thus store and load the DrawPage
  14.              data contents to and from an IStorage given by the client
  15.              (using the standard IPersistStorage interface).
  16.  
  17.              CODrawPage offers a main standard IUnknown interface (basic
  18.              COM object features), an implementation of the standard
  19.              IConnectionPointContainer interface (connectable object
  20.              features), an implementation of the standard IPersistStorage
  21.              interface (features for object persistence in compound file
  22.              storages), and an implementation of the custom IDrawPage
  23.              interface (drawing page related features). This multiple
  24.              interface COM Object Class is achieved via the technique of
  25.              nested classes.  The implementation of the various
  26.              interfaces are nested inside of the CODrawPage Class.
  27.  
  28.              For a comprehensive tutorial code tour of this module's
  29.              contents and offerings see the tutorial PERDRAW.HTM file. For
  30.              more specific technical details on the internal workings see
  31.              the comments dispersed throughout the module's source code.
  32.  
  33.   Classes:   CODrawPage.
  34.  
  35.   Functions: none.
  36.  
  37.   Origin:    5-20-97: atrent - Editor-inheritance from PAPER.CPP in
  38.              the STOSERVE Tutorial Code Sample.
  39.  
  40. ----------------------------------------------------------------------------
  41.   This file is part of the Microsoft COM Tutorial Code Samples.
  42.  
  43.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  44.  
  45.   This source code is intended only as a supplement to Microsoft
  46.   Development Tools and/or on-line documentation.  See these other
  47.   materials for detailed information regarding Microsoft code samples.
  48.  
  49.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  50.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  51.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  52.   PARTICULAR PURPOSE.
  53. ==========================================================================+*/
  54.  
  55.  
  56. /*---------------------------------------------------------------------------
  57.   We include WINDOWS.H for all Win32 applications.
  58.   We include OLE2.H because we will be calling the COM/OLE Libraries.
  59.   We include OLECTL.H because it has definitions for connectable objects.
  60.   We include APPUTIL.H because we will be building this application using
  61.     the convenient Virtual Window and Dialog classes and other
  62.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  63.   We include IPAGES.H and PAGEGUID.H for the common DrawPage-related
  64.     Interface classes, GUID, and CLSID specifications.
  65.   We include SERVER.H because it has internal class declarations for
  66.     the server's control object.
  67.   We include CONNECT.H for object class declarations for the various
  68.     connection point and connection COM objects used in PERDRAW.
  69.   We include DRAWPAGE.H because it has the CODrawPage class declarations.
  70. ---------------------------------------------------------------------------*/
  71. #include <windows.h>
  72. #include <ole2.h>
  73. #include <olectl.h>
  74. #include <apputil.h>
  75. #include <ipages.h>
  76. #include <pageguid.h>
  77. #include "server.h"
  78. #include "connect.h"
  79. #include "drawpage.h"
  80.  
  81.  
  82. /*---------------------------------------------------------------------------
  83.   CODrawPage's implementation of its main COM object class including
  84.   Constructor, Destructor, and the QueryInterface, AddRef, and Release
  85.   methods of the principal IUnknown interface.
  86. ---------------------------------------------------------------------------*/
  87.  
  88. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  89.   Method:   CODrawPage::CODrawPage
  90.  
  91.   Summary:  CODrawPage Constructor. Note the member initializers like:
  92.             "m_ImpIDrawPage(this, pUnkOuter)" which is used to pass the
  93.             'this' and pUnkOuter pointers of the constructor function to
  94.             the constructor in the instantiation of the implementation of
  95.             the CImpIDrawPage interface (which is nested inside this
  96.             present CODrawPage Object Class). Same initializer technique
  97.             is used for the other nested interface implementations.
  98.  
  99.   Args:     IUnknown* pUnkOuter,
  100.               Pointer to the the outer IUnknown.  NULL means this COM Object
  101.               is not being Aggregated.  Non-NULL means it is being created
  102.               on behalf of an outside COM object that is reusing it via
  103.               aggregation.
  104.             CServer* pServer)
  105.               Pointer to the server's control object.
  106.  
  107.   Modifies: m_cRefs, m_pUnkOuter, m_pServer.
  108.  
  109.   Returns:  void
  110. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  111. CODrawPage::CODrawPage(
  112.   IUnknown* pUnkOuter,
  113.   CServer* pServer) :
  114.   m_ImpIConnectionPointContainer(this, pUnkOuter),
  115.   m_ImpIPersistStorage(this, pUnkOuter),
  116.   m_ImpIDrawPage(this, pUnkOuter)
  117. {
  118.   UINT i;
  119.  
  120.   // Zero the COM object's reference count.
  121.   m_cRefs = 0;
  122.  
  123.   // No AddRef necessary if non-NULL, as we're nested.
  124.   m_pUnkOuter = pUnkOuter;
  125.  
  126.   // Assign the pointer to the server control object.
  127.   m_pServer = pServer;
  128.  
  129.   // Null all entries in the connection point array.
  130.   for (i=0; i<MAX_CONNECTION_POINTS; i++)
  131.     m_aConnectionPoints[i] = NULL;
  132.  
  133.   // Now initialize the living heart of this virtual DrawPage entity.
  134.   m_crWinColor   = RGB(255,255,255); // White window background color.
  135.   m_crInkColor   = RGB(0,0,0);       // Black ink drawing color.
  136.   m_nInkWidth    = 2;                // 2 pixels wide (thin) for ink.
  137.   m_lInkDataEnd  = 0;                // Current drawing data end.
  138.   m_lInkDataMax  = 0;                // Upper bound to m_lInkDataEnd.
  139.   m_paInkData    = NULL;             // Points to the Ink data array.
  140.   m_ClassID      = CLSID_DrawPage;   // ClassID. Copy w/ overloaded '='.
  141.   m_ClipFmt      = 0;                // Registered clipboard format ID.
  142.   m_StgState     = PERS_UNINIT;      // Persistent Storage State.
  143.   m_bDirty       = TRUE;             // File initially doesn't match RAM.
  144.  
  145.   return;
  146. }
  147.  
  148.  
  149. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  150.   Method:   CODrawPage::~CODrawPage
  151.  
  152.   Summary:  CODrawPage Destructor.
  153.  
  154.   Args:     void
  155.  
  156.   Returns:  void
  157. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  158. CODrawPage::~CODrawPage(void)
  159. {
  160.   UINT i;
  161.   IConnectionPoint* pIConnectionPoint;
  162.  
  163.   // Do final release of the connection point objects.
  164.   for (i=0; i<MAX_CONNECTION_POINTS; i++)
  165.   {
  166.     pIConnectionPoint = m_aConnectionPoints[i];
  167.     RELEASE_INTERFACE(pIConnectionPoint);
  168.   }
  169.  
  170.   return;
  171. }
  172.  
  173.  
  174. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  175.   Method:   CODrawPage::Init
  176.  
  177.   Summary:  CODrawPage initialization method.  Create any necessary arrays,
  178.             structures, and subordinate objects. Rigs for connectivity.
  179.  
  180.   Args:     void
  181.  
  182.   Modifies: m_aConnectionPoints.
  183.  
  184.   Returns:  HRESULT
  185.               Standard result code. NOERROR for success.
  186. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  187. HRESULT CODrawPage::Init(void)
  188. {
  189.   HRESULT hr = NOERROR;
  190.   INKDATA* paInkData;
  191.   COConnectionPoint* pCOConnPt;
  192.  
  193.   // Zero the Properties structure. Init the ink data version.
  194.   memset(&m_DrawProps, 0, sizeof(DRAWPROPS));
  195.   m_DrawProps.lInkDataVersion = INKDATA_VERSION20;
  196.  
  197.   // Register a clipboard format for DrawPages.
  198.   m_ClipFmt = RegisterClipboardFormat(TEXT(SZ_CLIPUSERTYPE));
  199.  
  200.   // Build the initial dynamic array of InkData.
  201.   paInkData = new INKDATA[(LONG) INKDATA_ALLOC_INIT];
  202.   if (NULL != paInkData)
  203.   {
  204.     // Zero the array.
  205.     memset(paInkData, 0, INKDATA_ALLOC_INIT * sizeof(INKDATA));
  206.  
  207.     // Rig this object so that it can use the Ink Data array.
  208.     m_lInkDataMax = INKDATA_ALLOC_INIT;
  209.     m_paInkData = paInkData;
  210.   }
  211.   else
  212.     hr = E_OUTOFMEMORY;
  213.  
  214.   if (SUCCEEDED(hr))
  215.   {
  216.     // Rig this CODrawPage COM object to be connectable. Assign the
  217.     // connection point array. This object's connection points are
  218.     // determined at compile time--it currently has only one connection
  219.     // point: the CONNPOINT_DRAWPAGESINK connection point. Create a
  220.     // connection point object for this and assign it into the array. This
  221.     // array could easily grow to support additional connection points in
  222.     // the future.
  223.  
  224.     // First try creating a new connection point object. Pass 'this' as the
  225.     // pHostObj pointer used by the connection point to pass its AddRef and
  226.     // Release calls back to the host connectable object.
  227.     pCOConnPt = new COConnectionPoint(this);
  228.     if (NULL != pCOConnPt)
  229.     {
  230.       // If creation succeeded then initialize it (including creating
  231.       // its initial dynamic connection array).
  232.       hr = pCOConnPt->Init(IID_IDrawPageSink);
  233.  
  234.       // If the init succeeded then use QueryInterface to obtain the
  235.       // IConnectionPoint interface on the new connection point object.
  236.       // The interface pointer is assigned directly into the
  237.       // connection point array. The QI also does the needed AddRef.
  238.       if (SUCCEEDED(hr))
  239.         hr = pCOConnPt->QueryInterface(
  240.                IID_IConnectionPoint,
  241.                (PPVOID)&m_aConnectionPoints[CONNPOINT_DRAWPAGESINK]);
  242.     }
  243.     else
  244.       hr = E_OUTOFMEMORY;
  245.   }
  246.  
  247.   return hr;
  248. }
  249.  
  250.  
  251. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  252.   Method:   CODrawPage::QueryInterface
  253.  
  254.   Summary:  QueryInterface of the CODrawPage main non-delegating IUnknown
  255.             implementation.
  256.  
  257.   Args:     REFIID riid,
  258.               [in] GUID of the Interface being requested.
  259.             PPVOID ppv)
  260.               [out] Address of the caller's pointer variable that will
  261.               receive the requested interface pointer.
  262.  
  263.   Returns:  HRESULT
  264.               Standard result code. NOERROR for success.
  265. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  266. STDMETHODIMP CODrawPage::QueryInterface(
  267.                REFIID riid,
  268.                PPVOID ppv)
  269. {
  270.   HRESULT hr = E_NOINTERFACE;
  271.  
  272.   *ppv = NULL;
  273.  
  274.   if (IID_IUnknown == riid)
  275.     *ppv = this;
  276.   else if (IID_IConnectionPointContainer == riid)
  277.     *ppv = &m_ImpIConnectionPointContainer;
  278.   else if (IID_IPersistStorage == riid)
  279.     *ppv = &m_ImpIPersistStorage;
  280.   else if (IID_IDrawPage == riid)
  281.     *ppv = &m_ImpIDrawPage;
  282.  
  283.   if (NULL != *ppv)
  284.   {
  285.     // We've handed out a pointer to the interface so obey the COM rules
  286.     // and AddRef the reference count.
  287.     ((LPUNKNOWN)*ppv)->AddRef();
  288.     hr = NOERROR;
  289.   }
  290.  
  291.   return (hr);
  292. }
  293.  
  294.  
  295. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  296.   Method:   CODrawPage::AddRef
  297.  
  298.   Summary:  AddRef of the CODrawPage non-delegating IUnknown implementation.
  299.  
  300.   Args:     void
  301.  
  302.   Modifies: m_cRefs.
  303.  
  304.   Returns:  ULONG
  305.               New value of m_cRefs (COM object's reference count).
  306. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  307. STDMETHODIMP_(ULONG) CODrawPage::AddRef(void)
  308. {
  309.   ULONG cRefs;
  310.  
  311.   cRefs = ++m_cRefs;
  312.  
  313.   return cRefs;
  314. }
  315.  
  316.  
  317. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  318.   Method:   CODrawPage::Release
  319.  
  320.   Summary:  Release of the CODrawPage non-delegating IUnknown implementation.
  321.  
  322.   Args:     void
  323.  
  324.   Modifies: m_cRefs.
  325.  
  326.   Returns:  ULONG
  327.               New value of m_cRefs (COM object's reference count).
  328. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  329. STDMETHODIMP_(ULONG) CODrawPage::Release(void)
  330. {
  331.   ULONG cRefs;
  332.  
  333.   cRefs = --m_cRefs;
  334.  
  335.   if (0 == cRefs)
  336.   {
  337.     // We've reached a zero reference count for this COM object.
  338.     // So we tell the server housing to decrement its global object
  339.     // count so that the server will be unloaded if appropriate.
  340.     if (NULL != m_pServer)
  341.       m_pServer->ObjectsDown();
  342.  
  343.     // We artificially bump the main ref count to prevent reentrancy
  344.     // via the main object destructor.
  345.     m_cRefs++;
  346.     delete this;
  347.   }
  348.  
  349.   return cRefs;
  350. }
  351.  
  352.  
  353. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  354.   Method:   CODrawPage::NotifySinks
  355.  
  356.   Summary:  Internal utility method of this COM object used to fire event
  357.             notification calls to all listening connection sinks in the
  358.             client.
  359.  
  360.   Args:     DRAWPAGE_EVENT DrawPageEvent
  361.               Type of notification event.
  362.             SHORT nX
  363.               X cordinate. Value is 0 unless event needs it.
  364.             SHORT nY
  365.               Y cordinate. Value is 0 unless event needs it.
  366.             SHORT nInkWidth
  367.               Ink Width. Value is 0 unless event needs it.
  368.             SHORT crInkColor
  369.               COLORREF RGB color value. Value is 0 unless event needs it.
  370.  
  371.   Returns:  HRESULT
  372.               Standard result code. NOERROR for success.
  373. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  374. HRESULT CODrawPage::NotifySinks(
  375.        DRAWPAGE_EVENT DrawPageEvent,
  376.        SHORT nX,
  377.        SHORT nY,
  378.        SHORT nInkWidth,
  379.        COLORREF crInkColor)
  380. {
  381.   HRESULT hr = NOERROR;
  382.   IConnectionPoint* pIConnectionPoint;
  383.   IEnumConnections* pIEnum;
  384.   CONNECTDATA ConnData;
  385.  
  386.   // If there was a DrawPage event, broadcast appropriate notifications to
  387.   // all Sinks connected to each connection point.
  388.   if (DRAWPAGE_EVENT_NONE != DrawPageEvent)
  389.   {
  390.     // Here is the section for the DrawPageSink connection point--currently
  391.     // this is the only connection point offered by CODrawPage objects.
  392.     pIConnectionPoint = m_aConnectionPoints[CONNPOINT_DRAWPAGESINK];
  393.     if (NULL != pIConnectionPoint)
  394.     {
  395.       pIConnectionPoint->AddRef();
  396.       hr = pIConnectionPoint->EnumConnections(&pIEnum);
  397.       if (SUCCEEDED(hr))
  398.       {
  399.         // Loop thru the connection point's connections and if the
  400.         // listening connection supports IDrawPageSink (ie, DrawPageSink
  401.         // events) then dispatch the DrawPageEvent event notification to
  402.         // that sink.
  403.         while (NOERROR == pIEnum->Next(1, &ConnData, NULL))
  404.         {
  405.           IDrawPageSink* pIDrawPageSink;
  406.  
  407.           hr = ConnData.pUnk->QueryInterface(
  408.                                 IID_IDrawPageSink,
  409.                                 (PPVOID)&pIDrawPageSink);
  410.           if (SUCCEEDED(hr))
  411.           {
  412.             switch (DrawPageEvent)
  413.             {
  414.               case DRAWPAGE_EVENT_INKDRAW:
  415.                 pIDrawPageSink->InkDraw(nX, nY);
  416.                 break;
  417.               case DRAWPAGE_EVENT_INKSTART:
  418.                 pIDrawPageSink->InkStart(nX, nY, nInkWidth, crInkColor);
  419.                 break;
  420.               case DRAWPAGE_EVENT_INKSTOP:
  421.                 pIDrawPageSink->InkStop(nX, nY);
  422.                 break;
  423.               case DRAWPAGE_EVENT_RESIZED:
  424.                 pIDrawPageSink->Resized(nX, nY);
  425.                 break;
  426.               case DRAWPAGE_EVENT_CLEARED:
  427.                 pIDrawPageSink->Cleared();
  428.                 break;
  429.               case DRAWPAGE_EVENT_LOADED:
  430.                 pIDrawPageSink->Loaded();
  431.                 break;
  432.               case DRAWPAGE_EVENT_SAVED:
  433.                 pIDrawPageSink->Saved();
  434.                 break;
  435.               default:
  436.                 break;
  437.             }
  438.             pIDrawPageSink->Release();
  439.           }
  440.           ConnData.pUnk->Release();
  441.         }
  442.         pIEnum->Release();
  443.       }
  444.       pIConnectionPoint->Release();
  445.     }
  446.   }
  447.  
  448.   return hr;
  449. }
  450.  
  451.  
  452. /*---------------------------------------------------------------------------
  453.   CODrawPage's nested implementation of the COM standard
  454.   IConnectionPointContainer interface including Constructor, Destructor,
  455.   QueryInterface, AddRef, Release, FindConnectionPoint, and
  456.   EnumConnectionPoints.
  457. ---------------------------------------------------------------------------*/
  458.  
  459. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  460.   Method:   CODrawPage::CImpIConnectionPointContainer
  461.               ::CImpIConnectionPointContainer
  462.  
  463.   Summary:  Constructor for the CImpIConnectionPointContainer interface
  464.             instantiation.
  465.  
  466.   Args:     CODrawPage* pCO,
  467.               Back pointer to the parent outer COM object.
  468.             IUnknown* pUnkOuter
  469.               Pointer to the outer Unknown.  For delegation.
  470.  
  471.   Modifies: m_pCO, m_pUnkOuter.
  472.  
  473.   Returns:  void
  474. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  475. CODrawPage::CImpIConnectionPointContainer::CImpIConnectionPointContainer(
  476.   CODrawPage* pCO,
  477.   IUnknown* pUnkOuter)
  478. {
  479.   // Init the interface's object pointer to point to the parent COM object.
  480.   m_pCO = pCO;
  481.  
  482.   // Init the CImpIConnectionPointContainer interface's delegating Unknown
  483.   // pointer.  We use the main Object pointer for IUnknown delegation here
  484.   // if we are not being aggregated.  If we are being aggregated we use
  485.   // the supplied pUnkOuter for IUnknown delegation.  In either case the
  486.   // pointer assignment requires no AddRef because the
  487.   // CImpIConnectionPointContainer lifetime is quaranteed by the lifetime
  488.   // of the parent object in which CImpIConnectionPointContainer is
  489.   // nested.
  490.   if (NULL == pUnkOuter)
  491.     m_pUnkOuter = pCO;
  492.   else
  493.     m_pUnkOuter = pUnkOuter;
  494.  
  495.   return;
  496. }
  497.  
  498.  
  499. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  500.   Method:   CODrawPage::CImpIConnectionPointContainer
  501.               ::~CImpIConnectionPointContainer
  502.  
  503.   Summary:  Destructor for the CImpIConnectionPointContainer interface
  504.             instantiation.
  505.  
  506.   Args:     void
  507.  
  508.   Returns:  void
  509. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  510. CODrawPage::CImpIConnectionPointContainer::~CImpIConnectionPointContainer(void)
  511. {
  512.   return;
  513. }
  514.  
  515.  
  516. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  517.   Method:   CODrawPage::CImpIConnectionPointContainer::QueryInterface
  518.  
  519.   Summary:  The QueryInterface IUnknown member of this interface
  520.             implementation that delegates to m_pUnkOuter, whatever it is.
  521.  
  522.   Args:     REFIID riid,
  523.               [in] GUID of the Interface being requested.
  524.             PPVOID ppv)
  525.               [out] Address of the caller's pointer variable that will
  526.               receive the requested interface pointer.
  527.  
  528.   Returns:  HRESULT
  529.               Standard result code. NOERROR for success.
  530.               Returned by the delegated outer QueryInterface call.
  531. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  532. STDMETHODIMP CODrawPage::CImpIConnectionPointContainer::QueryInterface(
  533.                REFIID riid,
  534.                PPVOID ppv)
  535. {
  536.   // Delegate this call to the outer object's QueryInterface.
  537.   return m_pUnkOuter->QueryInterface(riid, ppv);
  538. }
  539.  
  540.  
  541. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  542.   Method:   CODrawPage::CImpIConnectionPointContainer::AddRef
  543.  
  544.   Summary:  The AddRef IUnknown member of this interface implementation
  545.             that delegates to m_pUnkOuter, whatever it is.
  546.  
  547.   Args:     void
  548.  
  549.   Returns:  ULONG
  550.               Returned by the delegated outer AddRef call.
  551. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  552. STDMETHODIMP_(ULONG) CODrawPage::CImpIConnectionPointContainer::AddRef(void)
  553. {
  554.   // Delegate this call to the outer object's AddRef.
  555.   return m_pUnkOuter->AddRef();
  556. }
  557.  
  558.  
  559. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  560.   Method:   CODrawPage::CImpIConnectionPointContainer::Release
  561.  
  562.   Summary:  The Release IUnknown member of this interface implementation
  563.             that delegates to m_pUnkOuter, whatever it is.
  564.  
  565.   Args:     void
  566.  
  567.   Returns:  ULONG
  568.               Returned by the delegated outer Release call.
  569. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  570. STDMETHODIMP_(ULONG) CODrawPage::CImpIConnectionPointContainer::Release(void)
  571. {
  572.   // Delegate this call to the outer object's Release.
  573.   return m_pUnkOuter->Release();
  574. }
  575.  
  576.  
  577. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  578.   Method:   CODrawPage::CImpIConnectionPointContainer::FindConnectionPoint
  579.  
  580.   Summary:  Given an IID for a connection point sink find and return the
  581.             interface pointer for that connection point sink.
  582.  
  583.   Args:     REFIID riid
  584.               Reference to an IID
  585.             IConnectionPoint** ppConnPt
  586.               Address of the caller's IConnectionPoint interface pointer
  587.               variable that will receive the requested interface pointer.
  588.  
  589.   Returns:  HRESULT
  590.               Standard result code. NOERROR for success.
  591. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  592. STDMETHODIMP CODrawPage::CImpIConnectionPointContainer::FindConnectionPoint(
  593.                REFIID riid,
  594.                IConnectionPoint** ppConnPt)
  595. {
  596.   HRESULT hr = E_NOINTERFACE;
  597.   IConnectionPoint* pIConnPt;
  598.  
  599.   // NULL the output variable.
  600.   *ppConnPt = NULL;
  601.  
  602.   pIConnPt = m_pCO->m_aConnectionPoints[CONNPOINT_DRAWPAGESINK];
  603.   if (NULL != pIConnPt)
  604.   {
  605.     // This connectable CODrawPage object currently has only the DrawPage
  606.     // Sink connection point. If the associated interface is requested,
  607.     // use QI to get the Connection Point interface and perform the needed
  608.     // AddRef.
  609.     if (IID_IDrawPageSink == riid)
  610.       hr = pIConnPt->QueryInterface(
  611.                        IID_IConnectionPoint,
  612.                        (PPVOID)ppConnPt);
  613.   }
  614.  
  615.   return hr;
  616. }
  617.  
  618.  
  619. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  620.   Method:   CODrawPage::CImpIConnectionPointContainer::EnumConnectionPoints
  621.  
  622.   Summary:  Return Enumerator for the connectable object's contained
  623.             connection points.
  624.  
  625.   Args:     IEnumConnectionPoints** ppIEnum
  626.               Address of the caller's Enumerator interface pointer
  627.               variable. An output variable that will receive a pointer to
  628.               the connection point enumerator COM object.
  629.  
  630.   Returns:  HRESULT
  631.               Standard result code. NOERROR for success.
  632. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  633. STDMETHODIMP CODrawPage::CImpIConnectionPointContainer::EnumConnectionPoints(
  634.                        IEnumConnectionPoints** ppIEnum)
  635. {
  636.   HRESULT hr = NOERROR;
  637.   IConnectionPoint* aConnPts[MAX_CONNECTION_POINTS];
  638.   COEnumConnectionPoints* pCOEnum;
  639.   UINT i;
  640.  
  641.   // Zero the output interface pointer.
  642.   *ppIEnum = NULL;
  643.  
  644.   // Make a copy on the stack of the array of connection point
  645.   // interfaces. The copy is used below in the creation of the new
  646.   // Enumerator object.
  647.   for (i=0; i<MAX_CONNECTION_POINTS; i++)
  648.     aConnPts[i] = (IConnectionPoint*)m_pCO->m_aConnectionPoints[i];
  649.  
  650.   // Create a Connection Point enumerator COM object for the connection
  651.   // points offered by this CODrawPage object. Pass 'this' to be used to
  652.   // hook the lifetime of the host object to the life time of this
  653.   // enumerator object.
  654.   pCOEnum = new COEnumConnectionPoints(this);
  655.   if (NULL != pCOEnum)
  656.   {
  657.     // Use the array copy to Init the new Enumerator COM object.
  658.     // Set the initial Enumerator index to 0.
  659.     hr = pCOEnum->Init(MAX_CONNECTION_POINTS, aConnPts, 0);
  660.     if (SUCCEEDED(hr))
  661.     {
  662.       // QueryInterface to return the requested interface pointer.
  663.       // An AddRef will be conveniently done by the QI.
  664.       if (SUCCEEDED(hr))
  665.         hr = pCOEnum->QueryInterface(
  666.                         IID_IEnumConnectionPoints,
  667.                         (PPVOID)ppIEnum);
  668.     }
  669.   }
  670.   else
  671.     hr = E_OUTOFMEMORY;
  672.  
  673.   return hr;
  674. }
  675.  
  676.  
  677. /*---------------------------------------------------------------------------
  678.   CODrawPage's nested implementation of the COM standard IPersistStorage
  679.   interface including Constructor, Destructor, QueryInterface, AddRef,
  680.   Release, GetClassID, IsDirty, InitNew, Load, Save, SaveCompleted, and
  681.   HandsOffStorage.
  682. ---------------------------------------------------------------------------*/
  683.  
  684. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  685.   Method:   CODrawPage::CImpIPersistStorage::CImpIPersistStorage
  686.  
  687.   Summary:  Constructor for the CImpIPersistStorage interface
  688.             implementation.
  689.  
  690.   Args:     CODrawPage* pCO,
  691.               Back pointer to the parent outer object.
  692.             IUnknown* pUnkOuter
  693.               Pointer to the outer Unknown.  For delegation.
  694.  
  695.   Modifies: m_pCO, m_pUnkOuter.
  696.  
  697.   Returns:  void
  698. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  699. CODrawPage::CImpIPersistStorage::CImpIPersistStorage(
  700.   CODrawPage* pCO,
  701.   IUnknown* pUnkOuter)
  702. {
  703.   // Init the interface's object pointer to point to the parent COM object.
  704.   m_pCO = pCO;
  705.  
  706.   // Init the CImpIPersistStorage interface's delegating IUnknown
  707.   // pointer.  We use the main object pointer for IUnknown delegation here
  708.   // if we are not being aggregated.  If we are being aggregated we use
  709.   // the supplied pUnkOuter for IUnknown delegation.  In either case the
  710.   // pointer assignment requires no AddRef because the
  711.   // CImpIPersistStorage lifetime is quaranteed by the lifetime
  712.   // of the parent object in which CImpIPersistStorage is
  713.   // nested.
  714.   if (NULL == pUnkOuter)
  715.     m_pUnkOuter = pCO;
  716.   else
  717.     m_pUnkOuter = pUnkOuter;
  718.  
  719.   return;
  720. }
  721.  
  722.  
  723. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  724.   Method:   CODrawPage::CImpIPersistStorage::~CImpIPersistStorage
  725.  
  726.   Summary:  Destructor for the CImpIPersistStorage interface
  727.             instantiation.
  728.  
  729.   Args:     void
  730.  
  731.   Returns:  void
  732. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  733. CODrawPage::CImpIPersistStorage::~CImpIPersistStorage(void)
  734. {
  735.   // Release the current stream elements and the main storage.
  736.   // This NULLs these interface pointers (via the release macro).
  737.   RELEASE_INTERFACE(m_pIStream_Props);
  738.   RELEASE_INTERFACE(m_pIStream_Data);
  739.   RELEASE_INTERFACE(m_pIStorage);
  740.  
  741.   return;
  742. }
  743.  
  744.  
  745. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  746.   Method:   CODrawPage::CImpIPersistStorage::QueryInterface
  747.  
  748.   Summary:  The QueryInterface IUnknown member of this IDrawPage interface
  749.             implementation that delegates to m_pUnkOuter, whatever it is.
  750.  
  751.   Args:     REFIID riid,
  752.               [in] GUID of the Interface being requested.
  753.             PPVOID ppv)
  754.               [out] Address of the caller's pointer variable that will
  755.               receive the requested interface pointer.
  756.  
  757.   Returns:  HRESULT
  758.               Standard result code. NOERROR for success.
  759.               Returned by the delegated outer QueryInterface call.
  760. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  761. STDMETHODIMP CODrawPage::CImpIPersistStorage::QueryInterface(
  762.                REFIID riid,
  763.                PPVOID ppv)
  764. {
  765.   // Delegate this call to the outer object's QueryInterface.
  766.   return m_pUnkOuter->QueryInterface(riid, ppv);
  767. }
  768.  
  769.  
  770. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  771.   Method:   CODrawPage::CImpIPersistStorage::AddRef
  772.  
  773.   Summary:  The AddRef IUnknown member of this IDrawPage interface
  774.             implementation that delegates to m_pUnkOuter, whatever it is.
  775.  
  776.   Args:     void
  777.  
  778.   Returns:  ULONG
  779.               Returned by the delegated outer AddRef call.
  780. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  781. STDMETHODIMP_(ULONG) CODrawPage::CImpIPersistStorage::AddRef(void)
  782. {
  783.   // Delegate this call to the outer object's AddRef.
  784.   return m_pUnkOuter->AddRef();
  785. }
  786.  
  787.  
  788. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  789.   Method:   CODrawPage::CImpIPersistStorage::Release
  790.  
  791.   Summary:  The Release IUnknown member of this IDrawPage interface
  792.             implementation that delegates to m_pUnkOuter, whatever it is.
  793.  
  794.   Args:     void
  795.  
  796.   Returns:  ULONG
  797.               Returned by the delegated outer Release call.
  798. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  799. STDMETHODIMP_(ULONG) CODrawPage::CImpIPersistStorage::Release(void)
  800. {
  801.   // Delegate this call to the outer object's Release.
  802.   return m_pUnkOuter->Release();
  803. }
  804.  
  805.  
  806. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  807.   Method:   CODrawPage::CImpIPersistStorage::GetClassID
  808.  
  809.   Summary:  A method inherited from IPersist. Get the Class ID of this
  810.             COM object.
  811.  
  812.   Args:     CLSID* pClassID
  813.               [out] Address of variable to hold Class ID.
  814.  
  815.   Returns:  HRESULT
  816.               Standard result code. NOERROR for success.
  817. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  818. STDMETHODIMP CODrawPage::CImpIPersistStorage::GetClassID(
  819.                CLSID* pClassID)
  820. {
  821.   HRESULT hr = E_POINTER;
  822.  
  823.   if (NULL != pClassID)
  824.   {
  825.     // Use overloaded '=' operator to copy the Class ID to caller.
  826.     *pClassID = m_pCO->m_ClassID;
  827.     hr = NOERROR;
  828.   }
  829.  
  830.   return hr;
  831. }
  832.  
  833.  
  834. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  835.   Method:   CODrawPage::CImpIPersistStorage::IsDirty
  836.  
  837.   Summary:  Called to determine if changes were made to this COM object
  838.             since it was last loaded or initialized.
  839.  
  840.   Args:     none.
  841.  
  842.   Returns:  HRESULT
  843.               Standard result code. NOERROR for success.
  844. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  845. STDMETHODIMP CODrawPage::CImpIPersistStorage::IsDirty(
  846.                void)
  847. {
  848.   HRESULT hr;
  849.  
  850.   hr = m_pCO->m_bDirty ? S_OK : S_FALSE;
  851.  
  852.   return hr;
  853. }
  854.  
  855.  
  856. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  857.   Method:   CODrawPage::CImpIPersistStorage::InitNew
  858.  
  859.   Summary:  Called to tell the object that it has been newly created. The
  860.             object has no existing persistent state already stored and
  861.             must create it anew to initialize the object.
  862.  
  863.             InitNew is called INSTEAD of Load when the new object instance
  864.             must be initialized with brand new data rather than with
  865.             persistent data previously saved. Creates and opens all
  866.             storage and stream elements that it needs (including any
  867.             elements that it would need in a low-memory save situation).
  868.             Pre-allocates any stream space that it will need in a later
  869.             save operation.
  870.  
  871.   Args:     IStorage* pIStorage
  872.               Interface of the substorage within which the DrawPage stores
  873.               its persistent state. The object should hold a copy of the
  874.               pStorage reference and any other references it would later
  875.               need in a low-memory save operation.
  876.  
  877.   Returns:  HRESULT
  878.               Standard result code. NOERROR for success.
  879. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  880. STDMETHODIMP CODrawPage::CImpIPersistStorage::InitNew(
  881.                IStorage* pIStorage)
  882. {
  883.   HRESULT hr = E_UNEXPECTED;
  884.   ULONG ulToWrite, ulWritten;
  885.  
  886.   // There is no previous persistent data for this CODrawPage object.
  887.   // Create and init new persistence data for an empty drawing page.
  888.  
  889.   // Return E_UNEXPECTED error if not in the UNINIT state.
  890.   if (PERS_UNINIT == m_pCO->m_StgState)
  891.   {
  892.     if (NULL != pIStorage)
  893.     {
  894.       // Create the Properties stream.
  895.       hr = pIStorage->CreateStream(
  896.              WSZ_DRAWPROPS,
  897.              STGM_CREATE | STGM_DIRECT
  898.                | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  899.              0,
  900.              0,
  901.              &m_pIStream_Props);
  902.       if (SUCCEEDED(hr))
  903.       {
  904.         // Create the Ink Data stream.
  905.         hr = pIStorage->CreateStream(
  906.                 WSZ_DRAWDATA,
  907.                 STGM_CREATE | STGM_DIRECT
  908.                   | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  909.                 0,
  910.                 0,
  911.                 &m_pIStream_Data);
  912.         if (SUCCEEDED(hr))
  913.         {
  914.           // Write the clipboard format and User Type Name info.
  915.           hr = WriteFmtUserTypeStg(
  916.                  pIStorage,
  917.                  m_pCO->m_ClipFmt,
  918.                  TEXT(SZ_CLIPUSERTYPE));
  919.         }
  920.       }
  921.     }
  922.     else
  923.       hr = E_POINTER;
  924.  
  925.     if (SUCCEEDED(hr))
  926.     {
  927.       // Preallocate stream space by writing the DRAWPROPS structure.
  928.       m_pCO->m_DrawProps.lInkArraySize = m_pCO->m_lInkDataEnd+1;
  929.       m_pCO->m_DrawProps.crWinColor = m_pCO->m_crWinColor;
  930.       m_pCO->m_DrawProps.WinRect.right = m_pCO->m_WinRect.right;
  931.       m_pCO->m_DrawProps.WinRect.bottom = m_pCO->m_WinRect.bottom;
  932.       ulToWrite = sizeof(DRAWPROPS);
  933.       hr = m_pIStream_Props->Write(
  934.              &m_pCO->m_DrawProps,
  935.              ulToWrite,
  936.              &ulWritten);
  937.       if (SUCCEEDED(hr) && ulToWrite != ulWritten)
  938.         hr = STG_E_CANTSAVE;
  939.       if (SUCCEEDED(hr))
  940.       {
  941.         // Preallocate stream space by writing the initial Ink Data array.
  942.         ulToWrite = m_pCO->m_DrawProps.lInkArraySize * sizeof(INKDATA);
  943.         hr = m_pIStream_Data->Write(
  944.                m_pCO->m_paInkData,
  945.                ulToWrite,
  946.                &ulWritten);
  947.         if (SUCCEEDED(hr) && ulToWrite != ulWritten)
  948.           hr = STG_E_CANTSAVE;
  949.         if (FAILED(hr))
  950.         {
  951.           // Release ink data stream if error writing.
  952.           m_pIStream_Data->Release();
  953.         }
  954.       }
  955.       else
  956.       {
  957.         // Release property stream if error writing.
  958.         m_pIStream_Props->Release();
  959.       }
  960.  
  961.       if (SUCCEEDED(hr))
  962.       {
  963.         // Keep open storage pointer around for use in later incremental or
  964.         // low-memory calls of Save. AddRef the interface pointer copy.
  965.         m_pIStorage = pIStorage;
  966.         m_pIStorage->AddRef();
  967.  
  968.         // Switch the persistent storage state to the scribble state.
  969.         m_pCO->m_StgState = PERS_SCRIBBLE;
  970.       }
  971.     }
  972.   }
  973.  
  974.   return hr;
  975. }
  976.  
  977.  
  978. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  979.   Method:   CODrawPage::CImpIPersistStorage::Load
  980.  
  981.   Summary:  Load the object's persistent data from the specified storage
  982.             where the persistent data was previously saved in a prior
  983.             object lifetime. During/after Load the object should hold any
  984.             elements it later needs for scribbling or for low-memory
  985.             saves. This includes the pStorage reference. Load is always
  986.             called INSTEAD of InitNew when the object is initialized with
  987.             its previously stored persistent data.
  988.  
  989.   Args:     IStorage* pIStorage
  990.               Interface of the substorage from which the DrawPage loads
  991.               its persistent state. The object should hold on to this
  992.               pIStorage (and all subordinate storage element pointers)
  993.               for later use in incremental or low-memory calls to Save.
  994.  
  995.   Returns:  HRESULT
  996.               Standard result code. NOERROR for success.
  997. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  998. STDMETHODIMP CODrawPage::CImpIPersistStorage::Load(
  999.                IStorage* pIStorage)
  1000. {
  1001.   HRESULT hr = E_UNEXPECTED;
  1002.   ULONG ulToRead, ulReadIn;
  1003.   LONG lNewArraySize;
  1004.   INKDATA* paInkData;
  1005.   DRAWPROPS NewProps;
  1006.  
  1007.   // Return E_UNEXPECTED error if not in the UNINIT state.
  1008.   if (PERS_UNINIT == m_pCO->m_StgState)
  1009.   {
  1010.     if (NULL != pIStorage)
  1011.     {
  1012.       // Open the existing DrawPage properties stream.
  1013.       hr = pIStorage->OpenStream(
  1014.              WSZ_DRAWPROPS,
  1015.              0,
  1016.              STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  1017.              0,
  1018.              &m_pIStream_Props);
  1019.       if (SUCCEEDED(hr))
  1020.       {
  1021.         // Open the existing DrawPage ink data stream.
  1022.         hr = pIStorage->OpenStream(
  1023.                WSZ_DRAWDATA,
  1024.                0,
  1025.                STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  1026.                0,
  1027.                &m_pIStream_Data);
  1028.         if (SUCCEEDED(hr))
  1029.         {
  1030.           // Read the DrawPage properties from the their stream.
  1031.           ulToRead = sizeof(DRAWPROPS);
  1032.           hr = m_pIStream_Props->Read(&NewProps, ulToRead, &ulReadIn);
  1033.           if (SUCCEEDED(hr) && ulToRead != ulReadIn)
  1034.             hr = STG_E_READFAULT;
  1035.           if (SUCCEEDED(hr))
  1036.           {
  1037.             // Read the Ink Data of the drawing from its stream.
  1038.             // Deal with the different versions of ink data format.
  1039.             switch (NewProps.lInkDataVersion)
  1040.             {
  1041.               case INKDATA_VERSION20:
  1042.                 // Allocate an ink data array big enough--add some extra too.
  1043.                 lNewArraySize = NewProps.lInkArraySize + INKDATA_ALLOC;
  1044.                 paInkData = new INKDATA[(LONG) lNewArraySize];
  1045.                 if (NULL != paInkData)
  1046.                 {
  1047.                   // Delete the entire old ink data array.
  1048.                   delete [] m_pCO->m_paInkData;
  1049.  
  1050.                   // Assign the new array.
  1051.                   m_pCO->m_paInkData = paInkData;
  1052.                   m_pCO->m_lInkDataMax = lNewArraySize;
  1053.  
  1054.                   // Now read the complete array of Ink Data.
  1055.                   ulToRead = NewProps.lInkArraySize * sizeof(INKDATA);
  1056.                   hr = m_pIStream_Data->Read(
  1057.                          m_pCO->m_paInkData,
  1058.                          ulToRead,
  1059.                          &ulReadIn);
  1060.                   if (SUCCEEDED(hr) && ulToRead != ulReadIn)
  1061.                     hr = STG_E_READFAULT;
  1062.                   if (SUCCEEDED(hr))
  1063.                   {
  1064.                     // Rig CODrawPage to use the DRAWPROPS info.
  1065.                     m_pCO->m_lInkDataEnd = NewProps.lInkArraySize-1;
  1066.                     m_pCO->m_crWinColor = NewProps.crWinColor;
  1067.                     m_pCO->m_WinRect.right = NewProps.WinRect.right;
  1068.                     m_pCO->m_WinRect.bottom = NewProps.WinRect.bottom;
  1069.  
  1070.                     // Copy the new properties into current properties.
  1071.                     memcpy(
  1072.                       &m_pCO->m_DrawProps,
  1073.                       &NewProps,
  1074.                       sizeof(DRAWPROPS));
  1075.  
  1076.                     // We are loaded and clean (ie, CODrawPage data
  1077.                     // matches file data). Clear dirty flag.
  1078.                     m_pCO->m_bDirty = FALSE;
  1079.                   }
  1080.                   else
  1081.                   {
  1082.                     // Release data stream if error reading.
  1083.                     m_pIStream_Data->Release();
  1084.                   }
  1085.                 }
  1086.                 else
  1087.                   hr = E_OUTOFMEMORY;
  1088.                 break;
  1089.               default:
  1090.                 hr = E_FAIL;  // Bad version.
  1091.                 break;
  1092.             }
  1093.           }
  1094.           else
  1095.           {
  1096.             // Release property stream if error reading.
  1097.             m_pIStream_Props->Release();
  1098.           }
  1099.         }
  1100.       }
  1101.  
  1102.       if (SUCCEEDED(hr))
  1103.       {
  1104.         // Keep open storage pointer around for use in later incremental or
  1105.         // low-memory calls of Save. AddRef the interface pointer copy.
  1106.         m_pIStorage = pIStorage;
  1107.         m_pIStorage->AddRef();
  1108.  
  1109.         // Switch the persistent storage state to the scribble state.
  1110.         m_pCO->m_StgState = PERS_SCRIBBLE;
  1111.       }
  1112.     }
  1113.     else
  1114.       hr = E_POINTER;
  1115.   }
  1116.  
  1117.   // Notify all other connected clients that DrawPage is now loaded.
  1118.   if (SUCCEEDED(hr))
  1119.     m_pCO->NotifySinks(DRAWPAGE_EVENT_LOADED, 0, 0, 0, 0);
  1120.  
  1121.   return hr;
  1122. }
  1123.  
  1124.  
  1125. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1126.   Method:   CODrawPage::CImpIPersistStorage::Save
  1127.  
  1128.   Summary:  Save the object's persistent state data to the currently open
  1129.             storage or to a newly specified storage depending on
  1130.             bSameAsLoad. Regardless of bSameAsLoad, and during/after Save,
  1131.             the object continues to hold its present pointers to opened
  1132.             elements. But the object cannot scribble on its data until the
  1133.             SaveCompleted method is called. Save clears the object's
  1134.             m_bDirty flag.
  1135.  
  1136.             Save must not fail if an out-of-memory condition is
  1137.             encountered. This relies on either InitNew or Load to open and
  1138.             hold pointers to any elements later needed by Save.
  1139.  
  1140.   Args:     IStorage* pIStorage
  1141.               Interface of the substorage into which the DrawPage saves
  1142.               its persistent state. Always non-NULL.
  1143.             BOOL bSameAsLoad
  1144.               TRUE  =>Save to opened storage (ie, the same one previously
  1145.                 passed to Load or InitNew). Saves only items that need
  1146.                 saving in the current storage (which could be all)
  1147.                 without using any extra memory and without opening or
  1148.                 creating any storages or streams.
  1149.               FALSE =>Save to the specified storage as a new storage.
  1150.                 A complete write of all persistent data is done to the
  1151.                 newly specified storage. The object's currently open
  1152.                 storage remains open and unaffected.
  1153.  
  1154.   Returns:  HRESULT
  1155.               Standard result code. NOERROR for success.
  1156. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1157. STDMETHODIMP CODrawPage::CImpIPersistStorage::Save(
  1158.                IStorage* pIStorage,
  1159.                BOOL bSameAsLoad)
  1160. {
  1161.   HRESULT hr = E_UNEXPECTED;
  1162.   IStream* pIStream_Props;
  1163.   IStream* pIStream_Data;
  1164.  
  1165.   // Return E_UNEXPECTED error if not in the Scribble state.
  1166.   if (PERS_SCRIBBLE == m_pCO->m_StgState)
  1167.   {
  1168.     if (bSameAsLoad)
  1169.     {
  1170.       LARGE_INTEGER li;
  1171.  
  1172.       // If SameAsLoad use copies of the existing open stream pointers.
  1173.       pIStream_Props = m_pIStream_Props;
  1174.       pIStream_Data = m_pIStream_Data;
  1175.  
  1176.       // AddRef these copies; they are released below.
  1177.       pIStream_Props->AddRef();
  1178.       pIStream_Data->AddRef();
  1179.  
  1180.       // We're going to do a fresh save to existing open elements.
  1181.       // So recue the stream seek pointers to their start.
  1182.       LISet32(li, 0);
  1183.       pIStream_Props->Seek(li, STREAM_SEEK_SET, NULL);
  1184.       pIStream_Data->Seek(li, STREAM_SEEK_SET, NULL);
  1185.  
  1186.       hr = NOERROR;
  1187.     }
  1188.     else
  1189.     {
  1190.       // If not SameAsLoad (save to a different storage) then return the
  1191.       // E_POINTER error if a NULL pIStroage was passed.
  1192.       if (NULL != pIStorage)
  1193.       {
  1194.         // If we are saving new persistent image of the object to a
  1195.         // different storage then create all the necessary persistent
  1196.         // storage elements.
  1197.  
  1198.         // Create the Properties stream.
  1199.         hr = pIStorage->CreateStream(
  1200.                WSZ_DRAWPROPS,
  1201.                STGM_CREATE | STGM_DIRECT
  1202.                  | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1203.                0,
  1204.                0,
  1205.                &pIStream_Props);
  1206.         if (SUCCEEDED(hr))
  1207.         {
  1208.           // Create the Ink Data stream.
  1209.           hr = pIStorage->CreateStream(
  1210.                   WSZ_DRAWDATA,
  1211.                   STGM_CREATE | STGM_DIRECT
  1212.                     | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1213.                   0,
  1214.                   0,
  1215.                   &pIStream_Data);
  1216.           if (SUCCEEDED(hr))
  1217.           {
  1218.             // Write the clipboard format and User Type Name info.
  1219.             hr = WriteFmtUserTypeStg(
  1220.                    pIStorage,
  1221.                    m_pCO->m_ClipFmt,
  1222.                    TEXT(SZ_CLIPUSERTYPE));
  1223.           }
  1224.         }
  1225.       }
  1226.       else
  1227.         hr = E_POINTER;
  1228.     }
  1229.  
  1230.     // Now perform the saves of the persistent data elements.
  1231.     if (SUCCEEDED(hr))
  1232.     {
  1233.       ULONG ulToWrite, ulWritten;
  1234.  
  1235.       // Save the DrawPage properties in a dedicated stream.
  1236.       m_pCO->m_DrawProps.lInkArraySize = m_pCO->m_lInkDataEnd+1;
  1237.       m_pCO->m_DrawProps.crWinColor = m_pCO->m_crWinColor;
  1238.       m_pCO->m_DrawProps.WinRect.right = m_pCO->m_WinRect.right;
  1239.       m_pCO->m_DrawProps.WinRect.bottom = m_pCO->m_WinRect.bottom;
  1240.       ulToWrite = sizeof(DRAWPROPS);
  1241.       hr = pIStream_Props->Write(&m_pCO->m_DrawProps, ulToWrite, &ulWritten);
  1242.       if (SUCCEEDED(hr) && ulToWrite != ulWritten)
  1243.         hr = STG_E_CANTSAVE;
  1244.       if (SUCCEEDED(hr))
  1245.       {
  1246.         // Save the DrawPage ink data in a dedicated stream.
  1247.         ulToWrite = m_pCO->m_DrawProps.lInkArraySize * sizeof(INKDATA);
  1248.         hr = pIStream_Data->Write(m_pCO->m_paInkData, ulToWrite, &ulWritten);
  1249.         if (SUCCEEDED(hr) && ulToWrite != ulWritten)
  1250.           hr = STG_E_CANTSAVE;
  1251.       }
  1252.  
  1253.       // Release any temporary streams used.
  1254.       pIStream_Props->Release();
  1255.       pIStream_Data->Release();
  1256.  
  1257.       if (SUCCEEDED(hr))
  1258.       {
  1259.         // Since the persistent save is now done for this object the
  1260.         // file matches the object. So set object's dirty flag to FALSE.
  1261.         if (bSameAsLoad)
  1262.           m_pCO->m_bDirty = FALSE;
  1263.  
  1264.         // Switch the persistent storage state to the NoScribble state.
  1265.         // After this Save this object cannot scribble to its persistent
  1266.         // storage again until the client grants this freedom by calling
  1267.         // SaveCompleted which switches this object to the Scribble state.
  1268.         m_pCO->m_StgState = PERS_NOSCRIBBLE;
  1269.       }
  1270.     }
  1271.   }
  1272.  
  1273.   // Notify all other connected clients that DrawPage is now saved.
  1274.   if (SUCCEEDED(hr))
  1275.     m_pCO->NotifySinks(DRAWPAGE_EVENT_SAVED, 0, 0, 0, 0);
  1276.  
  1277.   return hr;
  1278. }
  1279.  
  1280.  
  1281. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1282.   Method:   CODrawPage::CImpIPersistStorage::SaveCompleted
  1283.  
  1284.   Summary:  Called by client to inform this COM object that the client has
  1285.             completed its overall save operations. Restores the object to
  1286.             a state where it is free to write  (ie, scribble) to its
  1287.             persistent data elements.
  1288.  
  1289.   Args:     IStorage* pIStorage
  1290.               Interface of the storage for which the object must release
  1291.               its held interface pointers and reopen its persistent data
  1292.               elements within that specified storage. If NULL then the
  1293.               release/reopen is not needed and the object can once again
  1294.               scribble to its expected elements under the currently open
  1295.               storage.
  1296.  
  1297.   Returns:  HRESULT
  1298.               Standard result code. NOERROR for success.
  1299. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1300. STDMETHODIMP CODrawPage::CImpIPersistStorage::SaveCompleted(
  1301.                IStorage* pIStorage)
  1302. {
  1303.   HRESULT hr = E_UNEXPECTED;
  1304.   IStream* pIStream_Props;
  1305.   IStream* pIStream_Data;
  1306.   BOOL bOk;
  1307.   PERSTGSTATE StgState = m_pCO->m_StgState;
  1308.  
  1309.   // Return E_UNEXPECTED error if storage is NOT in either the
  1310.   // No-scribble or Hands-off state.
  1311.   bOk = (StgState == PERS_NOSCRIBBLE || StgState == PERS_HANDSOFF);
  1312.   if (bOk)
  1313.   {
  1314.     // Return E_UNEXPECTED if in Hands-off state but pIStorage is NULL.
  1315.     if (StgState == PERS_HANDSOFF && NULL == pIStorage)
  1316.       bOk = FALSE;
  1317.     else
  1318.       hr = NOERROR;
  1319.   }
  1320.  
  1321.   if (bOk)
  1322.   {
  1323.     if (NULL != pIStorage)
  1324.     {
  1325.       // If specified storage is non-NULL, release all storage elements
  1326.       // and use the specified pIStorage to re-open those elements.
  1327.       // If pIStorage == NULL then we need do nothing since we already
  1328.       // have all the pointers to storage elements needed for Save.
  1329.  
  1330.       // First ensure we can open the property and data streams
  1331.       hr = pIStorage->OpenStream(
  1332.              WSZ_DRAWPROPS,
  1333.              0,
  1334.              STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1335.              0,
  1336.              &pIStream_Props);
  1337.       if (SUCCEEDED(hr))
  1338.       {
  1339.         hr = pIStorage->OpenStream(
  1340.                WSZ_DRAWDATA,
  1341.                0,
  1342.                STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1343.                0,
  1344.                &pIStream_Data);
  1345.         if (SUCCEEDED(hr))
  1346.         {
  1347.           // Release the current stream elements and the main storage.
  1348.           RELEASE_INTERFACE(m_pIStream_Props);
  1349.           RELEASE_INTERFACE(m_pIStream_Data);
  1350.           RELEASE_INTERFACE(m_pIStorage);
  1351.  
  1352.           // Reassign the storage and stream interface pointers.
  1353.           m_pIStorage = pIStorage;
  1354.           m_pIStorage->AddRef();
  1355.           m_pIStream_Props = pIStream_Props;
  1356.           m_pIStream_Data = pIStream_Data;
  1357.         }
  1358.       }
  1359.     }
  1360.  
  1361.     if (SUCCEEDED(hr))
  1362.     {
  1363.       // Switch the persistent storage state back to the scribble state.
  1364.       m_pCO->m_StgState = PERS_SCRIBBLE;
  1365.  
  1366.       // Since save is completed, no save is needed. So set object's
  1367.       // dirty flag to FALSE.
  1368.       m_pCO->m_bDirty = FALSE;
  1369.     }
  1370.   }
  1371.  
  1372.   return hr;
  1373. }
  1374.  
  1375.  
  1376. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1377.   Method:   CODrawPage::CImpIPersistStorage::HandsOffStorage
  1378.  
  1379.   Summary:  Directs object to release the pointers it holds to all
  1380.             persistent data elements and, until further notice, NOT to
  1381.             write to its persistent data elements. A subsequent call to
  1382.             SaveCompleted restores the object's freedom to write to its
  1383.             persistent data elements.
  1384.  
  1385.   Args:     void
  1386.  
  1387.   Returns:  HRESULT
  1388.               Standard result code. NOERROR for success.
  1389. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1390. STDMETHODIMP CODrawPage::CImpIPersistStorage::HandsOffStorage(
  1391.                void)
  1392. {
  1393.   HRESULT hr = E_UNEXPECTED;
  1394.   PERSTGSTATE StgState = m_pCO->m_StgState;
  1395.  
  1396.   // Return E_UNEXPECTED error if NOT in scribble or no-scribble state.
  1397.   if (StgState == PERS_NOSCRIBBLE || StgState == PERS_SCRIBBLE)
  1398.   {
  1399.     // Release the current stream elements and the main storage.
  1400.     // This NULLs these interface pointers (via the release macro).
  1401.     RELEASE_INTERFACE(m_pIStream_Props);
  1402.     RELEASE_INTERFACE(m_pIStream_Data);
  1403.     RELEASE_INTERFACE(m_pIStorage);
  1404.  
  1405.     // Switch the persistent storage state to the Hands-off state.
  1406.     m_pCO->m_StgState = PERS_HANDSOFF;
  1407.     hr = NOERROR;
  1408.   }
  1409.  
  1410.   return hr;
  1411. }
  1412.  
  1413.  
  1414. /*---------------------------------------------------------------------------
  1415.   CODrawPage's nested implementation of the custom IDrawPage interface
  1416.   including Constructor, Destructor, QueryInterface, AddRef, Release,
  1417.   InkStart, InkDraw, InkStop, Clear, Resize, and Redraw.
  1418. ---------------------------------------------------------------------------*/
  1419.  
  1420. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1421.   Method:   CODrawPage::CImpIDrawPage::CImpIDrawPage
  1422.  
  1423.   Summary:  Constructor for the CImpIDrawPage interface instantiation.
  1424.  
  1425.   Args:     CODrawPage* pCO,
  1426.               Back pointer to the parent outer COM object.
  1427.             IUnknown* pUnkOuter
  1428.               Pointer to the outer Unknown.  For delegation.
  1429.  
  1430.   Modifies: m_pCO, m_pUnkOuter.
  1431.  
  1432.   Returns:  void
  1433. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1434. CODrawPage::CImpIDrawPage::CImpIDrawPage(
  1435.   CODrawPage* pCO,
  1436.   IUnknown* pUnkOuter)
  1437. {
  1438.   // Init the interface's COM object pointer to point to the parent object.
  1439.   m_pCO = pCO;
  1440.  
  1441.   // Init the CImpIDrawPage interface's delegating IUnknown pointer.  We
  1442.   // use the main Object pointer for IUnknown delegation here if we are
  1443.   // not being aggregated.  If we are being aggregated we use the supplied
  1444.   // pUnkOuter for IUnknown delegation.  In either case the pointer
  1445.   // assignment requires no AddRef because the CImpIDrawPage lifetime is
  1446.   // quaranteed by the lifetime of the parent object in which
  1447.   // CImpIDrawPage is nested.
  1448.   if (NULL == pUnkOuter)
  1449.     m_pUnkOuter = pCO;
  1450.   else
  1451.     m_pUnkOuter = pUnkOuter;
  1452.  
  1453.   return;
  1454. }
  1455.  
  1456.  
  1457. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1458.   Method:   CODrawPage::CImpIDrawPage::~CImpIDrawPage
  1459.  
  1460.   Summary:  Destructor for the CImpIDrawPage interface instantiation.
  1461.  
  1462.   Args:     void
  1463.  
  1464.   Returns:  void
  1465. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1466. CODrawPage::CImpIDrawPage::~CImpIDrawPage(void)
  1467. {
  1468.   INKDATA* paInkData;
  1469.  
  1470.   // NULL the pointer first and then delete the entire ink data array.
  1471.   paInkData = m_pCO->m_paInkData;
  1472.   m_pCO->m_paInkData = NULL;
  1473.   if (NULL != paInkData)
  1474.     delete [] paInkData;
  1475.  
  1476.   return;
  1477. }
  1478.  
  1479.  
  1480. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1481.   Method:   CODrawPage::CImpIDrawPage::QueryInterface
  1482.  
  1483.   Summary:  The QueryInterface IUnknown member of this IDrawPage interface
  1484.             implementation that delegates to m_pUnkOuter, whatever it is.
  1485.  
  1486.   Args:     REFIID riid,
  1487.               [in] GUID of the Interface being requested.
  1488.             PPVOID ppv)
  1489.               [out] Address of the caller's pointer variable that will
  1490.               receive the requested interface pointer.
  1491.  
  1492.   Returns:  HRESULT
  1493.               Standard result code. NOERROR for success.
  1494.               Returned by the delegated outer QueryInterface call.
  1495. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1496. STDMETHODIMP CODrawPage::CImpIDrawPage::QueryInterface(
  1497.                REFIID riid,
  1498.                PPVOID ppv)
  1499. {
  1500.   // Delegate this call to the outer object's QueryInterface.
  1501.   return m_pUnkOuter->QueryInterface(riid, ppv);
  1502. }
  1503.  
  1504.  
  1505. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1506.   Method:   CODrawPage::CImpIDrawPage::AddRef
  1507.  
  1508.   Summary:  The AddRef IUnknown member of this IDrawPage interface
  1509.             implementation that delegates to m_pUnkOuter, whatever it is.
  1510.  
  1511.   Args:     void
  1512.  
  1513.   Returns:  ULONG
  1514.               Returned by the delegated outer AddRef call.
  1515. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1516. STDMETHODIMP_(ULONG) CODrawPage::CImpIDrawPage::AddRef(void)
  1517. {
  1518.   // Delegate this call to the outer object's AddRef.
  1519.   return m_pUnkOuter->AddRef();
  1520. }
  1521.  
  1522.  
  1523. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1524.   Method:   CODrawPage::CImpIDrawPage::Release
  1525.  
  1526.   Summary:  The Release IUnknown member of this IDrawPage interface
  1527.             implementation that delegates to m_pUnkOuter, whatever it is.
  1528.  
  1529.   Args:     void
  1530.  
  1531.   Returns:  ULONG
  1532.               Returned by the delegated outer Release call.
  1533. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1534. STDMETHODIMP_(ULONG) CODrawPage::CImpIDrawPage::Release(void)
  1535. {
  1536.   // Delegate this call to the outer object's Release.
  1537.   return m_pUnkOuter->Release();
  1538. }
  1539.  
  1540.  
  1541. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1542.   Method:   CODrawPage::CImpIDrawPage::NextSlot
  1543.  
  1544.   Summary:  An internal private utility member method to increment to the
  1545.             next slot in the dynamic Ink Data array. NextSlot will expand
  1546.             the dynamic array for more entries if needed.
  1547.  
  1548.   Args:     void
  1549.  
  1550.   Modifies: m_lInkDataEnd, m_lInkDataMax, m_paInkData.
  1551.  
  1552.   Returns:  HRESULT
  1553.               Standard result code. NOERROR for success.
  1554. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1555. HRESULT CODrawPage::CImpIDrawPage::NextSlot(
  1556.                                void)
  1557. {
  1558.   HRESULT hr = NOERROR;
  1559.   LONG lInkDataEnd = m_pCO->m_lInkDataEnd + 1;
  1560.   INKDATA* paInkData;
  1561.  
  1562.   if (lInkDataEnd >= m_pCO->m_lInkDataMax)
  1563.   {
  1564.     // No more room in Ink Data array. Allocate new space.
  1565.     paInkData = new INKDATA[(LONG) (m_pCO->m_lInkDataMax + INKDATA_ALLOC)];
  1566.     if (NULL != paInkData)
  1567.     {
  1568.       // Copy the content of the old full array to the new larger array.
  1569.       memcpy(paInkData, m_pCO->m_paInkData, lInkDataEnd * sizeof(INKDATA));
  1570.  
  1571.       // Zero (& mark as empty) the expanded portion of the new array.
  1572.       memset(&paInkData[lInkDataEnd], 0, INKDATA_ALLOC * sizeof(INKDATA));
  1573.  
  1574.       // New larger array is ready--delete the old array.
  1575.       delete [] m_pCO->m_paInkData;
  1576.  
  1577.       // Rig the to use the new larger array.
  1578.       m_pCO->m_paInkData = paInkData;
  1579.  
  1580.       // Calculate the new max index.
  1581.       m_pCO->m_lInkDataMax += INKDATA_ALLOC;
  1582.     }
  1583.     else
  1584.       hr = E_OUTOFMEMORY;
  1585.   }
  1586.  
  1587.   if (SUCCEEDED(hr))
  1588.   {
  1589.     m_pCO->m_lInkDataEnd = lInkDataEnd;
  1590.     // NextSlot always preceeds the addition of new drawing data.
  1591.     // So use this convenient common place to set the dirty flag.
  1592.     m_pCO->m_bDirty = TRUE;
  1593.   }
  1594.  
  1595.   return hr;
  1596. }
  1597.  
  1598.  
  1599. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1600.   Method:   CODrawPage::CImpIDrawPage::InkStart
  1601.  
  1602.   Summary:  The InkStart member method of the IDrawPage interface
  1603.             implementation. Called by outside clients of a CODrawPage
  1604.             object to start an ink drawing sequence (ie, a stroke).
  1605.  
  1606.   Args:     SHORT nX,
  1607.               The X coordinate of the ink point.
  1608.             SHORT nY,
  1609.               The Y coordinate of the ink point.
  1610.             SHORT nInkWidth,
  1611.               The width of the ink in pixels.
  1612.             COLORREF crInkColor);
  1613.               The new ink color--an RGB COLORREF color.
  1614.  
  1615.   Returns:  HRESULT
  1616.               Standard result code. NOERROR for success.
  1617. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1618. STDMETHODIMP CODrawPage::CImpIDrawPage::InkStart(
  1619.                SHORT nX,
  1620.                SHORT nY,
  1621.                SHORT nInkWidth,
  1622.                COLORREF crInkColor)
  1623. {
  1624.   HRESULT hr = E_FAIL;
  1625.  
  1626.   hr = NextSlot();
  1627.   if (SUCCEEDED(hr))
  1628.   {
  1629.     // Add the new item to the Ink Data Array.
  1630.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].nType = INKTYPE_START;
  1631.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].nX = nX;
  1632.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].nY = nY;
  1633.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].nWidth = nInkWidth;
  1634.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].crColor = crInkColor;
  1635.     m_pCO->m_nInkWidth = nInkWidth;
  1636.     m_pCO->m_crInkColor = crInkColor;
  1637.   }
  1638.  
  1639.   return hr;
  1640. }
  1641.  
  1642.  
  1643. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1644.   Method:   CODrawPage::CImpIDrawPage::InkDraw
  1645.  
  1646.   Summary:  The InkDraw member method of the IDrawPage interface
  1647.             implementation. Called by outside clients of a CODrawPage
  1648.             object to "draw" ink data into an inking sequence. Adds
  1649.             ink points to the current stroke.
  1650.  
  1651.   Args:     SHORT nX,
  1652.               The X coordinate of the ink point.
  1653.             SHORT nY,
  1654.               The Y coordinate of the ink point.
  1655.  
  1656.   Returns:  HRESULT
  1657.               Standard result code. NOERROR for success.
  1658. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1659. STDMETHODIMP CODrawPage::CImpIDrawPage::InkDraw(
  1660.                SHORT nX,
  1661.                SHORT nY)
  1662. {
  1663.   HRESULT hr = E_FAIL;
  1664.  
  1665.   hr = NextSlot();
  1666.   if (SUCCEEDED(hr))
  1667.   {
  1668.     // Add the new item to the Ink Data Array.
  1669.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].nType = INKTYPE_DRAW;
  1670.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].nX = nX;
  1671.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].nY = nY;
  1672.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].nWidth = m_pCO->m_nInkWidth;
  1673.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].crColor = m_pCO->m_crInkColor;
  1674.   }
  1675.  
  1676.   return hr;
  1677. }
  1678.  
  1679.  
  1680. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1681.   Method:   CODrawPage::CImpIDrawPage::InkStop
  1682.  
  1683.   Summary:  The InkStop member method of the IDrawPage interface
  1684.             implementation. Called by outside clients of a CODrawPage
  1685.             object to stop the current ink drawing sequence. Ends the
  1686.             current stroke.
  1687.  
  1688.   Args:     SHORT nX,
  1689.               The X coordinate of the ink point.
  1690.             SHORT nY,
  1691.               The Y coordinate of the ink point.
  1692.  
  1693.   Returns:  HRESULT
  1694.               Standard result code. NOERROR for success.
  1695. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1696. STDMETHODIMP CODrawPage::CImpIDrawPage::InkStop(
  1697.                SHORT nX,
  1698.                SHORT nY)
  1699. {
  1700.   HRESULT hr = E_FAIL;
  1701.  
  1702.   hr = NextSlot();
  1703.   if (SUCCEEDED(hr))
  1704.   {
  1705.     // Add the new item to the Ink Data Array.
  1706.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].nType = INKTYPE_STOP;
  1707.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].nX = nX;
  1708.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].nY = nY;
  1709.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].nWidth = m_pCO->m_nInkWidth;
  1710.     m_pCO->m_paInkData[m_pCO->m_lInkDataEnd].crColor = m_pCO->m_crInkColor;
  1711.   }
  1712.  
  1713.   return hr;
  1714. }
  1715.  
  1716.  
  1717. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1718.   Method:   CODrawPage::CImpIDrawPage::Clear
  1719.  
  1720.   Summary:  The Clear member method of the IDrawPage interface
  1721.             implementation. Called by outside clients of a CODrawPage
  1722.             object to clear the drawn ink content of the DrawPage object.
  1723.             Notifies all connected clients of the event.
  1724.  
  1725.   Args:     BOOL bSaveNeeded
  1726.               Specifies whether the cleared draw page should later be
  1727.               saved to file. TRUE=>later save needed; FALSE=>later save
  1728.               not needed.
  1729.  
  1730.   Returns:  HRESULT
  1731.               Standard result code. NOERROR for success.
  1732. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1733. STDMETHODIMP CODrawPage::CImpIDrawPage::Clear(
  1734.                BOOL bSaveNeeded)
  1735. {
  1736.   HRESULT hr = NOERROR;
  1737.   LONG i;
  1738.  
  1739.   if (m_pCO->m_lInkDataEnd > 0 && NULL != m_pCO->m_paInkData)
  1740.   {
  1741.     // Loop thru the current Ink Data array and mark each
  1742.     // item as erased.
  1743.     for (i=0; i<m_pCO->m_lInkDataMax; i++)
  1744.       m_pCO->m_paInkData[i].nType = INKTYPE_NONE;
  1745.  
  1746.     // Reset the Ink Data End index to 0.
  1747.     m_pCO->m_lInkDataEnd = 0;
  1748.   }
  1749.  
  1750.   // Specify if a later save to file is needed.
  1751.   m_pCO->m_bDirty = bSaveNeeded;
  1752.  
  1753.   // Notify all other connected clients of the clear.
  1754.   if (SUCCEEDED(hr))
  1755.     m_pCO->NotifySinks(DRAWPAGE_EVENT_CLEARED, 0, 0, 0, 0);
  1756.  
  1757.   return hr;
  1758. }
  1759.  
  1760.  
  1761. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1762.   Method:   CODrawPage::CImpIDrawPage::Resize
  1763.  
  1764.   Summary:  The Resize member method of the IDrawPage interface
  1765.             implementation. Called by outside clients of a CODrawPage
  1766.             object to resize the drawing rectangle of the DrawPage object.
  1767.             Notifies all connected clients of the event and passes them
  1768.             the new rectangle size.
  1769.  
  1770.   Args:     SHORT nWidth,
  1771.               The new rectangle width in pixels.
  1772.             SHORT nHeight
  1773.               The new rectangle height in pixels.
  1774.  
  1775.   Returns:  HRESULT
  1776.               Standard result code. NOERROR for success.
  1777. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1778. STDMETHODIMP CODrawPage::CImpIDrawPage::Resize(
  1779.                SHORT nWidth,
  1780.                SHORT nHeight)
  1781. {
  1782.   HRESULT hr = NOERROR;
  1783.  
  1784.   if (m_pCO->m_WinRect.right != nWidth
  1785.       || m_pCO->m_WinRect.bottom != nHeight)
  1786.   {
  1787.     m_pCO->m_WinRect.top = 0;
  1788.     m_pCO->m_WinRect.left = 0;
  1789.     m_pCO->m_WinRect.right = nWidth;
  1790.     m_pCO->m_WinRect.bottom = nHeight;
  1791.  
  1792.     // For future evolution.
  1793.     // m_pCO->m_bDirty = TRUE;
  1794.   }
  1795.  
  1796.   // Notify all other connected clients of the Resize.
  1797.   m_pCO->NotifySinks(
  1798.            DRAWPAGE_EVENT_RESIZED,
  1799.            nWidth,
  1800.            nHeight,
  1801.            0,
  1802.            0);
  1803.  
  1804.   return hr;
  1805. }
  1806.  
  1807.  
  1808. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1809.   Method:   CODrawPage::CImpIDrawPage::Redraw
  1810.  
  1811.   Summary:  The Redraw member method of the IDrawPage interface
  1812.             implementation. Called by outside clients of a CODrawPage
  1813.             object to resend all of the DrawPage object's current ink data
  1814.             to all connected clients for a redraw of the content in each.
  1815.  
  1816.   Args:     void
  1817.  
  1818.   Returns:  HRESULT
  1819.               Standard result code. NOERROR for success.
  1820. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1821. STDMETHODIMP CODrawPage::CImpIDrawPage::Redraw(
  1822.                void)
  1823. {
  1824.   HRESULT hr = E_FAIL;
  1825.   IConnectionPoint* pIConnectionPoint;
  1826.   IEnumConnections* pIEnum;
  1827.   CONNECTDATA ConnData;
  1828.   SHORT nInkType;
  1829.   LONG i;
  1830.  
  1831.   // Broadcast InkData notifications to all Sinks connected to
  1832.   // each connection point.
  1833.  
  1834.   // Here is the section for the DrawPageSink connection point--currently
  1835.   // this is the only connection point offered by CODrawPage objects.
  1836.   pIConnectionPoint = m_pCO->m_aConnectionPoints[CONNPOINT_DRAWPAGESINK];
  1837.   if (NULL != pIConnectionPoint)
  1838.   {
  1839.     pIConnectionPoint->AddRef();
  1840.     hr = pIConnectionPoint->EnumConnections(&pIEnum);
  1841.     if (SUCCEEDED(hr))
  1842.     {
  1843.       // Loop thru the connection point's connections and if the
  1844.       // listening connection supports IDrawPageSink (ie, DrawPageSink
  1845.       // events) then send all the current DrawPage's Ink Data to it.
  1846.       while (NOERROR == pIEnum->Next(1, &ConnData, NULL))
  1847.       {
  1848.         IDrawPageSink* pIDrawPageSink = NULL;
  1849.  
  1850.         hr = ConnData.pUnk->QueryInterface(
  1851.                               IID_IDrawPageSink,
  1852.                               (PPVOID)&pIDrawPageSink);
  1853.         if (SUCCEEDED(hr))
  1854.         {
  1855.           // Loop thru all the Ink Data and send it to this connected
  1856.           // client sink.
  1857.           for (i=0; i<m_pCO->m_lInkDataEnd+1; i++)
  1858.           {
  1859.             nInkType = m_pCO->m_paInkData[i].nType;
  1860.             switch (nInkType)
  1861.             {
  1862.               case INKTYPE_DRAW:
  1863.                 pIDrawPageSink->InkDraw(
  1864.                                   m_pCO->m_paInkData[i].nX,
  1865.                                   m_pCO->m_paInkData[i].nY);
  1866.                 break;
  1867.               case INKTYPE_START:
  1868.                 pIDrawPageSink->InkStart(
  1869.                                   m_pCO->m_paInkData[i].nX,
  1870.                                   m_pCO->m_paInkData[i].nY,
  1871.                                   m_pCO->m_paInkData[i].nWidth,
  1872.                                   m_pCO->m_paInkData[i].crColor);
  1873.                 break;
  1874.               case INKTYPE_STOP:
  1875.                 pIDrawPageSink->InkStop(
  1876.                                   m_pCO->m_paInkData[i].nX,
  1877.                                   m_pCO->m_paInkData[i].nY);
  1878.                 break;
  1879.               default:
  1880.                 break;
  1881.             }
  1882.           }
  1883.           pIDrawPageSink->Release();
  1884.         }
  1885.         ConnData.pUnk->Release();
  1886.       }
  1887.       pIEnum->Release();
  1888.     }
  1889.     pIConnectionPoint->Release();
  1890.   }
  1891.  
  1892.   return hr;
  1893. }
  1894.