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 >
Wrap
C/C++ Source or Header
|
1997-08-05
|
47KB
|
1,355 lines
/*+==========================================================================
File: TEXTPAGE.CPP
Summary: Implementation file for the COTextPage COM Object Class (for
connectable COTextPage COM Objects). COTextPage encapsulates
into a COM object the behavior of a page of editable text.
The client can use the native ITextPage interface to get and
put the text of the text page into the object. No GUI
behavior is provided within COTextPage--it only provides a
persistent data management for the text page.
Connectable object technology is used in COTextPage to notify
connected clients of various events like when a load of new
text data is completed.
COTextPage offers a main standard IUnknown interface (basic
COM object features), the standard IConnectionPointContainer
interface (connectable COM object features), the standard
IPersistStreamInit (Stream persistent object features), and
the custom ITextPage interface (TextPage related features).
This multiple interface COM Object Class is achieved via the
technique of nested classes. The implementations of the
various interfaces are nested inside the COTextPage Class.
For a comprehensive tutorial code tour of this module's
contents and offerings see the tutorial PERTEXT.HTM
file. For more specific technical details on the internal
workings see the comments dispersed throughout the module's
source code.
Classes: COTextPage.
Functions: none.
Origin: 5-18-97: atrent - Editor-inheritance from PAPER.CPP in
the STOSERVE Tutorial Code Sample.
----------------------------------------------------------------------------
This file is part of the Microsoft COM Tutorial Code Samples.
Copyright (C) Microsoft Corporation, 1997. All rights reserved.
This source code is intended only as a supplement to Microsoft
Development Tools and/or on-line documentation. See these other
materials for detailed information regarding Microsoft code samples.
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
==========================================================================+*/
/*---------------------------------------------------------------------------
We include WINDOWS.H for all Win32 applications.
We include OLE2.H because we will be calling the COM/OLE Libraries.
We include OLECTL.H because it has definitions for connectable objects.
We include APPUTIL.H because we will be building this application using
the convenient Virtual Window and Dialog classes and other
utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
We include IPAGES.H and PAGEGUID.H for the common TextPage-related
Interface class, GUID, and CLSID specifications.
We include SERVER.H because it has internal class declarations for
the server's control object.
We include CONNECT.H for object class declarations for the various
connection point and connection COM objects used in PERSERVE.
We include TEXTPAGE.H because it has the COTextPage class declarations.
---------------------------------------------------------------------------*/
#include <windows.h>
#include <ole2.h>
#include <olectl.h>
#include <apputil.h>
#include <ipages.h>
#include <pageguid.h>
#include "server.h"
#include "connect.h"
#include "textpage.h"
/*---------------------------------------------------------------------------
COTextPage's implementation of its main COM object class including
Constructor, Destructor, QueryInterface, AddRef, and Release.
---------------------------------------------------------------------------*/
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::COTextPage
Summary: COTextPage Constructor. Note the member initializers like:
"m_ImpITextPage(this, pUnkOuter)" which is used to pass the
'this' and pUnkOuter pointers of the constructor function to
the constructor in the instantiation of the implementation of
the CImpITextPage interface (which is nested inside this present
COTextPage Object Class). Same technique is used for the other
nested interface implementations.
Args: IUnknown* pUnkOuter,
Pointer to the the outer Unknown. NULL means this COM Object
is not being Aggregated. Non-NULL means it is being created
on behalf of an outside COM object that is reusing it via
aggregation.
CServer* pServer)
Pointer to the server's control object.
Modifies: m_cRefs, m_pUnkOuter, m_pServer.
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
COTextPage::COTextPage(
IUnknown* pUnkOuter,
CServer* pServer) :
m_ImpITextPage(this, pUnkOuter),
m_ImpIPersistStreamInit(this, pUnkOuter),
m_ImpIConnectionPointContainer(this, pUnkOuter)
{
UINT i;
// Zero the COM object's reference count.
m_cRefs = 0;
// No AddRef necessary if non-NULL, as we're nested.
m_pUnkOuter = pUnkOuter;
// Assign the pointer to the server control object.
m_pServer = pServer;
// Null all entries in the connection point array.
for (i=0; i<MAX_CONNECTION_POINTS; i++)
m_aConnectionPoints[i] = NULL;
// Now initialize the TextPage itself.
m_pwszPageText = NULL;
m_ClassID = CLSID_TextPage;
m_bInitNew = FALSE;
m_bDirty = TRUE;
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::~COTextPage
Summary: COTextPage Destructor.
Args: void
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
COTextPage::~COTextPage(void)
{
UINT i;
IConnectionPoint* pIConnectionPoint;
// Do final release of the connection point objects.
for (i=0; i<MAX_CONNECTION_POINTS; i++)
{
pIConnectionPoint = m_aConnectionPoints[i];
RELEASE_INTERFACE(pIConnectionPoint);
}
DELETE_POINTER(m_pwszPageText);
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::Init
Summary: COTextPage initialization method. Create any necessary
arrays, structures, and subordinate objects. Rig connectivity.
Args: void
Modifies: m_aConnectionPoints.
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
HRESULT COTextPage::Init(void)
{
HRESULT hr = NOERROR;
COConnectionPoint* pCOConnPt;
// Rig this new COTextPage COM object to be connectable. Assign the
// connection point array. This object's connection points are
// determined at compile time--it currently has only one connection
// point: the CONNPOINT_TEXTPAGESINK connection point. Create a
// connection point object for this and assign it into the array. This
// array could easily grow to support additional connection points in
// the future.
// First try creating a new connection point object. Pass 'this' as the
// pHostObj pointer used by the connection point to pass its AddRef and
// Release calls back to the host connectable object.
pCOConnPt = new COConnectionPoint(this);
if (NULL != pCOConnPt)
{
// If creation succeeded then initialize it (including creating
// its initial dynamic connection array).
hr = pCOConnPt->Init(IID_ITextPageSink);
// If the init succeeded then use QueryInterface to obtain the
// IConnectionPoint interface on the new connection point object.
// The interface pointer is assigned directly into the
// connection point array. The QI also does the needed AddRef.
if (SUCCEEDED(hr))
{
hr = pCOConnPt->QueryInterface(
IID_IConnectionPoint,
(PPVOID)&m_aConnectionPoints[CONNPOINT_TEXTPAGESINK]);
}
if (FAILED(hr))
delete pCOConnPt;
}
else
hr = E_OUTOFMEMORY;
return hr;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::QueryInterface
Summary: QueryInterface of the COTextPage non-delegating IUnknown
implementation.
Args: REFIID riid,
[in] GUID of the Interface being requested.
PPVOID ppv)
[out] Address of the caller's pointer variable that will
receive the requested interface pointer.
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::QueryInterface(
REFIID riid,
PPVOID ppv)
{
HRESULT hr = E_NOINTERFACE;
*ppv = NULL;
if (IID_IUnknown == riid)
*ppv = this;
else if (IID_IConnectionPointContainer == riid)
*ppv = &m_ImpIConnectionPointContainer;
else if (IID_IPersistStreamInit == riid)
*ppv = &m_ImpIPersistStreamInit;
else if (IID_ITextPage == riid)
*ppv = &m_ImpITextPage;
if (NULL != *ppv)
{
// We've handed out a pointer to the interface so obey the COM rules
// and AddRef the reference count.
((LPUNKNOWN)*ppv)->AddRef();
hr = NOERROR;
}
return (hr);
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::AddRef
Summary: AddRef of the COTextPage non-delegating IUnknown implementation.
Args: void
Modifies: m_cRefs.
Returns: ULONG
New value of m_cRefs (COM object's reference count).
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP_(ULONG) COTextPage::AddRef(void)
{
ULONG cRefs;
cRefs = ++m_cRefs;
return cRefs;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::Release
Summary: Release of the COTextPage non-delegating IUnknown implementation.
Args: void
Modifies: m_cRefs.
Returns: ULONG
New value of m_cRefs (COM object's reference count).
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP_(ULONG) COTextPage::Release(void)
{
ULONG cRefs;
cRefs = --m_cRefs;
if (0 == cRefs)
{
// We've reached a zero reference count for this COM object.
// So we tell the server housing to decrement its global object
// count so that the server will be unloaded if appropriate.
if (NULL != m_pServer)
m_pServer->ObjectsDown();
// We artificially bump the main ref count to prevent reentrancy
// via the main object destructor. Not really needed in this
// COTextPage but a good practice because we are aggregatable and
// may at some point in the future add something entertaining like
// some Releases to the COTextPage destructor. We relinquish thread
// ownership of this object prior to deleting it--a good practice.
m_cRefs++;
delete this;
}
return cRefs;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::Clear
Summary: Internal private utility method of this COM object used to
clear the content of the text page.
Args: BOOL bSaveNeeded
Specifies whether the cleared text page should later be
saved to file. TRUE=>later save needed; FALSE=>later save
not needed.
Modifies: m_pwszPageText.
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
HRESULT COTextPage::Clear(
BOOL bSaveNeeded)
{
HRESULT hr = NOERROR;
// Zero the text string array.
if (NULL != m_pwszPageText)
memset(m_pwszPageText, 0, TEXTPAGE_V10_MAX * sizeof(WCHAR));
// Set the Page Properties for this version of TextPages.
m_TextProps.ulVersion = TEXTPAGE_VERSION10;
m_TextProps.ulMaxLength = TEXTPAGE_V10_MAX;
m_TextProps.ulLength = 0;
// Mark TextPage as dirty (ie, needs to be saved to file) if specified.
m_bDirty = bSaveNeeded;
return hr;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::NotifySinks
Summary: Internal utility method of this COM object used to fire event
notification calls to all listening connection sinks in the
client.
Args: TEXTPAGE_EVENT TextPageEvent
Type of TextPage notification event.
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
HRESULT COTextPage::NotifySinks(
TEXTPAGE_EVENT TextPageEvent)
{
HRESULT hr = NOERROR;
IConnectionPoint* pIConnectionPoint;
IEnumConnections* pIEnum;
CONNECTDATA ConnData;
// If there was a TextPage event, broadcast appropriate notifications to
// all Sinks connected to each connection point.
if (TEXTPAGE_EVENT_NONE != TextPageEvent)
{
// Here is the section for the TextPageSink connection point--currently
// this is the only connection point offered by COTextPage objects.
pIConnectionPoint = m_aConnectionPoints[CONNPOINT_TEXTPAGESINK];
if (NULL != pIConnectionPoint)
{
pIConnectionPoint->AddRef();
hr = pIConnectionPoint->EnumConnections(&pIEnum);
if (SUCCEEDED(hr))
{
// Loop thru the connection point's connections and if the
// listening connection supports ITextPageSink (ie, TextPageSink
// events) then dispatch the TextPageEvent event notification to
// that sink.
while (NOERROR == pIEnum->Next(1, &ConnData, NULL))
{
ITextPageSink* pITextPageSink;
hr = ConnData.pUnk->QueryInterface(
IID_ITextPageSink,
(PPVOID)&pITextPageSink);
if (SUCCEEDED(hr))
{
switch (TextPageEvent)
{
case TEXTPAGE_EVENT_LOADED:
pITextPageSink->Loaded();
break;
case TEXTPAGE_EVENT_SAVED:
pITextPageSink->Saved();
break;
case TEXTPAGE_EVENT_PUT:
pITextPageSink->Put();
break;
case TEXTPAGE_EVENT_CLEARED:
pITextPageSink->Cleared();
break;
default:
break;
}
pITextPageSink->Release();
}
ConnData.pUnk->Release();
}
pIEnum->Release();
}
pIConnectionPoint->Release();
}
}
return hr;
}
/*---------------------------------------------------------------------------
COTextPage's nested implementation of the COM standard
IConnectionPointContainer interface including Constructor, Destructor,
QueryInterface, AddRef, Release, FindConnectionPoint, and
EnumConnectionPoints.
---------------------------------------------------------------------------*/
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIConnectionPointContainer
::CImpIConnectionPointContainer
Summary: Constructor for the CImpIConnectionPointContainer interface
instantiation.
Args: COTextPage* pCO,
Back pointer to the parent outer object.
IUnknown* pUnkOuter
Pointer to the outer Unknown. For delegation.
Modifies: m_pCO, m_pUnkOuter.
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
COTextPage::CImpIConnectionPointContainer::CImpIConnectionPointContainer(
COTextPage* pCO,
IUnknown* pUnkOuter)
{
// Init the Main Object Pointer to point to the parent object.
m_pCO = pCO;
// Init the CImpIConnectionPointContainer interface's delegating Unknown
// pointer. We use the Main Object pointer for IUnknown delegation here
// if we are not being aggregated. If we are being aggregated we use
// the supplied pUnkOuter for IUnknown delegation. In either case the
// pointer assignment requires no AddRef because the
// CImpIConnectionPointContainer lifetime is quaranteed by the lifetime
// of the parent object in which CImpIConnectionPointContainer is
// nested.
if (NULL == pUnkOuter)
m_pUnkOuter = pCO;
else
m_pUnkOuter = pUnkOuter;
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIConnectionPointContainer
::~CImpIConnectionPointContainer
Summary: Destructor for the CImpIConnectionPointContainer interface
instantiation.
Args: void
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
COTextPage::CImpIConnectionPointContainer::~CImpIConnectionPointContainer(void)
{
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIConnectionPointContainer::QueryInterface
Summary: The QueryInterface IUnknown member of this ITextPage interface
implementation that delegates to m_pUnkOuter, whatever it is.
Args: REFIID riid,
[in] GUID of the Interface being requested.
PPVOID ppv)
[out] Address of the caller's pointer variable that will
receive the requested interface pointer.
Returns: HRESULT
Standard result code. NOERROR for success.
Returned by the delegated outer QueryInterface call.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpIConnectionPointContainer::QueryInterface(
REFIID riid,
PPVOID ppv)
{
// Delegate this call to the outer object's QueryInterface.
return m_pUnkOuter->QueryInterface(riid, ppv);
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIConnectionPointContainer::AddRef
Summary: The AddRef IUnknown member of this ITextPage interface
implementation that delegates to m_pUnkOuter, whatever it is.
Args: void
Returns: ULONG
Returned by the delegated outer AddRef call.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP_(ULONG) COTextPage::CImpIConnectionPointContainer::AddRef(void)
{
// Delegate this call to the outer object's AddRef.
return m_pUnkOuter->AddRef();
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIConnectionPointContainer::Release
Summary: The Release IUnknown member of this ITextPage interface
implementation that delegates to m_pUnkOuter, whatever it is.
Args: void
Returns: ULONG
Returned by the delegated outer Release call.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP_(ULONG) COTextPage::CImpIConnectionPointContainer::Release(void)
{
// Delegate this call to the outer object's Release.
return m_pUnkOuter->Release();
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIConnectionPointContainer::FindConnectionPoint
Summary: Given an IID for a connection point sink find and return the
interface pointer for that connection point sink.
Args: REFIID riid
Reference to an IID
IConnectionPoint** ppConnPt
Address of the caller's IConnectionPoint interface pointer
variable that will receive the requested interface pointer.
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpIConnectionPointContainer::FindConnectionPoint(
REFIID riid,
IConnectionPoint** ppConnPt)
{
HRESULT hr = E_NOINTERFACE;
IConnectionPoint* pIConnPt;
// NULL the output variable.
*ppConnPt = NULL;
pIConnPt = m_pCO->m_aConnectionPoints[CONNPOINT_TEXTPAGESINK];
if (NULL != pIConnPt)
{
// This connectable COTextPage object currently has only the
// TextPage Sink connection point. If the associated interface is
// requested, use QI to get the Connection Point interface and
// perform the needed AddRef.
if (IID_ITextPageSink == riid)
hr = pIConnPt->QueryInterface(
IID_IConnectionPoint,
(PPVOID)ppConnPt);
}
return hr;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIConnectionPointContainer::EnumConnectionPoints
Summary: Return Enumerator for the connectable object's contained
connection points.
Args: IEnumConnectionPoints** ppIEnum
Address of the caller's Enumerator interface pointer
variable. An output variable that will receive a pointer to
the connection point enumerator COM object.
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpIConnectionPointContainer::EnumConnectionPoints(
IEnumConnectionPoints** ppIEnum)
{
HRESULT hr = NOERROR;
IConnectionPoint* aConnPts[MAX_CONNECTION_POINTS];
COEnumConnectionPoints* pCOEnum;
UINT i;
// Zero the output interface pointer.
*ppIEnum = NULL;
// Make a copy on the stack of the array of connection point
// interfaces. The copy is used below in the creation of the new
// Enumerator object.
for (i=0; i<MAX_CONNECTION_POINTS; i++)
aConnPts[i] = (IConnectionPoint*)m_pCO->m_aConnectionPoints[i];
// Create a Connection Point enumerator COM object for the connection
// points offered by this COTextPage object. Pass 'this' to be used to
// hook the lifetime of the host object to the life time of this
// enumerator object.
pCOEnum = new COEnumConnectionPoints(this);
if (NULL != pCOEnum)
{
// Use the array copy to Init the new Enumerator COM object.
// Set the initial Enumerator index to 0.
hr = pCOEnum->Init(MAX_CONNECTION_POINTS, aConnPts, 0);
if (SUCCEEDED(hr))
{
// QueryInterface to return the requested interface pointer.
// An AddRef will be conveniently done by the QI.
if (SUCCEEDED(hr))
hr = pCOEnum->QueryInterface(
IID_IEnumConnectionPoints,
(PPVOID)ppIEnum);
}
}
else
hr = E_OUTOFMEMORY;
return hr;
}
/*---------------------------------------------------------------------------
COTextPage's nested implementation of the COM standard
IPersistStreamInit interface including Constructor, Destructor,
QueryInterface, AddRef, Release, GetClassID, IsDirty, Load, Save,
GetSizeMax, and InitNew.
---------------------------------------------------------------------------*/
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIPersistStreamInit::CImpIPersistStreamInit
Summary: Constructor for the CImpIPersistStreamInit interface
instantiation.
Args: COTextPage* pCO,
Back pointer to the parent outer object.
IUnknown* pUnkOuter
Pointer to the outer Unknown. For delegation.
Modifies: m_pCO, m_pUnkOuter.
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
COTextPage::CImpIPersistStreamInit::CImpIPersistStreamInit(
COTextPage* pCO,
IUnknown* pUnkOuter)
{
// Init the Main Object Pointer to point to the parent object.
m_pCO = pCO;
// Init the CImpIPersistStreamInit interface's delegating IUnknown
// pointer. We use the Main Object pointer for IUnknown delegation here
// if we are not being aggregated. If we are being aggregated we use
// the supplied pUnkOuter for IUnknown delegation. In either case the
// pointer assignment requires no AddRef because the
// pIPersistStreamInit lifetime is quaranteed by the lifetime of the
// parent object in which CImpIPersistStreamInit is nested.
if (NULL == pUnkOuter)
m_pUnkOuter = pCO;
else
m_pUnkOuter = pUnkOuter;
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIPersistStreamInit::~CImpIPersistStreamInit
Summary: Destructor for the CImpIPersistStreamIint interface
instantiation.
Args: void
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
COTextPage::CImpIPersistStreamInit::~CImpIPersistStreamInit(void)
{
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIPersistStreamInit::QueryInterface
Summary: The QueryInterface IUnknown member of this interface
implementation that delegates to m_pUnkOuter, whatever it is.
Args: REFIID riid,
[in] GUID of the Interface being requested.
PPVOID ppv)
[out] Address of the caller's pointer variable that will
receive the requested interface pointer.
Returns: HRESULT
Standard result code. NOERROR for success.
Returned by the delegated outer QueryInterface call.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpIPersistStreamInit::QueryInterface(
REFIID riid,
PPVOID ppv)
{
// Delegate this call to the outer object's QueryInterface.
return m_pUnkOuter->QueryInterface(riid, ppv);
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIPersistStreamInit::AddRef
Summary: The AddRef IUnknown member of this interface implementation
that delegates to m_pUnkOuter, whatever it is.
Args: void
Returns: ULONG
Returned by the delegated outer AddRef call.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP_(ULONG) COTextPage::CImpIPersistStreamInit::AddRef(void)
{
// Delegate this call to the outer object's AddRef.
return m_pUnkOuter->AddRef();
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIPersistStreamInit::Release
Summary: The Release IUnknown member of this interface implementation
that delegates to m_pUnkOuter, whatever it is.
Args: void
Returns: ULONG
Returned by the delegated outer Release call.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP_(ULONG) COTextPage::CImpIPersistStreamInit::Release(void)
{
// Delegate this call to the outer object's Release.
return m_pUnkOuter->Release();
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIPersistStreamInit::GetClassID
Summary: A method inherited from IPersist. Get the Class ID of this
COM object.
Args: CLSID* pClassID
[out] Address of variable to hold Class ID.
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpIPersistStreamInit::GetClassID(
CLSID* pClassID)
{
HRESULT hr = E_POINTER;
if (NULL != pClassID)
{
// Use overloaded '=' operator to copy the Class ID to caller.
*pClassID = m_pCO->m_ClassID;
hr = NOERROR;
}
return hr;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIPersistStreamInit::IsDirty
Summary: Called to determine if changes were made to this COM object
since it was last loaded or initialized.
Args: none.
Returns: HRESULT
Standard result code. S_OK if dirty; S_FALSE if not.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpIPersistStreamInit::IsDirty(
void)
{
HRESULT hr;
hr = m_pCO->m_bDirty ? S_OK : S_FALSE;
return hr;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIPersistStreamInit::Load
Summary: Asks this COM object to load its persistent data from the
specified stream at the current seek pointer. This function
assumes the seek pointer is the same as it was before Save
was last called. This function must leave the seek pointer
the same as it was after Save was last completed regardless
of success or failure. This function should not keep a copy
of pIStream in the COM object after it completes.
Load is called INSTEAD of InitNew when this COM object already
has a persistent state stored in a stream. Notifies all other
connected clients when the load is complete.
Args: IStream* pIStream
IStream interface pointer for stream to load from. This
COM object must NOT retain a copy of this IStream pointer
after this call completes.
Returns: HRESULT
Standard result code. NOERROR for success. E_UNEXPECTED if
an InitNew or Load has already been called.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpIPersistStreamInit::Load(
IStream* pIStream)
{
HRESULT hr = E_POINTER;
ULONG ulToRead, ulReadIn;
TEXTPROPS NewProps;
WCHAR* pwszPageText;
if (NULL != pIStream)
{
if (!m_pCO->m_bInitNew)
{
// We have the TextPage data stream. First read the TextPage
// Properties.
ulToRead = sizeof(TEXTPROPS);
hr = pIStream->Read(
&NewProps,
ulToRead,
&ulReadIn);
if (SUCCEEDED(hr) && ulToRead != ulReadIn)
hr = E_FAIL;
if (SUCCEEDED(hr))
{
// Deal with the different versions.
switch (NewProps.ulVersion)
{
case TEXTPAGE_VERSION10:
if (NewProps.ulMaxLength <= TEXTPAGE_V10_MAX)
{
// Allocate an page text array big enough for the largest
// text page.
pwszPageText = new WCHAR[(ULONG) NewProps.ulMaxLength];
if (NULL != pwszPageText)
{
m_pCO->m_pwszPageText = pwszPageText;
// First zero the page text area.
memset(
pwszPageText,
0,
NewProps.ulMaxLength * sizeof(WCHAR));
ulToRead = NewProps.ulLength * sizeof(WCHAR);
if (ulToRead >= 0 && ulToRead < (ULONG)NewProps.ulMaxLength)
{
// Now read in the complete text page.
hr = pIStream->Read(
pwszPageText,
ulToRead,
&ulReadIn);
if (SUCCEEDED(hr) && ulToRead != ulReadIn)
hr = E_FAIL;
if (SUCCEEDED(hr))
{
// Copy the new properties into current properties.
memcpy(
&m_pCO->m_TextProps,
&NewProps,
sizeof(TEXTPROPS));
// We are loaded and clean (ie, COTextPage data
// matches file data). Clear dirty flag.
m_pCO->m_bDirty = FALSE;
}
}
else
hr = E_FAIL;
}
else
hr = E_OUTOFMEMORY;
}
break;
default:
hr = E_FAIL; // Bad version.
break;
}
}
}
else
hr = E_UNEXPECTED;
}
// Notify all other connected clients that TextPage is now loaded.
// If we didn't load then clear to a safe, empty text page.
if (SUCCEEDED(hr))
m_pCO->NotifySinks(TEXTPAGE_EVENT_LOADED);
else
m_pCO->Clear(TRUE);
return hr;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIPersistStreamInit::Save
Summary: Called to save the persistent data of this COM object to a
stream using the specified IStream interface. This call stores
data from the current seek pointer offset. On exit from this
method the seek pointer is assumed to be just past the end of
the data saved. This allows a series of contiguous persistent
objects to be saved into the same stream. Notifies all other
connected clients when the save is complete.
Args: IStream* pIStream
IStream interface pointer for stream to load from. This
COM object must NOT retain a copy of this IStream pointer
after the function completes.
BOOL bClearDirty
Determines if this method should clear the COM object's
dirty flag. If bClearDirty is TRUE then clear the dirty
flag.
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpIPersistStreamInit::Save(
IStream* pIStream,
BOOL bClearDirty)
{
HRESULT hr = E_POINTER;
ULONG ulToWrite, ulWritten;
if (NULL != pIStream)
{
// Got a stream. Now write data into it.
// First write TEXTPROPS structure.
ulToWrite = sizeof(TEXTPROPS);
hr = pIStream->Write(&m_pCO->m_TextProps, ulToWrite, &ulWritten);
if (SUCCEEDED(hr) && ulToWrite != ulWritten)
hr = STG_E_CANTSAVE;
if (SUCCEEDED(hr))
{
// Now write the complete page text data.
ulToWrite = m_pCO->m_TextProps.ulLength * sizeof(WCHAR);
hr = pIStream->Write(m_pCO->m_pwszPageText, ulToWrite, &ulWritten);
if (SUCCEEDED(hr) && ulToWrite != ulWritten)
hr = STG_E_CANTSAVE;
if (SUCCEEDED(hr))
{
// Clear this COM object's dirty flag if instructed.
if (bClearDirty)
m_pCO->m_bDirty = FALSE;
}
}
}
// Notify all other connected clients that TextPage is now saved.
if (SUCCEEDED(hr))
m_pCO->NotifySinks(TEXTPAGE_EVENT_SAVED);
return hr;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIPersistStreamInit::GetSizeMax
Summary: Called to obtain the maximum possible total size of the
chunks of data that could be saved when Save is next called.
Args: ULARGE_INTEGER* pcbSize
Address of the caller's variable to receive the size (bytes).
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpIPersistStreamInit::GetSizeMax(
ULARGE_INTEGER* pcbSize)
{
HRESULT hr = E_POINTER;
ULONG ulMax = m_pCO->m_TextProps.ulMaxLength;
if (NULL != pcbSize)
{
ULISet32(*pcbSize, sizeof(TEXTPROPS) + (ulMax * sizeof(WCHAR)));
hr = NOERROR;
}
return hr;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpIPersistStreamInit::InitNew
Summary: Called to tell the object that it has been newly created and
has no existing persistent state already stored.
InitNew is called INSTEAD of Load when the new object instance
must be initialized with brand new data rather than with
persistent data previously saved in a stream.
Args: none.
Modifies: m_pwszPageText, m_aConnectionPoints.
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpIPersistStreamInit::InitNew(
void)
{
HRESULT hr = E_FAIL;
WCHAR* pwszPageText;
if (!m_pCO->m_bInitNew)
{
// There is no previous persistent data for this COTextPage object.
// Create and init a new set of persistence data for an empty text page.
// Allocate an page text array big enough for the largest text page.
// This maximum is hard-coded here for this Version 1.0 of Text Pages.
pwszPageText = new WCHAR[(LONG) TEXTPAGE_V10_MAX];
if (NULL != pwszPageText)
{
m_pCO->m_pwszPageText = pwszPageText;
// Use the private Clear method to clear the new text array and to
// set the Page Properties structure appropriately. Also sets dirty.
hr = m_pCO->Clear(TRUE);
m_pCO->m_bInitNew = TRUE;
}
else
hr = E_OUTOFMEMORY;
}
else
hr = E_UNEXPECTED;
return hr;
}
/*---------------------------------------------------------------------------
COTextPage's nested implementation of the custom ITextPage interface
including Constructor, Destructor, QueryInterface, AddRef, Release,
GetFirst, GetNext, Add, Delete, and Clear.
---------------------------------------------------------------------------*/
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpITextPage::CImpITextPage
Summary: Constructor for the CImpITextPage interface instantiation.
Args: COTextPage* pCO,
Back pointer to the parent outer object.
IUnknown* pUnkOuter
Pointer to the outer Unknown. For delegation.
Modifies: m_pCO, m_pUnkOuter.
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
COTextPage::CImpITextPage::CImpITextPage(
COTextPage* pCO,
IUnknown* pUnkOuter)
{
// Init the Main Object Pointer to point to the parent object.
m_pCO = pCO;
// Init the CImpITextPage interface's delegating IUnknown pointer. We
// use the Main Object pointer for IUnknown delegation here if we are
// not being aggregated. If we are being aggregated we use the supplied
// pUnkOuter for IUnknown delegation. In either case the pointer
// assignment requires no AddRef because the CImpITextPage lifetime is
// quaranteed by the lifetime of the parent object in which
// CImpITextPage is nested.
if (NULL == pUnkOuter)
m_pUnkOuter = pCO;
else
m_pUnkOuter = pUnkOuter;
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpITextPage::~CImpITextPage
Summary: Destructor for the CImpITextPage interface instantiation.
Args: void
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
COTextPage::CImpITextPage::~CImpITextPage(void)
{
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpITextPage::QueryInterface
Summary: The QueryInterface IUnknown member of this ITextPage interface
implementation that delegates to m_pUnkOuter, whatever it is.
Args: REFIID riid,
[in] GUID of the Interface being requested.
PPVOID ppv)
[out] Address of the caller's pointer variable that will
receive the requested interface pointer.
Returns: HRESULT
Standard result code. NOERROR for success.
Returned by the delegated outer QueryInterface call.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpITextPage::QueryInterface(
REFIID riid,
PPVOID ppv)
{
// Delegate this call to the outer object's QueryInterface.
return m_pUnkOuter->QueryInterface(riid, ppv);
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpITextPage::AddRef
Summary: The AddRef IUnknown member of this ITextPage interface
implementation that delegates to m_pUnkOuter, whatever it is.
Args: void
Returns: ULONG
Returned by the delegated outer AddRef call.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP_(ULONG) COTextPage::CImpITextPage::AddRef(void)
{
// Delegate this call to the outer object's AddRef.
return m_pUnkOuter->AddRef();
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpITextPage::Release
Summary: The Release IUnknown member of this ITextPage interface
implementation that delegates to m_pUnkOuter, whatever it is.
Args: void
Returns: ULONG
Returned by the delegated outer Release call.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP_(ULONG) COTextPage::CImpITextPage::Release(void)
{
// Delegate this call to the outer object's Release.
return m_pUnkOuter->Release();
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpITextPage::GetLength
Summary: Get the current length (in WCHARs) of the text page.
Args: INT* piLength
Address of the caller's variable that is assigned the length.
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpITextPage::GetLength(
INT* piLength)
{
HRESULT hr = E_POINTER;
if (NULL != piLength)
{
*piLength = (INT) m_pCO->m_TextProps.ulLength;
hr = NOERROR;
}
return hr;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpITextPage::GetText
Summary: Get the current page text held in this object.
Args: WCHAR* pwszPageText
Address of a wide character string to receive the text
data of the text page.
Returns: HRESULT
Standard result code. NOERROR for success. E_POINTER if
NULL passed for the output string pointer.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpITextPage::GetText(
WCHAR* pwszPageText)
{
HRESULT hr = E_POINTER;
if (NULL != pwszPageText && NULL != m_pCO->m_pwszPageText)
{
// Copy the Text Page's text to the caller.
memcpy(
pwszPageText,
m_pCO->m_pwszPageText,
m_pCO->m_TextProps.ulLength * sizeof(WCHAR));
hr = NOERROR;
}
return hr;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpITextPage::PutText
Summary: Put specified text into the Text Page COM object. This does
not save the text persistently.
Args: WCHAR* pwszPageText,
Address of the wide character string to put into the text
page.
INT iLength)
Length in wide characters of the string.
Returns: HRESULT
Standard result code. NOERROR for success. E_POINTER if
NULL passed for the input string.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpITextPage::PutText(
WCHAR* pwszPageText,
INT iLength)
{
HRESULT hr = E_POINTER;
if (NULL != pwszPageText && NULL != m_pCO->m_pwszPageText)
{
if (iLength < (INT) m_pCO->m_TextProps.ulMaxLength)
{
// Copy the Caller's text into the text page.
memcpy(
m_pCO->m_pwszPageText,
pwszPageText,
iLength * sizeof(WCHAR));
// Set the new current length.
m_pCO->m_TextProps.ulLength = (ULONG)iLength;
// Mark TextPage as dirty. Subsequent save to file is needed.
m_pCO->m_bDirty = TRUE;
// Notify all other connected clients that the new text was
// put into the COTextPage object.
m_pCO->NotifySinks(TEXTPAGE_EVENT_PUT);
hr = NOERROR;
}
else
hr = E_FAIL;
}
return hr;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COTextPage::CImpITextPage::Clear
Summary: Clears the entire text page. Sets dirty flag if specified.
Reassigns the page properties as appropriate. Notifies clients
of this event.
Args: BOOL bSaveNeeded
Specifies whether the cleared text page should later be
saved to file. TRUE=>later save needed; FALSE=>later save
not needed.
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
STDMETHODIMP COTextPage::CImpITextPage::Clear(
BOOL bSaveNeeded)
{
HRESULT hr = E_FAIL;
hr = m_pCO->Clear(bSaveNeeded);
// Notify all other connected clients that the list was cleared.
if (SUCCEEDED(hr))
m_pCO->NotifySinks(TEXTPAGE_EVENT_CLEARED);
return hr;
}