The EX28B Example -- An Embedding Container

Now we can move on to the working program. It's a good time to open the \vcpp32\ex28b\ex28b.dsw workspace and build the EX28B project. If you choose Insert Object from the Edit menu and select Ex28a Document, the EX28A component will start. If you change the component's data, the container and the component will look like this.

click to view at full size.

The CEx28bView Class

You can best understand the program by first concentrating on the view class. Look at the code in Figure 28-6, but ignore all IOleClientSite pointers. The container program will actually work if you pass NULL in every IOleClientSite pointer parameter. It just won't get notifications when the metafile or the native data changes. Also, components will appear displaying their stand-alone menus instead of the special embedded menus.

EX28BVIEW.H

 #if !defined(AFX_EX28BVIEW_H__1EAAB6E1_6011_11D0_848F_00400526305B__INCLUDED_) #define AFX_EX28BVIEW_H__1EAAB6E1_6011_11D0_848F_00400526305B__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #define CF_OBJECTDESCRIPTOR "Object Descriptor" #define CF_EMBEDDEDOBJECT "Embedded Object" #define SETFORMATETC(fe, cf, asp, td, med, li)   \     ((fe).cfFormat=cf, \      (fe).dwAspect=asp, \      (fe).ptd=td, \      (fe).tymed=med, \      (fe).lindex=li) //////////////////////////////////////////////////////////////////// class CEx28bView : public CScrollView { public:     CLIPFORMAT m_cfObjDesc;     CLIPFORMAT m_cfEmbedded;     CSize m_sizeTotal;  // document size     CRectTracker m_tracker;     CRect m_rectTracker; // logical coords protected: // create from serialization only     CEx28bView();     DECLARE_DYNCREATE(CEx28bView) // Attributes public:     CEx28bDoc* GetDocument(); private:     void GetSize();     void SetNames();     void SetViewAdvise();     BOOL MakeMetafilePict(COleDataSource* pSource);     COleDataSource* SaveObject();     BOOL DoPasteObject(COleDataObject* pDataObject);     BOOL DoPasteObjectDescriptor(COleDataObject* pDataObject); // Overrides     // ClassWizard generated virtual function overrides     //{{AFX_VIRTUAL(CEx28bView)     public:     virtual void OnDraw(CDC* pDC);  // overridden to draw this view     virtual BOOL PreCreateWindow(CREATESTRUCT& cs);     virtual void OnInitialUpdate();     protected:     virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);     virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);     virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);     //}}AFX_VIRTUAL // Implementation public:     virtual ~CEx28bView(); #ifdef _DEBUG     virtual void AssertValid() const;     virtual void Dump(CDumpContext& dc) const; #endif protected: // Generated message map functions protected:     //{{AFX_MSG(CEx28bView)     afx_msg void OnEditCopy();     afx_msg void OnUpdateEditCopy(CCmdUI* pCmdUI);     afx_msg void OnEditCopyto();     afx_msg void OnEditCut();     afx_msg void OnEditPaste();     afx_msg void OnUpdateEditPaste(CCmdUI* pCmdUI);     afx_msg void OnEditPastefrom();     afx_msg void OnEditInsertobject();     afx_msg void OnUpdateEditInsertobject(CCmdUI* pCmdUI);     afx_msg void OnLButtonDown(UINT nFlags, CPoint point);     afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);     afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest,                               UINT message);     //}}AFX_MSG     DECLARE_MESSAGE_MAP() }; #ifndef _DEBUG  // debug version in ex28bView.cpp inline CEx28bDoc* CEx28bView::GetDocument()     { return (CEx28bDoc*) m_pDocument; } #endif //////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations  //  immediately before the previous line. #endif  //!defined(AFX_EX28BVIEW_H__1EAAB6E1_6011_11D0_848F_00400526305B__INCLUDED_) 

