| Tenouk C & C++ | MFC Home | OLE & Containers 5 | OLE & Containers 7 | Download | Site Index |


 

 

 

 

 

OLE Embedded Components and Containers part 6

 

 

 

 

 

 

Program examples compiled using Visual C++ 6.0 compiler on Windows XP Pro machine with Service Pack 2. The Excel version is Excel 2003/Office 11. Topics and sub topics for this tutorial are listed below. Don’t forget to read Tenouk’s small disclaimer. The supplementary notes for this tutorial are IOleObject and OLE.

  1. GetSize()

  2. SetNames()

  3. SetViewAdvise()

  4. MakeMetafilePict()

  5. SaveObject()

  6. DoPasteObjectDescriptor()

  7. DoPasteObject()

  8. The CEx32bDoc Class

 

Study the message map and the associated command handlers. They're all relatively short, and they mostly call the OLE functions described earlier. A few private helper functions need some explanation, however.

You'll see many calls to a GetInterface() function. This is a member of class CCmdTarget and returns the specified OLE interface pointer for a class in your project. It's used mostly to get the IOleClientSite interface pointer for your document. It's more efficient than calling ExternalQueryInterface(), but it doesn't increment the object's reference count.

 

GetSize()

 

This function calls IOleObject::GetSize to get the embedded object's extents, which it converts to a rectangle for storage in the tracker.

 

SetNames()

 

The SetNames function calls IOleObject::SetHostNames to send the container application's name to the component.

 

SetViewAdvise()

 

This function calls the embedded object's IViewObject2::SetAdvise function to set up the advisory connection from the component object to the container document.

 

MakeMetafilePict()

 

The MakeMetafilePict() function calls the embedded object's IDataObject::GetData function to get a metafile picture to copy to the clipboard data object. A metafile picture, by the way, is a Windows METAFILEPICT structure instance, which contains a pointer to the metafile plus extent information.

 

SaveObject()

 

This function acts like the SaveDib() function in the EX25A example. It creates a COleDataSource object with three formats: embedded object, metafile, and object descriptor.

 

DoPasteObjectDescriptor()

 

The DoPasteObjectDescriptor() function pastes an object descriptor from the clipboard but doesn't do anything with it. This function must be called prior to calling DoPasteObject().

 

 

DoPasteObject()

 

This function calls OleCreateFromData() to create an embedded object from an embedded object format on the clipboard.

 

The CEx32bDoc Class

 

This class implements the IOleClientSite and IAdviseSink interfaces. Because of our one-embedded-item-per-document simplification, we don't need to track separate site objects. The document is the site. We're using the standard MFC interface macros, and, as always, we must provide at least a skeleton function for all interface members.

Look carefully at the functions XOleClientSite::SaveObject, XOleClientSite::OnShowWindow, and XAdviseSink::OnViewChange in Listing 38. They're the important ones. The other ones are less important, but they contain TRACE statements as well, so you can watch the functions as they're called by the handler. Look also at the OnNewDocument(), OnCloseDocument(), and DeleteContents() functions of the CEx32bView class. Notice how the document is managing a temporary storage. The document's m_pTempStgSub data member holds the storage pointer for the embedded object, and the m_lpOleObj data member holds the embedded object's IOleObject pointer.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

EX32BDOC.H

 

// ex32bDoc.h : interface of the CEx32bDoc class

//

/////////////////////////////////////////////////////////////////////////////

 

#if !defined(AFX_EX32BDOC_H__5C6DE978_9660_4229_887E_9A63ECF07A05__INCLUDED_)

#define AFX_EX32BDOC_H__5C6DE978_9660_4229_887E_9A63ECF07A05__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

void ITrace(REFIID iid, const char* str);

 

class CEx32bDoc : public CDocument

{

protected: // create from serialization only

       CEx32bDoc();

       DECLARE_DYNCREATE(CEx32bDoc)

 

       BEGIN_INTERFACE_PART(OleClientSite, IOleClientSite)

              STDMETHOD(SaveObject)();

              STDMETHOD(GetMoniker)(DWORD, DWORD, LPMONIKER*);

              STDMETHOD(GetContainer)(LPOLECONTAINER*);

              STDMETHOD(ShowObject)();

              STDMETHOD(OnShowWindow)(BOOL);

              STDMETHOD(RequestNewObjectLayout)();

       END_INTERFACE_PART(OleClientSite)

 

       BEGIN_INTERFACE_PART(AdviseSink, IAdviseSink)

              STDMETHOD_(void,OnDataChange)(LPFORMATETC, LPSTGMEDIUM);

