mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1538 lines
41 KiB
1538 lines
41 KiB
/*************************************************************************
|
|
**
|
|
** OLE 2 Server Sample Code
|
|
**
|
|
** svrpsobj.c
|
|
**
|
|
** This file contains all PseudoObj methods and related support
|
|
** functions.
|
|
**
|
|
** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
|
|
**
|
|
*************************************************************************/
|
|
|
|
|
|
#include "outline.h"
|
|
|
|
OLEDBGDATA
|
|
|
|
extern LPOUTLINEAPP g_lpApp;
|
|
extern IUnknownVtbl g_PseudoObj_UnknownVtbl;
|
|
extern IOleObjectVtbl g_PseudoObj_OleObjectVtbl;
|
|
extern IDataObjectVtbl g_PseudoObj_DataObjectVtbl;
|
|
|
|
|
|
/* PseudoObj_Init
|
|
** --------------
|
|
** Initialize fields in a newly constructed PseudoObj.
|
|
** NOTE: ref cnt of PseudoObj initialized to 0
|
|
*/
|
|
void PseudoObj_Init(
|
|
LPPSEUDOOBJ lpPseudoObj,
|
|
LPSERVERNAME lpServerName,
|
|
LPSERVERDOC lpServerDoc
|
|
)
|
|
{
|
|
OleDbgOut2("++PseudoObj Created\r\n");
|
|
|
|
lpPseudoObj->m_cRef = 0;
|
|
lpPseudoObj->m_lpName = lpServerName;
|
|
lpPseudoObj->m_lpDoc = lpServerDoc;
|
|
lpPseudoObj->m_lpOleAdviseHldr = NULL;
|
|
lpPseudoObj->m_lpDataAdviseHldr = NULL;
|
|
lpPseudoObj->m_fObjIsClosing = FALSE;
|
|
|
|
INIT_INTERFACEIMPL(
|
|
&lpPseudoObj->m_Unknown,
|
|
&g_PseudoObj_UnknownVtbl,
|
|
lpPseudoObj
|
|
);
|
|
|
|
INIT_INTERFACEIMPL(
|
|
&lpPseudoObj->m_OleObject,
|
|
&g_PseudoObj_OleObjectVtbl,
|
|
lpPseudoObj
|
|
);
|
|
|
|
INIT_INTERFACEIMPL(
|
|
&lpPseudoObj->m_DataObject,
|
|
&g_PseudoObj_DataObjectVtbl,
|
|
lpPseudoObj
|
|
);
|
|
|
|
/* OLE2NOTE: Increment the refcnt of the Doc on behalf of the
|
|
** PseudoObj. the Document should not shut down unless all
|
|
** pseudo objects are closed. when a pseudo object is destroyed,
|
|
** it calls ServerDoc_PseudoObjUnlockDoc to release this hold on
|
|
** the document.
|
|
*/
|
|
ServerDoc_PseudoObjLockDoc(lpServerDoc);
|
|
}
|
|
|
|
|
|
|
|
/* PseudoObj_AddRef
|
|
** ----------------
|
|
**
|
|
** increment the ref count of the PseudoObj object.
|
|
**
|
|
** Returns the new ref count on the object
|
|
*/
|
|
ULONG PseudoObj_AddRef(LPPSEUDOOBJ lpPseudoObj)
|
|
{
|
|
++lpPseudoObj->m_cRef;
|
|
|
|
#if defined( _DEBUG )
|
|
OleDbgOutRefCnt4(
|
|
"PseudoObj_AddRef: cRef++\r\n",
|
|
lpPseudoObj,
|
|
lpPseudoObj->m_cRef
|
|
);
|
|
#endif
|
|
return lpPseudoObj->m_cRef;
|
|
}
|
|
|
|
|
|
/* PseudoObj_Release
|
|
** -----------------
|
|
**
|
|
** decrement the ref count of the PseudoObj object.
|
|
** if the ref count goes to 0, then the PseudoObj is destroyed.
|
|
**
|
|
** Returns the remaining ref count on the object
|
|
*/
|
|
ULONG PseudoObj_Release(LPPSEUDOOBJ lpPseudoObj)
|
|
{
|
|
ULONG cRef;
|
|
|
|
/*********************************************************************
|
|
** OLE2NOTE: when the obj refcnt == 0, then destroy the object. **
|
|
** otherwise the object is still in use. **
|
|
*********************************************************************/
|
|
|
|
cRef = --lpPseudoObj->m_cRef;
|
|
|
|
#if defined( _DEBUG )
|
|
OleDbgAssertSz(lpPseudoObj->m_cRef >= 0,"Release called with cRef == 0");
|
|
|
|
OleDbgOutRefCnt4(
|
|
"PseudoObj_Release: cRef--\r\n", lpPseudoObj,cRef);
|
|
#endif
|
|
|
|
if (cRef == 0)
|
|
PseudoObj_Destroy(lpPseudoObj);
|
|
|
|
return cRef;
|
|
}
|
|
|
|
|
|
/* PseudoObj_QueryInterface
|
|
** ------------------------
|
|
**
|
|
** Retrieve a pointer to an interface on the PseudoObj object.
|
|
**
|
|
** Returns S_OK if interface is successfully retrieved.
|
|
** E_NOINTERFACE if the interface is not supported
|
|
*/
|
|
HRESULT PseudoObj_QueryInterface(
|
|
LPPSEUDOOBJ lpPseudoObj,
|
|
REFIID riid,
|
|
LPVOID FAR* lplpvObj
|
|
)
|
|
{
|
|
SCODE sc = E_NOINTERFACE;
|
|
|
|
/* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */
|
|
*lplpvObj = NULL;
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown)) {
|
|
OleDbgOut4("PseudoObj_QueryInterface: IUnknown* RETURNED\r\n");
|
|
|
|
*lplpvObj = (LPVOID) &lpPseudoObj->m_Unknown;
|
|
PseudoObj_AddRef(lpPseudoObj);
|
|
sc = S_OK;
|
|
}
|
|
else if (IsEqualIID(riid, &IID_IOleObject)) {
|
|
OleDbgOut4("PseudoObj_QueryInterface: IOleObject* RETURNED\r\n");
|
|
|
|
*lplpvObj = (LPVOID) &lpPseudoObj->m_OleObject;
|
|
PseudoObj_AddRef(lpPseudoObj);
|
|
sc = S_OK;
|
|
}
|
|
else if (IsEqualIID(riid, &IID_IDataObject)) {
|
|
OleDbgOut4("PseudoObj_QueryInterface: IDataObject* RETURNED\r\n");
|
|
|
|
*lplpvObj = (LPVOID) &lpPseudoObj->m_DataObject;
|
|
PseudoObj_AddRef(lpPseudoObj);
|
|
sc = S_OK;
|
|
}
|
|
|
|
OleDbgQueryInterfaceMethod(*lplpvObj);
|
|
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
/* PseudoObj_Close
|
|
* ---------------
|
|
*
|
|
* Close the pseudo object. Force all external connections to close
|
|
* down. This causes link clients to release this PseudoObj. when
|
|
* the refcount actually reaches 0, then the PseudoObj will be
|
|
* destroyed.
|
|
*
|
|
* Returns:
|
|
* FALSE -- user canceled the closing of the doc.
|
|
* TRUE -- the doc was successfully closed
|
|
*/
|
|
|
|
BOOL PseudoObj_Close(LPPSEUDOOBJ lpPseudoObj)
|
|
{
|
|
LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpPseudoObj->m_lpDoc;
|
|
LPSERVERNAME lpServerName = (LPSERVERNAME)lpPseudoObj->m_lpName;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
|
|
BOOL fStatus = TRUE;
|
|
|
|
if (lpPseudoObj->m_fObjIsClosing)
|
|
return TRUE; // Closing is already in progress
|
|
|
|
lpPseudoObj->m_fObjIsClosing = TRUE; // guard against recursive call
|
|
|
|
OLEDBG_BEGIN3("PseudoObj_Close\r\n")
|
|
|
|
/* OLE2NOTE: in order to have a stable App, Doc, AND pseudo object
|
|
** during the process of closing, we intially AddRef the App,
|
|
** Doc, and PseudoObj ref counts and later Release them. These
|
|
** initial AddRefs are artificial; they are simply done to
|
|
** guarantee that these objects do not get destroyed until the
|
|
** end of this routine.
|
|
*/
|
|
OleApp_AddRef(lpOleApp);
|
|
OleDoc_AddRef(lpOleDoc);
|
|
PseudoObj_AddRef(lpPseudoObj);
|
|
|
|
if (lpPseudoObj->m_lpDataAdviseHldr) {
|
|
/* OLE2NOTE: send last OnDataChange notification to clients
|
|
** that have registered for data notifications when object
|
|
** stops running (ADVF_DATAONSTOP)
|
|
*/
|
|
PseudoObj_SendAdvise(
|
|
lpPseudoObj,
|
|
OLE_ONDATACHANGE,
|
|
NULL, /* lpmkObj -- not relevant here */
|
|
ADVF_DATAONSTOP
|
|
);
|
|
|
|
/* OLE2NOTE: we just sent the last data notification that we
|
|
** need to send; release our DataAdviseHolder. we SHOULD be
|
|
** the only one using it.
|
|
*/
|
|
OleStdVerifyRelease(
|
|
(LPUNKNOWN)lpPseudoObj->m_lpDataAdviseHldr,
|
|
"DataAdviseHldr not released properly"
|
|
);
|
|
lpPseudoObj->m_lpDataAdviseHldr = NULL;
|
|
}
|
|
|
|
if (lpPseudoObj->m_lpOleAdviseHldr) {
|
|
// OLE2NOTE: inform all of our linking clients that we are closing.
|
|
PseudoObj_SendAdvise(
|
|
lpPseudoObj,
|
|
OLE_ONCLOSE,
|
|
NULL, /* lpmkObj -- not relevant here */
|
|
0 /* advf -- not relevant here */
|
|
);
|
|
|
|
/* OLE2NOTE: OnClose is the last notification that we need to
|
|
** send; release our OleAdviseHolder. we SHOULD be the only
|
|
** one using it. this will make our destructor realize that
|
|
** OnClose notification has already been sent.
|
|
*/
|
|
OleStdVerifyRelease(
|
|
(LPUNKNOWN)lpPseudoObj->m_lpOleAdviseHldr,
|
|
"OleAdviseHldr not released properly"
|
|
);
|
|
lpPseudoObj->m_lpOleAdviseHldr = NULL;
|
|
}
|
|
|
|
/* OLE2NOTE: this call forces all external connections to our
|
|
** object to close down and therefore guarantees that we receive
|
|
** all releases associated with those external connections.
|
|
*/
|
|
OLEDBG_BEGIN2("CoDisconnectObject called\r\n")
|
|
CoDisconnectObject((LPUNKNOWN)&lpPseudoObj->m_Unknown, 0);
|
|
OLEDBG_END2
|
|
|
|
PseudoObj_Release(lpPseudoObj); // release artificial AddRef above
|
|
OleDoc_Release(lpOleDoc); // release artificial AddRef above
|
|
OleApp_Release(lpOleApp); // release artificial AddRef above
|
|
|
|
OLEDBG_END3
|
|
return fStatus;
|
|
}
|
|
|
|
|
|
/* PseudoObj_Destroy
|
|
** -----------------
|
|
** Destroy (Free) the memory used by a PseudoObj structure.
|
|
** This function is called when the ref count of the PseudoObj goes
|
|
** to zero. the ref cnt goes to zero after PseudoObj_Delete forces
|
|
** the OleObject to unload and release its pointers to the
|
|
** PseudoObj IOleClientSite and IAdviseSink interfaces.
|
|
*/
|
|
|
|
void PseudoObj_Destroy(LPPSEUDOOBJ lpPseudoObj)
|
|
{
|
|
LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
|
|
|
|
OLEDBG_BEGIN3("PseudoObj_Destroy\r\n")
|
|
|
|
/* OLE2NOTE: in order to have a stable App, Doc, AND pseudo object
|
|
** during the process of closing, we intially AddRef the App,
|
|
** Doc ref counts and later Release them. These
|
|
** initial AddRefs are artificial; they are simply done to
|
|
** guarantee that these objects do not get destroyed until the
|
|
** end of this routine.
|
|
*/
|
|
OleApp_AddRef(lpOleApp);
|
|
OleDoc_AddRef(lpOleDoc);
|
|
|
|
/******************************************************************
|
|
** OLE2NOTE: we no longer need the advise and enum holder objects,
|
|
** so release them.
|
|
******************************************************************/
|
|
|
|
if (lpPseudoObj->m_lpDataAdviseHldr) {
|
|
/* release DataAdviseHldr; we SHOULD be the only one using it. */
|
|
OleStdVerifyRelease(
|
|
(LPUNKNOWN)lpPseudoObj->m_lpDataAdviseHldr,
|
|
"DataAdviseHldr not released properly"
|
|
);
|
|
lpPseudoObj->m_lpDataAdviseHldr = NULL;
|
|
}
|
|
|
|
if (lpPseudoObj->m_lpOleAdviseHldr) {
|
|
/* release OleAdviseHldr; we SHOULD be the only one using it. */
|
|
OleStdVerifyRelease(
|
|
(LPUNKNOWN)lpPseudoObj->m_lpOleAdviseHldr,
|
|
"OleAdviseHldr not released properly"
|
|
);
|
|
lpPseudoObj->m_lpOleAdviseHldr = NULL;
|
|
}
|
|
|
|
/* forget the pointer to destroyed PseudoObj in NameTable */
|
|
if (lpPseudoObj->m_lpName)
|
|
lpPseudoObj->m_lpName->m_lpPseudoObj = NULL;
|
|
|
|
/* OLE2NOTE: release the lock on the Doc held on behalf of the
|
|
** PseudoObj. the Document should not shut down unless all
|
|
** pseudo objects are closed. when a pseudo object is first
|
|
** created, it calls ServerDoc_PseudoObjLockDoc to guarantee
|
|
** that the document stays alive (called from PseudoObj_Init).
|
|
*/
|
|
ServerDoc_PseudoObjUnlockDoc(lpServerDoc, lpPseudoObj);
|
|
|
|
Delete(lpPseudoObj); // Free the memory for the structure itself
|
|
|
|
OleDoc_Release(lpOleDoc); // release artificial AddRef above
|
|
OleApp_Release(lpOleApp); // release artificial AddRef above
|
|
|
|
OLEDBG_END3
|
|
}
|
|
|
|
|
|
/* PseudoObj_GetSel
|
|
** ----------------
|
|
** Return the line range for the pseudo object
|
|
*/
|
|
void PseudoObj_GetSel(LPPSEUDOOBJ lpPseudoObj, LPLINERANGE lplrSel)
|
|
{
|
|
LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpPseudoObj->m_lpName;
|
|
lplrSel->m_nStartLine = lpOutlineName->m_nStartLine;
|
|
lplrSel->m_nEndLine = lpOutlineName->m_nEndLine;
|
|
}
|
|
|
|
|
|
/* PseudoObj_GetExtent
|
|
* -------------------
|
|
*
|
|
* Get the extent (width, height) of the entire document.
|
|
*/
|
|
void PseudoObj_GetExtent(LPPSEUDOOBJ lpPseudoObj, LPSIZEL lpsizel)
|
|
{
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpPseudoObj->m_lpDoc;
|
|
LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
|
|
LINERANGE lrSel;
|
|
|
|
PseudoObj_GetSel(lpPseudoObj, (LPLINERANGE)&lrSel);
|
|
|
|
LineList_CalcSelExtentInHimetric(lpLL, (LPLINERANGE)&lrSel, lpsizel);
|
|
}
|
|
|
|
|
|
/* PseudoObj_SendAdvise
|
|
* --------------------
|
|
*
|
|
* This function sends an advise notification on behalf of a specific
|
|
* doc object to all its clients.
|
|
*/
|
|
void PseudoObj_SendAdvise(
|
|
LPPSEUDOOBJ lpPseudoObj,
|
|
WORD wAdvise,
|
|
LPMONIKER lpmkObj,
|
|
DWORD dwAdvf
|
|
)
|
|
{
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpPseudoObj->m_lpDoc;
|
|
|
|
switch (wAdvise) {
|
|
|
|
case OLE_ONDATACHANGE:
|
|
|
|
// inform clients that the data of the object has changed
|
|
|
|
if (lpOutlineDoc->m_nDisableDraw == 0) {
|
|
/* drawing is currently enabled. inform clients that
|
|
** the data of the object has changed
|
|
*/
|
|
|
|
lpPseudoObj->m_fDataChanged = FALSE;
|
|
if (lpPseudoObj->m_lpDataAdviseHldr) {
|
|
|
|
OLEDBG_BEGIN2("IDataAdviseHolder::SendOnDataChange called\r\n");
|
|
lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->SendOnDataChange(
|
|
lpPseudoObj->m_lpDataAdviseHldr,
|
|
(LPDATAOBJECT)&lpPseudoObj->m_DataObject,
|
|
0,
|
|
dwAdvf
|
|
);
|
|
OLEDBG_END2
|
|
}
|
|
|
|
} else {
|
|
/* drawing is currently disabled. do not send
|
|
** notifications until drawing is re-enabled.
|
|
*/
|
|
lpPseudoObj->m_fDataChanged = TRUE;
|
|
}
|
|
break;
|
|
|
|
case OLE_ONCLOSE:
|
|
|
|
// inform clients that the object is shutting down
|
|
|
|
if (lpPseudoObj->m_lpOleAdviseHldr) {
|
|
|
|
OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose called\r\n");
|
|
lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->SendOnClose(
|
|
lpPseudoObj->m_lpOleAdviseHldr
|
|
);
|
|
OLEDBG_END2
|
|
}
|
|
break;
|
|
|
|
case OLE_ONSAVE:
|
|
|
|
// inform clients that the object has been saved
|
|
|
|
if (lpPseudoObj->m_lpOleAdviseHldr) {
|
|
|
|
OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose called\r\n");
|
|
lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->SendOnSave(
|
|
lpPseudoObj->m_lpOleAdviseHldr
|
|
);
|
|
OLEDBG_END2
|
|
}
|
|
break;
|
|
|
|
case OLE_ONRENAME:
|
|
|
|
// inform clients that the object's name has changed
|
|
if (lpmkObj && lpPseudoObj->m_lpOleAdviseHldr) {
|
|
|
|
OLEDBG_BEGIN2("IOleAdviseHolder::SendOnRename called\r\n");
|
|
if (lpPseudoObj->m_lpOleAdviseHldr)
|
|
lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->SendOnRename(
|
|
lpPseudoObj->m_lpOleAdviseHldr,
|
|
lpmkObj
|
|
);
|
|
OLEDBG_END2
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* PseudoObj_GetFullMoniker
|
|
* ------------------------
|
|
*
|
|
* Returns the Full, absolute Moniker which identifies this pseudo object.
|
|
*/
|
|
LPMONIKER PseudoObj_GetFullMoniker(LPPSEUDOOBJ lpPseudoObj, LPMONIKER lpmkDoc)
|
|
{
|
|
LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpPseudoObj->m_lpName;
|
|
LPMONIKER lpmkItem = NULL;
|
|
LPMONIKER lpmkPseudoObj = NULL;
|
|
|
|
if (lpmkDoc != NULL) {
|
|
CreateItemMonikerA(OLESTDDELIM,lpOutlineName->m_szName,&lpmkItem);
|
|
|
|
/* OLE2NOTE: create an absolute moniker which identifies the
|
|
** pseudo object. this moniker is created as a composite of
|
|
** the absolute moniker for the entire document appended
|
|
** with an item moniker which identifies the selection of
|
|
** the pseudo object relative to the document.
|
|
*/
|
|
CreateGenericComposite(lpmkDoc, lpmkItem, &lpmkPseudoObj);
|
|
|
|
if (lpmkItem)
|
|
OleStdRelease((LPUNKNOWN)lpmkItem);
|
|
|
|
return lpmkPseudoObj;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
** PseudoObj::IUnknown interface implementation
|
|
*************************************************************************/
|
|
|
|
STDMETHODIMP PseudoObj_Unk_QueryInterface(
|
|
LPUNKNOWN lpThis,
|
|
REFIID riid,
|
|
LPVOID FAR* lplpvObj
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjUnknownImpl FAR*)lpThis)->lpPseudoObj;
|
|
|
|
return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObj);
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) PseudoObj_Unk_AddRef(LPUNKNOWN lpThis)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjUnknownImpl FAR*)lpThis)->lpPseudoObj;
|
|
|
|
OleDbgAddRefMethod(lpThis, "IUnknown");
|
|
|
|
return PseudoObj_AddRef(lpPseudoObj);
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) PseudoObj_Unk_Release (LPUNKNOWN lpThis)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjUnknownImpl FAR*)lpThis)->lpPseudoObj;
|
|
|
|
OleDbgReleaseMethod(lpThis, "IUnknown");
|
|
|
|
return PseudoObj_Release(lpPseudoObj);
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
** PseudoObj::IOleObject interface implementation
|
|
*************************************************************************/
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_QueryInterface(
|
|
LPOLEOBJECT lpThis,
|
|
REFIID riid,
|
|
LPVOID FAR* lplpvObj
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
|
|
return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObj);
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) PseudoObj_OleObj_AddRef(LPOLEOBJECT lpThis)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
|
|
OleDbgAddRefMethod(lpThis, "IOleObject");
|
|
|
|
return PseudoObj_AddRef((LPPSEUDOOBJ)lpPseudoObj);
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) PseudoObj_OleObj_Release(LPOLEOBJECT lpThis)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
|
|
OleDbgReleaseMethod(lpThis, "IOleObject");
|
|
|
|
return PseudoObj_Release((LPPSEUDOOBJ)lpPseudoObj);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_SetClientSite(
|
|
LPOLEOBJECT lpThis,
|
|
LPOLECLIENTSITE lpClientSite
|
|
)
|
|
{
|
|
OleDbgOut2("PseudoObj_OleObj_SetClientSite\r\n");
|
|
|
|
// OLE2NOTE: a pseudo object does NOT support SetExtent
|
|
|
|
return ResultFromScode(E_FAIL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_GetClientSite(
|
|
LPOLEOBJECT lpThis,
|
|
LPOLECLIENTSITE FAR* lplpClientSite
|
|
)
|
|
{
|
|
OleDbgOut2("PseudoObj_OleObj_GetClientSite\r\n");
|
|
|
|
*lplpClientSite = NULL;
|
|
|
|
// OLE2NOTE: a pseudo object does NOT support SetExtent
|
|
|
|
return ResultFromScode(E_FAIL);
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_SetHostNamesA(
|
|
LPOLEOBJECT lpThis,
|
|
LPCSTR szContainerApp,
|
|
LPCSTR szContainerObj
|
|
)
|
|
{
|
|
OleDbgOut2("PseudoObj_OleObj_SetHostNamesA\r\n");
|
|
|
|
// OLE2NOTE: a pseudo object does NOT support SetExtent
|
|
|
|
return ResultFromScode(E_FAIL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_SetHostNames(
|
|
LPOLEOBJECT lpThis,
|
|
LPCOLESTR szContainerApp,
|
|
LPCOLESTR szContainerObj
|
|
)
|
|
{
|
|
OleDbgOut2("PseudoObj_OleObj_SetHostNames\r\n");
|
|
|
|
// OLE2NOTE: a pseudo object does NOT support SetExtent
|
|
|
|
return ResultFromScode(E_FAIL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_Close(
|
|
LPOLEOBJECT lpThis,
|
|
DWORD dwSaveOption
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
BOOL fStatus;
|
|
|
|
OLEDBG_BEGIN2("PseudoObj_OleObj_Close\r\n")
|
|
|
|
/* OLE2NOTE: a pseudo object's implementation of IOleObject::Close
|
|
** should ignore the dwSaveOption parameter. it is NOT
|
|
** applicable to pseudo objects.
|
|
*/
|
|
|
|
fStatus = PseudoObj_Close(lpPseudoObj);
|
|
OleDbgAssertSz(fStatus == TRUE, "PseudoObj_OleObj_Close failed\r\n");
|
|
|
|
OLEDBG_END2
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_SetMoniker(
|
|
LPOLEOBJECT lpThis,
|
|
DWORD dwWhichMoniker,
|
|
LPMONIKER lpmk
|
|
)
|
|
{
|
|
OleDbgOut2("PseudoObj_OleObj_SetMoniker\r\n");
|
|
|
|
// OLE2NOTE: a pseudo object does NOT support SetMoniker
|
|
|
|
return ResultFromScode(E_FAIL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_GetMoniker(
|
|
LPOLEOBJECT lpThis,
|
|
DWORD dwAssign,
|
|
DWORD dwWhichMoniker,
|
|
LPMONIKER FAR* lplpmk
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpPseudoObj->m_lpDoc;
|
|
LPMONIKER lpmkDoc;
|
|
|
|
OLEDBG_BEGIN2("PseudoObj_OleObj_GetMoniker\r\n")
|
|
|
|
lpmkDoc = OleDoc_GetFullMoniker(lpOleDoc, GETMONIKER_ONLYIFTHERE);
|
|
*lplpmk = PseudoObj_GetFullMoniker(lpPseudoObj, lpmkDoc);
|
|
|
|
OLEDBG_END2
|
|
|
|
if (*lplpmk != NULL)
|
|
return NOERROR;
|
|
else
|
|
return ResultFromScode(E_FAIL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_InitFromData(
|
|
LPOLEOBJECT lpThis,
|
|
LPDATAOBJECT lpDataObject,
|
|
BOOL fCreation,
|
|
DWORD reserved
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
OleDbgOut2("PseudoObj_OleObj_InitFromData\r\n");
|
|
|
|
// REVIEW: NOT YET IMPLEMENTED
|
|
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_GetClipboardData(
|
|
LPOLEOBJECT lpThis,
|
|
DWORD reserved,
|
|
LPDATAOBJECT FAR* lplpDataObject
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
OleDbgOut2("PseudoObj_OleObj_GetClipboardData\r\n");
|
|
|
|
// REVIEW: NOT YET IMPLEMENTED
|
|
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_DoVerb(
|
|
LPOLEOBJECT lpThis,
|
|
LONG lVerb,
|
|
LPMSG lpmsg,
|
|
LPOLECLIENTSITE lpActiveSite,
|
|
LONG lindex,
|
|
HWND hwndParent,
|
|
LPCRECT lprcPosRect
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpPseudoObj->m_lpDoc;
|
|
LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc;
|
|
LINERANGE lrSel;
|
|
HRESULT hrErr;
|
|
|
|
OLEDBG_BEGIN2("PseudoObj_OleObj_DoVerb\r\n");
|
|
|
|
/* OLE2NOTE: we must first ask our Document to perform the same
|
|
** verb. then if the verb is NOT OLEIVERB_HIDE we should also
|
|
** select the range of our pseudo object.
|
|
** however, we must give our document its own embedding site as
|
|
** its active site.
|
|
*/
|
|
hrErr = SvrDoc_OleObj_DoVerb(
|
|
(LPOLEOBJECT)&lpServerDoc->m_OleObject,
|
|
lVerb,
|
|
lpmsg,
|
|
lpServerDoc->m_lpOleClientSite,
|
|
lindex,
|
|
NULL, /* we have no hwndParent to give */
|
|
NULL /* we have no lprcPosRect to give */
|
|
);
|
|
if (FAILED(hrErr)) {
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
}
|
|
|
|
if (lVerb != OLEIVERB_HIDE) {
|
|
PseudoObj_GetSel(lpPseudoObj, &lrSel);
|
|
OutlineDoc_SetSel(lpOutlineDoc, &lrSel);
|
|
}
|
|
|
|
OLEDBG_END2
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_EnumVerbs(
|
|
LPOLEOBJECT lpThis,
|
|
LPENUMOLEVERB FAR* lplpenumOleVerb
|
|
)
|
|
{
|
|
OleDbgOut2("PseudoObj_OleObj_EnumVerbs\r\n");
|
|
|
|
/* OLE2NOTE: we must make sure to set all out parameters to NULL. */
|
|
*lplpenumOleVerb = NULL;
|
|
|
|
/* A pseudo object may NOT return OLE_S_USEREG; they must call the
|
|
** OleReg* API or provide their own implementation. Because this
|
|
** pseudo object does NOT implement IPersist, simply a low-level
|
|
** remoting handler (ProxyManager) object as opposed to a
|
|
** DefHandler object is used as the handler for the pseudo
|
|
** object in a clients process space. The ProxyManager does NOT
|
|
** handle the OLE_S_USEREG return values.
|
|
*/
|
|
return OleRegEnumVerbs((REFCLSID)&CLSID_APP, lplpenumOleVerb);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_Update(LPOLEOBJECT lpThis)
|
|
{
|
|
OleDbgOut2("PseudoObj_OleObj_Update\r\n");
|
|
|
|
/* OLE2NOTE: a server-only app is always "up-to-date".
|
|
** a container-app which contains links where the link source
|
|
** has changed since the last update of the link would be
|
|
** considered "out-of-date". the "Update" method instructs the
|
|
** object to get an update from any out-of-date links.
|
|
*/
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_IsUpToDate(LPOLEOBJECT lpThis)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
OleDbgOut2("PseudoObj_OleObj_IsUpToDate\r\n");
|
|
|
|
/* OLE2NOTE: a server-only app is always "up-to-date".
|
|
** a container-app which contains links where the link source
|
|
** has changed since the last update of the link would be
|
|
** considered "out-of-date".
|
|
*/
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_GetUserClassID(
|
|
LPOLEOBJECT lpThis,
|
|
LPCLSID lpclsid
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpPseudoObj->m_lpDoc;
|
|
OleDbgOut2("PseudoObj_OleObj_GetUserClassID\r\n");
|
|
|
|
/* OLE2NOTE: we must be carefull to return the correct CLSID here.
|
|
** if we are currently preforming a "TreatAs (aka. ActivateAs)"
|
|
** operation then we need to return the class of the object
|
|
** written in the storage of the object. otherwise we would
|
|
** return our own class id.
|
|
*/
|
|
return ServerDoc_GetClassID(lpServerDoc, lpclsid);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_GetUserTypeA(
|
|
LPOLEOBJECT lpThis,
|
|
DWORD dwFormOfType,
|
|
LPSTR FAR* lpszUserType
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpPseudoObj->m_lpDoc;
|
|
OleDbgOut2("PseudoObj_OleObj_GetUserType\r\n");
|
|
|
|
/* OLE2NOTE: we must make sure to set all out parameters to NULL. */
|
|
*lpszUserType = NULL;
|
|
|
|
/* OLE2NOTE: we must be carefull to return the correct user type here.
|
|
** if we are currently preforming a "TreatAs (aka. ActivateAs)"
|
|
** operation then we need to return the user type name that
|
|
** corresponds to the class of the object we are currently
|
|
** emmulating. otherwise we should return our normal user type
|
|
** name corresponding to our own class. This routine determines
|
|
** the current clsid in effect.
|
|
**
|
|
** A pseudo object may NOT return OLE_S_USEREG; they must call the
|
|
** OleReg* API or provide their own implementation. Because this
|
|
** pseudo object does NOT implement IPersist, simply a low-level
|
|
** remoting handler (ProxyManager) object as opposed to a
|
|
** DefHandler object is used as the handler for the pseudo
|
|
** object in a clients process space. The ProxyManager does NOT
|
|
** handle the OLE_S_USEREG return values.
|
|
*/
|
|
#if defined( SVR_TREATAS )
|
|
if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL) )
|
|
return OleRegGetUserTypeA(
|
|
&lpServerDoc->m_clsidTreatAs,dwFormOfType,lpszUserType);
|
|
else
|
|
#endif // SVR_TREATAS
|
|
|
|
return OleRegGetUserTypeA(&CLSID_APP, dwFormOfType, lpszUserType);
|
|
}
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_GetUserType(
|
|
LPOLEOBJECT lpThis,
|
|
DWORD dwFormOfType,
|
|
LPOLESTR FAR* lpszUserType
|
|
)
|
|
{
|
|
LPSTR pstr;
|
|
|
|
HRESULT hr = PseudoObj_OleObj_GetUserTypeA(lpThis, dwFormOfType, &pstr);
|
|
|
|
CopyAndFreeSTR(pstr, lpszUserType);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_SetExtent(
|
|
LPOLEOBJECT lpThis,
|
|
DWORD dwDrawAspect,
|
|
LPSIZEL lplgrc
|
|
)
|
|
{
|
|
OleDbgOut2("PseudoObj_OleObj_SetExtent\r\n");
|
|
|
|
// OLE2NOTE: a pseudo object does NOT support SetExtent
|
|
|
|
return ResultFromScode(E_FAIL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_GetExtent(
|
|
LPOLEOBJECT lpThis,
|
|
DWORD dwDrawAspect,
|
|
LPSIZEL lpsizel
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
OleDbgOut2("PseudoObj_OleObj_GetExtent\r\n");
|
|
|
|
/* OLE2NOTE: it is VERY important to check which aspect the caller
|
|
** is asking about. an object implemented by a server EXE MAY
|
|
** fail to return extents when asked for DVASPECT_ICON.
|
|
*/
|
|
if (dwDrawAspect == DVASPECT_CONTENT) {
|
|
PseudoObj_GetExtent(lpPseudoObj, lpsizel);
|
|
return NOERROR;
|
|
}
|
|
else
|
|
{
|
|
return ResultFromScode(E_FAIL);
|
|
}
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_Advise(
|
|
LPOLEOBJECT lpThis,
|
|
LPADVISESINK lpAdvSink,
|
|
LPDWORD lpdwConnection
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
HRESULT hrErr;
|
|
SCODE sc;
|
|
OLEDBG_BEGIN2("PseudoObj_OleObj_Advise\r\n");
|
|
|
|
if (lpPseudoObj->m_lpOleAdviseHldr == NULL &&
|
|
CreateOleAdviseHolder(&lpPseudoObj->m_lpOleAdviseHldr) != NOERROR) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
OLEDBG_BEGIN2("IOleAdviseHolder::Advise called\r\n")
|
|
hrErr = lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->Advise(
|
|
lpPseudoObj->m_lpOleAdviseHldr,
|
|
lpAdvSink,
|
|
lpdwConnection
|
|
);
|
|
OLEDBG_END2
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
|
|
error:
|
|
OLEDBG_END2
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_Unadvise(LPOLEOBJECT lpThis, DWORD dwConnection)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
HRESULT hrErr;
|
|
SCODE sc;
|
|
|
|
OLEDBG_BEGIN2("PseudoObj_OleObj_Unadvise\r\n");
|
|
|
|
if (lpPseudoObj->m_lpOleAdviseHldr == NULL) {
|
|
sc = E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
OLEDBG_BEGIN2("IOleAdviseHolder::Unadvise called\r\n")
|
|
hrErr = lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->Unadvise(
|
|
lpPseudoObj->m_lpOleAdviseHldr,
|
|
dwConnection
|
|
);
|
|
OLEDBG_END2
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
|
|
error:
|
|
OLEDBG_END2
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_EnumAdvise(
|
|
LPOLEOBJECT lpThis,
|
|
LPENUMSTATDATA FAR* lplpenumAdvise
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
HRESULT hrErr;
|
|
SCODE sc;
|
|
|
|
OLEDBG_BEGIN2("PseudoObj_OleObj_EnumAdvise\r\n");
|
|
|
|
/* OLE2NOTE: we must make sure to set all out parameters to NULL. */
|
|
*lplpenumAdvise = NULL;
|
|
|
|
if (lpPseudoObj->m_lpOleAdviseHldr == NULL) {
|
|
sc = E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise called\r\n")
|
|
hrErr = lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->EnumAdvise(
|
|
lpPseudoObj->m_lpOleAdviseHldr,
|
|
lplpenumAdvise
|
|
);
|
|
OLEDBG_END2
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
|
|
error:
|
|
OLEDBG_END2
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_GetMiscStatus(
|
|
LPOLEOBJECT lpThis,
|
|
DWORD dwAspect,
|
|
DWORD FAR* lpdwStatus
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpPseudoObj->m_lpDoc;
|
|
OleDbgOut2("PseudoObj_OleObj_GetMiscStatus\r\n");
|
|
|
|
/* Get our default MiscStatus for the given Aspect. this
|
|
** information is registered in the RegDB. We query the RegDB
|
|
** here to guarantee that the value returned from this method
|
|
** agrees with the values in RegDB. in this way we only have to
|
|
** maintain the info in one place (in the RegDB). Alternatively
|
|
** we could have the values hard coded here.
|
|
**
|
|
** OLE2NOTE: A pseudo object may NOT return OLE_S_USEREG; they must
|
|
** call the
|
|
** OleReg* API or provide their own implementation. Because this
|
|
** pseudo object does NOT implement IPersist, simply a low-level
|
|
** remoting handler (ProxyManager) object as opposed to a
|
|
** DefHandler object is used as the handler for the pseudo
|
|
** object in a clients process space. The ProxyManager does NOT
|
|
** handle the OLE_S_USEREG return values.
|
|
*/
|
|
OleRegGetMiscStatus((REFCLSID)&CLSID_APP, dwAspect, lpdwStatus);
|
|
|
|
/* OLE2NOTE: check if the pseudo object is compatible to be
|
|
** linked by an OLE 1.0 container. it is compatible if
|
|
** either the pseudo object is an untitled document or a
|
|
** file-based document. if the pseudo object is part of
|
|
** an embedded object, then it is NOT compatible to be
|
|
** linked by an OLE 1.0 container. if it is compatible then
|
|
** we should include OLEMISC_CANLINKBYOLE1 as part of the
|
|
** dwStatus flags.
|
|
*/
|
|
if (lpOutlineDoc->m_docInitType == DOCTYPE_NEW ||
|
|
lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE)
|
|
*lpdwStatus |= OLEMISC_CANLINKBYOLE1;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_OleObj_SetColorScheme(
|
|
LPOLEOBJECT lpThis,
|
|
LPLOGPALETTE lpLogpal
|
|
)
|
|
{
|
|
OleDbgOut2("PseudoObj_OleObj_SetColorScheme\r\n");
|
|
|
|
// REVIEW: NOT YET IMPLEMENTED
|
|
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
** PseudoObj::IDataObject interface implementation
|
|
*************************************************************************/
|
|
|
|
STDMETHODIMP PseudoObj_DataObj_QueryInterface (
|
|
LPDATAOBJECT lpThis,
|
|
REFIID riid,
|
|
LPVOID FAR* lplpvObj
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
|
|
return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObj);
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) PseudoObj_DataObj_AddRef(LPDATAOBJECT lpThis)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
|
|
OleDbgAddRefMethod(lpThis, "IDataObject");
|
|
|
|
return PseudoObj_AddRef((LPPSEUDOOBJ)lpPseudoObj);
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) PseudoObj_DataObj_Release (LPDATAOBJECT lpThis)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
|
|
OleDbgReleaseMethod(lpThis, "IDataObject");
|
|
|
|
return PseudoObj_Release((LPPSEUDOOBJ)lpPseudoObj);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_DataObj_GetData (
|
|
LPDATAOBJECT lpThis,
|
|
LPFORMATETC lpformatetc,
|
|
LPSTGMEDIUM lpMedium
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
|
|
LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp;
|
|
LINERANGE lrSel;
|
|
SCODE sc = S_OK;
|
|
OLEDBG_BEGIN2("PseudoObj_DataObj_GetData\r\n")
|
|
|
|
PseudoObj_GetSel(lpPseudoObj, &lrSel);
|
|
|
|
/* OLE2NOTE: we must make sure to set all out parameters to NULL. */
|
|
lpMedium->tymed = TYMED_NULL;
|
|
lpMedium->pUnkForRelease = NULL; // we transfer ownership to caller
|
|
lpMedium->hGlobal = NULL;
|
|
|
|
if (lpformatetc->cfFormat == lpOutlineApp->m_cfOutline) {
|
|
// Verify caller asked for correct medium
|
|
if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {
|
|
sc = DATA_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->hGlobal = OutlineDoc_GetOutlineData (lpOutlineDoc,&lrSel);
|
|
if (! lpMedium->hGlobal) return ResultFromScode(E_OUTOFMEMORY);
|
|
lpMedium->tymed = TYMED_HGLOBAL;
|
|
OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_OUTLINE\r\n");
|
|
|
|
} else if(lpformatetc->cfFormat == CF_METAFILEPICT &&
|
|
(lpformatetc->dwAspect & DVASPECT_CONTENT) ) {
|
|
// Verify caller asked for correct medium
|
|
if (!(lpformatetc->tymed & TYMED_MFPICT)) {
|
|
sc = DATA_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->hGlobal=ServerDoc_GetMetafilePictData(lpServerDoc,&lrSel);
|
|
if (! lpMedium->hGlobal) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
lpMedium->tymed = TYMED_MFPICT;
|
|
OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_METAFILEPICT\r\n");
|
|
|
|
} else if (lpformatetc->cfFormat == CF_METAFILEPICT &&
|
|
(lpformatetc->dwAspect & DVASPECT_ICON) ) {
|
|
CLSID clsid;
|
|
// Verify caller asked for correct medium
|
|
if (!(lpformatetc->tymed & TYMED_MFPICT)) {
|
|
sc = DATA_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
/* OLE2NOTE: we should return the default icon for our class.
|
|
** we must be carefull to use the correct CLSID here.
|
|
** if we are currently preforming a "TreatAs (aka. ActivateAs)"
|
|
** operation then we need to use the class of the object
|
|
** written in the storage of the object. otherwise we would
|
|
** use our own class id.
|
|
*/
|
|
if (ServerDoc_GetClassID(lpServerDoc, (LPCLSID)&clsid) != NOERROR) {
|
|
sc = DATA_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->hGlobal=GetIconOfClass(
|
|
g_lpApp->m_hInst,(REFCLSID)&clsid, NULL, FALSE);
|
|
if (! lpMedium->hGlobal) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->tymed = TYMED_MFPICT;
|
|
OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_METAFILEPICT (icon)\r\n");
|
|
return NOERROR;
|
|
|
|
} else if (lpformatetc->cfFormat == CF_TEXT) {
|
|
// Verify caller asked for correct medium
|
|
if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {
|
|
sc = DATA_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->hGlobal = OutlineDoc_GetTextData (lpOutlineDoc, &lrSel);
|
|
if (! lpMedium->hGlobal) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
lpMedium->tymed = TYMED_HGLOBAL;
|
|
OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_TEXT\r\n");
|
|
|
|
} else {
|
|
sc = DATA_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
OLEDBG_END2
|
|
return NOERROR;
|
|
|
|
error:
|
|
OLEDBG_END2
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_DataObj_GetDataHere (
|
|
LPDATAOBJECT lpThis,
|
|
LPFORMATETC lpformatetc,
|
|
LPSTGMEDIUM lpMedium
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
|
|
LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp;
|
|
OleDbgOut("PseudoObj_DataObj_GetDataHere\r\n");
|
|
|
|
/* Caller is requesting data to be returned in Caller allocated
|
|
** medium, but we do NOT support this. we only support
|
|
** global memory blocks that WE allocate for the caller.
|
|
*/
|
|
return ResultFromScode(DATA_E_FORMATETC);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_DataObj_QueryGetData (
|
|
LPDATAOBJECT lpThis,
|
|
LPFORMATETC lpformatetc
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
|
|
LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp;
|
|
OleDbgOut2("PseudoObj_DataObj_QueryGetData\r\n");
|
|
|
|
/* Caller is querying if we support certain format but does not
|
|
** want any data actually returned.
|
|
*/
|
|
if (lpformatetc->cfFormat == CF_METAFILEPICT &&
|
|
(lpformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON)) ) {
|
|
return OleStdQueryFormatMedium(lpformatetc, TYMED_MFPICT);
|
|
|
|
} else if (lpformatetc->cfFormat == (lpOutlineApp)->m_cfOutline ||
|
|
lpformatetc->cfFormat == CF_TEXT) {
|
|
return OleStdQueryFormatMedium(lpformatetc, TYMED_HGLOBAL);
|
|
}
|
|
|
|
return ResultFromScode(DATA_E_FORMATETC);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_DataObj_GetCanonicalFormatEtc(
|
|
LPDATAOBJECT lpThis,
|
|
LPFORMATETC lpformatetc,
|
|
LPFORMATETC lpformatetcOut
|
|
)
|
|
{
|
|
HRESULT hrErr;
|
|
OleDbgOut2("PseudoObj_DataObj_GetCanonicalFormatEtc\r\n");
|
|
|
|
if (!lpformatetcOut)
|
|
return ResultFromScode(E_INVALIDARG);
|
|
|
|
/* OLE2NOTE: we must make sure to set all out parameters to NULL. */
|
|
lpformatetcOut->ptd = NULL;
|
|
|
|
if (!lpformatetc)
|
|
return ResultFromScode(E_INVALIDARG);
|
|
|
|
// OLE2NOTE: we must validate that the format requested is supported
|
|
if ((hrErr=lpThis->lpVtbl->QueryGetData(lpThis,lpformatetc)) != NOERROR)
|
|
return hrErr;
|
|
|
|
/* OLE2NOTE: an app that is insensitive to target device (as the
|
|
** Outline Sample is) should fill in the lpformatOut parameter
|
|
** but NULL out the "ptd" field; it should return NOERROR if the
|
|
** input formatetc->ptd what non-NULL. this tells the caller
|
|
** that it is NOT necessary to maintain a separate screen
|
|
** rendering and printer rendering. if should return
|
|
** DATA_S_SAMEFORMATETC if the input and output formatetc's are
|
|
** identical.
|
|
*/
|
|
|
|
*lpformatetcOut = *lpformatetc;
|
|
if (lpformatetc->ptd == NULL)
|
|
return ResultFromScode(DATA_S_SAMEFORMATETC);
|
|
else {
|
|
lpformatetcOut->ptd = NULL;
|
|
return NOERROR;
|
|
}
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_DataObj_SetData (
|
|
LPDATAOBJECT lpThis,
|
|
LPFORMATETC lpformatetc,
|
|
LPSTGMEDIUM lpmedium,
|
|
BOOL fRelease
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
|
|
LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;
|
|
|
|
OleDbgOut2("PseudoObj_DataObj_SetData\r\n");
|
|
|
|
// REVIEW: NOT-YET-IMPLEMENTED
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_DataObj_EnumFormatEtc(
|
|
LPDATAOBJECT lpThis,
|
|
DWORD dwDirection,
|
|
LPENUMFORMATETC FAR* lplpenumFormatEtc
|
|
)
|
|
{
|
|
SCODE sc;
|
|
OleDbgOut2("PseudoObj_DataObj_EnumFormatEtc\r\n");
|
|
|
|
/* OLE2NOTE: a pseudo object only needs to enumerate the static list
|
|
** of formats that are registered for our app in the
|
|
** registration database. it is NOT
|
|
** required that a pseudo object (ie. non-DataTransferDoc)
|
|
** enumerate the OLE formats: CF_LINKSOURCE, CF_EMBEDSOURCE, or
|
|
** CF_EMBEDDEDOBJECT. we do NOT use pseudo objects for data
|
|
** transfers.
|
|
**
|
|
** A pseudo object may NOT return OLE_S_USEREG; they must call the
|
|
** OleReg* API or provide their own implementation. Because this
|
|
** pseudo object does NOT implement IPersist, simply a low-level
|
|
** remoting handler (ProxyManager) object as opposed to a
|
|
** DefHandler object is used as the handler for the pseudo
|
|
** object in a clients process space. The ProxyManager does NOT
|
|
** handle the OLE_S_USEREG return values.
|
|
*/
|
|
if (dwDirection == DATADIR_GET)
|
|
return OleRegEnumFormatEtc(
|
|
(REFCLSID)&CLSID_APP, dwDirection, lplpenumFormatEtc);
|
|
else if (dwDirection == DATADIR_SET)
|
|
sc = E_NOTIMPL;
|
|
else
|
|
sc = E_INVALIDARG;
|
|
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_DataObj_DAdvise(
|
|
LPDATAOBJECT lpThis,
|
|
FORMATETC FAR* lpFormatetc,
|
|
DWORD advf,
|
|
LPADVISESINK lpAdvSink,
|
|
DWORD FAR* lpdwConnection
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
HRESULT hrErr;
|
|
SCODE sc;
|
|
|
|
OLEDBG_BEGIN2("PseudoObj_DataObj_DAdvise\r\n")
|
|
|
|
/* OLE2NOTE: we must make sure to set all out parameters to NULL. */
|
|
*lpdwConnection = 0;
|
|
|
|
/* OLE2NOTE: we should validate if the caller is setting up an
|
|
** Advise for a data type that we support. we must
|
|
** explicitly allow an advise for the "wildcard" advise.
|
|
*/
|
|
if ( !( lpFormatetc->cfFormat == 0 &&
|
|
lpFormatetc->ptd == NULL &&
|
|
lpFormatetc->dwAspect == -1L &&
|
|
lpFormatetc->lindex == -1L &&
|
|
lpFormatetc->tymed == -1L) &&
|
|
(hrErr = PseudoObj_DataObj_QueryGetData(lpThis, lpFormatetc))
|
|
!= NOERROR) {
|
|
sc = GetScode(hrErr);
|
|
goto error;
|
|
}
|
|
|
|
if (lpPseudoObj->m_lpDataAdviseHldr == NULL &&
|
|
CreateDataAdviseHolder(&lpPseudoObj->m_lpDataAdviseHldr) != NOERROR) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
OLEDBG_BEGIN2("IOleAdviseHolder::Advise called\r\n")
|
|
hrErr = lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->Advise(
|
|
lpPseudoObj->m_lpDataAdviseHldr,
|
|
(LPDATAOBJECT)&lpPseudoObj->m_DataObject,
|
|
lpFormatetc,
|
|
advf,
|
|
lpAdvSink,
|
|
lpdwConnection
|
|
);
|
|
OLEDBG_END2
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
|
|
error:
|
|
OLEDBG_END2
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_DataObj_DUnadvise(LPDATAOBJECT lpThis, DWORD dwConnection)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
HRESULT hrErr;
|
|
SCODE sc;
|
|
|
|
OLEDBG_BEGIN2("PseudoObj_DataObj_Unadvise\r\n");
|
|
|
|
// no one registered
|
|
if (lpPseudoObj->m_lpDataAdviseHldr == NULL) {
|
|
sc = E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
OLEDBG_BEGIN2("IOleAdviseHolder::DUnadvise called\r\n")
|
|
hrErr = lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->Unadvise(
|
|
lpPseudoObj->m_lpDataAdviseHldr,
|
|
dwConnection
|
|
);
|
|
OLEDBG_END2
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
|
|
error:
|
|
OLEDBG_END2
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
STDMETHODIMP PseudoObj_DataObj_EnumAdvise(
|
|
LPDATAOBJECT lpThis,
|
|
LPENUMSTATDATA FAR* lplpenumAdvise
|
|
)
|
|
{
|
|
LPPSEUDOOBJ lpPseudoObj =
|
|
((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;
|
|
HRESULT hrErr;
|
|
SCODE sc;
|
|
|
|
OLEDBG_BEGIN2("PseudoObj_DataObj_EnumAdvise\r\n");
|
|
|
|
/* OLE2NOTE: we must make sure to set all out parameters to NULL. */
|
|
*lplpenumAdvise = NULL;
|
|
|
|
if (lpPseudoObj->m_lpDataAdviseHldr == NULL) {
|
|
sc = E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise called\r\n")
|
|
hrErr = lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->EnumAdvise(
|
|
lpPseudoObj->m_lpDataAdviseHldr,
|
|
lplpenumAdvise
|
|
);
|
|
OLEDBG_END2
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
|
|
error:
|
|
OLEDBG_END2
|
|
return ResultFromScode(sc);
|
|
}
|