3402 lines
99 KiB
C
3402 lines
99 KiB
C
/*************************************************************************
|
|
**
|
|
** OLE 2 Sample Code
|
|
**
|
|
** clipbrd.c
|
|
**
|
|
** This file contains the major interfaces, methods and related support
|
|
** functions for implementing clipboard data transfer. The code
|
|
** contained in this file is used by BOTH the Container and Server
|
|
** (Object) versions of the Outline sample code.
|
|
** (see file dragdrop.c for Drag/Drop support implementation)
|
|
**
|
|
** OleDoc Object
|
|
** exposed interfaces:
|
|
** IDataObject
|
|
**
|
|
** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
|
|
**
|
|
*************************************************************************/
|
|
|
|
#include "outline.h"
|
|
|
|
OLEDBGDATA
|
|
|
|
extern LPOUTLINEAPP g_lpApp;
|
|
|
|
// REVIEW: should use string resource for messages
|
|
char ErrMsgPasting[] = "Could not paste data from clipboard!";
|
|
char ErrMsgBadFmt[] = "Invalid format selected!";
|
|
char ErrMsgPasteFailed[] = "Could not paste data from clipboard!";
|
|
char ErrMsgClipboardChanged[] = "Contents of clipboard have changed!\r\nNo paste performed.";
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
** OleDoc::IDataObject interface implementation
|
|
*************************************************************************/
|
|
|
|
// IDataObject::QueryInterface
|
|
STDMETHODIMP OleDoc_DataObj_QueryInterface (
|
|
LPDATAOBJECT lpThis,
|
|
REFIID riid,
|
|
LPVOID FAR* lplpvObj
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
|
|
|
|
return OleDoc_QueryInterface((LPOLEDOC)lpOleDoc, riid, lplpvObj);
|
|
}
|
|
|
|
|
|
// IDataObject::AddRef
|
|
STDMETHODIMP_(ULONG) OleDoc_DataObj_AddRef(LPDATAOBJECT lpThis)
|
|
{
|
|
LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
|
|
|
|
OleDbgAddRefMethod(lpThis, "IDataObject");
|
|
|
|
return OleDoc_AddRef((LPOLEDOC)lpOleDoc);
|
|
}
|
|
|
|
|
|
// IDataObject::Release
|
|
STDMETHODIMP_(ULONG) OleDoc_DataObj_Release (LPDATAOBJECT lpThis)
|
|
{
|
|
LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
|
|
|
|
OleDbgReleaseMethod(lpThis, "IDataObject");
|
|
|
|
return OleDoc_Release((LPOLEDOC)lpOleDoc);
|
|
}
|
|
|
|
|
|
// IDataObject::GetData
|
|
STDMETHODIMP OleDoc_DataObj_GetData (
|
|
LPDATAOBJECT lpThis,
|
|
LPFORMATETC lpFormatetc,
|
|
LPSTGMEDIUM lpMedium
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
|
|
HRESULT hrErr;
|
|
|
|
OLEDBG_BEGIN2("OleDoc_DataObj_GetData\r\n")
|
|
|
|
#if defined( OLE_SERVER )
|
|
// Call OLE Server specific version of this function
|
|
hrErr = ServerDoc_GetData((LPSERVERDOC)lpOleDoc, lpFormatetc, lpMedium);
|
|
#endif
|
|
#if defined( OLE_CNTR )
|
|
// Call OLE Container specific version of this function
|
|
hrErr = ContainerDoc_GetData(
|
|
(LPCONTAINERDOC)lpOleDoc,
|
|
lpFormatetc,
|
|
lpMedium
|
|
);
|
|
#endif
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
}
|
|
|
|
|
|
// IDataObject::GetDataHere
|
|
STDMETHODIMP OleDoc_DataObj_GetDataHere (
|
|
LPDATAOBJECT lpThis,
|
|
LPFORMATETC lpFormatetc,
|
|
LPSTGMEDIUM lpMedium
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
|
|
HRESULT hrErr;
|
|
|
|
OLEDBG_BEGIN2("OleDoc_DataObj_GetDataHere\r\n")
|
|
|
|
#if defined( OLE_SERVER )
|
|
// Call OLE Server specific version of this function
|
|
hrErr = ServerDoc_GetDataHere(
|
|
(LPSERVERDOC)lpOleDoc,
|
|
lpFormatetc,
|
|
lpMedium
|
|
);
|
|
#endif
|
|
#if defined( OLE_CNTR )
|
|
// Call OLE Container specific version of this function
|
|
hrErr = ContainerDoc_GetDataHere(
|
|
(LPCONTAINERDOC)lpOleDoc,
|
|
lpFormatetc,
|
|
lpMedium
|
|
);
|
|
#endif
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
}
|
|
|
|
|
|
// IDataObject::QueryGetData
|
|
STDMETHODIMP OleDoc_DataObj_QueryGetData (
|
|
LPDATAOBJECT lpThis,
|
|
LPFORMATETC lpFormatetc
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
|
|
HRESULT hrErr;
|
|
OLEDBG_BEGIN2("OleDoc_DataObj_QueryGetData\r\n");
|
|
|
|
#if defined( OLE_SERVER )
|
|
// Call OLE Server specific version of this function
|
|
hrErr = ServerDoc_QueryGetData((LPSERVERDOC)lpOleDoc, lpFormatetc);
|
|
#endif
|
|
#if defined( OLE_CNTR )
|
|
// Call OLE Container specific version of this function
|
|
hrErr = ContainerDoc_QueryGetData((LPCONTAINERDOC)lpOleDoc, lpFormatetc);
|
|
#endif
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
}
|
|
|
|
|
|
// IDataObject::GetCanonicalFormatEtc
|
|
STDMETHODIMP OleDoc_DataObj_GetCanonicalFormatEtc(
|
|
LPDATAOBJECT lpThis,
|
|
LPFORMATETC lpformatetc,
|
|
LPFORMATETC lpformatetcOut
|
|
)
|
|
{
|
|
HRESULT hrErr;
|
|
OleDbgOut2("OleDoc_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;
|
|
}
|
|
}
|
|
|
|
|
|
// IDataObject::SetData
|
|
STDMETHODIMP OleDoc_DataObj_SetData (
|
|
LPDATAOBJECT lpThis,
|
|
LPFORMATETC lpFormatetc,
|
|
LPSTGMEDIUM lpMedium,
|
|
BOOL fRelease
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
|
SCODE sc = S_OK;
|
|
OLEDBG_BEGIN2("OleDoc_DataObj_SetData\r\n")
|
|
|
|
/* OLE2NOTE: a document that is used to transfer data (either via
|
|
** the clipboard or drag/drop) does NOT accept SetData on ANY
|
|
** format!
|
|
*/
|
|
if (lpOutlineDoc->m_fDataTransferDoc) {
|
|
sc = E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
#if defined( OLE_SERVER )
|
|
if (lpFormatetc->cfFormat == lpOutlineApp->m_cfOutline) {
|
|
OLEDBG_BEGIN2("ServerDoc_SetData: CF_OUTLINE\r\n")
|
|
OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );
|
|
OutlineDoc_ClearAllLines(lpOutlineDoc);
|
|
OutlineDoc_PasteOutlineData(lpOutlineDoc,lpMedium->hGlobal,-1);
|
|
OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );
|
|
OLEDBG_END3
|
|
} else if (lpFormatetc->cfFormat == CF_TEXT) {
|
|
OLEDBG_BEGIN2("ServerDoc_SetData: CF_TEXT\r\n")
|
|
OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );
|
|
OutlineDoc_ClearAllLines(lpOutlineDoc);
|
|
OutlineDoc_PasteTextData(lpOutlineDoc,lpMedium->hGlobal,-1);
|
|
OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );
|
|
OLEDBG_END3
|
|
} else {
|
|
sc = DV_E_FORMATETC;
|
|
}
|
|
#endif // OLE_SERVER
|
|
#if defined( OLE_CNTR )
|
|
/* the Container-Only version of Outline does NOT offer
|
|
** IDataObject interface from its User documents. this is
|
|
** required by objects which can be embedded or linked. the
|
|
** Container-only app only allows linking to its contained
|
|
** objects, NOT the data of the container itself.
|
|
*/
|
|
OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n");
|
|
sc = E_NOTIMPL;
|
|
#endif // OLE_CNTR
|
|
|
|
error:
|
|
|
|
/* OLE2NOTE: if fRelease==TRUE, then we must take
|
|
** responsibility to release the lpMedium. we should only do
|
|
** this if we are going to return NOERROR. if we do NOT
|
|
** accept the data, then we should NOT release the lpMedium.
|
|
** if fRelease==FALSE, then the caller retains ownership of
|
|
** the data.
|
|
*/
|
|
if (sc == S_OK && fRelease)
|
|
ReleaseStgMedium(lpMedium);
|
|
|
|
OLEDBG_END2
|
|
return ResultFromScode(sc);
|
|
|
|
}
|
|
|
|
|
|
// IDataObject::EnumFormatEtc
|
|
STDMETHODIMP OleDoc_DataObj_EnumFormatEtc(
|
|
LPDATAOBJECT lpThis,
|
|
DWORD dwDirection,
|
|
LPENUMFORMATETC FAR* lplpenumFormatEtc
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
|
|
HRESULT hrErr;
|
|
|
|
OLEDBG_BEGIN2("OleDoc_DataObj_EnumFormatEtc\r\n")
|
|
|
|
/* OLE2NOTE: we must make sure to set all out parameters to NULL. */
|
|
*lplpenumFormatEtc = NULL;
|
|
|
|
#if defined( OLE_SERVER )
|
|
/* OLE2NOTE: a user document only needs to enumerate the static list
|
|
** of formats that are registered for our app in the
|
|
** registration database. OLE provides a default enumerator
|
|
** which enumerates from the registration database. this default
|
|
** enumerator is requested by returning OLE_S_USEREG. it is NOT
|
|
** required that a user document (ie. non-DataTransferDoc)
|
|
** enumerate the OLE formats: CF_LINKSOURCE, CF_EMBEDSOURCE, or
|
|
** CF_EMBEDDEDOBJECT.
|
|
**
|
|
** An object implemented as a server EXE (as this sample
|
|
** is) may simply return OLE_S_USEREG to instruct the OLE
|
|
** DefHandler to call the OleReg* helper API which uses info in
|
|
** the registration database. Alternatively, the OleRegEnumFormatEtc
|
|
** API may be called directly. Objects implemented as a server
|
|
** DLL may NOT return OLE_S_USEREG; they must call the OleReg*
|
|
** API or provide their own implementation. For EXE based
|
|
** objects it is more efficient to return OLE_S_USEREG, because
|
|
** in then the enumerator is instantiated in the callers
|
|
** process space and no LRPC remoting is required.
|
|
*/
|
|
if (! ((LPOUTLINEDOC)lpOleDoc)->m_fDataTransferDoc)
|
|
return ResultFromScode(OLE_S_USEREG);
|
|
|
|
// Call OLE Server specific version of this function
|
|
hrErr = ServerDoc_EnumFormatEtc(
|
|
(LPSERVERDOC)lpOleDoc,
|
|
dwDirection,
|
|
lplpenumFormatEtc
|
|
);
|
|
#endif
|
|
#if defined( OLE_CNTR )
|
|
// Call OLE Container specific version of this function
|
|
hrErr = ContainerDoc_EnumFormatEtc(
|
|
(LPCONTAINERDOC)lpOleDoc,
|
|
dwDirection,
|
|
lplpenumFormatEtc
|
|
);
|
|
#endif
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
}
|
|
|
|
|
|
// IDataObject::DAdvise
|
|
STDMETHODIMP OleDoc_DataObj_DAdvise(
|
|
LPDATAOBJECT lpThis,
|
|
FORMATETC FAR* lpFormatetc,
|
|
DWORD advf,
|
|
LPADVISESINK lpAdvSink,
|
|
DWORD FAR* lpdwConnection
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
|
|
SCODE sc;
|
|
|
|
OLEDBG_BEGIN2("OleDoc_DataObj_DAdvise\r\n")
|
|
|
|
/* OLE2NOTE: we must make sure to set all out parameters to NULL. */
|
|
*lpdwConnection = 0;
|
|
|
|
/* OLE2NOTE: a document that is used to transfer data (either via
|
|
** the clipboard or drag/drop) does NOT support Advise notifications.
|
|
*/
|
|
if (lpOutlineDoc->m_fDataTransferDoc) {
|
|
sc = OLE_E_ADVISENOTSUPPORTED;
|
|
goto error;
|
|
}
|
|
|
|
#if defined( OLE_SERVER )
|
|
{
|
|
HRESULT hrErr;
|
|
LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
|
|
|
|
/* 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 = OleDoc_DataObj_QueryGetData(lpThis, lpFormatetc))
|
|
!= NOERROR) {
|
|
sc = GetScode(hrErr);
|
|
goto error;
|
|
}
|
|
|
|
if (lpServerDoc->m_OleDoc.m_fObjIsClosing)
|
|
{
|
|
// We don't accept any more Advise's once we're closing
|
|
sc = OLE_E_ADVISENOTSUPPORTED;
|
|
goto error;
|
|
}
|
|
|
|
if (lpServerDoc->m_lpDataAdviseHldr == NULL &&
|
|
CreateDataAdviseHolder(&lpServerDoc->m_lpDataAdviseHldr)
|
|
!= NOERROR) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
OLEDBG_BEGIN2("IDataAdviseHolder::Advise called\r\n");
|
|
hrErr = lpServerDoc->m_lpDataAdviseHldr->lpVtbl->Advise(
|
|
lpServerDoc->m_lpDataAdviseHldr,
|
|
(LPDATAOBJECT)&lpOleDoc->m_DataObject,
|
|
lpFormatetc,
|
|
advf,
|
|
lpAdvSink,
|
|
lpdwConnection
|
|
);
|
|
OLEDBG_END2
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
}
|
|
#endif // OLE_SVR
|
|
#if defined( OLE_CNTR )
|
|
{
|
|
/* the Container-Only version of Outline does NOT offer
|
|
** IDataObject interface from its User documents. this is
|
|
** required by objects which can be embedded or linked. the
|
|
** Container-only app only allows linking to its contained
|
|
** objects, NOT the data of the container itself.
|
|
*/
|
|
OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n");
|
|
sc = E_NOTIMPL;
|
|
goto error;
|
|
}
|
|
#endif // OLE_CNTR
|
|
|
|
error:
|
|
OLEDBG_END2
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
|
|
// IDataObject::DUnadvise
|
|
STDMETHODIMP OleDoc_DataObj_DUnadvise(LPDATAOBJECT lpThis, DWORD dwConnection)
|
|
{
|
|
LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
|
|
SCODE sc;
|
|
|
|
OLEDBG_BEGIN2("OleDoc_DataObj_DUnadvise\r\n")
|
|
|
|
/* OLE2NOTE: a document that is used to transfer data (either via
|
|
** the clipboard or drag/drop) does NOT support Advise notifications.
|
|
*/
|
|
if (lpOutlineDoc->m_fDataTransferDoc) {
|
|
sc = OLE_E_ADVISENOTSUPPORTED;
|
|
goto error;
|
|
}
|
|
|
|
#if defined( OLE_SERVER )
|
|
{
|
|
LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
|
|
HRESULT hrErr;
|
|
|
|
if (lpServerDoc->m_lpDataAdviseHldr == NULL) {
|
|
sc = E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
OLEDBG_BEGIN2("IDataAdviseHolder::Unadvise called\r\n");
|
|
hrErr = lpServerDoc->m_lpDataAdviseHldr->lpVtbl->Unadvise(
|
|
lpServerDoc->m_lpDataAdviseHldr,
|
|
dwConnection
|
|
);
|
|
OLEDBG_END2
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
}
|
|
#endif
|
|
#if defined( OLE_CNTR )
|
|
{
|
|
/* the Container-Only version of Outline does NOT offer
|
|
** IDataObject interface from its User documents. this is
|
|
** required by objects which can be embedded or linked. the
|
|
** Container-only app only allows linking to its contained
|
|
** objects, NOT the data of the container itself.
|
|
*/
|
|
OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n");
|
|
sc = E_NOTIMPL;
|
|
goto error;
|
|
}
|
|
#endif
|
|
|
|
error:
|
|
OLEDBG_END2
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
// IDataObject::EnumDAdvise
|
|
STDMETHODIMP OleDoc_DataObj_EnumDAdvise(
|
|
LPDATAOBJECT lpThis,
|
|
LPENUMSTATDATA FAR* lplpenumAdvise
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
|
|
SCODE sc;
|
|
|
|
OLEDBG_BEGIN2("OleDoc_DataObj_EnumDAdvise\r\n")
|
|
|
|
/* OLE2NOTE: we must make sure to set all out parameters to NULL. */
|
|
*lplpenumAdvise = NULL;
|
|
|
|
/* OLE2NOTE: a document that is used to transfer data (either via
|
|
** the clipboard or drag/drop) does NOT support Advise notifications.
|
|
*/
|
|
if (lpOutlineDoc->m_fDataTransferDoc) {
|
|
sc = OLE_E_ADVISENOTSUPPORTED;
|
|
goto error;
|
|
}
|
|
|
|
#if defined( OLE_SERVER )
|
|
{
|
|
LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
|
|
HRESULT hrErr;
|
|
|
|
if (lpServerDoc->m_lpDataAdviseHldr == NULL) {
|
|
sc = E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
OLEDBG_BEGIN2("IDataAdviseHolder::EnumAdvise called\r\n");
|
|
hrErr = lpServerDoc->m_lpDataAdviseHldr->lpVtbl->EnumAdvise(
|
|
lpServerDoc->m_lpDataAdviseHldr,
|
|
lplpenumAdvise
|
|
);
|
|
OLEDBG_END2
|
|
|
|
OLEDBG_END2
|
|
return hrErr;
|
|
}
|
|
#endif
|
|
#if defined( OLE_CNTR )
|
|
{
|
|
/* the Container-Only version of Outline does NOT offer
|
|
** IDataObject interface from its User documents. this is
|
|
** required by objects which can be embedded or linked. the
|
|
** Container-only app only allows linking to its contained
|
|
** objects, NOT the data of the container itself.
|
|
*/
|
|
OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n");
|
|
sc = E_NOTIMPL;
|
|
goto error;
|
|
}
|
|
#endif
|
|
|
|
error:
|
|
OLEDBG_END2
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
** OleDoc Supprt Functions common to both Container and Server versions
|
|
*************************************************************************/
|
|
|
|
|
|
/* OleDoc_CopyCommand
|
|
* ------------------
|
|
* Copy selection to clipboard.
|
|
* Post to the clipboard the formats that the app can render.
|
|
* the actual data is not rendered at this time. using the
|
|
* delayed rendering technique, Windows will send the clipboard
|
|
* owner window either a WM_RENDERALLFORMATS or a WM_RENDERFORMAT
|
|
* message when the actual data is requested.
|
|
*
|
|
* OLE2NOTE: the normal delayed rendering technique where Windows
|
|
* sends the clipboard owner window either a WM_RENDERALLFORMATS or
|
|
* a WM_RENDERFORMAT message when the actual data is requested is
|
|
* NOT exposed to the app calling OleSetClipboard. OLE internally
|
|
* creates its own window as the clipboard owner and thus our app
|
|
* will NOT get these WM_RENDER messages.
|
|
*/
|
|
void OleDoc_CopyCommand(LPOLEDOC lpSrcOleDoc)
|
|
{
|
|
LPOUTLINEDOC lpSrcOutlineDoc = (LPOUTLINEDOC)lpSrcOleDoc;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
|
LPOUTLINEDOC lpClipboardDoc;
|
|
|
|
/* squirrel away a copy of the current selection to the ClipboardDoc */
|
|
lpClipboardDoc = OutlineDoc_CreateDataTransferDoc(lpSrcOutlineDoc);
|
|
|
|
if (! lpClipboardDoc)
|
|
return; // Error: could not create DataTransferDoc
|
|
|
|
lpOutlineApp->m_lpClipboardDoc = (LPOUTLINEDOC)lpClipboardDoc;
|
|
|
|
/* OLE2NOTE: initially the Doc object is created with a 0 ref
|
|
** count. in order to have a stable Doc object during the
|
|
** process of initializing the Doc instance and transfering it
|
|
** to the clipboard, we intially AddRef the Doc ref cnt and later
|
|
** Release it. This initial AddRef is artificial; it is simply
|
|
** done to guarantee that a harmless QueryInterface followed by
|
|
** a Release does not inadvertantly force our object to destroy
|
|
** itself prematurely.
|
|
*/
|
|
OleDoc_AddRef((LPOLEDOC)lpClipboardDoc);
|
|
|
|
/* OLE2NOTE: the OLE 2.0 style to put data onto the clipboard is to
|
|
** give the clipboard a pointer to an IDataObject interface that
|
|
** is able to statisfy IDataObject::GetData calls to render
|
|
** data. in our case we give the pointer to the ClipboardDoc
|
|
** which holds a cloned copy of the current user's selection.
|
|
*/
|
|
OLEDBG_BEGIN2("OleSetClipboard called\r\n")
|
|
OleSetClipboard((LPDATAOBJECT)&((LPOLEDOC)lpClipboardDoc)->m_DataObject);
|
|
OLEDBG_END2
|
|
|
|
OleDoc_Release((LPOLEDOC)lpClipboardDoc); // rel artificial AddRef above
|
|
}
|
|
|
|
|
|
/* OleDoc_PasteCommand
|
|
** -------------------
|
|
** Paste default format data from the clipboard.
|
|
** In this function we choose the highest fidelity format that the
|
|
** source clipboard IDataObject* offers that we understand.
|
|
**
|
|
** OLE2NOTE: clipboard handling in an OLE 2.0 application is
|
|
** different than normal Windows clipboard handling. Data from the
|
|
** clipboard is retieved by getting the IDataObject* pointer
|
|
** returned by calling OleGetClipboard.
|
|
*/
|
|
void OleDoc_PasteCommand(LPOLEDOC lpOleDoc)
|
|
{
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
|
LPDATAOBJECT lpClipboardDataObj = NULL;
|
|
BOOL fLink = FALSE;
|
|
BOOL fLocalDataObj = FALSE;
|
|
BOOL fStatus;
|
|
HRESULT hrErr;
|
|
|
|
hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj);
|
|
if (hrErr != NOERROR)
|
|
return; // Clipboard seems to be empty or can't be accessed
|
|
|
|
OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );
|
|
|
|
/* check if the data on the clipboard is local to our application
|
|
** instance.
|
|
*/
|
|
if (lpOutlineApp->m_lpClipboardDoc) {
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;
|
|
if (lpClipboardDataObj == (LPDATAOBJECT)&lpOleDoc->m_DataObject)
|
|
fLocalDataObj = TRUE;
|
|
}
|
|
|
|
fStatus = OleDoc_PasteFromData(
|
|
lpOleDoc,
|
|
lpClipboardDataObj,
|
|
fLocalDataObj,
|
|
fLink
|
|
);
|
|
|
|
OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );
|
|
|
|
if (! fStatus)
|
|
OutlineApp_ErrorMessage(g_lpApp,"Could not paste data from clipboard!");
|
|
|
|
if (lpClipboardDataObj)
|
|
OleStdRelease((LPUNKNOWN)lpClipboardDataObj);
|
|
}
|
|
|
|
|
|
/* OleDoc_PasteSpecialCommand
|
|
** --------------------------
|
|
** Allow the user to paste data in a particular format from the
|
|
** clipboard. The paste special command displays a dialog to the
|
|
** user that allows him to choose the format to be pasted from the
|
|
** list of formats available.
|
|
**
|
|
** OLE2NOTE: the PasteSpecial dialog is one of the standard OLE 2.0
|
|
** UI dialogs for which the dialog is implemented and in the OLE2UI
|
|
** library.
|
|
**
|
|
** OLE2NOTE: clipboard handling in an OLE 2.0 application is
|
|
** different than normal Windows clipboard handling. Data from the
|
|
** clipboard is retieved by getting the IDataObject* pointer
|
|
** returned by calling OleGetClipboard.
|
|
*/
|
|
void OleDoc_PasteSpecialCommand(LPOLEDOC lpOleDoc)
|
|
{
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
|
LPDATAOBJECT lpClipboardDataObj = NULL;
|
|
CLIPFORMAT cfFormat;
|
|
int nFmtEtc;
|
|
UINT uInt;
|
|
BOOL fLink = FALSE;
|
|
BOOL fLocalDataObj = FALSE;
|
|
BOOL fStatus;
|
|
HRESULT hrErr;
|
|
OLEUIPASTESPECIAL ouiPasteSpl;
|
|
BOOL fDisplayAsIcon;
|
|
|
|
hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj);
|
|
if (hrErr != NOERROR)
|
|
return; // Clipboard seems to be empty or can't be accessed
|
|
|
|
/* check if the data on the clipboard is local to our application
|
|
** instance.
|
|
*/
|
|
if (lpOutlineApp->m_lpClipboardDoc) {
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;
|
|
if (lpClipboardDataObj == (LPDATAOBJECT)&lpOleDoc->m_DataObject)
|
|
fLocalDataObj = TRUE;
|
|
}
|
|
|
|
/* Display the PasteSpecial dialog and allow the user to select the
|
|
** format to paste.
|
|
*/
|
|
_fmemset((LPOLEUIPASTESPECIAL)&ouiPasteSpl, 0, sizeof(ouiPasteSpl));
|
|
ouiPasteSpl.cbStruct = sizeof(ouiPasteSpl); //Structure Size
|
|
ouiPasteSpl.dwFlags = PSF_SELECTPASTE | PSF_SHOWHELP; //IN-OUT: Flags
|
|
ouiPasteSpl.hWndOwner = lpOutlineApp->m_lpDoc->m_hWndDoc; //Owning window
|
|
ouiPasteSpl.lpszCaption = "Paste Special"; //Dialog caption bar contents
|
|
ouiPasteSpl.lpfnHook = NULL; //Hook callback
|
|
ouiPasteSpl.lCustData = 0; //Custom data to pass to hook
|
|
ouiPasteSpl.hInstance = NULL; //Instance for customized template name
|
|
ouiPasteSpl.lpszTemplate = NULL; //Customized template name
|
|
ouiPasteSpl.hResource = NULL; //Customized template handle
|
|
|
|
ouiPasteSpl.arrPasteEntries = lpOleApp->m_arrPasteEntries;
|
|
ouiPasteSpl.cPasteEntries = lpOleApp->m_nPasteEntries;
|
|
ouiPasteSpl.lpSrcDataObj = lpClipboardDataObj;
|
|
ouiPasteSpl.arrLinkTypes = lpOleApp->m_arrLinkTypes;
|
|
ouiPasteSpl.cLinkTypes = lpOleApp->m_nLinkTypes;
|
|
ouiPasteSpl.cClsidExclude = 0;
|
|
|
|
OLEDBG_BEGIN3("OleUIPasteSpecial called\r\n")
|
|
uInt = OleUIPasteSpecial(&ouiPasteSpl);
|
|
OLEDBG_END3
|
|
|
|
fDisplayAsIcon =
|
|
(ouiPasteSpl.dwFlags & PSF_CHECKDISPLAYASICON ? TRUE : FALSE);
|
|
|
|
if (uInt == OLEUI_OK) {
|
|
nFmtEtc = ouiPasteSpl.nSelectedIndex;
|
|
fLink = ouiPasteSpl.fLink;
|
|
|
|
if (nFmtEtc < 0 || nFmtEtc >= lpOleApp->m_nPasteEntries) {
|
|
OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgBadFmt);
|
|
goto error;
|
|
}
|
|
|
|
OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );
|
|
|
|
cfFormat = lpOleApp->m_arrPasteEntries[nFmtEtc].fmtetc.cfFormat;
|
|
|
|
fStatus = OleDoc_PasteFormatFromData(
|
|
lpOleDoc,
|
|
cfFormat,
|
|
lpClipboardDataObj,
|
|
fLocalDataObj,
|
|
fLink,
|
|
fDisplayAsIcon,
|
|
ouiPasteSpl.hMetaPict,
|
|
(LPSIZEL)&ouiPasteSpl.sizel
|
|
);
|
|
|
|
OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );
|
|
|
|
if (! fStatus) {
|
|
OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgPasteFailed);
|
|
goto error;
|
|
}
|
|
|
|
} else if (uInt == OLEUI_PSERR_CLIPBOARDCHANGED) {
|
|
/* OLE2NOTE: this error code is returned when the contents of
|
|
** the clipboard change while the PasteSpecial dialog is up.
|
|
** in this situation the PasteSpecial dialog automatically
|
|
** brings itself down and NO paste operation should be performed.
|
|
*/
|
|
OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgClipboardChanged);
|
|
}
|
|
|
|
error:
|
|
|
|
if (lpClipboardDataObj)
|
|
OleStdRelease((LPUNKNOWN)lpClipboardDataObj);
|
|
|
|
if (uInt == OLEUI_OK && ouiPasteSpl.hMetaPict)
|
|
// clean up metafile
|
|
OleUIMetafilePictIconFree(ouiPasteSpl.hMetaPict);
|
|
}
|
|
|
|
|
|
|
|
/* OleDoc_CreateDataTransferDoc
|
|
* ----------------------------
|
|
*
|
|
* Create a document to be use to transfer data (either via a
|
|
* drag/drop operation of the clipboard). Copy the selection of the
|
|
* source doc to the data transfer document. A data transfer document is
|
|
* the same as a document that is created by the user except that it is
|
|
* NOT made visible to the user. it is specially used to hold a copy of
|
|
* data that the user should not be able to change.
|
|
*
|
|
* OLE2NOTE: in the OLE version the data transfer document is used
|
|
* specifically to provide an IDataObject* that renders the data copied.
|
|
*/
|
|
LPOUTLINEDOC OleDoc_CreateDataTransferDoc(LPOLEDOC lpSrcOleDoc)
|
|
{
|
|
LPOUTLINEDOC lpSrcOutlineDoc = (LPOUTLINEDOC)lpSrcOleDoc;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
|
LPOUTLINEDOC lpDestOutlineDoc;
|
|
LPLINELIST lpSrcLL = &lpSrcOutlineDoc->m_LineList;
|
|
LINERANGE lrSel;
|
|
int nCopied;
|
|
|
|
lpDestOutlineDoc = OutlineApp_CreateDoc(lpOutlineApp, TRUE);
|
|
if (! lpDestOutlineDoc) return NULL;
|
|
|
|
// set the ClipboardDoc to an (Untitled) doc.
|
|
if (! OutlineDoc_InitNewFile(lpDestOutlineDoc))
|
|
goto error;
|
|
|
|
LineList_GetSel(lpSrcLL, (LPLINERANGE)&lrSel);
|
|
nCopied = LineList_CopySelToDoc(
|
|
lpSrcLL,
|
|
(LPLINERANGE)&lrSel,
|
|
lpDestOutlineDoc
|
|
);
|
|
|
|
if (nCopied != (lrSel.m_nEndLine - lrSel.m_nStartLine + 1)) {
|
|
OleDbgAssertSz(FALSE,"OleDoc_CreateDataTransferDoc: entire selection NOT copied\r\n");
|
|
goto error; // ERROR: all lines could NOT be copied
|
|
}
|
|
|
|
#if defined( OLE_SERVER )
|
|
{
|
|
LPOLEDOC lpSrcOleDoc = (LPOLEDOC)lpSrcOutlineDoc;
|
|
LPOLEDOC lpDestOleDoc = (LPOLEDOC)lpDestOutlineDoc;
|
|
LPSERVERDOC lpDestServerDoc = (LPSERVERDOC)lpDestOutlineDoc;
|
|
LPMONIKER lpmkDoc = NULL;
|
|
LPMONIKER lpmkItem = NULL;
|
|
|
|
/* If source document is able to provide a moniker, then the
|
|
** destination document (lpDestOutlineDoc) should offer
|
|
** CF_LINKSOURCE via its IDataObject interface that it gives
|
|
** to the clipboard or the drag/drop operation.
|
|
**
|
|
** OLE2NOTE: we want to ask the source document if it can
|
|
** produce a moniker, but we do NOT want to FORCE moniker
|
|
** assignment at this point. we only want to FORCE moniker
|
|
** assignment later if a Paste Link occurs (ie. GetData for
|
|
** CF_LINKSOURCE). if the source document is able to give
|
|
** a moniker, then we store a pointer to the source document
|
|
** so we can ask it at a later time to get the moniker. we
|
|
** also save the range of the current selection so we can
|
|
** generate a proper item name later when Paste Link occurs.
|
|
** Also we need to give a string which identifies the source
|
|
** of the copy in the CF_OBJECTDESCRIPTOR format. this
|
|
** string is used to display in the PasteSpecial dialog. we
|
|
** get and store a TEMPFORUSER moniker which identifies the
|
|
** source of copy.
|
|
*/
|
|
lpDestOleDoc->m_lpSrcDocOfCopy = lpSrcOleDoc;
|
|
lpmkDoc = OleDoc_GetFullMoniker(lpSrcOleDoc, GETMONIKER_TEMPFORUSER);
|
|
if (lpmkDoc != NULL) {
|
|
lpDestOleDoc->m_fLinkSourceAvail = TRUE;
|
|
lpDestServerDoc->m_lrSrcSelOfCopy = lrSel;
|
|
OleStdRelease((LPUNKNOWN)lpmkDoc);
|
|
}
|
|
}
|
|
#endif
|
|
#if defined( OLE_CNTR )
|
|
{
|
|
LPOLEDOC lpSrcOleDoc = (LPOLEDOC)lpSrcOutlineDoc;
|
|
LPOLEDOC lpDestOleDoc = (LPOLEDOC)lpDestOutlineDoc;
|
|
LPCONTAINERDOC lpDestContainerDoc = (LPCONTAINERDOC)lpDestOutlineDoc;
|
|
|
|
/* If one line was copied from the source document, and it was a
|
|
** single OLE object, then the destination document should
|
|
** offer additional data formats to allow the transfer of
|
|
** the OLE object via IDataObject::GetData. Specifically, the
|
|
** following additional data formats are offered if a single
|
|
** OLE object is copied:
|
|
** CF_EMBEDDEDOBJECT
|
|
** CF_OBJECTDESCRIPTOR (should be given even w/o object)
|
|
** CF_METAFILEPICT (note: dwAspect depends on object)
|
|
** CF_LINKSOURCE -- if linking is possible
|
|
** CF_LINKSOURCEDESCRIPTOR -- if linking is possible
|
|
**
|
|
** optionally the container may give
|
|
** <data format available in OLE object's cache>
|
|
*/
|
|
|
|
if (nCopied == 1) {
|
|
LPOLEOBJECT lpSrcOleObj;
|
|
LPCONTAINERLINE lpSrcContainerLine;
|
|
DWORD dwStatus;
|
|
|
|
lpSrcContainerLine = (LPCONTAINERLINE)LineList_GetLine(
|
|
lpSrcLL,
|
|
lrSel.m_nStartLine
|
|
);
|
|
|
|
if (! lpSrcContainerLine)
|
|
goto error;
|
|
|
|
lpDestOleDoc->m_lpSrcDocOfCopy = lpSrcOleDoc;
|
|
|
|
if ((((LPLINE)lpSrcContainerLine)->m_lineType==CONTAINERLINETYPE)
|
|
&& ((lpSrcOleObj=lpSrcContainerLine->m_lpOleObj)!=NULL)) {
|
|
|
|
lpDestContainerDoc->m_fEmbeddedObjectAvail = TRUE;
|
|
lpSrcOleObj->lpVtbl->GetUserClassID(
|
|
lpSrcOleObj,
|
|
&lpDestContainerDoc->m_clsidOleObjCopied
|
|
);
|
|
lpDestContainerDoc->m_dwAspectOleObjCopied =
|
|
lpSrcContainerLine->m_dwDrawAspect;
|
|
|
|
/* OLE2NOTE: if the object is allowed to be linked
|
|
** to from the inside (ie. we are allowed to
|
|
** give out a moniker which binds to the running
|
|
** OLE object), then we want to offer
|
|
** CF_LINKSOURCE format. if the object is an OLE
|
|
** 2.0 embedded object then it is allowed to be
|
|
** linked to from the inside. if the object is
|
|
** either an OleLink or an OLE 1.0 embedding
|
|
** then it can not be linked to from the inside.
|
|
** if we were a container/server app then we
|
|
** could offer linking to the outside of the
|
|
** object (ie. a pseudo object within our
|
|
** document). we are a container only app that
|
|
** does not support linking to ranges of its data.
|
|
*/
|
|
|
|
lpSrcOleObj->lpVtbl->GetMiscStatus(
|
|
lpSrcOleObj,
|
|
DVASPECT_CONTENT, /* aspect is not important */
|
|
(LPDWORD)&dwStatus
|
|
);
|
|
if (! (dwStatus & OLEMISC_CANTLINKINSIDE)) {
|
|
/* Our container supports linking to an embedded
|
|
** object. We want the lpDestContainerDoc to
|
|
** offer CF_LINKSOURCE via the IDataObject
|
|
** interface that it gives to the clipboard or
|
|
** the drag/drop operation. The link source will
|
|
** be identified by a composite moniker
|
|
** comprised of the FileMoniker of the source
|
|
** document and an ItemMoniker which identifies
|
|
** the OLE object inside the container. we do
|
|
** NOT want to force moniker assignment to the
|
|
** OLE object now (at copy time); we only want
|
|
** to FORCE moniker assignment later if a Paste
|
|
** Link occurs (ie. GetData for CF_LINKSOURCE).
|
|
** thus we store a pointer to the source document
|
|
** and the source ContainerLine so we can
|
|
** generate a proper ItemMoniker later when
|
|
** Paste Link occurs.
|
|
*/
|
|
lpDestOleDoc->m_fLinkSourceAvail = TRUE;
|
|
lpDestContainerDoc->m_lpSrcContainerLine =
|
|
lpSrcContainerLine;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // OLE_CNTR
|
|
|
|
return lpDestOutlineDoc;
|
|
|
|
error:
|
|
if (lpDestOutlineDoc)
|
|
OutlineDoc_Destroy(lpDestOutlineDoc);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* OleDoc_PasteFromData
|
|
** --------------------
|
|
**
|
|
** Paste data from an IDataObject*. The IDataObject* may come from
|
|
** the clipboard (GetClipboard) or from a drag/drop operation.
|
|
** In this function we choose the best format that we prefer.
|
|
**
|
|
** Returns TRUE if data was successfully pasted.
|
|
** FALSE if data could not be pasted.
|
|
*/
|
|
|
|
BOOL OleDoc_PasteFromData(
|
|
LPOLEDOC lpOleDoc,
|
|
LPDATAOBJECT lpSrcDataObj,
|
|
BOOL fLocalDataObj,
|
|
BOOL fLink
|
|
)
|
|
{
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
|
CLIPFORMAT cfFormat;
|
|
BOOL fDisplayAsIcon = FALSE;
|
|
SIZEL sizelInSrc = {0, 0};
|
|
HGLOBAL hMem = NULL;
|
|
HGLOBAL hMetaPict = NULL;
|
|
STGMEDIUM medium;
|
|
|
|
if (fLink) {
|
|
#if defined( OLE_SERVER )
|
|
return FALSE; // server version of app does NOT support links
|
|
#endif
|
|
#if defined( OLE_CNTR )
|
|
// container version of app only supports OLE object type links
|
|
cfFormat = lpOleApp->m_cfLinkSource;
|
|
#endif
|
|
|
|
} else {
|
|
|
|
int nFmtEtc;
|
|
|
|
nFmtEtc = OleStdGetPriorityClipboardFormat(
|
|
lpSrcDataObj,
|
|
lpOleApp->m_arrPasteEntries,
|
|
lpOleApp->m_nPasteEntries
|
|
);
|
|
|
|
if (nFmtEtc < 0)
|
|
return FALSE; // there is no format we like
|
|
|
|
cfFormat = lpOleApp->m_arrPasteEntries[nFmtEtc].fmtetc.cfFormat;
|
|
}
|
|
|
|
/* OLE2NOTE: we need to check what dwDrawAspect is being
|
|
** transfered. if the data is an object that is displayed as an
|
|
** icon in the source, then we want to keep it as an icon. the
|
|
** aspect the object is displayed in at the source is transfered
|
|
** via the CF_OBJECTDESCRIPTOR format for a Paste operation.
|
|
*/
|
|
if (hMem = OleStdGetData(
|
|
lpSrcDataObj,
|
|
lpOleApp->m_cfObjectDescriptor,
|
|
NULL,
|
|
DVASPECT_CONTENT,
|
|
(LPSTGMEDIUM)&medium)) {
|
|
LPOBJECTDESCRIPTOR lpOD = GlobalLock(hMem);
|
|
fDisplayAsIcon = (lpOD->dwDrawAspect == DVASPECT_ICON ? TRUE : FALSE);
|
|
sizelInSrc = lpOD->sizel; // size of object/picture in source (opt.)
|
|
GlobalUnlock(hMem);
|
|
ReleaseStgMedium((LPSTGMEDIUM)&medium); // equiv to GlobalFree
|
|
|
|
if (fDisplayAsIcon) {
|
|
hMetaPict = OleStdGetData(
|
|
lpSrcDataObj,
|
|
CF_METAFILEPICT,
|
|
NULL,
|
|
DVASPECT_ICON,
|
|
(LPSTGMEDIUM)&medium
|
|
);
|
|
if (hMetaPict == NULL)
|
|
fDisplayAsIcon = FALSE; // give up; failed to get icon MFP
|
|
}
|
|
}
|
|
|
|
return OleDoc_PasteFormatFromData(
|
|
lpOleDoc,
|
|
cfFormat,
|
|
lpSrcDataObj,
|
|
fLocalDataObj,
|
|
fLink,
|
|
fDisplayAsIcon,
|
|
hMetaPict,
|
|
(LPSIZEL)&sizelInSrc
|
|
);
|
|
|
|
if (hMetaPict)
|
|
ReleaseStgMedium((LPSTGMEDIUM)&medium); // properly free METAFILEPICT
|
|
}
|
|
|
|
|
|
/* OleDoc_PasteFormatFromData
|
|
** --------------------------
|
|
**
|
|
** Paste a particular data format from a IDataObject*. The
|
|
** IDataObject* may come from the clipboard (GetClipboard) or from a
|
|
** drag/drop operation.
|
|
**
|
|
** Returns TRUE if data was successfully pasted.
|
|
** FALSE if data could not be pasted.
|
|
*/
|
|
|
|
BOOL OleDoc_PasteFormatFromData(
|
|
LPOLEDOC lpOleDoc,
|
|
CLIPFORMAT cfFormat,
|
|
LPDATAOBJECT lpSrcDataObj,
|
|
BOOL fLocalDataObj,
|
|
BOOL fLink,
|
|
BOOL fDisplayAsIcon,
|
|
HGLOBAL hMetaPict,
|
|
LPSIZEL lpSizelInSrc
|
|
)
|
|
{
|
|
#if defined( OLE_SERVER )
|
|
/* call server specific version of the function. */
|
|
return ServerDoc_PasteFormatFromData(
|
|
(LPSERVERDOC)lpOleDoc,
|
|
cfFormat,
|
|
lpSrcDataObj,
|
|
fLocalDataObj,
|
|
fLink
|
|
);
|
|
#endif
|
|
#if defined( OLE_CNTR )
|
|
|
|
/* call container specific version of the function. */
|
|
return ContainerDoc_PasteFormatFromData(
|
|
(LPCONTAINERDOC)lpOleDoc,
|
|
cfFormat,
|
|
lpSrcDataObj,
|
|
fLocalDataObj,
|
|
fLink,
|
|
fDisplayAsIcon,
|
|
hMetaPict,
|
|
lpSizelInSrc
|
|
);
|
|
#endif
|
|
}
|
|
|
|
|
|
/* OleDoc_QueryPasteFromData
|
|
** -------------------------
|
|
**
|
|
** Check if the IDataObject* offers data in a format that we can
|
|
** paste. The IDataObject* may come from the clipboard
|
|
** (GetClipboard) or from a drag/drop operation.
|
|
**
|
|
** Returns TRUE if paste can be performed
|
|
** FALSE if paste is not possible.
|
|
*/
|
|
|
|
BOOL OleDoc_QueryPasteFromData(
|
|
LPOLEDOC lpOleDoc,
|
|
LPDATAOBJECT lpSrcDataObj,
|
|
BOOL fLink
|
|
)
|
|
{
|
|
#if defined( OLE_SERVER )
|
|
return ServerDoc_QueryPasteFromData(
|
|
(LPSERVERDOC) lpOleDoc,
|
|
lpSrcDataObj,
|
|
fLink
|
|
);
|
|
#endif
|
|
#if defined( OLE_CNTR )
|
|
|
|
return ContainerDoc_QueryPasteFromData(
|
|
(LPCONTAINERDOC) lpOleDoc,
|
|
lpSrcDataObj,
|
|
fLink
|
|
);
|
|
#endif
|
|
}
|
|
|
|
|
|
/* OleDoc_GetExtent
|
|
* ----------------
|
|
*
|
|
* Get the extent (width, height) of the entire document in Himetric.
|
|
*/
|
|
void OleDoc_GetExtent(LPOLEDOC lpOleDoc, LPSIZEL lpsizel)
|
|
{
|
|
LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
|
|
|
|
LineList_CalcSelExtentInHimetric(lpLL, NULL, lpsizel);
|
|
}
|
|
|
|
|
|
/* OleDoc_GetObjectDescriptorData
|
|
* ------------------------------
|
|
*
|
|
* Return a handle to an object's data in CF_OBJECTDESCRIPTOR form
|
|
*
|
|
*/
|
|
HGLOBAL OleDoc_GetObjectDescriptorData(LPOLEDOC lpOleDoc, LPLINERANGE lplrSel)
|
|
{
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
|
|
|
|
/* Only our data transfer doc renders CF_OBJECTDESCRIPTOR */
|
|
OleDbgAssert(lpOutlineDoc->m_fDataTransferDoc);
|
|
|
|
#if defined( OLE_SERVER )
|
|
{
|
|
LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
|
|
SIZEL sizel;
|
|
POINTL pointl;
|
|
LPSTR lpszSrcOfCopy = NULL;
|
|
IBindCtx FAR *pbc = NULL;
|
|
HGLOBAL hObjDesc;
|
|
DWORD dwStatus = 0;
|
|
LPOUTLINEDOC lpSrcDocOfCopy=(LPOUTLINEDOC)lpOleDoc->m_lpSrcDocOfCopy;
|
|
LPMONIKER lpSrcMonikerOfCopy = ServerDoc_GetSelFullMoniker(
|
|
(LPSERVERDOC)lpOleDoc->m_lpSrcDocOfCopy,
|
|
&lpServerDoc->m_lrSrcSelOfCopy,
|
|
GETMONIKER_TEMPFORUSER
|
|
);
|
|
|
|
SvrDoc_OleObj_GetMiscStatus(
|
|
(LPOLEOBJECT)&lpServerDoc->m_OleObject,
|
|
DVASPECT_CONTENT,
|
|
&dwStatus
|
|
);
|
|
|
|
OleDoc_GetExtent(lpOleDoc, &sizel);
|
|
pointl.x = pointl.y = 0;
|
|
|
|
if (lpSrcMonikerOfCopy) {
|
|
CreateBindCtx(0, (LPBC FAR*)&pbc);
|
|
CallIMonikerGetDisplayNameA(
|
|
lpSrcMonikerOfCopy, pbc, NULL, &lpszSrcOfCopy);
|
|
pbc->lpVtbl->Release(pbc);
|
|
lpSrcMonikerOfCopy->lpVtbl->Release(lpSrcMonikerOfCopy);
|
|
} else {
|
|
/* this document has no moniker; use our FullUserTypeName
|
|
** as the description of the source of copy.
|
|
*/
|
|
lpszSrcOfCopy = FULLUSERTYPENAME;
|
|
}
|
|
|
|
hObjDesc = OleStdGetObjectDescriptorData(
|
|
CLSID_APP,
|
|
DVASPECT_CONTENT,
|
|
sizel,
|
|
pointl,
|
|
dwStatus,
|
|
FULLUSERTYPENAME,
|
|
lpszSrcOfCopy
|
|
);
|
|
|
|
if (lpSrcMonikerOfCopy && lpszSrcOfCopy)
|
|
OleStdFreeString(lpszSrcOfCopy, NULL);
|
|
return hObjDesc;
|
|
|
|
}
|
|
#endif
|
|
#if defined( OLE_CNTR )
|
|
{
|
|
LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;
|
|
LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
|
|
LPCONTAINERLINE lpContainerLine;
|
|
HGLOBAL hObjDesc;
|
|
BOOL fSelIsOleObject = FALSE;
|
|
LPOLEOBJECT lpOleObj;
|
|
SIZEL sizel;
|
|
POINTL pointl;
|
|
|
|
if ( lpLL->m_nNumLines == 1 ) {
|
|
fSelIsOleObject = ContainerDoc_IsSelAnOleObject(
|
|
lpContainerDoc,
|
|
&IID_IOleObject,
|
|
(LPUNKNOWN FAR*)&lpOleObj,
|
|
NULL, /* we don't need the line index */
|
|
(LPCONTAINERLINE FAR*)&lpContainerLine
|
|
);
|
|
}
|
|
|
|
pointl.x = pointl.y = 0;
|
|
|
|
if (fSelIsOleObject) {
|
|
/* OLE2NOTE: a single OLE object is being transfered via
|
|
** this DataTransferDoc. we need to generate the
|
|
** CF_ObjectDescrioptor which describes the OLE object.
|
|
*/
|
|
|
|
LPOUTLINEDOC lpSrcOutlineDoc =
|
|
(LPOUTLINEDOC)lpOleDoc->m_lpSrcDocOfCopy;
|
|
LPSTR lpszSrcOfCopy = lpSrcOutlineDoc->m_szFileName;
|
|
BOOL fFreeSrcOfCopy = FALSE;
|
|
SIZEL sizelOleObject;
|
|
LPLINE lpLine = (LPLINE)lpContainerLine;
|
|
|
|
/* if the object copied can be linked to then get a
|
|
** TEMPFORUSER form of the moniker which identifies the
|
|
** source of copy. we do not want to force the
|
|
** assignment of the moniker until CF_LINKSOURCE is
|
|
** rendered.
|
|
** if the object copied can not be a link source then use
|
|
** the source filename to identify the source of copy.
|
|
** there is no need to generate a moniker for the object
|
|
** copied.
|
|
*/
|
|
if (lpOleDoc->m_fLinkSourceAvail &&
|
|
lpContainerDoc->m_lpSrcContainerLine) {
|
|
LPBINDCTX pbc = NULL;
|
|
LPMONIKER lpSrcMonikerOfCopy = ContainerLine_GetFullMoniker(
|
|
lpContainerDoc->m_lpSrcContainerLine,
|
|
GETMONIKER_TEMPFORUSER
|
|
);
|
|
if (lpSrcMonikerOfCopy) {
|
|
CreateBindCtx(0, (LPBC FAR*)&pbc);
|
|
if (pbc != NULL) {
|
|
CallIMonikerGetDisplayNameA(
|
|
lpSrcMonikerOfCopy, pbc, NULL, &lpszSrcOfCopy);
|
|
|
|
pbc->lpVtbl->Release(pbc);
|
|
fFreeSrcOfCopy = TRUE;
|
|
}
|
|
lpSrcMonikerOfCopy->lpVtbl->Release(lpSrcMonikerOfCopy);
|
|
}
|
|
}
|
|
|
|
/* OLE2NOTE: Get size that object is being drawn. If the
|
|
** object has been scaled because the user resized the
|
|
** object, then we want to pass the scaled size of the
|
|
** object in the ObjectDescriptor rather than the size
|
|
** that the object would return via
|
|
** IOleObject::GetExtent and IViewObject2::GetExtent. in
|
|
** this way if the object is transfered to another container
|
|
** (via clipboard or drag/drop), then the object will
|
|
** remain the scaled size.
|
|
*/
|
|
sizelOleObject.cx = lpLine->m_nWidthInHimetric;
|
|
sizelOleObject.cy = lpLine->m_nHeightInHimetric;
|
|
|
|
hObjDesc = OleStdGetObjectDescriptorDataFromOleObject(
|
|
lpOleObj,
|
|
lpszSrcOfCopy,
|
|
lpContainerLine->m_dwDrawAspect,
|
|
pointl,
|
|
(LPSIZEL)&sizelOleObject
|
|
);
|
|
|
|
if (fFreeSrcOfCopy && lpszSrcOfCopy)
|
|
OleStdFreeString(lpszSrcOfCopy, NULL);
|
|
OleStdRelease((LPUNKNOWN)lpOleObj);
|
|
return hObjDesc;
|
|
} else {
|
|
/* OLE2NOTE: the data being transfered via this
|
|
** DataTransferDoc is NOT a single OLE object. thus in
|
|
** this case the CF_ObjectDescriptor data should
|
|
** describe our container app itself.
|
|
*/
|
|
OleDoc_GetExtent(lpOleDoc, &sizel);
|
|
return OleStdGetObjectDescriptorData(
|
|
CLSID_NULL, /* not used if no object formats */
|
|
DVASPECT_CONTENT,
|
|
sizel,
|
|
pointl,
|
|
0,
|
|
NULL, /* UserTypeName not used if no obj fmt's */
|
|
FULLUSERTYPENAME /* string to identify source of copy */
|
|
);
|
|
|
|
}
|
|
}
|
|
#endif // OLE_CNTR
|
|
}
|
|
|
|
|
|
#if defined( OLE_SERVER )
|
|
|
|
/*************************************************************************
|
|
** ServerDoc Supprt Functions Used by Server versions
|
|
*************************************************************************/
|
|
|
|
|
|
/* ServerDoc_PasteFormatFromData
|
|
** -----------------------------
|
|
**
|
|
** Paste a particular data format from a IDataObject*. The
|
|
** IDataObject* may come from the clipboard (GetClipboard) or from a
|
|
** drag/drop operation.
|
|
**
|
|
** NOTE: fLink is specified then FALSE if returned because the
|
|
** Server only version of the app can not support links.
|
|
**
|
|
** Returns TRUE if data was successfully pasted.
|
|
** FALSE if data could not be pasted.
|
|
*/
|
|
BOOL ServerDoc_PasteFormatFromData(
|
|
LPSERVERDOC lpServerDoc,
|
|
CLIPFORMAT cfFormat,
|
|
LPDATAOBJECT lpSrcDataObj,
|
|
BOOL fLocalDataObj,
|
|
BOOL fLink
|
|
)
|
|
{
|
|
LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpServerDoc)->m_LineList;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
|
int nIndex;
|
|
int nCount = 0;
|
|
HGLOBAL hData;
|
|
STGMEDIUM medium;
|
|
LINERANGE lrSel;
|
|
|
|
if (LineList_GetCount(lpLL) == 0)
|
|
nIndex = -1; // pasting to empty list
|
|
else
|
|
nIndex=LineList_GetFocusLineIndex(lpLL);
|
|
|
|
if (fLink) {
|
|
/* We should paste a Link to the data, but we do not support links */
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
if (cfFormat == lpOutlineApp->m_cfOutline) {
|
|
|
|
hData = OleStdGetData(
|
|
lpSrcDataObj,
|
|
lpOutlineApp->m_cfOutline,
|
|
NULL,
|
|
DVASPECT_CONTENT,
|
|
(LPSTGMEDIUM)&medium
|
|
);
|
|
if (hData == NULL)
|
|
return FALSE;
|
|
|
|
nCount = OutlineDoc_PasteOutlineData(
|
|
(LPOUTLINEDOC)lpServerDoc,
|
|
hData,
|
|
nIndex
|
|
);
|
|
// OLE2NOTE: we must free data handle by releasing the medium
|
|
ReleaseStgMedium((LPSTGMEDIUM)&medium);
|
|
|
|
} else if(cfFormat == CF_TEXT) {
|
|
|
|
hData = OleStdGetData(
|
|
lpSrcDataObj,
|
|
CF_TEXT,
|
|
NULL,
|
|
DVASPECT_CONTENT,
|
|
(LPSTGMEDIUM)&medium
|
|
);
|
|
if (hData == NULL)
|
|
return FALSE;
|
|
|
|
nCount = OutlineDoc_PasteTextData(
|
|
(LPOUTLINEDOC)lpServerDoc,
|
|
hData,
|
|
nIndex
|
|
);
|
|
// OLE2NOTE: we must free data handle by releasing the medium
|
|
ReleaseStgMedium((LPSTGMEDIUM)&medium);
|
|
}
|
|
}
|
|
|
|
lrSel.m_nEndLine = nIndex + 1;
|
|
lrSel.m_nStartLine = nIndex + nCount;
|
|
LineList_SetSel(lpLL, &lrSel);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* ServerDoc_QueryPasteFromData
|
|
** ----------------------------
|
|
**
|
|
** Check if the IDataObject* offers data in a format that we can
|
|
** paste. The IDataObject* may come from the clipboard
|
|
** (GetClipboard) or from a drag/drop operation.
|
|
** In this function we look if one of the following formats is
|
|
** offered:
|
|
** CF_OUTLINE
|
|
** CF_TEXT
|
|
**
|
|
** NOTE: fLink is specified then FALSE if returned because the
|
|
** Server only version of the app can not support links.
|
|
**
|
|
** Returns TRUE if paste can be performed
|
|
** FALSE if paste is not possible.
|
|
*/
|
|
BOOL ServerDoc_QueryPasteFromData(
|
|
LPSERVERDOC lpServerDoc,
|
|
LPDATAOBJECT lpSrcDataObj,
|
|
BOOL fLink
|
|
)
|
|
{
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
|
|
|
if (fLink) {
|
|
/* we do not support links */
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
int nFmtEtc;
|
|
|
|
nFmtEtc = OleStdGetPriorityClipboardFormat(
|
|
lpSrcDataObj,
|
|
lpOleApp->m_arrPasteEntries,
|
|
lpOleApp->m_nPasteEntries
|
|
);
|
|
|
|
if (nFmtEtc < 0)
|
|
return FALSE; // there is no format we like
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* ServerDoc_GetData
|
|
* -----------------
|
|
*
|
|
* Render data from the document on a CALLEE allocated STGMEDIUM.
|
|
* This routine is called via IDataObject::GetData.
|
|
*/
|
|
|
|
HRESULT ServerDoc_GetData (
|
|
LPSERVERDOC lpServerDoc,
|
|
LPFORMATETC lpformatetc,
|
|
LPSTGMEDIUM lpMedium
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
|
|
LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp;
|
|
HRESULT hrErr;
|
|
SCODE sc;
|
|
|
|
// OLE2NOTE: we must set out pointer parameters to NULL
|
|
lpMedium->pUnkForRelease = NULL;
|
|
|
|
/* 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 = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
lpMedium->hGlobal = OutlineDoc_GetOutlineData (lpOutlineDoc,NULL);
|
|
if (! lpMedium->hGlobal) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->tymed = TYMED_HGLOBAL;
|
|
OleDbgOut3("ServerDoc_GetData: rendered CF_OUTLINE\r\n");
|
|
return NOERROR;
|
|
|
|
} else if (lpformatetc->cfFormat == CF_METAFILEPICT &&
|
|
(lpformatetc->dwAspect & DVASPECT_CONTENT) ) {
|
|
// Verify caller asked for correct medium
|
|
if (!(lpformatetc->tymed & TYMED_MFPICT)) {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->hGlobal = ServerDoc_GetMetafilePictData(lpServerDoc,NULL);
|
|
if (! lpMedium->hGlobal) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->tymed = TYMED_MFPICT;
|
|
OleDbgOut3("ServerDoc_GetData: rendered CF_METAFILEPICT\r\n");
|
|
return NOERROR;
|
|
|
|
} else if (lpformatetc->cfFormat == CF_METAFILEPICT &&
|
|
(lpformatetc->dwAspect & DVASPECT_ICON) ) {
|
|
CLSID clsid;
|
|
// Verify caller asked for correct medium
|
|
if (!(lpformatetc->tymed & TYMED_MFPICT)) {
|
|
sc = DV_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 = DV_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("ServerDoc_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 = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->hGlobal = OutlineDoc_GetTextData (
|
|
(LPOUTLINEDOC)lpServerDoc,
|
|
NULL
|
|
);
|
|
if (! lpMedium->hGlobal) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->tymed = TYMED_HGLOBAL;
|
|
OleDbgOut3("ServerDoc_GetData: rendered CF_TEXT\r\n");
|
|
return NOERROR;
|
|
}
|
|
|
|
/* the above are the only formats supports by a user document (ie.
|
|
** a non-data transfer doc). if the document is used for
|
|
** purposes of data transfer, then additional formats are offered.
|
|
*/
|
|
if (! lpOutlineDoc->m_fDataTransferDoc) {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
/* OLE2NOTE: ObjectDescriptor and LinkSrcDescriptor will
|
|
** contain the same data for the pure container and pure server
|
|
** type applications. only a container/server application may
|
|
** have different content for ObjectDescriptor and
|
|
** LinkSrcDescriptor. if a container/server copies a link for
|
|
** example, then the ObjectDescriptor would give the class
|
|
** of the link source but the LinkSrcDescriptor would give the
|
|
** class of the container/server itself. in this situation if a
|
|
** paste operation occurs, an equivalent link is pasted, but if
|
|
** a pastelink operation occurs, then a link to a pseudo object
|
|
** in the container/server is created.
|
|
*/
|
|
if (lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor ||
|
|
(lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor &&
|
|
lpOleDoc->m_fLinkSourceAvail)) {
|
|
// Verify caller asked for correct medium
|
|
if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->hGlobal = OleDoc_GetObjectDescriptorData (
|
|
(LPOLEDOC)lpServerDoc,
|
|
NULL
|
|
);
|
|
if (! lpMedium->hGlobal) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->tymed = TYMED_HGLOBAL;
|
|
OleDbgOut3("ServerDoc_GetData: rendered CF_OBJECTDESCRIPTOR\r\n");
|
|
return NOERROR;
|
|
|
|
} else if (lpformatetc->cfFormat == lpOleApp->m_cfEmbedSource) {
|
|
hrErr = OleStdGetOleObjectData(
|
|
(LPPERSISTSTORAGE)&lpServerDoc->m_PersistStorage,
|
|
lpformatetc,
|
|
lpMedium,
|
|
FALSE /* fUseMemory -- (use file-base stg) */
|
|
|
|
);
|
|
if (hrErr != NOERROR) {
|
|
sc = GetScode(hrErr);
|
|
goto error;
|
|
}
|
|
OleDbgOut3("ServerDoc_GetData: rendered CF_EMBEDSOURCE\r\n");
|
|
return NOERROR;
|
|
|
|
} else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) {
|
|
if (lpOleDoc->m_fLinkSourceAvail) {
|
|
LPMONIKER lpmk;
|
|
|
|
lpmk = ServerDoc_GetSelFullMoniker(
|
|
(LPSERVERDOC)lpOleDoc->m_lpSrcDocOfCopy,
|
|
&lpServerDoc->m_lrSrcSelOfCopy,
|
|
GETMONIKER_FORCEASSIGN
|
|
);
|
|
if (lpmk) {
|
|
hrErr = OleStdGetLinkSourceData(
|
|
lpmk,
|
|
(LPCLSID)&CLSID_APP,
|
|
lpformatetc,
|
|
lpMedium
|
|
);
|
|
OleStdRelease((LPUNKNOWN)lpmk);
|
|
if (hrErr != NOERROR) {
|
|
sc = GetScode(hrErr);
|
|
goto error;
|
|
}
|
|
OleDbgOut3("ServerDoc_GetData: rendered CF_LINKSOURCE\r\n");
|
|
return NOERROR;
|
|
|
|
} else {
|
|
sc = E_FAIL;
|
|
goto error;
|
|
}
|
|
} else {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
} else {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
return NOERROR;
|
|
|
|
error:
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
/* ServerDoc_GetDataHere
|
|
* ---------------------
|
|
*
|
|
* Render data from the document on a CALLER allocated STGMEDIUM.
|
|
* This routine is called via IDataObject::GetDataHere.
|
|
*/
|
|
HRESULT ServerDoc_GetDataHere (
|
|
LPSERVERDOC lpServerDoc,
|
|
LPFORMATETC lpformatetc,
|
|
LPSTGMEDIUM lpMedium
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
|
|
LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp;
|
|
HRESULT hrErr;
|
|
SCODE sc;
|
|
|
|
// OLE2NOTE: lpMedium is an IN parameter. we should NOT set
|
|
// lpMedium->pUnkForRelease to NULL
|
|
|
|
/* our user document does not support any formats for GetDataHere.
|
|
** if the document is used for
|
|
** purposes of data transfer, then additional formats are offered.
|
|
*/
|
|
if (! lpOutlineDoc->m_fDataTransferDoc) {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
if (lpformatetc->cfFormat == lpOleApp->m_cfEmbedSource) {
|
|
hrErr = OleStdGetOleObjectData(
|
|
(LPPERSISTSTORAGE)&lpServerDoc->m_PersistStorage,
|
|
lpformatetc,
|
|
lpMedium,
|
|
FALSE /* fUseMemory -- (use file-base stg) */
|
|
);
|
|
if (hrErr != NOERROR) {
|
|
sc = GetScode(hrErr);
|
|
goto error;
|
|
}
|
|
OleDbgOut3("ServerDoc_GetDataHere: rendered CF_EMBEDSOURCE\r\n");
|
|
return NOERROR;
|
|
|
|
} else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) {
|
|
if (lpOleDoc->m_fLinkSourceAvail) {
|
|
LPMONIKER lpmk;
|
|
|
|
lpmk = ServerDoc_GetSelFullMoniker(
|
|
(LPSERVERDOC)lpOleDoc->m_lpSrcDocOfCopy,
|
|
&lpServerDoc->m_lrSrcSelOfCopy,
|
|
GETMONIKER_FORCEASSIGN
|
|
);
|
|
if (lpmk) {
|
|
hrErr = OleStdGetLinkSourceData(
|
|
lpmk,
|
|
(LPCLSID)&CLSID_APP,
|
|
lpformatetc,
|
|
lpMedium
|
|
);
|
|
OleStdRelease((LPUNKNOWN)lpmk);
|
|
if (hrErr != NOERROR) {
|
|
sc = GetScode(hrErr);
|
|
goto error;
|
|
}
|
|
|
|
OleDbgOut3("ServerDoc_GetDataHere: rendered CF_LINKSOURCE\r\n");
|
|
return NOERROR;
|
|
|
|
} else {
|
|
sc = E_FAIL;
|
|
goto error;
|
|
}
|
|
} else {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
} else {
|
|
|
|
/* 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.
|
|
*/
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
return NOERROR;
|
|
|
|
error:
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
/* ServerDoc_QueryGetData
|
|
* ----------------------
|
|
*
|
|
* Answer if a particular data format is supported via GetData/GetDataHere.
|
|
* This routine is called via IDataObject::QueryGetData.
|
|
*/
|
|
|
|
HRESULT ServerDoc_QueryGetData (LPSERVERDOC lpServerDoc,LPFORMATETC lpformatetc)
|
|
{
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
|
|
LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp;
|
|
|
|
/* Caller is querying if we support certain format but does not
|
|
** want any data actually returned.
|
|
*/
|
|
if (lpformatetc->cfFormat == lpOutlineApp->m_cfOutline ||
|
|
lpformatetc->cfFormat == CF_TEXT) {
|
|
// we only support HGLOBAL
|
|
return OleStdQueryFormatMedium(lpformatetc, TYMED_HGLOBAL);
|
|
} else if (lpformatetc->cfFormat == CF_METAFILEPICT &&
|
|
(lpformatetc->dwAspect &
|
|
(DVASPECT_CONTENT | DVASPECT_ICON)) ) {
|
|
return OleStdQueryFormatMedium(lpformatetc, TYMED_MFPICT);
|
|
}
|
|
|
|
/* the above are the only formats supports by a user document (ie.
|
|
** a non-data transfer doc). if the document is used for
|
|
** purposes of data transfer, then additional formats are offered.
|
|
*/
|
|
if (! lpOutlineDoc->m_fDataTransferDoc)
|
|
return ResultFromScode(DV_E_FORMATETC);
|
|
|
|
if (lpformatetc->cfFormat == lpOleApp->m_cfEmbedSource) {
|
|
return OleStdQueryOleObjectData(lpformatetc);
|
|
|
|
} else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource &&
|
|
lpOleDoc->m_fLinkSourceAvail) {
|
|
return OleStdQueryLinkSourceData(lpformatetc);
|
|
|
|
} else if (lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor) {
|
|
return OleStdQueryObjectDescriptorData(lpformatetc);
|
|
|
|
} else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor &&
|
|
lpOleDoc->m_fLinkSourceAvail) {
|
|
return OleStdQueryObjectDescriptorData(lpformatetc);
|
|
}
|
|
|
|
return ResultFromScode(DV_E_FORMATETC);
|
|
}
|
|
|
|
|
|
/* ServerDoc_EnumFormatEtc
|
|
* -----------------------
|
|
*
|
|
* Return an enumerator which enumerates the data accepted/offered by
|
|
* the document.
|
|
* This routine is called via IDataObject::EnumFormatEtc.
|
|
*/
|
|
HRESULT ServerDoc_EnumFormatEtc(
|
|
LPSERVERDOC lpServerDoc,
|
|
DWORD dwDirection,
|
|
LPENUMFORMATETC FAR* lplpenumFormatEtc
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
|
int nActualFmts;
|
|
SCODE sc = S_OK;
|
|
|
|
/* OLE2NOTE: the enumeration of formats for a data transfer
|
|
** document is not a static list. the list of formats offered
|
|
** may or may not include CF_LINKSOURCE depending on whether a
|
|
** moniker is available for our document. thus we can NOT use
|
|
** the default OLE enumerator which enumerates the formats that
|
|
** are registered for our app in the registration database.
|
|
*/
|
|
if (dwDirection == DATADIR_GET) {
|
|
nActualFmts = lpOleApp->m_nDocGetFmts;
|
|
|
|
/* If the document does not have a Moniker, then exclude
|
|
** CF_LINKSOURCE and CF_LINKSRCDESCRIPTOR from the list of
|
|
** formats available. these formats are deliberately listed
|
|
** last in the array of possible "Get" formats.
|
|
*/
|
|
if (! lpOleDoc->m_fLinkSourceAvail)
|
|
nActualFmts -= 2;
|
|
|
|
*lplpenumFormatEtc = OleStdEnumFmtEtc_Create(
|
|
nActualFmts, lpOleApp->m_arrDocGetFmts);
|
|
if (*lplpenumFormatEtc == NULL)
|
|
sc = E_OUTOFMEMORY;
|
|
|
|
} else if (dwDirection == DATADIR_SET) {
|
|
/* OLE2NOTE: a document that is used to transfer data
|
|
** (either via the clipboard or drag/drop does NOT
|
|
** accept SetData on ANY format!
|
|
*/
|
|
sc = E_NOTIMPL;
|
|
goto error;
|
|
} else {
|
|
sc = E_INVALIDARG;
|
|
goto error;
|
|
}
|
|
|
|
error:
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
/* ServerDoc_GetMetafilePictData
|
|
* -----------------------------
|
|
*
|
|
* Return a handle to an object's picture data in metafile format.
|
|
*
|
|
*
|
|
* RETURNS: A handle to the object's data in metafile format.
|
|
*
|
|
*/
|
|
HGLOBAL ServerDoc_GetMetafilePictData(
|
|
LPSERVERDOC lpServerDoc,
|
|
LPLINERANGE lplrSel
|
|
)
|
|
{
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
|
LPOUTLINEDOC lpOutlineDoc=(LPOUTLINEDOC)lpServerDoc;
|
|
LPLINELIST lpLL=(LPLINELIST)&lpOutlineDoc->m_LineList;
|
|
LPLINE lpLine;
|
|
LPMETAFILEPICT lppict = NULL;
|
|
HGLOBAL hMFPict = NULL;
|
|
HMETAFILE hMF = NULL;
|
|
RECT rect;
|
|
RECT rectWBounds;
|
|
HDC hDC;
|
|
int i;
|
|
int nWidth;
|
|
int nStart = (lplrSel ? lplrSel->m_nStartLine : 0);
|
|
int nEnd =(lplrSel ? lplrSel->m_nEndLine : LineList_GetCount(lpLL)-1);
|
|
int nLines = nEnd - nStart + 1;
|
|
UINT fuAlign;
|
|
POINT point;
|
|
SIZE size;
|
|
|
|
hDC = CreateMetaFile(NULL);
|
|
|
|
rect.left = 0;
|
|
rect.right = 0;
|
|
rect.bottom = 0;
|
|
|
|
if (nLines > 0) {
|
|
// calculate the total height/width of LineList in HIMETRIC
|
|
for(i = nStart; i <= nEnd; i++) {
|
|
lpLine = LineList_GetLine(lpLL,i);
|
|
if (! lpLine)
|
|
continue;
|
|
|
|
nWidth = Line_GetTotalWidthInHimetric(lpLine);
|
|
rect.right = max(rect.right, nWidth);
|
|
rect.bottom -= Line_GetHeightInHimetric(lpLine);
|
|
}
|
|
|
|
|
|
SetMapMode(hDC, MM_ANISOTROPIC);
|
|
|
|
SetWindowOrgEx(hDC, 0, 0, &point);
|
|
SetWindowExtEx(hDC, rect.right, rect.bottom, &size);
|
|
rectWBounds = rect;
|
|
|
|
// Set the default font size, and font face name
|
|
SelectObject(hDC, OutlineApp_GetActiveFont(lpOutlineApp));
|
|
|
|
FillRect(hDC, (LPRECT) &rect, GetStockObject(WHITE_BRUSH));
|
|
|
|
rect.bottom = 0;
|
|
|
|
fuAlign = SetTextAlign(hDC, TA_LEFT | TA_TOP | TA_NOUPDATECP);
|
|
|
|
/* While more lines print out the text */
|
|
for(i = nStart; i <= nEnd; i++) {
|
|
lpLine = LineList_GetLine(lpLL,i);
|
|
if (! lpLine)
|
|
continue;
|
|
|
|
rect.top = rect.bottom;
|
|
rect.bottom -= Line_GetHeightInHimetric(lpLine);
|
|
|
|
/* Draw the line */
|
|
Line_Draw(lpLine, hDC, &rect, &rectWBounds, FALSE /*fHighlight*/);
|
|
}
|
|
|
|
SetTextAlign(hDC, fuAlign);
|
|
}
|
|
|
|
// Get handle to the metafile.
|
|
if (!(hMF = CloseMetaFile (hDC)))
|
|
return NULL;
|
|
|
|
if (!(hMFPict = GlobalAlloc (GMEM_SHARE | GMEM_ZEROINIT,
|
|
sizeof (METAFILEPICT)))) {
|
|
DeleteMetaFile (hMF);
|
|
return NULL;
|
|
}
|
|
|
|
if (!(lppict = (LPMETAFILEPICT)GlobalLock(hMFPict))) {
|
|
DeleteMetaFile (hMF);
|
|
GlobalFree (hMFPict);
|
|
return NULL;
|
|
}
|
|
|
|
lppict->mm = MM_ANISOTROPIC;
|
|
lppict->hMF = hMF;
|
|
lppict->xExt = rect.right;
|
|
lppict->yExt = - rect.bottom; // add minus sign to make it +ve
|
|
GlobalUnlock (hMFPict);
|
|
|
|
return hMFPict;
|
|
}
|
|
|
|
#endif // OLE_SERVER
|
|
|
|
|
|
|
|
#if defined( OLE_CNTR )
|
|
|
|
/*************************************************************************
|
|
** ContainerDoc Supprt Functions Used by Container versions
|
|
*************************************************************************/
|
|
|
|
|
|
/* Paste OLE Link from clipboard */
|
|
void ContainerDoc_PasteLinkCommand(LPCONTAINERDOC lpContainerDoc)
|
|
{
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
|
LPDATAOBJECT lpClipboardDataObj = NULL;
|
|
BOOL fLink = TRUE;
|
|
BOOL fLocalDataObj = FALSE;
|
|
BOOL fDisplayAsIcon = FALSE;
|
|
SIZEL sizelInSrc;
|
|
HCURSOR hPrevCursor;
|
|
HGLOBAL hMem = NULL;
|
|
HGLOBAL hMetaPict = NULL;
|
|
STGMEDIUM medium;
|
|
BOOL fStatus;
|
|
HRESULT hrErr;
|
|
|
|
hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj);
|
|
if (hrErr != NOERROR)
|
|
return; // Clipboard seems to be empty or can't be accessed
|
|
|
|
// this may take a while, put up hourglass cursor
|
|
hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
/* check if the data on the clipboard is local to our application
|
|
** instance.
|
|
*/
|
|
if (lpOutlineApp->m_lpClipboardDoc) {
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;
|
|
if (lpClipboardDataObj == (LPDATAOBJECT)&lpOleDoc->m_DataObject)
|
|
fLocalDataObj = TRUE;
|
|
}
|
|
|
|
/* OLE2NOTE: we need to check what dwDrawAspect is being
|
|
** transfered. if the data is an object that is displayed as an
|
|
** icon in the source, then we want to keep it as an icon. the
|
|
** aspect the object is displayed in at the source is transfered
|
|
** via the CF_LINKSOURCEDESCRIPTOR format for a PasteLink
|
|
** operation.
|
|
*/
|
|
if (hMem = OleStdGetData(
|
|
lpClipboardDataObj,
|
|
lpOleApp->m_cfLinkSrcDescriptor,
|
|
NULL,
|
|
DVASPECT_CONTENT,
|
|
(LPSTGMEDIUM)&medium)) {
|
|
LPOBJECTDESCRIPTOR lpOD = GlobalLock(hMem);
|
|
fDisplayAsIcon = (lpOD->dwDrawAspect == DVASPECT_ICON ? TRUE : FALSE);
|
|
sizelInSrc = lpOD->sizel; // size of object/picture in source (opt.)
|
|
GlobalUnlock(hMem);
|
|
ReleaseStgMedium((LPSTGMEDIUM)&medium); // equiv to GlobalFree
|
|
|
|
if (fDisplayAsIcon) {
|
|
hMetaPict = OleStdGetData(
|
|
lpClipboardDataObj,
|
|
CF_METAFILEPICT,
|
|
NULL,
|
|
DVASPECT_ICON,
|
|
(LPSTGMEDIUM)&medium
|
|
);
|
|
if (hMetaPict == NULL)
|
|
fDisplayAsIcon = FALSE; // give up; failed to get icon MFP
|
|
}
|
|
}
|
|
|
|
fStatus = ContainerDoc_PasteFormatFromData(
|
|
lpContainerDoc,
|
|
lpOleApp->m_cfLinkSource,
|
|
lpClipboardDataObj,
|
|
fLocalDataObj,
|
|
fLink,
|
|
fDisplayAsIcon,
|
|
hMetaPict,
|
|
(LPSIZEL)&sizelInSrc
|
|
);
|
|
|
|
if (!fStatus)
|
|
OutlineApp_ErrorMessage(g_lpApp, ErrMsgPasting);
|
|
|
|
if (hMetaPict)
|
|
ReleaseStgMedium((LPSTGMEDIUM)&medium); // properly free METAFILEPICT
|
|
|
|
if (lpClipboardDataObj)
|
|
OleStdRelease((LPUNKNOWN)lpClipboardDataObj);
|
|
|
|
SetCursor(hPrevCursor); // restore original cursor
|
|
}
|
|
|
|
|
|
/* ContainerDoc_PasteFormatFromData
|
|
** --------------------------------
|
|
**
|
|
** Paste a particular data format from a IDataObject*. The
|
|
** IDataObject* may come from the clipboard (GetClipboard) or from a
|
|
** drag/drop operation.
|
|
**
|
|
** Returns TRUE if data was successfully pasted.
|
|
** FALSE if data could not be pasted.
|
|
*/
|
|
BOOL ContainerDoc_PasteFormatFromData(
|
|
LPCONTAINERDOC lpContainerDoc,
|
|
CLIPFORMAT cfFormat,
|
|
LPDATAOBJECT lpSrcDataObj,
|
|
BOOL fLocalDataObj,
|
|
BOOL fLink,
|
|
BOOL fDisplayAsIcon,
|
|
HGLOBAL hMetaPict,
|
|
LPSIZEL lpSizelInSrc
|
|
)
|
|
{
|
|
LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
|
LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
|
|
int nIndex;
|
|
int nCount = 0;
|
|
HGLOBAL hData;
|
|
STGMEDIUM medium;
|
|
FORMATETC formatetc;
|
|
HRESULT hrErr;
|
|
LINERANGE lrSel;
|
|
|
|
if (LineList_GetCount(lpLL) == 0)
|
|
nIndex = -1; // pasting to empty list
|
|
else
|
|
nIndex=LineList_GetFocusLineIndex(lpLL);
|
|
|
|
if (fLink) {
|
|
|
|
/* We should paste a Link to the data */
|
|
|
|
if (cfFormat != lpOleApp->m_cfLinkSource)
|
|
return FALSE; // we only support OLE object type links
|
|
|
|
nCount = ContainerDoc_PasteOleObject(
|
|
lpContainerDoc,
|
|
lpSrcDataObj,
|
|
OLECREATEFROMDATA_LINK,
|
|
cfFormat,
|
|
nIndex,
|
|
fDisplayAsIcon,
|
|
hMetaPict,
|
|
lpSizelInSrc
|
|
);
|
|
return (nCount > 0 ? TRUE : FALSE);
|
|
|
|
} else {
|
|
|
|
if (cfFormat == lpContainerApp->m_cfCntrOutl) {
|
|
if (fLocalDataObj) {
|
|
|
|
/* CASE I: IDataObject* is local to our app
|
|
**
|
|
** if the source of the data is local to our
|
|
** application instance, then we can get direct
|
|
** access to the original OleDoc object that
|
|
** corresponds to the IDataObject* given.
|
|
** CF_CNTROUTL data is passed through a LPSTORAGE.
|
|
** if we call OleGetData asking for CF_CNTROUTL, we
|
|
** will be returned a copy of the existing open pStg
|
|
** of the original source document. we can NOT open
|
|
** streams and sub-storages again via this pStg
|
|
** since it is already open within our same
|
|
** application instance. we must copy the data from
|
|
** the original OleDoc source document.
|
|
*/
|
|
LPLINELIST lpSrcLL;
|
|
LPOLEDOC lpLocalSrcDoc =
|
|
((struct CDocDataObjectImpl FAR*)lpSrcDataObj)->lpOleDoc;
|
|
|
|
/* copy all lines from SrcDoc to DestDoc. */
|
|
lpSrcLL = &((LPOUTLINEDOC)lpLocalSrcDoc)->m_LineList;
|
|
nCount = LineList_CopySelToDoc(
|
|
lpSrcLL,
|
|
NULL,
|
|
(LPOUTLINEDOC)lpContainerDoc
|
|
);
|
|
|
|
} else {
|
|
|
|
/* CASE II: IDataObject* is NOT local to our app
|
|
**
|
|
** if the source of the data comes from another
|
|
** application instance. we can call GetDataHere to
|
|
** retrieve the CF_CNTROUTL data. CF_CNTROUTL data
|
|
** is passed through a LPSTORAGE. we MUST use
|
|
** IDataObject::GetDataHere. calling
|
|
** IDataObject::GetData does NOT work because OLE
|
|
** currently does NOT support remoting of a callee
|
|
** allocated root storage back to the caller. this
|
|
** hopefully will be supported in a future version.
|
|
** in order to call GetDataHere we must allocate an
|
|
** IStorage instance for the callee to write into.
|
|
** we will allocate an IStorage docfile that will
|
|
** delete-on-release. we could use either a
|
|
** memory-based storage or a file-based storage.
|
|
*/
|
|
LPSTORAGE lpTmpStg = OleStdCreateTempStorage(
|
|
FALSE /*fUseMemory*/,
|
|
STGM_READWRITE | STGM_TRANSACTED |STGM_SHARE_EXCLUSIVE
|
|
);
|
|
if (! lpTmpStg)
|
|
return FALSE;
|
|
|
|
formatetc.cfFormat = cfFormat;
|
|
formatetc.ptd = NULL;
|
|
formatetc.dwAspect = DVASPECT_CONTENT;
|
|
formatetc.tymed = TYMED_ISTORAGE;
|
|
formatetc.lindex = -1;
|
|
|
|
medium.tymed = TYMED_ISTORAGE;
|
|
medium.pstg = lpTmpStg;
|
|
medium.pUnkForRelease = NULL;
|
|
|
|
OLEDBG_BEGIN2("IDataObject::GetDataHere called\r\n")
|
|
hrErr = lpSrcDataObj->lpVtbl->GetDataHere(
|
|
lpSrcDataObj,
|
|
(LPFORMATETC)&formatetc,
|
|
(LPSTGMEDIUM)&medium
|
|
);
|
|
OLEDBG_END2
|
|
|
|
if (hrErr == NOERROR) {
|
|
nCount = ContainerDoc_PasteCntrOutlData(
|
|
lpContainerDoc,
|
|
lpTmpStg,
|
|
nIndex
|
|
);
|
|
}
|
|
OleStdVerifyRelease(
|
|
(LPUNKNOWN)lpTmpStg, "Temp stg NOT released!\r\n");
|
|
return ((hrErr == NOERROR) ? TRUE : FALSE);
|
|
}
|
|
|
|
} else if (cfFormat == lpOutlineApp->m_cfOutline) {
|
|
|
|
hData = OleStdGetData(
|
|
lpSrcDataObj,
|
|
lpOutlineApp->m_cfOutline,
|
|
NULL,
|
|
DVASPECT_CONTENT,
|
|
(LPSTGMEDIUM)&medium
|
|
);
|
|
nCount = OutlineDoc_PasteOutlineData(
|
|
(LPOUTLINEDOC)lpContainerDoc,
|
|
hData,
|
|
nIndex
|
|
);
|
|
// OLE2NOTE: we must free data handle by releasing the medium
|
|
ReleaseStgMedium((LPSTGMEDIUM)&medium);
|
|
|
|
} else if (cfFormat == lpOleApp->m_cfEmbedSource ||
|
|
cfFormat == lpOleApp->m_cfEmbeddedObject ||
|
|
cfFormat == lpOleApp->m_cfFileName) {
|
|
/* OLE2NOTE: OleCreateFromData API creates an OLE object if
|
|
** CF_EMBEDDEDOBJECT, CF_EMBEDSOURCE, or CF_FILENAME are
|
|
** available from the source data object. the
|
|
** CF_FILENAME case arises when a file is copied to the
|
|
** clipboard from the FileManager. if the file has an
|
|
** associated class (see GetClassFile API), then an
|
|
** object of that class is created. otherwise an OLE 1.0
|
|
** Packaged object is created.
|
|
*/
|
|
nCount = ContainerDoc_PasteOleObject(
|
|
lpContainerDoc,
|
|
lpSrcDataObj,
|
|
OLECREATEFROMDATA_OBJECT,
|
|
0, /* N/A -- cfFormat */
|
|
nIndex,
|
|
fDisplayAsIcon,
|
|
hMetaPict,
|
|
lpSizelInSrc
|
|
);
|
|
return (nCount > 0 ? TRUE : FALSE);
|
|
|
|
} else if (cfFormat == CF_METAFILEPICT
|
|
|| cfFormat == CF_DIB
|
|
|| cfFormat == CF_BITMAP) {
|
|
|
|
/* OLE2NOTE: OleCreateStaticFromData API creates an static
|
|
** OLE object if CF_METAFILEPICT, CF_DIB, or CF_BITMAP is
|
|
** CF_EMBEDDEDOBJECT, CF_EMBEDSOURCE, or CF_FILENAME are
|
|
** available from the source data object.
|
|
*/
|
|
nCount = ContainerDoc_PasteOleObject(
|
|
lpContainerDoc,
|
|
lpSrcDataObj,
|
|
OLECREATEFROMDATA_STATIC,
|
|
cfFormat,
|
|
nIndex,
|
|
fDisplayAsIcon,
|
|
hMetaPict,
|
|
lpSizelInSrc
|
|
);
|
|
return (nCount > 0 ? TRUE : FALSE);
|
|
|
|
} else if(cfFormat == CF_TEXT) {
|
|
|
|
hData = OleStdGetData(
|
|
lpSrcDataObj,
|
|
CF_TEXT,
|
|
NULL,
|
|
DVASPECT_CONTENT,
|
|
(LPSTGMEDIUM)&medium
|
|
);
|
|
nCount = OutlineDoc_PasteTextData(
|
|
(LPOUTLINEDOC)lpContainerDoc,
|
|
hData,
|
|
nIndex
|
|
);
|
|
// OLE2NOTE: we must free data handle by releasing the medium
|
|
ReleaseStgMedium((LPSTGMEDIUM)&medium);
|
|
|
|
} else {
|
|
return FALSE; // no acceptable format available to paste
|
|
}
|
|
}
|
|
|
|
lrSel.m_nStartLine = nIndex + nCount;
|
|
lrSel.m_nEndLine = nIndex + 1;
|
|
LineList_SetSel(lpLL, &lrSel);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* ContainerDoc_PasteCntrOutlData
|
|
* -------------------------------
|
|
*
|
|
* Load the lines stored in a lpSrcStg (stored in CF_CNTROUTL format)
|
|
* into the document.
|
|
*
|
|
* Return the number of items added
|
|
*/
|
|
int ContainerDoc_PasteCntrOutlData(
|
|
LPCONTAINERDOC lpDestContainerDoc,
|
|
LPSTORAGE lpSrcStg,
|
|
int nStartIndex
|
|
)
|
|
{
|
|
int nCount;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
|
LPOUTLINEDOC lpDestOutlineDoc = (LPOUTLINEDOC)lpDestContainerDoc;
|
|
LPOUTLINEDOC lpSrcOutlineDoc;
|
|
LPLINELIST lpSrcLL;
|
|
|
|
// create a temp document that will be used to load the lpSrcStg data.
|
|
lpSrcOutlineDoc = (LPOUTLINEDOC)OutlineApp_CreateDoc(lpOutlineApp, FALSE);
|
|
if ( ! lpSrcOutlineDoc )
|
|
return 0;
|
|
|
|
if (! OutlineDoc_LoadFromStg(lpSrcOutlineDoc, lpSrcStg))
|
|
goto error;
|
|
|
|
/* copy all lines from the SrcDoc to the DestDoc. */
|
|
lpSrcLL = &lpSrcOutlineDoc->m_LineList;
|
|
nCount = LineList_CopySelToDoc(lpSrcLL, NULL, lpDestOutlineDoc);
|
|
|
|
if (lpSrcOutlineDoc) // destroy temporary document.
|
|
OutlineDoc_Close(lpSrcOutlineDoc, OLECLOSE_NOSAVE);
|
|
|
|
return nCount;
|
|
|
|
error:
|
|
if (lpSrcOutlineDoc) // destroy temporary document.
|
|
OutlineDoc_Close(lpSrcOutlineDoc, OLECLOSE_NOSAVE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* ContainerDoc_QueryPasteFromData
|
|
** -------------------------------
|
|
**
|
|
** Check if the IDataObject* offers data in a format that we can
|
|
** paste. The IDataObject* may come from the clipboard
|
|
** (GetClipboard) or from a drag/drop operation.
|
|
** In this function we look if one of the following formats is
|
|
** offered:
|
|
** CF_OUTLINE
|
|
** <OLE object -- CF_EMBEDSOURCE or CF_EMBEDDEDOBJECT>
|
|
** CF_TEXT
|
|
**
|
|
** NOTE: fLink is specified and CF_LINKSOURCE is available then TRUE
|
|
** is returned, else FALSE.
|
|
**
|
|
** Returns TRUE if paste can be performed
|
|
** FALSE if paste is not possible.
|
|
*/
|
|
BOOL ContainerDoc_QueryPasteFromData(
|
|
LPCONTAINERDOC lpContainerDoc,
|
|
LPDATAOBJECT lpSrcDataObj,
|
|
BOOL fLink
|
|
)
|
|
{
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
|
|
|
if (fLink) {
|
|
/* check if we can paste a Link to the data */
|
|
if (OleQueryLinkFromData(lpSrcDataObj) != NOERROR)
|
|
return FALSE; // linking is NOT possible
|
|
} else {
|
|
|
|
int nFmtEtc;
|
|
|
|
nFmtEtc = OleStdGetPriorityClipboardFormat(
|
|
lpSrcDataObj,
|
|
lpOleApp->m_arrPasteEntries,
|
|
lpOleApp->m_nPasteEntries
|
|
);
|
|
|
|
if (nFmtEtc < 0)
|
|
return FALSE; // there is no format we like
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* ContainerDoc_PasteOleObject
|
|
** ---------------------------
|
|
**
|
|
** Embed or link an OLE object. the source of the data is a pointer
|
|
** to an IDataObject. normally this lpSrcDataObj comes from the
|
|
** clipboard after call OleGetClipboard.
|
|
**
|
|
** dwCreateType controls what type of object will created:
|
|
** OLECREATEFROMDATA_LINK -- OleCreateLinkFromData will be called
|
|
** OLECREATEFROMDATA_OBJECT -- OleCreateFromData will be called
|
|
** OLECREATEFROMDATA_STATIC -- OleCreateStaticFromData will be called
|
|
** cfFormat controls the type of static
|
|
** a CONTAINERLINE object is created to manage the OLE object. this
|
|
** CONTAINERLINE is added to the ContainerDoc after line nIndex.
|
|
**
|
|
*/
|
|
int ContainerDoc_PasteOleObject(
|
|
LPCONTAINERDOC lpContainerDoc,
|
|
LPDATAOBJECT lpSrcDataObj,
|
|
DWORD dwCreateType,
|
|
CLIPFORMAT cfFormat,
|
|
int nIndex,
|
|
BOOL fDisplayAsIcon,
|
|
HGLOBAL hMetaPict,
|
|
LPSIZEL lpSizelInSrc
|
|
)
|
|
{
|
|
LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
|
|
LPLINE lpLine = NULL;
|
|
HDC hDC;
|
|
int nTab = 0;
|
|
char szStgName[CWCSTORAGENAME];
|
|
LPCONTAINERLINE lpContainerLine = NULL;
|
|
|
|
ContainerDoc_GetNextStgName(lpContainerDoc, szStgName, sizeof(szStgName));
|
|
|
|
/* default the new line to have the same indent as previous line */
|
|
lpLine = LineList_GetLine(lpLL, nIndex);
|
|
if (lpLine)
|
|
nTab = Line_GetTabLevel(lpLine);
|
|
|
|
hDC = LineList_GetDC(lpLL);
|
|
|
|
lpContainerLine = ContainerLine_CreateFromData(
|
|
hDC,
|
|
nTab,
|
|
lpContainerDoc,
|
|
lpSrcDataObj,
|
|
dwCreateType,
|
|
cfFormat,
|
|
fDisplayAsIcon,
|
|
hMetaPict,
|
|
szStgName
|
|
);
|
|
LineList_ReleaseDC(lpLL, hDC);
|
|
|
|
if (! lpContainerLine)
|
|
goto error;
|
|
|
|
/* add a ContainerLine object to the document's LineList. The
|
|
** ContainerLine manages the rectangle on the screen occupied by
|
|
** the OLE object. later when the app is updated to support
|
|
** extended layout, there could be more than one Line associated
|
|
** with the OLE object.
|
|
*/
|
|
|
|
LineList_AddLine(lpLL, (LPLINE)lpContainerLine, nIndex);
|
|
|
|
/* OLE2NOTE: if the source of the OLE object just pasted, passed a
|
|
** non-zero sizel in the ObjectDescriptor, then we will try to
|
|
** keep the object the same size as it is in the source. this
|
|
** may be a scaled size if the object had been resized in the
|
|
** source container. if the source did not give a valid sizel,
|
|
** then we will retrieve the size of the object by calling
|
|
** IViewObject2::GetExtent.
|
|
*/
|
|
if (lpSizelInSrc && (lpSizelInSrc->cx != 0 || lpSizelInSrc->cy != 0)) {
|
|
ContainerLine_UpdateExtent(lpContainerLine, lpSizelInSrc);
|
|
} else
|
|
ContainerLine_UpdateExtent(lpContainerLine, NULL);
|
|
|
|
OutlineDoc_SetModified((LPOUTLINEDOC)lpContainerDoc, TRUE, TRUE, TRUE);
|
|
|
|
return 1; // one line added to LineList
|
|
|
|
error:
|
|
// NOTE: if ContainerLine_CreateFromClip failed
|
|
OutlineApp_ErrorMessage(g_lpApp, "Paste Object failed!");
|
|
return 0; // no lines added to line list
|
|
}
|
|
|
|
|
|
/* ContainerDoc_GetData
|
|
* --------------------
|
|
*
|
|
* Render data from the document on a CALLEE allocated STGMEDIUM.
|
|
* This routine is called via IDataObject::GetData.
|
|
*/
|
|
HRESULT ContainerDoc_GetData (
|
|
LPCONTAINERDOC lpContainerDoc,
|
|
LPFORMATETC lpformatetc,
|
|
LPSTGMEDIUM lpMedium
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
|
|
LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)lpContainerApp;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpContainerApp;
|
|
HRESULT hrErr;
|
|
SCODE sc;
|
|
|
|
// OLE2NOTE: we must set out pointer parameters to NULL
|
|
lpMedium->pUnkForRelease = NULL;
|
|
|
|
/* OLE2NOTE: we must set all out pointer parameters to NULL. */
|
|
lpMedium->tymed = TYMED_NULL;
|
|
lpMedium->pUnkForRelease = NULL; // we transfer ownership to caller
|
|
lpMedium->hGlobal = NULL;
|
|
|
|
if (lpformatetc->cfFormat == lpContainerApp->m_cfCntrOutl) {
|
|
|
|
/* OLE2NOTE: currently OLE does NOT support remoting a root
|
|
** level IStorage (either memory or file based) as an OUT
|
|
** parameter. thus, we can NOT support GetData for this
|
|
** TYMED_ISTORAGE based format. the caller MUST call GetDataHere.
|
|
*/
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
|
|
} else if (!lpContainerDoc->m_fEmbeddedObjectAvail &&
|
|
lpformatetc->cfFormat == lpOutlineApp->m_cfOutline) {
|
|
// Verify caller asked for correct medium
|
|
if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->hGlobal = OutlineDoc_GetOutlineData(lpOutlineDoc, NULL);
|
|
if (! lpMedium->hGlobal) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->tymed = TYMED_HGLOBAL;
|
|
OleDbgOut3("ContainerDoc_GetData: rendered CF_OUTLINE\r\n");
|
|
return NOERROR;
|
|
|
|
} else if (!lpContainerDoc->m_fEmbeddedObjectAvail &&
|
|
lpformatetc->cfFormat == CF_TEXT) {
|
|
// Verify caller asked for correct medium
|
|
if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->hGlobal = OutlineDoc_GetTextData (
|
|
(LPOUTLINEDOC)lpContainerDoc,
|
|
NULL
|
|
);
|
|
if (! lpMedium->hGlobal) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->tymed = TYMED_HGLOBAL;
|
|
OleDbgOut3("ContainerDoc_GetData: rendered CF_TEXT\r\n");
|
|
return NOERROR;
|
|
|
|
} else if ( lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor ||
|
|
(lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor &&
|
|
lpOleDoc->m_fLinkSourceAvail) ) {
|
|
// Verify caller asked for correct medium
|
|
if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->hGlobal = OleDoc_GetObjectDescriptorData (
|
|
(LPOLEDOC)lpContainerDoc,
|
|
NULL
|
|
);
|
|
if (! lpMedium->hGlobal) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->tymed = TYMED_HGLOBAL;
|
|
#if defined( _DEBUG )
|
|
if (lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor)
|
|
OleDbgOut3(
|
|
"ContainerDoc_GetData: rendered CF_OBJECTDESCRIPTOR\r\n");
|
|
else
|
|
OleDbgOut3(
|
|
"ContainerDoc_GetData: rendered CF_LINKSRCDESCRIPTOR\r\n");
|
|
#endif
|
|
return NOERROR;
|
|
|
|
} else if (lpContainerDoc->m_fEmbeddedObjectAvail) {
|
|
|
|
/* OLE2NOTE: if this document contains a single OLE object
|
|
** (ie. cfEmbeddedObject data format is available), then
|
|
** the formats offered via our IDataObject must include
|
|
** the formats available from the OLE object itself.
|
|
** thus, we delegate this call to the IDataObject* of the
|
|
** OLE object.
|
|
*/
|
|
|
|
if (lpformatetc->cfFormat == lpOleApp->m_cfEmbeddedObject) {
|
|
LPPERSISTSTORAGE lpPersistStg =
|
|
(LPPERSISTSTORAGE)ContainerDoc_GetSingleOleObject(
|
|
lpContainerDoc,
|
|
&IID_IPersistStorage,
|
|
NULL
|
|
);
|
|
|
|
if (! lpPersistStg)
|
|
return ResultFromScode(DV_E_FORMATETC);
|
|
|
|
/* render CF_EMBEDDEDOBJECT by asking the object to save
|
|
** into a temporary, DELETEONRELEASE pStg allocated by us.
|
|
*/
|
|
|
|
hrErr = OleStdGetOleObjectData(
|
|
lpPersistStg,
|
|
lpformatetc,
|
|
lpMedium,
|
|
FALSE /* fUseMemory -- (use file-base stg) */
|
|
);
|
|
OleStdRelease((LPUNKNOWN)lpPersistStg);
|
|
if (hrErr != NOERROR) {
|
|
sc = GetScode(hrErr);
|
|
goto error;
|
|
}
|
|
OleDbgOut3("ContainerDoc_GetData: rendered CF_EMBEDDEDOBJECT\r\n");
|
|
return hrErr;
|
|
|
|
} else if (lpformatetc->cfFormat == CF_METAFILEPICT) {
|
|
|
|
/* OLE2NOTE: as a container which draws objects, when a single
|
|
** OLE object is copied, we can give the Metafile picture of
|
|
** the object.
|
|
*/
|
|
LPCONTAINERLINE lpContainerLine;
|
|
LPOLEOBJECT lpOleObj;
|
|
SIZEL sizelOleObject;
|
|
|
|
// Verify caller asked for correct medium
|
|
if (!(lpformatetc->tymed & TYMED_MFPICT)) {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
lpOleObj = (LPOLEOBJECT)ContainerDoc_GetSingleOleObject(
|
|
lpContainerDoc,
|
|
&IID_IOleObject,
|
|
(LPCONTAINERLINE FAR*)&lpContainerLine
|
|
);
|
|
|
|
if (! lpOleObj) {
|
|
sc = E_OUTOFMEMORY; // could not load object
|
|
goto error;
|
|
}
|
|
if (lpformatetc->dwAspect & lpContainerLine->m_dwDrawAspect) {
|
|
LPLINE lpLine = (LPLINE)lpContainerLine;
|
|
|
|
/* render CF_METAFILEPICT by drawing the object into
|
|
** a metafile DC
|
|
*/
|
|
|
|
/* OLE2NOTE: Get size that object is being drawn. If the
|
|
** object has been scaled because the user resized the
|
|
** object, then we want to render a metafile with the
|
|
** scaled size.
|
|
*/
|
|
sizelOleObject.cx = lpLine->m_nWidthInHimetric;
|
|
sizelOleObject.cy = lpLine->m_nHeightInHimetric;
|
|
|
|
lpMedium->hGlobal = OleStdGetMetafilePictFromOleObject(
|
|
lpOleObj,
|
|
lpContainerLine->m_dwDrawAspect,
|
|
(LPSIZEL)&sizelOleObject,
|
|
lpformatetc->ptd
|
|
);
|
|
OleStdRelease((LPUNKNOWN)lpOleObj);
|
|
if (! lpMedium->hGlobal) {
|
|
sc = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
lpMedium->tymed = TYMED_MFPICT;
|
|
OleDbgOut3("ContainerDoc_GetData: rendered CF_METAFILEPICT\r\n");
|
|
return NOERROR;
|
|
} else {
|
|
// improper aspect requested
|
|
OleStdRelease((LPUNKNOWN)lpOleObj);
|
|
return ResultFromScode(DV_E_FORMATETC);
|
|
}
|
|
|
|
} else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) {
|
|
if (lpOleDoc->m_fLinkSourceAvail) {
|
|
LPMONIKER lpmk;
|
|
|
|
lpmk = ContainerLine_GetFullMoniker(
|
|
lpContainerDoc->m_lpSrcContainerLine,
|
|
GETMONIKER_FORCEASSIGN
|
|
);
|
|
if (lpmk) {
|
|
hrErr = OleStdGetLinkSourceData(
|
|
lpmk,
|
|
&lpContainerDoc->m_clsidOleObjCopied,
|
|
lpformatetc,
|
|
lpMedium
|
|
);
|
|
OleStdRelease((LPUNKNOWN)lpmk);
|
|
if (hrErr != NOERROR) {
|
|
sc = GetScode(hrErr);
|
|
goto error;
|
|
}
|
|
OleDbgOut3("ContainerDoc_GetData: rendered CF_LINKSOURCE\r\n");
|
|
return hrErr;
|
|
} else {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
} else {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
}
|
|
#if defined( OPTIONAL_ADVANCED_DATA_TRANSFER )
|
|
/* OLE2NOTE: optionally, a container that wants to have a
|
|
** potentially richer data transfer, can enumerate the data
|
|
** formats from the OLE object's cache and offer them too. if
|
|
** the object has a special handler, then it might be able to
|
|
** render additional data formats. in this case, the
|
|
** container must delegate the GetData call to the object if
|
|
** it does not directly support the format.
|
|
**
|
|
** CNTROUTL does NOT enumerate the cache; it implements the
|
|
** simpler strategy of offering a static list of formats.
|
|
** thus the delegation is NOT required.
|
|
*/
|
|
else {
|
|
|
|
/* OLE2NOTE: we delegate this call to the IDataObject* of the
|
|
** OLE object.
|
|
*/
|
|
LPDATAOBJECT lpDataObj;
|
|
|
|
lpDataObj = (LPDATAOBJECT)ContainerDoc_GetSingleOleObject(
|
|
lpContainerDoc,
|
|
&IID_IDataObject,
|
|
NULL
|
|
);
|
|
|
|
if (! lpDataObj) {
|
|
sc = DV_E_FORMATETC;
|
|
goto error;
|
|
}
|
|
|
|
OLEDBG_BEGIN2("ContainerDoc_GetData: delegate to OLE obj\r\n")
|
|
hrErr=lpDataObj->lpVtbl->GetData(lpDataObj,lpformatetc,lpMedium);
|
|
OLEDBG_END2
|
|
|
|
OleStdRelease((LPUNKNOWN)lpDataObj);
|
|
return hrErr;
|
|
}
|
|
#endif // ! OPTIONAL_ADVANCED_DATA_TRANSFER
|
|
|
|
}
|
|
|
|
// if we get here then we do NOT support the requested format
|
|
sc = DV_E_FORMATETC;
|
|
|
|
error:
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
/* ContainerDoc_GetDataHere
|
|
* ------------------------
|
|
*
|
|
* Render data from the document on a CALLER allocated STGMEDIUM.
|
|
* This routine is called via IDataObject::GetDataHere.
|
|
*/
|
|
HRESULT ContainerDoc_GetDataHere (
|
|
LPCONTAINERDOC lpContainerDoc,
|
|
LPFORMATETC lpformatetc,
|
|
LPSTGMEDIUM lpMedium
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
|
|
LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)lpContainerApp;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpContainerApp;
|
|
HRESULT hrErr;
|
|
|
|
// OLE2NOTE: lpMedium is an IN parameter. we should NOT set
|
|
// lpMedium->pUnkForRelease to NULL
|
|
|
|
// we only support IStorage medium
|
|
if (lpformatetc->cfFormat == lpContainerApp->m_cfCntrOutl) {
|
|
if (!(lpformatetc->tymed & TYMED_ISTORAGE))
|
|
return ResultFromScode(DV_E_FORMATETC);
|
|
|
|
if (lpMedium->tymed == TYMED_ISTORAGE) {
|
|
/* Caller has allocated the storage. we must copy all of our
|
|
** data into his storage.
|
|
*/
|
|
|
|
/* OLE2NOTE: we must be sure to write our class ID into our
|
|
** storage. this information is used by OLE to determine the
|
|
** class of the data stored in our storage.
|
|
*/
|
|
if((hrErr=WriteClassStg(lpMedium->pstg,&CLSID_APP)) != NOERROR)
|
|
return hrErr;
|
|
|
|
OutlineDoc_SaveSelToStg(
|
|
(LPOUTLINEDOC)lpContainerDoc,
|
|
NULL, /* entire doc */
|
|
lpContainerApp->m_cfCntrOutl,
|
|
lpMedium->pstg,
|
|
FALSE, /* fSameAsLoad */
|
|
FALSE /* fRemember */
|
|
);
|
|
OleStdCommitStorage(lpMedium->pstg);
|
|
|
|
OleDbgOut3("ContainerDoc_GetDataHere: rendered CF_CNTROUTL\r\n");
|
|
return NOERROR;
|
|
} else {
|
|
// we only support IStorage medium
|
|
return ResultFromScode(DV_E_FORMATETC);
|
|
}
|
|
|
|
} else if (lpContainerDoc->m_fEmbeddedObjectAvail) {
|
|
|
|
/* OLE2NOTE: if this document contains a single OLE object
|
|
** (ie. cfEmbeddedObject data format is available), then
|
|
** the formats offered via our IDataObject must include
|
|
** CF_EMBEDDEDOBJECT and the formats available from the OLE
|
|
** object itself.
|
|
*/
|
|
|
|
if (lpformatetc->cfFormat == lpOleApp->m_cfEmbeddedObject) {
|
|
LPPERSISTSTORAGE lpPersistStg =
|
|
(LPPERSISTSTORAGE)ContainerDoc_GetSingleOleObject(
|
|
lpContainerDoc,
|
|
&IID_IPersistStorage,
|
|
NULL
|
|
);
|
|
|
|
if (! lpPersistStg) {
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
/* render CF_EMBEDDEDOBJECT by asking the object to save
|
|
** into the IStorage allocated by the caller.
|
|
*/
|
|
|
|
hrErr = OleStdGetOleObjectData(
|
|
lpPersistStg,
|
|
lpformatetc,
|
|
lpMedium,
|
|
FALSE /* fUseMemory -- N/A */
|
|
);
|
|
OleStdRelease((LPUNKNOWN)lpPersistStg);
|
|
if (hrErr != NOERROR) {
|
|
return hrErr;
|
|
}
|
|
OleDbgOut3("ContainerDoc_GetDataHere: rendered CF_EMBEDDEDOBJECT\r\n");
|
|
return hrErr;
|
|
|
|
} else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) {
|
|
if (lpOleDoc->m_fLinkSourceAvail) {
|
|
LPMONIKER lpmk;
|
|
|
|
lpmk = ContainerLine_GetFullMoniker(
|
|
lpContainerDoc->m_lpSrcContainerLine,
|
|
GETMONIKER_FORCEASSIGN
|
|
);
|
|
if (lpmk) {
|
|
hrErr = OleStdGetLinkSourceData(
|
|
lpmk,
|
|
&lpContainerDoc->m_clsidOleObjCopied,
|
|
lpformatetc,
|
|
lpMedium
|
|
);
|
|
OleStdRelease((LPUNKNOWN)lpmk);
|
|
OleDbgOut3("ContainerDoc_GetDataHere: rendered CF_LINKSOURCE\r\n");
|
|
return hrErr;
|
|
} else {
|
|
return ResultFromScode(E_FAIL);
|
|
}
|
|
} else {
|
|
return ResultFromScode(DV_E_FORMATETC);
|
|
}
|
|
|
|
} else {
|
|
#if !defined( OPTIONAL_ADVANCED_DATA_TRANSFER )
|
|
return ResultFromScode(DV_E_FORMATETC);
|
|
#endif
|
|
#if defined( OPTIONAL_ADVANCED_DATA_TRANSFER )
|
|
/* OLE2NOTE: optionally, a container that wants to have a
|
|
** potentially richer data transfer, can enumerate the data
|
|
** formats from the OLE object's cache and offer them too. if
|
|
** the object has a special handler, then it might be able to
|
|
** render additional data formats. in this case, the
|
|
** container must delegate the GetData call to the object if
|
|
** it does not directly support the format.
|
|
**
|
|
** CNTROUTL does NOT enumerate the cache; it implements the
|
|
** simpler strategy of offering a static list of formats.
|
|
** thus the delegation is NOT required.
|
|
*/
|
|
/* OLE2NOTE: we delegate this call to the IDataObject* of the
|
|
** OLE object.
|
|
*/
|
|
LPDATAOBJECT lpDataObj;
|
|
|
|
lpDataObj = (LPDATAOBJECT)ContainerDoc_GetSingleOleObject(
|
|
lpContainerDoc,
|
|
&IID_IDataObject,
|
|
NULL
|
|
);
|
|
|
|
if (! lpDataObj)
|
|
return ResultFromScode(DV_E_FORMATETC);
|
|
|
|
OLEDBG_BEGIN2("ContainerDoc_GetDataHere: delegate to OLE obj\r\n")
|
|
hrErr = lpDataObj->lpVtbl->GetDataHere(
|
|
lpDataObj,
|
|
lpformatetc,
|
|
lpMedium
|
|
);
|
|
OLEDBG_END2
|
|
|
|
OleStdRelease((LPUNKNOWN)lpDataObj);
|
|
return hrErr;
|
|
#endif // OPTIONAL_ADVANCED_DATA_TRANSFER
|
|
}
|
|
} else {
|
|
return ResultFromScode(DV_E_FORMATETC);
|
|
}
|
|
}
|
|
|
|
|
|
/* ContainerDoc_QueryGetData
|
|
* -------------------------
|
|
*
|
|
* Answer if a particular data format is supported via GetData/GetDataHere.
|
|
* This routine is called via IDataObject::QueryGetData.
|
|
*/
|
|
HRESULT ContainerDoc_QueryGetData (
|
|
LPCONTAINERDOC lpContainerDoc,
|
|
LPFORMATETC lpformatetc
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
|
|
LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)lpContainerApp;
|
|
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpContainerApp;
|
|
LPDATAOBJECT lpDataObj = NULL;
|
|
LPCONTAINERLINE lpContainerLine = NULL;
|
|
SCODE sc;
|
|
HRESULT hrErr;
|
|
|
|
if (lpContainerDoc->m_fEmbeddedObjectAvail) {
|
|
lpDataObj = (LPDATAOBJECT)ContainerDoc_GetSingleOleObject(
|
|
lpContainerDoc,
|
|
&IID_IDataObject,
|
|
(LPCONTAINERLINE FAR*)&lpContainerLine
|
|
);
|
|
}
|
|
|
|
/* Caller is querying if we support certain format but does not
|
|
** want any data actually returned.
|
|
*/
|
|
if (lpformatetc->cfFormat == lpContainerApp->m_cfCntrOutl) {
|
|
// we only support ISTORAGE medium
|
|
sc = GetScode( OleStdQueryFormatMedium(lpformatetc, TYMED_ISTORAGE) );
|
|
|
|
} else if (lpformatetc->cfFormat == lpOleApp->m_cfEmbeddedObject &&
|
|
lpContainerDoc->m_fEmbeddedObjectAvail ) {
|
|
sc = GetScode( OleStdQueryOleObjectData(lpformatetc) );
|
|
|
|
} else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource &&
|
|
lpOleDoc->m_fLinkSourceAvail) {
|
|
sc = GetScode( OleStdQueryLinkSourceData(lpformatetc) );
|
|
|
|
// CF_TEXT and CF_OUTLINE are NOT supported when single object is copied
|
|
} else if (!lpContainerDoc->m_fEmbeddedObjectAvail &&
|
|
(lpformatetc->cfFormat == (lpOutlineApp)->m_cfOutline ||
|
|
lpformatetc->cfFormat == CF_TEXT) ) {
|
|
// we only support HGLOBAL medium
|
|
sc = GetScode( OleStdQueryFormatMedium(lpformatetc, TYMED_HGLOBAL) );
|
|
|
|
} else if ( lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor ||
|
|
(lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor &&
|
|
lpOleDoc->m_fLinkSourceAvail) ) {
|
|
sc = GetScode( OleStdQueryObjectDescriptorData(lpformatetc) );
|
|
|
|
} else if (lpformatetc->cfFormat == CF_METAFILEPICT &&
|
|
lpContainerDoc->m_fEmbeddedObjectAvail && lpContainerLine &&
|
|
(lpformatetc->dwAspect & lpContainerLine->m_dwDrawAspect)) {
|
|
|
|
/* OLE2NOTE: as a container which draws objects, when a single
|
|
** OLE object is copied, we can give the Metafile picture of
|
|
** the object.
|
|
*/
|
|
// we only support MFPICT medium
|
|
sc = GetScode( OleStdQueryFormatMedium(lpformatetc, TYMED_MFPICT) );
|
|
|
|
} else if (lpDataObj) {
|
|
|
|
/* OLE2NOTE: if this document contains a single OLE object
|
|
** (ie. cfEmbeddedObject data format is available), then
|
|
** the formats offered via our IDataObject must include
|
|
** the formats available from the OLE object itself.
|
|
** thus we delegate this call to the IDataObject* of the
|
|
** OLE object.
|
|
*/
|
|
OLEDBG_BEGIN2("ContainerDoc_QueryGetData: delegate to OLE obj\r\n")
|
|
hrErr = lpDataObj->lpVtbl->QueryGetData(lpDataObj, lpformatetc);
|
|
OLEDBG_END2
|
|
|
|
sc = GetScode(hrErr);
|
|
|
|
} else {
|
|
sc = DV_E_FORMATETC;
|
|
}
|
|
|
|
if (lpDataObj)
|
|
OleStdRelease((LPUNKNOWN)lpDataObj);
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
|
|
/* ContainerDoc_SetData
|
|
* --------------------
|
|
*
|
|
* Set (modify) data of the document.
|
|
* This routine is called via IDataObject::SetData.
|
|
*/
|
|
HRESULT ContainerDoc_SetData (
|
|
LPCONTAINERDOC lpContainerDoc,
|
|
LPFORMATETC lpformatetc,
|
|
LPSTGMEDIUM lpmedium,
|
|
BOOL fRelease
|
|
)
|
|
{
|
|
/* in the container version of Outline, only DataTransferDoc's support
|
|
** IDataObject interface; the user documents do not support
|
|
** IDataObject. DataTransferDoc's do not accept SetData calls.
|
|
*/
|
|
return ResultFromScode(DV_E_FORMATETC);
|
|
}
|
|
|
|
|
|
/* ContainerDoc_EnumFormatEtc
|
|
* --------------------------
|
|
*
|
|
* Return an enumerator which enumerates the data accepted/offered by
|
|
* the document.
|
|
* This routine is called via IDataObject::SetData.
|
|
*/
|
|
HRESULT ContainerDoc_EnumFormatEtc(
|
|
LPCONTAINERDOC lpContainerDoc,
|
|
DWORD dwDirection,
|
|
LPENUMFORMATETC FAR* lplpenumFormatEtc
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;
|
|
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
|
LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOleApp;
|
|
int nActualFmts;
|
|
int i;
|
|
SCODE sc = S_OK;
|
|
|
|
/* the Container-Only version of Outline does NOT offer
|
|
** IDataObject interface from its User documents.
|
|
*/
|
|
if (! lpOutlineDoc->m_fDataTransferDoc)
|
|
return ResultFromScode(E_FAIL);
|
|
|
|
if (dwDirection == DATADIR_GET) {
|
|
if (lpContainerDoc->m_fEmbeddedObjectAvail) {
|
|
|
|
/* OLE2NOTE: if this document contains a single OLE object
|
|
** (ie. cfEmbeddedObject data format is available), then
|
|
** the formats offered via our enumerator must include
|
|
** the formats available from the OLE object itself. we
|
|
** have previously set up a special array of FORMATETC's
|
|
** in OutlineDoc_CreateDataTransferDoc routine which includes
|
|
** the combination of data we offer directly and data
|
|
** offered by the OLE object.
|
|
*/
|
|
|
|
/* If the document does not have a Moniker, then exclude
|
|
** CF_LINKSOURCE CF_LINKSRCDESCRIPTOR from the list of
|
|
** formats available. these formats are deliberately
|
|
** listed last in the array of possible "Get" formats.
|
|
*/
|
|
nActualFmts = lpContainerApp->m_nSingleObjGetFmts;
|
|
if (! lpOleDoc->m_fLinkSourceAvail)
|
|
nActualFmts -= 2;
|
|
|
|
// set correct dwDrawAspect for METAFILEPICT of object copied
|
|
for (i = 0; i < nActualFmts; i++) {
|
|
if (lpContainerApp->m_arrSingleObjGetFmts[i].cfFormat ==
|
|
CF_METAFILEPICT) {
|
|
lpContainerApp->m_arrSingleObjGetFmts[i].dwAspect =
|
|
lpContainerDoc->m_dwAspectOleObjCopied;
|
|
break; // DONE
|
|
}
|
|
}
|
|
*lplpenumFormatEtc = OleStdEnumFmtEtc_Create(
|
|
nActualFmts, lpContainerApp->m_arrSingleObjGetFmts);
|
|
if (*lplpenumFormatEtc == NULL)
|
|
sc = E_OUTOFMEMORY;
|
|
|
|
} else {
|
|
|
|
/* This document does NOT offer cfEmbeddedObject,
|
|
** therefore we can simply enumerate the
|
|
** static list of formats that we handle directly.
|
|
*/
|
|
*lplpenumFormatEtc = OleStdEnumFmtEtc_Create(
|
|
lpOleApp->m_nDocGetFmts, lpOleApp->m_arrDocGetFmts);
|
|
if (*lplpenumFormatEtc == NULL)
|
|
sc = E_OUTOFMEMORY;
|
|
}
|
|
} else if (dwDirection == DATADIR_SET) {
|
|
/* OLE2NOTE: a document that is used to transfer data
|
|
** (either via the clipboard or drag/drop does NOT
|
|
** accept SetData on ANY format!
|
|
*/
|
|
sc = E_NOTIMPL;
|
|
|
|
} else {
|
|
sc = E_NOTIMPL;
|
|
}
|
|
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
#if defined( OPTIONAL_ADVANCED_DATA_TRANSFER )
|
|
/* OLE2NOTE: optionally, a container that wants to have a
|
|
** potentially richer data transfer, can enumerate the data
|
|
** formats from the OLE object's cache and offer them too. if
|
|
** the object has a special handler, then it might be able to
|
|
** render additional data formats.
|
|
**
|
|
** CNTROUTL does NOT enumerate the cache; it implements the simpler
|
|
** strategy of offering a static list of formats. the following
|
|
** function is included in order to illustrates how enumerating the
|
|
** cache could be done. CNTROUTL does NOT call this function.
|
|
**
|
|
*/
|
|
|
|
/* ContainerDoc_SetupDocGetFmts
|
|
** ----------------------------
|
|
** Setup the combined list of formats that this data transfer
|
|
** ContainerDoc which contains a single OLE object should offer.
|
|
**
|
|
** OLE2NOTE: The list of formats that should be offered when a
|
|
** single OLE object is being transfered include the following:
|
|
** * any formats the container app wants to give
|
|
** * CF_EMBEDDEDOBJECT
|
|
** * CF_METAFILEPICT
|
|
** * any formats that the OLE object's cache can offer directly
|
|
**
|
|
** We will offer the following formats in the order given:
|
|
** 1. CF_CNTROUTL
|
|
** 2. CF_EMBEDDEDOBJECT
|
|
** 3. CF_OBJECTDESCRIPTOR
|
|
** 4. CF_METAFILEPICT
|
|
** 5. <data formats from OLE object's cache>
|
|
** 6. CF_LINKSOURCE
|
|
** 7. CF_LINKSRCDESCRIPTOR
|
|
*/
|
|
BOOL ContainerDoc_SetupDocGetFmts(
|
|
LPCONTAINERDOC lpContainerDoc,
|
|
LPCONTAINERLINE lpContainerLine
|
|
)
|
|
{
|
|
LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;
|
|
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
|
LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
|
|
LPOLECACHE lpOleCache;
|
|
HRESULT hrErr;
|
|
STATDATA StatData;
|
|
LPENUMSTATDATA lpEnumStatData = NULL;
|
|
LPFORMATETC lparrDocGetFmts = NULL;
|
|
UINT nOleObjFmts = 0;
|
|
UINT nTotalFmts;
|
|
UINT i;
|
|
UINT iFmt;
|
|
|
|
lpOleCache = (LPOLECACHE)OleStdQueryInterface(
|
|
(LPUNKNOWN)lpContainerLine->m_lpOleObj,
|
|
&IID_IOleCache
|
|
);
|
|
if (lpOleCache) {
|
|
OLEDBG_BEGIN2("IOleCache::EnumCache called\r\n")
|
|
hrErr = lpOleCache->lpVtbl->EnumCache(
|
|
lpOleCache,
|
|
(LPENUMSTATDATA FAR*)&lpEnumStatData
|
|
);
|
|
OLEDBG_END2
|
|
}
|
|
|
|
if (lpEnumStatData) {
|
|
/* Cache enumerator is available. count the number of
|
|
** formats that the OLE object's cache offers.
|
|
*/
|
|
while(lpEnumStatData->lpVtbl->Next(
|
|
lpEnumStatData,
|
|
1,
|
|
(LPSTATDATA)&StatData,
|
|
NULL) == NOERROR) {
|
|
nOleObjFmts++;
|
|
// OLE2NOTE: we MUST free the TargetDevice
|
|
OleStdFree(StatData.formatetc.ptd);
|
|
}
|
|
lpEnumStatData->lpVtbl->Reset(lpEnumStatData); // reset for next loop
|
|
}
|
|
|
|
/* OLE2NOTE: the maximum total number of formats that our IDataObject
|
|
** could offer equals the sum of the following:
|
|
** n offered by the OLE object's cache
|
|
** + n normally offered by our app
|
|
** + 1 CF_EMBEDDEDOBJECT
|
|
** + 1 CF_METAFILEPICT
|
|
** + 1 CF_LINKSOURCE
|
|
** + 1 CF_LINKSRCDESCRIPTOR
|
|
** the actual number of formats that we can offer could be less
|
|
** than this total if there is any clash between the formats
|
|
** that we offer directly and those offered by the cache. if
|
|
** there is a clash, the container's rendering overrides that of
|
|
** the object. eg.: as a container transfering an OLE object we
|
|
** should directly offer CF_METAFILEPICT to guarantee that this
|
|
** format is always available. thus, if the cache offers
|
|
** CF_METAFILEPICT then it is skipped.
|
|
*/
|
|
nTotalFmts = nOleObjFmts + lpOleApp->m_nDocGetFmts + 4;
|
|
lparrDocGetFmts = (LPFORMATETC)New (nTotalFmts * sizeof(FORMATETC));
|
|
|
|
OleDbgAssertSz(lparrDocGetFmts != NULL,"Error allocating arrDocGetFmts");
|
|
if (lparrDocGetFmts == NULL)
|
|
return FALSE;
|
|
|
|
for (i = 0, iFmt = 0; i < lpOleApp->m_nDocGetFmts; i++) {
|
|
_fmemcpy((LPFORMATETC)&lparrDocGetFmts[iFmt++],
|
|
(LPFORMATETC)&lpOleApp->m_arrDocGetFmts[i],
|
|
sizeof(FORMATETC)
|
|
);
|
|
if (lpOleApp->m_arrDocGetFmts[i].cfFormat ==
|
|
lpContainerApp->m_cfCntrOutl) {
|
|
/* insert CF_EMBEDDEDOBJECT, CF_METAFILEPICT, and formats
|
|
** available from the OLE object's cache following
|
|
** CF_CNTROUTL.
|
|
*/
|
|
lparrDocGetFmts[iFmt].cfFormat = lpOleApp->m_cfEmbeddedObject;
|
|
lparrDocGetFmts[iFmt].ptd = NULL;
|
|
lparrDocGetFmts[iFmt].dwAspect = DVASPECT_CONTENT;
|
|
lparrDocGetFmts[iFmt].tymed = TYMED_ISTORAGE;
|
|
lparrDocGetFmts[iFmt].lindex = -1;
|
|
iFmt++;
|
|
lparrDocGetFmts[iFmt].cfFormat = CF_METAFILEPICT;
|
|
lparrDocGetFmts[iFmt].ptd = NULL;
|
|
lparrDocGetFmts[iFmt].dwAspect = lpContainerLine->m_dwDrawAspect;
|
|
lparrDocGetFmts[iFmt].tymed = TYMED_MFPICT;
|
|
lparrDocGetFmts[iFmt].lindex = -1;
|
|
iFmt++;
|
|
|
|
if (lpEnumStatData) {
|
|
/* Cache enumerator is available. enumerate all of
|
|
** the formats that the OLE object's cache offers.
|
|
*/
|
|
while(lpEnumStatData->lpVtbl->Next(
|
|
lpEnumStatData,
|
|
1,
|
|
(LPSTATDATA)&StatData,
|
|
NULL) == NOERROR) {
|
|
/* check if the format clashes with one of our fmts */
|
|
if (StatData.formatetc.cfFormat != CF_METAFILEPICT
|
|
&& ! OleStdIsDuplicateFormat(
|
|
(LPFORMATETC)&StatData.formatetc,
|
|
lpOleApp->m_arrDocGetFmts,
|
|
lpOleApp->m_nDocGetFmts)) {
|
|
OleStdCopyFormatEtc(
|
|
&(lparrDocGetFmts[iFmt]),&StatData.formatetc);
|
|
iFmt++;
|
|
}
|
|
// OLE2NOTE: we MUST free the TargetDevice
|
|
OleStdFree(StatData.formatetc.ptd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lpOleCache)
|
|
OleStdRelease((LPUNKNOWN)lpOleCache);
|
|
|
|
/* append CF_LINKSOURCE format */
|
|
lparrDocGetFmts[iFmt].cfFormat = lpOleApp->m_cfLinkSource;
|
|
lparrDocGetFmts[iFmt].ptd = NULL;
|
|
lparrDocGetFmts[iFmt].dwAspect = DVASPECT_CONTENT;
|
|
lparrDocGetFmts[iFmt].tymed = TYMED_ISTREAM;
|
|
lparrDocGetFmts[iFmt].lindex = -1;
|
|
iFmt++;
|
|
|
|
/* append CF_LINKSRCDESCRIPTOR format */
|
|
lparrDocGetFmts[iFmt].cfFormat = lpOleApp->m_cfLinkSrcDescriptor;
|
|
lparrDocGetFmts[iFmt].ptd = NULL;
|
|
lparrDocGetFmts[iFmt].dwAspect = DVASPECT_CONTENT;
|
|
lparrDocGetFmts[iFmt].tymed = TYMED_HGLOBAL;
|
|
lparrDocGetFmts[iFmt].lindex = -1;
|
|
iFmt++;
|
|
|
|
lpContainerDoc->m_lparrDocGetFmts = lparrDocGetFmts;
|
|
lpContainerDoc->m_nDocGetFmts = iFmt;
|
|
|
|
if (lpEnumStatData)
|
|
OleStdVerifyRelease(
|
|
(LPUNKNOWN)lpEnumStatData,
|
|
"Cache enumerator not released properly"
|
|
);
|
|
|
|
return TRUE;
|
|
}
|
|
#endif // OPTIONAL_ADVANCED_DATA_TRANSFER
|
|
|
|
#endif // OLE_CNTR
|