              STDMETHOD_(void,OnViewChange)(DWORD, LONG);

              STDMETHOD_(void,OnRename)(LPMONIKER);

              STDMETHOD_(void,OnSave)();

              STDMETHOD_(void,OnClose)();

       END_INTERFACE_PART(AdviseSink)

 

       DECLARE_INTERFACE_MAP()

 

friend class CEx32bView;

 

private:

       LPOLEOBJECT m_lpOleObj;

       LPSTORAGE m_pTempStgRoot;

       LPSTORAGE m_pTempStgSub;

       BOOL m_bHatch;

       static const OLECHAR* s_szSub;

 

// Attributes

public:

 

// Operations

public:

 

// Overrides

       // ClassWizard generated virtual function overrides

       //{{AFX_VIRTUAL(CEx32bDoc)

       public:

       virtual BOOL OnNewDocument();

       virtual void Serialize(CArchive& ar);

       virtual void DeleteContents();

       virtual void OnCloseDocument();

       protected:

       virtual BOOL SaveModified();

       //}}AFX_VIRTUAL

 

// Implementation

public:

       virtual ~CEx32bDoc();

#ifdef _DEBUG

       virtual void AssertValid() const;

       virtual void Dump(CDumpContext& dc) const;

#endif

 

protected:

 

// Generated message map functions

protected:

       //{{AFX_MSG(CEx32bDoc)

       afx_msg void OnEditClearAll();

       //}}AFX_MSG

       DECLARE_MESSAGE_MAP()

};

 

/////////////////////////////////////////////////////////////////////////////

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

 

#endif // !defined(AFX_EX32BDOC_H__5C6DE978_9660_4229_887E_9A63ECF07A05__INCLUDED_)

 

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

EX32BDOC.CPP

 

// ex32bDoc.cpp : implementation of the CEx32bDoc class

//

 

#include "stdafx.h"

#include "ex32b.h"

 

#include "ex32bDoc.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[ ] = __FILE__;

#endif

 

const OLECHAR* CEx32bDoc::s_szSub = L"sub";   // static

 

/////////////////////////////////////////////////////////////////////////////

// CEx32bDoc

 

IMPLEMENT_DYNCREATE(CEx32bDoc, CDocument)

 

BEGIN_MESSAGE_MAP(CEx32bDoc, CDocument)

       //{{AFX_MSG_MAP(CEx32bDoc)

       ON_COMMAND(ID_EDIT_CLEAR_ALL, OnEditClearAll)

       //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

BEGIN_INTERFACE_MAP(CEx32bDoc, CDocument)

       INTERFACE_PART(CEx32bDoc, IID_IOleClientSite, OleClientSite)

       INTERFACE_PART(CEx32bDoc, IID_IAdviseSink, AdviseSink)

END_INTERFACE_MAP()

 

/////////////////////////////////////////////////////////////////////////////

// Implementation of IOleClientSite

 

STDMETHODIMP_(ULONG) CEx32bDoc::XOleClientSite::AddRef()

{

       TRACE("CEx32bDoc::XOleClientSite::AddRef\n");

       METHOD_PROLOGUE(CEx32bDoc, OleClientSite)

       return pThis->InternalAddRef();

}

 

STDMETHODIMP_(ULONG) CEx32bDoc::XOleClientSite::Release()

{

       TRACE("CEx32bDoc::XOleClientSite::Release\n");

       METHOD_PROLOGUE(CEx32bDoc, OleClientSite)

       return pThis->InternalRelease();

}

 

STDMETHODIMP CEx32bDoc::XOleClientSite::QueryInterface(REFIID iid, LPVOID* ppvObj)

{

       ITrace(iid, "CEx32bDoc::XOleClientSite::QueryInterface");

       METHOD_PROLOGUE(CEx32bDoc, OleClientSite)

       return pThis->InternalQueryInterface(&iid, ppvObj);

}

 

STDMETHODIMP CEx32bDoc::XOleClientSite::SaveObject()

{

       TRACE("CEx32bDoc::XOleClientSite::SaveObject\n");

       METHOD_PROLOGUE(CEx32bDoc, OleClientSite)

       ASSERT_VALID(pThis);

 

       LPPERSISTSTORAGE lpPersistStorage;

       pThis->m_lpOleObj->QueryInterface(IID_IPersistStorage, (void**) &lpPersistStorage);

       ASSERT(lpPersistStorage != NULL);

       HRESULT hr = NOERROR;

       if (lpPersistStorage->IsDirty() == NOERROR)

       {

              // NOERROR == S_OK != S_FALSE, therefore object is dirty!

              hr = ::OleSave(lpPersistStorage, pThis->m_pTempStgSub, TRUE);

              if (hr != NOERROR)

                     hr = lpPersistStorage->SaveCompleted(NULL);

 

              // Mark the document as dirty, if save successful

              pThis->SetModifiedFlag();

       }

       lpPersistStorage->Release();

       pThis->UpdateAllViews(NULL);

       return hr;

}

 

