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.
Add the #include directive in ex32bView.cpp.
#include <afxole.h>
Listing 7.
Modify the constructor as shown below.
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);
}
--------------------------------------------------------------------------------------------------------------------------------------
Listing 8.
Modify the OnDraw() as shown below.
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);
}
Listing 9.
Edit OnPreparePrinting() as shown below.
BOOL CEx32bView::OnPreparePrinting(CPrintInfo* pInfo)
{
pInfo->SetMaxPage(1);
return DoPreparePrinting(pInfo);
}
Listing 10.
Edit OnInitialUpdate() as shown below.
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();
}
Listing 11.
Edit other message handlers as shown in the following codes.
void CEx32bView::OnEditCopy()
{
// TODO: Add your command handler code here
COleDataSource* pSource = SaveObject();
if(pSource)
{
pSource->SetClipboard(); // OLE deletes data source
}
}
Listing 12.
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);
}
Listing 13.
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();
}
Listing 14.
void CEx32bView::OnEditCut()
{
// TODO: Add your command handler code here
OnEditCopy();
GetDocument()->OnEditClearAll();
}
Listing 15.
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);
}
Listing 16.
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); }
}
Listing 17.
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);
}
Listing 18.
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");
}
Listing 19.
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);
}
}
Listing 20.
Complete other message handlers’ codes previously added.
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();
}
}
Listing 21.
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;
}
Listing 22. |
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;
}
Listing 23.
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;
}
Listing 24.
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 25.
Add the following prototype in ex32bDoc.h.
void ITrace(REFIID iid, const char* str);
Listing 26.
Manually add the following interface OleClientSite and AdviseSink.
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()
Listing 27.
Add the following friend class (in order to access the private variables and member functions).
friend class CEx32bView;
private:
LPOLEOBJECT m_lpOleObj;
LPSTORAGE m_pTempStgRoot;
LPSTORAGE m_pTempStgSub;
BOOL m_bHatch;
static const OLECHAR* s_szSub;
Listing 28.
Add the following constant in ex32bDoc.cpp.
const OLECHAR* CEx32bDoc::s_szSub = L"sub"; // static
Listing 29.
Add the following interface mapping of the OleClientSite and AdviseSink.
BEGIN_INTERFACE_MAP(CEx32bDoc, CDocument)
INTERFACE_PART(CEx32bDoc, IID_IOleClientSite, OleClientSite)
INTERFACE_PART(CEx32bDoc, IID_IAdviseSink, AdviseSink)
END_INTERFACE_MAP()
Listing 30.
Then, add the implementation of the OleClientSite.
/////////////////////////////////////////////////////////////////////////////
// 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;
}
And for AdviseSink.
//////////////////////////////////////////////////////////////////
// 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);
}
Add/edit other codes.
CEx32bDoc::CEx32bDoc()
{
// TODO: add one-time construction code here
m_lpOleObj = NULL;
m_pTempStgRoot = NULL;
m_pTempStgSub = NULL;
m_bHatch = FALSE;
}
Listing 31.
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();
}
Listing 32.
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;
}
}
Listing 33.
|
|
Listing 34.
Add the following #include directives for automation support in StdAfx.h.
#include <afxole.h>
#include <afxodlgs.h>
Listing 35.
Then add the following in ex32b.cpp at the beginning of the InitInstance().
AfxOleInit();
Listing 36.
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.