The EX27B Example -- A Persistent DLL Component

The EX27B program, which is used by EX27C, is a COM DLL that contains the CText component. This is a simple COM class that implements the IDispatch and IPersistStream interfaces. The IDispatch interface allows access to the component's one and only property, Text, and the IPersistStream interface allows an object to save and load that Text property to and from a structured storage file.

To prepare EX27B, open the \vcpp32\ex27b\ex27b.dsw workspace and build the project. Use regsvr32 or REGCOMP to register the DLL.

Figure 27-4 lists the code for the CText class in Text.h and Text.cpp.

TEXT.H

 #ifndef __TEXT_H__ #define __TEXT_H__ // CText command target class CText : public CCmdTarget { private:     char* m_pchText;     DECLARE_DYNCREATE(CText)     CText();           // protected constructor used by dynamic creation // Attributes public: // Operations public: // Overrides     // ClassWizard generated virtual function overrides     //{{AFX_VIRTUAL(CText)     public:     virtual void OnFinalRelease();     //}}AFX_VIRTUAL // Implementation protected:     virtual ~CText(); // Generated message map functions     //{{AFX_MSG(CText)         // NOTE the ClassWizard will add and remove member functions here.     //}}AFX_MSG     DECLARE_MESSAGE_MAP()     DECLARE_OLECREATE(CText)     // Generated OLE dispatch map functions     //{{AFX_DISPATCH(CText)     afx_msg VARIANT GetText();     afx_msg void SetText(const VARIANT FAR& newValue);     //}}AFX_DISPATCH     DECLARE_DISPATCH_MAP()     DECLARE_INTERFACE_MAP()     BEGIN_INTERFACE_PART(PersistStream, IPersistStream)         STDMETHOD(GetClassID)(LPCLSID);         STDMETHOD(IsDirty)();         STDMETHOD(Load)(LPSTREAM);         STDMETHOD(Save)(LPSTREAM, BOOL);         STDMETHOD(GetSizeMax)(ULARGE_INTEGER FAR*);     END_INTERFACE_PART(PersistStream) }; ////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations //  immediately before the previous line. #endif // __TEXT_H__ 