STDMETHODIMP CEx32bDoc::XOleClientSite::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER* ppMoniker)

{

       TRACE("CEx32bDoc::XOleClientSite::GetMoniker\n");

       return E_NOTIMPL;

}

 

STDMETHODIMP CEx32bDoc::XOleClientSite::GetContainer(LPOLECONTAINER* ppContainer)

{

       TRACE("CEx32bDoc::XOleClientSite::GetContainer\n");

       return E_NOTIMPL;

}

 

STDMETHODIMP CEx32bDoc::XOleClientSite::ShowObject()

{

       TRACE("CEx32bDoc::XOleClientSite::ShowObject\n");

       METHOD_PROLOGUE(CEx32bDoc, OleClientSite)

       ASSERT_VALID(pThis);

       pThis->UpdateAllViews(NULL);

       return NOERROR;

}

 

STDMETHODIMP CEx32bDoc::XOleClientSite::OnShowWindow(BOOL fShow)

{

       TRACE("CEx32bDoc::XOleClientSite::OnShowWindow\n");

       METHOD_PROLOGUE(CEx32bDoc, OleClientSite)

       ASSERT_VALID(pThis);

       pThis->m_bHatch = fShow;

       pThis->UpdateAllViews(NULL);

       return NOERROR;

}

 

STDMETHODIMP CEx32bDoc::XOleClientSite::RequestNewObjectLayout()

{

       TRACE("CEx32bDoc::XOleClientSite::RequestNewObjectLayout\n");

       return E_NOTIMPL;

}

 

/////////////////////////////////////////////////////////////////////////////

// Implementation of IAdviseSink

 

STDMETHODIMP_(ULONG) CEx32bDoc::XAdviseSink::AddRef()

{

       TRACE("CEx32bDoc::XAdviseSink::AddRef\n");

       METHOD_PROLOGUE(CEx32bDoc, AdviseSink)

       return pThis->InternalAddRef();

}

 

STDMETHODIMP_(ULONG) CEx32bDoc::XAdviseSink::Release()

{

       TRACE("CEx32bDoc::XAdviseSink::Release\n");

       METHOD_PROLOGUE(CEx32bDoc, AdviseSink)

       return pThis->InternalRelease();

}

 

STDMETHODIMP CEx32bDoc::XAdviseSink::QueryInterface(REFIID iid, LPVOID* ppvObj)

{

       ITrace(iid, "CEx32bDoc::XAdviseSink::QueryInterface");

       METHOD_PROLOGUE(CEx32bDoc, AdviseSink)

       return pThis->InternalQueryInterface(&iid, ppvObj);

}

 

STDMETHODIMP_(void) CEx32bDoc::XAdviseSink::OnDataChange(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)

{

       TRACE("CEx32bDoc::XAdviseSink::OnDataChange\n");

       METHOD_PROLOGUE(CEx32bDoc, AdviseSink)

       ASSERT_VALID(pThis);

       // Interesting only for advanced containers.  Forward it such that

       //  containers do not have to implement the entire interface.

}

 

STDMETHODIMP_(void) CEx32bDoc::XAdviseSink::OnViewChange(DWORD aspects, LONG /*lindex*/)

{

       TRACE("CEx32bDoc::XAdviseSink::OnViewChange\n");

       METHOD_PROLOGUE(CEx32bDoc, AdviseSink)

       ASSERT_VALID(pThis);

       pThis->UpdateAllViews(NULL); // the really important one

}

 

STDMETHODIMP_(void) CEx32bDoc::XAdviseSink::OnRename(LPMONIKER /*lpMoniker*/)

{

       TRACE("CEx32bDoc::XAdviseSink::OnRename\n");

       // Interesting only to the OLE link object. Containers ignore this.

}

 

STDMETHODIMP_(void) CEx32bDoc::XAdviseSink::OnSave()

{

       TRACE("CEx32bDoc::XAdviseSink::OnSave\n");

       METHOD_PROLOGUE(CEx32bDoc, AdviseSink)

       ASSERT_VALID(pThis);

 

       pThis->UpdateAllViews(NULL);

}

 

