ReactOS  0.4.15-dev-1184-g23e04ae
CCopyToMenu.cpp
Go to the documentation of this file.
1 /*
2  * PROJECT: shell32
3  * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE: CopyTo implementation
5  * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
6  */
7 
8 #include "precomp.h"
9 
11 
13 {
14  static CLIPFORMAT s_cfHIDA = 0;
15  if (s_cfHIDA == 0)
16  {
17  s_cfHIDA = static_cast<CLIPFORMAT>(RegisterClipboardFormatW(CFSTR_SHELLIDLIST));
18  }
19 
20  FORMATETC fmt = { s_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
21  STGMEDIUM medium;
22 
23  HRESULT hr = pDataObject->GetData(&fmt, &medium);
25  return hr;
26 
27  LPVOID lpSrc = GlobalLock(medium.hGlobal);
28  SIZE_T cbSize = GlobalSize(medium.hGlobal);
29 
30  *ppcida = reinterpret_cast<CIDA *>(::CoTaskMemAlloc(cbSize));
31  if (*ppcida)
32  {
33  memcpy(*ppcida, lpSrc, cbSize);
34  hr = S_OK;
35  }
36  else
37  {
38  ERR("Out of memory\n");
39  hr = E_FAIL;
40  }
41  ReleaseStgMedium(&medium);
42  return hr;
43 }
44 
46  m_idCmdFirst(0),
47  m_idCmdLast(0),
48  m_idCmdCopyTo(-1),
49  m_fnOldWndProc(NULL),
50  m_bIgnoreTextBoxChange(FALSE)
51 {
52 }
53 
55 {
56 }
57 
58 static LRESULT CALLBACK
60 {
62  CCopyToMenu *this_ =
63  reinterpret_cast<CCopyToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
64 
65  switch (uMsg)
66  {
67  case WM_COMMAND:
68  {
69  switch (LOWORD(wParam))
70  {
72  {
73  if (HIWORD(wParam) == EN_CHANGE)
74  {
75  if (!this_->m_bIgnoreTextBoxChange)
76  {
77  // get the text
79  StrTrimW(szPath, L" \t");
80 
81  // update OK button
83  SendMessageW(hwnd, BFFM_ENABLEOK, 0, bValid);
84 
85  return 0;
86  }
87 
88  // reset flag
90  }
91  break;
92  }
93  }
94  break;
95  }
96  }
97  return CallWindowProcW(this_->m_fnOldWndProc, hwnd, uMsg, wParam, lParam);
98 }
99 
100 static int CALLBACK
102 {
103  CCopyToMenu *this_ =
104  reinterpret_cast<CCopyToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
105 
106  switch (uMsg)
107  {
108  case BFFM_INITIALIZED:
109  {
111  this_ = reinterpret_cast<CCopyToMenu *>(lpData);
112 
113  // Select initial directory
115  reinterpret_cast<LPARAM>(static_cast<LPCITEMIDLIST>(this_->m_pidlFolder)));
116 
117  // Set caption
119  SetWindowTextW(hwnd, strCaption);
120 
121  // Set OK button text
123  SetDlgItemText(hwnd, IDOK, strCopy);
124 
125  // Subclassing
126  this_->m_fnOldWndProc =
127  reinterpret_cast<WNDPROC>(
128  SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc)));
129 
130  // Disable OK
132  break;
133  }
134  case BFFM_SELCHANGED:
135  {
137  LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(lParam);
138 
139  szPath[0] = 0;
141 
142  if (ILIsEqual(pidl, this_->m_pidlFolder))
144  else if (PathFileExistsW(szPath) || _ILIsDesktop(pidl))
146  else
148 
149  // the text box will be updated later soon, ignore it
150  this_->m_bIgnoreTextBoxChange = TRUE;
151  break;
152  }
153  }
154 
155  return FALSE;
156 }
157 
159 {
160  CComHeapPtr<CIDA> pCIDA;
162  if (FAILED_UNEXPECTEDLY(hr))
163  return hr;
164 
165  PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(pCIDA);
166  if (!pidlParent)
167  {
168  ERR("HIDA_GetPIDLFolder failed\n");
169  return E_FAIL;
170  }
171 
172  CStringW strFiles;
174  for (UINT n = 0; n < pCIDA->cidl; ++n)
175  {
176  PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(pCIDA, n);
177  if (!pidlRelative)
178  continue;
179 
180  CComHeapPtr<ITEMIDLIST> pidlCombine(ILCombine(pidlParent, pidlRelative));
181  if (!pidl)
182  return E_FAIL;
183 
184  SHGetPathFromIDListW(pidlCombine, szPath);
185 
186  if (n > 0)
187  strFiles += L'|';
188  strFiles += szPath;
189  }
190 
191  strFiles += L'|'; // double null-terminated
192  strFiles.Replace(L'|', L'\0');
193 
194  if (_ILIsDesktop(pidl))
196  else
198  INT cchPath = lstrlenW(szPath);
199  if (cchPath + 1 < MAX_PATH)
200  {
201  szPath[cchPath + 1] = 0; // double null-terminated
202  }
203  else
204  {
205  ERR("Too long path\n");
206  return E_FAIL;
207  }
208 
209  SHFILEOPSTRUCTW op = { lpici->hwnd };
210  op.wFunc = FO_COPY;
211  op.pFrom = strFiles;
212  op.pTo = szPath;
213  op.fFlags = FOF_ALLOWUNDO;
214  int res = SHFileOperationW(&op);
215  if (res)
216  {
217  ERR("SHFileOperationW failed with 0x%x\n", res);
218  return E_FAIL;
219  }
220  return S_OK;
221 }
222 
224 {
225  CStringW ret = L"(file)";
226 
227  CComHeapPtr<CIDA> pCIDA;
229  if (FAILED_UNEXPECTEDLY(hr))
230  return ret;
231 
232  PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(pCIDA);
233  if (!pidlParent)
234  {
235  ERR("HIDA_GetPIDLFolder failed\n");
236  return ret;
237  }
238 
240  PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(pCIDA, 0);
241  if (!pidlRelative)
242  {
243  ERR("HIDA_GetPIDLItem failed\n");
244  return ret;
245  }
246 
247  CComHeapPtr<ITEMIDLIST> pidlCombine(ILCombine(pidlParent, pidlRelative));
248 
249  if (SHGetPathFromIDListW(pidlCombine, szPath))
251  else
252  ERR("Cannot get path\n");
253 
254  if (pCIDA->cidl > 1)
255  ret += L" ...";
256 
257  return ret;
258 }
259 
261 {
262  WCHAR wszPath[MAX_PATH];
263  HRESULT hr = E_FAIL;
264 
265  TRACE("DoCopyToFolder(%p)\n", lpici);
266 
267  if (!SHGetPathFromIDListW(m_pidlFolder, wszPath))
268  {
269  ERR("SHGetPathFromIDListW failed\n");
270  return hr;
271  }
272 
273  CStringW strFileTitle = DoGetFileTitle();
274  CStringW strTitle;
275  strTitle.Format(IDS_COPYTOTITLE, static_cast<LPCWSTR>(strFileTitle));
276 
277  BROWSEINFOW info = { lpici->hwnd };
278  info.pidlRoot = NULL;
279  info.lpszTitle = strTitle;
281  info.lpfn = BrowseCallbackProc;
282  info.lParam = reinterpret_cast<LPARAM>(this);
284  if (pidl)
285  {
286  hr = DoRealCopy(lpici, pidl);
287  }
288 
289  return hr;
290 }
291 
294  UINT indexMenu,
295  UINT idCmdFirst,
296  UINT idCmdLast,
297  UINT uFlags)
298 {
299  MENUITEMINFOW mii;
300  UINT Count = 0;
301 
302  TRACE("CCopyToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
303  hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
304 
305  m_idCmdFirst = m_idCmdLast = idCmdFirst;
306 
307  // insert separator if necessary
308  ZeroMemory(&mii, sizeof(mii));
309  mii.cbSize = sizeof(mii);
310  mii.fMask = MIIM_TYPE;
311  if (GetMenuItemInfoW(hMenu, indexMenu - 1, TRUE, &mii) &&
312  mii.fType != MFT_SEPARATOR)
313  {
314  ZeroMemory(&mii, sizeof(mii));
315  mii.cbSize = sizeof(mii);
316  mii.fMask = MIIM_TYPE;
317  mii.fType = MFT_SEPARATOR;
318  if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
319  {
320  ++indexMenu;
321  ++Count;
322  }
323  }
324 
325  // insert "Copy to folder..."
327  ZeroMemory(&mii, sizeof(mii));
328  mii.cbSize = sizeof(mii);
329  mii.fMask = MIIM_ID | MIIM_TYPE;
330  mii.fType = MFT_STRING;
331  mii.dwTypeData = strText.GetBuffer();
332  mii.cch = wcslen(mii.dwTypeData);
333  mii.wID = m_idCmdLast;
334  if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
335  {
337  ++indexMenu;
338  ++Count;
339  }
340 
341  return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count);
342 }
343 
346 {
347  HRESULT hr = E_FAIL;
348  TRACE("CCopyToMenu::InvokeCommand(%p)\n", lpici);
349 
350  if (HIWORD(lpici->lpVerb) == 0)
351  {
352  if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdCopyTo)
353  {
354  hr = DoCopyToFolder(lpici);
355  }
356  }
357  else
358  {
359  if (::lstrcmpiA(lpici->lpVerb, "copyto") == 0)
360  {
361  hr = DoCopyToFolder(lpici);
362  }
363  }
364 
365  return hr;
366 }
367 
370  UINT uType,
371  UINT *pwReserved,
372  LPSTR pszName,
373  UINT cchMax)
374 {
375  FIXME("%p %lu %u %p %p %u\n", this,
376  idCmd, uType, pwReserved, pszName, cchMax);
377 
378  return E_NOTIMPL;
379 }
380 
383 {
384  TRACE("This %p uMsg %x\n", this, uMsg);
385  return E_NOTIMPL;
386 }
387 
390  IDataObject *pdtobj, HKEY hkeyProgID)
391 {
392  m_pidlFolder.Attach(ILClone(pidlFolder));
393  m_pDataObject = pdtobj;
394  return S_OK;
395 }
396 
398 {
399  m_pSite = pUnkSite;
400  return S_OK;
401 }
402 
404 {
405  if (!m_pSite)
406  return E_FAIL;
407 
408  return m_pSite->QueryInterface(riid, ppvSite);
409 }
#define IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT
Definition: shresdef.h:387
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1702
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
HRESULT _GetCidlFromDataObject(IDataObject *pDataObject, CIDA **ppcida)
Definition: CCopyToMenu.cpp:12
UINT WINAPI GetDlgItemTextW(HWND hDlg, int nIDDlgItem, LPWSTR lpString, int nMaxCount)
Definition: dialog.c:2271
#define MFT_STRING
Definition: winuser.h:741
#define REFIID
Definition: guiddef.h:118
#define IDOK
Definition: winuser.h:824
int WINAPI lstrcmpiA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:42
#define CFSTR_SHELLIDLIST
Definition: shlobj.h:477
HRESULT hr
Definition: shlfolder.c:183
#define PathIsRelative
Definition: shlwapi.h:951
void WINAPI ReleaseStgMedium(STGMEDIUM *pmedium)
Definition: ole2.c:2033
#define IDS_COPYTOTITLE
Definition: shresdef.h:301
#define TRUE
Definition: types.h:120
REFIID riid
Definition: precomp.h:44
UINT WINAPI RegisterClipboardFormatW(_In_ LPCWSTR)
#define FO_COPY
Definition: shellapi.h:134
CComHeapPtr< ITEMIDLIST > m_pidlFolder
LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:699
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1294
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: CCopyToMenu.cpp:59
#define CALLBACK
Definition: compat.h:35
static PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const *pida, SIZE_T i)
Definition: shellutils.h:543
#define BFFM_INITIALIZED
Definition: shlobj.h:1163
GLdouble n
Definition: glext.h:7729
#define FOF_ALLOWUNDO
Definition: shellapi.h:144
HRESULT GetData([in, unique] FORMATETC *pformatetcIn, [out] STGMEDIUM *pmedium)
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1223
#define ZeroMemory
Definition: winbase.h:1648
void __cdecl Format(UINT nFormatID,...)
Definition: cstringt.h:716
LPWSTR dwTypeData
Definition: winuser.h:3244
BOOL WINAPI SetWindowTextW(_In_ HWND, _In_opt_ LPCWSTR)
BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:535
UINT_PTR WPARAM
Definition: windef.h:207
virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen)
UINT uFlags
Definition: api.c:59
char * LPSTR
Definition: xmlstorage.h:182
#define lstrlenW
Definition: compat.h:498
#define E_FAIL
Definition: ddrawi.h:102
#define IDS_COPYBUTTON
Definition: shresdef.h:303
int32_t INT
Definition: typedefs.h:58
int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
Definition: shlfileop.cpp:1918
#define SetWindowLongPtr
Definition: treelist.c:70
WPARAM wParam
Definition: combotst.c:138
#define SEVERITY_SUCCESS
Definition: winerror.h:64
virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
SIZE_T NTAPI GlobalSize(HGLOBAL hMem)
Definition: heapmem.c:1090
#define FALSE
Definition: types.h:117
#define BFFM_SETSELECTION
Definition: shlobj.h:1183
unsigned int BOOL
Definition: ntddk_ex.h:94
#define FIXME(fmt,...)
Definition: debug.h:111
CStringW DoGetFileTitle()
#define GWLP_USERDATA
Definition: treelist.c:63
smooth NULL
Definition: ftsmooth.c:416
WNDPROC m_fnOldWndProc
LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
Definition: path.c:389
LONG_PTR LPARAM
Definition: windef.h:208
HRESULT DoRealCopy(LPCMINVOKECOMMANDINFO lpici, PCUIDLIST_ABSOLUTE pidl)
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1756
#define MAKE_HRESULT(sev, fac, code)
Definition: dmerror.h:30
BOOL _ILIsDesktop(LPCITEMIDLIST pidl)
Definition: CBandSite.h:24
#define SHBrowseForFolder
Definition: shlobj.h:1180
#define MIIM_ID
Definition: winuser.h:717
CComPtr< IDataObject > m_pDataObject
virtual HRESULT WINAPI SetSite(IUnknown *pUnkSite)
virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
BOOL WINAPI GetMenuItemInfoW(_In_ HMENU, _In_ UINT, _In_ BOOL, _Inout_ LPMENUITEMINFOW)
#define TRACE(s)
Definition: solgame.cpp:4
__wchar_t WCHAR
Definition: xmlstorage.h:180
LONG HRESULT
Definition: typedefs.h:79
#define _countof(array)
Definition: sndvol32.h:68
CComPtr< IUnknown > m_pSite
virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
#define FAILED_UNEXPECTEDLY(hr)
Definition: shellutils.h:71
#define MAX_PATH
Definition: compat.h:34
#define WINAPI
Definition: msvc.h:6
UINT cidl
Definition: shlobj.h:499
UINT op
Definition: effect.c:224
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
#define BIF_USENEWUI
Definition: shlobj.h:1151
#define SetDlgItemText
Definition: winuser.h:5824
UINT cchMax
#define MFT_SEPARATOR
Definition: winuser.h:739
int ret
static const WCHAR L[]
Definition: oid.c:1250
LPVOID NTAPI GlobalLock(HGLOBAL hMem)
Definition: heapmem.c:755
#define MIIM_TYPE
Definition: winuser.h:720
virtual HRESULT WINAPI Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const *pida)
Definition: shellutils.h:538
#define WM_COMMAND
Definition: winuser.h:1722
BOOL m_bIgnoreTextBoxChange
#define GWLP_WNDPROC
Definition: treelist.c:66
#define ERR(fmt,...)
Definition: debug.h:110
HRESULT DoCopyToFolder(LPCMINVOKECOMMANDINFO lpici)
ULONG_PTR SIZE_T
Definition: typedefs.h:80
int Replace(PCXSTR pszOld, PCXSTR pszNew)
Definition: cstringt.h:774
#define BFFM_ENABLEOK
Definition: shlobj.h:1171
#define S_OK
Definition: intsafe.h:51
const ITEMIDLIST_ABSOLUTE UNALIGNED * PCUIDLIST_ABSOLUTE
Definition: shtypes.idl:63
#define BIF_RETURNONLYFSDIRS
Definition: shlobj.h:1144
BOOL WINAPI SHGetSpecialFolderPathW(HWND hwndOwner, LPWSTR szPath, int nFolder, BOOL bCreate)
Definition: shellpath.c:2709
void shell(int argc, const char *argv[])
Definition: cmds.c:1231
static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
LPCWSTR szPath
Definition: env.c:35
LPITEMIDLIST WINAPI ILClone(LPCITEMIDLIST pidl)
Definition: pidl.c:228
#define BFFM_SELCHANGED
Definition: shlobj.h:1164
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define E_NOTIMPL
Definition: ddrawi.h:99
BOOL WINAPI InsertMenuItemW(_In_ HMENU, _In_ UINT, _In_ BOOL, _In_ LPCMENUITEMINFOW)
unsigned int UINT
Definition: ndis.h:50
WINE_DEFAULT_DEBUG_CHANNEL(shell)
BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
Definition: string.c:1869
const ITEMIDLIST_RELATIVE UNALIGNED * PCUIDLIST_RELATIVE
Definition: shtypes.idl:57
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
GLuint res
Definition: glext.h:9613
LRESULT WINAPI CallWindowProcW(_In_ WNDPROC, _In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define HIWORD(l)
Definition: typedefs.h:247
#define IDS_COPYITEMS
Definition: shresdef.h:302
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
#define CSIDL_DESKTOPDIRECTORY
Definition: shlobj.h:2027
#define GetWindowLongPtr
Definition: treelist.c:73
LONG_PTR LRESULT
Definition: windef.h:209
#define IDS_COPYTOMENU
Definition: shresdef.h:300
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:60
virtual HRESULT WINAPI GetSite(REFIID riid, void **ppvSite)
LPARAM lParam
Definition: combotst.c:139
LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
Definition: ifs.c:426
#define LOWORD(l)
Definition: pedump.c:82
Definition: dsound.c:943
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
Definition: shlobj.h:498
#define EN_CHANGE
Definition: winuser.h:2004