ReactOS  0.4.15-dev-1187-g119f102
CSendToMenu.cpp
Go to the documentation of this file.
1 /*
2  * provides SendTo shell item service
3  *
4  * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "precomp.h"
22 
24 
26  : m_hSubMenu(NULL)
27  , m_pItems(NULL)
28  , m_idCmdFirst(0)
29 {
31  if (FAILED(hr))
32  {
33  ERR("SHGetDesktopFolder: %08lX\n", hr);
34  }
35 
37 }
38 
40 {
42 
43  if (m_hSubMenu)
44  {
46  m_hSubMenu = NULL;
47  }
48 }
49 
51 {
52  DWORD dwEffect = DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK;
53 
55  BOOL bCtrl = (GetAsyncKeyState(VK_CONTROL) < 0);
56 
57  // THIS CODE IS NOT HUMAN-FRIENDLY. SORRY.
58  // (We have to translate a SendTo action to a Drop action)
59  DWORD dwKeyState = MK_LBUTTON;
60  if (bShift && bCtrl)
61  dwKeyState |= MK_SHIFT | MK_CONTROL;
62  else if (!bShift)
63  dwKeyState |= MK_CONTROL;
64  if (bCtrl)
65  dwKeyState |= MK_SHIFT;
66 
67  POINTL ptl = { 0, 0 };
68  HRESULT hr = pDropTarget->DragEnter(pDataObject, dwKeyState, ptl, &dwEffect);
70  {
71  pDropTarget->DragLeave();
72  return hr;
73  }
74 
75  if (dwEffect == DROPEFFECT_NONE)
76  {
77  ERR("DROPEFFECT_NONE\n");
78  pDropTarget->DragLeave();
79  return E_FAIL;
80  }
81 
82  // THIS CODE IS NOT HUMAN-FRIENDLY. SORRY.
83  // (We have to translate a SendTo action to a Drop action)
84  if (bShift && bCtrl)
85  dwEffect = DROPEFFECT_LINK;
86  else if (!bShift)
87  dwEffect = DROPEFFECT_MOVE;
88  else
89  dwEffect = DROPEFFECT_COPY;
90 
91  hr = pDropTarget->Drop(pDataObject, dwKeyState, ptl, &dwEffect);
93  return hr;
94 
95  return hr;
96 }
97 
98 // get an IShellFolder from CSIDL
99 HRESULT
101  int csidl, PIDLIST_ABSOLUTE *ppidl)
102 {
103  if (!ppFolder)
104  return E_POINTER;
105  *ppFolder = NULL;
106 
107  if (ppidl)
108  *ppidl = NULL;
109 
111  HRESULT hr = SHGetSpecialFolderLocation(hwnd, csidl, &pidl);
112  if (FAILED_UNEXPECTEDLY(hr))
113  return hr;
114 
115  IShellFolder *pFolder = NULL;
116  hr = m_pDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &pFolder));
117 
118  if (ppidl)
119  *ppidl = pidl.Detach();
120 
121  if (FAILED_UNEXPECTEDLY(hr))
122  return hr;
123 
124  *ppFolder = pFolder;
125  return hr;
126 }
127 
128 // get a UI object from PIDL
130  REFIID riid, LPVOID *ppvOut)
131 {
132  *ppvOut = NULL;
133 
134  PCITEMID_CHILD pidlLast;
135  CComPtr<IShellFolder> pFolder;
136  HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &pFolder), &pidlLast);
137  if (FAILED_UNEXPECTEDLY(hr))
138  return hr;
139 
140  hr = pFolder->GetUIObjectOf(hwnd, 1, &pidlLast, riid, NULL, ppvOut);
141  if (FAILED_UNEXPECTEDLY(hr))
142  return hr;
143 
144  return hr;
145 }
146 
148 {
150  m_pItems = NULL;
151  while (pItems)
152  {
153  SENDTO_ITEM *pCurItem = pItems;
154  pItems = pItems->pNext;
155  delete pCurItem;
156  }
157 }
158 
160 {
161  UnloadAllItems();
162 
164 
165  m_pSendTo.Release();
167  if (FAILED_UNEXPECTEDLY(hr))
168  return hr;
169 
170  CComPtr<IEnumIDList> pEnumIDList;
171  hr = m_pSendTo->EnumObjects(hwnd,
172  SHCONTF_FOLDERS | SHCONTF_NONFOLDERS,
173  &pEnumIDList);
174  if (FAILED_UNEXPECTEDLY(hr))
175  return hr;
176 
177  hr = S_OK;
179  while (pEnumIDList->Next(1, &child, NULL) == S_OK)
180  {
181  CComHeapPtr<ITEMID_CHILD> pidlChild(child);
182 
183  STRRET strret;
184  hr = m_pSendTo->GetDisplayNameOf(pidlChild, SHGDN_NORMAL, &strret);
185  if (FAILED_UNEXPECTEDLY(hr))
186  continue;
187 
188  CComHeapPtr<WCHAR> pszText;
189  hr = StrRetToStrW(&strret, pidlChild, &pszText);
190  if (FAILED_UNEXPECTEDLY(hr))
191  continue;
192 
194  pidlAbsolute.Attach(ILCombine(pidlSendTo, pidlChild));
195 
196  SHFILEINFOW fi = { NULL };
199  SHGetFileInfoW(reinterpret_cast<LPWSTR>(static_cast<PIDLIST_ABSOLUTE>(pidlAbsolute)), 0,
200  &fi, sizeof(fi), uFlags);
201 
202  SENDTO_ITEM *pNewItem =
203  new SENDTO_ITEM(pidlChild.Detach(), pszText.Detach(), fi.hIcon);
204  if (m_pItems)
205  {
206  pNewItem->pNext = m_pItems;
207  }
208  m_pItems = pNewItem;
209  }
210 
211  return hr;
212 }
213 
215 {
216  if (m_pItems == NULL)
217  {
219  if (FAILED_UNEXPECTEDLY(hr))
220  return 0;
221  }
222 
223  m_idCmdFirst = idCmdFirst;
224 
225  UINT idCmd = idCmdFirst;
226  for (SENDTO_ITEM *pCurItem = m_pItems; pCurItem; pCurItem = pCurItem->pNext)
227  {
229  if (InsertMenuW(hMenu, Pos, uFlags, idCmd, pCurItem->pszText))
230  {
231  MENUITEMINFOW mii;
232  mii.cbSize = sizeof(mii);
233  mii.fMask = MIIM_DATA | MIIM_BITMAP;
234  mii.dwItemData = reinterpret_cast<ULONG_PTR>(pCurItem);
235  mii.hbmpItem = HBMMENU_CALLBACK;
236  SetMenuItemInfoW(hMenu, idCmd, FALSE, &mii);
237  ++idCmd;
238 
239  // successful
240  }
241  }
242 
243  if (idCmd == idCmdFirst)
244  {
246  AppendMenuW(hMenu, MF_GRAYED | MF_DISABLED | MF_STRING, idCmd, strNone);
247  }
248 
249  return idCmd - idCmdFirst;
250 }
251 
253 {
254  UINT idCmd = m_idCmdFirst + IdOffset;
255 
256  MENUITEMINFOW mii = { sizeof(mii) };
257  mii.fMask = MIIM_DATA;
258  if (GetMenuItemInfoW(m_hSubMenu, idCmd, FALSE, &mii))
259  return reinterpret_cast<SENDTO_ITEM *>(mii.dwItemData);
260 
261  ERR("GetMenuItemInfoW: %ld\n", GetLastError());
262  return NULL;
263 }
264 
266 {
267  if (!m_pDataObject)
268  {
269  ERR("!m_pDataObject\n");
270  return E_FAIL;
271  }
272 
273  HRESULT hr;
274  CComPtr<IDropTarget> pDropTarget;
275  hr = m_pSendTo->GetUIObjectOf(NULL, 1, &pItem->pidlChild, IID_IDropTarget,
276  NULL, (LPVOID *)&pDropTarget);
277  if (FAILED_UNEXPECTEDLY(hr))
278  return hr;
279 
280  hr = DoDrop(m_pDataObject, pDropTarget);
281  if (FAILED_UNEXPECTEDLY(hr))
282  return hr;
283 
284  return hr;
285 }
286 
289  UINT indexMenu,
290  UINT idCmdFirst,
291  UINT idCmdLast,
292  UINT uFlags)
293 {
294  TRACE("%p %p %u %u %u %u\n", this,
295  hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
296 
297  HMENU hSubMenu = CreateMenu();
298  if (!hSubMenu)
299  {
300  ERR("CreateMenu: %ld\n", GetLastError());
301  return E_FAIL;
302  }
303 
304  UINT cItems = InsertSendToItems(hSubMenu, idCmdFirst, 0);
305 
307 
308  MENUITEMINFOW mii = { sizeof(mii) };
310  mii.fType = MFT_STRING;
311  mii.wID = -1;
312  mii.dwTypeData = strSendTo.GetBuffer();
313  mii.cch = wcslen(mii.dwTypeData);
314  mii.fState = MFS_ENABLED;
315  mii.hSubMenu = hSubMenu;
316  if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
317  {
318  ERR("InsertMenuItemW: %ld\n", GetLastError());
319  return E_FAIL;
320  }
321 
322  HMENU hOldSubMenu = m_hSubMenu;
323  m_hSubMenu = hSubMenu;
324  DestroyMenu(hOldSubMenu);
325 
326  return MAKE_HRESULT(SEVERITY_SUCCESS, 0, cItems);
327 }
328 
331 {
332  HRESULT hr = E_FAIL;
333 
334  WORD idCmd = LOWORD(lpici->lpVerb);
335  TRACE("idCmd: %d\n", idCmd);
336 
337  SENDTO_ITEM *pItem = FindItemFromIdOffset(idCmd);
338  if (pItem)
339  {
340  hr = DoSendToItem(pItem, lpici);
341  }
342 
343  TRACE("CSendToMenu::InvokeCommand %x\n", hr);
344  return hr;
345 }
346 
349  UINT uType,
350  UINT *pwReserved,
351  LPSTR pszName,
352  UINT cchMax)
353 {
354  FIXME("%p %lu %u %p %p %u\n", this,
355  idCmd, uType, pwReserved, pszName, cchMax);
356 
357  return E_NOTIMPL;
358 }
359 
362 {
363  return S_OK;
364 }
365 
368  LRESULT *plResult)
369 {
370  UINT cxSmall = GetSystemMetrics(SM_CXSMICON);
371  UINT cySmall = GetSystemMetrics(SM_CYSMICON);
372 
373  switch (uMsg)
374  {
375  case WM_MEASUREITEM:
376  {
377  MEASUREITEMSTRUCT* lpmis = reinterpret_cast<MEASUREITEMSTRUCT*>(lParam);
378  if (!lpmis || lpmis->CtlType != ODT_MENU)
379  break;
380 
381  UINT cxMenuCheck = GetSystemMetrics(SM_CXMENUCHECK);
382  if (lpmis->itemWidth < cxMenuCheck)
383  lpmis->itemWidth = cxMenuCheck;
384  if (lpmis->itemHeight < cySmall)
385  lpmis->itemHeight = cySmall;
386 
387  if (plResult)
388  *plResult = TRUE;
389  break;
390  }
391  case WM_DRAWITEM:
392  {
393  DRAWITEMSTRUCT* lpdis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);
394  if (!lpdis || lpdis->CtlType != ODT_MENU)
395  break;
396 
397  SENDTO_ITEM *pItem = reinterpret_cast<SENDTO_ITEM *>(lpdis->itemData);
398  HICON hIcon = NULL;
399  if (pItem)
400  hIcon = pItem->hIcon;
401  if (!hIcon)
402  break;
403 
404  const RECT& rcItem = lpdis->rcItem;
405  INT x = 4;
406  INT y = lpdis->rcItem.top;
407  y += (rcItem.bottom - rcItem.top - cySmall) / 2;
408  DrawIconEx(lpdis->hDC, x, y, hIcon, cxSmall, cySmall,
409  0, NULL, DI_NORMAL);
410 
411  if (plResult)
412  *plResult = TRUE;
413  }
414  }
415 
416  return S_OK;
417 }
418 
421  IDataObject *pdtobj, HKEY hkeyProgID)
422 {
423  m_pDataObject = pdtobj;
424  return S_OK;
425 }
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
HMENU WINAPI CreateMenu(void)
Definition: menu.c:837
static HICON
Definition: imagelist.c:84
#define MFT_STRING
Definition: winuser.h:741
#define MF_DISABLED
Definition: winuser.h:130
#define REFIID
Definition: guiddef.h:118
WINE_DEFAULT_DEBUG_CHANNEL(shell)
#define MK_SHIFT
Definition: winuser.h:2344
#define SHGFI_TYPENAME
Definition: shellapi.h:165
CComPtr< IDataObject > m_pDataObject
Definition: CSendToMenu.h:67
HRESULT hr
Definition: shlfolder.c:183
BOOL WINAPI InsertMenuW(_In_ HMENU, _In_ UINT, _In_ UINT, _In_ UINT_PTR, _In_opt_ LPCWSTR)
#define MK_LBUTTON
Definition: winuser.h:2342
#define TRUE
Definition: types.h:120
REFIID riid
Definition: precomp.h:44
STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
CComPtr< IShellFolder > m_pSendTo
Definition: CSendToMenu.h:66
#define IDS_NONE
Definition: resource.h:123
LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:699
#define ODT_MENU
Definition: winuser.h:2512
ush Pos
Definition: deflate.h:92
#define MF_STRING
Definition: winuser.h:138
#define SM_CXMENUCHECK
Definition: winuser.h:1021
LONG top
Definition: windef.h:307
ULONG_PTR itemData
Definition: winuser.h:3068
volatile BOOLEAN bShift
Definition: shell.c:71
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1044
#define SM_CYSMICON
Definition: winuser.h:1003
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
LPWSTR dwTypeData
Definition: winuser.h:3244
UINT_PTR WPARAM
Definition: windef.h:207
UINT uFlags
Definition: api.c:59
char * LPSTR
Definition: xmlstorage.h:182
#define IID_PPV_ARG(Itype, ppType)
#define E_FAIL
Definition: ddrawi.h:102
#define SHGFI_SMALLICON
Definition: shellapi.h:174
int32_t INT
Definition: typedefs.h:58
static HWND child
Definition: cursoricon.c:298
WPARAM wParam
Definition: combotst.c:138
#define MIIM_BITMAP
Definition: winuser.h:723
#define SEVERITY_SUCCESS
Definition: winerror.h:64
BOOL WINAPI AppendMenuW(_In_ HMENU, _In_ UINT, _In_ UINT_PTR, _In_opt_ LPCWSTR)
HRESULT DoDrop(IDataObject *pDataObject, IDropTarget *pDropTarget)
Definition: CSendToMenu.cpp:50
SENDTO_ITEM * FindItemFromIdOffset(UINT IdOffset)
#define MIIM_SUBMENU
Definition: winuser.h:718
#define MFS_ENABLED
Definition: winuser.h:745
#define FALSE
Definition: types.h:117
#define MIIM_STATE
Definition: winuser.h:716
HRESULT GetUIObjectFromPidl(HWND hwnd, PIDLIST_ABSOLUTE pidl, REFIID riid, LPVOID *ppvOut)
unsigned int BOOL
Definition: ntddk_ex.h:94
#define MF_BYPOSITION
Definition: winuser.h:203
#define SHGFI_PIDL
Definition: shellapi.h:178
#define FIXME(fmt,...)
Definition: debug.h:111
#define STDMETHODIMP
Definition: basetyps.h:43
#define VK_SHIFT
Definition: winuser.h:2177
BOOL WINAPI SetMenuItemInfoW(_In_ HMENU, _In_ UINT, _In_ BOOL, _In_ LPCMENUITEMINFOW)
PITEMID_CHILD pidlChild
Definition: CSendToMenu.h:36
smooth NULL
Definition: ftsmooth.c:416
SENDTO_ITEM * m_pItems
Definition: CSendToMenu.h:62
LONG_PTR LPARAM
Definition: windef.h:208
STDMETHODIMP HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult)
#define MAKE_HRESULT(sev, fac, code)
Definition: dmerror.h:30
#define MIIM_ID
Definition: winuser.h:717
STDMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
static int int const SCRIPT_CONTROL const SCRIPT_STATE SCRIPT_ITEM * pItems
Definition: usp10.c:62
#define HBMMENU_CALLBACK
Definition: winuser.h:2605
BOOL WINAPI GetMenuItemInfoW(_In_ HMENU, _In_ UINT, _In_ BOOL, _Inout_ LPMENUITEMINFOW)
#define TRACE(s)
Definition: solgame.cpp:4
HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
HRESULT DragEnter([in, unique] IDataObject *pDataObj, [in] DWORD grfKeyState, [in] POINTL pt, [in, out] DWORD *pdwEffect)
DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path, DWORD dwFileAttributes, SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags)
Definition: shell32_main.c:413
BOOL WINAPI DrawIconEx(_In_ HDC, _In_ int, _In_ int, _In_ HICON, _In_ int, _In_ int, _In_ UINT, _In_opt_ HBRUSH, _In_ UINT)
Definition: cursoricon.c:1997
HRESULT WINAPI SHGetSpecialFolderLocation(HWND hwndOwner, INT nFolder, LPITEMIDLIST *ppidl)
Definition: shellpath.c:2830
LONG HRESULT
Definition: typedefs.h:79
#define MF_ENABLED
Definition: winuser.h:128
#define CSIDL_SENDTO
Definition: shlobj.h:2021
#define FAILED_UNEXPECTEDLY(hr)
Definition: shellutils.h:71
unsigned short WORD
Definition: ntddk_ex.h:93
int WINAPI GetSystemMetrics(_In_ int)
unsigned long DWORD
Definition: ntddk_ex.h:95
#define WM_MEASUREITEM
Definition: winuser.h:1628
UINT InsertSendToItems(HMENU hMenu, UINT idFirst, UINT idMenu)
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
HMENU m_hSubMenu
Definition: CSendToMenu.h:61
UINT cchMax
#define SM_CXSMICON
Definition: winuser.h:1002
HRESULT LoadAllItems(HWND hwnd)
#define MIIM_TYPE
Definition: winuser.h:720
SHORT WINAPI GetAsyncKeyState(_In_ int)
#define DI_NORMAL
Definition: wingdi.h:72
UINT m_idCmdFirst
Definition: CSendToMenu.h:63
HICON hIcon
Definition: shellapi.h:370
BOOL WINAPI DestroyMenu(_In_ HMENU)
#define ERR(fmt,...)
Definition: debug.h:110
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
#define S_OK
Definition: intsafe.h:51
HRESULT Drop([in, unique] IDataObject *pDataObj, [in] DWORD grfKeyState, [in] POINTL pt, [in, out] DWORD *pdwEffect)
HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast)
Definition: pidl.c:1337
void shell(int argc, const char *argv[])
Definition: cmds.c:1231
HICON hIcon
Definition: msconfig.c:44
void Release()
Definition: atlcomcli.h:140
#define E_NOTIMPL
Definition: ddrawi.h:99
STDMETHODIMP GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen)
void UnloadAllItems()
BOOL WINAPI InsertMenuItemW(_In_ HMENU, _In_ UINT, _In_ BOOL, _In_ LPCMENUITEMINFOW)
#define IDS_SENDTO_MENU
Definition: shresdef.h:232
unsigned int UINT
Definition: ndis.h:50
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
#define MK_CONTROL
Definition: winuser.h:2345
#define VK_CONTROL
Definition: winuser.h:2178
#define WM_DRAWITEM
Definition: winuser.h:1627
LONG bottom
Definition: windef.h:309
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
#define MF_GRAYED
Definition: winuser.h:129
#define MIIM_DATA
Definition: winuser.h:721
LONG_PTR LRESULT
Definition: windef.h:209
#define E_POINTER
Definition: winerror.h:2365
#define SHGFI_ICON
Definition: shellapi.h:162
HRESULT GetSpecialFolder(HWND hwnd, IShellFolder **ppFolder, int csidl, PIDLIST_ABSOLUTE *ppidl=NULL)
CComPtr< IShellFolder > m_pDesktop
Definition: CSendToMenu.h:65
ULONG_PTR dwItemData
Definition: winuser.h:3243
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:60
HRESULT DoSendToItem(SENDTO_ITEM *pItem, LPCMINVOKECOMMANDINFO lpici)
LPARAM lParam
Definition: combotst.c:139
#define LOWORD(l)
Definition: pedump.c:82
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
Definition: string.c:1623
HRESULT DragLeave()
STDMETHODIMP HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)