1 /* 2 * PROJECT: mydocs 3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) 4 * PURPOSE: MyDocs implementation 5 * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 6 */ 7 8 #include "precomp.hpp" 9 10 WINE_DEFAULT_DEBUG_CHANNEL(mydocs); 11 12 static CLIPFORMAT g_cfHIDA = 0; 13 14 CMyDocsDropHandler::CMyDocsDropHandler() 15 { 16 InterlockedIncrement(&g_ModuleRefCnt); 17 } 18 19 CMyDocsDropHandler::~CMyDocsDropHandler() 20 { 21 InterlockedDecrement(&g_ModuleRefCnt); 22 } 23 24 // IDropTarget 25 STDMETHODIMP 26 CMyDocsDropHandler::DragEnter(IDataObject *pDataObject, DWORD dwKeyState, 27 POINTL pt, DWORD *pdwEffect) 28 { 29 TRACE("(%p)\n", this); 30 31 *pdwEffect &= DROPEFFECT_COPY; // Copy only 32 33 return S_OK; 34 } 35 36 STDMETHODIMP 37 CMyDocsDropHandler::DragOver(DWORD dwKeyState, POINTL pt, DWORD *pdwEffect) 38 { 39 TRACE("(%p)\n", this); 40 41 *pdwEffect &= DROPEFFECT_COPY; // Copy only 42 43 return S_OK; 44 } 45 46 STDMETHODIMP CMyDocsDropHandler::DragLeave() 47 { 48 TRACE("(%p)\n", this); 49 return S_OK; 50 } 51 52 STDMETHODIMP 53 CMyDocsDropHandler::Drop(IDataObject *pDataObject, DWORD dwKeyState, 54 POINTL pt, DWORD *pdwEffect) 55 { 56 TRACE("(%p)\n", this); 57 58 if (!pDataObject) 59 { 60 ERR("pDataObject is NULL\n"); 61 *pdwEffect = 0; 62 DragLeave(); 63 return E_POINTER; 64 } 65 66 CComPtr<IShellFolder> pDesktop; 67 HRESULT hr = SHGetDesktopFolder(&pDesktop); 68 if (FAILED_UNEXPECTEDLY(hr)) 69 return hr; 70 71 // get the clipboard format 72 if (g_cfHIDA == 0) 73 g_cfHIDA = ::RegisterClipboardFormatW(CFSTR_SHELLIDLIST); 74 75 // Retrieve an HIDA (handle of IDA) 76 STGMEDIUM medium; 77 FORMATETC fmt = { g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; 78 hr = pDataObject->GetData(&fmt, &medium); 79 if (FAILED_UNEXPECTEDLY(hr)) 80 { 81 *pdwEffect = 0; 82 DragLeave(); 83 return E_FAIL; 84 } 85 86 // lock HIDA 87 LPIDA pida = reinterpret_cast<LPIDA>(GlobalLock(medium.hGlobal)); 88 UINT iItem, cItems = pida->cidl; 89 90 // get the path of "My Documents" 91 WCHAR szzDir[MAX_PATH + 1]; 92 SHGetSpecialFolderPathW(NULL, szzDir, CSIDL_PERSONAL, FALSE); 93 szzDir[lstrlenW(szzDir) + 1] = 0; // ends with double NULs 94 95 // for all source items 96 CStringW strSrcList; 97 WCHAR szSrc[MAX_PATH]; 98 PCIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(pida); 99 for (iItem = 0; iItem < cItems; ++iItem) 100 { 101 // query source pidl 102 PCITEMID_CHILD pidlChild = HIDA_GetPIDLItem(pida, iItem); 103 CComHeapPtr<ITEMIDLIST> pidl(ILCombine(pidlParent, pidlChild)); 104 105 // can get path? 106 szSrc[0] = 0; 107 if (!SHGetPathFromIDListW(pidl, szSrc)) 108 { 109 // try to retrieve path from desktop 110 STRRET strret; 111 hr = pDesktop->GetDisplayNameOf(pidl, SHGDN_INFOLDER, &strret); 112 if (FAILED_UNEXPECTEDLY(hr)) 113 break; 114 hr = StrRetToBufW(&strret, pidl, szSrc, _countof(szSrc)); 115 if (FAILED_UNEXPECTEDLY(hr)) 116 break; 117 if (!PathFileExistsW(szSrc)) 118 break; 119 } 120 121 if (iItem > 0) 122 strSrcList += L'|'; // separator is '|' 123 strSrcList += szSrc; 124 } 125 126 // unlock HIDA 127 GlobalUnlock(medium.hGlobal); 128 129 if (iItem != cItems) 130 { 131 // source not found 132 CStringW strText; 133 strText.Format(IDS_NOSRCFILEFOUND, szSrc[0] ? szSrc : L"(null)"); 134 MessageBoxW(NULL, strText, NULL, MB_ICONERROR); 135 136 *pdwEffect = 0; 137 DragLeave(); 138 return E_FAIL; 139 } 140 141 strSrcList += L"||"; // double separators 142 143 // lock the buffer 144 LPWSTR pszzSrcList = strSrcList.GetBuffer(); 145 146 // convert every separator to a NUL 147 INT cch = strSrcList.GetLength(); 148 for (INT i = 0; i < cch; ++i) 149 { 150 if (pszzSrcList[i] == L'|') 151 pszzSrcList[i] = L'\0'; 152 } 153 154 // copy them 155 SHFILEOPSTRUCTW fileop = { NULL }; 156 fileop.wFunc = FO_COPY; 157 fileop.pFrom = pszzSrcList; 158 fileop.pTo = szzDir; 159 fileop.fFlags = FOF_ALLOWUNDO | FOF_FILESONLY | FOF_MULTIDESTFILES | FOF_NOCONFIRMMKDIR; 160 int res = SHFileOperationW(&fileop); 161 if (res) 162 { 163 ERR("SHFileOperationW failed with 0x%x\n", res); 164 hr = E_FAIL; 165 } 166 167 // unlock buffer 168 strSrcList.ReleaseBuffer(); 169 170 DragLeave(); 171 return hr; 172 } 173 174 // IPersistFile 175 STDMETHODIMP CMyDocsDropHandler::GetCurFile(LPOLESTR *ppszFileName) 176 { 177 FIXME("(%p)\n", this); 178 return E_NOTIMPL; 179 } 180 181 STDMETHODIMP CMyDocsDropHandler::IsDirty() 182 { 183 FIXME("(%p)\n", this); 184 return E_NOTIMPL; 185 } 186 187 STDMETHODIMP CMyDocsDropHandler::Load(LPCOLESTR pszFileName, DWORD dwMode) 188 { 189 return S_OK; 190 } 191 192 STDMETHODIMP CMyDocsDropHandler::Save(LPCOLESTR pszFileName, BOOL fRemember) 193 { 194 FIXME("(%p)\n", this); 195 return E_NOTIMPL; 196 } 197 198 STDMETHODIMP CMyDocsDropHandler::SaveCompleted(LPCOLESTR pszFileName) 199 { 200 FIXME("(%p)\n", this); 201 return E_NOTIMPL; 202 } 203 204 // IPersist 205 STDMETHODIMP CMyDocsDropHandler::GetClassID(CLSID * lpClassId) 206 { 207 TRACE("(%p)\n", this); 208 209 if (!lpClassId) 210 { 211 ERR("lpClassId is NULL\n"); 212 return E_POINTER; 213 } 214 215 *lpClassId = CLSID_MyDocsDropHandler; 216 217 return S_OK; 218 } 219