|
|
Microsoft Windows NT Build 297 06-28-1992
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and Microsoft
// QuickHelp documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "afxole.h"
#pragma hdrstop
#include "oleptr_.h"
#include <limits.h>
#include "shellapi.h"
#ifdef AFX_OLE_SEG
#pragma code_seg(AFX_OLE_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#define OLEEXPORT FAR PASCAL _export
/////////////////////////////////////////////////////////////////////////////
// Helper class for locking out main message pump during callbacks
class LOCK_PUMP
{
public:
LOCK_PUMP()
{
#ifdef _DEBUG
AfxGetApp()->EnablePump(FALSE);
#endif
}
~LOCK_PUMP()
{
#ifdef _DEBUG
AfxGetApp()->EnablePump(TRUE);
#endif
}
};
#define OLE_TRACE(string) \
if (afxTraceFlags & 0x10) \
TRACE(string)
/////////////////////////////////////////////////////////////////////////////
// OLEOBJECT callbacks mapping to COleServerItem virtual functions
inline COleServerItem * COleServerItem::FromLp(LPOLEOBJECT lpObject)
{
ASSERT(lpObject != NULL);
COleServerItem* pItem;
pItem = (COleServerItem*) GetPtrFromFarPtr(lpObject, sizeof(CObject));
ASSERT(lpObject == &pItem->m_oleObject);
return pItem;
}
// friend class to get access to COleServerItem protected implementations
struct _afxOleServerItemImplementation
{
static LPVOID OLEEXPORT
QueryProtocol(LPOLEOBJECT lpObject, OLE_LPCSTR lpszProtocol)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerItem::OnQueryProtocol()\n");
return COleServerItem::FromLp(lpObject)->OnQueryProtocol(lpszProtocol);
}
static OLESTATUS OLEEXPORT
Release(LPOLEOBJECT lpObject)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerItem::OnRelease()\n");
return COleServerItem::FromLp(lpObject)->OnRelease();
}
static OLESTATUS OLEEXPORT
Show(LPOLEOBJECT lpObject, BOOL bTakeFocus)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerItem::OnShow()\n");
return COleServerItem::FromLp(lpObject)->OnShow(bTakeFocus);
}
static OLESTATUS OLEEXPORT
DoVerb(LPOLEOBJECT lpObject, UINT nVerb, BOOL bShow, BOOL bTakeFocus)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerItem::OnDoVerb()\n");
OLESTATUS status;
status = COleServerItem::FromLp(lpObject)->OnDoVerb(nVerb, bShow,
bTakeFocus);
#ifdef _DEBUG
if ((afxTraceFlags & 0x10) && status != OLE_OK)
TRACE("COleServerItem::OnDoVerb(%d) failed\n", nVerb);
#endif
return status;
}
static OLESTATUS OLEEXPORT
GetData(LPOLEOBJECT lpObject, OLECLIPFORMAT nFormat,
LPHANDLE lphDataReturn)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerItem::OnGetData()\n");
OLESTATUS status;
status = COleServerItem::FromLp(lpObject)->OnGetData(nFormat, lphDataReturn);
#ifdef _DEBUG
if ((afxTraceFlags & 0x10) && status != OLE_OK)
TRACE("COleServerItem::OnGetData() failed to get format 0x%x\n",
nFormat);
#endif
return status;
}
static OLESTATUS OLEEXPORT
SetData(LPOLEOBJECT lpObject, OLECLIPFORMAT nFormat, HANDLE hData)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerItem::OnSetData()\n");
return COleServerItem::FromLp(lpObject)->OnSetData(nFormat, hData);
}
static OLESTATUS OLEEXPORT
SetTargetDevice(LPOLEOBJECT lpObject, HANDLE hData)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerItem::OnSetTargetDevice()\n");
OLESTATUS status;
status = COleServerItem::FromLp(lpObject)->OnSetTargetDevice(
(LPOLETARGETDEVICE)((hData == NULL) ? NULL : ::GlobalLock(hData)));
if (hData != NULL)
{
::GlobalUnlock(hData);
::GlobalFree(hData);
}
return status;
}
static OLESTATUS OLEEXPORT
SetBounds(LPOLEOBJECT lpObject, OLE_CONST RECT FAR* lpRect)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerItem::SetBounds()\n");
return COleServerItem::FromLp(lpObject)->OnSetBounds((LPRECT)lpRect);
}
static OLECLIPFORMAT OLEEXPORT
EnumFormats(LPOLEOBJECT lpObject, OLECLIPFORMAT nFormat)
{
OLECLIPFORMAT wNext;
LOCK_PUMP lock;
wNext = COleServerItem::FromLp(lpObject)->OnEnumFormats(nFormat);
#ifdef _DEBUG
if (afxTraceFlags & 0x10)
TRACE("COleServerItem::OnEnumFormats(0x%x) returns 0x%x\n",
nFormat, wNext);
#endif
return wNext;
}
static OLESTATUS OLEEXPORT
SetColorScheme(LPOLEOBJECT lpObject, OLE_CONST LOGPALETTE FAR* lpLogPalette)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerItem::SetColorScheme()\n");
return COleServerItem::FromLp(lpObject)->
OnSetColorScheme((LPLOGPALETTE)lpLogPalette);
}
};
static struct _OLEOBJECTVTBL NEAR objectVtbl =
{
&_afxOleServerItemImplementation::QueryProtocol,
&_afxOleServerItemImplementation::Release,
&_afxOleServerItemImplementation::Show,
&_afxOleServerItemImplementation::DoVerb,
&_afxOleServerItemImplementation::GetData,
&_afxOleServerItemImplementation::SetData,
&_afxOleServerItemImplementation::SetTargetDevice,
&_afxOleServerItemImplementation::SetBounds,
&_afxOleServerItemImplementation::EnumFormats,
&_afxOleServerItemImplementation::SetColorScheme,
};
//////////////////////////////////////////////////////////////////////////////
// Server view of embedded OLEOBJECT (includes back pointer to OLECLIENT)
IMPLEMENT_DYNAMIC(COleServerItem, CObject)
COleServerItem::COleServerItem()
{
m_oleObject.lpvtbl = &objectVtbl;
m_pDocument = NULL;
m_hPalette = NULL;
m_lpClient = NULL; // will be set later
m_rectBounds.SetRectEmpty();
}
COleServerItem::~COleServerItem()
{
ASSERT(m_lpClient == NULL); // must be released first
if (m_hPalette != NULL)
::DeleteObject(m_hPalette);
}
void
COleServerItem::BeginRevoke() // Start revoking the client connection
{
ASSERT(m_lpClient != NULL);
OLESTATUS status = ::OleRevokeObject(m_lpClient);
ASSERT(status == OLE_OK || status == OLE_WAIT_FOR_RELEASE);
// revoke will not be finished until OnRelease called
}
int
COleServerItem::NotifyClient(OLE_NOTIFICATION wNotify)
{
ASSERT(m_lpClient != NULL);
ASSERT(wNotify <= OLE_QUERY_RETRY); // last valid notification code
#ifdef _DEBUG
if (afxTraceFlags & 0x10)
TRACE("Notifying client item (wNotification = %d)\n", wNotify);
#endif
return (*m_lpClient->lpvtbl->CallBack)(m_lpClient, wNotify, &m_oleObject);
}
//////////////////////////////////////////////////////////////////////////////
// Default implementations
OLESTATUS
COleServerItem::OnRelease()
{
ASSERT(m_lpClient != NULL);
m_lpClient = NULL;
return OLE_OK;
}
OLESTATUS
COleServerItem::OnSetTargetDevice(LPOLETARGETDEVICE /*lpTargetDevice*/)
{
// default to ignore request
return OLE_OK;
}
BOOL
COleServerItem::OnGetTextData(CString& /*rStringReturn*/)
{
// default to not supported
return FALSE;
}
OLESTATUS
COleServerItem::OnExtraVerb(UINT /*nVerb*/)
{
return OLE_ERROR_DOVERB; // Error in sending do verb, or invalid
}
// Overridables you do not have to override
LPVOID
COleServerItem::OnQueryProtocol(LPCSTR lpszProtocol) const
{
if (_fstrcmp(lpszProtocol, "StdFileEditing") == 0)
return (LPVOID) &m_oleObject;
return NULL; // not supported
}
OLESTATUS
COleServerItem::OnSetColorScheme(LPLOGPALETTE lpLogPalette)
{
// save in item palette
HPALETTE hNewPal = ::CreatePalette(lpLogPalette);
if (hNewPal == NULL)
return OLE_ERROR_PALETTE;
if (m_hPalette != NULL)
::DeleteObject(m_hPalette);
m_hPalette = hNewPal;
return OLE_OK;
}
OLESTATUS
COleServerItem::OnSetBounds(LPRECT lpRect)
{
m_rectBounds = lpRect;
return OLE_OK;
}
OLESTATUS
COleServerItem::OnDoVerb(UINT nVerb, BOOL bShow, BOOL bTakeFocus)
{
OLESTATUS status;
if (nVerb == OLEVERB_PRIMARY)
{
status = OLE_OK;
}
else
{
status = OnExtraVerb(nVerb);
}
if ((status == OLE_OK) && bShow)
status = OnShow(bTakeFocus);
return status;
}
// Clipboard formats
static UINT cfNative = ::RegisterClipboardFormat("Native");
static UINT cfOwnerLink = ::RegisterClipboardFormat("OwnerLink");
static UINT cfObjectLink = ::RegisterClipboardFormat("ObjectLink");
static UINT formats[] =
{
cfNative, // native data format
CF_METAFILEPICT, // item rendered as a metafile
CF_TEXT, // optionally supported if OnGetTextData implemented
NULL
};
OLECLIPFORMAT
COleServerItem::OnEnumFormats(OLECLIPFORMAT nFormat) const
{
int index = 0;
if (nFormat != 0)
{
// find the last element
while (formats[index++] != nFormat)
;
}
return (OLECLIPFORMAT)formats[index];
}
HANDLE
COleServerItem::GetNativeData()
{
// get native data via serialization
CSharedFile memFile;
TRY
{
CArchive getArchive(&memFile, CArchive::store);
this->Serialize(getArchive); // store to archive
}
CATCH (CNotSupportedException, e)
{
memFile.Close();
return NULL; // not supported
}
AND_CATCH (CException, e)
{
memFile.Close();
THROW_LAST(); // will be caught in GetData
}
END_CATCH
return memFile.Detach();
}
HANDLE
COleServerItem::GetMetafileData()
{
CMetaFileDC dc;
if (!dc.Create())
return NULL;
if (m_hPalette)
{
::SelectPalette(dc.m_hDC, m_hPalette, TRUE);
dc.RealizePalette();
}
// Paint directly into the metafile.
if (!OnDraw(&dc))
{
OLE_TRACE("calling COleServerItem::OnDraw() failed\n");
return NULL; // will destroy DC
}
HMETAFILE hMF = (HMETAFILE)dc.Close();
if (hMF == NULL)
return NULL;
HANDLE hPict;
if ((hPict = ::GlobalAlloc(GMEM_DDESHARE, sizeof(METAFILEPICT))) == NULL)
{
DeleteMetaFile(hMF);
return NULL;
}
LPMETAFILEPICT lpPict;
if ((lpPict = (LPMETAFILEPICT)::GlobalLock(hPict)) == NULL)
{
DeleteMetaFile(hMF);
::GlobalFree(hPict);
return NULL;
}
lpPict->mm = MM_ANISOTROPIC;
lpPict->hMF = hMF;
lpPict->xExt = m_rectBounds.Width();
lpPict->yExt = m_rectBounds.Height(); // will be negative for HiMetric
::GlobalUnlock(hPict);
return hPict;
}
OLESTATUS
COleServerItem::OnGetData(OLECLIPFORMAT nFormat, LPHANDLE lphReturn)
{
HANDLE hData = NULL; // default to not supported
TRY
{
if (nFormat == cfNative)
{
hData = GetNativeData();
}
else if (nFormat == CF_METAFILEPICT)
{
hData = GetMetafileData();
}
else if (nFormat == CF_TEXT)
{
CString text;
if (OnGetTextData(text))
{
// allocate a global block for the string
hData = ::GlobalAlloc(GMEM_DDESHARE, text.GetLength() + 1);
if (hData == NULL)
AfxThrowMemoryException();
LPSTR lpszText = (LPSTR)::GlobalLock(hData);
ASSERT(lpszText != NULL);
_fstrcpy(lpszText, (const char*) text);
::GlobalUnlock(hData);
}
}
else
{
TRACE("Warning: OLE get data, unknown format %d\n", nFormat);
}
}
CATCH (COleException, e)
{
return e->m_status;
}
AND_CATCH (CException, e)
{
// other exceptions
return OLE_ERROR_MEMORY;
}
END_CATCH
if (hData == NULL)
return OLE_ERROR_FORMAT; // not supported
// return the data
*lphReturn = hData;
return OLE_OK;
}
OLESTATUS
COleServerItem::OnSetData(OLECLIPFORMAT nFormat, HANDLE hData)
{
if (nFormat != cfNative)
{
::GlobalFree(hData);
return OLE_ERROR_FORMAT; // Requested format is not available
}
// set native data via serialization
CSharedFile memFile;
memFile.SetHandle(hData);
TRY
{
CArchive setArchive(&memFile, CArchive::load);
this->Serialize(setArchive); // load me
}
CATCH (CException, e)
{
memFile.Close();
return OLE_ERROR_GENERIC;
}
END_CATCH
return OLE_OK;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// COleServerDoc
inline COleServerDoc * COleServerDoc::FromLp(LPOLESERVERDOC lpServerDoc)
{
COleServerDoc* pDoc;
pDoc = (COleServerDoc*) GetPtrFromFarPtr(lpServerDoc, sizeof(CObject));
ASSERT(lpServerDoc == &pDoc->m_oleServerDoc);
return pDoc;
}
// friend class to get access to COleServerDoc protected implementations
struct _afxOleServerDocImplementation
{
static OLESTATUS OLEEXPORT
Save(LPOLESERVERDOC lpServerDoc)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerDoc::OnSave()\n");
return COleServerDoc::FromLp(lpServerDoc)->OnSave();
}
static OLESTATUS OLEEXPORT
Close(LPOLESERVERDOC lpServerDoc)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerDoc::OnClose()\n");
return COleServerDoc::FromLp(lpServerDoc)->OnClose();
}
static OLESTATUS OLEEXPORT
SetHostNames(LPOLESERVERDOC lpServerDoc,
OLE_LPCSTR lpszClient, OLE_LPCSTR lpszDoc)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerDoc::OnSetHostNames()\n");
OLESTATUS status = COleServerDoc::FromLp(lpServerDoc)->OnSetHostNames(
lpszClient, lpszDoc);
return status;
}
static OLESTATUS OLEEXPORT
SetDocDimensions(LPOLESERVERDOC lpServerDoc, OLE_CONST RECT FAR* lpRect)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerDoc::OnSetDocDimensions()\n");
return COleServerDoc::FromLp(lpServerDoc)->OnSetDocDimensions((LPRECT)lpRect);
}
static OLESTATUS OLEEXPORT
Release(LPOLESERVERDOC lpServerDoc)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerDoc::OnRelease()\n");
return COleServerDoc::FromLp(lpServerDoc)->OnRelease();
}
static OLESTATUS OLEEXPORT
SetColorScheme(LPOLESERVERDOC lpServerDoc,
OLE_CONST LOGPALETTE FAR* lpLogPalette)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerDoc::OnSetColorScheme()\n");
OLESTATUS status = COleServerDoc::FromLp(lpServerDoc)->OnSetColorScheme(
(LPLOGPALETTE)lpLogPalette);
return status;
}
static OLESTATUS OLEEXPORT
Execute(LPOLESERVERDOC lpServerDoc, HANDLE hCommands)
{
LOCK_PUMP lock;
OLE_TRACE("COleServerDoc::OnExecute()\n");
LPVOID lpCommands = ::GlobalLock(hCommands);
ASSERT(lpCommands != NULL);
OLESTATUS status;
status = COleServerDoc::FromLp(lpServerDoc)->OnExecute(lpCommands);
::GlobalUnlock(hCommands);
return status;
}
static OLESTATUS OLEEXPORT
GetObject(LPOLESERVERDOC lpServerDoc, OLE_LPCSTR lpszObjname,
LPOLEOBJECT FAR * lplpObject, LPOLECLIENT lpClient)
{
COleServerDoc* pDoc = COleServerDoc::FromLp(lpServerDoc);
COleServerItem* pItem;
LOCK_PUMP lock;
TRY
{
if (lpszObjname == NULL || *lpszObjname == '\0')
{
OLE_TRACE("calling COleServerDoc::OnGetDocument\n");
pItem = pDoc->OnGetDocument();
}
else
{
#ifdef _DEBUG
if (afxTraceFlags & 0x10)
TRACE("calling COleServerDoc::GetItem(%Fs)\n", lpszObjname);
#endif
pItem = pDoc->OnGetItem(lpszObjname);
}
}
CATCH (CException, e)
{
return COleException::Process(e);
}
END_CATCH
if (pItem == NULL)
return OLE_ERROR_GENERIC;
pDoc->AddItem(pItem, lpClient); // attaches everything
*lplpObject = &pItem->m_oleObject;
return OLE_OK;
}
};
static struct _OLESERVERDOCVTBL NEAR serverDocVtbl =
{
&_afxOleServerDocImplementation::Save,
&_afxOleServerDocImplementation::Close,
&_afxOleServerDocImplementation::SetHostNames,
&_afxOleServerDocImplementation::SetDocDimensions,
&_afxOleServerDocImplementation::GetObject,
&_afxOleServerDocImplementation::Release,
&_afxOleServerDocImplementation::SetColorScheme,
&_afxOleServerDocImplementation::Execute,
};
/////////////////////////////////////////////////////////////////////////////
// COleServerDoc construction and other operations
COleServerDoc::COleServerDoc()
{
m_oleServerDoc.lpvtbl = &serverDocVtbl;
m_pServer = NULL;
m_lhServerDoc = NULL;
m_hPalette = NULL;
m_bWaiting = FALSE;
}
IMPLEMENT_DYNAMIC(COleServerDoc, CObject)
COleServerDoc::~COleServerDoc()
{
if (IsOpen())
BeginRevoke();
if (m_hPalette != NULL)
::DeleteObject(m_hPalette);
}
void
COleServerDoc::CheckAsync(OLESTATUS status)
// throw exception if not ok to continue
{
ASSERT(!m_bWaiting);
if (status == OLE_WAIT_FOR_RELEASE)
{
m_bWaiting = TRUE;
while (m_bWaiting)
{
OLE_TRACE("OLE Server Doc waiting for release\n");
AfxGetApp()->PumpMessage();
}
m_bWaiting = FALSE;
return; // assume it worked
}
if (status == OLE_OK || status > OLE_WARN_DELETE_DATA)
{
// ok, or just a warning
return;
}
// otherwise this error wasn't expected, so throw an exception
TRACE("Warning: COleServerDoc operation failed %d, throwing exception\n", status);
AfxThrowOleException(status);
}
OLESTATUS
COleServerDoc::BeginRevoke()
// do not wait for async completion
{
ASSERT(IsOpen());
LHCLIENTDOC lh = m_lhServerDoc;
ASSERT(lh != NULL);
if (m_pServer != NULL)
m_pServer->RemoveDocument(this);
m_lhServerDoc = NULL;
OLESTATUS status = ::OleRevokeServerDoc(lh);
ASSERT(status == OLE_OK || status == OLE_WAIT_FOR_RELEASE);
// revoke will not be finished until OnRelease called
return status;
}
void
COleServerDoc::Revoke()
// wait for async completion
{
ASSERT(IsOpen());
CheckAsync(BeginRevoke());
}
/////////////////////////////////////////////////////////////////////////////
// Interesting operations
BOOL
COleServerDoc::Register(COleServer* pServer, LPCSTR lpszDoc)
{
ASSERT(m_lhServerDoc == NULL); // one time only
ASSERT(pServer != NULL);
ASSERT(pServer->IsOpen());
LHSERVERDOC lhDoc;
if (::OleRegisterServerDoc(pServer->m_lhServer, lpszDoc,
&m_oleServerDoc, &lhDoc) != OLE_OK)
{
return FALSE;
}
pServer->AddDocument(this, lhDoc);
ASSERT(m_lhServerDoc == lhDoc); // make sure it connected it
return TRUE;
}
void
COleServerDoc::NotifyRename(LPCSTR lpszNewName)
{
ASSERT(IsOpen());
ASSERT(lpszNewName != NULL);
CheckAsync(::OleRenameServerDoc(m_lhServerDoc, lpszNewName));
}
void
COleServerDoc::NotifyRevert()
{
ASSERT(IsOpen());
CheckAsync(::OleRevertServerDoc(m_lhServerDoc));
}
void
COleServerDoc::NotifySaved()
{
ASSERT(IsOpen());
CheckAsync(::OleSavedServerDoc(m_lhServerDoc));
}
void
COleServerDoc::NotifyAllClients(OLE_NOTIFICATION wNotify)
{
POSITION pos = GetStartPosition();
COleServerItem* pItem;
while ((pItem = GetNextItem(pos)) != NULL)
{
pItem->NotifyClient(wNotify);
}
}
void
COleServerDoc::AddItem(COleServerItem* pItem, LPOLECLIENT lpClient)
{
ASSERT_VALID(pItem);
// Attach handle to un-attached item
ASSERT(pItem->m_lpClient == NULL); // must be unattached !
ASSERT(pItem->m_pDocument == NULL); // must be unconnected !
pItem->m_lpClient = lpClient;
pItem->m_pDocument = this;
}
/////////////////////////////////////////////////////////////////////////////
// COleServerDoc standard implementation of overridables
OLESTATUS
COleServerDoc::OnRelease()
{
OLE_TRACE("COleServerDoc::OnRelease\n");
m_bWaiting = FALSE;
// close connection to OLE server doc
m_lhServerDoc = NULL;
return OLE_OK;
}
OLESTATUS
COleServerDoc::OnSave()
{
return OLE_OK;
}
OLESTATUS
COleServerDoc::OnClose()
{
ASSERT(IsOpen());
BeginRevoke();
return OLE_OK;
}
OLESTATUS
COleServerDoc::OnExecute(LPVOID /*lpCommands*/) // DDE commands
{
return OLE_ERROR_COMMAND;
}
OLESTATUS
COleServerDoc::OnSetDocDimensions(LPRECT /*lpRect*/)
{
return OLE_OK; // default to ignore it
}
// Overridables you do not have to override
OLESTATUS
COleServerDoc::OnSetHostNames(LPCSTR /*lpszHost*/, LPCSTR /*lpszHostObj*/)
{
return OLE_OK;
}
OLESTATUS
COleServerDoc::OnSetColorScheme(LPLOGPALETTE lpLogPalette)
{
// save in global document palette
HPALETTE hNewPal = ::CreatePalette(lpLogPalette);
if (hNewPal == NULL)
return OLE_ERROR_PALETTE;
if (m_hPalette != NULL)
::DeleteObject(m_hPalette);
m_hPalette = hNewPal;
return OLE_OK;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// COleServer
inline COleServer * COleServer::FromLp(LPOLESERVER lpServer)
{
COleServer* pOleServer;
pOleServer = (COleServer*) GetPtrFromFarPtr(lpServer, sizeof(CObject));
ASSERT(lpServer == &pOleServer->m_oleServer);
return pOleServer;
}
// friend class to get access to COleServer protected implementations
struct _afxOleServerImplementation
{
static OLESTATUS OLEEXPORT
Exit(LPOLESERVER lpServer)
{
LOCK_PUMP lock;
OLE_TRACE("COleServer::OnExit()\n");
return COleServer::FromLp(lpServer)->OnExit();
}
static OLESTATUS OLEEXPORT
Release(LPOLESERVER lpServer)
{
LOCK_PUMP lock;
OLE_TRACE("COleServer::OnRelease()\n");
return COleServer::FromLp(lpServer)->OnRelease();
}
static OLESTATUS OLEEXPORT
Execute(LPOLESERVER lpServer, HANDLE hCommands)
{
LOCK_PUMP lock;
OLE_TRACE("COleServer::Execute()\n");
LPVOID lpCommands = ::GlobalLock(hCommands);
ASSERT(lpCommands != NULL);
OLESTATUS status;
status = COleServer::FromLp(lpServer)->OnExecute(lpCommands);
::GlobalUnlock(hCommands);
return status;
}
static OLESTATUS OLEEXPORT
Open(LPOLESERVER lpServer, LHSERVERDOC lhServerDoc,
OLE_LPCSTR lpszDoc, LPOLESERVERDOC FAR * lplpServerDoc)
{
LOCK_PUMP lock;
OLE_TRACE("COleServer::OnOpenDoc()\n");
COleServer* pServer = COleServer::FromLp(lpServer);
COleServerDoc* pDoc;
TRY
pDoc = pServer->OnOpenDoc(lpszDoc);
CATCH (CException, e)
return COleException::Process(e);
END_CATCH
if (pDoc == NULL)
return OLE_ERROR_GENERIC;
pServer->AddDocument(pDoc, lhServerDoc);
*lplpServerDoc = &pDoc->m_oleServerDoc;
return OLE_OK;
}
static OLESTATUS OLEEXPORT
Create(LPOLESERVER lpServer, LHSERVERDOC lhServerDoc,
OLE_LPCSTR lpszClass, OLE_LPCSTR lpszDoc, LPOLESERVERDOC FAR * lplpServerDoc)
{
LOCK_PUMP lock;
OLE_TRACE("COleServer::OnCreateDoc()\n");
COleServer* pServer = COleServer::FromLp(lpServer);
COleServerDoc* pDoc;
TRY
pDoc = pServer->OnCreateDoc(lpszClass, lpszDoc);
CATCH (CException, e)
return COleException::Process(e);
END_CATCH
if (pDoc == NULL)
return OLE_ERROR_GENERIC;
pServer->AddDocument(pDoc, lhServerDoc);
*lplpServerDoc = &pDoc->m_oleServerDoc;
return OLE_OK;
}
static OLESTATUS OLEEXPORT
CreateFromTemplate(LPOLESERVER lpServer, LHSERVERDOC lhServerDoc,
OLE_LPCSTR lpszClass, OLE_LPCSTR lpszDoc, OLE_LPCSTR lpszTemplate,
LPOLESERVERDOC FAR * lplpServerDoc)
{
LOCK_PUMP lock;
OLE_TRACE("COleServer::OnCreateDocFromTemplate()\n");
COleServer* pServer = COleServer::FromLp(lpServer);
COleServerDoc* pDoc;
TRY
pDoc = pServer->OnCreateDocFromTemplate(lpszClass,
lpszDoc, lpszTemplate);
CATCH (CException, e)
return COleException::Process(e);
END_CATCH
if (pDoc == NULL)
return OLE_ERROR_GENERIC;
pServer->AddDocument(pDoc, lhServerDoc);
*lplpServerDoc = &pDoc->m_oleServerDoc;
return OLE_OK;
}
static OLESTATUS OLEEXPORT
Edit(LPOLESERVER lpServer, LHSERVERDOC lhServerDoc,
OLE_LPCSTR lpszClass, OLE_LPCSTR lpszDoc, LPOLESERVERDOC FAR * lplpServerDoc)
{
LOCK_PUMP lock;
OLE_TRACE("COleServer::OnEditDoc()\n");
COleServer* pServer = COleServer::FromLp(lpServer);
COleServerDoc* pDoc;
TRY
pDoc = pServer->OnEditDoc(lpszClass, lpszDoc);
CATCH (CException, e)
return COleException::Process(e);
END_CATCH
if (pDoc == NULL)
return OLE_ERROR_GENERIC;
pServer->AddDocument(pDoc, lhServerDoc);
*lplpServerDoc = &pDoc->m_oleServerDoc;
return OLE_OK;
}
};
static struct _OLESERVERVTBL NEAR serverVtbl =
{
&_afxOleServerImplementation::Open,
&_afxOleServerImplementation::Create,
&_afxOleServerImplementation::CreateFromTemplate,
&_afxOleServerImplementation::Edit,
&_afxOleServerImplementation::Exit,
&_afxOleServerImplementation::Release,
&_afxOleServerImplementation::Execute,
};
//////////////////////////////////////////////////////////////////////////////
// COleServer construction etc
COleServer::COleServer(BOOL bLaunchEmbedded)
{
m_oleServer.lpvtbl = &serverVtbl;
m_lhServer = NULL;
m_cOpenDocuments = 0;
m_bLaunchEmbedded = bLaunchEmbedded;
}
IMPLEMENT_DYNAMIC(COleServer, CObject)
COleServer::~COleServer()
{
if (IsOpen())
BeginRevoke(); // server death
}
void
COleServer::BeginRevoke()
{
ASSERT(IsOpen());
LHSERVER lhServer = m_lhServer;
if (lhServer != NULL)
{
m_lhServer = NULL; // closed for all intensive purposes
OLESTATUS status = ::OleRevokeServer(lhServer);
ASSERT(status == OLE_OK || status == OLE_WAIT_FOR_RELEASE);
}
// NOTE: will return before the Revoke is acknowledged
}
BOOL
COleServer::Register(LPCSTR lpszClass, BOOL bMultiInstance)
{
ASSERT(m_lhServer == NULL); // one time only
ASSERT(lpszClass != NULL);
OLE_SERVER_USE use = bMultiInstance ? OLE_SERVER_MULTI : OLE_SERVER_SINGLE;
return ::OleRegisterServer(lpszClass, &m_oleServer, &m_lhServer,
AfxGetInstanceHandle(), use) == OLE_OK;
}
//////////////////////////////////////////////////////////////////////////////
// COleServer manages COleServerDocs
void COleServer::AddDocument(COleServerDoc* pDoc, LHSERVERDOC lhServerDoc)
{
// Attach handle to un-open server document
ASSERT_VALID(pDoc);
ASSERT(pDoc->m_lhServerDoc == NULL); // must be unregistered !
ASSERT(pDoc->m_pServer == NULL); // must be dis-connected
ASSERT(lhServerDoc != NULL);
// connect to server
pDoc->m_lhServerDoc = lhServerDoc;
pDoc->m_pServer = this;
m_cOpenDocuments++;
}
void COleServer::RemoveDocument(COleServerDoc* pDoc)
{
ASSERT(pDoc != NULL);
ASSERT(pDoc->m_pServer == this);
ASSERT(m_cOpenDocuments > 0);
pDoc->m_pServer = NULL;
m_cOpenDocuments--;
}
//////////////////////////////////////////////////////////////////////////////
// COleServer default implementation of overridables
COleServerDoc* COleServer::OnOpenDoc(LPCSTR /*lpszDoc*/)
{
return NULL;
}
COleServerDoc* COleServer::OnCreateDocFromTemplate(LPCSTR /*lpszClass*/,
LPCSTR /*lpszDoc*/, LPCSTR /*lpszTemplate*/)
{
return NULL;
}
OLESTATUS COleServer::OnExecute(LPVOID /*lpCommands*/) // DDE commands
{
return OLE_ERROR_COMMAND;
}
OLESTATUS COleServer::OnExit()
{
if (IsOpen())
{
OLE_TRACE("COleServer::OnExit() Revoking server\n");
BeginRevoke();
}
return OLE_OK;
}
OLESTATUS COleServer::OnRelease()
{
CWnd* pMainWnd = AfxGetApp()->m_pMainWnd;
if (IsOpen() && m_bLaunchEmbedded)
{
// there is a chance we should be shutting down
// shut down if no open documents, or if main window is invisible
if (m_cOpenDocuments == 0 ||
(pMainWnd != NULL && !pMainWnd->IsWindowVisible()))
{
OLE_TRACE("COleServer::OnRelease() Revoking server\n");
BeginRevoke();
}
}
// if someone has already revoked us
if (!IsOpen())
{
TRACE("COleServer::OnRelease() terminating server app\n");
OLE_TRACE("\tcalling ::PostQuitMessage\n");
::PostQuitMessage(0);
}
return OLE_OK;
}
//////////////////////////////////////////////////////////////////////////////
// Special register for server in case user does not run REGLOAD
BOOL AfxOleRegisterServerName(LPCSTR lpszClass, LPCSTR lpszLocalClassName)
{
ASSERT(lpszClass != NULL && *lpszClass != '\0');
LONG lSize;
char szBuffer[OLE_MAXNAMESIZE];
if (lpszLocalClassName == NULL || *lpszLocalClassName == '\0')
{
TRACE("Warning: no localized class name provided for server,"
" using %Fs\n", lpszClass);
lpszLocalClassName = lpszClass;
}
lSize = OLE_MAXNAMESIZE;
if (::RegQueryValue(HKEY_CLASSES_ROOT, lpszClass, szBuffer,
&lSize) == ERROR_SUCCESS)
{
// don't replace an existing localized name
TRACE("Server already has localized class name (%s)\n", szBuffer);
}
else
{
// set localized (user visible) class name
if (::RegSetValue(HKEY_CLASSES_ROOT, lpszClass, REG_SZ,
lpszLocalClassName, _fstrlen(lpszLocalClassName)) != ERROR_SUCCESS)
return FALSE;
}
// set the path name for the server for "StdFileEditing" to this app
// get name/path of executable
char szPathName[256];
::GetModuleFileName(AfxGetInstanceHandle(), szPathName,
sizeof(szPathName)-1);
wsprintf(szBuffer, "%s\\protocol\\StdFileEditing\\server",
(LPCSTR)lpszClass);
if (::RegSetValue(HKEY_CLASSES_ROOT, szBuffer, REG_SZ,
szPathName, strlen(szPathName)) != ERROR_SUCCESS)
return FALSE;
// if there are no verbs, throw in the default "Edit" verb
// (Note: we hard code the English "Edit" so you should have
// a .REG file for localized verb names)
char szOldVerb[256];
wsprintf(szBuffer, "%s\\protocol\\StdFileEditing\\verb",
(LPCSTR)lpszClass);
lSize = OLE_MAXNAMESIZE;
if (::RegQueryValue(HKEY_CLASSES_ROOT, szBuffer, szOldVerb,
&lSize) != ERROR_SUCCESS)
{
// no verbs, add "Edit"
if (::RegSetValue(HKEY_CLASSES_ROOT, szBuffer, REG_SZ,
"", 0) != ERROR_SUCCESS)
return FALSE;
strcat(szBuffer, "\\0"); // backslash + zero
if (::RegSetValue(HKEY_CLASSES_ROOT, szBuffer, REG_SZ,
"Edit", 4) != ERROR_SUCCESS)
return FALSE;
}
// all set
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
// Diagnostics
#ifdef _DEBUG
void COleServerItem::AssertValid() const
{
CObject::AssertValid();
// must be completely detached or completely attached
ASSERT((m_pDocument == NULL && m_lpClient == NULL) ||
(m_pDocument != NULL && m_lpClient != NULL));
}
void COleServerItem::Dump(CDumpContext& dc) const
{
CObject::Dump(dc);
// shallow dump
dc << "\n\tm_pDocument = " << (void*)m_pDocument;
dc << "\n\tm_lpClient = " << m_lpClient;
dc << "\n\tm_hPalette = " << m_hPalette;
dc << "\n\tm_rectBounds (HIMETRIC) = " << m_rectBounds;
}
void COleServerDoc::AssertValid() const
{
CObject::AssertValid();
ASSERT(!m_bWaiting); // waiting is an internal state
}
void COleServerDoc::Dump(CDumpContext& dc) const
{
CObject::Dump(dc);
dc << "\n\tm_pServer = " << (void*)m_pServer;
dc << "\n\tm_lhServerDoc = " << m_lhServerDoc;
dc << "\n\tm_bWaiting = " << m_bWaiting;
}
void COleServer::AssertValid() const
{
CObject::AssertValid();
ASSERT(m_cOpenDocuments >= 0);
}
void COleServer::Dump(CDumpContext& dc) const
{
CObject::Dump(dc);
dc << "\n\tm_lhServer = " << m_lhServer;
dc << "\n\tm_bLaunchEmbedded = " << m_bLaunchEmbedded;
dc << "\n\tm_cOpenDocuments = " << m_cOpenDocuments;
}
#endif //_DEBUG
//////////////////////////////////////////////////////////////////////////////
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.