/* * Copyright (C) 2007 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ static void DuplicateMedium(CLIPFORMAT source_clipformat, STGMEDIUM* source, STGMEDIUM* destination) { switch(source->tymed) { case TYMED_HGLOBAL: destination->hGlobal = static_cast<HGLOBAL>(OleDuplicateData( source->hGlobal, source_clipformat, 0)); break; case TYMED_MFPICT: destination->hMetaFilePict = static_cast<HMETAFILEPICT>(OleDuplicateData( source->hMetaFilePict, source_clipformat, 0)); break; case TYMED_GDI: destination->hBitmap = static_cast<HBITMAP>(OleDuplicateData( source->hBitmap, source_clipformat, 0)); break; case TYMED_ENHMF: destination->hEnhMetaFile = static_cast<HENHMETAFILE>(OleDuplicateData( source->hEnhMetaFile, source_clipformat, 0)); break; case TYMED_FILE: destination->lpszFileName = static_cast<LPOLESTR>(OleDuplicateData( source->lpszFileName, source_clipformat, 0)); break; case TYMED_ISTREAM: destination->pstm = source->pstm; destination->pstm->AddRef(); break; case TYMED_ISTORAGE: destination->pstg = source->pstg; destination->pstg->AddRef(); break; } destination->tymed = source->tymed; destination->pUnkForRelease = source->pUnkForRelease; if(destination->pUnkForRelease) { destination->pUnkForRelease->AddRef(); } }
HRESULT __stdcall CDataObject::GetData (FORMATETC *pFormatEtc, STGMEDIUM *pMedium) { int idx; if((idx = LookupFormatEtc(pFormatEtc)) == -1) { return DV_E_FORMATETC; } pMedium->tymed = m_pFormatEtc[idx].tymed; pMedium->pUnkForRelease = 0; switch(m_pFormatEtc[idx].tymed) { case TYMED_GDI: pMedium->hBitmap = (HBITMAP)OleDuplicateData(m_pStgMedium[idx].hBitmap, CF_BITMAP, NULL); break; default: return DV_E_FORMATETC; } return S_OK; }
BOOL CSTGMEDIUM::Dup(STGMEDIUM* pdest, const FORMATETC* pFormatetc, const STGMEDIUM* pMedium) { HANDLE hVoid = NULL; switch (pMedium->tymed) { case TYMED_HGLOBAL: hVoid = OleDuplicateData(pMedium->hGlobal, pFormatetc->cfFormat, (UINT)NULL); pdest->hGlobal = (HGLOBAL)hVoid; break; case TYMED_GDI: hVoid = OleDuplicateData(pMedium->hBitmap, pFormatetc->cfFormat, (UINT)NULL); pdest->hBitmap = (HBITMAP)hVoid; break; case TYMED_MFPICT: hVoid = OleDuplicateData(pMedium->hMetaFilePict, pFormatetc->cfFormat, (UINT)NULL); pdest->hMetaFilePict = (HMETAFILEPICT)hVoid; break; case TYMED_ENHMF: hVoid = OleDuplicateData(pMedium->hEnhMetaFile, pFormatetc->cfFormat, (UINT)NULL); pdest->hEnhMetaFile = (HENHMETAFILE)hVoid; break; case TYMED_FILE: hVoid = OleDuplicateData(pMedium->lpszFileName, pFormatetc->cfFormat, (UINT)NULL); pdest->lpszFileName = (LPOLESTR)hVoid; break; } if (hVoid == NULL) return FALSE; pdest->tymed = pMedium->tymed; pdest->pUnkForRelease = pMedium->pUnkForRelease; if (pMedium->pUnkForRelease != NULL) pMedium->pUnkForRelease->AddRef(); return TRUE; }
void GitDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc) { switch (pMedSrc->tymed) { case TYMED_HGLOBAL: pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal, pFmtSrc->cfFormat, 0); break; case TYMED_GDI: pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap, pFmtSrc->cfFormat, 0); break; case TYMED_MFPICT: pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict, pFmtSrc->cfFormat, 0); break; case TYMED_ENHMF: pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile, pFmtSrc->cfFormat, 0); break; case TYMED_FILE: pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName, pFmtSrc->cfFormat, 0); break; case TYMED_ISTREAM: pMedDest->pstm = pMedSrc->pstm; pMedSrc->pstm->AddRef(); break; case TYMED_ISTORAGE: pMedDest->pstg = pMedSrc->pstg; pMedSrc->pstg->AddRef(); break; case TYMED_NULL: default: break; } pMedDest->tymed = pMedSrc->tymed; pMedDest->pUnkForRelease = nullptr; if (pMedSrc->pUnkForRelease) { pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease; pMedSrc->pUnkForRelease->AddRef(); } }
void DRTDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc) { switch (pMedSrc->tymed) { case TYMED_HGLOBAL: pMedDest->hGlobal = static_cast<HGLOBAL>(OleDuplicateData(pMedSrc->hGlobal, pFmtSrc->cfFormat, 0)); break; case TYMED_GDI: pMedDest->hBitmap = static_cast<HBITMAP>(OleDuplicateData(pMedSrc->hBitmap, pFmtSrc->cfFormat, 0)); break; case TYMED_MFPICT: pMedDest->hMetaFilePict = static_cast<HMETAFILEPICT>(OleDuplicateData(pMedSrc->hMetaFilePict, pFmtSrc->cfFormat, 0)); break; case TYMED_ENHMF: pMedDest->hEnhMetaFile = static_cast<HENHMETAFILE>(OleDuplicateData(pMedSrc->hEnhMetaFile, pFmtSrc->cfFormat, 0)); break; case TYMED_FILE: pMedSrc->lpszFileName = static_cast<LPOLESTR>(OleDuplicateData(pMedSrc->lpszFileName, pFmtSrc->cfFormat, 0)); break; case TYMED_ISTREAM: pMedDest->pstm = pMedSrc->pstm; pMedSrc->pstm->AddRef(); break; case TYMED_ISTORAGE: pMedDest->pstg = pMedSrc->pstg; pMedSrc->pstg->AddRef(); break; default: break; } pMedDest->tymed = pMedSrc->tymed; pMedDest->pUnkForRelease = 0; if (pMedSrc->pUnkForRelease) { pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease; pMedSrc->pUnkForRelease->AddRef(); } }
//获取数据 HRESULT STDMETHODCALLTYPE CImageDataObject::GetData(FORMATETC * pFormatEtcIn, STGMEDIUM * pStgMedium) { //状态判断 ASSERT(m_StgMedium.hBitmap!=NULL); if (m_StgMedium.hBitmap==NULL) return E_HANDLE; //获取数据 HANDLE hHandle=OleDuplicateData(m_StgMedium.hBitmap,CF_BITMAP,0); if (hHandle==NULL) return E_HANDLE; //设置变量 pStgMedium->tymed=TYMED_GDI; pStgMedium->pUnkForRelease=NULL; pStgMedium->hBitmap=(HBITMAP)hHandle; return S_OK; }
/** * Retrieves the data stored in this object and store the result in * pMedium. * * @return IPRT status code. * @return HRESULT * @param pFormatEtc * @param pMedium */ STDMETHODIMP UIDnDDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium) { AssertPtrReturn(pFormatEtc, DV_E_FORMATETC); AssertPtrReturn(pMedium, DV_E_FORMATETC); HRESULT hr = DV_E_FORMATETC; LPFORMATETC pThisFormat = NULL; LPSTGMEDIUM pThisMedium = NULL; LogFlowThisFunc(("\n")); /* Format supported? */ ULONG lIndex; if ( LookupFormatEtc(pFormatEtc, &lIndex) && lIndex < m_cFormats) /* Paranoia. */ { pThisMedium = &m_pStgMedium[lIndex]; AssertPtr(pThisMedium); pThisFormat = &m_pFormatEtc[lIndex]; AssertPtr(pThisFormat); LogFlowThisFunc(("pThisMedium=%p, pThisFormat=%p\n", pThisMedium, pThisFormat)); LogFlowThisFunc(("mStatus=%RU32\n", m_enmStatus)); switch (m_enmStatus) { case DnDDataObjectStatus_Dropping: { #if 0 LogRel3(("DnD: Dropping\n")); LogFlowFunc(("Waiting for event ...\n")); int rc2 = RTSemEventWait(m_SemEvent, RT_INDEFINITE_WAIT); LogFlowFunc(("rc=%Rrc, mStatus=%RU32\n", rc2, m_enmStatus)); #endif break; } case DnDDataObjectStatus_Dropped: { LogRel3(("DnD: Dropped\n")); LogRel3(("DnD: cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32\n", pThisFormat->cfFormat, UIDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat), pThisFormat->tymed, pThisFormat->dwAspect)); LogRel3(("DnD: Got strFormat=%s, pvData=%p, cbData=%RU32\n", m_strFormat.toUtf8().constData(), m_pvData, m_cbData)); QVariant::Type vaType; QString strMIMEType; if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && ( pFormatEtc->cfFormat == CF_TEXT || pFormatEtc->cfFormat == CF_UNICODETEXT) ) { strMIMEType = "text/plain"; /** @todo Indicate UTF8 encoding? */ vaType = QVariant::String; } else if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_HDROP)) { strMIMEType = "text/uri-list"; vaType = QVariant::StringList; } #if 0 /* More formats; not needed right now. */ else if ( (pFormatEtc->tymed & TYMED_ISTREAM) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_FILECONTENTS)) { } else if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_FILEDESCRIPTOR)) { } else if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->cfFormat == CF_PREFERREDDROPEFFECT)) { HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD)); DWORD *pdwEffect = (DWORD *)GlobalLock(hData); AssertPtr(pdwEffect); *pdwEffect = DROPEFFECT_COPY; GlobalUnlock(hData); pMedium->hGlobal = hData; pMedium->tymed = TYMED_HGLOBAL; } #endif LogRel3(("DnD: strMIMEType=%s, vaType=%ld\n", strMIMEType.toUtf8().constData(), vaType)); int rc; if (!m_fDataRetrieved) { if (m_pDnDHandler) { rc = m_pDnDHandler->retrieveData(Qt::CopyAction, strMIMEType, vaType, m_vaData); } else rc = VERR_NOT_FOUND; m_fDataRetrieved = true; LogFlowFunc(("Retrieving data ended with %Rrc\n", rc)); } else /* Data already been retrieved. */ rc = VINF_SUCCESS; if ( RT_SUCCESS(rc) && m_vaData.isValid()) { if ( strMIMEType.startsWith("text/uri-list") /* One item. */ && ( m_vaData.canConvert(QVariant::String) /* Multiple items. */ || m_vaData.canConvert(QVariant::StringList)) ) { QStringList lstFilesURI = m_vaData.toStringList(); QStringList lstFiles; for (size_t i = 0; i < lstFilesURI.size(); i++) { char *pszFilePath = RTUriFilePath(lstFilesURI.at(i).toUtf8().constData()); if (pszFilePath) { lstFiles.append(pszFilePath); RTStrFree(pszFilePath); } else /* Unable to parse -- refuse entire request. */ { lstFiles.clear(); rc = VERR_INVALID_PARAMETER; break; } } size_t cFiles = lstFiles.size(); LogFlowThisFunc(("Files (%zu)\n", cFiles)); if ( RT_SUCCESS(rc) && cFiles) { size_t cchFiles = 0; /* Number of characters. */ for (size_t i = 0; i < cFiles; i++) { const char *pszFile = lstFiles.at(i).toUtf8().constData(); cchFiles += strlen(pszFile); cchFiles += 1; /* Terminating '\0'. */ LogFlowThisFunc(("\tFile: %s (cchFiles=%zu)\n", pszFile, cchFiles)); } /* List termination with '\0'. */ cchFiles++; size_t cbBuf = sizeof(DROPFILES) + (cchFiles * sizeof(RTUTF16)); DROPFILES *pDropFiles = (DROPFILES *)RTMemAllocZ(cbBuf); if (pDropFiles) { /* Put the files list right after our DROPFILES structure. */ pDropFiles->pFiles = sizeof(DROPFILES); /* Offset to file list. */ pDropFiles->fWide = 1; /* We use Unicode. Always. */ uint8_t *pCurFile = (uint8_t *)pDropFiles + pDropFiles->pFiles; AssertPtr(pCurFile); LogFlowThisFunc(("Encoded:\n")); for (size_t i = 0; i < cFiles; i++) { const char *pszFile = lstFiles.at(i).toUtf8().constData(); Assert(strlen(pszFile)); size_t cchCurFile; PRTUTF16 pwszFile; rc = RTStrToUtf16(pszFile, &pwszFile); if (RT_SUCCESS(rc)) { cchCurFile = RTUtf16Len(pwszFile); Assert(cchCurFile); memcpy(pCurFile, pwszFile, cchCurFile * sizeof(RTUTF16)); RTUtf16Free(pwszFile); } else break; pCurFile += cchCurFile * sizeof(RTUTF16); /* Terminate current file name. */ *pCurFile = L'\0'; pCurFile += sizeof(RTUTF16); LogFlowThisFunc(("\t#%zu: cchCurFile=%zu\n", i, cchCurFile)); } if (RT_SUCCESS(rc)) { *pCurFile = L'\0'; /* Final list terminator. */ /* * Fill out the medium structure we're going to report back. */ pMedium->tymed = TYMED_HGLOBAL; pMedium->pUnkForRelease = NULL; pMedium->hGlobal = GlobalAlloc( GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, cbBuf); if (pMedium->hGlobal) { LPVOID pvMem = GlobalLock(pMedium->hGlobal); if (pvMem) { memcpy(pvMem, pDropFiles, cbBuf); GlobalUnlock(pMedium->hGlobal); hr = S_OK; } else rc = VERR_ACCESS_DENIED; } else rc = VERR_NO_MEMORY; LogFlowThisFunc(("Copying to TYMED_HGLOBAL (%zu bytes): %Rrc\n", cbBuf, rc)); } RTMemFree(pDropFiles); } else rc = VERR_NO_MEMORY; if (RT_FAILURE(rc)) LogFlowThisFunc(("Failed with %Rrc\n", rc)); } } else if ( strMIMEType.startsWith("text/plain") && m_vaData.canConvert(QVariant::String)) { const bool fUnicode = pFormatEtc->cfFormat == CF_UNICODETEXT; const size_t cbCh = fUnicode ? sizeof(WCHAR) : sizeof(char); QString strText = m_vaData.toString(); size_t cbSrc = strText.length() * cbCh; Assert(cbSrc); LPCVOID pvSrc = fUnicode ? (void *)strText.unicode() : (void *)strText.toUtf8().constData(); AssertPtr(pvSrc); LogFlowFunc(("pvSrc=0x%p, cbSrc=%zu, cbCh=%zu, fUnicode=%RTbool\n", pvSrc, cbSrc, cbCh, fUnicode)); pMedium->tymed = TYMED_HGLOBAL; pMedium->pUnkForRelease = NULL; pMedium->hGlobal = GlobalAlloc(GHND | GMEM_SHARE, cbSrc); if (pMedium->hGlobal) { LPVOID pvDst = GlobalLock(pMedium->hGlobal); if (pvDst) { memcpy(pvDst, pvSrc, cbSrc); GlobalUnlock(pMedium->hGlobal); } else rc = VERR_ACCESS_DENIED; hr = S_OK; } else hr = VERR_NO_MEMORY; } else LogRel2(("DnD: MIME type '%s' not supported\n", strMIMEType.toUtf8().constData())); LogFlowThisFunc(("Handling formats ended with rc=%Rrc\n", rc)); } break; } default: break; } } /* * Fallback in error case. */ if (FAILED(hr)) { if (pThisMedium) { switch (pThisMedium->tymed) { case TYMED_HGLOBAL: pMedium->hGlobal = (HGLOBAL)OleDuplicateData(pThisMedium->hGlobal, pThisFormat->cfFormat, 0 /* Flags */); break; default: break; } } if (pFormatEtc) pMedium->tymed = pFormatEtc->tymed; pMedium->pUnkForRelease = NULL; } LogFlowThisFunc(("Returning hr=%Rhrc\n", hr)); return hr; }
BOOL AFXAPI _AfxCopyStgMedium( CLIPFORMAT cfFormat, LPSTGMEDIUM lpDest, LPSTGMEDIUM lpSource) { if (lpDest->tymed == TYMED_NULL) { ASSERT(lpSource->tymed != TYMED_NULL); switch (lpSource->tymed) { case TYMED_ENHMF: case TYMED_HGLOBAL: ASSERT(sizeof(HGLOBAL) == sizeof(HENHMETAFILE)); lpDest->tymed = lpSource->tymed; lpDest->hGlobal = NULL; break; // fall through to CopyGlobalMemory case case TYMED_ISTREAM: lpDest->pstm = lpSource->pstm; lpDest->pstm->AddRef(); lpDest->tymed = TYMED_ISTREAM; return TRUE; case TYMED_ISTORAGE: lpDest->pstg = lpSource->pstg; lpDest->pstg->AddRef(); lpDest->tymed = TYMED_ISTORAGE; return TRUE; case TYMED_MFPICT: { // copy LPMETAFILEPICT struct + embedded HMETAFILE HGLOBAL hDest = _AfxCopyGlobalMemory(NULL, lpSource->hGlobal); if (hDest == NULL) return FALSE; LPMETAFILEPICT lpPict = (LPMETAFILEPICT)::GlobalLock(hDest); ASSERT(lpPict != NULL); lpPict->hMF = ::CopyMetaFile(lpPict->hMF, NULL); if (lpPict->hMF == NULL) { ::GlobalUnlock(hDest); ::GlobalFree(hDest); return FALSE; } ::GlobalUnlock(hDest); // fill STGMEDIUM struct lpDest->hGlobal = hDest; lpDest->tymed = TYMED_MFPICT; } return TRUE; case TYMED_GDI: lpDest->tymed = TYMED_GDI; lpDest->hGlobal = NULL; break; case TYMED_FILE: { USES_CONVERSION; lpDest->tymed = TYMED_FILE; ASSERT(lpSource->lpszFileName != NULL); UINT cbSrc = ocslen(lpSource->lpszFileName); LPOLESTR szFileName = (LPOLESTR)CoTaskMemAlloc(cbSrc*sizeof(OLECHAR)); lpDest->lpszFileName = szFileName; if (szFileName == NULL) return FALSE; memcpy(szFileName, lpSource->lpszFileName, (cbSrc+1)*sizeof(OLECHAR)); return TRUE; } // unable to create + copy other TYMEDs default: return FALSE; } } ASSERT(lpDest->tymed == lpSource->tymed); switch (lpSource->tymed) { case TYMED_HGLOBAL: { HGLOBAL hDest = _AfxCopyGlobalMemory(lpDest->hGlobal, lpSource->hGlobal); if (hDest == NULL) return FALSE; lpDest->hGlobal = hDest; } return TRUE; case TYMED_ISTREAM: { ASSERT(lpDest->pstm != NULL); ASSERT(lpSource->pstm != NULL); // get the size of the source stream STATSTG stat; if (lpSource->pstm->Stat(&stat, STATFLAG_NONAME) != S_OK) { // unable to get size of source stream return FALSE; } ASSERT(stat.pwcsName == NULL); // always seek to zero before copy LARGE_INTEGER zero = { 0, 0 }; lpDest->pstm->Seek(zero, STREAM_SEEK_SET, NULL); lpSource->pstm->Seek(zero, STREAM_SEEK_SET, NULL); // copy source to destination if (lpSource->pstm->CopyTo(lpDest->pstm, stat.cbSize, NULL, NULL) != NULL) { // copy from source to dest failed return FALSE; } // always seek to zero after copy lpDest->pstm->Seek(zero, STREAM_SEEK_SET, NULL); lpSource->pstm->Seek(zero, STREAM_SEEK_SET, NULL); } return TRUE; case TYMED_ISTORAGE: { ASSERT(lpDest->pstg != NULL); ASSERT(lpSource->pstg != NULL); // just copy source to destination if (lpSource->pstg->CopyTo(0, NULL, NULL, lpDest->pstg) != S_OK) return FALSE; } return TRUE; case TYMED_FILE: { USES_CONVERSION; ASSERT(lpSource->lpszFileName != NULL); ASSERT(lpDest->lpszFileName != NULL); return CopyFile(OLE2T(lpSource->lpszFileName), OLE2T(lpDest->lpszFileName), FALSE); } case TYMED_ENHMF: case TYMED_GDI: { ASSERT(sizeof(HGLOBAL) == sizeof(HENHMETAFILE)); // with TYMED_GDI cannot copy into existing HANDLE if (lpDest->hGlobal != NULL) return FALSE; // otherwise, use OleDuplicateData for the copy lpDest->hGlobal = OleDuplicateData(lpSource->hGlobal, cfFormat, 0); if (lpDest->hGlobal == NULL) return FALSE; } return TRUE; // other TYMEDs cannot be copied default: return FALSE; } }
/** * Retrieves the data stored in this object and store the result in * pMedium. * * @return IPRT status code. * @return HRESULT * @param pFormatEtc * @param pMedium */ STDMETHODIMP UIDnDDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium) { AssertPtrReturn(pFormatEtc, DV_E_FORMATETC); AssertPtrReturn(pMedium, DV_E_FORMATETC); HRESULT hr = DV_E_FORMATETC; LPFORMATETC pThisFormat = NULL; LPSTGMEDIUM pThisMedium = NULL; /* Format supported? */ ULONG lIndex; if ( LookupFormatEtc(pFormatEtc, &lIndex) && lIndex < mcFormats) /* Paranoia. */ { pThisMedium = &mpStgMedium[lIndex]; AssertPtr(pThisMedium); pThisFormat = &mpFormatEtc[lIndex]; AssertPtr(pThisFormat); LogFlowFunc(("pThisMedium=%p, pThisFormat=%p\n", pThisMedium, pThisFormat)); LogFlowFunc(("mStatus=%ld\n", mStatus)); switch (mStatus) { case Dropping: { LogRel3(("DnD: Dropping\n")); LogFlowFunc(("Waiting for event ...\n")); int rc2 = RTSemEventWait(mSemEvent, RT_INDEFINITE_WAIT); LogFlowFunc(("rc=%Rrc, mStatus=%ld\n", rc2, mStatus)); } case Dropped: { LogRel3(("DnD: Dropped\n")); LogRel3(("DnD: cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32\n", pThisFormat->cfFormat, UIDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat), pThisFormat->tymed, pThisFormat->dwAspect)); LogRel3(("DnD: Got strFormat=%s, pvData=%p, cbData=%RU32\n", mstrFormat.toAscii().constData(), mpvData, mcbData)); QVariant::Type vaType; QString strMIMEType; if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && ( pFormatEtc->cfFormat == CF_TEXT || pFormatEtc->cfFormat == CF_UNICODETEXT) ) { strMIMEType = "text/plain"; /** @todo Indicate UTF8 encoding? */ vaType = QVariant::String; } else if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_HDROP)) { strMIMEType = "text/uri-list"; vaType = QVariant::StringList; } #if 0 /* More formats; not needed right now. */ else if ( (pFormatEtc->tymed & TYMED_ISTREAM) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_FILECONTENTS)) { } else if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_FILEDESCRIPTOR)) { } else if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->cfFormat == CF_PREFERREDDROPEFFECT)) { HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD)); DWORD *pdwEffect = (DWORD *)GlobalLock(hData); AssertPtr(pdwEffect); *pdwEffect = DROPEFFECT_COPY; GlobalUnlock(hData); pMedium->hGlobal = hData; pMedium->tymed = TYMED_HGLOBAL; } #endif LogRel3(("DnD: strMIMEType=%s, vaType=%ld\n", strMIMEType.toAscii().constData(), vaType)); int rc; if (!mVaData.isValid()) { /* Note: We're usig Qt::MoveAction because this speeds up the whole operation * significantly: Instead of copying the data from the temporary location to * the final destination we just move it. * * Note2: The Qt::MoveAction *only* affects the behavior on the host! The desired * action for the guest (e.g. moving a file from guest to host) is not affected * by this setting. */ rc = m_pDnDHandler->retrieveData(Qt::MoveAction, strMIMEType, vaType, mVaData); } else rc = VINF_SUCCESS; /* Data already retrieved. */ if (RT_SUCCESS(rc)) { if ( strMIMEType.startsWith("text/uri-list") /* One item. */ && ( mVaData.canConvert(QVariant::String) /* Multiple items. */ || mVaData.canConvert(QVariant::StringList)) ) { QStringList lstFilesURI = mVaData.toStringList(); QStringList lstFiles; for (size_t i = 0; i < lstFilesURI.size(); i++) { /* Extract path from URI. */ char *pszPath = RTUriPath(lstFilesURI.at(i).toAscii().constData()); if ( pszPath && strlen(pszPath) > 1) { pszPath++; /** @todo Skip first '/' (part of URI). Correct? */ pszPath = RTPathChangeToDosSlashes(pszPath, false /* fForce */); lstFiles.append(pszPath); } } size_t cFiles = lstFiles.size(); Assert(cFiles); #ifdef DEBUG LogFlowFunc(("Files (%zu)\n", cFiles)); for (size_t i = 0; i < cFiles; i++) LogFlowFunc(("\tFile: %s\n", lstFiles.at(i).toAscii().constData())); #endif size_t cchFiles = 0; /* Number of ASCII characters. */ for (size_t i = 0; i < cFiles; i++) { cchFiles += strlen(lstFiles.at(i).toAscii().constData()); cchFiles += 1; /* Terminating '\0'. */ } size_t cbBuf = sizeof(DROPFILES) + ((cchFiles + 1) * sizeof(RTUTF16)); DROPFILES *pDropFiles = (DROPFILES *)RTMemAllocZ(cbBuf); if (pDropFiles) { pDropFiles->pFiles = sizeof(DROPFILES); pDropFiles->fWide = 1; /* We use unicode. Always. */ uint8_t *pCurFile = (uint8_t *)pDropFiles + pDropFiles->pFiles; AssertPtr(pCurFile); for (size_t i = 0; i < cFiles; i++) { size_t cchCurFile; PRTUTF16 pwszFile; rc = RTStrToUtf16(lstFiles.at(i).toAscii().constData(), &pwszFile); if (RT_SUCCESS(rc)) { cchCurFile = RTUtf16Len(pwszFile); Assert(cchCurFile); memcpy(pCurFile, pwszFile, cchCurFile * sizeof(RTUTF16)); RTUtf16Free(pwszFile); } else break; pCurFile += cchCurFile * sizeof(RTUTF16); /* Terminate current file name. */ *pCurFile = L'\0'; pCurFile += sizeof(RTUTF16); } if (RT_SUCCESS(rc)) { *pCurFile = L'\0'; /* Final list terminator. */ pMedium->tymed = TYMED_HGLOBAL; pMedium->pUnkForRelease = NULL; pMedium->hGlobal = GlobalAlloc( GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, cbBuf); if (pMedium->hGlobal) { LPVOID pvMem = GlobalLock(pMedium->hGlobal); if (pvMem) { memcpy(pvMem, pDropFiles, cbBuf); GlobalUnlock(pMedium->hGlobal); hr = S_OK; } else rc = VERR_ACCESS_DENIED; } else rc = VERR_NO_MEMORY; } RTMemFree(pDropFiles); } } else if ( strMIMEType.startsWith("text/plain") && mVaData.canConvert(QVariant::String)) { bool fUnicode = pFormatEtc->cfFormat == CF_UNICODETEXT; int cbCh = fUnicode ? sizeof(WCHAR) : sizeof(char); QString strText = mVaData.toString(); size_t cbSrc = strText.length() * cbCh; Assert(cbSrc); LPCVOID pvSrc = fUnicode ? (void *)strText.unicode() : (void *)strText.toAscii().constData(); AssertPtr(pvSrc); LogFlowFunc(("pvSrc=0x%p, cbSrc=%zu, cbch=%d, fUnicode=%RTbool\n", pvSrc, cbSrc, cbCh, fUnicode)); pMedium->tymed = TYMED_HGLOBAL; pMedium->pUnkForRelease = NULL; pMedium->hGlobal = GlobalAlloc( GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, cbSrc); if (pMedium->hGlobal) { LPVOID pvDst = GlobalLock(pMedium->hGlobal); if (pvDst) { memcpy(pvDst, pvSrc, cbSrc); GlobalUnlock(pMedium->hGlobal); } else rc = VERR_ACCESS_DENIED; hr = S_OK; } else hr = VERR_NO_MEMORY; } else LogFlowFunc(("MIME type=%s not supported\n", strMIMEType.toAscii().constData())); LogFlowFunc(("Handling formats ended with rc=%Rrc\n", rc)); } } default: break; } } /* * Fallback in error case. */ if (FAILED(hr)) { if (pThisMedium) { switch (pThisMedium->tymed) { case TYMED_HGLOBAL: pMedium->hGlobal = (HGLOBAL)OleDuplicateData(pThisMedium->hGlobal, pThisFormat->cfFormat, 0 /* Flags */); break; default: break; } } if (pFormatEtc) pMedium->tymed = pFormatEtc->tymed; pMedium->pUnkForRelease = NULL; } LogFlowFunc(("Returning hr=%Rhrc\n", hr)); return hr; }
/** * Retrieves the data stored in this object and store the result in * pMedium. * * @return IPRT status code. * @return HRESULT * @param pFormatEtc * @param pMedium */ STDMETHODIMP VBoxDnDDataObject::GetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium) { AssertPtrReturn(pFormatEtc, DV_E_FORMATETC); AssertPtrReturn(pMedium, DV_E_FORMATETC); ULONG lIndex; if (!LookupFormatEtc(pFormatEtc, &lIndex)) /* Format supported? */ return DV_E_FORMATETC; if (lIndex >= mcFormats) /* Paranoia. */ return DV_E_FORMATETC; LogFlowFunc(("pFormatEtc=%p, pMedium=%p\n", pFormatEtc, pMedium)); FORMATETC *pThisFormat = &mpFormatEtc[lIndex]; AssertPtr(pThisFormat); STGMEDIUM *pThisMedium = &mpStgMedium[lIndex]; AssertPtr(pThisMedium); HRESULT hr = DV_E_FORMATETC; LogFlowFunc(("mStatus=%ld\n", mStatus)); if (mStatus == Dropping) { LogFlowFunc(("Waiting for event ...\n")); int rc2 = RTSemEventWait(mSemEvent, RT_INDEFINITE_WAIT); LogFlowFunc(("rc=%Rrc, mStatus=%ld\n", rc2, mStatus)); } if (mStatus == Dropped) { LogFlowFunc(("cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32\n", pThisFormat->cfFormat, VBoxDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat), pThisFormat->tymed, pThisFormat->dwAspect)); LogFlowFunc(("Got strFormat=%s, pvData=%p, cbData=%RU32\n", mstrFormat.c_str(), mpvData, mcbData)); if (mstrFormat.equalsIgnoreCase("text/uri-list")) { RTCList<RTCString> lstFilesURI = RTCString((char*)mpvData, mcbData).split("\r\n"); RTCList<RTCString> lstFiles; for (size_t i = 0; i < lstFilesURI.size(); i++) { /* Extract path from URI. */ char *pszPath = RTUriPath(lstFilesURI.at(i).c_str()); if ( pszPath && strlen(pszPath) > 1) { pszPath++; /** @todo Skip first '/' (part of URI). Correct? */ pszPath = RTPathChangeToDosSlashes(pszPath, false /* fForce */); lstFiles.append(pszPath); } } #ifdef DEBUG LogFlowFunc(("Files (%zu)\n", lstFiles.size())); for (size_t i = 0; i < lstFiles.size(); i++) LogFlowFunc(("\tFile: %s\n", lstFiles.at(i).c_str())); #endif #if 0 if ( (pFormatEtc->tymed & TYMED_ISTREAM) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_FILECONTENTS)) { } else if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_FILEDESCRIPTOR)) { } else if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->cfFormat == CF_PREFERREDDROPEFFECT)) { HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD)); DWORD *pdwEffect = (DWORD *)GlobalLock(hData); AssertPtr(pdwEffect); *pdwEffect = DROPEFFECT_COPY; GlobalUnlock(hData); pMedium->hGlobal = hData; pMedium->tymed = TYMED_HGLOBAL; } else #endif if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_TEXT)) { pMedium->hGlobal = GlobalAlloc(GHND, mcbData + 1); if (pMedium->hGlobal) { /** @todo Not working yet -- needs URI to plain ASCII conversion. */ char *pcDst = (char *)GlobalLock(pMedium->hGlobal); memcpy(pcDst, mpvData, mcbData); pcDst[mcbData] = '\0'; GlobalUnlock(pMedium->hGlobal); hr = S_OK; } } else if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_HDROP)) { int rc = VINF_SUCCESS; size_t cchFiles = 0; /* Number of ASCII characters. */ for (size_t i = 0; i < lstFiles.size(); i++) { cchFiles += strlen(lstFiles.at(i).c_str()); cchFiles += 1; /* Terminating '\0'. */ } size_t cbBuf = sizeof(DROPFILES) + ((cchFiles + 1) * sizeof(RTUTF16)); DROPFILES *pBuf = (DROPFILES *)RTMemAllocZ(cbBuf); if (pBuf) { pBuf->pFiles = sizeof(DROPFILES); pBuf->fWide = 1; /* We use unicode. Always. */ uint8_t *pCurFile = (uint8_t *)pBuf + pBuf->pFiles; AssertPtr(pCurFile); for (size_t i = 0; i < lstFiles.size() && RT_SUCCESS(rc); i++) { size_t cchCurFile; PRTUTF16 pwszFile; rc = RTStrToUtf16(lstFiles.at(i).c_str(), &pwszFile); if (RT_SUCCESS(rc)) { cchCurFile = RTUtf16Len(pwszFile); Assert(cchCurFile); memcpy(pCurFile, pwszFile, cchCurFile * sizeof(RTUTF16)); RTUtf16Free(pwszFile); } else break; pCurFile += cchCurFile * sizeof(RTUTF16); /* Terminate current file name. */ *pCurFile = L'\0'; pCurFile += sizeof(RTUTF16); } if (RT_SUCCESS(rc)) { *pCurFile = L'\0'; /* Final list terminator. */ pMedium->tymed = TYMED_HGLOBAL; pMedium->pUnkForRelease = NULL; pMedium->hGlobal = GlobalAlloc( GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, cbBuf); if (pMedium->hGlobal) { LPVOID pMem = GlobalLock(pMedium->hGlobal); if (pMem) { memcpy(pMem, pBuf, cbBuf); GlobalUnlock(pMedium->hGlobal); hr = S_OK; } } } RTMemFree(pBuf); } else rc = VERR_NO_MEMORY; if (RT_FAILURE(rc)) hr = DV_E_FORMATETC; } } } if (FAILED(hr)) { LogFlowFunc(("Copying medium ...\n")); switch (pThisMedium->tymed) { case TYMED_HGLOBAL: pMedium->hGlobal = (HGLOBAL)OleDuplicateData(pThisMedium->hGlobal, pThisFormat->cfFormat, NULL); break; default: break; } pMedium->tymed = pThisFormat->tymed; pMedium->pUnkForRelease = NULL; } LogFlowFunc(("hr=%Rhrc\n", hr)); return hr; }