[SHELLEXT][MYDOCS][INF] Add mydocs.dll and .mydocs file extension (#2624)
[reactos.git] / dll / shellext / mydocs / CMyDocsDropHandler.cpp
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 const BYTE *pb = reinterpret_cast<BYTE *>(pida);
99 PCIDLIST_ABSOLUTE pidlParent = reinterpret_cast<PCIDLIST_ABSOLUTE>(pb + pida->aoffset[0]);
100 for (iItem = 0; iItem < cItems; ++iItem)
101 {
102 // query source pidl
103 PCITEMID_CHILD pidlChild = reinterpret_cast<PCITEMID_CHILD>(pb + pida->aoffset[iItem + 1]);
104 CComHeapPtr<ITEMIDLIST> pidl(ILCombine(pidlParent, pidlChild));
105
106 // can get path?
107 szSrc[0] = 0;
108 if (!SHGetPathFromIDListW(pidl, szSrc))
109 {
110 // try to retrieve path from desktop
111 STRRET strret;
112 hr = pDesktop->GetDisplayNameOf(pidl, SHGDN_INFOLDER, &strret);
113 if (FAILED_UNEXPECTEDLY(hr))
114 break;
115 hr = StrRetToBufW(&strret, pidl, szSrc, _countof(szSrc));
116 if (FAILED_UNEXPECTEDLY(hr))
117 break;
118 if (!PathFileExistsW(szSrc))
119 break;
120 }
121
122 if (iItem > 0)
123 strSrcList += L'|'; // separator is '|'
124 strSrcList += szSrc;
125 }
126
127 // unlock HIDA
128 GlobalUnlock(medium.hGlobal);
129
130 if (iItem != cItems)
131 {
132 // source not found
133 CStringW strText;
134 strText.Format(IDS_NOSRCFILEFOUND, szSrc[0] ? szSrc : L"(null)");
135 MessageBoxW(NULL, strText, NULL, MB_ICONERROR);
136
137 *pdwEffect = 0;
138 DragLeave();
139 return E_FAIL;
140 }
141
142 strSrcList += L"||"; // double separators
143
144 // lock the buffer
145 LPWSTR pszzSrcList = strSrcList.GetBuffer();
146
147 // convert every separator to a NUL
148 INT cch = strSrcList.GetLength();
149 for (INT i = 0; i < cch; ++i)
150 {
151 if (pszzSrcList[i] == L'|')
152 pszzSrcList[i] = L'\0';
153 }
154
155 // copy them
156 SHFILEOPSTRUCTW fileop = { NULL };
157 fileop.wFunc = FO_COPY;
158 fileop.pFrom = pszzSrcList;
159 fileop.pTo = szzDir;
160 fileop.fFlags = FOF_ALLOWUNDO | FOF_FILESONLY | FOF_MULTIDESTFILES | FOF_NOCONFIRMMKDIR;
161 SHFileOperationW(&fileop);
162
163 // unlock buffer
164 strSrcList.ReleaseBuffer();
165
166 DragLeave();
167 return hr;
168 }
169
170 // IPersistFile
171 STDMETHODIMP CMyDocsDropHandler::GetCurFile(LPOLESTR *ppszFileName)
172 {
173 FIXME("(%p)\n", this);
174 return E_NOTIMPL;
175 }
176
177 STDMETHODIMP CMyDocsDropHandler::IsDirty()
178 {
179 FIXME("(%p)\n", this);
180 return E_NOTIMPL;
181 }
182
183 STDMETHODIMP CMyDocsDropHandler::Load(LPCOLESTR pszFileName, DWORD dwMode)
184 {
185 return S_OK;
186 }
187
188 STDMETHODIMP CMyDocsDropHandler::Save(LPCOLESTR pszFileName, BOOL fRemember)
189 {
190 FIXME("(%p)\n", this);
191 return E_NOTIMPL;
192 }
193
194 STDMETHODIMP CMyDocsDropHandler::SaveCompleted(LPCOLESTR pszFileName)
195 {
196 FIXME("(%p)\n", this);
197 return E_NOTIMPL;
198 }
199
200 // IPersist
201 STDMETHODIMP CMyDocsDropHandler::GetClassID(CLSID * lpClassId)
202 {
203 TRACE("(%p)\n", this);
204
205 if (!lpClassId)
206 {
207 ERR("lpClassId is NULL\n");
208 return E_POINTER;
209 }
210
211 *lpClassId = CLSID_MyDocsDropHandler;
212
213 return S_OK;
214 }