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() :
17 m_bIgnoreTextBoxChange(FALSE
)
21 CMoveToMenu::~CMoveToMenu()
25 static LRESULT CALLBACK
26 WindowProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
28 WCHAR szPath
[MAX_PATH
];
30 reinterpret_cast<CMoveToMenu
*>(GetWindowLongPtr(hwnd
, GWLP_USERDATA
));
36 switch (LOWORD(wParam
))
38 case IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT
:
40 if (HIWORD(wParam
) == EN_CHANGE
)
42 if (!this_
->m_bIgnoreTextBoxChange
)
45 GetDlgItemTextW(hwnd
, IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT
, szPath
, _countof(szPath
));
46 StrTrimW(szPath
, L
" \t");
49 BOOL bValid
= !PathIsRelative(szPath
) && PathIsDirectoryW(szPath
);
50 SendMessageW(hwnd
, BFFM_ENABLEOK
, 0, bValid
);
56 this_
->m_bIgnoreTextBoxChange
= FALSE
;
64 return CallWindowProcW(this_
->m_fnOldWndProc
, hwnd
, uMsg
, wParam
, lParam
);
68 BrowseCallbackProc(HWND hwnd
, UINT uMsg
, LPARAM lParam
, LPARAM lpData
)
71 reinterpret_cast<CMoveToMenu
*>(GetWindowLongPtr(hwnd
, GWLP_USERDATA
));
75 case BFFM_INITIALIZED
:
77 SetWindowLongPtr(hwnd
, GWLP_USERDATA
, lpData
);
78 this_
= reinterpret_cast<CMoveToMenu
*>(lpData
);
80 // Select initial directory
81 SendMessageW(hwnd
, BFFM_SETSELECTION
, FALSE
,
82 reinterpret_cast<LPARAM
>(static_cast<LPCITEMIDLIST
>(this_
->m_pidlFolder
)));
85 CString
strCaption(MAKEINTRESOURCEW(IDS_MOVEITEMS
));
86 SetWindowTextW(hwnd
, strCaption
);
89 CString
strMove(MAKEINTRESOURCEW(IDS_MOVEBUTTON
));
90 SetDlgItemText(hwnd
, IDOK
, strMove
);
93 this_
->m_fnOldWndProc
=
94 reinterpret_cast<WNDPROC
>(
95 SetWindowLongPtr(hwnd
, GWLP_WNDPROC
, reinterpret_cast<LONG_PTR
>(WindowProc
)));
98 PostMessageW(hwnd
, BFFM_ENABLEOK
, 0, FALSE
);
101 case BFFM_SELCHANGED
:
103 WCHAR szPath
[MAX_PATH
];
104 LPCITEMIDLIST pidl
= reinterpret_cast<LPCITEMIDLIST
>(lParam
);
107 SHGetPathFromIDListW(pidl
, szPath
);
109 if (ILIsEqual(pidl
, this_
->m_pidlFolder
))
110 PostMessageW(hwnd
, BFFM_ENABLEOK
, 0, FALSE
);
111 else if (PathFileExistsW(szPath
) || _ILIsDesktop(pidl
))
112 PostMessageW(hwnd
, BFFM_ENABLEOK
, 0, TRUE
);
114 PostMessageW(hwnd
, BFFM_ENABLEOK
, 0, FALSE
);
116 // the text box will be updated later soon, ignore it
117 this_
->m_bIgnoreTextBoxChange
= TRUE
;
125 HRESULT
CMoveToMenu::DoRealMove(LPCMINVOKECOMMANDINFO lpici
, LPCITEMIDLIST pidl
)
127 CDataObjectHIDA
pCIDA(m_pDataObject
);
128 if (FAILED_UNEXPECTEDLY(pCIDA
.hr()))
131 PCUIDLIST_ABSOLUTE pidlParent
= HIDA_GetPIDLFolder(pCIDA
);
134 ERR("HIDA_GetPIDLFolder failed\n");
139 WCHAR szPath
[MAX_PATH
];
140 for (UINT n
= 0; n
< pCIDA
->cidl
; ++n
)
142 PCUIDLIST_RELATIVE pidlRelative
= HIDA_GetPIDLItem(pCIDA
, n
);
146 CComHeapPtr
<ITEMIDLIST
> pidlCombine(ILCombine(pidlParent
, pidlRelative
));
150 SHGetPathFromIDListW(pidlCombine
, szPath
);
157 strFiles
+= L
'|'; // double null-terminated
158 strFiles
.Replace(L
'|', L
'\0');
160 if (_ILIsDesktop(pidl
))
161 SHGetSpecialFolderPathW(NULL
, szPath
, CSIDL_DESKTOPDIRECTORY
, FALSE
);
163 SHGetPathFromIDListW(pidl
, szPath
);
164 INT cchPath
= lstrlenW(szPath
);
165 if (cchPath
+ 1 < MAX_PATH
)
167 szPath
[cchPath
+ 1] = 0; // double null-terminated
171 ERR("Too long path\n");
175 SHFILEOPSTRUCTW op
= { lpici
->hwnd
};
179 op
.fFlags
= FOF_ALLOWUNDO
;
180 int res
= SHFileOperationW(&op
);
183 ERR("SHFileOperationW failed with 0x%x\n", res
);
189 CStringW
CMoveToMenu::DoGetFileTitle()
191 CStringW ret
= L
"(file)";
193 CDataObjectHIDA
pCIDA(m_pDataObject
);
194 if (FAILED_UNEXPECTEDLY(pCIDA
.hr()))
197 PCUIDLIST_ABSOLUTE pidlParent
= HIDA_GetPIDLFolder(pCIDA
);
200 ERR("HIDA_GetPIDLFolder failed\n");
204 WCHAR szPath
[MAX_PATH
];
205 PCUIDLIST_RELATIVE pidlRelative
= HIDA_GetPIDLItem(pCIDA
, 0);
208 ERR("HIDA_GetPIDLItem failed\n");
212 CComHeapPtr
<ITEMIDLIST
> pidlCombine(ILCombine(pidlParent
, pidlRelative
));
214 if (SHGetPathFromIDListW(pidlCombine
, szPath
))
215 ret
= PathFindFileNameW(szPath
);
217 ERR("Cannot get path\n");
225 HRESULT
CMoveToMenu::DoMoveToFolder(LPCMINVOKECOMMANDINFO lpici
)
227 WCHAR wszPath
[MAX_PATH
];
230 TRACE("DoMoveToFolder(%p)\n", lpici
);
232 if (!SHGetPathFromIDListW(m_pidlFolder
, wszPath
))
234 ERR("SHGetPathFromIDListW failed\n");
238 CStringW strFileTitle
= DoGetFileTitle();
240 strTitle
.Format(IDS_MOVETOTITLE
, static_cast<LPCWSTR
>(strFileTitle
));
242 BROWSEINFOW info
= { lpici
->hwnd
};
243 info
.pidlRoot
= NULL
;
244 info
.lpszTitle
= strTitle
;
245 info
.ulFlags
= BIF_RETURNONLYFSDIRS
| BIF_USENEWUI
;
246 info
.lpfn
= BrowseCallbackProc
;
247 info
.lParam
= reinterpret_cast<LPARAM
>(this);
248 CComHeapPtr
<ITEMIDLIST
> pidl(SHBrowseForFolder(&info
));
251 hr
= DoRealMove(lpici
, pidl
);
258 CMoveToMenu::QueryContextMenu(HMENU hMenu
,
267 TRACE("CMoveToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
268 hMenu
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
270 m_idCmdFirst
= m_idCmdLast
= idCmdFirst
;
272 // insert separator if necessary
273 CStringW
strCopyTo(MAKEINTRESOURCEW(IDS_COPYTOMENU
));
275 ZeroMemory(&mii
, sizeof(mii
));
276 mii
.cbSize
= sizeof(mii
);
277 mii
.fMask
= MIIM_TYPE
;
278 mii
.dwTypeData
= szBuff
;
279 mii
.cch
= _countof(szBuff
);
280 if (GetMenuItemInfoW(hMenu
, indexMenu
- 1, TRUE
, &mii
) &&
281 mii
.fType
!= MFT_SEPARATOR
&&
282 !(mii
.fType
== MFT_STRING
&& CStringW(szBuff
) == strCopyTo
))
284 ZeroMemory(&mii
, sizeof(mii
));
285 mii
.cbSize
= sizeof(mii
);
286 mii
.fMask
= MIIM_TYPE
;
287 mii
.fType
= MFT_SEPARATOR
;
288 if (InsertMenuItemW(hMenu
, indexMenu
, TRUE
, &mii
))
295 // insert "Move to folder..."
296 CStringW
strText(MAKEINTRESOURCEW(IDS_MOVETOMENU
));
297 ZeroMemory(&mii
, sizeof(mii
));
298 mii
.cbSize
= sizeof(mii
);
299 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
300 mii
.fType
= MFT_STRING
;
301 mii
.dwTypeData
= strText
.GetBuffer();
302 mii
.cch
= wcslen(mii
.dwTypeData
);
303 mii
.wID
= m_idCmdLast
;
304 if (InsertMenuItemW(hMenu
, indexMenu
, TRUE
, &mii
))
306 m_idCmdMoveTo
= m_idCmdLast
++;
311 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, Count
);
315 CMoveToMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
318 TRACE("CMoveToMenu::InvokeCommand(%p)\n", lpici
);
320 if (HIWORD(lpici
->lpVerb
) == 0)
322 if (m_idCmdFirst
+ LOWORD(lpici
->lpVerb
) == m_idCmdMoveTo
)
324 hr
= DoMoveToFolder(lpici
);
329 if (::lstrcmpiA(lpici
->lpVerb
, "moveto") == 0)
331 hr
= DoMoveToFolder(lpici
);
339 CMoveToMenu::GetCommandString(UINT_PTR idCmd
,
345 FIXME("%p %lu %u %p %p %u\n", this,
346 idCmd
, uType
, pwReserved
, pszName
, cchMax
);
352 CMoveToMenu::HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
354 TRACE("This %p uMsg %x\n", this, uMsg
);
359 CMoveToMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder
,
360 IDataObject
*pdtobj
, HKEY hkeyProgID
)
362 m_pidlFolder
.Attach(ILClone(pidlFolder
));
363 m_pDataObject
= pdtobj
;
367 HRESULT WINAPI
CMoveToMenu::SetSite(IUnknown
*pUnkSite
)
373 HRESULT WINAPI
CMoveToMenu::GetSite(REFIID riid
, void **ppvSite
)
378 return m_pSite
->QueryInterface(riid
, ppvSite
);