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 / pertext / textpage.cpp < prev    next >
C/C++ Source or Header  |  1997-08-05  |  47KB  |  1,355 lines

  1. /*+==========================================================================
  2.   File:      TEXTPAGE.CPP
  3.  
  4.   Summary:   Implementation file for the COTextPage COM Object Class (for
  5.              connectable COTextPage COM Objects). COTextPage encapsulates
  6.              into a COM object the behavior of a page of editable text.
  7.              The client can use the native ITextPage interface to get and
  8.              put the text of the text page into the object. No GUI
  9.              behavior is provided within COTextPage--it only provides a
  10.              persistent data management for the text page.
  11.  
  12.              Connectable object technology is used in COTextPage to notify
  13.              connected clients of various events like when a load of new
  14.              text data is completed.
  15.  
  16.              COTextPage offers a main standard IUnknown interface (basic
  17.              COM object features), the standard IConnectionPointContainer
  18.              interface (connectable COM object features), the standard
  19.              IPersistStreamInit (Stream persistent object features), and
  20.              the custom ITextPage interface (TextPage related features).
  21.              This multiple interface COM Object Class is achieved via the
  22.              technique of nested classes.  The implementations of the
  23.              various interfaces are nested inside the COTextPage Class.
  24.  
  25.              For a comprehensive tutorial code tour of this module's
  26.              contents and offerings see the tutorial PERTEXT.HTM
  27.              file. For more specific technical details on the internal
  28.              workings see the comments dispersed throughout the module's
  29.              source code.
  30.  
  31.   Classes:   COTextPage.
  32.  
  33.   Functions: none.
  34.  
  35.   Origin:    5-18-97: atrent - Editor-inheritance from PAPER.CPP in
  36.              the STOSERVE Tutorial Code Sample.
  37.  
  38. ----------------------------------------------------------------------------
  39.   This file is part of the Microsoft COM Tutorial Code Samples.
  40.  
  41.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  42.  
  43.   This source code is intended only as a supplement to Microsoft
  44.   Development Tools and/or on-line documentation.  See these other
  45.   materials for detailed information regarding Microsoft code samples.
  46.  
  47.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  48.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  49.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  50.   PARTICULAR PURPOSE.
  51. ==========================================================================+*/
  52.  
  53.  
  54. /*---------------------------------------------------------------------------
  55.   We include WINDOWS.H for all Win32 applications.
  56.   We include OLE2.H because we will be calling the COM/OLE Libraries.
  57.   We include OLECTL.H because it has definitions for connectable objects.
  58.   We include APPUTIL.H because we will be building this application using
  59.     the convenient Virtual Window and Dialog classes and other
  60.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  61.   We include IPAGES.H and PAGEGUID.H for the common TextPage-related
  62.     Interface class, GUID, and CLSID specifications.
  63.   We include SERVER.H because it has internal class declarations for
  64.     the server's control object.
  65.   We include CONNECT.H for object class declarations for the various
  66.     connection point and connection COM objects used in PERSERVE.
  67.   We include TEXTPAGE.H because it has the COTextPage class declarations.
  68. ---------------------------------------------------------------------------*/
  69. #include <windows.h>
  70. #include <ole2.h>
  71. #include <olectl.h>
  72. #include <apputil.h>
  73. #include <ipages.h>
  74. #include <pageguid.h>
  75. #include "server.h"
  76. #include "connect.h"
  77. #include "textpage.h"
  78.  
  79.  
  80. /*---------------------------------------------------------------------------
  81.   COTextPage's implementation of its main COM object class including
  82.   Constructor, Destructor, QueryInterface, AddRef, and Release.
  83. ---------------------------------------------------------------------------*/
  84.  
  85. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  86.   Method:   COTextPage::COTextPage
  87.  
  88.   Summary:  COTextPage Constructor. Note the member initializers like:
  89.             "m_ImpITextPage(this, pUnkOuter)" which is used to pass the
  90.             'this' and pUnkOuter pointers of the constructor function to
  91.             the constructor in the instantiation of the implementation of
  92.             the CImpITextPage interface (which is nested inside this present
  93.             COTextPage Object Class). Same technique is used for the other
  94.             nested interface implementations.
  95.  
  96.   Args:     IUnknown* pUnkOuter,
  97.               Pointer to the the outer Unknown.  NULL means this COM Object
  98.               is not being Aggregated.  Non-NULL means it is being created
  99.               on behalf of an outside COM object that is reusing it via
  100.               aggregation.
  101.             CServer* pServer)
  102.               Pointer to the server's control object.
  103.  
  104.   Modifies: m_cRefs, m_pUnkOuter, m_pServer.
  105.  
  106.   Returns:  void
  107. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  108. COTextPage::COTextPage(
  109.   IUnknown* pUnkOuter,
  110.   CServer* pServer) :
  111.   m_ImpITextPage(this, pUnkOuter),
  112.   m_ImpIPersistStreamInit(this, pUnkOuter),
  113.   m_ImpIConnectionPointContainer(this, pUnkOuter)
  114. {
  115.   UINT i;
  116.  
  117.   // Zero the COM object's reference count.
  118.   m_cRefs = 0;
  119.  
  120.   // No AddRef necessary if non-NULL, as we're nested.
  121.   m_pUnkOuter = pUnkOuter;
  122.  
  123.   // Assign the pointer to the server control object.
  124.   m_pServer = pServer;
  125.  
  126.   // Null all entries in the connection point array.
  127.   for (i=0; i<MAX_CONNECTION_POINTS; i++)
  128.     m_aConnectionPoints[i] = NULL;
  129.  
  130.   // Now initialize the TextPage itself.
  131.   m_pwszPageText = NULL;
  132.   m_ClassID = CLSID_TextPage;
  133.   m_bInitNew = FALSE;
  134.   m_bDirty = TRUE;
  135.  
  136.   return;
  137. }
  138.  
  139.  
  140. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  141.   Method:   COTextPage::~COTextPage
  142.  
  143.   Summary:  COTextPage Destructor.
  144.  
  145.   Args:     void
  146.  
  147.   Returns:  void
  148. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  149. COTextPage::~COTextPage(void)
  150. {
  151.   UINT i;
  152.   IConnectionPoint* pIConnectionPoint;
  153.  
  154.   // Do final release of the connection point objects.
  155.   for (i=0; i<MAX_CONNECTION_POINTS; i++)
  156.   {
  157.     pIConnectionPoint = m_aConnectionPoints[i];
  158.     RELEASE_INTERFACE(pIConnectionPoint);
  159.   }
  160.  
  161.   DELETE_POINTER(m_pwszPageText);
  162.  
  163.   return;
  164. }
  165.  
  166.  
  167. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  168.   Method:   COTextPage::Init
  169.  
  170.   Summary:  COTextPage initialization method.  Create any necessary
  171.             arrays, structures, and subordinate objects. Rig connectivity.
  172.  
  173.   Args:     void
  174.  
  175.   Modifies: m_aConnectionPoints.
  176.  
  177.   Returns:  HRESULT
  178.               Standard result code. NOERROR for success.
  179. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  180. HRESULT COTextPage::Init(void)
  181. {
  182.   HRESULT hr = NOERROR;
  183.   COConnectionPoint* pCOConnPt;
  184.  
  185.   // Rig this new COTextPage COM object to be connectable. Assign the
  186.   // connection point array. This object's connection points are
  187.   // determined at compile time--it currently has only one connection
  188.   // point: the CONNPOINT_TEXTPAGESINK connection point. Create a
  189.   // connection point object for this and assign it into the array. This
  190.   // array could easily grow to support additional connection points in
  191.   // the future.
  192.  
  193.   // First try creating a new connection point object. Pass 'this' as the
  194.   // pHostObj pointer used by the connection point to pass its AddRef and
  195.   // Release calls back to the host connectable object.
  196.   pCOConnPt = new COConnectionPoint(this);
  197.   if (NULL != pCOConnPt)
  198.   {
  199.     // If creation succeeded then initialize it (including creating
  200.     // its initial dynamic connection array).
  201.     hr = pCOConnPt->Init(IID_ITextPageSink);
  202.  
  203.     // If the init succeeded then use QueryInterface to obtain the
  204.     // IConnectionPoint interface on the new connection point object.
  205.     // The interface pointer is assigned directly into the
  206.     // connection point array. The QI also does the needed AddRef.
  207.     if (SUCCEEDED(hr))
  208.     {
  209.       hr = pCOConnPt->QueryInterface(
  210.              IID_IConnectionPoint,
  211.              (PPVOID)&m_aConnectionPoints[CONNPOINT_TEXTPAGESINK]);
  212.     }
  213.  
  214.     if (FAILED(hr))
  215.       delete pCOConnPt;
  216.   }
  217.   else
  218.     hr = E_OUTOFMEMORY;
  219.  
  220.   return hr;
  221. }
  222.  
  223.  
  224. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  225.   Method:   COTextPage::QueryInterface
  226.  
  227.   Summary:  QueryInterface of the COTextPage non-delegating IUnknown
  228.             implementation.
  229.  
  230.   Args:     REFIID riid,
  231.               [in] GUID of the Interface being requested.
  232.             PPVOID ppv)
  233.               [out] Address of the caller's pointer variable that will
  234.               receive the requested interface pointer.
  235.  
  236.   Returns:  HRESULT
  237.               Standard result code. NOERROR for success.
  238. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  239. STDMETHODIMP COTextPage::QueryInterface(
  240.                REFIID riid,
  241.                PPVOID ppv)
  242. {
  243.   HRESULT hr = E_NOINTERFACE;
  244.  
  245.   *ppv = NULL;
  246.  
  247.   if (IID_IUnknown == riid)
  248.     *ppv = this;
  249.   else if (IID_IConnectionPointContainer == riid)
  250.     *ppv = &m_ImpIConnectionPointContainer;
  251.   else if (IID_IPersistStreamInit == riid)
  252.     *ppv = &m_ImpIPersistStreamInit;
  253.   else if (IID_ITextPage == riid)
  254.     *ppv = &m_ImpITextPage;
  255.  
  256.   if (NULL != *ppv)
  257.   {
  258.     // We've handed out a pointer to the interface so obey the COM rules
  259.     // and AddRef the reference count.
  260.     ((LPUNKNOWN)*ppv)->AddRef();
  261.     hr = NOERROR;
  262.   }
  263.  
  264.   return (hr);
  265. }
  266.  
  267.  
  268. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  269.   Method:   COTextPage::AddRef
  270.  
  271.   Summary:  AddRef of the COTextPage non-delegating IUnknown implementation.
  272.  
  273.   Args:     void
  274.  
  275.   Modifies: m_cRefs.
  276.  
  277.   Returns:  ULONG
  278.               New value of m_cRefs (COM object's reference count).
  279. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  280. STDMETHODIMP_(ULONG) COTextPage::AddRef(void)
  281. {
  282.   ULONG cRefs;
  283.  
  284.   cRefs = ++m_cRefs;
  285.  
  286.   return cRefs;
  287. }
  288.  
  289.  
  290. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  291.   Method:   COTextPage::Release
  292.  
  293.   Summary:  Release of the COTextPage non-delegating IUnknown implementation.
  294.  
  295.   Args:     void
  296.  
  297.   Modifies: m_cRefs.
  298.  
  299.   Returns:  ULONG
  300.               New value of m_cRefs (COM object's reference count).
  301. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  302. STDMETHODIMP_(ULONG) COTextPage::Release(void)
  303. {
  304.   ULONG cRefs;
  305.  
  306.   cRefs = --m_cRefs;
  307.  
  308.   if (0 == cRefs)
  309.   {
  310.     // We've reached a zero reference count for this COM object.
  311.     // So we tell the server housing to decrement its global object
  312.     // count so that the server will be unloaded if appropriate.
  313.     if (NULL != m_pServer)
  314.       m_pServer->ObjectsDown();
  315.  
  316.     // We artificially bump the main ref count to prevent reentrancy
  317.     // via the main object destructor.  Not really needed in this
  318.     // COTextPage but a good practice because we are aggregatable and
  319.     // may at some point in the future add something entertaining like
  320.     // some Releases to the COTextPage destructor. We relinquish thread
  321.     // ownership of this object prior to deleting it--a good practice.
  322.     m_cRefs++;
  323.     delete this;
  324.   }
  325.  
  326.   return cRefs;
  327. }
  328.  
  329.  
  330. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  331.   Method:   COTextPage::Clear
  332.  
  333.   Summary:  Internal private utility method of this COM object used to
  334.             clear the content of the text page.
  335.  
  336.   Args:     BOOL bSaveNeeded
  337.               Specifies whether the cleared text page should later be
  338.               saved to file. TRUE=>later save needed; FALSE=>later save
  339.               not needed.
  340.  
  341.   Modifies: m_pwszPageText.
  342.  
  343.   Returns:  HRESULT
  344.               Standard result code. NOERROR for success.
  345. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  346. HRESULT COTextPage::Clear(
  347.           BOOL bSaveNeeded)
  348. {
  349.   HRESULT hr = NOERROR;
  350.  
  351.   // Zero the text string array.
  352.   if (NULL != m_pwszPageText)
  353.     memset(m_pwszPageText, 0, TEXTPAGE_V10_MAX * sizeof(WCHAR));
  354.  
  355.   // Set the Page Properties for this version of TextPages.
  356.   m_TextProps.ulVersion = TEXTPAGE_VERSION10;
  357.   m_TextProps.ulMaxLength = TEXTPAGE_V10_MAX;
  358.   m_TextProps.ulLength = 0;
  359.  
  360.   // Mark TextPage as dirty (ie, needs to be saved to file) if specified.
  361.   m_bDirty = bSaveNeeded;
  362.  
  363.   return hr;
  364. }
  365.  
  366.  
  367. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  368.   Method:   COTextPage::NotifySinks
  369.  
  370.   Summary:  Internal utility method of this COM object used to fire event
  371.             notification calls to all listening connection sinks in the
  372.             client.
  373.  
  374.   Args:     TEXTPAGE_EVENT TextPageEvent
  375.               Type of TextPage notification event.
  376.  
  377.   Returns:  HRESULT
  378.               Standard result code. NOERROR for success.
  379. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  380. HRESULT COTextPage::NotifySinks(
  381.        TEXTPAGE_EVENT TextPageEvent)
  382. {
  383.   HRESULT hr = NOERROR;
  384.   IConnectionPoint* pIConnectionPoint;
  385.   IEnumConnections* pIEnum;
  386.   CONNECTDATA ConnData;
  387.  
  388.   // If there was a TextPage event, broadcast appropriate notifications to
  389.   // all Sinks connected to each connection point.
  390.   if (TEXTPAGE_EVENT_NONE != TextPageEvent)
  391.   {
  392.     // Here is the section for the TextPageSink connection point--currently
  393.     // this is the only connection point offered by COTextPage objects.
  394.     pIConnectionPoint = m_aConnectionPoints[CONNPOINT_TEXTPAGESINK];
  395.     if (NULL != pIConnectionPoint)
  396.     {
  397.       pIConnectionPoint->AddRef();
  398.       hr = pIConnectionPoint->EnumConnections(&pIEnum);
  399.       if (SUCCEEDED(hr))
  400.       {
  401.         // Loop thru the connection point's connections and if the
  402.         // listening connection supports ITextPageSink (ie, TextPageSink
  403.         // events) then dispatch the TextPageEvent event notification to
  404.         // that sink.
  405.         while (NOERROR == pIEnum->Next(1, &ConnData, NULL))
  406.         {
  407.           ITextPageSink* pITextPageSink;
  408.  
  409.           hr = ConnData.pUnk->QueryInterface(
  410.                                 IID_ITextPageSink,
  411.                                 (PPVOID)&pITextPageSink);
  412.           if (SUCCEEDED(hr))
  413.           {
  414.             switch (TextPageEvent)
  415.             {
  416.               case TEXTPAGE_EVENT_LOADED:
  417.                 pITextPageSink->Loaded();
  418.                 break;
  419.               case TEXTPAGE_EVENT_SAVED:
  420.                 pITextPageSink->Saved();
  421.                 break;
  422.               case TEXTPAGE_EVENT_PUT:
  423.                 pITextPageSink->Put();
  424.                 break;
  425.               case TEXTPAGE_EVENT_CLEARED:
  426.                 pITextPageSink->Cleared();
  427.                 break;
  428.               default:
  429.                 break;
  430.             }
  431.             pITextPageSink->Release();
  432.           }
  433.           ConnData.pUnk->Release();
  434.         }
  435.         pIEnum->Release();
  436.       }
  437.       pIConnectionPoint->Release();
  438.     }
  439.   }
  440.  
  441.   return hr;
  442. }
  443.  
  444.  
  445. /*---------------------------------------------------------------------------
  446.   COTextPage's nested implementation of the COM standard
  447.   IConnectionPointContainer interface including Constructor, Destructor,
  448.   QueryInterface, AddRef, Release, FindConnectionPoint, and
  449.   EnumConnectionPoints.
  450. ---------------------------------------------------------------------------*/
  451.  
  452. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  453.   Method:   COTextPage::CImpIConnectionPointContainer
  454.               ::CImpIConnectionPointContainer
  455.  
  456.   Summary:  Constructor for the CImpIConnectionPointContainer interface
  457.             instantiation.
  458.  
  459.   Args:     COTextPage* pCO,
  460.               Back pointer to the parent outer object.
  461.             IUnknown* pUnkOuter
  462.               Pointer to the outer Unknown.  For delegation.
  463.  
  464.   Modifies: m_pCO, m_pUnkOuter.
  465.  
  466.   Returns:  void
  467. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  468. COTextPage::CImpIConnectionPointContainer::CImpIConnectionPointContainer(
  469.   COTextPage* pCO,
  470.   IUnknown* pUnkOuter)
  471. {
  472.   // Init the Main Object Pointer to point to the parent object.
  473.   m_pCO = pCO;
  474.  
  475.   // Init the CImpIConnectionPointContainer interface's delegating Unknown
  476.   // pointer.  We use the Main Object pointer for IUnknown delegation here
  477.   // if we are not being aggregated.  If we are being aggregated we use
  478.   // the supplied pUnkOuter for IUnknown delegation.  In either case the
  479.   // pointer assignment requires no AddRef because the
  480.   // CImpIConnectionPointContainer lifetime is quaranteed by the lifetime
  481.   // of the parent object in which CImpIConnectionPointContainer is
  482.   // nested.
  483.   if (NULL == pUnkOuter)
  484.     m_pUnkOuter = pCO;
  485.   else
  486.     m_pUnkOuter = pUnkOuter;
  487.  
  488.   return;
  489. }
  490.  
  491.  
  492. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  493.   Method:   COTextPage::CImpIConnectionPointContainer
  494.               ::~CImpIConnectionPointContainer
  495.  
  496.   Summary:  Destructor for the CImpIConnectionPointContainer interface
  497.             instantiation.
  498.  
  499.   Args:     void
  500.  
  501.   Returns:  void
  502. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  503. COTextPage::CImpIConnectionPointContainer::~CImpIConnectionPointContainer(void)
  504. {
  505.   return;
  506. }
  507.  
  508.  
  509. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  510.   Method:   COTextPage::CImpIConnectionPointContainer::QueryInterface
  511.  
  512.   Summary:  The QueryInterface IUnknown member of this ITextPage interface
  513.             implementation that delegates to m_pUnkOuter, whatever it is.
  514.  
  515.   Args:     REFIID riid,
  516.               [in] GUID of the Interface being requested.
  517.             PPVOID ppv)
  518.               [out] Address of the caller's pointer variable that will
  519.               receive the requested interface pointer.
  520.  
  521.   Returns:  HRESULT
  522.               Standard result code. NOERROR for success.
  523.               Returned by the delegated outer QueryInterface call.
  524. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  525. STDMETHODIMP COTextPage::CImpIConnectionPointContainer::QueryInterface(
  526.                REFIID riid,
  527.                PPVOID ppv)
  528. {
  529.   // Delegate this call to the outer object's QueryInterface.
  530.   return m_pUnkOuter->QueryInterface(riid, ppv);
  531. }
  532.  
  533.  
  534. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  535.   Method:   COTextPage::CImpIConnectionPointContainer::AddRef
  536.  
  537.   Summary:  The AddRef IUnknown member of this ITextPage interface
  538.             implementation that delegates to m_pUnkOuter, whatever it is.
  539.  
  540.   Args:     void
  541.  
  542.   Returns:  ULONG
  543.               Returned by the delegated outer AddRef call.
  544. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  545. STDMETHODIMP_(ULONG) COTextPage::CImpIConnectionPointContainer::AddRef(void)
  546. {
  547.   // Delegate this call to the outer object's AddRef.
  548.   return m_pUnkOuter->AddRef();
  549. }
  550.  
  551.  
  552. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  553.   Method:   COTextPage::CImpIConnectionPointContainer::Release
  554.  
  555.   Summary:  The Release IUnknown member of this ITextPage interface
  556.             implementation that delegates to m_pUnkOuter, whatever it is.
  557.  
  558.   Args:     void
  559.  
  560.   Returns:  ULONG
  561.               Returned by the delegated outer Release call.
  562. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  563. STDMETHODIMP_(ULONG) COTextPage::CImpIConnectionPointContainer::Release(void)
  564. {
  565.   // Delegate this call to the outer object's Release.
  566.   return m_pUnkOuter->Release();
  567. }
  568.  
  569.  
  570. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  571.   Method:   COTextPage::CImpIConnectionPointContainer::FindConnectionPoint
  572.  
  573.   Summary:  Given an IID for a connection point sink find and return the
  574.             interface pointer for that connection point sink.
  575.  
  576.   Args:     REFIID riid
  577.               Reference to an IID
  578.             IConnectionPoint** ppConnPt
  579.               Address of the caller's IConnectionPoint interface pointer
  580.               variable that will receive the requested interface pointer.
  581.  
  582.   Returns:  HRESULT
  583.               Standard result code. NOERROR for success.
  584. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  585. STDMETHODIMP COTextPage::CImpIConnectionPointContainer::FindConnectionPoint(
  586.                REFIID riid,
  587.                IConnectionPoint** ppConnPt)
  588. {
  589.   HRESULT hr = E_NOINTERFACE;
  590.   IConnectionPoint* pIConnPt;
  591.  
  592.   // NULL the output variable.
  593.   *ppConnPt = NULL;
  594.  
  595.   pIConnPt = m_pCO->m_aConnectionPoints[CONNPOINT_TEXTPAGESINK];
  596.   if (NULL != pIConnPt)
  597.   {
  598.     // This connectable COTextPage object currently has only the
  599.     // TextPage Sink connection point. If the associated interface is
  600.     // requested, use QI to get the Connection Point interface and
  601.     // perform the needed AddRef.
  602.     if (IID_ITextPageSink == riid)
  603.       hr = pIConnPt->QueryInterface(
  604.                        IID_IConnectionPoint,
  605.                        (PPVOID)ppConnPt);
  606.   }
  607.  
  608.   return hr;
  609. }
  610.  
  611.  
  612. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  613.   Method:   COTextPage::CImpIConnectionPointContainer::EnumConnectionPoints
  614.  
  615.   Summary:  Return Enumerator for the connectable object's contained
  616.             connection points.
  617.  
  618.   Args:     IEnumConnectionPoints** ppIEnum
  619.               Address of the caller's Enumerator interface pointer
  620.               variable. An output variable that will receive a pointer to
  621.               the connection point enumerator COM object.
  622.  
  623.   Returns:  HRESULT
  624.               Standard result code. NOERROR for success.
  625. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  626. STDMETHODIMP COTextPage::CImpIConnectionPointContainer::EnumConnectionPoints(
  627.                IEnumConnectionPoints** ppIEnum)
  628. {
  629.   HRESULT hr = NOERROR;
  630.   IConnectionPoint* aConnPts[MAX_CONNECTION_POINTS];
  631.   COEnumConnectionPoints* pCOEnum;
  632.   UINT i;
  633.  
  634.   // Zero the output interface pointer.
  635.   *ppIEnum = NULL;
  636.  
  637.   // Make a copy on the stack of the array of connection point
  638.   // interfaces. The copy is used below in the creation of the new
  639.   // Enumerator object.
  640.   for (i=0; i<MAX_CONNECTION_POINTS; i++)
  641.     aConnPts[i] = (IConnectionPoint*)m_pCO->m_aConnectionPoints[i];
  642.  
  643.   // Create a Connection Point enumerator COM object for the connection
  644.   // points offered by this COTextPage object. Pass 'this' to be used to
  645.   // hook the lifetime of the host object to the life time of this
  646.   // enumerator object.
  647.   pCOEnum = new COEnumConnectionPoints(this);
  648.   if (NULL != pCOEnum)
  649.   {
  650.     // Use the array copy to Init the new Enumerator COM object.
  651.     // Set the initial Enumerator index to 0.
  652.     hr = pCOEnum->Init(MAX_CONNECTION_POINTS, aConnPts, 0);
  653.     if (SUCCEEDED(hr))
  654.     {
  655.       // QueryInterface to return the requested interface pointer.
  656.       // An AddRef will be conveniently done by the QI.
  657.       if (SUCCEEDED(hr))
  658.         hr = pCOEnum->QueryInterface(
  659.                         IID_IEnumConnectionPoints,
  660.                         (PPVOID)ppIEnum);
  661.     }
  662.   }
  663.   else
  664.     hr = E_OUTOFMEMORY;
  665.  
  666.   return hr;
  667. }
  668.  
  669.  
  670. /*---------------------------------------------------------------------------
  671.   COTextPage's nested implementation of the COM standard
  672.   IPersistStreamInit interface including Constructor, Destructor,
  673.   QueryInterface, AddRef, Release, GetClassID, IsDirty, Load, Save,
  674.   GetSizeMax, and InitNew.
  675. ---------------------------------------------------------------------------*/
  676.  
  677. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  678.   Method:   COTextPage::CImpIPersistStreamInit::CImpIPersistStreamInit
  679.  
  680.   Summary:  Constructor for the CImpIPersistStreamInit interface
  681.             instantiation.
  682.  
  683.   Args:     COTextPage* pCO,
  684.               Back pointer to the parent outer object.
  685.             IUnknown* pUnkOuter
  686.               Pointer to the outer Unknown.  For delegation.
  687.  
  688.   Modifies: m_pCO, m_pUnkOuter.
  689.  
  690.   Returns:  void
  691. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  692. COTextPage::CImpIPersistStreamInit::CImpIPersistStreamInit(
  693.   COTextPage* pCO,
  694.   IUnknown* pUnkOuter)
  695. {
  696.   // Init the Main Object Pointer to point to the parent object.
  697.   m_pCO = pCO;
  698.  
  699.   // Init the CImpIPersistStreamInit interface's delegating IUnknown
  700.   // pointer.  We use the Main Object pointer for IUnknown delegation here
  701.   // if we are not being aggregated.  If we are being aggregated we use
  702.   // the supplied pUnkOuter for IUnknown delegation.  In either case the
  703.   // pointer assignment requires no AddRef because the
  704.   // pIPersistStreamInit lifetime is quaranteed by the lifetime of the
  705.   // parent object in which CImpIPersistStreamInit is nested.
  706.   if (NULL == pUnkOuter)
  707.     m_pUnkOuter = pCO;
  708.   else
  709.     m_pUnkOuter = pUnkOuter;
  710.  
  711.   return;
  712. }
  713.  
  714.  
  715. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  716.   Method:   COTextPage::CImpIPersistStreamInit::~CImpIPersistStreamInit
  717.  
  718.   Summary:  Destructor for the CImpIPersistStreamIint interface
  719.             instantiation.
  720.  
  721.   Args:     void
  722.  
  723.   Returns:  void
  724. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  725. COTextPage::CImpIPersistStreamInit::~CImpIPersistStreamInit(void)
  726. {
  727.   return;
  728. }
  729.  
  730.  
  731. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  732.   Method:   COTextPage::CImpIPersistStreamInit::QueryInterface
  733.  
  734.   Summary:  The QueryInterface IUnknown member of this interface
  735.             implementation that delegates to m_pUnkOuter, whatever it is.
  736.  
  737.   Args:     REFIID riid,
  738.               [in] GUID of the Interface being requested.
  739.             PPVOID ppv)
  740.               [out] Address of the caller's pointer variable that will
  741.               receive the requested interface pointer.
  742.  
  743.   Returns:  HRESULT
  744.               Standard result code. NOERROR for success.
  745.               Returned by the delegated outer QueryInterface call.
  746. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  747. STDMETHODIMP COTextPage::CImpIPersistStreamInit::QueryInterface(
  748.                REFIID riid,
  749.                PPVOID ppv)
  750. {
  751.   // Delegate this call to the outer object's QueryInterface.
  752.   return m_pUnkOuter->QueryInterface(riid, ppv);
  753. }
  754.  
  755.  
  756. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  757.   Method:   COTextPage::CImpIPersistStreamInit::AddRef
  758.  
  759.   Summary:  The AddRef IUnknown member of this interface implementation
  760.             that delegates to m_pUnkOuter, whatever it is.
  761.  
  762.   Args:     void
  763.  
  764.   Returns:  ULONG
  765.               Returned by the delegated outer AddRef call.
  766. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  767. STDMETHODIMP_(ULONG) COTextPage::CImpIPersistStreamInit::AddRef(void)
  768. {
  769.   // Delegate this call to the outer object's AddRef.
  770.   return m_pUnkOuter->AddRef();
  771. }
  772.  
  773.  
  774. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  775.   Method:   COTextPage::CImpIPersistStreamInit::Release
  776.  
  777.   Summary:  The Release IUnknown member of this interface implementation
  778.             that delegates to m_pUnkOuter, whatever it is.
  779.  
  780.   Args:     void
  781.  
  782.   Returns:  ULONG
  783.               Returned by the delegated outer Release call.
  784. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  785. STDMETHODIMP_(ULONG) COTextPage::CImpIPersistStreamInit::Release(void)
  786. {
  787.   // Delegate this call to the outer object's Release.
  788.   return m_pUnkOuter->Release();
  789. }
  790.  
  791.  
  792. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  793.   Method:   COTextPage::CImpIPersistStreamInit::GetClassID
  794.  
  795.   Summary:  A method inherited from IPersist. Get the Class ID of this
  796.             COM object.
  797.  
  798.   Args:     CLSID* pClassID
  799.               [out] Address of variable to hold Class ID.
  800.  
  801.   Returns:  HRESULT
  802.               Standard result code. NOERROR for success.
  803. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  804. STDMETHODIMP COTextPage::CImpIPersistStreamInit::GetClassID(
  805.                CLSID* pClassID)
  806. {
  807.   HRESULT hr = E_POINTER;
  808.  
  809.   if (NULL != pClassID)
  810.   {
  811.     // Use overloaded '=' operator to copy the Class ID to caller.
  812.     *pClassID = m_pCO->m_ClassID;
  813.     hr = NOERROR;
  814.   }
  815.  
  816.   return hr;
  817. }
  818.  
  819.  
  820. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  821.   Method:   COTextPage::CImpIPersistStreamInit::IsDirty
  822.  
  823.   Summary:  Called to determine if changes were made to this COM object
  824.             since it was last loaded or initialized.
  825.  
  826.   Args:     none.
  827.  
  828.   Returns:  HRESULT
  829.               Standard result code. S_OK if dirty; S_FALSE if not.
  830. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  831. STDMETHODIMP COTextPage::CImpIPersistStreamInit::IsDirty(
  832.                void)
  833. {
  834.   HRESULT hr;
  835.  
  836.   hr = m_pCO->m_bDirty ? S_OK : S_FALSE;
  837.  
  838.   return hr;
  839. }
  840.  
  841.  
  842. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  843.   Method:   COTextPage::CImpIPersistStreamInit::Load
  844.  
  845.   Summary:  Asks this COM object to load its persistent data from the
  846.             specified stream at the current seek pointer. This function
  847.             assumes the seek pointer is the same as it was before Save
  848.             was last called. This function must leave the seek pointer
  849.             the same as it was after Save was last completed regardless
  850.             of success or failure. This function should not keep a copy
  851.             of pIStream in the COM object after it completes.
  852.  
  853.             Load is called INSTEAD of InitNew when this COM object already
  854.             has a persistent state stored in a stream. Notifies all other
  855.             connected clients when the load is complete.
  856.  
  857.   Args:     IStream* pIStream
  858.               IStream interface pointer for stream to load from. This
  859.               COM object must NOT retain a copy of this IStream pointer
  860.               after this call completes.
  861.  
  862.   Returns:  HRESULT
  863.               Standard result code. NOERROR for success. E_UNEXPECTED if
  864.               an InitNew or Load has already been called.
  865. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  866. STDMETHODIMP COTextPage::CImpIPersistStreamInit::Load(
  867.                IStream* pIStream)
  868. {
  869.   HRESULT hr = E_POINTER;
  870.   ULONG ulToRead, ulReadIn;
  871.   TEXTPROPS NewProps;
  872.   WCHAR* pwszPageText;
  873.  
  874.   if (NULL != pIStream)
  875.   {
  876.     if (!m_pCO->m_bInitNew)
  877.     {
  878.       // We have the TextPage data stream. First read the TextPage
  879.       // Properties.
  880.       ulToRead = sizeof(TEXTPROPS);
  881.       hr = pIStream->Read(
  882.                        &NewProps,
  883.                        ulToRead,
  884.                        &ulReadIn);
  885.       if (SUCCEEDED(hr) && ulToRead != ulReadIn)
  886.         hr = E_FAIL;
  887.       if (SUCCEEDED(hr))
  888.       {
  889.         // Deal with the different versions.
  890.         switch (NewProps.ulVersion)
  891.         {
  892.           case TEXTPAGE_VERSION10:
  893.             if (NewProps.ulMaxLength <= TEXTPAGE_V10_MAX)
  894.             {
  895.               // Allocate an page text array big enough for the largest
  896.               // text page.
  897.               pwszPageText = new WCHAR[(ULONG) NewProps.ulMaxLength];
  898.               if (NULL != pwszPageText)
  899.               {
  900.                 m_pCO->m_pwszPageText = pwszPageText;
  901.                 // First zero the page text area.
  902.                 memset(
  903.                   pwszPageText,
  904.                   0,
  905.                   NewProps.ulMaxLength * sizeof(WCHAR));
  906.                 ulToRead = NewProps.ulLength * sizeof(WCHAR);
  907.                 if (ulToRead >= 0 && ulToRead < (ULONG)NewProps.ulMaxLength)
  908.                 {
  909.                   // Now read in the complete text page.
  910.                   hr = pIStream->Read(
  911.                          pwszPageText,
  912.                          ulToRead,
  913.                          &ulReadIn);
  914.                   if (SUCCEEDED(hr) && ulToRead != ulReadIn)
  915.                     hr = E_FAIL;
  916.                   if (SUCCEEDED(hr))
  917.                   {
  918.                     // Copy the new properties into current properties.
  919.                     memcpy(
  920.                       &m_pCO->m_TextProps,
  921.                       &NewProps,
  922.                       sizeof(TEXTPROPS));
  923.  
  924.                     // We are loaded and clean (ie, COTextPage data
  925.                     // matches file data). Clear dirty flag.
  926.                     m_pCO->m_bDirty = FALSE;
  927.                   }
  928.                 }
  929.                 else
  930.                   hr = E_FAIL;
  931.               }
  932.               else
  933.                 hr = E_OUTOFMEMORY;
  934.             }
  935.             break;
  936.           default:
  937.             hr = E_FAIL;  // Bad version.
  938.             break;
  939.         }
  940.       }
  941.     }
  942.     else
  943.       hr = E_UNEXPECTED;
  944.   }
  945.  
  946.   // Notify all other connected clients that TextPage is now loaded.
  947.   // If we didn't load then clear to a safe, empty text page.
  948.   if (SUCCEEDED(hr))
  949.     m_pCO->NotifySinks(TEXTPAGE_EVENT_LOADED);
  950.   else
  951.     m_pCO->Clear(TRUE);
  952.  
  953.   return hr;
  954. }
  955.  
  956.  
  957. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  958.   Method:   COTextPage::CImpIPersistStreamInit::Save
  959.  
  960.   Summary:  Called to save the persistent data of this COM object to a
  961.             stream using the specified IStream interface. This call stores
  962.             data from the current seek pointer offset. On exit from this
  963.             method the seek pointer is assumed to be just past the end of
  964.             the data saved. This allows a series of contiguous persistent
  965.             objects to be saved into the same stream. Notifies all other
  966.             connected clients when the save is complete.
  967.  
  968.   Args:     IStream* pIStream
  969.               IStream interface pointer for stream to load from. This
  970.               COM object must NOT retain a copy of this IStream pointer
  971.               after the function completes.
  972.             BOOL bClearDirty
  973.               Determines if this method should clear the COM object's
  974.               dirty flag. If bClearDirty is TRUE then clear the dirty
  975.               flag.
  976.  
  977.   Returns:  HRESULT
  978.               Standard result code. NOERROR for success.
  979. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  980. STDMETHODIMP COTextPage::CImpIPersistStreamInit::Save(
  981.                IStream* pIStream,
  982.                BOOL bClearDirty)
  983. {
  984.   HRESULT hr = E_POINTER;
  985.   ULONG ulToWrite, ulWritten;
  986.  
  987.   if (NULL != pIStream)
  988.   {
  989.     // Got a stream. Now write data into it.
  990.  
  991.     // First write TEXTPROPS structure.
  992.     ulToWrite = sizeof(TEXTPROPS);
  993.     hr = pIStream->Write(&m_pCO->m_TextProps, ulToWrite, &ulWritten);
  994.     if (SUCCEEDED(hr) && ulToWrite != ulWritten)
  995.       hr = STG_E_CANTSAVE;
  996.     if (SUCCEEDED(hr))
  997.     {
  998.       // Now write the complete page text data.
  999.       ulToWrite = m_pCO->m_TextProps.ulLength * sizeof(WCHAR);
  1000.       hr = pIStream->Write(m_pCO->m_pwszPageText, ulToWrite, &ulWritten);
  1001.       if (SUCCEEDED(hr) && ulToWrite != ulWritten)
  1002.         hr = STG_E_CANTSAVE;
  1003.       if (SUCCEEDED(hr))
  1004.       {
  1005.         // Clear this COM object's dirty flag if instructed.
  1006.         if (bClearDirty)
  1007.           m_pCO->m_bDirty = FALSE;
  1008.       }
  1009.     }
  1010.   }
  1011.  
  1012.   // Notify all other connected clients that TextPage is now saved.
  1013.   if (SUCCEEDED(hr))
  1014.     m_pCO->NotifySinks(TEXTPAGE_EVENT_SAVED);
  1015.  
  1016.   return hr;
  1017. }
  1018.  
  1019.  
  1020. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1021.   Method:   COTextPage::CImpIPersistStreamInit::GetSizeMax
  1022.  
  1023.   Summary:  Called to obtain the maximum possible total size of the
  1024.             chunks of data that could be saved when Save is next called.
  1025.  
  1026.   Args:     ULARGE_INTEGER* pcbSize
  1027.               Address of the caller's variable to receive the size (bytes).
  1028.  
  1029.   Returns:  HRESULT
  1030.               Standard result code. NOERROR for success.
  1031. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1032. STDMETHODIMP COTextPage::CImpIPersistStreamInit::GetSizeMax(
  1033.                ULARGE_INTEGER* pcbSize)
  1034. {
  1035.   HRESULT hr = E_POINTER;
  1036.   ULONG ulMax = m_pCO->m_TextProps.ulMaxLength;
  1037.  
  1038.   if (NULL != pcbSize)
  1039.   {
  1040.     ULISet32(*pcbSize, sizeof(TEXTPROPS) + (ulMax * sizeof(WCHAR)));
  1041.     hr = NOERROR;
  1042.   }
  1043.  
  1044.   return hr;
  1045. }
  1046.  
  1047.  
  1048. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1049.   Method:   COTextPage::CImpIPersistStreamInit::InitNew
  1050.  
  1051.   Summary:  Called to tell the object that it has been newly created and
  1052.             has no existing persistent state already stored.
  1053.  
  1054.             InitNew is called INSTEAD of Load when the new object instance
  1055.             must be initialized with brand new data rather than with
  1056.             persistent data previously saved in a stream.
  1057.  
  1058.   Args:     none.
  1059.  
  1060.   Modifies: m_pwszPageText, m_aConnectionPoints.
  1061.  
  1062.   Returns:  HRESULT
  1063.               Standard result code. NOERROR for success.
  1064. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1065. STDMETHODIMP COTextPage::CImpIPersistStreamInit::InitNew(
  1066.                void)
  1067. {
  1068.   HRESULT hr = E_FAIL;
  1069.   WCHAR* pwszPageText;
  1070.  
  1071.   if (!m_pCO->m_bInitNew)
  1072.   {
  1073.     // There is no previous persistent data for this COTextPage object.
  1074.     // Create and init a new set of persistence data for an empty text page.
  1075.  
  1076.     // Allocate an page text array big enough for the largest text page.
  1077.     // This maximum is hard-coded here for this Version 1.0 of Text Pages.
  1078.     pwszPageText = new WCHAR[(LONG) TEXTPAGE_V10_MAX];
  1079.     if (NULL != pwszPageText)
  1080.     {
  1081.       m_pCO->m_pwszPageText = pwszPageText;
  1082.       // Use the private Clear method to clear the new text array and to
  1083.       // set the Page Properties structure appropriately. Also sets dirty.
  1084.       hr = m_pCO->Clear(TRUE);
  1085.       m_pCO->m_bInitNew = TRUE;
  1086.     }
  1087.     else
  1088.       hr = E_OUTOFMEMORY;
  1089.   }
  1090.   else
  1091.     hr = E_UNEXPECTED;
  1092.  
  1093.   return hr;
  1094. }
  1095.  
  1096.  
  1097. /*---------------------------------------------------------------------------
  1098.   COTextPage's nested implementation of the custom ITextPage interface
  1099.   including Constructor, Destructor, QueryInterface, AddRef, Release,
  1100.   GetFirst, GetNext, Add, Delete, and Clear.
  1101. ---------------------------------------------------------------------------*/
  1102.  
  1103. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1104.   Method:   COTextPage::CImpITextPage::CImpITextPage
  1105.  
  1106.   Summary:  Constructor for the CImpITextPage interface instantiation.
  1107.  
  1108.   Args:     COTextPage* pCO,
  1109.               Back pointer to the parent outer object.
  1110.             IUnknown* pUnkOuter
  1111.               Pointer to the outer Unknown.  For delegation.
  1112.  
  1113.   Modifies: m_pCO, m_pUnkOuter.
  1114.  
  1115.   Returns:  void
  1116. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1117. COTextPage::CImpITextPage::CImpITextPage(
  1118.   COTextPage* pCO,
  1119.   IUnknown* pUnkOuter)
  1120. {
  1121.   // Init the Main Object Pointer to point to the parent object.
  1122.   m_pCO = pCO;
  1123.  
  1124.   // Init the CImpITextPage interface's delegating IUnknown pointer.  We
  1125.   // use the Main Object pointer for IUnknown delegation here if we are
  1126.   // not being aggregated.  If we are being aggregated we use the supplied
  1127.   // pUnkOuter for IUnknown delegation.  In either case the pointer
  1128.   // assignment requires no AddRef because the CImpITextPage lifetime is
  1129.   // quaranteed by the lifetime of the parent object in which
  1130.   // CImpITextPage is nested.
  1131.   if (NULL == pUnkOuter)
  1132.     m_pUnkOuter = pCO;
  1133.   else
  1134.     m_pUnkOuter = pUnkOuter;
  1135.  
  1136.   return;
  1137. }
  1138.  
  1139.  
  1140. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1141.   Method:   COTextPage::CImpITextPage::~CImpITextPage
  1142.  
  1143.   Summary:  Destructor for the CImpITextPage interface instantiation.
  1144.  
  1145.   Args:     void
  1146.  
  1147.   Returns:  void
  1148. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1149. COTextPage::CImpITextPage::~CImpITextPage(void)
  1150. {
  1151.  
  1152.   return;
  1153. }
  1154.  
  1155.  
  1156. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1157.   Method:   COTextPage::CImpITextPage::QueryInterface
  1158.  
  1159.   Summary:  The QueryInterface IUnknown member of this ITextPage interface
  1160.             implementation that delegates to m_pUnkOuter, whatever it is.
  1161.  
  1162.   Args:     REFIID riid,
  1163.               [in] GUID of the Interface being requested.
  1164.             PPVOID ppv)
  1165.               [out] Address of the caller's pointer variable that will
  1166.               receive the requested interface pointer.
  1167.  
  1168.   Returns:  HRESULT
  1169.               Standard result code. NOERROR for success.
  1170.               Returned by the delegated outer QueryInterface call.
  1171. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1172. STDMETHODIMP COTextPage::CImpITextPage::QueryInterface(
  1173.                REFIID riid,
  1174.                PPVOID ppv)
  1175. {
  1176.   // Delegate this call to the outer object's QueryInterface.
  1177.   return m_pUnkOuter->QueryInterface(riid, ppv);
  1178. }
  1179.  
  1180.  
  1181. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1182.   Method:   COTextPage::CImpITextPage::AddRef
  1183.  
  1184.   Summary:  The AddRef IUnknown member of this ITextPage interface
  1185.             implementation that delegates to m_pUnkOuter, whatever it is.
  1186.  
  1187.   Args:     void
  1188.  
  1189.   Returns:  ULONG
  1190.               Returned by the delegated outer AddRef call.
  1191. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1192. STDMETHODIMP_(ULONG) COTextPage::CImpITextPage::AddRef(void)
  1193. {
  1194.   // Delegate this call to the outer object's AddRef.
  1195.   return m_pUnkOuter->AddRef();
  1196. }
  1197.  
  1198.  
  1199. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1200.   Method:   COTextPage::CImpITextPage::Release
  1201.  
  1202.   Summary:  The Release IUnknown member of this ITextPage interface
  1203.             implementation that delegates to m_pUnkOuter, whatever it is.
  1204.  
  1205.   Args:     void
  1206.  
  1207.   Returns:  ULONG
  1208.               Returned by the delegated outer Release call.
  1209. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1210. STDMETHODIMP_(ULONG) COTextPage::CImpITextPage::Release(void)
  1211. {
  1212.   // Delegate this call to the outer object's Release.
  1213.   return m_pUnkOuter->Release();
  1214. }
  1215.  
  1216.  
  1217. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1218.   Method:   COTextPage::CImpITextPage::GetLength
  1219.  
  1220.   Summary:  Get the current length (in WCHARs) of the text page.
  1221.  
  1222.   Args:     INT* piLength
  1223.               Address of the caller's variable that is assigned the length.
  1224.  
  1225.   Returns:  HRESULT
  1226.               Standard result code. NOERROR for success.
  1227. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1228. STDMETHODIMP COTextPage::CImpITextPage::GetLength(
  1229.                INT* piLength)
  1230. {
  1231.   HRESULT hr = E_POINTER;
  1232.  
  1233.   if (NULL != piLength)
  1234.   {
  1235.     *piLength = (INT) m_pCO->m_TextProps.ulLength;
  1236.     hr = NOERROR;
  1237.   }
  1238.  
  1239.   return hr;
  1240. }
  1241.  
  1242.  
  1243. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1244.   Method:   COTextPage::CImpITextPage::GetText
  1245.  
  1246.   Summary:  Get the current page text held in this object.
  1247.  
  1248.   Args:     WCHAR* pwszPageText
  1249.               Address of a wide character string to receive the text
  1250.               data of the text page.
  1251.  
  1252.   Returns:  HRESULT
  1253.               Standard result code. NOERROR for success. E_POINTER if
  1254.               NULL passed for the output string pointer.
  1255. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1256. STDMETHODIMP COTextPage::CImpITextPage::GetText(
  1257.                WCHAR* pwszPageText)
  1258. {
  1259.   HRESULT hr = E_POINTER;
  1260.  
  1261.   if (NULL != pwszPageText && NULL != m_pCO->m_pwszPageText)
  1262.   {
  1263.     // Copy the Text Page's text to the caller.
  1264.     memcpy(
  1265.       pwszPageText,
  1266.       m_pCO->m_pwszPageText,
  1267.       m_pCO->m_TextProps.ulLength * sizeof(WCHAR));
  1268.     hr = NOERROR;
  1269.   }
  1270.  
  1271.   return hr;
  1272. }
  1273.  
  1274.  
  1275. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1276.   Method:   COTextPage::CImpITextPage::PutText
  1277.  
  1278.   Summary:  Put specified text into the Text Page COM object. This does
  1279.             not save the text persistently.
  1280.  
  1281.   Args:     WCHAR* pwszPageText,
  1282.               Address of the wide character string to put into the text
  1283.               page.
  1284.             INT iLength)
  1285.               Length in wide characters of the string.
  1286.  
  1287.   Returns:  HRESULT
  1288.               Standard result code. NOERROR for success. E_POINTER if
  1289.               NULL passed for the input string.
  1290. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1291. STDMETHODIMP COTextPage::CImpITextPage::PutText(
  1292.                WCHAR* pwszPageText,
  1293.                INT iLength)
  1294. {
  1295.   HRESULT hr = E_POINTER;
  1296.  
  1297.   if (NULL != pwszPageText && NULL != m_pCO->m_pwszPageText)
  1298.   {
  1299.     if (iLength < (INT) m_pCO->m_TextProps.ulMaxLength)
  1300.     {
  1301.       // Copy the Caller's text into the text page.
  1302.       memcpy(
  1303.         m_pCO->m_pwszPageText,
  1304.         pwszPageText,
  1305.         iLength * sizeof(WCHAR));
  1306.  
  1307.       // Set the new current length.
  1308.       m_pCO->m_TextProps.ulLength = (ULONG)iLength;
  1309.  
  1310.       // Mark TextPage as dirty. Subsequent save to file is needed.
  1311.       m_pCO->m_bDirty = TRUE;
  1312.  
  1313.       // Notify all other connected clients that the new text was
  1314.       // put into the COTextPage object.
  1315.       m_pCO->NotifySinks(TEXTPAGE_EVENT_PUT);
  1316.  
  1317.       hr = NOERROR;
  1318.     }
  1319.     else
  1320.       hr = E_FAIL;
  1321.   }
  1322.  
  1323.   return hr;
  1324. }
  1325.  
  1326.  
  1327. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1328.   Method:   COTextPage::CImpITextPage::Clear
  1329.  
  1330.   Summary:  Clears the entire text page. Sets dirty flag if specified.
  1331.             Reassigns the page properties as appropriate. Notifies clients
  1332.             of this event.
  1333.  
  1334.   Args:     BOOL bSaveNeeded
  1335.               Specifies whether the cleared text page should later be
  1336.               saved to file. TRUE=>later save needed; FALSE=>later save
  1337.               not needed.
  1338.  
  1339.   Returns:  HRESULT
  1340.               Standard result code. NOERROR for success.
  1341. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1342. STDMETHODIMP COTextPage::CImpITextPage::Clear(
  1343.                BOOL bSaveNeeded)
  1344. {
  1345.   HRESULT hr = E_FAIL;
  1346.  
  1347.   hr = m_pCO->Clear(bSaveNeeded);
  1348.  
  1349.   // Notify all other connected clients that the list was cleared.
  1350.   if (SUCCEEDED(hr))
  1351.     m_pCO->NotifySinks(TEXTPAGE_EVENT_CLEARED);
  1352.  
  1353.   return hr;
  1354. }
  1355.