ReactOS 0.4.15-dev-7998-gdb93cb1
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
260static BOOL
262{
264
265 while (iItem > 0)
266 {
267 bSuccess = GetMenuItemInfoW(hMenu, --iItem, TRUE, lpmii);
269 break;
270 }
271
272 return bSuccess;
273}
274
277 UINT indexMenu,
278 UINT idCmdFirst,
279 UINT idCmdLast,
280 UINT uFlags)
281{
282 MENUITEMINFOW mii;
283 UINT Count = 0;
284
285 TRACE("CCopyToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
286 hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
287
288 if (uFlags & (CMF_NOVERBS | CMF_VERBSONLY))
289 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst);
290
291 m_idCmdFirst = m_idCmdLast = idCmdFirst;
292
293 // insert separator if necessary
294 ZeroMemory(&mii, sizeof(mii));
295 mii.cbSize = sizeof(mii);
296 mii.fMask = MIIM_TYPE;
297 if (GetPreviousMenuItemInfo(hMenu, indexMenu, &mii) &&
298 mii.fType != MFT_SEPARATOR)
299 {
300 ZeroMemory(&mii, sizeof(mii));
301 mii.cbSize = sizeof(mii);
302 mii.fMask = MIIM_TYPE;
303 mii.fType = MFT_SEPARATOR;
304 if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
305 {
306 ++indexMenu;
307 ++Count;
308 }
309 }
310
311 // insert "Copy to folder..."
313 ZeroMemory(&mii, sizeof(mii));
314 mii.cbSize = sizeof(mii);
315 mii.fMask = MIIM_ID | MIIM_TYPE;
316 mii.fType = MFT_STRING;
317 mii.dwTypeData = strText.GetBuffer();
318 mii.cch = wcslen(mii.dwTypeData);
319 mii.wID = m_idCmdLast;
320 if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
321 {
323 ++indexMenu;
324 ++Count;
325 }
326
327 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst + Count);
328}
329
332 UINT indexMenu,
333 UINT idCmdFirst,
334 UINT idCmdLast,
335 UINT uFlags)
336{
337 MENUITEMINFOW mii;
338 UINT Count = 0;
339
340 TRACE("CMoveToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
341 hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
342
343 if (uFlags & (CMF_NOVERBS | CMF_VERBSONLY))
344 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst);
345
346 m_idCmdFirst = m_idCmdLast = idCmdFirst;
347
348 // insert separator if necessary
350 WCHAR szBuff[128];
351 ZeroMemory(&mii, sizeof(mii));
352 mii.cbSize = sizeof(mii);
353 mii.fMask = MIIM_TYPE;
354 mii.dwTypeData = szBuff;
355 mii.cch = _countof(szBuff);
356 if (GetPreviousMenuItemInfo(hMenu, indexMenu, &mii) &&
357 mii.fType != MFT_SEPARATOR &&
358 !(mii.fType == MFT_STRING && CStringW(szBuff) == strCopyTo))
359 {
360 ZeroMemory(&mii, sizeof(mii));
361 mii.cbSize = sizeof(mii);
362 mii.fMask = MIIM_TYPE;
363 mii.fType = MFT_SEPARATOR;
364 if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
365 {
366 ++indexMenu;
367 ++Count;
368 }
369 }
370
371 // insert "Move to folder..."
373 ZeroMemory(&mii, sizeof(mii));
374 mii.cbSize = sizeof(mii);
375 mii.fMask = MIIM_ID | MIIM_TYPE;
376 mii.fType = MFT_STRING;
377 mii.dwTypeData = strText.GetBuffer();
378 mii.cch = wcslen(mii.dwTypeData);
379 mii.wID = m_idCmdLast;
380 if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
381 {
383 ++indexMenu;
384 ++Count;
385 }
386
387 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst + Count);
388}
389
392{
393 HRESULT hr = E_FAIL;
394 TRACE("CCopyMoveToMenu::InvokeCommand(%p)\n", lpici);
395
396 if (IS_INTRESOURCE(lpici->lpVerb))
397 {
398 if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdAction)
399 hr = DoAction(lpici);
400 }
401 else
402 {
403 if (::lstrcmpiA(lpici->lpVerb, GetVerb()) == 0)
404 hr = DoAction(lpici);
405 }
406
407 return hr;
408}
409
412 UINT_PTR idCmd,
413 UINT uType,
414 UINT *pwReserved,
415 LPSTR pszName,
416 UINT cchMax)
417{
418 FIXME("%p %lu %u %p %p %u\n", this,
419 idCmd, uType, pwReserved, pszName, cchMax);
420
421 return E_NOTIMPL;
422}
423
426{
427 TRACE("This %p uMsg %x\n", this, uMsg);
428 return E_NOTIMPL;
429}
430
433{
434 m_pidlFolder.Attach(ILClone(pidlFolder));
435 m_pDataObject = pdtobj;
436 return S_OK;
437}
438
441{
442 m_pSite = pUnkSite;
443 return S_OK;
444}
445
448{
449 if (!m_pSite)
450 return E_FAIL;
451
452 return m_pSite->QueryInterface(riid, ppvSite);
453}
BOOL _ILIsDesktop(LPCITEMIDLIST pidl)
Definition: CBandSite.h:24
static HRESULT DoGetFileTitle(CStringW &strTitle, IDataObject *pDataObject)
static BOOL GetPreviousMenuItemInfo(HMENU hMenu, UINT iItem, LPMENUITEMINFOW lpmii)
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:394
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:3092
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:1877
#define MAKE_HRESULT(sev, fac, code)
Definition: dmerror.h:30
static BOOLEAN bSuccess
Definition: drive.cpp:433
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:237
LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:712
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1353
BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:548
#define REFIID
Definition: guiddef.h:118
#define FOF_ALLOWUNDO
Definition: shellapi.h:147
static PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const *pida, SIZE_T i)
Definition: shellutils.h:591
static PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const *pida)
Definition: shellutils.h:586
int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
Definition: shlfileop.cpp:1987
HRESULT hr
Definition: shlfolder.c:183
#define CSIDL_DESKTOPDIRECTORY
Definition: shlobj.h:2173
#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:434
#define IDS_MOVETOMENU
Definition: shresdef.h:345
#define IDS_COPYTOMENU
Definition: shresdef.h:341
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:3269
#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
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
_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 ERROR_MENU_ITEM_NOT_FOUND
Definition: winerror.h:937
#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:1740
#define IS_INTRESOURCE(i)
Definition: winuser.h:580
#define MFT_SEPARATOR
Definition: winuser.h:744
#define IDOK
Definition: winuser.h:830
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:2906
LRESULT WINAPI CallWindowProcW(_In_ WNDPROC, _In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define SetDlgItemText
Definition: winuser.h:5849
#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:2022
char * LPSTR
Definition: xmlstorage.h:182
__wchar_t WCHAR
Definition: xmlstorage.h:180
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185