EX28BVIEW.CPP

 #include "stdafx.h" #include "ex28b.h" #include "ex28bDoc.h" #include "ex28bView.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = _FILE_; #endif //////////////////////////////////////////////////////////////////// // CEx28bView IMPLEMENT_DYNCREATE(CEx28bView, CScrollView) BEGIN_MESSAGE_MAP(CEx28bView, CScrollView)     //{{AFX_MSG_MAP(CEx28bView)     ON_COMMAND(ID_EDIT_COPY, OnEditCopy)     ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)     ON_COMMAND(ID_EDIT_COPYTO, OnEditCopyto)     ON_UPDATE_COMMAND_UI(ID_EDIT_COPYTO, OnUpdateEditCopy)     ON_COMMAND(ID_EDIT_CUT, OnEditCut)     ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCopy)     ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)     ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)     ON_COMMAND(ID_EDIT_PASTEFROM, OnEditPastefrom)     ON_COMMAND(ID_EDIT_INSERTOBJECT, OnEditInsertobject)     ON_UPDATE_COMMAND_UI(ID_EDIT_INSERTOBJECT,                           OnUpdateEditInsertobject)     ON_WM_LBUTTONDOWN()     ON_WM_LBUTTONDBLCLK()     ON_WM_SETCURSOR()     //}}AFX_MSG_MAP     // Standard printing commands     ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)     ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)     ON_COMMAND(ID_FILE_PRINT_PREVIEW,                CScrollView::OnFilePrintPreview) END_MESSAGE_MAP() //////////////////////////////////////////////////////////////////// // CEx28bView construction/destruction CEx28bView::CEx28bView() : m_sizeTotal(20000, 25000),     // 20 x 25 cm when printed     m_rectTracker(0, 0, 0, 0)  {     m_cfObjDesc = ::RegisterClipboardFormat(CF_OBJECTDESCRIPTOR);     m_cfEmbedded = ::RegisterClipboardFormat(CF_EMBEDDEDOBJECT); } CEx28bView::~CEx28bView() { } BOOL CEx28bView::PreCreateWindow(CREATESTRUCT& cs) {     // TODO: Modify the Window class or styles here by modifying     //  the CREATESTRUCT cs     return CScrollView::PreCreateWindow(cs); } //////////////////////////////////////////////////////////////////// // CEx28bView drawing void CEx28bView::OnDraw(CDC* pDC) {     CEx28bDoc* pDoc = GetDocument();     if(pDoc->m_lpOleObj != NULL) {         VERIFY(::OleDraw(pDoc-> m_lpOleObj, DVASPECT_CONTENT,                pDC->GetSafeHdc(),  m_rectTracker) == S_OK);     }     m_tracker.m_rect =  m_rectTracker;     pDC->LPtoDP(m_tracker.m_rect);   // device     if(pDoc->m_bHatch) {         m_tracker. m_nStyle |= CRectTracker::hatchInside;     }     else {         m_tracker. m_nStyle &= ~CRectTracker::hatchInside;     }     m_tracker.Draw(pDC); } //////////////////////////////////////////////////////////////////// // CEx28bView printing BOOL CEx28bView::OnPreparePrinting(CPrintInfo* pInfo) {     pInfo->SetMaxPage(1);     return DoPreparePrinting(pInfo); } void CEx28bView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) {     // TODO: add extra initialization before printing } void CEx28bView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) {     // TODO: add cleanup after printing } //////////////////////////////////////////////////////////////////// // CEx28bView diagnostics #ifdef _DEBUG void CEx28bView::AssertValid() const {     CScrollView::AssertValid(); } void CEx28bView::Dump(CDumpContext& dc) const {     CScrollView::Dump(dc); } CEx28bDoc* CEx28bView::GetDocument() // non-debug version is inline {     ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CEx28bDoc)));     return (CEx28bDoc*)m_pDocument; } #endif //_DEBUG //////////////////////////////////////////////////////////////////// // CEx28bView message handlers void CEx28bView::OnInitialUpdate()  {     TRACE("CEx28bView::OnInitialUpdate\n");     m_rectTracker = CRect(1000, -1000, 5000, -5000);     m_tracker.m_nStyle = CRectTracker::solidLine |         CRectTracker::resizeOutside;     SetScrollSizes(MM_HIMETRIC,  m_sizeTotal);     CScrollView::OnInitialUpdate(); } void CEx28bView::OnEditCopy()  {     COleDataSource* pSource = SaveObject();     if(pSource) {         pSource->SetClipboard(); // OLE deletes data source      } } void CEx28bView::OnUpdateEditCopy(CCmdUI* pCmdUI)  {     // serves Copy, Cut, and Copy To     pCmdUI->Enable(GetDocument()-> m_lpOleObj != NULL); } void CEx28bView::OnEditCopyto()  {     // Copy text to an STG file (nothing special about STG ext)     CFileDialog dlg(FALSE, "stg", "*.stg");     if (dlg.DoModal() != IDOK) {         return;     }     CEx28bDoc* pDoc = GetDocument();     // Create a structured storage home for the object ( pStgSub).     //  Create a root storage file, then a substorage named "sub".     LPSTORAGE pStgRoot;     VERIFY(::StgCreateDocfile(dlg.GetPathName().AllocSysString(),            STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,            0, &pStgRoot) == S_OK);     ASSERT(pStgRoot != NULL);     LPSTORAGE pStgSub;     VERIFY(pStgRoot->CreateStorage(CEx28bDoc::s_szSub,            STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE,            0, 0, &pStgSub) == S_OK);      ASSERT(pStgSub != NULL);     // Get the IPersistStorage* for the object     LPPERSISTSTORAGE pPS = NULL;     VERIFY(pDoc->m_lpOleObj->QueryInterface(IID_IPersistStorage,           (void**) &pPS) == S_OK);     // Finally, save the object in its new home in the user's file     VERIFY(::OleSave(pPS, pStgSub, FALSE) == S_OK);      // FALSE means different stg     pPS->SaveCompleted(NULL);  // What does this do?     pPS->Release();     pStgSub->Release();     pStgRoot->Release(); } void CEx28bView::OnEditCut()  {     OnEditCopy();     GetDocument()->OnEditClearAll(); } void CEx28bView::OnEditPaste()  {     CEx28bDoc* pDoc = GetDocument();     COleDataObject dataObject;     VERIFY(dataObject.AttachClipboard());     pDoc->DeleteContents();     DoPasteObjectDescriptor(&dataObject);     DoPasteObject(&dataObject);     SetViewAdvise();     GetSize();     pDoc->SetModifiedFlag();     pDoc->UpdateAllViews(NULL); } void CEx28bView::OnUpdateEditPaste(CCmdUI* pCmdUI)  {     // Make sure that object data is available     COleDataObject dataObject;     if (dataObject.AttachClipboard() &&         dataObject.IsDataAvailable( m_cfEmbedded)) {         pCmdUI->Enable(TRUE);     } else {         pCmdUI->Enable(FALSE);     } } void CEx28bView::OnEditPastefrom()  {     CEx28bDoc* pDoc = GetDocument();     // Paste from an STG file     CFileDialog dlg(TRUE, "stg", "*.stg");     if (dlg.DoModal() != IDOK) {         return;     }     // Open the storage and substorage     LPSTORAGE pStgRoot;     VERIFY(::StgOpenStorage(dlg.GetPathName().AllocSysString(),            NULL, STGM_READ|STGM_SHARE_EXCLUSIVE,            NULL, 0, &pStgRoot) == S_OK);     ASSERT(pStgRoot != NULL);     LPSTORAGE pStgSub;     VERIFY(pStgRoot->OpenStorage(CEx28bDoc::s_szSub, NULL,            STGM_READ|STGM_SHARE_EXCLUSIVE,            NULL, 0, &pStgSub) == S_OK);     ASSERT(pStgSub != NULL);     // Copy the object data from the user storage to the temporary     //  storage     VERIFY(pStgSub->CopyTo(NULL, NULL, NULL,             pDoc-> m_pTempStgSub) == S_OK);     // Finally, load the object -- pClientSite not necessary     LPOLECLIENTSITE pClientSite =         (LPOLECLIENTSITE) pDoc->GetInterface(&IID_IOleClientSite);     ASSERT(pClientSite != NULL);     pDoc->DeleteContents();     VERIFY(::OleLoad(pDoc->m _pTempStgSub, IID_IOleObject,            pClientSite, (void**) &pDoc-> m_lpOleObj) == S_OK);     SetViewAdvise();     pStgSub->Release();     pStgRoot->Release();     GetSize();     pDoc->SetModifiedFlag();     pDoc->UpdateAllViews(NULL); } void CEx28bView::OnEditInsertobject()  {     CEx28bDoc* pDoc = GetDocument();     COleInsertDialog dlg;     if(dlg.DoModal() == IDCANCEL) return;     // no addrefs done for GetInterface     LPOLECLIENTSITE pClientSite =         (LPOLECLIENTSITE) pDoc->GetInterface(&IID_IOleClientSite);     ASSERT(pClientSite != NULL);     pDoc->DeleteContents();     VERIFY(::OleCreate(dlg.GetClassID(), IID_IOleObject,            OLERENDER_DRAW, NULL, pClientSite, pDoc->m_pTempStgSub,            (void**) &pDoc-> m_lpOleObj) == S_OK);     SetViewAdvise();     pDoc->m_lpOleObj->DoVerb(OLEIVERB_SHOW, NULL, pClientSite, 0,          NULL, NULL); // OleRun doesn't show it     SetNames();     GetDocument()->SetModifiedFlag();     GetSize();     pDoc->UpdateAllViews(NULL); } void CEx28bView::OnUpdateEditInsertobject(CCmdUI* pCmdUI)  {     pCmdUI->Enable(GetDocument()->m_lpOleObj == NULL); } void CEx28bView::OnLButtonDown(UINT nFlags, CPoint point)  {     TRACE("**Entering CEx28bView::OnLButtonDown -- point = "           "(%d, %d)\n", point.x, point.y);     if(m_tracker.Track(this, point, FALSE, NULL)) {         CClientDC dc(this);         OnPrepareDC(&dc);         m_rectTracker =  m_tracker.m_rect;         dc.DPtoLP( m_rectTracker); // Update logical coords         GetDocument()->UpdateAllViews(NULL);     }     TRACE("**Leaving CEx28bView::OnLButtonDown\n"); } void CEx28bView::OnLButtonDblClk(UINT nFlags, CPoint point)  {     if(m_tracker.HitTest(point) == CRectTracker::hitNothing) return;     // Activate the object     CEx28bDoc* pDoc = GetDocument();     if(pDoc->m_lpOleObj != NULL) {         LPOLECLIENTSITE pClientSite =             (LPOLECLIENTSITE)               pDoc->GetInterface(&IID_IOleClientSite);         ASSERT(pClientSite != NULL);         VERIFY(pDoc-> m_lpOleObj->DoVerb(OLEIVERB_OPEN, NULL,                pClientSite, 0,GetSafeHwnd(), CRect(0, 0, 0, 0))                == S_OK);         SetNames();         GetDocument()->SetModifiedFlag();     } } BOOL CEx28bView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) {     if(m_tracker.SetCursor(pWnd, nHitTest)) {         return TRUE;     }     else {         return CScrollView::OnSetCursor(pWnd, nHitTest, message);     } } //////////////////////////////////////////////////////////////////// void CEx28bView::SetViewAdvise()  {     CEx28bDoc* pDoc = GetDocument();     if(pDoc->m_lpOleObj != NULL) {         LPVIEWOBJECT2 pViewObj;         pDoc-> m_lpOleObj->QueryInterface(IID_IViewObject2,              (void**) &pViewObj);         LPADVISESINK pAdviseSink =              (LPADVISESINK) pDoc->GetInterface(&IID_IAdviseSink);         VERIFY(pViewObj->SetAdvise(DVASPECT_CONTENT, 0, pAdviseSink)             == S_OK);         pViewObj->Release();     } } void CEx28bView::SetNames() // sets host names {     CEx28bDoc* pDoc = GetDocument();     CString strApp = AfxGetApp()-> m_pszAppName;     if(pDoc->m_lpOleObj != NULL) {         pDoc-> m_lpOleObj->SetHostNames(strApp.AllocSysString(),         NULL);     } } void CEx28bView::GetSize() {     CEx28bDoc* pDoc = GetDocument();     if(pDoc->m_lpOleObj != NULL) {         SIZEL size;      // Ask the component for its size         pDoc-> m_lpOleObj->GetExtent(DVASPECT_CONTENT, &size);         m_rectTracker.right = m_rectTracker.left + size.cx;         m_rectTracker.bottom = m_rectTracker.top - size.cy;     } } BOOL CEx28bView::DoPasteObject(COleDataObject* pDataObject) {     TRACE("Entering CEx28bView::DoPasteObject\n");     // Update command UI should keep us out of here if not      //  CF_EMBEDDEDOBJECT     if (!pDataObject->IsDataAvailable(m_cfEmbedded)) {         TRACE("CF_EMBEDDEDOBJECT format is unavailable\n");         return FALSE;     }     CEx28bDoc* pDoc = GetDocument();     // Now create the object from the IDataObject*.     //  OleCreateFromData will use CF_EMBEDDEDOBJECT format if     //  available.     LPOLECLIENTSITE pClientSite =          (LPOLECLIENTSITE) pDoc->GetInterface(&IID_IOleClientSite);     ASSERT(pClientSite != NULL);     VERIFY(::OleCreateFromData(pDataObject->m_lpDataObject,            IID_IOleObject, OLERENDER_DRAW, NULL, pClientSite,            pDoc-> m_pTempStgSub, (void**) &pDoc->m_lpOleObj) == S_OK);     return TRUE; } BOOL CEx28bView::DoPasteObjectDescriptor(COleDataObject* pDataObject) {     TRACE("Entering CEx28bView::DoPasteObjectDescriptor\n");     STGMEDIUM stg;     FORMATETC fmt;     CEx28bDoc* pDoc = GetDocument();     if (!pDataObject->IsDataAvailable(m_cfObjDesc)) {         TRACE("OBJECTDESCRIPTOR format is unavailable\n");         return FALSE;     }     SETFORMATETC(fmt, m_cfObjDesc, DVASPECT_CONTENT, NULL,          TYMED_HGLOBAL, -1);     VERIFY(pDataObject->GetDatam_cfObjDesc, &stg, &fmt));     return TRUE; } // helper function used for clipboard and drag-drop  COleDataSource* CEx28bView::SaveObject() {     TRACE("Entering CEx28bView::SaveObject\n");     CEx28bDoc* pDoc = GetDocument();     if (pDoc->m_lpOleObj != NULL) {         COleDataSource* pSource = new COleDataSource();         // CODE FOR OBJECT DATA         FORMATETC fmte;         SETFORMATETC(fmte, m_cfEmbedded, DVASPECT_CONTENT, NULL,             TYMED_ISTORAGE, -1);         STGMEDIUM stgm;         stgm.tymed = TYMED_ISTORAGE;         stgm.pstg = pDoc->m_pTempStgSub;         stgm.pUnkForRelease = NULL;         pDoc->m_pTempStgSub->AddRef();   // must do both!         pDoc->m_pTempStgRoot->AddRef();         pSource->CacheData(m_cfEmbedded, &stgm, &fmte);         // metafile needed too         MakeMetafilePict(pSource);         // CODE FOR OBJECT DESCRIPTION DATA         HGLOBAL hObjDesc = ::GlobalAlloc(GMEM_SHARE,             sizeof(OBJECTDESCRIPTOR));         LPOBJECTDESCRIPTOR pObjDesc =             (LPOBJECTDESCRIPTOR) ::GlobalLock(hObjDesc);         pObjDesc->cbSize = sizeof(OBJECTDESCRIPTOR);         pObjDesc->clsid = CLSID_NULL;         pObjDesc->dwDrawAspect = 0;         pObjDesc->dwStatus = 0;         pObjDesc->dwFullUserTypeName = 0;         pObjDesc->dwSrcOfCopy = 0;         pObjDesc->sizel.cx = 0;         pObjDesc->sizel.cy = 0;         pObjDesc->pointl.x = 0;         pObjDesc->pointl.y = 0;         ::GlobalUnlock(hObjDesc);         pSource->CacheGlobalData( m_cfObjDesc, hObjDesc);         return pSource;     }     return NULL; } BOOL CEx28bView::MakeMetafilePict(COleDataSource* pSource) {     CEx28bDoc* pDoc = GetDocument();     COleDataObject dataObject;     LPDATAOBJECT pDataObj; // OLE object's IDataObject interface     VERIFY(pDoc->m_lpOleObj->QueryInterface(IID_IDataObject,           (void**) &pDataObj) == S_OK);     dataObject.Attach(pDataObj);     FORMATETC fmtem;     SETFORMATETC(fmtem, CF_METAFILEPICT, DVASPECT_CONTENT, NULL,         TYMED_MFPICT, -1);     if (!dataObject.IsDataAvailable(CF_METAFILEPICT, &fmtem)) {         TRACE("CF_METAFILEPICT format is unavailable\n");         return FALSE;     }     // Just copy the metafile handle from the OLE object     //  to the clipboard data object     STGMEDIUM stgmm;     VERIFY(dataObject.GetData(CF_METAFILEPICT, &stgmm, &fmtem));     pSource->CacheData(CF_METAFILEPICT, &stgmm, &fmtem);     return TRUE; } 

