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.
Now, it is time to test EX32B. Build and run, make sure there is no error lol! Select Edit Insert Object menu.
|
Figure 28: EX32B in action.
Select EX32A object, Ex32a Document. Click the OK button.
Figure 29: Selecting EX32A object, Ex32a Document. |
Figure 30: The embedded of the EX32A with in-place put side by side.
Figure 31: Modifying text in embedded mode.
Figure 32: Trying some new strings.
Figure 33: The new string in in-place and embedded modes.
Figure 34: Testing the Clear All menu.
Next, let try other object. Click the Edit Insert Object menu. Select Bitmap Image.
Figure 35: Selecting Bitmap Image object.
The default bitmap editor (Microsoft Paint) was launched. Then, select Edit Paste From menu of the Paint.
Figure 36: Default bitmap editor (Microsoft Paint) was launched.
Select any bitmap file sample. Do some editing for example, adding text as shown below.
---------------------------------------------------------------------
Figure 37: Do some editing to the bitmap.
Then select File Update menu.
Figure 38: Updating the edited bitmap.
Figure 39: The updated embedded and in-place modes.
For the Paste From menu, ASSERT failed for the OnEditPasteFrom(). You should debug this!
The Story
The CEx32bView Class
You can best understand the program by first concentrating on the view class. Look at the code in Listing 37, 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.
X32BVIEW.H
// ex32bView.h : interface of the CEx32bView class // /////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_EX32BVIEW_H__FDA1A035_08CC_454C_88DF_8311CA5A0B9C__INCLUDED_) #define AFX_EX32BVIEW_H__FDA1A035_08CC_454C_88DF_8311CA5A0B9C__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 CEx32bView : 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 CEx32bView(); DECLARE_DYNCREATE(CEx32bView)
// Attributes public: CEx32bDoc* GetDocument();
// Operations public:
// Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CEx32bView) public: virtual void OnDraw(CDC* pDC); // overridden to draw this view virtual BOOL PreCreateWindow(CREATESTRUCT& cs); protected: virtual void OnInitialUpdate(); // called first time after construct virtual BOOL OnPreparePrinting(CPrintInfo* pInfo); virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo); virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo); //}}AFX_VIRTUAL
// Implementation public: virtual ~CEx32bView(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif
protected:
// Generated message map functions protected: //{{AFX_MSG(CEx32bView) afx_msg void OnEditCopy(); afx_msg void OnUpdateEditCopy(CCmdUI* pCmdUI); afx_msg void OnEditCopyto(); afx_msg void OnEditCut(); afx_msg void OnEditInsertobject(); afx_msg void OnUpdateEditInsertobject(CCmdUI* pCmdUI); afx_msg void OnEditPaste(); afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); afx_msg void OnEditPastefrom(); afx_msg void OnUpdateEditPaste(CCmdUI* pCmdUI); //}}AFX_MSG DECLARE_MESSAGE_MAP() private: BOOL DoPasteObjectDescriptor(COleDataObject* pDataObject); BOOL DoPasteObject(COleDataObject* pDataObject); COleDataSource* SaveObject(); BOOL MakeMetafilePict(COleDataSource* pSource); void SetViewAdvise(); void SetNames(); void GetSize(); };
#ifndef _DEBUG // debug version in ex32bView.cpp inline CEx32bDoc* CEx32bView::GetDocument() { return (CEx32bDoc*)m_pDocument; } #endif
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_EX32BVIEW_H__FDA1A035_08CC_454C_88DF_8311CA5A0B9C__INCLUDED_)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
EX32BVIEW.CPP // ex32bView.cpp : implementation of the CEx32bView class //
#include "stdafx.h" #include "ex32b.h"
#include <afxole.h>
#include "ex32bDoc.h" #include "ex32bView.h"
#ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[ ] = __FILE__; #endif
///////////////////////////////////////////////////////////////////////////// // CEx32bView
IMPLEMENT_DYNCREATE(CEx32bView, CScrollView)
BEGIN_MESSAGE_MAP(CEx32bView, CScrollView) //{{AFX_MSG_MAP(CEx32bView) ON_COMMAND(ID_EDIT_COPY, OnEditCopy) ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy) ON_COMMAND(ID_EDIT_COPYTO, OnEditCopyto) ON_COMMAND(ID_EDIT_CUT, OnEditCut) ON_COMMAND(ID_EDIT_INSERTOBJECT, OnEditInsertobject) ON_UPDATE_COMMAND_UI(ID_EDIT_INSERTOBJECT, OnUpdateEditInsertobject) ON_COMMAND(ID_EDIT_PASTE, OnEditPaste) ON_WM_LBUTTONDBLCLK() ON_WM_LBUTTONDOWN() ON_WM_SETCURSOR() ON_COMMAND(ID_EDIT_PASTEFROM, OnEditPastefrom) ON_UPDATE_COMMAND_UI(ID_EDIT_COPYTO, OnUpdateEditCopy) ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCopy) ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste) //}}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()
///////////////////////////////////////////////////////////////////////////// // CEx32bView construction/destruction
CEx32bView::CEx32bView(): m_sizeTotal(20000, 25000), // 20 x 25 cm when printed m_rectTracker(0, 0, 0, 0) { // TODO: add construction code here m_cfObjDesc = ::RegisterClipboardFormat(CF_OBJECTDESCRIPTOR); m_cfEmbedded = ::RegisterClipboardFormat(CF_EMBEDDEDOBJECT); }
CEx32bView::~CEx32bView() { }
BOOL CEx32bView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CScrollView::PreCreateWindow(cs); }
///////////////////////////////////////////////////////////////////////////// // CEx32bView drawing
void CEx32bView::OnDraw(CDC* pDC) { CEx32bDoc* 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); }
void CEx32bView::OnInitialUpdate() { TRACE("CEx32bView::OnInitialUpdate\n"); m_rectTracker = CRect(1000, -1000, 5000, -5000); m_tracker.m_nStyle = CRectTracker::solidLine | CRectTracker::resizeOutside; SetScrollSizes(MM_HIMETRIC, m_sizeTotal); CScrollView::OnInitialUpdate(); }
///////////////////////////////////////////////////////////////////////////// // CEx32bView printing
BOOL CEx32bView::OnPreparePrinting(CPrintInfo* pInfo) { pInfo->SetMaxPage(1); return DoPreparePrinting(pInfo); }
void CEx32bView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing }
void CEx32bView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add cleanup after printing }
///////////////////////////////////////////////////////////////////////////// // CEx32bView diagnostics
#ifdef _DEBUG void CEx32bView::AssertValid() const { CScrollView::AssertValid(); }
void CEx32bView::Dump(CDumpContext& dc) const { CScrollView::Dump(dc); }
CEx32bDoc* CEx32bView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CEx32bDoc))); return (CEx32bDoc*)m_pDocument; } #endif //_DEBUG
///////////////////////////////////////////////////////////////////////////// // CEx32bView message handlers
void CEx32bView::OnEditCopy() { // TODO: Add your command handler code here COleDataSource* pSource = SaveObject(); if(pSource) { pSource->SetClipboard(); // OLE deletes data source } }
void CEx32bView::OnUpdateEditCopy(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here serves Copy, Cut, and Copy To pCmdUI->Enable(GetDocument()->m_lpOleObj != NULL); }
void CEx32bView::OnEditCopyto() { // TODO: Add your command handler code here // Copy text to an .STG file (nothing special about STG ext) CFileDialog dlg(FALSE, "stg", "*.stg"); if (dlg.DoModal() != IDOK) { return; } CEx32bDoc* pDoc = GetDocument(); // Create a structured storage home for the object (m_pStgSub). // Create a root storage file, then a sub-storage 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(CEx32bDoc::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 CEx32bView::OnEditCut() { // TODO: Add your command handler code here OnEditCopy(); GetDocument()->OnEditClearAll(); }
void CEx32bView::OnEditInsertobject() { // TODO: Add your command handler code here CEx32bDoc* 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 CEx32bView::OnUpdateEditInsertobject(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable(GetDocument()->m_lpOleObj == NULL); }
void CEx32bView::OnEditPaste() { // TODO: Add your command handler code here CEx32bDoc* pDoc = GetDocument(); COleDataObject dataObject; VERIFY(dataObject.AttachClipboard()); pDoc->DeleteContents(); DoPasteObjectDescriptor(&dataObject); DoPasteObject(&dataObject); SetViewAdvise(); GetSize(); pDoc->SetModifiedFlag(); pDoc->UpdateAllViews(NULL); }
void CEx32bView::OnUpdateEditPaste(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here // Make sure that object data is available COleDataObject dataObject; if (dataObject.AttachClipboard() && dataObject.IsDataAvailable(m_cfEmbedded)) { pCmdUI->Enable(TRUE); } else { pCmdUI->Enable(FALSE); } }
void CEx32bView::OnEditPastefrom() { // TODO: Add your command handler code here CEx32bDoc* pDoc = GetDocument(); // Paste from an .STG file CFileDialog dlg(TRUE, "stg", "*.stg"); if (dlg.DoModal() != IDOK) { return; } // Open the storage and sub storage 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(CEx32bDoc::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 CEx32bView::OnLButtonDblClk(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default if(m_tracker.HitTest(point) == CRectTracker::hitNothing) return; // Activate the object CEx32bDoc* 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(); } }
void CEx32bView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default TRACE("**Entering CEx32bView::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 CEx32bView::OnLButtonDown\n"); }
BOOL CEx32bView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { // TODO: Add your message handler code here and/or call default if(m_tracker.SetCursor(pWnd, nHitTest)) { return TRUE; } else { return CScrollView::OnSetCursor(pWnd, nHitTest, message); } }
void CEx32bView::GetSize() { CEx32bDoc* 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; } }
void CEx32bView::SetNames() { CEx32bDoc* pDoc = GetDocument(); CString strApp = AfxGetApp()->m_pszAppName; if(pDoc->m_lpOleObj != NULL) { pDoc->m_lpOleObj->SetHostNames(strApp.AllocSysString(), NULL); } }
void CEx32bView::SetViewAdvise() { CEx32bDoc* 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(); } }
BOOL CEx32bView::MakeMetafilePict(COleDataSource *pSource) { CEx32bDoc* 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; }
COleDataSource* CEx32bView::SaveObject() { TRACE("Entering CEx32bView::SaveObject\n"); CEx32bDoc* 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 CEx32bView::DoPasteObject(COleDataObject *pDataObject) { TRACE("Entering CEx32bView::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; } CEx32bDoc* 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 CEx32bView::DoPasteObjectDescriptor(COleDataObject *pDataObject) { TRACE("Entering CEx32bView::DoPasteObjectDescriptor\n"); STGMEDIUM stg; FORMATETC fmt; CEx32bDoc* 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->GetData(m_cfObjDesc, &stg, &fmt));
return TRUE; }
|
Listing 37: The container's CEx32bView class listing.
Further reading and digging:
Win32 process, thread and synchronization story can be found starting from Module R.
MSDN What's New (MFC Feature Pack) - feature pack.
DCOM at MSDN.
COM+ at MSDN.
COM at MSDN.
Unicode and Multi-byte character set: Story and program examples.