ReactOS  0.4.15-dev-3728-ga92304f
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 
12 
14  m_idCmdFirst(0),
15  m_idCmdLast(0),
16  m_idCmdCopyTo(-1),
17  m_fnOldWndProc(NULL),
18  m_bIgnoreTextBoxChange(FALSE)
19 {
20 }
21 
23 {
24 }
25 
26 static LRESULT CALLBACK
28 {
30  CCopyToMenu *this_ =
31  reinterpret_cast<CCopyToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
32 
33  switch (uMsg)
34  {
35  case WM_COMMAND:
36  {
37  switch (LOWORD(wParam))
38  {
40  {
41  if (HIWORD(wParam) == EN_CHANGE)
42  {
43  if (!this_->m_bIgnoreTextBoxChange)
44  {
45  // get the text
47  StrTrimW(szPath, L" \t");
48 
49  // update OK button
51  SendMessageW(hwnd, BFFM_ENABLEOK, 0, bValid);
52 
53  return 0;
54  }
55 
56  // reset flag
58  }
59  break;
60  }
61  }
62  break;
63  }
64  }
65  return CallWindowProcW(this_->m_fnOldWndProc, hwnd, uMsg, wParam, lParam);
66 }
67 
68 static int CALLBACK
70 {
71  CCopyToMenu *this_ =
72  reinterpret_cast<CCopyToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
73 
74  switch (uMsg)
75  {
76  case BFFM_INITIALIZED:
77  {
79  this_ = reinterpret_cast<CCopyToMenu *>(lpData);
80 
81  // Select initial directory
83  reinterpret_cast<LPARAM>(static_cast<LPCITEMIDLIST>(this_->m_pidlFolder)));
84 
85  // Set caption
87  SetWindowTextW(hwnd, strCaption);
88 
89  // Set OK button text
91  SetDlgItemText(hwnd, IDOK, strCopy);
92 
93  // Subclassing
94  this_->m_fnOldWndProc =
95  reinterpret_cast<WNDPROC>(
96  SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc)));
97 
98  // Disable OK
100  break;
101  }
102  case BFFM_SELCHANGED:
103  {
105  LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(lParam);
106 
107  szPath[0] = 0;
109 
110  if (ILIsEqual(pidl, this_->m_pidlFolder))
112  else if (PathFileExistsW(szPath) || _ILIsDesktop(pidl))
114  else
116 
117  // the text box will be updated later soon, ignore it
118  this_->m_bIgnoreTextBoxChange = TRUE;
119  break;
120  }
121  }
122 
123  return FALSE;
124 }
125 
127 {
128  CDataObjectHIDA pCIDA(m_pDataObject);
129  if (FAILED_UNEXPECTEDLY(pCIDA.hr()))
130  return pCIDA.hr();
131 
132  PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(pCIDA);
133  if (!pidlParent)
134  {
135  ERR("HIDA_GetPIDLFolder failed\n");
136  return E_FAIL;
137  }
138 
139  CStringW strFiles;
141  for (UINT n = 0; n < pCIDA->cidl; ++n)
142  {
143  PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(pCIDA, n);
144  if (!pidlRelative)
145  continue;
146 
147  CComHeapPtr<ITEMIDLIST> pidlCombine(ILCombine(pidlParent, pidlRelative));
148  if (!pidl)
149  return E_FAIL;
150 
151  SHGetPathFromIDListW(pidlCombine, szPath);
152 
153  if (n > 0)
154  strFiles += L'|';
155  strFiles += szPath;
156  }
157 
158  strFiles += L'|'; // double null-terminated
159  strFiles.Replace(L'|', L'\0');
160 
161  if (_ILIsDesktop(pidl))
163  else
165  INT cchPath = lstrlenW(szPath);
166  if (cchPath + 1 < MAX_PATH)
167  {
168  szPath[cchPath + 1] = 0; // double null-terminated
169  }
170  else
171  {
172  ERR("Too long path\n");
173  return E_FAIL;
174  }
175 
176  SHFILEOPSTRUCTW op = { lpici->hwnd };
177  op.wFunc = FO_COPY;
178  op.pFrom = strFiles;
179  op.pTo = szPath;
180  op.fFlags = FOF_ALLOWUNDO;
181  int res = SHFileOperationW(&op);
182  if (res)
183  {
184  ERR("SHFileOperationW failed with 0x%x\n", res);
185  return E_FAIL;
186  }
187  return S_OK;
188 }
189 
191 {
192  CStringW ret = L"(file)";
193 
194  CDataObjectHIDA pCIDA(m_pDataObject);
195  if (FAILED_UNEXPECTEDLY(pCIDA.hr()))
196  return ret;
197 
198  PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(pCIDA);
199  if (!pidlParent)
200  {
201  ERR("HIDA_GetPIDLFolder failed\n");
202  return ret;
203  }
204 
206  PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(pCIDA, 0);
207  if (!pidlRelative)
208  {
209  ERR("HIDA_GetPIDLItem failed\n");
210  return ret;
211  }
212 
213  CComHeapPtr<ITEMIDLIST> pidlCombine(ILCombine(pidlParent, pidlRelative));
214 
215  if (SHGetPathFromIDListW(pidlCombine, szPath))
217  else
218  ERR("Cannot get path\n");
219 
220  if (pCIDA->cidl > 1)
221  ret += L" ...";
222 
223  return ret;
224 }
225 
227 {
228  WCHAR wszPath[MAX_PATH];
229  HRESULT hr = E_FAIL;
230 
231  TRACE("DoCopyToFolder(%p)\n", lpici);
232 
233  if (!SHGetPathFromIDListW(m_pidlFolder, wszPath))
234  {
235  ERR("SHGetPathFromIDListW failed\n");
236  return hr;
237  }
238 
239  CStringW strFileTitle = DoGetFileTitle();
240  CStringW strTitle;
241  strTitle.Format(IDS_COPYTOTITLE, static_cast<LPCWSTR>(strFileTitle));
242 
243  BROWSEINFOW info = { lpici->hwnd };
244  info.pidlRoot = NULL;
245  info.lpszTitle = strTitle;
247  info.lpfn = BrowseCallbackProc;
248  info.lParam = reinterpret_cast<LPARAM>(this);
250  if (pidl)
251  {
252  hr = DoRealCopy(lpici, pidl);
253  }
254 
255  return hr;
256 }
257 
260  UINT indexMenu,
261  UINT idCmdFirst,
262  UINT idCmdLast,
263  UINT uFlags)
264 {
265  MENUITEMINFOW mii;
266  UINT Count = 0;
267 
268  TRACE("CCopyToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
269  hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
270 
271  m_idCmdFirst = m_idCmdLast = idCmdFirst;
272 
273  // insert separator if necessary
274  ZeroMemory(&mii, sizeof(mii));
275  mii.cbSize = sizeof(mii);
276  mii.fMask = MIIM_TYPE;
277  if (GetMenuItemInfoW(hMenu, indexMenu - 1, TRUE, &mii) &&
278  mii.fType != MFT_SEPARATOR)
279  {
280  ZeroMemory(&mii, sizeof(mii));
281  mii.cbSize = sizeof(mii);
282  mii.fMask = MIIM_TYPE;
283  mii.fType = MFT_SEPARATOR;
284  if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
285  {
286  ++indexMenu;
287  ++Count;
288  }
289  }
290 
291  // insert "Copy to folder..."
293  ZeroMemory(&mii, sizeof(mii));
294  mii.cbSize = sizeof(mii);
295  mii.fMask = MIIM_ID | MIIM_TYPE;
296  mii.fType = MFT_STRING;
297  mii.dwTypeData = strText.GetBuffer();
298  mii.cch = wcslen(mii.dwTypeData);
299  mii.wID = m_idCmdLast;
300  if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
301  {
303  ++indexMenu;
304  ++Count;
305  }
306 
307  return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count);
308 }
309 
312 {
313  HRESULT hr = E_FAIL;
314  TRACE("CCopyToMenu::InvokeCommand(%p)\n", lpici);
315 
316  if (HIWORD(lpici->lpVerb) == 0)
317  {
318  if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdCopyTo)
319  {
320  hr = DoCopyToFolder(lpici);
321  }
322  }
323  else
324  {
325  if (::lstrcmpiA(lpici->lpVerb, "copyto") == 0)
326  {
327  hr = DoCopyToFolder(lpici);
328  }
329  }
330 
331  return hr;
332 }
333 
336  UINT uType,
337  UINT *pwReserved,
338  LPSTR pszName,
339  UINT cchMax)
340 {
341  FIXME("%p %lu %u %p %p %u\n", this,
342  idCmd, uType, pwReserved, pszName, cchMax);
343 
344  return E_NOTIMPL;
345 }
346 
349 {
350  TRACE("This %p uMsg %x\n", this, uMsg);
351  return E_NOTIMPL;
352 }
353 
356  IDataObject *pdtobj, HKEY hkeyProgID)
357 {
358  m_pidlFolder.Attach(ILClone(pidlFolder));
359  m_pDataObject = pdtobj;
360  return S_OK;
361 }
362 
364 {
365  m_pSite = pUnkSite;
366  return S_OK;
367 }
368 
370 {
371  if (!m_pSite)
372  return E_FAIL;
373 
374  return m_pSite->QueryInterface(riid, ppvSite);
375 }
#define IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT
Definition: shresdef.h:407
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1722
UINT WINAPI GetDlgItemTextW(HWND hDlg, int nIDDlgItem, LPWSTR lpString, int nMaxCount)
Definition: dialog.c:2263
#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
HRESULT hr
Definition: shlfolder.c:183
#define PathIsRelative
Definition: shlwapi.h:951
#define IDS_COPYTOTITLE
Definition: shresdef.h:315
#define TRUE
Definition: types.h:120
REFIID riid
Definition: precomp.h:44
#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:27
#define CALLBACK
Definition: compat.h:35
static PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const *pida, SIZE_T i)
Definition: shellutils.h:554
#define BFFM_INITIALIZED
Definition: shlobj.h:1163
GLdouble n
Definition: glext.h:7729
#define FOF_ALLOWUNDO
Definition: shellapi.h:144
#define ZeroMemory
Definition: winbase.h:1664
void __cdecl Format(UINT nFormatID,...)
Definition: cstringt.h:753
LPWSTR dwTypeData
Definition: winuser.h:3249
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:609
#define E_FAIL
Definition: ddrawi.h:102
#define IDS_COPYBUTTON
Definition: shresdef.h:317
int32_t INT
Definition: typedefs.h:58
int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
Definition: shlfileop.cpp:1959
#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)
#define L(x)
Definition: ntvdm.h:50
#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
WNDPROC m_fnOldWndProc
LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
Definition: path.c:394
LONG_PTR LPARAM
Definition: windef.h:208
HRESULT DoRealCopy(LPCMINVOKECOMMANDINFO lpici, PCUIDLIST_ABSOLUTE pidl)
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1776
#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)
int Count
Definition: noreturn.cpp:7
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:82
#define MAX_PATH
Definition: compat.h:34
#define WINAPI
Definition: msvc.h:6
UINT op
Definition: effect.c:236
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
#define BIF_USENEWUI
Definition: shlobj.h:1151
#define SetDlgItemText
Definition: winuser.h:5829
UINT cchMax
#define MFT_SEPARATOR
Definition: winuser.h:739
int ret
#define MIIM_TYPE
Definition: winuser.h:720
virtual HRESULT WINAPI Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
static PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const *pida)
Definition: shellutils.h:549
#define WM_COMMAND
Definition: winuser.h:1727
BOOL m_bIgnoreTextBoxChange
#define GWLP_WNDPROC
Definition: treelist.c:66
#define ERR(fmt,...)
Definition: debug.h:110
HRESULT DoCopyToFolder(LPCMINVOKECOMMANDINFO lpici)
int Replace(PCXSTR pszOld, PCXSTR pszNew)
Definition: cstringt.h:811
#define BFFM_ENABLEOK
Definition: shlobj.h:1171
#define S_OK
Definition: intsafe.h:52
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:2851
void shell(int argc, const char *argv[])
Definition: cmds.c:1231
static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
Definition: CCopyToMenu.cpp:69
LPCWSTR szPath
Definition: env.c:37
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
#define NULL
Definition: types.h:112
WINE_DEFAULT_DEBUG_CHANNEL(shell)
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
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:316
#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
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4022
#define IDS_COPYTOMENU
Definition: shresdef.h:314
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
#define LOWORD(l)
Definition: pedump.c:82
#define EN_CHANGE
Definition: winuser.h:2009