#include "stdafx.h" static void ProcessDroppedItems(char **ppDroppedItems, int nCount, char **ppFiles); static int CountDroppedFiles(char **ppDroppedItems, int nCount); static BOOL OnDropFiles(HDROP hDrop, ThumbInfo *pThumb); HRESULT STDMETHODCALLTYPE CDropTarget::QueryInterface(REFIID riid, LPVOID *ppvObj) { if (IsEqualIID(riid, IID_IDropTarget)) { *ppvObj = this; this->AddRef(); return S_OK; } *ppvObj = nullptr; return (E_NOINTERFACE); } ULONG STDMETHODCALLTYPE CDropTarget::AddRef() { return ++this->refCount; } ULONG STDMETHODCALLTYPE CDropTarget::Release() { int res = --this->refCount; if (!res) delete this; return res; } HRESULT STDMETHODCALLTYPE CDropTarget::DragOver(DWORD, POINTL, DWORD *pdwEffect) { *pdwEffect = 0; if (hwndCurDrag == nullptr) { *pdwEffect = DROPEFFECT_NONE; } else { *pdwEffect |= DROPEFFECT_COPY; } return S_OK; } HRESULT STDMETHODCALLTYPE CDropTarget::DragEnter(IDataObject *pData, DWORD fKeyState, POINTL pt, DWORD *pdwEffect) { FORMATETC feFile = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; FORMATETC feText = { CF_TEXT, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; if (S_OK == pData->QueryGetData(&feFile) || S_OK == pData->QueryGetData(&feText)) { POINT shortPt; shortPt.x = pt.x; shortPt.y = pt.y; HWND hwnd = WindowFromPoint(shortPt); ThumbInfo *pThumb = thumbList.FindThumb(hwnd); if (pThumb) { hwndCurDrag = hwnd; pThumb->ThumbSelect(TRUE); } } return DragOver(fKeyState, pt, pdwEffect); } HRESULT STDMETHODCALLTYPE CDropTarget::DragLeave() { ThumbInfo *pThumb = thumbList.FindThumb(hwndCurDrag); if (nullptr != pThumb) { pThumb->ThumbDeselect(TRUE); } hwndCurDrag = nullptr; return S_OK; } HRESULT STDMETHODCALLTYPE CDropTarget::Drop(IDataObject *pData, DWORD, POINTL, DWORD *pdwEffect) { FORMATETC fe = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; *pdwEffect = DROPEFFECT_NONE; if (hwndCurDrag == nullptr) return S_OK; ThumbInfo *pThumb = (ThumbInfo*)GetWindowLongPtr(hwndCurDrag, GWLP_USERDATA); if (pThumb == nullptr) return S_OK; STGMEDIUM stg; bool bFormatText = false; if (S_OK != pData->GetData(&fe, &stg)) { fe.cfFormat = CF_UNICODETEXT; if (S_OK != pData->GetData(&fe, &stg)) { return S_OK; } else { bFormatText = true; } } if (!bFormatText) { HDROP hDrop = (HDROP)stg.hGlobal; if (hDrop != nullptr) { OnDropFiles(hDrop, pThumb); } } else { wchar_t *pText = (wchar_t*)GlobalLock(stg.hGlobal); if (pText != nullptr) { SendMsgDialog(hwndCurDrag, pText); GlobalUnlock(stg.hGlobal); } } if (stg.pUnkForRelease != nullptr) { stg.pUnkForRelease->Release(); } else { GlobalFree(stg.hGlobal); } DragLeave(); return S_OK; } /////////////////////////////////////////////////////// // Send files processing BOOL OnDropFiles(HDROP hDrop, ThumbInfo *pThumb) { UINT nDroppedItemsCount = DragQueryFile(hDrop, 0xFFFFFFFF, nullptr, 0); char **ppDroppedItems = (char**)malloc(sizeof(char*)*(nDroppedItemsCount + 1)); if (ppDroppedItems == nullptr) { return FALSE; } ppDroppedItems[nDroppedItemsCount] = nullptr; char szFilename[MAX_PATH]; for (UINT iItem = 0; iItem < nDroppedItemsCount; ++iItem) { DragQueryFileA(hDrop, iItem, szFilename, sizeof(szFilename)); ppDroppedItems[iItem] = _strdup(szFilename); } UINT nFilesCount = CountDroppedFiles(ppDroppedItems, nDroppedItemsCount); char **ppFiles = (char**)malloc(sizeof(char *)* (nFilesCount + 1)); BOOL bSuccess = FALSE; if (ppFiles != nullptr) { ppFiles[nFilesCount] = nullptr; ProcessDroppedItems(ppDroppedItems, nDroppedItemsCount, ppFiles); bSuccess = (BOOL)CallService(MS_FILE_SENDSPECIFICFILES, pThumb->hContact, (LPARAM)ppFiles); for (UINT iItem = 0; iItem < nFilesCount; ++iItem) free(ppFiles[iItem]); free(ppFiles); } // Cleanup for (UINT iItem = 0; ppDroppedItems[iItem]; ++iItem) { free(ppDroppedItems[iItem]); } free(ppDroppedItems); return bSuccess; } static int CountFiles(char *szItem) { int nCount = 0; WIN32_FIND_DATAA fd; HANDLE hFind = FindFirstFileA(szItem, &fd); if (hFind != INVALID_HANDLE_VALUE) { do { if (fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) { // Skip parent directories if ((0 != mir_strcmp(fd.cFileName, ".")) && (0 != mir_strcmp(fd.cFileName, ".."))) { char szDirName[MAX_PATH]; strncpy(szDirName, szItem, MAX_PATH - 1); if (nullptr != strstr(szItem, "*.*")) { size_t offset = mir_strlen(szDirName) - 3; mir_snprintf(szDirName + offset, _countof(szDirName) - offset, "%s\0", fd.cFileName); } ++nCount; mir_strcat(szDirName, "\\*.*"); nCount += CountFiles(szDirName); } } else { ++nCount; } } while (FALSE != FindNextFileA(hFind, &fd)); } return nCount; } static void SaveFiles(char *szItem, char **ppFiles, int *pnCount) { WIN32_FIND_DATAA fd; HANDLE hFind = FindFirstFileA(szItem, &fd); if (hFind != INVALID_HANDLE_VALUE) { do { if (fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) { // Skip parent directories if ((0 != mir_strcmp(fd.cFileName, ".")) && (0 != mir_strcmp(fd.cFileName, ".."))) { char szDirName[MAX_PATH]; strncpy(szDirName, szItem, MAX_PATH - 1); if (nullptr != strstr(szItem, "*.*")) { size_t offset = mir_strlen(szDirName) - 3; mir_snprintf(szDirName + offset, _countof(szDirName) - offset, "%s\0", fd.cFileName); } ppFiles[*pnCount] = _strdup(szDirName); ++(*pnCount); mir_strcat(szDirName, "\\*.*"); SaveFiles(szDirName, ppFiles, pnCount); } } else { size_t nSize = sizeof(char) * (mir_strlen(szItem) + mir_strlen(fd.cFileName) + sizeof(char)); char *szFile = (char*)malloc(nSize); strncpy(szFile, szItem, nSize - 1); if (nullptr != strstr(szFile, "*.*")) { szFile[mir_strlen(szFile) - 3] = '\0'; mir_strncat(szFile, fd.cFileName, nSize - mir_strlen(szFile)); } ppFiles[*pnCount] = szFile; ++(*pnCount); } } while (FALSE != FindNextFileA(hFind, &fd)); } } static void ProcessDroppedItems(char **ppDroppedItems, int nCount, char **ppFiles) { int fileCount = 0; for (int i = 0; i < nCount; ++i) SaveFiles(ppDroppedItems[i], ppFiles, &fileCount); } static int CountDroppedFiles(char **ppDroppedItems, int nCount) { int fileCount = 0; for (int i = 0; i < nCount; ++i) { fileCount += CountFiles(ppDroppedItems[i]); } return fileCount; } /////////////////////////////////////////////////////////////////////////////// // Init/destroy void RegisterFileDropping(HWND hwnd, CDropTarget* pdropTarget) { RegisterDragDrop(hwnd, (IDropTarget*)pdropTarget); } void UnregisterFileDropping(HWND hwnd) { RevokeDragDrop(hwnd); }