Figure 28-6. The container's CEx28bView class listing.

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 CEx28bDoc 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 Figure 28-7. 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 CEx28bView 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.

EX28BDOC.H

 #if !defined(AFX_EX28BDOC_H__1EAAB6DF_6011_11D0_848F_00400526305B__INCLUDED_) #define AFX_EX28BDOC_H__1EAAB6DF_6011_11D0_848F_00400526305B__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif //_MSC_VER > 1000 void ITrace(REFIID iid, const char* str); class CEx28bDoc : public CDocument { protected: // create from serialization only     CEx28bDoc();     DECLARE_DYNCREATE(CEx28bDoc)     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 CEx28bView; private:     LPOLEOBJECT m_lpOleObj;     LPSTORAGE m_pTempStgRoot;     LPSTORAGE m_pTempStgSub;     BOOL m_bHatch;     static const OLECHAR* s_szSub; // Overrides     // ClassWizard generated virtual function overrides     //{{AFX_VIRTUAL(CEx28bDoc)     public:     virtual BOOL OnNewDocument();     virtual void Serialize(CArchive& ar);     virtual void OnCloseDocument();     virtual void DeleteContents();     protected:     virtual BOOL SaveModified();     //}}AFX_VIRTUAL // Implementation public:     virtual ~CEx28bDoc(); #ifdef _DEBUG     virtual void AssertValid() const;     virtual void Dump(CDumpContext& dc) const; #endif protected: // Generated message map functions protected:     //{{AFX_MSG(CEx28bDoc)     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_EX28BDOC_H__1EAAB6DF_6011_11D0_848F_00400526305B__INCLUDED_) EX28BDOC.CPP #include "stdafx.h" #include "ex28b.h" #include "ex28bDoc.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE __; #endif const OLECHAR* CEx28bDoc::s_szSub = L"sub";   // static //////////////////////////////////////////////////////////////////// // CEx28bDoc IMPLEMENT_DYNCREATE(CEx28bDoc, CDocument) BEGIN_MESSAGE_MAP(CEx28bDoc, CDocument)     //{{AFX_MSG_MAP(CEx28bDoc)     ON_COMMAND(ID_EDIT_CLEAR_ALL, OnEditClearAll)     //}}AFX_MSG_MAP END_MESSAGE_MAP() BEGIN_INTERFACE_MAP(CEx28bDoc, CDocument)     INTERFACE_PART(CEx28bDoc, IID_IOleClientSite, OleClientSite)     INTERFACE_PART(CEx28bDoc, IID_IAdviseSink, AdviseSink) END_INTERFACE_MAP() //////////////////////////////////////////////////////////////////// // implementation of IOleClientSite STDMETHODIMP_(ULONG) CEx28bDoc::XOleClientSite::AddRef() {     TRACE("CEx28bDoc::XOleClientSite::AddRef\n");     METHOD_PROLOGUE(CEx28bDoc, OleClientSite)     return pThis->InternalAddRef(); } STDMETHODIMP_(ULONG) CEx28bDoc::XOleClientSite::Release() {     TRACE("CEx28bDoc::XOleClientSite::Release\n");     METHOD_PROLOGUE(CEx28bDoc, OleClientSite)     return pThis->InternalRelease(); } STDMETHODIMP CEx28bDoc::XOleClientSite::QueryInterface(     REFIID iid, LPVOID* ppvObj) {     ITrace(iid, "CEx28bDoc::XOleClientSite::QueryInterface");     METHOD_PROLOGUE(CEx28bDoc, OleClientSite)     return pThis->InternalQueryInterface(&iid, ppvObj); } STDMETHODIMP CEx28bDoc::XOleClientSite::SaveObject() {     TRACE("CEx28bDoc::XOleClientSite::SaveObject\n");     METHOD_PROLOGUE(CEx28bDoc, OleClientSite)     ASSERT_VALID(pThis);     LPPERSISTSTORAGE lpPersistStorage;     pThis->m_pOleObj->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 CEx28bDoc::XOleClientSite::GetMoniker(     DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER* ppMoniker) {     TRACE("CEx28bDoc::XOleClientSite::GetMoniker\n");     return E_NOTIMPL; } STDMETHODIMP CEx28bDoc::XOleClientSite::GetContainer(     LPOLECONTAINER* ppContainer) {     TRACE("CEx28bDoc::XOleClientSite::GetContainer\n");     return E_NOTIMPL; } STDMETHODIMP CEx28bDoc::XOleClientSite::ShowObject() {     TRACE("CEx28bDoc::XOleClientSite::ShowObject\n");     METHOD_PROLOGUE(CEx28bDoc, OleClientSite)     ASSERT_VALID(pThis);     pThis->UpdateAllViews(NULL);     return NOERROR; } STDMETHODIMP CEx28bDoc::XOleClientSite::OnShowWindow(BOOL fShow) {     TRACE("CEx28bDoc::XOleClientSite::OnShowWindow\n");     METHOD_PROLOGUE(CEx28bDoc, OleClientSite)     ASSERT_VALID(pThis);     pThis->m_bHatch = fShow;     pThis->UpdateAllViews(NULL);     return NOERROR; } STDMETHODIMP CEx28bDoc::XOleClientSite::RequestNewObjectLayout() {     TRACE("CEx28bDoc::XOleClientSite::RequestNewObjectLayout\n");     return E_NOTIMPL; } //////////////////////////////////////////////////////////////////// // implementation of IAdviseSink STDMETHODIMP_(ULONG) CEx28bDoc::XAdviseSink::AddRef() {     TRACE("CEx28bDoc::XAdviseSink::AddRef\n");     METHOD_PROLOGUE(CEx28bDoc, AdviseSink)     return pThis->InternalAddRef(); } STDMETHODIMP_(ULONG) CEx28bDoc::XAdviseSink::Release() {     TRACE("CEx28bDoc::XAdviseSink::Release\n");     METHOD_PROLOGUE(CEx28bDoc, AdviseSink)     return pThis->InternalRelease(); } STDMETHODIMP CEx28bDoc::XAdviseSink::QueryInterface(     REFIID iid, LPVOID* ppvObj) {     ITrace(iid, "CEx28bDoc::XAdviseSink::QueryInterface");     METHOD_PROLOGUE(CEx28bDoc, AdviseSink)     return pThis->InternalQueryInterface(&iid, ppvObj); } STDMETHODIMP_(void) CEx28bDoc::XAdviseSink::OnDataChange(     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium) {     TRACE("CEx28bDoc::XAdviseSink::OnDataChange\n");     METHOD_PROLOGUE(CEx28bDoc, AdviseSink)     ASSERT_VALID(pThis);     // Interesting only for advanced containers. Forward it such     //  that containers do not have to implement the entire     //  interface. } STDMETHODIMP_(void) CEx28bDoc::XAdviseSink::OnViewChange(     DWORD aspects, LONG /*lindex*/) {     TRACE("CEx28bDoc::XAdviseSink::OnViewChange\n");     METHOD_PROLOGUE(CEx28bDoc, AdviseSink)     ASSERT_VALID(pThis);     pThis->UpdateAllViews(NULL);        // the really important one } STDMETHODIMP_(void) CEx28bDoc::XAdviseSink::OnRename(     LPMONIKER /*lpMoniker*/) {     TRACE("CEx28bDoc::XAdviseSink::OnRename\n");     // Interesting only to the OLE link object. Containers ignore     //  this. } STDMETHODIMP_(void) CEx28bDoc::XAdviseSink::OnSave() {     TRACE("CEx28bDoc::XAdviseSink::OnSave\n");     METHOD_PROLOGUE(CEx28bDoc, AdviseSink)     ASSERT_VALID(pThis);     pThis->UpdateAllViews(NULL); } STDMETHODIMP_(void) CEx28bDoc::XAdviseSink::OnClose() {     TRACE("CEx28bDoc::XAdviseSink::OnClose\n");     METHOD_PROLOGUE(CEx28bDoc, AdviseSink)     ASSERT_VALID(pThis);     pThis->UpdateAllViews(NULL); } //////////////////////////////////////////////////////////////////// // CEx28bDoc construction/destruction CEx28bDoc::CEx28bDoc() {     m_lpOleObj = NULL;     m_pTempStgRoot = NULL;     m_pTempStgSub = NULL;     m_bHatch = FALSE; } CEx28bDoc::~CEx28bDoc() { } BOOL CEx28bDoc::OnNewDocument() {     TRACE("Entering CEx28bDoc::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(); } //////////////////////////////////////////////////////////////////// // CEx28bDoc serialization void CEx28bDoc::Serialize(CArchive& ar) {     // no hookup to MFC serialization     if (ar.IsStoring())     {         // TODO: add storing code here     }     else     {         // TODO: add loading code here     } } //////////////////////////////////////////////////////////////////// // CEx28bDoc diagnostics #ifdef _DEBUG void CEx28bDoc::AssertValid() const {     CDocument::AssertValid(); } void CEx28bDoc::Dump(CDumpContext& dc) const {     CDocument::Dump(dc); } #endif //_DEBUG //////////////////////////////////////////////////////////////////// // CEx28bDoc commands void CEx28bDoc::OnCloseDocument()  {     m_pTempStgSub->Release(); // must release BEFORE calling                               //  base class     m_pTempStgRoot->Release();     CDocument::OnCloseDocument(); } void CEx28bDoc::DeleteContents()  {     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 CEx28bDoc::OnEditClearAll()  {     DeleteContents();     UpdateAllViews(NULL);     SetModifiedFlag();     m_bHatch = FALSE; } BOOL CEx28bDoc::SaveModified()  {     // Eliminate "save to file" message     return TRUE; } 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); } 

Figure 28-7. The container's CEx28bDoc class listing.



Programming Visual C++
Advanced 3ds max 5 Modeling & Animating
ISBN: 1572318570
EAN: 2147483647
Year: 1997
Pages: 331
Authors: Boris Kulagin

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