/*--------------------------------------------------------------------------- | CDRAG.C | This file has the interfaces for the object transferred through the | Clipboard or through a Drag-Drop. These interfaces unlike the interfaces | implemented in the file OBJ.C transfer the state of the object at | Edit->Copy time or Drag-Drop time. The interfaces in OBJ.C transfer the | real-time Object Data. | | Created by: Vij Rajarajan (VijR) +---------------------------------------------------------------------------*/ #define SERVERONLY #include #include #include "mpole.h" #include "mplayer.h" #include #define OLESTDDELIM "!" #define STGM_SALL (STGM_READWRITE | STGM_SHARE_EXCLUSIVE) HANDLE GetMetafilePict (VOID); SCODE SaveMoniker (LPSTREAM lpstream); HANDLE PASCAL GetDib (VOID); HANDLE ghClipData = NULL; /* Holds the data handle at the time of Copy */ HANDLE ghClipMetafile = NULL; /* to clipboard */ HANDLE ghClipDib = NULL; /* Global flag to indicate OLE was initialized for drag. * This happens on a separate thread from the main window, * so we need to initialize and uninitialize independently. */ BOOL gfOleInitForDrag = FALSE; extern LPDATAOBJECT gpClipboardDataObject; /************************************************************************** * CutOrCopyObject * Sets the clipboard with the IDataObject interface of the lpdoc * object passed as the argument. The function also saves a snapshot of * the state of the object in the globals ghClipMetafile, ghClipData, * and ghClipDib. **************************************************************************/ void CutOrCopyObj (LPDOC lpdoc) { LPDATAOBJECT lpDataObj; lpDataObj = (LPDATAOBJECT)CreateClipDragDataObject(lpdoc,TRUE); if (lpDataObj != NULL) { if (ghClipData) GLOBALFREE(ghClipData); if (ghClipMetafile) { { // note that ghClipMetafile is set deep in PictureFromDib and contains // a handle to a windows metafile. Clean this up properly here. There may // be other memory/handle leaks caused by this coding of the metafile handle elsewhere. // SteveZ LPMETAFILEPICT pmfp; BOOL bReturn; DWORD dw; pmfp = (LPMETAFILEPICT)GLOBALLOCK(ghClipMetafile); bReturn = DeleteMetaFile(pmfp->hMF); if (!bReturn) { dw = GetLastError(); } GLOBALUNLOCK(ghClipMetafile); } GLOBALFREE(ghClipMetafile); } if (ghClipDib) GLOBALFREE(ghClipDib); ghClipData = GetLink(); ghClipMetafile = GetMetafilePict(); ghClipDib = GetDib(); OleSetClipboard(lpDataObj); IDataObject_Release(lpDataObj); gpClipboardDataObject = lpDataObj; } } /************************************************************************** * CreateClipDragDataObject: * This function returns an initialized instance of the CLIPDRAGDATA data * structure. fClipData = TRUE if the object is for the clipboard and * = FALSE if the object is for Drag-Drop operation. **************************************************************************/ LPCLIPDRAGDATA CreateClipDragDataObject(LPDOC lpdoc, BOOL fClipData) { LPCLIPDRAGDATA lpclipdragdata; lpclipdragdata = malloc( sizeof(CLIPDRAGDATA) ); if (lpclipdragdata == NULL) { DPF0("Malloc failed in CreateClipDragDataObject\n"); return NULL; } lpclipdragdata->m_IDataObject.lpVtbl = &clipdragVtbl; lpclipdragdata->lpClipDragEnum = NULL; lpclipdragdata->m_IDropSource.lpVtbl = &dropsourceVtbl; lpclipdragdata->m_IDataObject.lpclipdragdata = lpclipdragdata; lpclipdragdata->m_IDropSource.lpclipdragdata = lpclipdragdata; lpclipdragdata->lpdoc = lpdoc; lpclipdragdata->cRef = 1; lpclipdragdata->fClipData = fClipData; return lpclipdragdata; } /************************************************************************** * DoDrag: * Initiates the Drag-Drop operation. **************************************************************************/ void DoDrag(void) { DWORD dwEffect; LPCLIPDRAGDATA lpclipdragdata; if (!InitOLE(&gfOleInitForDrag, NULL)) { DPF0("Initialization of OLE FAILED!! Can't do drag.\n"); return; } lpclipdragdata = CreateClipDragDataObject ((LPDOC)&docMain, FALSE); if (lpclipdragdata) { HRESULT hr; hr = (HRESULT)DoDragDrop((IDataObject FAR*)&lpclipdragdata->m_IDataObject, (IDropSource FAR*)&lpclipdragdata->m_IDropSource, DROPEFFECT_COPY, &dwEffect); DPF("DoDragDrop returned %s\n", hr == S_OK ? "S_OK" : hr == DRAGDROP_S_DROP ? "DRAGDROP_S_DROP" : hr == DRAGDROP_S_CANCEL ? "DRAGDROP_S_CANCEL" : hr == E_OUTOFMEMORY ? "E_OUTOFMEMORY" : hr == E_UNEXPECTED ? "E_UNEXPECTED" : ""); IDataObject_Release((IDataObject *)&lpclipdragdata->m_IDataObject); } } void CleanUpDrag(void) { if (gfOleInitForDrag) { DPF("Uninitializing OLE for thread %d\n", GetCurrentThreadId()); CoDisconnectObject((LPUNKNOWN)&docMain, 0); OleUninitialize(); gfOleInitForDrag = FALSE; } } /************************************************************************** * GetObjectDescriptorData: * Packages an ObjectDescriptor data structure. **************************************************************************/ HGLOBAL GetObjectDescriptorData( CLSID clsid, DWORD dwAspect, SIZEL sizel, POINTL pointl, DWORD dwStatus, LPTSTR lpszFullUserTypeName, LPTSTR lpszSrcOfCopy ) { HGLOBAL hMem = NULL; IBindCtx FAR *pbc = NULL; LPOBJECTDESCRIPTOR lpOD; DWORD dwObjectDescSize, dwFullUserTypeNameLen, dwSrcOfCopyLen; DWORD Offset; // Get the length of Full User Type Name: dwFullUserTypeNameLen = STRING_BYTE_COUNT_NULLOK(lpszFullUserTypeName); dwFullUserTypeNameLen *= (sizeof(WCHAR) / sizeof(TCHAR)); // Get the Source of Copy string and its length: dwSrcOfCopyLen = STRING_BYTE_COUNT_NULLOK(lpszSrcOfCopy); dwSrcOfCopyLen *= (sizeof(WCHAR) / sizeof(TCHAR)); if (lpszSrcOfCopy == NULL) { // No src moniker so use user type name as source string. lpszSrcOfCopy = lpszFullUserTypeName; dwSrcOfCopyLen = dwFullUserTypeNameLen; } // Allocate space for OBJECTDESCRIPTOR and the additional string data dwObjectDescSize = sizeof(OBJECTDESCRIPTOR); hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, dwObjectDescSize + dwFullUserTypeNameLen + dwSrcOfCopyLen); if (NULL == hMem) goto error; lpOD = (LPOBJECTDESCRIPTOR)GLOBALLOCK(hMem); if(!lpOD) goto error; // Set offset to copy strings at end of the object descriptor: Offset = dwObjectDescSize; // Set the FullUserTypeName offset and copy the string if (lpszFullUserTypeName) { lpOD->dwFullUserTypeName = Offset; #ifdef UNICODE lstrcpy((LPWSTR)(((LPBYTE)lpOD)+Offset), lpszFullUserTypeName); #else AnsiToUnicodeString(lpszFullUserTypeName, (LPWSTR)(((LPBYTE)lpOD)+Offset), -1); #endif Offset += dwFullUserTypeNameLen; } else lpOD->dwFullUserTypeName = 0; // zero offset indicates that string is not present // Set the SrcOfCopy offset and copy the string if (lpszSrcOfCopy) { lpOD->dwSrcOfCopy = Offset; #ifdef UNICODE lstrcpy((LPWSTR)(((LPBYTE)lpOD)+Offset), lpszSrcOfCopy); #else AnsiToUnicodeString(lpszSrcOfCopy, (LPWSTR)(((LPBYTE)lpOD)+Offset), -1); #endif } else lpOD->dwSrcOfCopy = 0; // zero offset indicates that string is not present // Initialize the rest of the OBJECTDESCRIPTOR lpOD->cbSize = dwObjectDescSize + dwFullUserTypeNameLen + dwSrcOfCopyLen; lpOD->clsid = clsid; lpOD->dwDrawAspect = dwAspect; lpOD->sizel = sizel; lpOD->pointl = pointl; lpOD->dwStatus = dwStatus; GLOBALUNLOCK(hMem); return hMem; error: if (hMem) { GLOBALUNLOCK(hMem); GLOBALFREE(hMem); } return NULL; } /************************************************************************** *************** IUnknown INTERFACE INPLEMENTATION. **************************************************************************/ STDMETHODIMP ClipDragUnknownQueryInterface ( LPCLIPDRAGDATA lpclipdragdata, // data object ptr REFIID riidReq, // IID required LPVOID FAR * lplpUnk // pre for returning the interface ) { if ( IsEqualIID(riidReq, &IID_IDataObject) || IsEqualIID(riidReq, &IID_IUnknown) ) { *lplpUnk = (LPVOID) lpclipdragdata; } else if ( IsEqualIID(riidReq, &IID_IDropSource)) { *lplpUnk = (LPVOID) &lpclipdragdata->m_IDropSource; } else { *lplpUnk = (LPVOID) NULL; RETURN_RESULT(E_NOINTERFACE); } DPF("ClipDragAddRef: cRef = %d\n", lpclipdragdata->cRef + 1); lpclipdragdata->cRef++; return NOERROR; } STDMETHODIMP_(ULONG) ClipDragUnknownAddRef( LPCLIPDRAGDATA lpclipdragdata // data object ptr ) { DPF("ClipDragAddRef: cRef = %d\n", lpclipdragdata->cRef + 1); return ++lpclipdragdata->cRef; } STDMETHODIMP_(ULONG) ClipDragUnknownRelease ( LPCLIPDRAGDATA lpclipdragdata ) { DPF("ClipDragRelease: cRef = %d\n", lpclipdragdata->cRef - 1); if ( --lpclipdragdata->cRef != 0 ) return lpclipdragdata->cRef; free(lpclipdragdata); return 0; } /************************************************************************** ****************** IDataObject INTERFACE IMPLEMENTATION. **************************************************************************/ STDMETHODIMP ClipDragQueryInterface ( LPDATAOBJECT lpDataObj, // data object ptr REFIID riidReq, // IID required LPVOID FAR * lplpUnk // pre for returning the interface ) { DPF("ClipDragQueryInterface\n"); return ClipDragUnknownQueryInterface ( (LPCLIPDRAGDATA) (( struct CDataObject FAR* )lpDataObj)->lpclipdragdata , riidReq, lplpUnk ); } STDMETHODIMP_(ULONG) ClipDragAddRef( LPDATAOBJECT lpDataObj // data object ptr ) { return ClipDragUnknownAddRef ( (LPCLIPDRAGDATA) (( struct CDataObject FAR* )lpDataObj)->lpclipdragdata ); } STDMETHODIMP_(ULONG) ClipDragRelease ( LPDATAOBJECT lpDataObj // data object ptr ) { return ClipDragUnknownRelease ( (LPCLIPDRAGDATA) (( struct CDataObject FAR* )lpDataObj)->lpclipdragdata ); } /* Routines called by ClipDragGetData, one for each format supported: */ HRESULT ClipDragGetData_EmbedSource( LPCLIPDRAGDATA lpclipdragdata, LPSTGMEDIUM lpMedium ); HRESULT ClipDragGetData_ObjectDescriptor( LPCLIPDRAGDATA lpclipdragdata, LPSTGMEDIUM lpMedium ); HRESULT ClipDragGetData_MetafilePict( LPCLIPDRAGDATA lpclipdragdata, LPSTGMEDIUM lpMedium ); HRESULT ClipDragGetData_DIB( LPCLIPDRAGDATA lpclipdragdata, LPSTGMEDIUM lpMedium ); /************************************************************************** * ClipDragGetData: * Returns the saved snapshot of the Object in the required format, * if available. If not, returns the current snapshot. We still write * out the OLE1 embedding to maintain backward compatibility. **************************************************************************/ STDMETHODIMP ClipDragGetData ( LPDATAOBJECT lpDataObj, LPFORMATETC lpformatetc, LPSTGMEDIUM lpMedium ) { LPCLIPDRAGDATA lpclipdragdata; SCODE scode; STGMEDIUM stgm; CLIPFORMAT cfFormat; DWORD tymed; DPF("ClipDragGetData\n"); if (lpMedium == NULL) RETURN_RESULT( E_FAIL); VERIFY_LINDEX(lpformatetc->lindex); memset(&stgm, 0, sizeof stgm); lpclipdragdata = (LPCLIPDRAGDATA) lpDataObj; cfFormat = lpformatetc->cfFormat; tymed = lpformatetc->tymed; if ((cfFormat == cfEmbedSource) && (tymed & TYMED_ISTORAGE)) scode = ClipDragGetData_EmbedSource(lpclipdragdata, &stgm); else if ((cfFormat == cfObjectDescriptor) && (tymed & TYMED_HGLOBAL)) scode = ClipDragGetData_ObjectDescriptor(lpclipdragdata, &stgm); else if ((cfFormat == CF_METAFILEPICT) && (tymed & TYMED_MFPICT)) scode = ClipDragGetData_MetafilePict(lpclipdragdata, &stgm); else if ((cfFormat == CF_DIB) && (tymed & TYMED_HGLOBAL)) scode = ClipDragGetData_DIB(lpclipdragdata, &stgm); else scode = DATA_E_FORMATETC; if (scode == S_OK) *lpMedium = stgm; RETURN_RESULT(scode); } #ifdef DEBUG BOOL WriteOLE2Class( ) { HKEY hKey; TCHAR Data[8]; DWORD Size; BOOL rc = FALSE; if( RegOpenKeyEx( HKEY_CLASSES_ROOT, TEXT( "MPlayer\\Debug" ), 0, KEY_READ, &hKey ) == ERROR_SUCCESS ) { if( RegQueryValueEx( hKey, TEXT( "WriteOLE2Class" ), NULL, NULL, (LPBYTE)&Data, &Size ) == ERROR_SUCCESS ) { if( Data[0] == TEXT( 'y' ) || Data[0] == TEXT( 'Y' ) ) rc = TRUE; } RegCloseKey( hKey ); } return rc; } #endif /* * */ HRESULT ClipDragGetData_EmbedSource( LPCLIPDRAGDATA lpclipdragdata, LPSTGMEDIUM lpMedium ) { SCODE scode; LPSTREAM lpstm = NULL; LPWSTR lpszUserType; HANDLE hGlobal = NULL; DWORD_PTR nNativeSz; ULONG cbWritten; scode = GetScode(StgCreateDocfile(NULL, /* Create temporary compound file */ STGM_CREATE | STGM_SALL | STGM_DELETEONRELEASE, 0, /* Reserved */ &lpMedium->pstg)); if (scode != S_OK) RETURN_RESULT(scode); lpMedium->tymed = TYMED_ISTORAGE; lpMedium->pUnkForRelease = NULL; //Mark the Object as OLE1. #ifdef UNICODE lpszUserType = gachClassRoot; #else lpszUserType = AllocateUnicodeString(gachClassRoot); if (!lpszUserType) RETURN_RESULT(E_OUTOFMEMORY); #endif #ifdef DEBUG if(WriteOLE2Class()) { DPF("ClipDragGetData_EmbedSource: Writing OLE2 class ID\n"); scode = GetScode(WriteClassStg(lpMedium->pstg, &CLSID_MPLAYER)); } else #endif scode = GetScode(WriteClassStg(lpMedium->pstg, &CLSID_OLE1MPLAYER)); if (scode != S_OK) RETURN_RESULT(scode); scode = GetScode(WriteFmtUserTypeStg(lpMedium->pstg, cfMPlayer, lpszUserType)); #ifndef UNICODE FreeUnicodeString(lpszUserType); #endif if (scode != S_OK) RETURN_RESULT(scode); //Write to \1Ole10Native stream so that this will be readable by OLE1 Mplayer scode = GetScode(IStorage_CreateStream(lpMedium->pstg,sz1Ole10Native, STGM_CREATE | STGM_SALL,0,0,&lpstm)); if (scode != S_OK) RETURN_RESULT(scode); //Duplicate the handle we have saved. if(lpclipdragdata->fClipData && ghClipData) hGlobal = OleDuplicateData(ghClipData, cfEmbedSource, 0); else hGlobal = GetLink(); if (!hGlobal) { GLOBALFREE(hGlobal); RETURN_RESULT(E_OUTOFMEMORY); } nNativeSz = GlobalSize(hGlobal); lpclipdragdata->lpdoc->native = GLOBALLOCK(hGlobal); if(!lpclipdragdata->lpdoc->native) { GLOBALUNLOCK(hGlobal); GLOBALFREE(hGlobal); RETURN_RESULT(E_OUTOFMEMORY); /* What's the right error here? */ } scode = GetScode(IStream_Write(lpstm,&nNativeSz,4,&cbWritten)); if (scode != S_OK) RETURN_RESULT(scode); scode = GetScode(IStream_Write(lpstm,lpclipdragdata->lpdoc->native, (ULONG)nNativeSz,&cbWritten)); if (cbWritten != nNativeSz) scode = E_FAIL ; IStream_Release(lpstm); GLOBALUNLOCK(hGlobal); GLOBALFREE(hGlobal); lpstm = NULL; RETURN_RESULT(scode); } /* * */ HRESULT ClipDragGetData_ObjectDescriptor( LPCLIPDRAGDATA lpclipdragdata, LPSTGMEDIUM lpMedium ) { SIZEL sizel; POINTL pointl; TCHAR displayname[256]; LPTSTR lpszdn = (LPTSTR)displayname; HGLOBAL hobjdesc; DWORD dwStatus = 0; static SZCODE aszDispFormat[] = TEXT("%"TS" : %"TS""); DPF("\n^^^^^^CDGetdata: OBJECTDESC"); sizel.cx = extWidth; sizel.cy = extHeight; pointl.x = pointl.y = 0; wsprintf(displayname, aszDispFormat, (LPTSTR)gachClassRoot, (LPTSTR)gachWindowTitle); #ifdef DEBUG if(WriteOLE2Class()) { DPF("ClipDragGetData_ObjectDescriptor: Getting OLE2 class\n"); hobjdesc = GetObjectDescriptorData(CLSID_MPLAYER, DVASPECT_CONTENT, sizel, pointl, dwStatus, lpszdn, lpszdn); } else #endif hobjdesc = GetObjectDescriptorData(CLSID_OLE1MPLAYER, DVASPECT_CONTENT, sizel, pointl, dwStatus, lpszdn, lpszdn); if (hobjdesc) { lpMedium->hGlobal = hobjdesc; lpMedium->tymed = TYMED_HGLOBAL; lpMedium->pUnkForRelease = NULL; return NOERROR; } RETURN_RESULT(E_OUTOFMEMORY); } /* * */ HRESULT ClipDragGetData_MetafilePict( LPCLIPDRAGDATA lpclipdragdata, LPSTGMEDIUM lpMedium ) { SCODE scode; lpMedium->tymed = TYMED_MFPICT; if(lpclipdragdata->fClipData && ghClipMetafile) lpMedium->hGlobal = OleDuplicateData(ghClipMetafile, CF_METAFILEPICT, 0); else lpMedium->hGlobal = GetMetafilePict(); if (lpMedium->hGlobal == NULL) scode = E_OUTOFMEMORY; else scode = S_OK; lpMedium->pUnkForRelease = NULL; RETURN_RESULT(scode); } /* * */ HRESULT ClipDragGetData_DIB( LPCLIPDRAGDATA lpclipdragdata, LPSTGMEDIUM lpMedium ) { SCODE scode; lpMedium->tymed = TYMED_HGLOBAL; if(lpclipdragdata->fClipData && ghClipDib) lpMedium->hGlobal = OleDuplicateData(ghClipDib, CF_DIB, 0); else /* We must make sure GetDib() happens on the main thread, * because otherwise MCI complains. */ lpMedium->hGlobal = (HANDLE)SendMessage(ghwndApp, WM_GETDIB, 0, 0); if (lpMedium->hGlobal == NULL) scode = E_OUTOFMEMORY; else scode = S_OK; lpMedium->pUnkForRelease = NULL; RETURN_RESULT(scode); } /************************************************************************** * ClipDragGetDataHere: * Make the embedding by writing into the Stream Mplayer3EmbedSource. * **************************************************************************/ STDMETHODIMP ClipDragGetDataHere ( LPDATAOBJECT lpDataObj, LPFORMATETC lpformatetc, LPSTGMEDIUM lpMedium ) { LPCLIPDRAGDATA lpclipdragdata; HANDLE hGlobal = NULL; DWORD_PTR nNativeSz; LPTSTR lpnative; ULONG cbWritten; DPF("ClipDragGetDataHere\n"); if (lpMedium == NULL) RETURN_RESULT(E_FAIL); VERIFY_LINDEX(lpformatetc->lindex); lpclipdragdata = (LPCLIPDRAGDATA) lpDataObj; if (lpformatetc->cfFormat == cfEmbedSource) { SCODE scode; LPSTREAM lpstm = NULL; LPWSTR lpszUserType; if (lpMedium->tymed != TYMED_ISTORAGE) RETURN_RESULT(DATA_E_FORMATETC); #ifdef UNICODE lpszUserType = gachClassRoot; #else lpszUserType = AllocateUnicodeString(gachClassRoot); if (!lpszUserType) RETURN_RESULT(E_OUTOFMEMORY); #endif //Mark the object as OLE1 MPlayer object for backward compatibility: #ifdef DEBUG if(WriteOLE2Class()) { DPF("ClipDragGetDataHere: Writing OLE2 class ID\n"); scode = GetScode(WriteClassStg(lpMedium->pstg, &CLSID_MPLAYER)); } else #endif scode = GetScode(WriteClassStg(lpMedium->pstg, &CLSID_OLE1MPLAYER)); if (scode != S_OK) RETURN_RESULT(scode); scode = GetScode(WriteFmtUserTypeStg(lpMedium->pstg, cfMPlayer, lpszUserType)); #ifndef UNICODE FreeUnicodeString(lpszUserType); #endif if (scode != S_OK) RETURN_RESULT(scode); //Write to the \1Ole10Native stream so the object will be readable by OLE1 Mplayer if ((scode = GetScode(IStorage_CreateStream(lpMedium->pstg, sz1Ole10Native, STGM_CREATE | STGM_SALL, 0, 0, &lpstm))) != S_OK) RETURN_RESULT(scode); //Duplicate and give out the handle we have saved. if(lpclipdragdata->fClipData && ghClipData) hGlobal = OleDuplicateData(ghClipData, cfEmbedSource, 0); else hGlobal = GetLink(); if (!hGlobal) { RETURN_RESULT(E_OUTOFMEMORY); } nNativeSz = GlobalSize(hGlobal); lpnative = GLOBALLOCK(hGlobal); if (!lpnative) { GLOBALUNLOCK(hGlobal); GLOBALFREE(hGlobal); RETURN_RESULT(E_OUTOFMEMORY); } scode = GetScode(IStream_Write(lpstm,&nNativeSz,4,&cbWritten)); scode = GetScode(IStream_Write(lpstm,lpnative,(ULONG)nNativeSz,&cbWritten)); if (cbWritten != nNativeSz) scode = E_FAIL ; IStream_Release(lpstm); GLOBALUNLOCK(hGlobal); GLOBALFREE(hGlobal); RETURN_RESULT( scode); } else RETURN_RESULT(DATA_E_FORMATETC); } STDMETHODIMP ClipDragQueryGetData ( LPDATAOBJECT lpDataObj, LPFORMATETC lpformatetc ) { DPF("ClipDragQueryGetData\n"); if (lpformatetc->cfFormat == cfEmbedSource || lpformatetc->cfFormat == CF_METAFILEPICT || lpformatetc->cfFormat == CF_DIB || lpformatetc->cfFormat == cfObjectDescriptor ) return NOERROR; else RETURN_RESULT(DATA_E_FORMATETC); } STDMETHODIMP ClipDragGetCanonicalFormatEtc( LPDATAOBJECT lpDataObj, LPFORMATETC lpformatetc, LPFORMATETC lpformatetcOut ) { DPF("ClipDragGetCanonicalFormatEtc\n"); RETURN_RESULT(DATA_S_SAMEFORMATETC); } STDMETHODIMP ClipDragSetData ( LPDATAOBJECT lpDataObj, LPFORMATETC lpformatetc, LPSTGMEDIUM lpmedium, BOOL fRelease ) { DPF("ClipDragSetData\n"); RETURN_RESULT(E_NOTIMPL); } STDMETHODIMP ClipDragEnumFormatEtc( LPDATAOBJECT lpDataObj, DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc ){ LPCLIPDRAGENUM lpclipdragenum; if (ppenumFormatEtc != NULL) *ppenumFormatEtc = NULL; lpclipdragenum = _fmalloc(sizeof(CLIPDRAGENUM)); if (lpclipdragenum == NULL) RETURN_RESULT(E_OUTOFMEMORY); lpclipdragenum->lpVtbl = &ClipDragEnumVtbl; lpclipdragenum->cRef = 1; lpclipdragenum->lpClipDragData = (LPCLIPDRAGDATA) lpDataObj; lpclipdragenum->cfNext = cfEmbedSource; lpclipdragenum->lpClipDragData->lpClipDragEnum = lpclipdragenum; *ppenumFormatEtc = (LPENUMFORMATETC) lpclipdragenum; return NOERROR; } STDMETHODIMP ClipDragAdvise( LPDATAOBJECT LPDATAOBJect, FORMATETC FAR* pFormatetc, DWORD advf, IAdviseSink FAR* pAdvSink, DWORD FAR* pdwConnection ) { RETURN_RESULT(E_NOTIMPL); } STDMETHODIMP ClipDragUnadvise( LPDATAOBJECT LPDATAOBJect, DWORD dwConnection ) { RETURN_RESULT(E_NOTIMPL); } STDMETHODIMP ClipDragEnumAdvise( LPDATAOBJECT LPDATAOBJect, LPENUMSTATDATA FAR* ppenumAdvise ) { RETURN_RESULT(E_NOTIMPL); } /************************************************************************** **************** IDropSource INTERFACE IMPLEMENTAION. **************************************************************************/ STDMETHODIMP DropSourceQueryInterface ( LPDROPSOURCE lpdropsource, // data object ptr REFIID riidReq, // IID required LPVOID FAR * lplpUnk // pre for returning the interface ) { return ClipDragUnknownQueryInterface ( (LPCLIPDRAGDATA) ( ( struct CDropSource FAR* )lpdropsource)->lpclipdragdata , riidReq, lplpUnk ); } STDMETHODIMP_(ULONG) DropSourceAddRef( LPDROPSOURCE lpdropsource // data object ptr ) { return ClipDragUnknownAddRef ( (LPCLIPDRAGDATA) ( ( struct CDropSource FAR* )lpdropsource)->lpclipdragdata ); } STDMETHODIMP_(ULONG) DropSourceRelease ( LPDROPSOURCE lpdropsource // data object ptr ) { return ClipDragUnknownRelease ( (LPCLIPDRAGDATA) ( ( struct CDropSource FAR* )lpdropsource)->lpclipdragdata ); } STDMETHODIMP DropSourceQueryContinueDrag ( LPDROPSOURCE lpdropsource, // data object ptr BOOL fEscapePressed, DWORD grfKeyState ) { if (fEscapePressed) { DPF("DropSourceQueryContinueDrag: fEscapePressed\n"); RETURN_RESULT( DRAGDROP_S_CANCEL); } else if (!(grfKeyState & MK_LBUTTON)) { DPF("DropSourceQueryContinueDrag: !(grfKeyState & MK_LBUTTON)\n"); RETURN_RESULT(DRAGDROP_S_DROP); } else return NOERROR; } STDMETHODIMP DropSourceGiveFeedback ( LPDROPSOURCE lpsropsource, // data object ptr DWORD dwEffect ) { DPF("DropSourceGiveFeedback\n"); RETURN_RESULT(DRAGDROP_S_USEDEFAULTCURSORS); } /************************************************************************** ************* IEnumFormatEtc INTERFACE IMPLEMENTATION. **************************************************************************/ STDMETHODIMP ClipDragEnumQueryInterface ( LPENUMFORMATETC lpEnumFormatEtc, // Enumerator object ptr REFIID riidReq, // IID required LPVOID FAR* lplpUnk // pre for returning the interface ) { LPCLIPDRAGENUM lpClipDragEnum; DPF("ClipDragEnumQueryInterface\n"); lpClipDragEnum = (LPCLIPDRAGENUM) lpEnumFormatEtc; if (IsEqualIID(riidReq, &IID_IEnumFORMATETC) || IsEqualIID(riidReq, &IID_IUnknown)) { *lplpUnk = (LPVOID) lpClipDragEnum; lpClipDragEnum->cRef++; return NOERROR; } else { *lplpUnk = (LPVOID) NULL; RETURN_RESULT( E_NOINTERFACE); } } STDMETHODIMP_(ULONG) ClipDragEnumAddRef ( LPENUMFORMATETC lpEnumFormatEtc // Enumerator object ptr ) { LPCLIPDRAGENUM lpClipDragEnum; lpClipDragEnum = (LPCLIPDRAGENUM) lpEnumFormatEtc; return ++lpClipDragEnum->cRef; } STDMETHODIMP_(ULONG) ClipDragEnumRelease ( LPENUMFORMATETC lpEnumFormatEtc // Enumerator object ptr ) { LPCLIPDRAGENUM lpClipDragEnum; lpClipDragEnum = (LPCLIPDRAGENUM) lpEnumFormatEtc; if (--lpClipDragEnum->cRef != 0) return lpClipDragEnum->cRef; // Remove Data object pointer (if one exists) to this // if (lpClipDragEnum->lpClipDragData != NULL) lpClipDragEnum->lpClipDragData->lpClipDragEnum = NULL; _ffree(lpClipDragEnum); return 0; } STDMETHODIMP ClipDragEnumNext ( LPENUMFORMATETC lpEnumFormatEtc, // Enumerator object ptr ULONG celt, // Number of items requested FORMATETC FAR rgelt[], // Buffer for retuend items ULONG FAR* pceltFetched // Number of items returned ) { LPCLIPDRAGENUM lpClipDragEnum; int ce; LPFORMATETC pfe; DPF("ClipDragEnumNext\n"); lpClipDragEnum = (LPCLIPDRAGENUM) lpEnumFormatEtc; if (pceltFetched != NULL) *pceltFetched = 0; if (lpClipDragEnum->lpClipDragData == NULL) // data object gone RETURN_RESULT( E_FAIL); pfe = rgelt; pfe->lindex = DEF_LINDEX; for (ce = (int) celt; ce > 0 && lpClipDragEnum->cfNext != 0; ce--) { if (lpClipDragEnum->cfNext == cfEmbedSource) { pfe->cfFormat = cfEmbedSource; pfe->ptd = NULL; pfe->dwAspect = DVASPECT_CONTENT; pfe->tymed = TYMED_ISTORAGE; pfe++; lpClipDragEnum->cfNext = CF_METAFILEPICT; } else if (lpClipDragEnum->cfNext == CF_METAFILEPICT) { pfe->cfFormat = CF_METAFILEPICT; pfe->ptd = NULL; pfe->dwAspect = DVASPECT_CONTENT; pfe->tymed = TYMED_MFPICT; pfe++; lpClipDragEnum->cfNext = CF_DIB; //0; } else if (lpClipDragEnum->cfNext == CF_DIB) { pfe->cfFormat = CF_DIB; pfe->ptd = NULL; pfe->dwAspect = DVASPECT_CONTENT; pfe->tymed = TYMED_HGLOBAL; pfe++; lpClipDragEnum->cfNext = cfObjectDescriptor; //0; } else if (lpClipDragEnum->cfNext == cfObjectDescriptor) { pfe->cfFormat = cfObjectDescriptor; pfe->ptd = NULL; pfe->dwAspect = DVASPECT_CONTENT; pfe->tymed = TYMED_HGLOBAL; pfe++; lpClipDragEnum->cfNext = 0; } } if (pceltFetched != NULL) *pceltFetched = celt - ((ULONG) ce) ; RETURN_RESULT( (ce == 0) ? S_OK : S_FALSE); } STDMETHODIMP ClipDragEnumSkip ( LPENUMFORMATETC lpEnumFormatEtc, // Enumerator object ptr ULONG celt // Number of elements to skip ) { LPCLIPDRAGENUM lpClipDragEnum; DPF("ClipDragEnumSkip\n"); lpClipDragEnum = (LPCLIPDRAGENUM) lpEnumFormatEtc; if (lpClipDragEnum->lpClipDragData == NULL) // data object gone RETURN_RESULT( E_FAIL); if (lpClipDragEnum->cfNext == cfEmbedSource) { if (celt == 1) lpClipDragEnum->cfNext = CF_METAFILEPICT; else if (celt == 2) lpClipDragEnum->cfNext = CF_DIB; else if (celt == 3) lpClipDragEnum->cfNext = cfObjectDescriptor; else if (celt > 3) goto ReturnFalse; } else if (lpClipDragEnum->cfNext == CF_METAFILEPICT) { if (celt == 1) lpClipDragEnum->cfNext = CF_DIB; else if (celt == 2) lpClipDragEnum->cfNext = cfObjectDescriptor; else if (celt > 2) goto ReturnFalse; } else if (lpClipDragEnum->cfNext == CF_DIB) { if (celt == 1) lpClipDragEnum->cfNext = cfObjectDescriptor; else if (celt > 1) goto ReturnFalse; } else if (lpClipDragEnum->cfNext == cfObjectDescriptor) { if (celt > 0) goto ReturnFalse; } else { ReturnFalse: RETURN_RESULT(S_FALSE); } return NOERROR; } STDMETHODIMP ClipDragEnumReset ( LPENUMFORMATETC lpEnumFormatEtc // Enumerator object ptr ) { LPCLIPDRAGENUM lpClipDragEnum; DPF("ClipDragEnumReset\n"); lpClipDragEnum = (LPCLIPDRAGENUM) lpEnumFormatEtc; if (lpClipDragEnum->lpClipDragData == NULL) // data object gone RETURN_RESULT( E_FAIL); lpClipDragEnum->cfNext = cfEmbedSource; return NOERROR; } STDMETHODIMP ClipDragEnumClone ( LPENUMFORMATETC lpEnumFormatEtc, // Enumerator object ptr LPENUMFORMATETC FAR* ppenum ) { DPF("ClipDragEnumClone\n"); if (ppenum != NULL) *ppenum = NULL; RETURN_RESULT( E_NOTIMPL); }