HRESULT BuildHDropList(FORMATETC *pftc,STGMEDIUM *pstg, const std::list<std::wstring> &FilenameList) { SetFORMATETC(pftc,CF_HDROP,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL); UINT uSize = 0; uSize = sizeof(DROPFILES); for each(auto Filename in FilenameList) { uSize += static_cast<UINT>((Filename.length() + 1) * sizeof(TCHAR)); } /* The last string is double-null terminated. */ uSize += (1 * sizeof(TCHAR)); HGLOBAL hglbHDrop = GlobalAlloc(GMEM_MOVEABLE,uSize); if(hglbHDrop == NULL) { return E_FAIL; } LPVOID pcidaData = static_cast<LPVOID>(GlobalLock(hglbHDrop)); DROPFILES *pdf = static_cast<DROPFILES *>(pcidaData); pdf->pFiles = sizeof(DROPFILES); pdf->fNC = FALSE; pdf->pt.x = 0; pdf->pt.y = 0; pdf->fWide = TRUE; LPBYTE pData; UINT uOffset = 0; TCHAR chNull = '\0'; for each(auto Filename in FilenameList) { pData = static_cast<LPBYTE>(pcidaData) + sizeof(DROPFILES) + uOffset; memcpy(pData,Filename.c_str(),(Filename.length() + 1) * sizeof(TCHAR)); uOffset += static_cast<UINT>((Filename.length() + 1) * sizeof(TCHAR)); }
void Explorerplusplus::OnAddressBarBeginDrag(void) { IDragSourceHelper *pDragSourceHelper = NULL; IDropSource *pDropSource = NULL; HRESULT hr; hr = CoCreateInstance(CLSID_DragDropHelper,NULL,CLSCTX_ALL, IID_IDragSourceHelper,(LPVOID *)&pDragSourceHelper); if(SUCCEEDED(hr)) { hr = CreateDropSource(&pDropSource,DRAG_TYPE_LEFTCLICK); if(SUCCEEDED(hr)) { LPITEMIDLIST pidlDirectory = m_pActiveShellBrowser->QueryCurrentDirectoryIdl(); FORMATETC ftc[2]; STGMEDIUM stg[2]; SetFORMATETC(&ftc[0],(CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR), NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL); HGLOBAL hglb = GlobalAlloc(GMEM_MOVEABLE,1000); FILEGROUPDESCRIPTOR *pfgd = static_cast<FILEGROUPDESCRIPTOR *>(GlobalLock(hglb)); pfgd->cItems = 1; FILEDESCRIPTOR *pfd = (FILEDESCRIPTOR *)((LPBYTE)pfgd + sizeof(UINT)); /* File information (name, size, date created, etc). */ pfd[0].dwFlags = FD_ATTRIBUTES|FD_FILESIZE; pfd[0].dwFileAttributes = FILE_ATTRIBUTE_NORMAL; pfd[0].nFileSizeLow = 16384; pfd[0].nFileSizeHigh = 0; /* The name of the file will be the folder name, followed by .lnk. */ TCHAR szDisplayName[MAX_PATH]; GetDisplayName(pidlDirectory,szDisplayName,SHGDN_INFOLDER); StringCchCat(szDisplayName,SIZEOF_ARRAY(szDisplayName),_T(".lnk")); StringCchCopy(pfd[0].cFileName,SIZEOF_ARRAY(pfd[0].cFileName),szDisplayName); GlobalUnlock(hglb); stg[0].pUnkForRelease = 0; stg[0].hGlobal = hglb; stg[0].tymed = TYMED_HGLOBAL; /* File contents. */ SetFORMATETC(&ftc[1],(CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILECONTENTS), NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL); hglb = GlobalAlloc(GMEM_MOVEABLE,16384); IShellLink *pShellLink = NULL; IPersistStream *pPersistStream = NULL; HRESULT hr; hr = CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER, IID_IShellLink,(LPVOID*)&pShellLink); if(SUCCEEDED(hr)) { TCHAR szPath[MAX_PATH]; GetDisplayName(pidlDirectory,szPath,SHGDN_FORPARSING); pShellLink->SetPath(szPath); hr = pShellLink->QueryInterface(IID_IPersistStream,(LPVOID*)&pPersistStream); if(SUCCEEDED(hr)) { IStream *pStream = NULL; CreateStreamOnHGlobal(hglb,FALSE,&pStream); hr = pPersistStream->Save(pStream,TRUE); } } GlobalUnlock(hglb); stg[1].pUnkForRelease = 0; stg[1].hGlobal = hglb; stg[1].tymed = TYMED_HGLOBAL; IDataObject *pDataObject = NULL; POINT pt = {0,0}; hr = CreateDataObject(ftc,stg,&pDataObject,2); pDragSourceHelper->InitializeFromWindow(m_hAddressBar,&pt,pDataObject); DWORD dwEffect; DoDragDrop(pDataObject,pDropSource,DROPEFFECT_LINK,&dwEffect); CoTaskMemFree(pidlDirectory); pDataObject->Release(); pDropSource->Release(); } pDragSourceHelper->Release(); } }
HRESULT CDropHandler::CopyFileDescriptorData(IDataObject *pDataObject, list<PastedFile_t> *pPastedFileList) { STGMEDIUM stg; HRESULT hr; hr = pDataObject->GetData(&m_ftcFileDescriptor,&stg); if(hr == S_OK) { FILEGROUPDESCRIPTOR *pfgd = (FILEGROUPDESCRIPTOR *)GlobalLock(stg.hGlobal); if(pfgd != NULL) { FILETIME *pftCreationTime = NULL; FILETIME *pftLastAccessTime = NULL; FILETIME *pftLastWriteTime = NULL; DWORD dwFileAttributes = FILE_ATTRIBUTE_NORMAL; DWORD nBytesToWrite = 0; for(unsigned int i = 0;i < pfgd->cItems;i++) { if(pfgd->fgd[i].dwFlags & FD_ATTRIBUTES) { dwFileAttributes = pfgd->fgd[i].dwFileAttributes; } if(pfgd->fgd[i].dwFlags & FD_FILESIZE) { nBytesToWrite = pfgd->fgd[i].nFileSizeLow; } if(pfgd->fgd[i].dwFlags & FD_LINKUI) { /* TODO: Complete. */ } if(pfgd->fgd[i].dwFlags & FD_CREATETIME) { pftCreationTime = &pfgd->fgd[i].ftCreationTime; } if(pfgd->fgd[i].dwFlags & FD_ACCESSTIME) { pftLastAccessTime = &pfgd->fgd[i].ftLastAccessTime; } if(pfgd->fgd[i].dwFlags & FD_WRITESTIME) { pftLastWriteTime = &pfgd->fgd[i].ftLastWriteTime; } /*if(pfgd->fgd[i].dwFlags & FD_UNICODE) { }*/ FORMATETC ftcfchg; FORMATETC ftcfcis; FORMATETC ftcfcstg; STGMEDIUM stgFileContents = {0}; BOOL bDataRetrieved = FALSE; LPBYTE pBuffer = NULL; SetFORMATETC(&ftcfchg,(CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILECONTENTS), NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL); SetFORMATETC(&ftcfcis,(CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILECONTENTS), NULL,DVASPECT_CONTENT,-1,TYMED_ISTREAM); SetFORMATETC(&ftcfcstg,(CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILECONTENTS), NULL,DVASPECT_CONTENT,-1,TYMED_ISTORAGE); if(pDataObject->QueryGetData(&ftcfchg) == S_OK) { ftcfchg.lindex = i; hr = pDataObject->GetData(&ftcfchg,&stgFileContents); if(hr == S_OK) { pBuffer = (LPBYTE)malloc(GlobalSize(stgFileContents.hGlobal) * sizeof(BYTE)); if(pBuffer != NULL) { if(!(pfgd->fgd[i].dwFlags & FD_FILESIZE)) nBytesToWrite = (DWORD)GlobalSize(stgFileContents.hGlobal); LPBYTE pTemp = (LPBYTE)GlobalLock(stgFileContents.hGlobal); if(pTemp != NULL) { memcpy(pBuffer,pTemp,GlobalSize(stgFileContents.hGlobal)); GlobalUnlock(stgFileContents.hGlobal); bDataRetrieved = TRUE; } ReleaseStgMedium(&stgFileContents); } } } else if(pDataObject->QueryGetData(&ftcfcis) == S_OK) { STATSTG sstg; ULONG cbRead; ftcfcis.lindex = i; hr = pDataObject->GetData(&ftcfcis,&stgFileContents); if(hr == S_OK) { hr = stgFileContents.pstm->Stat(&sstg,STATFLAG_NONAME); if(hr == S_OK) { pBuffer = (LPBYTE)malloc(sstg.cbSize.LowPart * sizeof(BYTE)); if(pBuffer != NULL) { /* If the file size isn't explicitly given, use the size of the stream. */ if(!(pfgd->fgd[i].dwFlags & FD_FILESIZE)) nBytesToWrite = sstg.cbSize.LowPart; stgFileContents.pstm->Read(pBuffer,sstg.cbSize.LowPart,&cbRead); bDataRetrieved = TRUE; } } ReleaseStgMedium(&stgFileContents); } } else if(pDataObject->QueryGetData(&ftcfcstg) == S_OK) { IStream *pStream; STATSTG sstg; ULONG cbRead; ftcfcstg.lindex = i; hr = pDataObject->GetData(&ftcfcstg,&stgFileContents); if(hr == S_OK) { hr = stgFileContents.pstg->Stat(&sstg,STATFLAG_DEFAULT); if(hr == S_OK) { hr = stgFileContents.pstg->OpenStream(sstg.pwcsName,NULL, STGM_READ|STGM_SHARE_EXCLUSIVE,0,&pStream); if(hr == S_OK) { CoTaskMemFree(sstg.pwcsName); hr = pStream->Stat(&sstg,STATFLAG_NONAME); if(hr == S_OK) { pBuffer = (LPBYTE)malloc(sstg.cbSize.LowPart * sizeof(BYTE)); if(pBuffer != NULL) { /* If the file size isn't explicitly given, use the size of the stream. */ if(!(pfgd->fgd[i].dwFlags & FD_FILESIZE)) nBytesToWrite = sstg.cbSize.LowPart; pStream->Read(pBuffer,sstg.cbSize.LowPart,&cbRead); bDataRetrieved = TRUE; } } } } ReleaseStgMedium(&stgFileContents); } } if(bDataRetrieved) { TCHAR szFullFileName[MAX_PATH]; StringCchCopy(szFullFileName,SIZEOF_ARRAY(szFullFileName),m_szDestDirectory); PathAppend(szFullFileName,pfgd->fgd[i].cFileName); HANDLE hFile = CreateFile(szFullFileName,GENERIC_WRITE,0,NULL, CREATE_ALWAYS,dwFileAttributes,NULL); if(hFile != INVALID_HANDLE_VALUE) { PastedFile_t pf; DWORD nBytesWritten; SetFileTime(hFile,pftCreationTime,pftLastAccessTime,pftLastWriteTime); WriteFile(hFile,pBuffer,nBytesToWrite,&nBytesWritten,NULL); CloseHandle(hFile); StringCchCopy(pf.szFileName,SIZEOF_ARRAY(pf.szFileName),szFullFileName); PathStripPath(pf.szFileName); pPastedFileList->push_back(pf); } HGLOBAL hglb = NULL; DWORD *pdwCopyEffect = NULL; FORMATETC ftc; STGMEDIUM stg1; ftc.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT); ftc.ptd = NULL; ftc.dwAspect = DVASPECT_CONTENT; ftc.lindex = -1; ftc.tymed = TYMED_HGLOBAL; hglb = GlobalAlloc(GMEM_MOVEABLE,sizeof(DWORD)); pdwCopyEffect = (DWORD *)GlobalLock(hglb); *pdwCopyEffect = DROPEFFECT_COPY; GlobalUnlock(hglb); stg1.tymed = TYMED_HGLOBAL; stg1.pUnkForRelease = 0; stg1.hGlobal = hglb; pDataObject->SetData(&ftc,&stg1,FALSE); } if(pBuffer != NULL) { free(pBuffer); } } GlobalUnlock(stg.hGlobal); } ReleaseStgMedium(&stg); } return hr; }
void CDropHandler::HandleLeftClickDrop(IDataObject *pDataObject,POINTL *pptl) { FORMATETC ftc; STGMEDIUM stg; DWORD *pdwEffect = NULL; DWORD dwEffect = DROPEFFECT_NONE; BOOL bPrefferedEffect = FALSE; POINT pt; pt.x = pptl->x; pt.y = pptl->y; SetFORMATETC(&ftc,(CLIPFORMAT)RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT), NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL); /* Check if the data has a preffered drop effect (i.e. copy or move). */ HRESULT hr = pDataObject->GetData(&ftc,&stg); if(hr == S_OK) { pdwEffect = (DWORD *)GlobalLock(stg.hGlobal); if(pdwEffect != NULL) { if(*pdwEffect != DROPEFFECT_NONE) { dwEffect = *pdwEffect; bPrefferedEffect = TRUE; GlobalUnlock(stg.hGlobal); } } ReleaseStgMedium(&stg); } HRESULT hrCopy = E_FAIL; list<PastedFile_t> PastedFileList; if(pDataObject->QueryGetData(&m_ftcHDrop) == S_OK) { hrCopy = CopyHDropData(pDataObject,bPrefferedEffect,dwEffect, &PastedFileList); } else if(pDataObject->QueryGetData(&m_ftcShellIDList) == S_OK) { hrCopy = CopyShellIDListData(pDataObject,&PastedFileList); } else if(pDataObject->QueryGetData(&m_ftcFileDescriptor) == S_OK) { hrCopy = CopyFileDescriptorData(pDataObject,&PastedFileList); } else if(pDataObject->QueryGetData(&m_ftcUnicodeText) == S_OK) { hrCopy = CopyUnicodeTextData(pDataObject,&PastedFileList); } else if(pDataObject->QueryGetData(&m_ftcText) == S_OK) { hrCopy = CopyAnsiTextData(pDataObject,&PastedFileList); } else if(pDataObject->QueryGetData(&m_ftcDIBV5) == S_OK) { hrCopy = CopyDIBV5Data(pDataObject,&PastedFileList); } if(hrCopy == S_OK && PastedFileList.size() > 0) { /* The data was copied successfully, so notify the caller via the specified callback interface. */ if(m_pDropFilesCallback != NULL) m_pDropFilesCallback->OnDropFile(&PastedFileList,&pt); } }