Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423/* * provides SendTo shell item service * * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
#include "precomp.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
CSendToMenu::CSendToMenu() : m_hSubMenu(NULL) , m_pItems(NULL) , m_idCmdFirst(0){ HRESULT hr = SHGetDesktopFolder(&m_pDesktop); if (FAILED(hr)) { ERR("SHGetDesktopFolder: %08lX\n", hr); }
GetSpecialFolder(NULL, &m_pSendTo, CSIDL_SENDTO);}
CSendToMenu::~CSendToMenu(){ UnloadAllItems();
if (m_hSubMenu) { DestroyMenu(m_hSubMenu); m_hSubMenu = NULL; }}
HRESULT CSendToMenu::DoDrop(IDataObject *pDataObject, IDropTarget *pDropTarget){ DWORD dwEffect = DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK;
BOOL bShift = (GetAsyncKeyState(VK_SHIFT) < 0); BOOL bCtrl = (GetAsyncKeyState(VK_CONTROL) < 0);
// THIS CODE IS NOT HUMAN-FRIENDLY. SORRY. // (We have to translate a SendTo action to a Drop action) DWORD dwKeyState = MK_LBUTTON; if (bShift && bCtrl) dwKeyState |= MK_SHIFT | MK_CONTROL; else if (!bShift) dwKeyState |= MK_CONTROL; if (bCtrl) dwKeyState |= MK_SHIFT;
POINTL ptl = { 0, 0 }; HRESULT hr = pDropTarget->DragEnter(pDataObject, dwKeyState, ptl, &dwEffect); if (FAILED_UNEXPECTEDLY(hr)) { pDropTarget->DragLeave(); return hr; }
if (dwEffect == DROPEFFECT_NONE) { ERR("DROPEFFECT_NONE\n"); pDropTarget->DragLeave(); return E_FAIL; }
// THIS CODE IS NOT HUMAN-FRIENDLY. SORRY. // (We have to translate a SendTo action to a Drop action) if (bShift && bCtrl) dwEffect = DROPEFFECT_LINK; else if (!bShift) dwEffect = DROPEFFECT_MOVE; else dwEffect = DROPEFFECT_COPY;
hr = pDropTarget->Drop(pDataObject, dwKeyState, ptl, &dwEffect); if (FAILED_UNEXPECTEDLY(hr)) return hr;
return hr;}
// get an IShellFolder from CSIDLHRESULTCSendToMenu::GetSpecialFolder(HWND hwnd, IShellFolder **ppFolder, int csidl, PIDLIST_ABSOLUTE *ppidl){ if (!ppFolder) return E_POINTER; *ppFolder = NULL;
if (ppidl) *ppidl = NULL;
CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl; HRESULT hr = SHGetSpecialFolderLocation(hwnd, csidl, &pidl); if (FAILED_UNEXPECTEDLY(hr)) return hr;
IShellFolder *pFolder = NULL; hr = m_pDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &pFolder));
if (ppidl) *ppidl = pidl.Detach();
if (FAILED_UNEXPECTEDLY(hr)) return hr;
*ppFolder = pFolder; return hr;}
// get a UI object from PIDLHRESULT CSendToMenu::GetUIObjectFromPidl(HWND hwnd, PIDLIST_ABSOLUTE pidl, REFIID riid, LPVOID *ppvOut){ *ppvOut = NULL; HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(hwnd, pidl, riid, ppvOut); if (FAILED_UNEXPECTEDLY(hr)) return hr;
return hr;}
void CSendToMenu::UnloadAllItems(){ SENDTO_ITEM *pItems = m_pItems; m_pItems = NULL; while (pItems) { SENDTO_ITEM *pCurItem = pItems; pItems = pItems->pNext; delete pCurItem; }}
HRESULT CSendToMenu::LoadAllItems(HWND hwnd){ UnloadAllItems();
CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlSendTo;
m_pSendTo.Release(); HRESULT hr = GetSpecialFolder(hwnd, &m_pSendTo, CSIDL_SENDTO, &pidlSendTo); if (FAILED_UNEXPECTEDLY(hr)) return hr;
CComPtr<IEnumIDList> pEnumIDList; hr = m_pSendTo->EnumObjects(hwnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &pEnumIDList); if (FAILED_UNEXPECTEDLY(hr)) return hr;
hr = S_OK; PITEMID_CHILD child; while (pEnumIDList->Next(1, &child, NULL) == S_OK) { CComHeapPtr<ITEMID_CHILD> pidlChild(child);
STRRET strret; hr = m_pSendTo->GetDisplayNameOf(pidlChild, SHGDN_NORMAL, &strret); if (FAILED_UNEXPECTEDLY(hr)) continue;
CComHeapPtr<WCHAR> pszText; hr = StrRetToStrW(&strret, pidlChild, &pszText); if (FAILED_UNEXPECTEDLY(hr)) continue;
CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlAbsolute; pidlAbsolute.Attach(ILCombine(pidlSendTo, pidlChild));
SHFILEINFOW fi = { NULL }; const UINT uFlags = SHGFI_PIDL | SHGFI_TYPENAME | SHGFI_ICON | SHGFI_SMALLICON; SHGetFileInfoW(reinterpret_cast<LPWSTR>(static_cast<PIDLIST_ABSOLUTE>(pidlAbsolute)), 0, &fi, sizeof(fi), uFlags);
SENDTO_ITEM *pNewItem = new SENDTO_ITEM(pidlChild.Detach(), pszText.Detach(), fi.hIcon); if (m_pItems) { pNewItem->pNext = m_pItems; } m_pItems = pNewItem; }
return hr;}
UINT CSendToMenu::InsertSendToItems(HMENU hMenu, UINT idCmdFirst, UINT Pos){ if (m_pItems == NULL) { HRESULT hr = LoadAllItems(NULL); if (FAILED_UNEXPECTEDLY(hr)) return 0; }
m_idCmdFirst = idCmdFirst;
UINT idCmd = idCmdFirst; for (SENDTO_ITEM *pCurItem = m_pItems; pCurItem; pCurItem = pCurItem->pNext) { const UINT uFlags = MF_BYPOSITION | MF_STRING | MF_ENABLED; if (InsertMenuW(hMenu, Pos, uFlags, idCmd, pCurItem->pszText)) { MENUITEMINFOW mii; mii.cbSize = sizeof(mii); mii.fMask = MIIM_DATA | MIIM_BITMAP; mii.dwItemData = reinterpret_cast<ULONG_PTR>(pCurItem); mii.hbmpItem = HBMMENU_CALLBACK; SetMenuItemInfoW(hMenu, idCmd, FALSE, &mii); ++idCmd;
// successful } }
if (idCmd == idCmdFirst) { CStringW strNone(MAKEINTRESOURCEW(IDS_NONE)); AppendMenuW(hMenu, MF_GRAYED | MF_DISABLED | MF_STRING, idCmd, strNone); ++idCmd; }
return idCmd - idCmdFirst;}
CSendToMenu::SENDTO_ITEM *CSendToMenu::FindItemFromIdOffset(UINT IdOffset){ UINT idCmd = m_idCmdFirst + IdOffset;
MENUITEMINFOW mii = { sizeof(mii) }; mii.fMask = MIIM_DATA; if (GetMenuItemInfoW(m_hSubMenu, idCmd, FALSE, &mii)) return reinterpret_cast<SENDTO_ITEM *>(mii.dwItemData);
ERR("GetMenuItemInfoW: %ld\n", GetLastError()); return NULL;}
HRESULT CSendToMenu::DoSendToItem(SENDTO_ITEM *pItem, LPCMINVOKECOMMANDINFO lpici){ if (!m_pDataObject) { ERR("!m_pDataObject\n"); return E_FAIL; }
HRESULT hr; CComPtr<IDropTarget> pDropTarget; hr = m_pSendTo->GetUIObjectOf(NULL, 1, &pItem->pidlChild, IID_IDropTarget, NULL, (LPVOID *)&pDropTarget); if (FAILED_UNEXPECTEDLY(hr)) return hr;
hr = DoDrop(m_pDataObject, pDropTarget); if (FAILED_UNEXPECTEDLY(hr)) return hr;
return hr;}
STDMETHODIMPCSendToMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags){ TRACE("%p %p %u %u %u %u\n", this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
if (uFlags & (CMF_NOVERBS | CMF_VERBSONLY)) return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst);
HMENU hSubMenu = CreateMenu(); if (!hSubMenu) { ERR("CreateMenu: %ld\n", GetLastError()); return E_FAIL; }
UINT cItems = InsertSendToItems(hSubMenu, idCmdFirst, 0);
CStringW strSendTo(MAKEINTRESOURCEW(IDS_SENDTO_MENU));
MENUITEMINFOW mii = { sizeof(mii) }; mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE | MIIM_SUBMENU; mii.fType = MFT_STRING; mii.wID = -1; mii.dwTypeData = strSendTo.GetBuffer(); mii.cch = wcslen(mii.dwTypeData); mii.fState = MFS_ENABLED; mii.hSubMenu = hSubMenu; if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii)) { ERR("InsertMenuItemW: %ld\n", GetLastError()); return E_FAIL; }
HMENU hOldSubMenu = m_hSubMenu; m_hSubMenu = hSubMenu; DestroyMenu(hOldSubMenu);
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst + cItems);}
STDMETHODIMPCSendToMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici){ HRESULT hr = E_FAIL;
WORD idCmd = LOWORD(lpici->lpVerb); TRACE("idCmd: %d\n", idCmd);
SENDTO_ITEM *pItem = FindItemFromIdOffset(idCmd); if (pItem) { hr = DoSendToItem(pItem, lpici); }
TRACE("CSendToMenu::InvokeCommand %x\n", hr); return hr;}
STDMETHODIMPCSendToMenu::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax){ FIXME("%p %lu %u %p %p %u\n", this, idCmd, uType, pwReserved, pszName, cchMax);
return E_NOTIMPL;}
STDMETHODIMPCSendToMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam){ return S_OK;}
STDMETHODIMPCSendToMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult){ UINT cxSmall = GetSystemMetrics(SM_CXSMICON); UINT cySmall = GetSystemMetrics(SM_CYSMICON);
switch (uMsg) { case WM_MEASUREITEM: { MEASUREITEMSTRUCT* lpmis = reinterpret_cast<MEASUREITEMSTRUCT*>(lParam); if (!lpmis || lpmis->CtlType != ODT_MENU) break;
UINT cxMenuCheck = GetSystemMetrics(SM_CXMENUCHECK); if (lpmis->itemWidth < cxMenuCheck) lpmis->itemWidth = cxMenuCheck; if (lpmis->itemHeight < cySmall) lpmis->itemHeight = cySmall;
if (plResult) *plResult = TRUE; break; } case WM_DRAWITEM: { DRAWITEMSTRUCT* lpdis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam); if (!lpdis || lpdis->CtlType != ODT_MENU) break;
SENDTO_ITEM *pItem = reinterpret_cast<SENDTO_ITEM *>(lpdis->itemData); HICON hIcon = NULL; if (pItem) hIcon = pItem->hIcon; if (!hIcon) break;
const RECT& rcItem = lpdis->rcItem; INT x = 4; INT y = lpdis->rcItem.top; y += (rcItem.bottom - rcItem.top - cySmall) / 2; DrawIconEx(lpdis->hDC, x, y, hIcon, cxSmall, cySmall, 0, NULL, DI_NORMAL);
if (plResult) *plResult = TRUE; } }
return S_OK;}
STDMETHODIMPCSendToMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID){ m_pDataObject = pdtobj; return S_OK;}