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
:
106 WCHAR szPath
[MAX_PATH
];
107 LPCITEMIDLIST pidl
= reinterpret_cast<LPCITEMIDLIST
>(lParam
);
110 SHGetPathFromIDListW(pidl
, szPath
);
112 if (ILIsEqual(pidl
, this_
->m_pidlFolder
))
113 PostMessageW(hwnd
, BFFM_ENABLEOK
, 0, FALSE
);
114 else if (PathFileExistsW(szPath
) || _ILIsDesktop(pidl
))
115 PostMessageW(hwnd
, BFFM_ENABLEOK
, 0, TRUE
);
117 PostMessageW(hwnd
, BFFM_ENABLEOK
, 0, FALSE
);
119 // the text box will be updated later soon, ignore it
120 this_
->m_bIgnoreTextBoxChange
= TRUE
;
128 HRESULT
CMoveToMenu::DoRealMove(LPCMINVOKECOMMANDINFO lpici
, LPCITEMIDLIST pidl
)
130 CDataObjectHIDA
pCIDA(m_pDataObject
);
131 if (FAILED_UNEXPECTEDLY(pCIDA
.hr()))
134 PCUIDLIST_ABSOLUTE pidlParent
= HIDA_GetPIDLFolder(pCIDA
);
137 ERR("HIDA_GetPIDLFolder failed\n");
142 WCHAR szPath
[MAX_PATH
];
143 for (UINT n
= 0; n
< pCIDA
->cidl
; ++n
)
145 PCUIDLIST_RELATIVE pidlRelative
= HIDA_GetPIDLItem(pCIDA
, n
);
149 CComHeapPtr
<ITEMIDLIST
> pidlCombine(ILCombine(pidlParent
, pidlRelative
));
153 SHGetPathFromIDListW(pidlCombine
, szPath
);
160 strFiles
+= L
'|'; // double null-terminated
161 strFiles
.Replace(L
'|', L
'\0');
163 if (_ILIsDesktop(pidl
))
164 SHGetSpecialFolderPathW(NULL
, szPath
, CSIDL_DESKTOPDIRECTORY
, FALSE
);
166 SHGetPathFromIDListW(pidl
, szPath
);
167 INT cchPath
= lstrlenW(szPath
);
168 if (cchPath
+ 1 < MAX_PATH
)
170 szPath
[cchPath
+ 1] = 0; // double null-terminated
174 ERR("Too long path\n");
178 SHFILEOPSTRUCTW op
= { lpici
->hwnd
};
182 op
.fFlags
= FOF_ALLOWUNDO
;
183 int res
= SHFileOperationW(&op
);
186 ERR("SHFileOperationW failed with 0x%x\n", res
);
192 CStringW
CMoveToMenu::DoGetFileTitle()
194 CStringW ret
= L
"(file)";
196 CDataObjectHIDA
pCIDA(m_pDataObject
);
197 if (FAILED_UNEXPECTEDLY(pCIDA
.hr()))
200 PCUIDLIST_ABSOLUTE pidlParent
= HIDA_GetPIDLFolder(pCIDA
);
203 ERR("HIDA_GetPIDLFolder failed\n");
207 WCHAR szPath
[MAX_PATH
];
208 PCUIDLIST_RELATIVE pidlRelative
= HIDA_GetPIDLItem(pCIDA
, 0);
211 ERR("HIDA_GetPIDLItem failed\n");
215 CComHeapPtr
<ITEMIDLIST
> pidlCombine(ILCombine(pidlParent
, pidlRelative
));
217 if (SHGetPathFromIDListW(pidlCombine
, szPath
))
218 ret
= PathFindFileNameW(szPath
);
220 ERR("Cannot get path\n");
228 HRESULT
CMoveToMenu::DoMoveToFolder(LPCMINVOKECOMMANDINFO lpici
)
230 WCHAR wszPath
[MAX_PATH
];
233 TRACE("DoMoveToFolder(%p)\n", lpici
);
235 if (!SHGetPathFromIDListW(m_pidlFolder
, wszPath
))
237 ERR("SHGetPathFromIDListW failed\n");
241 CStringW strFileTitle
= DoGetFileTitle();
243 strTitle
.Format(IDS_MOVETOTITLE
, static_cast<LPCWSTR
>(strFileTitle
));
245 BROWSEINFOW info
= { lpici
->hwnd
};
246 info
.pidlRoot
= NULL
;
247 info
.lpszTitle
= strTitle
;
248 info
.ulFlags
= BIF_RETURNONLYFSDIRS
| BIF_USENEWUI
;
249 info
.lpfn
= BrowseCallbackProc
;
250 info
.lParam
= reinterpret_cast<LPARAM
>(this);
251 CComHeapPtr
<ITEMIDLIST
> pidl(SHBrowseForFolder(&info
));
254 hr
= DoRealMove(lpici
, pidl
);
261 CMoveToMenu::QueryContextMenu(HMENU hMenu
,
270 TRACE("CMoveToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
271 hMenu
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
273 m_idCmdFirst
= m_idCmdLast
= idCmdFirst
;
275 // insert separator if necessary
276 CStringW
strCopyTo(MAKEINTRESOURCEW(IDS_COPYTOMENU
));
278 ZeroMemory(&mii
, sizeof(mii
));
279 mii
.cbSize
= sizeof(mii
);
280 mii
.fMask
= MIIM_TYPE
;
281 mii
.dwTypeData
= szBuff
;
282 mii
.cch
= _countof(szBuff
);
283 if (GetMenuItemInfoW(hMenu
, indexMenu
- 1, TRUE
, &mii
) &&
284 mii
.fType
!= MFT_SEPARATOR
&&
285 !(mii
.fType
== MFT_STRING
&& CStringW(szBuff
) == strCopyTo
))
287 ZeroMemory(&mii
, sizeof(mii
));
288 mii
.cbSize
= sizeof(mii
);
289 mii
.fMask
= MIIM_TYPE
;
290 mii
.fType
= MFT_SEPARATOR
;
291 if (InsertMenuItemW(hMenu
, indexMenu
, TRUE
, &mii
))
298 // insert "Move to folder..."
299 CStringW
strText(MAKEINTRESOURCEW(IDS_MOVETOMENU
));
300 ZeroMemory(&mii
, sizeof(mii
));
301 mii
.cbSize
= sizeof(mii
);
302 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
303 mii
.fType
= MFT_STRING
;
304 mii
.dwTypeData
= strText
.GetBuffer();
305 mii
.cch
= wcslen(mii
.dwTypeData
);
306 mii
.wID
= m_idCmdLast
;
307 if (InsertMenuItemW(hMenu
, indexMenu
, TRUE
, &mii
))
309 m_idCmdMoveTo
= m_idCmdLast
++;
314 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, Count
);
318 CMoveToMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
321 TRACE("CMoveToMenu::InvokeCommand(%p)\n", lpici
);
323 if (HIWORD(lpici
->lpVerb
) == 0)
325 if (m_idCmdFirst
+ LOWORD(lpici
->lpVerb
) == m_idCmdMoveTo
)
327 hr
= DoMoveToFolder(lpici
);
332 if (::lstrcmpiA(lpici
->lpVerb
, "moveto") == 0)
334 hr
= DoMoveToFolder(lpici
);
342 CMoveToMenu::GetCommandString(UINT_PTR idCmd
,
348 FIXME("%p %lu %u %p %p %u\n", this,
349 idCmd
, uType
, pwReserved
, pszName
, cchMax
);
355 CMoveToMenu::HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
357 TRACE("This %p uMsg %x\n", this, uMsg
);
362 CMoveToMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder
,
363 IDataObject
*pdtobj
, HKEY hkeyProgID
)
365 m_pidlFolder
.Attach(ILClone(pidlFolder
));
366 m_pDataObject
= pdtobj
;
370 HRESULT WINAPI
CMoveToMenu::SetSite(IUnknown
*pUnkSite
)
376 HRESULT WINAPI
CMoveToMenu::GetSite(REFIID riid
, void **ppvSite
)
381 return m_pSite
->QueryInterface(riid
, ppvSite
);