STDMETHODIMP_(void) CEx32bDoc::XAdviseSink::OnClose()

{

       TRACE("CEx32bDoc::XAdviseSink::OnClose\n");

       METHOD_PROLOGUE(CEx32bDoc, AdviseSink)

       ASSERT_VALID(pThis);

 

       pThis->UpdateAllViews(NULL);

}

 

/////////////////////////////////////////////////////////////////////////////

// CEx32bDoc construction/destruction

 

CEx32bDoc::CEx32bDoc()

{

       // TODO: add one-time construction code here

       m_lpOleObj = NULL;

       m_pTempStgRoot = NULL;

       m_pTempStgSub = NULL;

       m_bHatch = FALSE;

}

 

CEx32bDoc::~CEx32bDoc()

{    }

 

BOOL CEx32bDoc::OnNewDocument()

{

       TRACE("Entering CEx32bDoc::OnNewDocument\n");

       // Create a structured storage home for the object (m_pTempStgSub).

       //  This is a temporary file -- random name supplied by OLE.

       VERIFY(::StgCreateDocfile(NULL, STGM_READWRITE|STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_DELETEONRELEASE, 0, &m_pTempStgRoot) == S_OK);

       ASSERT(m_pTempStgRoot!= NULL);

 

    VERIFY(m_pTempStgRoot->CreateStorage(OLESTR("sub"), STGM_CREATE|STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &m_pTempStgSub) == S_OK);

       ASSERT(m_pTempStgSub != NULL);

       return CDocument::OnNewDocument();

}

 

/////////////////////////////////////////////////////////////////////////////

// CEx32bDoc serialization

 

void CEx32bDoc::Serialize(CArchive& ar)

{

       if (ar.IsStoring())

       {

              // TODO: add storing code here

       }

       else

       {

              // TODO: add loading code here

       }

}

 

/////////////////////////////////////////////////////////////////////////////

// CEx32bDoc diagnostics

 

#ifdef _DEBUG

void CEx32bDoc::AssertValid() const

{

       CDocument::AssertValid();

}

 

void CEx32bDoc::Dump(CDumpContext& dc) const

{

       CDocument::Dump(dc);

}

#endif //_DEBUG

 

/////////////////////////////////////////////////////////////////////////////

// CEx32bDoc commands

 

void CEx32bDoc::DeleteContents()

{

       // TODO: Add your specialized code here and/or call the base class

       if(m_lpOleObj != NULL) {

          // If object is running, close it, which releases our IOleClientSite

              m_lpOleObj->Close(OLECLOSE_NOSAVE);

              m_lpOleObj->Release(); // should be final release (or else..)

              m_lpOleObj = NULL;

       }

}

 

void CEx32bDoc::OnCloseDocument()

{

       // TODO: Add your specialized code here and/or call the base class

       m_pTempStgSub->Release(); // must release BEFORE calling base class

       m_pTempStgRoot->Release();

       CDocument::OnCloseDocument();

}

 

BOOL CEx32bDoc::SaveModified()

{

       // TODO: Add your specialized code here and/or call the base class

       // Eliminate "save to file" message

       return TRUE;

}

 

void CEx32bDoc::OnEditClearAll()

{

       // TODO: Add your command handler code here

       DeleteContents();

    UpdateAllViews(NULL);

    SetModifiedFlag();

       m_bHatch = FALSE;

}

 

void ITrace(REFIID iid, const char* str)

{

       OLECHAR* lpszIID;

       ::StringFromIID(iid, &lpszIID);

       CString strIID = lpszIID;

       TRACE("%s - %s\n", (const char*) strIID, (const char*) str);

       AfxFreeTaskMem(lpszIID);

}

 

 

 

 

 

 

 

 

 

 

 

 

 

Listing 38:  The container’s CEx32bDoc class listing.

 

Continue on next module...

 

 

--------------------End part 2------------------

 

 

 

 

 

 

Further reading and digging:

  1. DCOM at MSDN.

  2. COM+ at MSDN.

  3. COM at MSDN.

  4. Win32 process, thread and synchronization story can be found starting from Module R.

  5. MSDN MFC 7.0 class library online documentation.

  6. MSDN MFC 9.0 class library online documentation - latest version.

  7. MSDN Library

  8. Windows data type.

  9. Win32 programming Tutorial.

  10. The best of C/C++, MFC, Windows and other related books.

  11. Unicode and Multibyte character set: Story and program examples.

 

 

 


 

| Tenouk C & C++ | MFC Home | OLE & Containers 5 | OLE & Containers 7 | Download | Site Index |