ReactOS  0.4.15-dev-5452-g3c95c95
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  {
104  if (!this_)
105  break;
106 
108  LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(lParam);
109 
110  szPath[0] = 0;
112 
113  if (ILIsEqual(pidl, this_->m_pidlFolder))
115  else if (PathFileExistsW(szPath) || _ILIsDesktop(pidl))
117  else
119 
120  // the text box will be updated later soon, ignore it
121  this_->m_bIgnoreTextBoxChange = TRUE;
122  break;
123  }
124  }
125 
126  return FALSE;
127 }
128 
130 {
131  CDataObjectHIDA pCIDA(m_pDataObject);
132  if (FAILED_UNEXPECTEDLY(pCIDA.hr()))
133  return pCIDA.hr();
134 
135  PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(pCIDA);
136  if (!pidlParent)
137  {
138  ERR("HIDA_GetPIDLFolder failed\n");
139  return E_FAIL;
140  }
141 
142  CStringW strFiles;
144  for (UINT n = 0; n < pCIDA->cidl; ++n)
145  {
146  PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(pCIDA, n);
147  if (!pidlRelative)
148  continue;
149 
150  CComHeapPtr<ITEMIDLIST> pidlCombine(ILCombine(pidlParent, pidlRelative));
151  if (!pidl)
152  return E_FAIL;
153 
154  SHGetPathFromIDListW(pidlCombine, szPath);
155 
156  if (n > 0)
157  strFiles += L'|';
158  strFiles += szPath;
159  }
160 
161  strFiles += L'|'; // double null-terminated
162  strFiles.Replace(L'|', L'\0');
163 
164  if (_ILIsDesktop(pidl))
166  else
168  INT cchPath = lstrlenW(szPath);
169  if (cchPath + 1 < MAX_PATH)
170  {
171  szPath[cchPath + 1] = 0; // double null-terminated
172  }
173  else
174  {
175  ERR("Too long path\n");
176  return E_FAIL;
177  }
178 
179  SHFILEOPSTRUCTW op = { lpici->hwnd };
180  op.wFunc = FO_COPY;
181  op.pFrom = strFiles;
182  op.pTo = szPath;
183  op.fFlags = FOF_ALLOWUNDO;
184  int res = SHFileOperationW(&op);
185  if (res)
186  {
187  ERR("SHFileOperationW failed with 0x%x\n", res);
188  return E_FAIL;
189  }
190  return S_OK;
191 }
192 
194 {
195  CStringW ret = L"(file)";
196 
197  CDataObjectHIDA pCIDA(m_pDataObject);
198  if (FAILED_UNEXPECTEDLY(pCIDA.hr()))
199  return ret;
200 
201  PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(pCIDA);
202  if (!pidlParent)
203  {
204  ERR("HIDA_GetPIDLFolder failed\n");
205  return ret;
206  }
207 
209  PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(pCIDA, 0);
210  if (!pidlRelative)
211  {
212  ERR("HIDA_GetPIDLItem failed\n");
213  return ret;
214  }
215 
216  CComHeapPtr<ITEMIDLIST> pidlCombine(ILCombine(pidlParent, pidlRelative));
217 
218  if (SHGetPathFromIDListW(pidlCombine, szPath))
220  else
221  ERR("Cannot get path\n");
222 
223  if (pCIDA->cidl > 1)
224  ret += L" ...";
225 
226  return ret;
227 }
228 
230 {
231  WCHAR wszPath[MAX_PATH];
232  HRESULT hr = E_FAIL;
233 
234  TRACE("DoCopyToFolder(%p)\n", lpici);
235 
236  if (!SHGetPathFromIDListW(m_pidlFolder, wszPath))
237  {
238  ERR("SHGetPathFromIDListW failed\n");
239  return hr;
240  }
241 
242  CStringW strFileTitle = DoGetFileTitle();
243  CStringW strTitle;
244  strTitle.Format(IDS_COPYTOTITLE, static_cast<LPCWSTR>(strFileTitle));
245 
246  BROWSEINFOW info = { lpici->hwnd };
247  info.pidlRoot = NULL;
248  info.lpszTitle = strTitle;
250  info.lpfn = BrowseCallbackProc;
251  info.lParam = reinterpret_cast<LPARAM>(this);
253  if (pidl)
254  {
255  hr = DoRealCopy(lpici, pidl);
256  }
257 
258  return hr;
259 }
260 
263  UINT indexMenu,
264  UINT idCmdFirst,
265  UINT idCmdLast,
266  UINT uFlags)
267 {
268  MENUITEMINFOW mii;
269  UINT Count = 0;
270 
271  TRACE("CCopyToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
272  hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
273 
274  m_idCmdFirst = m_idCmdLast = idCmdFirst;
275 
276  // insert separator if necessary
277  ZeroMemory(&mii, sizeof(mii));
278  mii.cbSize = sizeof(mii);
279  mii.fMask = MIIM_TYPE;
280  if (GetMenuItemInfoW(hMenu, indexMenu - 1, TRUE, &mii) &&
281  mii.fType != MFT_SEPARATOR)
282  {
283  ZeroMemory(&mii, sizeof(mii));
284  mii.cbSize = sizeof(mii);
285  mii.fMask = MIIM_TYPE;
286  mii.fType = MFT_SEPARATOR;
287  if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
288  {
289  ++indexMenu;
290  ++Count;
291  }
292  }
293 
294  // insert "Copy to folder..."
296  ZeroMemory(&mii, sizeof(mii));
297  mii.cbSize = sizeof(mii);
298  mii.fMask = MIIM_ID | MIIM_TYPE;
299  mii.fType = MFT_STRING;
300  mii.dwTypeData = strText.GetBuffer();
301  mii.cch = wcslen(mii.dwTypeData);
302  mii.wID = m_idCmdLast;
303  if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
304  {
306  ++indexMenu;
307  ++Count;
308  }
309 
310  return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count);
311 }
312 
315 {
316  HRESULT hr = E_FAIL;
317  TRACE("CCopyToMenu::InvokeCommand(%p)\n", lpici);
318 
319  if (HIWORD(lpici->lpVerb) == 0)
320  {
321  if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdCopyTo)
322  {
323  hr = DoCopyToFolder(lpici);
324  }
325  }
326  else
327  {
328  if (::lstrcmpiA(lpici->lpVerb, "copyto") == 0)
329  {
330  hr = DoCopyToFolder(lpici);
331  }
332  }
333 
334  return hr;
335 }
336 
339  UINT uType,
340  UINT *pwReserved,
341  LPSTR pszName,
342  UINT cchMax)
343 {
344  FIXME("%p %lu %u %p %p %u\n", this,
345  idCmd, uType, pwReserved, pszName, cchMax);
346 
347  return E_NOTIMPL;
348 }
349 
352 {
353  TRACE("This %p uMsg %x\n", this, uMsg);
354  return E_NOTIMPL;
355 }
356 
359  IDataObject *pdtobj, HKEY hkeyProgID)
360 {
361  m_pidlFolder.Attach(ILClone(pidlFolder));
362  m_pDataObject = pdtobj;
363  return S_OK;
364 }
365 
367 {
368  m_pSite = pUnkSite;
369  return S_OK;
370 }
371 
373 {
374  if (!m_pSite)
375  return E_FAIL;
376 
377  return m_pSite->QueryInterface(riid, ppvSite);
378 }
#define IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT
Definition: shresdef.h:413
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:321
#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:569
#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:1670
void __cdecl Format(UINT nFormatID,...)
Definition: cstringt.h:753
LPWSTR dwTypeData
Definition: winuser.h:3259
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:750
#define E_FAIL
Definition: ddrawi.h:102
#define IDS_COPYBUTTON
Definition: shresdef.h:323
int32_t INT
Definition: typedefs.h:58
int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
Definition: shlfileop.cpp:1982
#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:5839
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:564
#define WM_COMMAND
Definition: winuser.h:1730
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:3061
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:322
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
#define CSIDL_DESKTOPDIRECTORY
Definition: shlobj.h:2040
#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:320
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:2012