3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: MoveTo implementation
5 * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
10 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
12 CMoveToMenu::CMoveToMenu() :
19 CMoveToMenu::~CMoveToMenu()
23 #define WM_ENABLEOK (WM_USER + 0x2000)
25 static LRESULT CALLBACK
26 WindowProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
29 reinterpret_cast<CMoveToMenu
*>(GetWindowLongPtr(hwnd
, GWLP_USERDATA
));
34 SendMessageW(hwnd
, BFFM_ENABLEOK
, 0, (BOOL
)lParam
);
37 return CallWindowProcW(this_
->m_fnOldWndProc
, hwnd
, uMsg
, wParam
, lParam
);
41 BrowseCallbackProc(HWND hwnd
, UINT uMsg
, LPARAM lParam
, LPARAM lpData
)
44 reinterpret_cast<CMoveToMenu
*>(GetWindowLongPtr(hwnd
, GWLP_USERDATA
));
48 case BFFM_INITIALIZED
:
50 SetWindowLongPtr(hwnd
, GWLP_USERDATA
, lpData
);
51 this_
= reinterpret_cast<CMoveToMenu
*>(lpData
);
53 // Select initial directory
54 SendMessageW(hwnd
, BFFM_SETSELECTION
, FALSE
,
55 reinterpret_cast<LPARAM
>(static_cast<LPCITEMIDLIST
>(this_
->m_pidlFolder
)));
58 CString
strCaption(MAKEINTRESOURCEW(IDS_MOVEITEMS
));
59 SetWindowTextW(hwnd
, strCaption
);
62 CString
strMove(MAKEINTRESOURCEW(IDS_MOVEBUTTON
));
63 SetDlgItemText(hwnd
, IDOK
, strMove
);
66 this_
->m_fnOldWndProc
=
67 reinterpret_cast<WNDPROC
>(
68 SetWindowLongPtr(hwnd
, GWLP_WNDPROC
, reinterpret_cast<LONG_PTR
>(WindowProc
)));
71 PostMessageW(hwnd
, WM_ENABLEOK
, 0, FALSE
);
76 WCHAR szPath
[MAX_PATH
];
77 LPCITEMIDLIST pidl
= reinterpret_cast<LPCITEMIDLIST
>(lParam
);
80 SHGetPathFromIDListW(pidl
, szPath
);
82 if (ILIsEqual(pidl
, this_
->m_pidlFolder
))
83 PostMessageW(hwnd
, WM_ENABLEOK
, 0, FALSE
);
84 else if (PathFileExistsW(szPath
) || _ILIsDesktop(pidl
))
85 PostMessageW(hwnd
, WM_ENABLEOK
, 0, TRUE
);
87 PostMessageW(hwnd
, WM_ENABLEOK
, 0, FALSE
);
95 HRESULT
CMoveToMenu::DoRealMove(LPCMINVOKECOMMANDINFO lpici
, LPCITEMIDLIST pidl
)
97 CComHeapPtr
<CIDA
> pCIDA
;
98 HRESULT hr
= _GetCidlFromDataObject(m_pDataObject
, &pCIDA
);
99 if (FAILED_UNEXPECTEDLY(hr
))
102 PCUIDLIST_ABSOLUTE pidlParent
= HIDA_GetPIDLFolder(pCIDA
);
105 ERR("HIDA_GetPIDLFolder failed\n");
110 WCHAR szPath
[MAX_PATH
];
111 for (UINT n
= 0; n
< pCIDA
->cidl
; ++n
)
113 PCUIDLIST_RELATIVE pidlRelative
= HIDA_GetPIDLItem(pCIDA
, n
);
117 CComHeapPtr
<ITEMIDLIST
> pidlCombine(ILCombine(pidlParent
, pidlRelative
));
121 SHGetPathFromIDListW(pidlCombine
, szPath
);
128 strFiles
+= L
'|'; // double null-terminated
129 strFiles
.Replace(L
'|', L
'\0');
131 if (_ILIsDesktop(pidl
))
132 SHGetSpecialFolderPathW(NULL
, szPath
, CSIDL_DESKTOPDIRECTORY
, FALSE
);
134 SHGetPathFromIDListW(pidl
, szPath
);
135 INT cchPath
= lstrlenW(szPath
);
136 if (cchPath
+ 1 < MAX_PATH
)
138 szPath
[cchPath
+ 1] = 0; // double null-terminated
142 ERR("Too long path\n");
146 SHFILEOPSTRUCTW op
= { lpici
->hwnd
};
150 op
.fFlags
= FOF_ALLOWUNDO
;
151 return ((SHFileOperation(&op
) == 0) ? S_OK
: E_FAIL
);
154 CStringW
CMoveToMenu::DoGetFileTitle()
156 CStringW ret
= L
"(file)";
158 CComHeapPtr
<CIDA
> pCIDA
;
159 HRESULT hr
= _GetCidlFromDataObject(m_pDataObject
, &pCIDA
);
160 if (FAILED_UNEXPECTEDLY(hr
))
163 PCUIDLIST_ABSOLUTE pidlParent
= HIDA_GetPIDLFolder(pCIDA
);
166 ERR("HIDA_GetPIDLFolder failed\n");
170 WCHAR szPath
[MAX_PATH
];
171 PCUIDLIST_RELATIVE pidlRelative
= HIDA_GetPIDLItem(pCIDA
, 0);
174 ERR("HIDA_GetPIDLItem failed\n");
178 CComHeapPtr
<ITEMIDLIST
> pidlCombine(ILCombine(pidlParent
, pidlRelative
));
180 if (SHGetPathFromIDListW(pidlCombine
, szPath
))
181 ret
= PathFindFileNameW(szPath
);
183 ERR("Cannot get path\n");
191 HRESULT
CMoveToMenu::DoMoveToFolder(LPCMINVOKECOMMANDINFO lpici
)
193 WCHAR wszPath
[MAX_PATH
];
196 TRACE("DoMoveToFolder(%p)\n", lpici
);
198 if (!SHGetPathFromIDListW(m_pidlFolder
, wszPath
))
200 ERR("SHGetPathFromIDListW failed\n");
204 CStringW strFileTitle
= DoGetFileTitle();
206 strTitle
.Format(IDS_MOVETOTITLE
, static_cast<LPCWSTR
>(strFileTitle
));
208 BROWSEINFOW info
= { lpici
->hwnd
};
209 info
.pidlRoot
= NULL
;
210 info
.lpszTitle
= strTitle
;
211 info
.ulFlags
= BIF_RETURNONLYFSDIRS
| BIF_USENEWUI
;
212 info
.lpfn
= BrowseCallbackProc
;
213 info
.lParam
= reinterpret_cast<LPARAM
>(this);
214 CComHeapPtr
<ITEMIDLIST
> pidl(SHBrowseForFolder(&info
));
217 hr
= DoRealMove(lpici
, pidl
);
224 CMoveToMenu::QueryContextMenu(HMENU hMenu
,
233 TRACE("CMoveToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
234 hMenu
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
236 m_idCmdFirst
= m_idCmdLast
= idCmdFirst
;
238 // insert separator if necessary
239 CStringW
strCopyTo(MAKEINTRESOURCEW(IDS_COPYTOMENU
));
241 ZeroMemory(&mii
, sizeof(mii
));
242 mii
.cbSize
= sizeof(mii
);
243 mii
.fMask
= MIIM_TYPE
;
244 mii
.dwTypeData
= szBuff
;
245 mii
.cch
= _countof(szBuff
);
246 if (GetMenuItemInfoW(hMenu
, indexMenu
- 1, TRUE
, &mii
) &&
247 mii
.fType
!= MFT_SEPARATOR
&&
248 !(mii
.fType
== MFT_STRING
&& CStringW(szBuff
) == strCopyTo
))
250 ZeroMemory(&mii
, sizeof(mii
));
251 mii
.cbSize
= sizeof(mii
);
252 mii
.fMask
= MIIM_TYPE
;
253 mii
.fType
= MFT_SEPARATOR
;
254 if (InsertMenuItemW(hMenu
, indexMenu
, TRUE
, &mii
))
261 // insert "Move to folder..."
262 CStringW
strText(MAKEINTRESOURCEW(IDS_MOVETOMENU
));
263 ZeroMemory(&mii
, sizeof(mii
));
264 mii
.cbSize
= sizeof(mii
);
265 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
266 mii
.fType
= MFT_STRING
;
267 mii
.dwTypeData
= strText
.GetBuffer();
268 mii
.cch
= wcslen(mii
.dwTypeData
);
269 mii
.wID
= m_idCmdLast
;
270 if (InsertMenuItemW(hMenu
, indexMenu
, TRUE
, &mii
))
272 m_idCmdMoveTo
= m_idCmdLast
++;
277 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, Count
);
281 CMoveToMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
284 TRACE("CMoveToMenu::InvokeCommand(%p)\n", lpici
);
286 if (HIWORD(lpici
->lpVerb
) == 0)
288 if (m_idCmdFirst
+ LOWORD(lpici
->lpVerb
) == m_idCmdMoveTo
)
290 hr
= DoMoveToFolder(lpici
);
295 if (::lstrcmpiA(lpici
->lpVerb
, "moveto") == 0)
297 hr
= DoMoveToFolder(lpici
);
305 CMoveToMenu::GetCommandString(UINT_PTR idCmd
,
311 FIXME("%p %lu %u %p %p %u\n", this,
312 idCmd
, uType
, pwReserved
, pszName
, cchMax
);
318 CMoveToMenu::HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
320 TRACE("This %p uMsg %x\n", this, uMsg
);
325 CMoveToMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder
,
326 IDataObject
*pdtobj
, HKEY hkeyProgID
)
328 m_pidlFolder
.Attach(ILClone(pidlFolder
));
329 m_pDataObject
= pdtobj
;
333 HRESULT WINAPI
CMoveToMenu::SetSite(IUnknown
*pUnkSite
)
339 HRESULT WINAPI
CMoveToMenu::GetSite(REFIID riid
, void **ppvSite
)
344 return m_pSite
->QueryInterface(riid
, ppvSite
);