The EX28C Example -- An OLE Embedded Component

You've already seen an MFC embedded component with in-place-activation capability (EX28A). Now you'll see a bare-bones component program that activates an embedded object in a separate window. It doesn't do much except display text and graphics in the window, but you'll learn a lot if you study the code. The application started as an SDI AppWizard Automation component with the document as the creatable object. The document's IDispatch interface was ripped out and replaced with IOleObject, IDataObject, and IPersistStorage interfaces. All the template server code carries through, so the document, view, and main frame objects are created when the container starts the component.

Open and build the EX28C project now. Run the application to register it, and then try it with the EX28B container or any other container program.

The CEx28cView Class

This class is straightforward. The only member functions of interest are the OnDraw function and the OnPrepareDC function, shown here:

 void CEx28cView::OnDraw(CDC* pDC) {     CEx28cDoc* pDoc = GetDocument();     ASSERT_VALID(pDoc);     pDC->Rectangle(CRect(500, -1000, 1500, -2000));     pDC->TextOut(0, 0, pDoc->m_strText); } void CEx28cView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)  {     pDC->SetMapMode(MM_HIMETRIC); } 

The CEx28cDoc Class

This class does most of the component's work and is too big to list here. Figure 28-8 lists the header file, but you'll have to go to the companion CD-ROM for the implementation code. A few of the important functions are listed here, however.

EX28CDOC.H

 #if !defined(AFX_EX28CDOC_H__1EAAB6F5_6011_11D0_848F_00400526305B  __INCLUDED_) #define AFX_EX28CDOC_H__1EAAB6F5_6011_11D0_848F_00400526305B  __INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 extern const CLSID clsid; // defined in ex28c.cpp void ITrace(REFIID iid, const char* str); #define SETFORMATETC(fe, cf, asp, td, med, li)   \     ((fe).cfFormat=cf, \      (fe).dwAspect=asp, \      (fe).ptd=td, \      (fe).tymed=med, \      (fe).lindex=li) class CEx28cDoc : public CDocument { friend class CEx28cView; private:     CString m_strText;     LPOLECLIENTSITE m_lpClientSite;     LPOLEADVISEHOLDER m_lpOleAdviseHolder;     LPDATAADVISEHOLDER m_lpDataAdviseHolder;     CString m_strContainerApp;     CString m_strContainerObj;     HGLOBAL MakeMetaFile();     BEGIN_INTERFACE_PART(OleObject, IOleObject)         STDMETHOD(SetClientSite)(LPOLECLIENTSITE);         STDMETHOD(GetClientSite)(LPOLECLIENTSITE*);         STDMETHOD(SetHostNames)(LPCOLESTR, LPCOLESTR);         STDMETHOD(Close)(DWORD);         STDMETHOD(SetMoniker)(DWORD, LPMONIKER);         STDMETHOD(GetMoniker)(DWORD, DWORD, LPMONIKER*);         STDMETHOD(InitFromData)(LPDATAOBJECT, BOOL, DWORD);         STDMETHOD(GetClipboardData)(DWORD, LPDATAOBJECT*);         STDMETHOD(DoVerb)(LONG, LPMSG, LPOLECLIENTSITE, LONG,                           HWND, LPCRECT);         STDMETHOD(EnumVerbs)(LPENUMOLEVERB*);         STDMETHOD(Update)();         STDMETHOD(IsUpToDate)();         STDMETHOD(GetUserClassID)(LPCLSID);         STDMETHOD(GetUserType)(DWORD, LPOLESTR*);         STDMETHOD(SetExtent)(DWORD, LPSIZEL);         STDMETHOD(GetExtent)(DWORD, LPSIZEL);         STDMETHOD(Advise)(LPADVISESINK, LPDWORD);         STDMETHOD(Unadvise)(DWORD);         STDMETHOD(EnumAdvise)(LPENUMSTATDATA*);         STDMETHOD(GetMiscStatus)(DWORD, LPDWORD);         STDMETHOD(SetColorScheme)(LPLOGPALETTE);     END_INTERFACE_PART(OleObject)     BEGIN_INTERFACE_PART(DataObject, IDataObject)         STDMETHOD(GetData)(LPFORMATETC, LPSTGMEDIUM);         STDMETHOD(GetDataHere)(LPFORMATETC, LPSTGMEDIUM);         STDMETHOD(QueryGetData)(LPFORMATETC);         STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC, LPFORMATETC);         STDMETHOD(SetData)(LPFORMATETC, LPSTGMEDIUM, BOOL);         STDMETHOD(EnumFormatEtc)(DWORD, LPENUMFORMATETC*);         STDMETHOD(DAdvise)(LPFORMATETC, DWORD, LPADVISESINK, LPDWORD);         STDMETHOD(DUnadvise)(DWORD);         STDMETHOD(EnumDAdvise)(LPENUMSTATDATA*);     END_INTERFACE_PART(DataObject)     BEGIN_INTERFACE_PART(PersistStorage, IPersistStorage)         STDMETHOD(GetClassID)(LPCLSID);         STDMETHOD(IsDirty)();         STDMETHOD(InitNew)(LPSTORAGE);         STDMETHOD(Load)(LPSTORAGE);         STDMETHOD(Save)(LPSTORAGE, BOOL);         STDMETHOD(SaveCompleted)(LPSTORAGE);         STDMETHOD(HandsOffStorage)();     END_INTERFACE_PART(PersistStorage)     DECLARE_INTERFACE_MAP() protected: // Create from serialization only     CEx28cDoc();     DECLARE_DYNCREATE(CEx28cDoc) // Overrides     // ClassWizard generated virtual function overrides     //{{AFX_VIRTUAL(CEx28cDoc)     public:     virtual BOOL OnNewDocument();     virtual void Serialize(CArchive& ar);     virtual void OnFinalRelease();     virtual void OnCloseDocument();     protected:     virtual BOOL SaveModified();     //}}AFX_VIRTUAL // Implementation public:     virtual ~CEx28cDoc(); #ifdef _DEBUG     virtual void AssertValid() const;     virtual void Dump(CDumpContext& dc) const; #endif // Generated message map functions public:     //{{AFX_MSG(CEx28cDoc)     afx_msg void OnModify();     afx_msg void OnFileUpdate();     afx_msg void OnUpdateFileUpdate(CCmdUI* pCmdUI);     //}}AFX_MSG     DECLARE_MESSAGE_MAP() }; //////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional //  declarations immediately before the previous line #endif  // !defined(AFX_EX28CDOC_H__1EAAB6F5_6011_11D0_848F_00400526305B  __INCLUDED_) 

