ReactOS 0.4.15-dev-7681-g776c3a3
CCopyMoveToMenu.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS shell32
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: CopyTo and MoveTo implementation
5 * COPYRIGHT: Copyright 2020-2023 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
6 */
7
8#include "precomp.h"
9
11
13 m_idCmdFirst(0),
14 m_idCmdLast(0),
15 m_idCmdAction(-1),
16 m_fnOldWndProc(NULL),
17 m_bIgnoreTextBoxChange(FALSE)
18{
19}
20
21static LRESULT CALLBACK
23{
25 CCopyMoveToMenu *this_ =
27
28 switch (uMsg)
29 {
30 case WM_COMMAND:
31 {
32 switch (LOWORD(wParam))
33 {
35 {
36 if (HIWORD(wParam) == EN_CHANGE)
37 {
38 if (!this_->m_bIgnoreTextBoxChange)
39 {
40 // get the text
42 StrTrimW(szPath, L" \t");
43
44 // update OK button
46 SendMessageW(hwnd, BFFM_ENABLEOK, 0, bValid);
47
48 return 0;
49 }
50
51 // reset flag
53 }
54 break;
55 }
56 }
57 break;
58 }
59 }
60 return CallWindowProcW(this_->m_fnOldWndProc, hwnd, uMsg, wParam, lParam);
61}
62
63static INT CALLBACK
65{
66 CCopyMoveToMenu *this_ =
68
69 switch (uMsg)
70 {
72 {
74 this_ = reinterpret_cast<CCopyMoveToMenu *>(lpData);
75
76 // Select initial directory
78 reinterpret_cast<LPARAM>(static_cast<LPCITEMIDLIST>(this_->m_pidlFolder)));
79
80 // Set caption
81 CString strCaption(MAKEINTRESOURCEW(this_->GetCaptionStringID()));
82 SetWindowTextW(hwnd, strCaption);
83
84 // Set OK button text
85 CString strCopyOrMove(MAKEINTRESOURCEW(this_->GetButtonStringID()));
86 SetDlgItemText(hwnd, IDOK, strCopyOrMove);
87
88 // Subclassing
89 this_->m_fnOldWndProc =
90 reinterpret_cast<WNDPROC>(
92
93 // Disable OK
95 break;
96 }
97 case BFFM_SELCHANGED:
98 {
99 if (!this_)
100 break;
101
103 LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(lParam);
104
105 szPath[0] = 0;
107
108 if (ILIsEqual(pidl, this_->m_pidlFolder))
110 else if (PathFileExistsW(szPath) || _ILIsDesktop(pidl))
112 else
114
115 // the text box will be updated later soon, ignore it
117 break;
118 }
119 }
120
121 return FALSE;
122}
123
126{
127 CDataObjectHIDA pCIDA(m_pDataObject);
128 if (FAILED_UNEXPECTEDLY(pCIDA.hr()))
129 return pCIDA.hr();
130
131 PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(pCIDA);
132 if (!pidlParent)
133 {
134 ERR("HIDA_GetPIDLFolder failed\n");
135 return E_FAIL;
136 }
137
138 CStringW strFiles;
140 for (UINT n = 0; n < pCIDA->cidl; ++n)
141 {
142 PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(pCIDA, n);
143 if (!pidlRelative)
144 continue;
145
146 CComHeapPtr<ITEMIDLIST> pidlCombine(ILCombine(pidlParent, pidlRelative));
147 if (!pidl)
148 return E_FAIL;
149
150 SHGetPathFromIDListW(pidlCombine, szPath);
151
152 if (n > 0)
153 strFiles += L'|';
154 strFiles += szPath;
155 }
156
157 strFiles += L'|'; // double null-terminated
158 strFiles.Replace(L'|', L'\0');
159
160 if (_ILIsDesktop(pidl))
162 else
164 INT cchPath = lstrlenW(szPath);
165 if (cchPath + 1 < MAX_PATH)
166 {
167 szPath[cchPath + 1] = 0; // double null-terminated
168 }
169 else
170 {
171 ERR("Too long path\n");
172 return E_FAIL;
173 }
174
175 SHFILEOPSTRUCTW op = { lpici->hwnd, GetFileOp(), strFiles, szPath };
176 op.fFlags = FOF_ALLOWUNDO;
177 int res = SHFileOperationW(&op);
178 if (res)
179 {
180 ERR("SHFileOperationW failed with 0x%x\n", res);
181 return E_FAIL;
182 }
183 return S_OK;
184}
185
186static HRESULT
187DoGetFileTitle(CStringW& strTitle, IDataObject *pDataObject)
188{
189 CDataObjectHIDA pCIDA(pDataObject);
190 if (FAILED_UNEXPECTEDLY(pCIDA.hr()))
191 return E_FAIL;
192
193 PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(pCIDA);
194 if (!pidlParent)
195 {
196 ERR("HIDA_GetPIDLFolder failed\n");
197 return E_FAIL;
198 }
199
201 PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(pCIDA, 0);
202 if (!pidlRelative)
203 {
204 ERR("HIDA_GetPIDLItem failed\n");
205 return E_FAIL;
206 }
207
208 CComHeapPtr<ITEMIDLIST> pidlCombine(ILCombine(pidlParent, pidlRelative));
209
210 if (!SHGetPathFromIDListW(pidlCombine, szPath))
211 {
212 ERR("Cannot get path\n");
213 return E_FAIL;
214 }
215
216 strTitle = PathFindFileNameW(szPath);
217 if (strTitle.IsEmpty())
218 return E_FAIL;
219
220 if (pCIDA->cidl > 1)
221 strTitle += L" ...";
222
223 return S_OK;
224}
225
227{
228 WCHAR wszPath[MAX_PATH];
229 HRESULT hr = E_FAIL;
230
231 TRACE("(%p)\n", lpici);
232
233 if (!SHGetPathFromIDListW(m_pidlFolder, wszPath))
234 {
235 ERR("SHGetPathFromIDListW failed\n");
236 return hr;
237 }
238
239 CStringW strFileTitle;
240 hr = DoGetFileTitle(strFileTitle, m_pDataObject);
241 if (FAILED(hr))
242 return hr;
243
244 CStringW strTitle;
245 strTitle.Format(GetActionTitleStringID(), static_cast<LPCWSTR>(strFileTitle));
246
247 BROWSEINFOW info = { lpici->hwnd };
248 info.pidlRoot = NULL;
249 info.lpszTitle = strTitle;
252 info.lParam = reinterpret_cast<LPARAM>(this);
254 if (pidl)
255 hr = DoRealFileOp(lpici, pidl);
256
257 return hr;
258}
259
262 UINT indexMenu,
263 UINT idCmdFirst,
264 UINT idCmdLast,
265 UINT uFlags)
266{
267 MENUITEMINFOW mii;
268 UINT Count = 0;
269
270 TRACE("CCopyToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
271 hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
272
273 if (uFlags & (CMF_NOVERBS | CMF_VERBSONLY))
274 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst);
275
276 m_idCmdFirst = m_idCmdLast = idCmdFirst;
277
278 // insert separator if necessary
279 ZeroMemory(&mii, sizeof(mii));
280 mii.cbSize = sizeof(mii);
281 mii.fMask = MIIM_TYPE;
282 if (GetMenuItemInfoW(hMenu, indexMenu - 1, TRUE, &mii) &&
283 mii.fType != MFT_SEPARATOR)
284 {
285 ZeroMemory(&mii, sizeof(mii));
286 mii.cbSize = sizeof(mii);
287 mii.fMask = MIIM_TYPE;
288 mii.fType = MFT_SEPARATOR;
289 if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
290 {
291 ++indexMenu;
292 ++Count;
293 }
294 }
295
296 // insert "Copy to folder..."
298 ZeroMemory(&mii, sizeof(mii));
299 mii.cbSize = sizeof(mii);
300 mii.fMask = MIIM_ID | MIIM_TYPE;
301 mii.fType = MFT_STRING;
302 mii.dwTypeData = strText.GetBuffer();
303 mii.cch = wcslen(mii.dwTypeData);
304 mii.wID = m_idCmdLast;
305 if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
306 {
308 ++indexMenu;
309 ++Count;
310 }
311
312 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst + Count);
313}
314
317 UINT indexMenu,
318 UINT idCmdFirst,
319 UINT idCmdLast,
320 UINT uFlags)
321{
322 MENUITEMINFOW mii;
323 UINT Count = 0;
324
325 TRACE("CMoveToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
326 hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
327
328 if (uFlags & (CMF_NOVERBS | CMF_VERBSONLY))
329 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst);
330
331 m_idCmdFirst = m_idCmdLast = idCmdFirst;
332
333 // insert separator if necessary
335 WCHAR szBuff[128];
336 ZeroMemory(&mii, sizeof(mii));
337 mii.cbSize = sizeof(mii);
338 mii.fMask = MIIM_TYPE;
339 mii.dwTypeData = szBuff;
340 mii.cch = _countof(szBuff);
341 if (GetMenuItemInfoW(hMenu, indexMenu - 1, TRUE, &mii) &&
342 mii.fType != MFT_SEPARATOR &&
343 !(mii.fType == MFT_STRING && CStringW(szBuff) == strCopyTo))
344 {
345 ZeroMemory(&mii, sizeof(mii));
346 mii.cbSize = sizeof(mii);
347 mii.fMask = MIIM_TYPE;
348 mii.fType = MFT_SEPARATOR;
349 if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
350 {
351 ++indexMenu;
352 ++Count;
353 }
354 }
355
356 // insert "Move to folder..."
358 ZeroMemory(&mii, sizeof(mii));
359 mii.cbSize = sizeof(mii);
360 mii.fMask = MIIM_ID | MIIM_TYPE;
361 mii.fType = MFT_STRING;
362 mii.dwTypeData = strText.GetBuffer();
363 mii.cch = wcslen(mii.dwTypeData);
364 mii.wID = m_idCmdLast;
365 if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
366 {
368 ++indexMenu;
369 ++Count;
370 }
371
372 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst + Count);
373}
374
377{
378 HRESULT hr = E_FAIL;
379 TRACE("CCopyMoveToMenu::InvokeCommand(%p)\n", lpici);
380
381 if (IS_INTRESOURCE(lpici->lpVerb))
382 {
383 if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdAction)
384 hr = DoAction(lpici);
385 }
386 else
387 {
388 if (::lstrcmpiA(lpici->lpVerb, GetVerb()) == 0)
389 hr = DoAction(lpici);
390 }
391
392 return hr;
393}
394
397 UINT_PTR idCmd,
398 UINT uType,
399 UINT *pwReserved,
400 LPSTR pszName,
401 UINT cchMax)
402{
403 FIXME("%p %lu %u %p %p %u\n", this,
404 idCmd, uType, pwReserved, pszName, cchMax);
405
406 return E_NOTIMPL;
407}
408
411{
412 TRACE("This %p uMsg %x\n", this, uMsg);
413 return E_NOTIMPL;
414}
415
418{
419 m_pidlFolder.Attach(ILClone(pidlFolder));
420 m_pDataObject = pdtobj;
421 return S_OK;
422}
423
426{
427 m_pSite = pUnkSite;
428 return S_OK;
429}
430
433{
434 if (!m_pSite)
435 return E_FAIL;
436
437 return m_pSite->QueryInterface(riid, ppvSite);
438}
BOOL _ILIsDesktop(LPCITEMIDLIST pidl)
Definition: CBandSite.h:24
static HRESULT DoGetFileTitle(CStringW &strTitle, IDataObject *pDataObject)
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
static INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
UINT cchMax
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
void shell(int argc, const char *argv[])
Definition: cmds.c:1231
#define STDMETHODIMP
Definition: basetyps.h:43
#define FIXME(fmt,...)
Definition: debug.h:111
#define ERR(fmt,...)
Definition: debug.h:110
bool IsEmpty() const noexcept
Definition: atlsimpstr.h:389
int Replace(PCXSTR pszOld, PCXSTR pszNew)
Definition: cstringt.h:886
void __cdecl Format(UINT nFormatID,...)
Definition: cstringt.h:818
HRESULT DoAction(LPCMINVOKECOMMANDINFO lpici)
virtual UINT GetCaptionStringID() const =0
CComHeapPtr< ITEMIDLIST > m_pidlFolder
virtual UINT GetActionTitleStringID() const =0
HRESULT DoRealFileOp(LPCMINVOKECOMMANDINFO lpici, PCUIDLIST_ABSOLUTE pidl)
virtual UINT GetButtonStringID() const =0
STDMETHODIMP GetSite(REFIID riid, void **ppvSite) override
STDMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID) override
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) override
virtual UINT GetFileOp() const =0
STDMETHODIMP GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen) override
CComPtr< IDataObject > m_pDataObject
STDMETHODIMP SetSite(IUnknown *pUnkSite) override
STDMETHODIMP HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) override
CComPtr< IUnknown > m_pSite
virtual LPCSTR GetVerb() const =0
WNDPROC m_fnOldWndProc
STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) override
STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) override
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
UINT op
Definition: effect.c:236
UINT uFlags
Definition: api.c:59
#define MAX_PATH
Definition: compat.h:34
#define CALLBACK
Definition: compat.h:35
#define lstrlenW
Definition: compat.h:750
#define FAILED_UNEXPECTEDLY(hr)
Definition: precomp.h:121
BOOL WINAPI SHGetSpecialFolderPathW(HWND hwndOwner, LPWSTR szPath, int nFolder, BOOL bCreate)
Definition: shellpath.c:3061
LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
Definition: path.c:394
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1777
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1723
BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
Definition: string.c:1869
#define MAKE_HRESULT(sev, fac, code)
Definition: dmerror.h:30
unsigned int BOOL
Definition: ntddk_ex.h:94
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
REFIID riid
Definition: atlbase.h:39
#define S_OK
Definition: intsafe.h:52
#define FAILED(hr)
Definition: intsafe.h:51
int WINAPI lstrcmpiA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:42
LPCWSTR szPath
Definition: env.c:37
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:63
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
unsigned int UINT
Definition: ndis.h:50
static INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
Definition: wizard.c:583
int Count
Definition: noreturn.cpp:7
#define L(x)
Definition: ntvdm.h:50
#define LOWORD(l)
Definition: pedump.c:82
LPITEMIDLIST WINAPI ILClone(LPCITEMIDLIST pidl)
Definition: pidl.c:228
LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:703
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1344
BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:539
#define REFIID
Definition: guiddef.h:118
#define FOF_ALLOWUNDO
Definition: shellapi.h:144
static PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const *pida, SIZE_T i)
Definition: shellutils.h:581
static PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const *pida)
Definition: shellutils.h:576
int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
Definition: shlfileop.cpp:1987
HRESULT hr
Definition: shlfolder.c:183
#define CSIDL_DESKTOPDIRECTORY
Definition: shlobj.h:2106
#define BFFM_SELCHANGED
Definition: shlobj.h:1230
#define BIF_RETURNONLYFSDIRS
Definition: shlobj.h:1210
#define BFFM_ENABLEOK
Definition: shlobj.h:1237
#define BFFM_SETSELECTION
Definition: shlobj.h:1249
#define BIF_USENEWUI
Definition: shlobj.h:1217
#define SHBrowseForFolder
Definition: shlobj.h:1246
#define BFFM_INITIALIZED
Definition: shlobj.h:1229
#define PathIsRelative
Definition: shlwapi.h:951
#define IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT
Definition: shresdef.h:427
#define IDS_MOVETOMENU
Definition: shresdef.h:338
#define IDS_COPYTOMENU
Definition: shresdef.h:334
const ITEMIDLIST_ABSOLUTE UNALIGNED * PCUIDLIST_ABSOLUTE
Definition: shtypes.idl:63
const ITEMIDLIST_RELATIVE UNALIGNED * PCUIDLIST_RELATIVE
Definition: shtypes.idl:57
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
#define _countof(array)
Definition: sndvol32.h:68
#define TRACE(s)
Definition: solgame.cpp:4
LPWSTR dwTypeData
Definition: winuser.h:3268
#define GetWindowLongPtr
Definition: treelist.c:73
#define SetWindowLongPtr
Definition: treelist.c:70
#define GWLP_WNDPROC
Definition: treelist.c:66
#define GWLP_USERDATA
Definition: treelist.c:63
int32_t INT
Definition: typedefs.h:58
#define HIWORD(l)
Definition: typedefs.h:247
UINT WINAPI GetDlgItemTextW(HWND hDlg, int nIDDlgItem, LPWSTR lpString, int nMaxCount)
Definition: dialog.c:2263
#define ZeroMemory
Definition: winbase.h:1712
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
#define SEVERITY_SUCCESS
Definition: winerror.h:64
#define MIIM_ID
Definition: winuser.h:722
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_COMMAND
Definition: winuser.h:1739
#define IS_INTRESOURCE(i)
Definition: winuser.h:580
#define MFT_SEPARATOR
Definition: winuser.h:744
#define IDOK
Definition: winuser.h:829
BOOL WINAPI SetWindowTextW(_In_ HWND, _In_opt_ LPCWSTR)
BOOL WINAPI GetMenuItemInfoW(_In_ HMENU, _In_ UINT, _In_ BOOL, _Inout_ LPMENUITEMINFOW)
#define MFT_STRING
Definition: winuser.h:746
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
LRESULT(CALLBACK * WNDPROC)(HWND, UINT, WPARAM, LPARAM)
Definition: winuser.h:2905
LRESULT WINAPI CallWindowProcW(_In_ WNDPROC, _In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define SetDlgItemText
Definition: winuser.h:5848
#define MIIM_TYPE
Definition: winuser.h:725
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
BOOL WINAPI InsertMenuItemW(_In_ HMENU, _In_ UINT, _In_ BOOL, _In_ LPCMENUITEMINFOW)
#define EN_CHANGE
Definition: winuser.h:2021
char * LPSTR
Definition: xmlstorage.h:182
__wchar_t WCHAR
Definition: xmlstorage.h:180
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185