/************************************************************************* ** ** 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 ** */ 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 ** ** 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. ** 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