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.
|
The Coding Part
Add the following code to ex32c.h.
Listing 1.
Add the following code to the InitInstance() of ex32c.cpp.
Listing 2. |
Edit the following code portion.
// When a server application is launched stand-alone, it is a good idea
// to update the system registry in case it has been damaged.
m_server.UpdateRegistry(OAT_SERVER);
AfxMessageBox("Server can't be run stand-alone, use container -- Registry updated");
return FALSE;
// // Dispatch commands specified on the command line
// if (!ProcessShellCommand(cmdInfo))
// return FALSE;
// // The one and only window has been initialized, so show and update it.
// m_pMainWnd->ShowWindow(SW_SHOW);
// m_pMainWnd->UpdateWindow();
// return TRUE;
Listing 3.
And the following code to the ExitInstance().
int CEx32cApp::ExitInstance()
{
// TODO: Add your specialized code here and/or call the base class
TRACE("CEx32cApp::ExitInstance\n");
return CWinApp::ExitInstance();
}
Listing 4.
Edit the OnDraw() code of ex32cView.cpp.
void CEx32cView::OnDraw(CDC* pDC)
{
CEx32cDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->Rectangle(CRect(500, -1000, 1500, -2000));
pDC->TextOut(5, 5, pDoc->m_strText);
}
Listing 5.
Edit the OnPrepareDC() as shown below.
void CEx32cView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
// TODO: Add your specialized code here and/or call the base class
pDC->SetMapMode(MM_HIMETRIC);
}
Listing 6.
Add the following codes to ex32cDoc.h just after the preprocessor directives
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)
Listing 7.
Add the following friend class, then adds those member variables and member function.
friend class CEx32cView;
private:
CString m_strText;
LPOLECLIENTSITE m_lpClientSite;
LPOLEADVISEHOLDER m_lpOleAdviseHolder;
LPDATAADVISEHOLDER m_lpDataAdviseHolder;
CString m_strContainerApp;
CString m_strContainerObj;
HGLOBAL MakeMetaFile();
Listing 8.
Manually add the following interface for IOleObject, IDataObject and IPersistStorage just after the previous codes.
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()
Listing 9.
Delete (or comment out) the AppWizard generated DECLARE_DISPATCH_MAP and DECLARE_INTERFACE_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()
Listing 10.
Add the following #include directive to ex32cDoc.cpp.
#include "TextDialog.h"
Listing 11.
Manually add the following interface.
BEGIN_INTERFACE_MAP(CEx32cDoc, CDocument)
INTERFACE_PART(CEx32cDoc, IID_IOleObject, OleObject)
INTERFACE_PART(CEx32cDoc, IID_IDataObject, DataObject)
INTERFACE_PART(CEx32cDoc, IID_IPersistStorage, PersistStorage)
END_INTERFACE_MAP()
Listing 12.
Delete (or comment out) the auto AppWizard generated DISPATCH_MAP and INTERFACE_MAP.
// BEGIN_DISPATCH_MAP(CEx32cDoc, CDocument)
// //{{AFX_DISPATCH_MAP(CEx32cDoc)
// // NOTE - the ClassWizard will add and remove mapping macros here.
// // DO NOT EDIT what you see in these blocks of generated code!
// //}}AFX_DISPATCH_MAP
// END_DISPATCH_MAP()
// // Note: we add support for IID_IEx32c to support typesafe binding
// // from VBA. This IID must match the GUID that is attached to the
// // dispinterface in the .ODL file.
// // {100A83A5-C1FB-4EA7-8AFC-689433F842E8}
// static const IID IID_IEx32c =
// { 0x100a83a5, 0xc1fb, 0x4ea7, { 0x8a, 0xfc, 0x68, 0x94, 0x33, 0xf8, 0x42, 0xe8 } };
// BEGIN_INTERFACE_MAP(CEx32cDoc, CDocument)
// INTERFACE_PART(CEx32cDoc, IID_IEx32c, Dispatch)
// END_INTERFACE_MAP()
Listing 13.
Add the implementation for the interfaces. Firstly add the implementation for OleObject just after the previous commented codes.
///////////////////////////////////////////////////////////////////////
// CEx32cDoc OLE interface functions
STDMETHODIMP_(ULONG) CEx32cDoc::XOleObject::AddRef()
{
TRACE("CEx32cDoc::XOleObject::AddRef\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
return pThis->InternalAddRef();
}
STDMETHODIMP_(ULONG) CEx32cDoc::XOleObject::Release()
{
TRACE("CEx32cDoc::XOleObject::Release\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
return pThis->InternalRelease();
}
STDMETHODIMP CEx32cDoc::XOleObject::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
ITrace(iid, "CEx32cDoc::XOleObject::QueryInterface");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
return pThis->InternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP CEx32cDoc::XOleObject::SetClientSite(LPOLECLIENTSITE pClientSite)
{
TRACE("CEx32cDoc::XOleObject::SetClientSite\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
// linked objects do not support SetClientSite
if (pClientSite != NULL)
pClientSite->AddRef();
if(pThis->m_lpClientSite != NULL) pThis->m_lpClientSite->Release();
pThis->m_lpClientSite = pClientSite;
return NOERROR;
}
STDMETHODIMP CEx32cDoc::XOleObject::GetClientSite(LPOLECLIENTSITE* ppClientSite)
{
TRACE("CEx32cDoc::XOleObject::GetClientSite\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
*ppClientSite = pThis->m_lpClientSite;
if (pThis->m_lpClientSite != NULL)
pThis->m_lpClientSite->AddRef(); // IMPORTANT
return NOERROR;
}
STDMETHODIMP CEx32cDoc::XOleObject::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
{
TRACE("CEx32cDoc::XOleObject::SetHostNames\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
CString strTitle = "EX28C object embedded in ";
if(szContainerApp != NULL) {
strTitle += CString(szContainerApp);
}
CWnd* pWnd = AfxGetMainWnd();
pWnd->SetWindowText(strTitle);
return NOERROR;
}
STDMETHODIMP CEx32cDoc::XOleObject::Close(DWORD /*dwSaveOption*/)
{
TRACE("CEx32cDoc::XOleObject::Close\n");
// linked objects do not support close
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XOleObject::SetMoniker(DWORD /*dwWhichMoniker*/, LPMONIKER /*pmk*/)
{
TRACE("CEx32cDoc::XOleObject::SetMoniker\n");
// linked objects do not support SetMoniker
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XOleObject::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER* ppMoniker)
{
TRACE("CEx32cDoc::XOleObject::GetMoniker\n");
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XOleObject::InitFromData(LPDATAOBJECT /*pDataObject*/, BOOL /*fCreation*/, DWORD/*dwReserved*/)
{
TRACE("CEx32cDoc::XOleObject::InitFromData\n");
// linked objects do not support InitFromData
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XOleObject::GetClipboardData(DWORD /*dwReserved*/, LPDATAOBJECT* ppDataObject)
{
TRACE("CEx32cDoc::XOleObject::GetClipboardData\n");
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XOleObject::DoVerb(LONG iVerb, LPMSG lpmsg, LPOLECLIENTSITE pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lpPosRect)
{
TRACE("CEx32cDoc::XOleObject::DoVerb - %d\n", iVerb);
METHOD_PROLOGUE(CEx32cDoc, OleObject)
ASSERT_VALID(pThis);
pThis->InternalAddRef(); // protect this object
CWnd* pWnd = AfxGetMainWnd();
switch (iVerb)
{
// open - maps to OnOpen
case OLEIVERB_OPEN:
case -OLEIVERB_OPEN-1: // allows positive OLEIVERB_OPEN-1 in registry
case OLEIVERB_PRIMARY: // OLEIVERB_PRIMARY is 0 and "Edit" in registry
case OLEIVERB_SHOW:
pWnd->ShowWindow(SW_SHOW);
pWnd->SetActiveWindow();
pWnd->SetForegroundWindow();
break;
// hide maps to OnHide
case OLEIVERB_HIDE:
case -OLEIVERB_HIDE-1: // allows positive OLEIVERB_HIDE-1 in registry
return E_NOTIMPL;
default:
// negative verbs not understood should return E_NOTIMPL
if (iVerb < 0)
return E_NOTIMPL;
AfxThrowOleException(OLEOBJ_S_INVALIDVERB);
}
pThis->InternalRelease(); // may 'delete this'
pThis->m_lpClientSite->OnShowWindow(TRUE); // hatch
return NOERROR;
}
STDMETHODIMP CEx32cDoc::XOleObject::EnumVerbs(IEnumOLEVERB** ppenumOleVerb)
{
TRACE("CEx32cDoc::XOleObject::EnumVerbs\n");
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XOleObject::Update()
{
TRACE("CEx32cDoc::XOleObject::Update\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XOleObject::IsUpToDate()
{
TRACE("CEx32cDoc::XOleObject::IsUpToDate\n");
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XOleObject::GetUserClassID(CLSID* pClsid)
{
TRACE("CEx32cDoc::XOleObject::GetUserClassID\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
ASSERT_VALID(pThis);
return pThis->m_xPersistStorage.GetClassID(pClsid);
}
STDMETHODIMP CEx32cDoc::XOleObject::GetUserType(DWORD dwFormOfType, LPOLESTR* ppszUserType)
{
TRACE("CEx32cDoc::XOleObject::GetUserType\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
ASSERT_VALID(pThis);
*ppszUserType = NULL;
CLSID clsid;
pThis->m_xOleObject.GetUserClassID(&clsid);
return OleRegGetUserType(clsid, dwFormOfType, ppszUserType);
}
STDMETHODIMP CEx32cDoc::XOleObject::SetExtent(DWORD /*dwDrawAspect*/, LPSIZEL /*lpsizel*/)
{
TRACE("CEx32cDoc::XOleObject::SetExtent\n");
return E_FAIL;
}
STDMETHODIMP CEx32cDoc::XOleObject::GetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
{
TRACE("CEx32cDoc::XOleObject::GetExtent\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
ASSERT_VALID(pThis);
// handler returns extent in metafilepict
return E_NOTIMPL;
}
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);
}
STDMETHODIMP CEx32cDoc::XOleObject::Unadvise(DWORD dwConnection)
{
TRACE("CEx32cDoc::XOleObject::Unadvise\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
ASSERT_VALID(pThis);
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XOleObject::EnumAdvise(LPENUMSTATDATA* ppenumAdvise)
{
TRACE("CEx32cDoc::XOleObject::EnumAdvise\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
ASSERT_VALID(pThis);
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XOleObject::GetMiscStatus(DWORD dwAspect, DWORD* pdwStatus)
{
TRACE("CEx32cDoc::XOleObject::GetMiscStatus\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
ASSERT_VALID(pThis);
*pdwStatus = 0;
CLSID clsid;
pThis->m_xOleObject.GetUserClassID(&clsid);
return OleRegGetMiscStatus(clsid, dwAspect, pdwStatus);
}
STDMETHODIMP CEx32cDoc::XOleObject::SetColorScheme(LPLOGPALETTE lpLogpal)
{
TRACE("CEx32cDoc::XOleObject::SetColorScheme\n");
METHOD_PROLOGUE(CEx32cDoc, OleObject)
ASSERT_VALID(pThis);
return E_NOTIMPL;
}
Next, add the implementation codes for DataObject.
// CEx32cDoc::XDataObject
// delegate many calls to embedded COleDataSource object, which manages formats
STDMETHODIMP_(ULONG) CEx32cDoc::XDataObject::AddRef()
{
TRACE("CEx32cDoc::XDataObject::AddRef\n");
METHOD_PROLOGUE(CEx32cDoc, DataObject)
return pThis->InternalAddRef();
}
STDMETHODIMP_(ULONG) CEx32cDoc::XDataObject::Release()
{
TRACE("CEx32cDoc::XDataObject::Release\n");
METHOD_PROLOGUE(CEx32cDoc, DataObject)
return pThis->InternalRelease();
}
STDMETHODIMP CEx32cDoc::XDataObject::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
ITrace(iid, "CEx32cDoc::XDataObject::QueryInterface");
METHOD_PROLOGUE(CEx32cDoc, DataObject)
return pThis->InternalQueryInterface(&iid, ppvObj);
}
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;
}
STDMETHODIMP CEx32cDoc::XDataObject::GetDataHere(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
{
TRACE("CEx32cDoc::XDataObject::GetDataHere\n");
METHOD_PROLOGUE(CEx32cDoc, DataObject)
ASSERT_VALID(pThis);
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XDataObject::QueryGetData(LPFORMATETC lpFormatEtc)
{
TRACE("CEx32cDoc::XDataObject::QueryGetData -- %d\n", lpFormatEtc->cfFormat);
METHOD_PROLOGUE(CEx32cDoc, DataObject)
ASSERT_VALID(pThis);
if(lpFormatEtc->cfFormat != CF_METAFILEPICT) {
return S_FALSE;
}
return S_OK;
}
STDMETHODIMP CEx32cDoc::XDataObject::GetCanonicalFormatEtc(LPFORMATETC /*lpFormatEtcIn*/, LPFORMATETC /*lpFormatEtcOut*/)
{
TRACE("CEx32cDoc::XDataObject::GetCanonicalFormatEtc\n");
return DATA_S_SAMEFORMATETC;
}
STDMETHODIMP CEx32cDoc::XDataObject::SetData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium, BOOL bRelease)
{
TRACE("CEx32cDoc::XDataObject::SetData\n");
METHOD_PROLOGUE(CEx32cDoc, DataObject)
ASSERT_VALID(pThis);
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC* ppenumFormatEtc)
{
TRACE("CEx32cDoc::XDataObject::EnumFormatEtc\n");
METHOD_PROLOGUE(CEx32cDoc, DataObject)
ASSERT_VALID(pThis);
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XDataObject::DAdvise(FORMATETC* pFormatEtc, DWORD advf, LPADVISESINK pAdvSink, DWORD* pdwConnection)
{
TRACE("CEx32cDoc::XDataObject::DAdvise\n");
METHOD_PROLOGUE(CEx32cDoc, DataObject)
ASSERT_VALID(pThis);
*pdwConnection = 555;
// create the advise holder, if necessary
if (pThis->m_lpDataAdviseHolder == NULL &&
CreateDataAdviseHolder(&pThis->m_lpDataAdviseHolder) != S_OK) {
return E_OUTOFMEMORY;
}
ASSERT(pThis->m_lpDataAdviseHolder != NULL);
HRESULT hr = pThis->m_lpDataAdviseHolder->Advise(this, pFormatEtc, advf, pAdvSink, pdwConnection);
return hr;
}
STDMETHODIMP CEx32cDoc::XDataObject::DUnadvise(DWORD dwConnection)
{
TRACE("CEx32cDoc::XDataObject::DUnadvise\n");
METHOD_PROLOGUE(CEx32cDoc, DataObject)
ASSERT_VALID(pThis);
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XDataObject::EnumDAdvise(LPENUMSTATDATA* ppenumAdvise)
{
TRACE("CEx32cDoc::XDataObject::EnumDAdvise\n");
METHOD_PROLOGUE(CEx32cDoc, DataObject)
ASSERT_VALID(pThis);
return E_NOTIMPL;
}
Finally for PersistStorage.
/////////////////////////////////////////////////////////////
// XPersistStorage
STDMETHODIMP_(ULONG) CEx32cDoc::XPersistStorage::AddRef()
{
TRACE("CEx32cDoc::XPersistStorage:::AddRef\n");
METHOD_PROLOGUE(CEx32cDoc, PersistStorage)
return pThis->InternalAddRef();
}
STDMETHODIMP_(ULONG) CEx32cDoc::XPersistStorage::Release()
{
TRACE("CEx32cDoc::XPersistStorage::Release\n");
METHOD_PROLOGUE(CEx32cDoc, PersistStorage)
return pThis->InternalRelease();
}
STDMETHODIMP CEx32cDoc::XPersistStorage::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
ITrace(iid, "CEx32cDoc::XPersistStorage::QueryInterface");
METHOD_PROLOGUE(CEx32cDoc, PersistStorage)
return pThis->InternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP CEx32cDoc::XPersistStorage::GetClassID(LPCLSID lpClassID)
{
TRACE("CEx32cDoc::XPersistStorage::GetClassID\n");
METHOD_PROLOGUE(CEx32cDoc, PersistStorage)
ASSERT_VALID(pThis);
*lpClassID = clsid;
return NOERROR;
}
STDMETHODIMP CEx32cDoc::XPersistStorage::IsDirty()
{
TRACE("CEx32cDoc::XPersistStorage::IsDirty\n");
METHOD_PROLOGUE(CEx32cDoc, PersistStorage)
ASSERT_VALID(pThis);
return pThis->IsModified() ? NOERROR : S_FALSE;
}
STDMETHODIMP CEx32cDoc::XPersistStorage::InitNew(LPSTORAGE pStg)
{
TRACE("CEx32cDoc::XPersistStorage::InitNew\n");
METHOD_PROLOGUE(CEx32cDoc, PersistStorage)
ASSERT_VALID(pThis);
ASSERT(pStg != NULL);
pThis->SetModifiedFlag(); // new storage-based documents are dirty!
pThis->SendInitialUpdate(); // in CDocument
return NOERROR;
}
STDMETHODIMP CEx32cDoc::XPersistStorage::Load(LPSTORAGE pStgLoad)
{
TRACE("CEx32cDoc::XPersistStorage::Load\n");
METHOD_PROLOGUE(CEx32cDoc, PersistStorage)
ASSERT_VALID(pThis);
ASSERT(pStgLoad != NULL);
LPSTREAM pStream;
ULONG nBytesRead;
char buffer[101]; // 100 characters max for m_strText
try {
pThis->DeleteContents();
if(pStgLoad->OpenStream(L"Ex28c Text", NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream) == NOERROR) {
pStream->Read(buffer, 100, &nBytesRead);
pStream->Release();
pThis->m_strText = buffer;
}
}
catch(CException* pe) {
pe->Delete();
return E_FAIL;
}
pThis->SetModifiedFlag(); // new storage-based documents are dirty!
pThis->SendInitialUpdate(); // in CDocument
return NOERROR;
}
STDMETHODIMP CEx32cDoc::XPersistStorage::Save(LPSTORAGE pStgSave, BOOL fSameAsLoad)
{
TRACE("CEx32cDoc::XPersistStorage::Save\n");
METHOD_PROLOGUE(CEx32cDoc, PersistStorage)
ASSERT_VALID(pThis);
// don't bother saving if destination is up-to-date
if (fSameAsLoad && !pThis->IsModified())
return NOERROR;
ASSERT(pStgSave != NULL);
LPSTREAM pStream;
ULONG nBytesWritten;
try {
if(pStgSave->CreateStream(L"Ex28c Text", STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,0, 0, &pStream) == NOERROR)
{
pStream->Write((const char*) pThis->m_strText,
pThis->m_strText.GetLength() + 1, &nBytesWritten);
pStream->Release();
}
else return E_FAIL;
}
catch(CException* pe) {
pe->Delete();
return E_FAIL;
}
pThis->SetModifiedFlag(); // new storage-based documents are dirty!
pThis->SendInitialUpdate(); // in CDocument
return NOERROR;
}
STDMETHODIMP CEx32cDoc::XPersistStorage::SaveCompleted(LPSTORAGE pStgSaved)
{
TRACE("CEx32cDoc::XPersistStorage::SaveCompleted\n");
METHOD_PROLOGUE(CEx32cDoc, PersistStorage)
ASSERT_VALID(pThis);
return E_NOTIMPL;
}
STDMETHODIMP CEx32cDoc::XPersistStorage::HandsOffStorage()
{
TRACE("CEx32cDoc::XPersistStorage::HandsOffStorage\n");
METHOD_PROLOGUE(CEx32cDoc, PersistStorage)
ASSERT_VALID(pThis);
return E_NOTIMPL;
}
Add and/or edit other codes starting from the constructor.
CEx32cDoc::CEx32cDoc()
{
// TODO: add one-time construction code here
TRACE("CEx32cDoc ctor\n");
m_lpClientSite = NULL;
m_lpOleAdviseHolder = NULL;
m_lpDataAdviseHolder = NULL;
}
CEx32cDoc::~CEx32cDoc()
{
TRACE("CEx32cDoc dtor\n");
}
BOOL CEx32cDoc::OnNewDocument()
{
TRACE("CEx32cDoc::OnNewDocument\n");
if (!CDocument::OnNewDocument())
return FALSE;
m_strText = "Default text";
return TRUE;
}
Listing 14. |
This function is manually added if you not using ClassView during the adding of the MakeMetaFile() declaration in ex32cDoc.h.
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;
}
Listing 15.
Add the following global diagnostic jus after the Dump().
Listing 16.
Edit the OnCloseDocument().
void CEx32cDoc::OnCloseDocument()
{
// TODO: Add your specialized code here and/or call the base class
InternalAddRef();
if(m_lpClientSite != NULL) {
m_lpClientSite->OnShowWindow(FALSE); // no hatch
m_lpClientSite->Release();
}
if (m_lpOleAdviseHolder != NULL)
// you need to send a close notification
m_lpOleAdviseHolder->SendOnClose();
// finish closing the document (before m_lpClientSite->Release)
BOOL bAutoDelete = m_bAutoDelete;
m_bAutoDelete = FALSE;
CDocument::OnCloseDocument();
// disconnect the object
LPUNKNOWN lpUnknown = (LPUNKNOWN)GetInterface(&IID_IUnknown);
ASSERT(lpUnknown != NULL);
// this is very important to close circular references
CoDisconnectObject(lpUnknown, 0);
if(m_lpOleAdviseHolder != NULL)
m_lpOleAdviseHolder->Release();
if(m_lpDataAdviseHolder != NULL)
m_lpDataAdviseHolder->Release();
m_lpClientSite = NULL;
m_lpOleAdviseHolder = NULL;
m_lpDataAdviseHolder = NULL;
// remove InternalAddRef above
InterlockedDecrement(&m_dwRef);
if (bAutoDelete) {
delete this;
}
}
Listing 17.
Add/edit other codes.
void CEx32cDoc::OnModify()
{
// TODO: Add your command handler code here
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
}
}
Listing 18.
void CEx32cDoc::OnFinalRelease()
{
// TODO: Add your specialized code here and/or call the base class
TRACE("CEx32cDoc::OnFinalRelease\n"); // so we can see it happen
CDocument::OnFinalRelease();
}
Listing 19.
BOOL CEx32cDoc::SaveModified()
{
// TODO: Add your specialized code here and/or call the base class
OnFileUpdate();
return TRUE;
}
Listing 20.
void CEx32cDoc::OnFileUpdate()
{
// TODO: Add your command handler code here
if(m_lpClientSite == NULL) return;
VERIFY(m_lpClientSite->SaveObject() == NOERROR);
if (m_lpOleAdviseHolder != NULL)
m_lpOleAdviseHolder->SendOnSave();
SetModifiedFlag(FALSE);
}
void CEx32cDoc::OnUpdateFileUpdate(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->Enable(IsModified());
}
Listing 21.
Add the following #include directive in StdAfx.h.
#include <afxole.h> // MFC OLE classes
And delete (or comment out) the following #include directives.
#include <afxdisp.h>
#include <afxdtctl.h>
Listing 22.
Finally, just delete the ODL file (ex32c.odl) or leave it empty as shown below. Select the file and use the Edit Delete menu.
Listing 23.
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.