ReactOS 0.4.15-dev-8434-g155a7c7
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
12enum { IDC_ACTION = 0 };
13
15 m_fnOldWndProc(NULL),
16 m_bIgnoreTextBoxChange(FALSE)
17{
18}
19
20static LRESULT CALLBACK
22{
24 CCopyMoveToMenu *this_ =
26
27 switch (uMsg)
28 {
29 case WM_COMMAND:
30 {
31 switch (LOWORD(wParam))
32 {
34 {
35 if (HIWORD(wParam) == EN_CHANGE)
36 {
37 if (!this_->m_bIgnoreTextBoxChange)
38 {
39 // get the text
41 StrTrimW(szPath, L" \t");
42
43 // update OK button
45 SendMessageW(hwnd, BFFM_ENABLEOK, 0, bValid);
46
47 return 0;
48 }
49
50 // reset flag
52 }
53 break;
54 }
55 }
56 break;
57 }
58 }
59 return CallWindowProcW(this_->m_fnOldWndProc, hwnd, uMsg, wParam, lParam);
60}
61
62static INT CALLBACK
64{
65 CCopyMoveToMenu *this_ =
67
68 switch (uMsg)
69 {
71 {
73 this_ = reinterpret_cast<CCopyMoveToMenu *>(lpData);
74
75 // Select initial directory
77 reinterpret_cast<LPARAM>(static_cast<LPCITEMIDLIST>(this_->m_pidlFolder)));
78
79 // Set caption
80 CString strCaption(MAKEINTRESOURCEW(this_->GetCaptionStringID()));
81 SetWindowTextW(hwnd, strCaption);
82
83 // Set OK button text
84 CString strCopyOrMove(MAKEINTRESOURCEW(this_->GetButtonStringID()));
85 SetDlgItemText(hwnd, IDOK, strCopyOrMove);
86
87 // Subclassing
88 this_->m_fnOldWndProc =
89 reinterpret_cast<WNDPROC>(
91
92 // Disable OK
94 break;
95 }
96 case BFFM_SELCHANGED:
97 {
98 if (!this_)
99 break;
100
102 LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(lParam);
103
104 szPath[0] = 0;
106
107 if (ILIsEqual(pidl, this_->m_pidlFolder))
109 else if (PathFileExistsW(szPath) || _ILIsDesktop(pidl))
111 else
113
114 // the text box will be updated later soon, ignore it
116 break;
117 }
118 }
119
120 return FALSE;
121}
122
125{
126 CStringW strFiles;
128 for (UINT n = 0; n < pCIDA->cidl; ++n)
129 {
131 if (!pidlCombine)
132 return E_FAIL;
133
134 if (!SHGetPathFromIDListW(pidlCombine, szPath))
135 return E_FAIL;
136
137 if (n > 0)
138 strFiles += L'|';
139 strFiles += szPath;
140 }
141
142 strFiles += L'|'; // double null-terminated
143 strFiles.Replace(L'|', L'\0');
144
145 if (_ILIsDesktop(pidlDestination))
147 else
148 SHGetPathFromIDListW(pidlDestination, szPath);
149 INT cchPath = lstrlenW(szPath);
150 if (cchPath + 1 < MAX_PATH)
151 {
152 szPath[cchPath + 1] = 0; // double null-terminated
153 }
154 else
155 {
156 ERR("Too long path\n");
157 return E_FAIL;
158 }
159
160 SHFILEOPSTRUCTW op = { lpici->hwnd, GetFileOp(), strFiles, szPath };
161 op.fFlags = FOF_ALLOWUNDO;
162 int res = SHFileOperationW(&op);
163 if (res)
164 {
165 ERR("SHFileOperationW failed with 0x%x\n", res);
166 return E_FAIL;
167 }
168 return S_OK;
169}
170
171static HRESULT
172DoGetFileTitle(const CIDA *pCIDA, CStringW& strTitle)
173{
174 CComHeapPtr<ITEMIDLIST> pidlCombine(SHELL_CIDA_ILCloneFull(pCIDA, 0));
175 if (!pidlCombine)
176 return E_OUTOFMEMORY;
177
179 HRESULT hr = SHGetNameAndFlagsW(pidlCombine, SHGDN_INFOLDER, szPath, _countof(szPath), NULL);
180 strTitle = SUCCEEDED(hr) ? szPath : L"";
181 if (strTitle.IsEmpty())
182 return E_FAIL;
183
184 if (pCIDA->cidl > 1)
185 strTitle += L" ...";
186 return S_OK;
187}
188
190{
191 WCHAR wszPath[MAX_PATH];
192 TRACE("(%p)\n", lpici);
193
194 CDataObjectHIDA pCIDA(m_pDataObject);
195 HRESULT hr = pCIDA.hr();
197 {
198 ERR("Failed to get CIDA, %#x\n", hr);
199 return hr;
200 }
201
202 if (!SHGetPathFromIDListW(m_pidlFolder, wszPath))
203 {
204 ERR("SHGetPathFromIDListW failed\n");
205 return E_FAIL;
206 }
207
208 CStringW strFileTitle;
209 hr = DoGetFileTitle(pCIDA, strFileTitle);
210 if (FAILED(hr))
211 return hr;
212
213 CStringW strTitle;
214 strTitle.Format(GetActionTitleStringID(), static_cast<LPCWSTR>(strFileTitle));
215
216 BROWSEINFOW info = { lpici->hwnd };
217 info.pidlRoot = NULL;
218 info.lpszTitle = strTitle;
221 info.lParam = reinterpret_cast<LPARAM>(this);
223 if (pidl)
224 hr = DoRealFileOp(pCIDA, lpici, pidl);
225
226 return hr;
227}
228
229static BOOL
231{
233
234 while (iItem > 0)
235 {
236 bSuccess = GetMenuItemInfoW(hMenu, --iItem, TRUE, lpmii);
238 break;
239 }
240
241 return bSuccess;
242}
243
246 UINT indexMenu,
247 UINT idCmdFirst,
248 UINT idCmdLast,
249 UINT uFlags)
250{
251 TRACE("CCopyToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
252 hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
253 return QueryContextMenuImpl(TRUE, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
254}
255
258 UINT indexMenu,
259 UINT idCmdFirst,
260 UINT idCmdLast,
261 UINT uFlags)
262{
263 TRACE("CMoveToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
264 hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
265 return QueryContextMenuImpl(FALSE, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
266}
267
269CCopyMoveToMenu::QueryContextMenuImpl(BOOL IsCopyOp, HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
270{
271 if (uFlags & (CMF_NOVERBS | CMF_VERBSONLY))
272 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
273
274 UINT idHighest = 0;
275 CStringW strCopyTo(MAKEINTRESOURCEW(IDS_COPYTOMENU)), strMoveTo;
276 LPWSTR itemText = strCopyTo.GetBuffer();
277 if (!IsCopyOp)
278 {
279 strMoveTo.LoadString(IDS_MOVETOMENU);
280 itemText = strMoveTo.GetBuffer();
281 }
282
283 // Insert separator if necessary
284 WCHAR szBuff[128];
285 MENUITEMINFOW mii = { sizeof(mii), MIIM_TYPE };
286 mii.dwTypeData = szBuff;
287 mii.cch = _countof(szBuff);
288 if (GetPreviousMenuItemInfo(hMenu, indexMenu, &mii) &&
289 mii.fType != MFT_SEPARATOR &&
290 (IsCopyOp || !(mii.fType == MFT_STRING && !wcscmp(szBuff, strCopyTo.GetBuffer()))))
291 {
292 mii.fMask = MIIM_TYPE;
293 mii.fType = MFT_SEPARATOR;
294 mii.dwTypeData = NULL;
295 mii.cch = 0;
296 if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
297 {
298 ++indexMenu;
299 }
300 }
301
302 // Insert the menu item
303 mii.fMask = MIIM_ID | MIIM_TYPE;
304 mii.fType = MFT_STRING;
305 mii.dwTypeData = itemText;
306 mii.wID = idCmdFirst + IDC_ACTION;
307 if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
308 {
309 idHighest = max(idHighest, mii.wID);
310 ++indexMenu;
311 }
312 return idHighest >= idCmdFirst ? MAKE_HRESULT(SEVERITY_SUCCESS, 0, idHighest - idCmdFirst + 1) : E_FAIL;
313}
314
317{
318 HRESULT hr = E_FAIL;
319 TRACE("CCopyMoveToMenu::InvokeCommand(%p)\n", lpici);
320
321 if (IS_INTRESOURCE(lpici->lpVerb))
322 {
323 if (LOWORD(lpici->lpVerb) == IDC_ACTION)
324 hr = DoAction(lpici);
325 }
326 else
327 {
328 if (::lstrcmpiA(lpici->lpVerb, GetVerb()) == 0)
329 hr = DoAction(lpici);
330 }
331
332 return hr;
333}
334
337 UINT_PTR idCmd,
338 UINT uType,
339 UINT *pwReserved,
340 LPSTR pszName,
341 UINT cchMax)
342{
343 if ((uType | GCS_UNICODE) == GCS_VALIDATEW)
344 return idCmd == IDC_ACTION ? S_OK : S_FALSE;
345
346 if (uType == GCS_VERBW && idCmd == IDC_ACTION)
347 return SHAnsiToUnicode(GetVerb(), (LPWSTR)pszName, cchMax);
348
349 FIXME("%p %lu %u %p %p %u\n", this,
350 idCmd, uType, pwReserved, pszName, cchMax);
351
352 return E_NOTIMPL;
353}
354
357{
358 TRACE("This %p uMsg %x\n", this, uMsg);
359 return E_NOTIMPL;
360}
361
364{
365 m_pDataObject = pdtobj;
366 HRESULT hr = E_FAIL;
367 if (pidlFolder)
368 {
369 hr = SHILClone(pidlFolder, &pidlFolder);
370 }
371 else
372 {
373 pidlFolder = SHELL_DataObject_ILCloneFullItem(pdtobj, 0);
374 if (pidlFolder)
375 {
376 ILRemoveLastID((LPITEMIDLIST)pidlFolder);
377 hr = S_OK;
378 }
379 }
380
381 if (SUCCEEDED(hr))
382 m_pidlFolder.Attach(const_cast<PIDLIST_ABSOLUTE>(pidlFolder));
383 return hr;
384}
385
388{
389 m_pSite = pUnkSite;
390 return S_OK;
391}
392
395{
396 if (!m_pSite)
397 return E_FAIL;
398
399 return m_pSite->QueryInterface(riid, ppvSite);
400}
BOOL _ILIsDesktop(LPCITEMIDLIST pidl)
Definition: CBandSite.h:24
static BOOL GetPreviousMenuItemInfo(HMENU hMenu, UINT iItem, LPMENUITEMINFOW lpmii)
@ IDC_ACTION
static HRESULT DoGetFileTitle(const CIDA *pCIDA, CStringW &strTitle)
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 IDC_ACTION
Definition: resource.h:44
#define FIXME(fmt,...)
Definition: precomp.h:53
#define ERR(fmt,...)
Definition: precomp.h:57
#define STDMETHODIMP
Definition: basetyps.h:43
bool IsEmpty() const noexcept
Definition: atlsimpstr.h:394
int Replace(PCXSTR pszOld, PCXSTR pszNew)
Definition: cstringt.h:886
BOOL LoadString(_In_ UINT nID)
Definition: cstringt.h:639
void __cdecl Format(UINT nFormatID,...)
Definition: cstringt.h:818
STDMETHODIMP QueryContextMenuImpl(BOOL IsCopyOp, HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
HRESULT DoAction(LPCMINVOKECOMMANDINFO lpici)
virtual UINT GetCaptionStringID() const =0
CComHeapPtr< ITEMIDLIST > m_pidlFolder
HRESULT DoRealFileOp(const CIDA *pCIDA, LPCMINVOKECOMMANDINFO lpici, PCUIDLIST_ABSOLUTE pidlDestination)
virtual UINT GetActionTitleStringID() const =0
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_OUTOFMEMORY
Definition: ddrawi.h:100
#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
int WINAPI lstrcmpiA(LPCSTR str1, LPCSTR str2)
Definition: locale.c:4223
PIDLIST_ABSOLUTE SHELL_CIDA_ILCloneFull(_In_ const CIDA *pCIDA, _In_ UINT Index)
HRESULT SHGetNameAndFlagsW(_In_ LPCITEMIDLIST pidl, _In_ DWORD dwFlags, _Out_opt_ LPWSTR pszText, _In_ UINT cchBuf, _Inout_opt_ DWORD *pdwAttributes)
Definition: utils.cpp:289
PIDLIST_ABSOLUTE SHELL_DataObject_ILCloneFullItem(_In_ IDataObject *pDO, _In_ UINT Index)
HRESULT SHILClone(_In_opt_ LPCITEMIDLIST pidl, _Outptr_ LPITEMIDLIST *ppidl)
Definition: utils.cpp:13
BOOL WINAPI SHGetSpecialFolderPathW(HWND hwndOwner, LPWSTR szPath, int nFolder, BOOL bCreate)
Definition: shellpath.c:3092
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1777
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1723
DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
Definition: string.c:2667
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:477
unsigned int BOOL
Definition: ntddk_ex.h:94
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
REFIID riid
Definition: atlbase.h:39
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
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
#define L(x)
Definition: ntvdm.h:50
#define LOWORD(l)
Definition: pedump.c:82
BOOL WINAPI ILRemoveLastID(LPITEMIDLIST pidl)
Definition: pidl.c:221
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1342
BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:548
#define REFIID
Definition: guiddef.h:118
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define FOF_ALLOWUNDO
Definition: shellapi.h:147
#define FO_COPY
Definition: shellapi.h:137
int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
Definition: shlfileop.cpp:1987
HRESULT hr
Definition: shlfolder.c:183
#define CSIDL_DESKTOPDIRECTORY
Definition: shlobj.h:2187
#define BFFM_SELCHANGED
Definition: shlobj.h:1237
#define BIF_RETURNONLYFSDIRS
Definition: shlobj.h:1217
#define BFFM_ENABLEOK
Definition: shlobj.h:1244
#define BFFM_SETSELECTION
Definition: shlobj.h:1256
#define BIF_USENEWUI
Definition: shlobj.h:1224
#define SHBrowseForFolder
Definition: shlobj.h:1253
#define BFFM_INITIALIZED
Definition: shlobj.h:1236
#define PathIsRelative
Definition: shlwapi.h:951
#define IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT
Definition: shresdef.h:439
#define IDS_MOVETOMENU
Definition: shresdef.h:350
#define IDS_COPYTOMENU
Definition: shresdef.h:346
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
const ITEMIDLIST_ABSOLUTE UNALIGNED * PCUIDLIST_ABSOLUTE
Definition: shtypes.idl:63
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
#define _countof(array)
Definition: sndvol32.h:70
#define TRACE(s)
Definition: solgame.cpp:4
Definition: shlobj.h:572
UINT cidl
Definition: shlobj.h:572
LPWSTR dwTypeData
Definition: winuser.h:3269
#define max(a, b)
Definition: svc.c:63
#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
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 S_FALSE
Definition: winerror.h:2357
#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:5858
#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
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185