Figure 28-8. The component's CEx28cDoc class handler file listing.

Here's a list of the important interface functions in ex28cDoc.cpp:

XOleObject::SetClientSite
XOleObject::DoVerb
XOleObject::Advise
XDataObject::GetData
XDataObject::QueryGetData
XDataObject::DAdvise
XPersistStorage::GetClassID
XPersistStorage::InitNew
XPersistStorage::Load
XPersistStorage::Save

You've seen the container code that draws a metafile. Here's the component code that creates it. The object handler calls the component's XDataObject::GetData function when it needs a metafile. This GetData implementation calls a helper function, MakeMetaFile, which creates the metafile picture. Compare the drawing code with the drawing code in CEx28cView::OnDraw.

 STDMETHODIMP CEx28cDoc::XDataObject::GetData(     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium) {     TRACE("CEx28cDoc::XDataObject::GetData -- %d\n",           lpFormatEtc->cfFormat);     METHOD_PROLOGUE(CEx28cDoc, DataObject)     ASSERT_VALID(pThis);     if (lpFormatEtc->cfFormat != CF_METAFILEPICT) {         return S_FALSE;     }     HGLOBAL hPict = pThis->MakeMetaFile();     lpStgMedium->tymed = TYMED_MFPICT;     lpStgMedium->hMetaFilePict = hPict;     lpStgMedium->pUnkForRelease = NULL;     return S_OK; } HGLOBAL CEx28cDoc::MakeMetaFile {     HGLOBAL hPict;     CMetaFileDC dcm;     VERIFY(dcm.Create());     CSize size(5000, 5000); // initial size of object in Excel & Word     dcm.SetMapMode(MM_ANISOTROPIC);     dcm.SetWindowOrg(0,0);     dcm.SetWindowExt(size.cx, -size.cy);     // drawing code     dcm.Rectangle(CRect(500, -1000, 1500, -2000));     CFont font;     font.CreateFont(-500, 0, 0, 0, 400, FALSE, FALSE, 0,                     ANSI_CHARSET, OUT_DEFAULT_PRECIS,                     CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,                     DEFAULT_PITCH | FF_SWISS, "Arial");     CFont* pFont = dcm.SelectObject(&font);     dcm.TextOut(0, 0, m_strText);     dcm.SelectObject(pFont);     HMETAFILE hMF = dcm.Close();     ASSERT(hMF != NULL);     hPict = ::GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE,                           sizeof(METAFILEPICT));     ASSERT(hPict != NULL);     LPMETAFILEPICT lpPict;     lpPict = (LPMETAFILEPICT) ::GlobalLock(hPict);     ASSERT(lpPict != NULL);     lpPict->mm = MM_ANISOTROPIC;     lpPict->hMF = hMF;     lpPict->xExt = size.cx;     lpPict->yExt = size.cy;  // HIMETRIC height     ::GlobalUnlock(hPict);     return hPict; } 

The XOleObject::Advise and the XDataObject::DAdvise functions are similar. Both functions call global OLE functions to set up OLE advise holder objects that can manage multiple advise sinks. (In this program, there is only one advise sink per OLE advise holder object.) The XOleObject::Advise function, listed below, establishes an OLE advise holder object with the IOleAdviseHolder interface. Other document functions call IOleAdviseHolder::SendOnClose and SendOnSave, which in turn call IAdviseSink::OnClose and OnSave for each attached sink.

 STDMETHODIMP CEx28cDoc::XOleObject::Advise(     IAdviseSink* pAdvSink, DWORD* pdwConnection) {     TRACE("CEx28cDoc::XOleObject::Advise\n");     METHOD_PROLOGUE(CEx28cDoc, OleObject)     ASSERT_VALID(pThis);     *pdwConnection = 0;     if (pThis->m_lpOleAdviseHolder == NULL &&         ::CreateOleAdviseHolder(&pThis->m_lpOleAdviseHolder)         != NOERROR) {             return E_OUTOFMEMORY;     }     ASSERT(pThis->m_lpOleAdviseHolder != NULL);     return pThis->m_lpOleAdviseHolder->Advise(pAdvSink,                                               pdwConnection); } 

The framework calls the OnModify function when the user chooses Modify from the EX28C-MAIN menu. The user enters a string through a dialog, and the function sends the OnDataChange notification to the object handler's data advise sink. (Figure 28-5 illustrates the advisory connections.)

Here is the OnModify function code:

 void CEx28cDoc::OnModify()  {     CTextDialog dlg;     dlg.m_strText = m_strText;     if (dlg.DoModal() == IDOK) {         m_strText = dlg.m_strText;         UpdateAllViews(NULL); // redraw view         // Notify the client that the metafile has changed.         //  Client must call IViewObject::SetAdvise.         LPDATAOBJECT lpDataObject =              (LPDATAOBJECT) GetInterface(&IID_IDataObject);         HRESULT hr =              m_lpDataAdviseHolder->SendOnDataChange(lpDataObject,                                                    0, NULL);         ASSERT(hr == NOERROR);         SetModifiedFlag(); // won't update without this     } } 

The framework calls the OnFileUpdate function when the user chooses Update from the File menu. The function calls IOleClientSite::SaveObject, which in turn causes the container to save the metafile and the object's native data in the storage. The function also sends the OnSave notification back to the client's advise sink. Here is the OnFileUpdate function code:

 void CEx28cDoc::OnFileUpdate()  {     if (m_lpClientSite == NULL) return;     VERIFY(m_lpClientSite->SaveObject() == NOERROR);     if (m_lpOleAdviseHolder != NULL)         m_lpOleAdviseHolder->SendOnSave();      SetModifiedFlag(FALSE); } 


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