| Tenouk C & C++ | MFC Home | OLE & Containers 8 | ATL 1 | Download | Site Index |


 

 

 

 

 

OLE Embedded Components and Containers part 9

 

 

 

 

 

 

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. The Coding Part...continue

  2. The Story

  3. The CEx32cView Class

  4. The CEx32cDoc Class

 

 

Build the program. When the program is run standalone, the following prompt will be displayed.

 

Figure 23: EX32C output.

 

Figure 23: EX32C output.

 

You can use EX32B program to test this server program. Launch EX32B and select Edit Insert Object menu as shown below.

 

Figure 24: Using EX32B to test EX32C.

 

Figure 24: Using EX32B to test EX32C.

 

 

Select EX32c’s object, Ex32c Document.

 

Figure 25: Selecting EX32C’s object.

 

Figure 25: Selecting EX32C’s object.

 

Figure 26: EX32C object in embedded mode, side-by-side with EX32B.

 

Figure 26: EX32C object in embedded mode, side-by-side with EX32B.

 

Select Modify menu.

 

Figure 27: Testing the Modify menu in embedded mode.

 

Figure 27: Testing the Modify menu in embedded mode.

 

Enter some string to see the update and click the OK button.

 

Figure 28: Trying some new string.

 

Figure 28: Trying some new string.

 

Figure 29: The new string was updated, in-place and embedded, side-by-side.

 

Figure 29: The new string was updated, in-place and embedded, side-by-side.

 

The Story

 

The CEx32cView Class

 

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

 

void CEx32cView::OnDraw(CDC* pDC)

{

    CEx32cDoc* pDoc = GetDocument();

    ASSERT_VALID(pDoc);

 

    pDC->Rectangle(CRect(500, -1000, 1500, -2000));

    pDC->TextOut(0, 0, pDoc->m_strText);

}

 

void CEx32cView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)

{

    pDC->SetMapMode(MM_HIMETRIC);

}

 

The CEx32cDoc Class

 

This class does most of the component's work and is too big to list here. Listing 24 lists the header file, for other source codes, please refer to the program. A few of the important functions are listed here, however.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

EX32CDOC.H

 

// ex32cDoc.h : interface of the CEx32cDoc class

//

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

 

#if !defined(AFX_EX32CDOC_H__17B0D8FA_4B3A_45C6_A94F_3BC4EA49A0DE__INCLUDED_)

#define AFX_EX32CDOC_H__17B0D8FA_4B3A_45C6_A94F_3BC4EA49A0DE__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

extern const CLSID clsid; // defined in ex32c.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 CEx32cDoc : public CDocument

{

friend class CEx32cView;

 

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

       CEx32cDoc();

       DECLARE_DYNCREATE(CEx32cDoc)

 

// Attributes

public:

 

// Operations

public:

 

// Overrides

       // ClassWizard generated virtual function overrides

       //{{AFX_VIRTUAL(CEx32cDoc)

       public:

       virtual BOOL OnNewDocument();

       virtual void Serialize(CArchive& ar);

       virtual void OnCloseDocument();

       virtual void OnFinalRelease();

       protected:

       virtual BOOL SaveModified();

       //}}AFX_VIRTUAL

 

// Implementation

public:

       virtual ~CEx32cDoc();

#ifdef _DEBUG

       virtual void AssertValid() const;

       virtual void Dump(CDumpContext& dc) const;

#endif

 

protected:

 

// Generated message map functions

protected:

       //{{AFX_MSG(CEx32cDoc)

       afx_msg void OnModify();

       afx_msg void OnFileUpdate();

       afx_msg void OnUpdateFileUpdate(CCmdUI* pCmdUI);

       //}}AFX_MSG

       DECLARE_MESSAGE_MAP()

 

//     // Generated OLE dispatch map functions

//     //{{AFX_DISPATCH(CEx32cDoc)

//            // NOTE - the ClassWizard will add and remove member functions here.

//            //    DO NOT EDIT what you see in these blocks of generated code !

//     //}}AFX_DISPATCH

//     DECLARE_DISPATCH_MAP()

//     DECLARE_INTERFACE_MAP()

};

 

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

 

//{{AFX_INSERT_LOCATION}}

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

 

#endif // !defined(AFX_EX32CDOC_H__17B0D8FA_4B3A_45C6_A94F_3BC4EA49A0DE__INCLUDED_)

 

 

 

 

 

 

 

 

 

 

 

 

 

Listing 24:  The component's CEx32cDoc class handler file listing.

 

Here's a list of the important interface functions in ex32cDoc.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 CEx32cView::OnDraw.

 

STDMETHODIMP CEx32cDoc::XDataObject::GetData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)

{

    TRACE("CEx32cDoc::XDataObject::GetData -- %d\n", lpFormatEtc->cfFormat);

    METHOD_PROLOGUE(CEx32cDoc, 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 CEx32cDoc::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 CEx32cDoc::XOleObject::Advise(IAdviseSink* pAdvSink, DWORD* pdwConnection)

{

    TRACE("CEx32cDoc::XOleObject::Advise\n");

    METHOD_PROLOGUE(CEx32cDoc, 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 EX32C-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 CEx32cDoc::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 CEx32cDoc::OnFileUpdate()

{

    if (m_lpClientSite == NULL) return;

    VERIFY(m_lpClientSite->SaveObject() == NOERROR);

    if (m_lpOleAdviseHolder != NULL)

        m_lpOleAdviseHolder->SendOnSave();

    SetModifiedFlag(FALSE);

}

 

---------------------End part 3----------------------

 

 

 

 

 

 

 

 

 

 

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 8 | ATL 1 | Download | Site Index |