TEXT.CPP

 #include "stdafx.h" #include "ex27b.h" #include "Text.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] =__FILE__; #endif ////////////////////////////////////////////////////////////////////// // CText IMPLEMENT_DYNCREATE(CText, CCmdTarget) CText::CText() {     EnableAutomation();     // To keep the application running as long as an OLE automation      //  object is active, the constructor calls AfxOleLockApp.     AfxOleLockApp();     m_pchText = NULL; } CText::~CText() {     // To terminate the application when all objects created     //  with OLE automation, the destructor calls AfxOleUnlockApp.     if(m_pchText != NULL) {         delete [] m_pchText;     }     AfxOleUnlockApp(); } void CText::OnFinalRelease() {     // When the last reference for an automation object is released,     //  OnFinalRelease is called. The base class will automatically     //  delete the object. Add additional cleanup required for your     //  object before calling the base class.     CCmdTarget::OnFinalRelease(); } BEGIN_MESSAGE_MAP(CText, CCmdTarget)     //{{AFX_MSG_MAP(CText)         // NOTE - ClassWizard will add and remove mapping macros here.     //}}AFX_MSG_MAP END_MESSAGE_MAP() BEGIN_DISPATCH_MAP(CText, CCmdTarget)     //{{AFX_DISPATCH_MAP(CText)     DISP_PROPERTY_EX(CText, "Text", GetText, SetText, VT_VARIANT)     //}}AFX_DISPATCH_MAP END_DISPATCH_MAP() // Note: we add support for IID_IText to support typesafe binding //  from VBA. This IID must match the GUID that is attached to the  //  dispinterface in the ODL file. // {4EBFDD71-5F7D-11D0-848F-00400526305B} static const IID IID_IText = { 0x4ebfdd71, 0x5f7d, 0x11d0, { 0x84, 0x8f, 0x0, 0x40, 0x5, 0x26,      0x30, 0x5b } }; BEGIN_INTERFACE_MAP(CText, CCmdTarget)     INTERFACE_PART(CText, IID_IPersistStream, PersistStream)     INTERFACE_PART(CText, IID_IText, Dispatch) END_INTERFACE_MAP() // {4EBFDD72-5F7D-11D0-848F-00400526305B} IMPLEMENT_OLECREATE(CText, "Ex27b.Text", 0x4ebfdd72, 0x5f7d,      0x11d0, 0x84, 0x8f, 0x0, 0x40, 0x5, 0x26, 0x30, 0x5b) ////////////////////////////////////////////////////////////////////// // CText message handlers VARIANT CText::GetText()  {     return COleVariant(m_pchText).Detach(); } void CText::SetText(const VARIANT FAR& newValue)  {     CString strTemp;     ASSERT(newValue.vt == VT_BSTR);     if(m_pchText != NULL) {         delete [] m_pchText;     }     strTemp = newValue.bstrVal; // converts to narrow chars     m_pchText = new char[strTemp.GetLength() + 1];     strcpy(m_pchText, strTemp); } ////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) CText::XPersistStream::AddRef() {     METHOD_PROLOGUE(CText, PersistStream)     return (ULONG) pThis->ExternalAddRef(); } STDMETHODIMP_(ULONG) CText::XPersistStream::Release() {     METHOD_PROLOGUE(CText, PersistStream)     return (ULONG) pThis->ExternalRelease(); } STDMETHODIMP CText::XPersistStream::QueryInterface(REFIID iid,     void FAR* FAR* ppvObj) {     METHOD_PROLOGUE(CText, PersistStream)     // ExternalQueryInterface looks up IID in the macro-generated tables     return (HRESULT) pThis->ExternalQueryInterface(&iid, ppvObj); } ////////////////////////////////////////////////////////////////////// STDMETHODIMP CText::XPersistStream::GetClassID(LPCLSID lpClassID) {     TRACE("Entering CText::XPersistStream::GetClassID\n");     METHOD_PROLOGUE(CText, PersistStream)     ASSERT_VALID(pThis);     *lpClassID = CText::guid;     return NOERROR; } STDMETHODIMP CText::XPersistStream::IsDirty() {     TRACE("Entering CText::XPersistStream::IsDirty\n");     METHOD_PROLOGUE(CText, PersistStream)     ASSERT_VALID(pThis);     return NOERROR; } STDMETHODIMP CText::XPersistStream::Load(LPSTREAM pStm) {     ULONG nLength;     STATSTG statstg;     METHOD_PROLOGUE(CText, PersistStream)     ASSERT_VALID(pThis);     if(pThis->m_pchText != NULL) {         delete [] pThis->m_pchText;     }     // don't need to free statstg.pwcsName because of NONAME flag     VERIFY(pStm->Stat(&statstg, STATFLAG_NONAME) == NOERROR);     int nSize = statstg.cbSize.LowPart; // assume < 4 GB     if(nSize > 0) {         pThis->m_pchText = new char[nSize];         pStm->Read(pThis->m_pchText, nSize, &nLength);     }     return NOERROR; } STDMETHODIMP CText::XPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty) {     METHOD_PROLOGUE(CText, PersistStream)     ASSERT_VALID(pThis);     int nSize = strlen(pThis->m_pchText) + 1;     pStm->Write(pThis->m_pchText, nSize, NULL);     return NOERROR; } STDMETHODIMP CText::XPersistStream::GetSizeMax(ULARGE_INTEGER FAR* pcbSize) {     TRACE("Entering CText::XPersistStream::GetSizeMax\n");     METHOD_PROLOGUE(CText, PersistStream)     ASSERT_VALID(pThis);     pcbSize->LowPart = strlen(pThis->m_pchText) + 1;     pcbSize->HighPart = 0; // assume < 4 GB     return NOERROR; } 

Figure 27-4. The code listing for the CText class in Text.h and Text.cpp.

ClassWizard generated the CText class as an ordinary Automation component. The IPersistStream interface was added manually. Look carefully at the XPersistStream::Load and XPersistStream::Save functions. The Load function allocates heap memory and then calls IStream::Read to load the contents of the stream. The Save function copies the object's data to the stream by calling IStream::Write.



Programming Microsoft Visual C++
Programming Microsoft Visual C++
ISBN: 1572318570
EAN: 2147483647
Year: 1997
Pages: 332

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net