1 /*
2 * ReactOS Explorer
3 *
4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "precomp.h"
22
23 /*
24 * Start menu button context menu
25 */
26
27 class CStartMenuBtnCtxMenu :
28 public CComCoClass<CStartMenuBtnCtxMenu>,
29 public CComObjectRootEx<CComMultiThreadModelNoCS>,
30 public IContextMenu
31 {
32 /* AddStartContextMenuItems uses ID_SHELL_CMD IDs directly and relies on idCmdFirst being 0.
33 * CTrayWindow::TrackCtxMenu must pass 0 because DeleteMenu ID_SHELL_CMD_UNDO_ACTION would
34 * delete the wrong item if it used 1. m_Inner->QueryContextMenu is not aware of this game
35 * so we have to reserve the entire ID_SHELL_CMD range for ourselves here. */
36 enum { INNERIDOFFSET = ID_SHELL_CMD_LAST + 1 };
IsShellCmdId(UINT_PTR id)37 static BOOL IsShellCmdId(UINT_PTR id) { return id < INNERIDOFFSET; }
38
39 CComPtr<ITrayWindow> m_TrayWnd;
40 CComPtr<IContextMenu> m_Inner;
41 CComPtr<IShellFolder> m_Folder;
42
43 HWND m_Owner;
44 LPITEMIDLIST m_FolderPidl;
45
CreateContextMenuFromShellFolderPidl(HMENU hPopup,UINT idCmdFirst,UINT idCmdLast)46 HRESULT CreateContextMenuFromShellFolderPidl(HMENU hPopup, UINT idCmdFirst, UINT idCmdLast)
47 {
48 HRESULT hRet;
49
50 hRet = m_Folder->GetUIObjectOf(m_Owner, 1, (LPCITEMIDLIST *) &m_FolderPidl, IID_NULL_PPV_ARG(IContextMenu, &m_Inner));
51 if (SUCCEEDED(hRet))
52 {
53 if (hPopup != NULL)
54 {
55 hRet = m_Inner->QueryContextMenu(
56 hPopup,
57 0,
58 idCmdFirst,
59 idCmdLast,
60 CMF_VERBSONLY);
61
62 if (SUCCEEDED(hRet))
63 {
64 return hRet;
65 }
66 }
67 }
68 return E_FAIL;
69 }
70
AddStartContextMenuItems(IN HMENU hPopup)71 VOID AddStartContextMenuItems(IN HMENU hPopup)
72 {
73 WCHAR szBuf[MAX_PATH];
74 HRESULT hRet;
75 C_ASSERT(ID_SHELL_CMD_FIRST != 0);
76 /* If this ever asserts, let m_Inner use 1..ID_SHELL_CMD_FIRST-1 instead */
77 C_ASSERT(ID_SHELL_CMD_LAST < 0xffff / 2);
78
79 /* Add the "Open All Users" menu item */
80 if (LoadStringW(hExplorerInstance,
81 IDS_PROPERTIES,
82 szBuf,
83 _countof(szBuf)))
84 {
85 AppendMenu(hPopup,
86 MF_STRING,
87 ID_SHELL_CMD_PROPERTIES,
88 szBuf);
89 }
90
91 if (!SHRestricted(REST_NOCOMMONGROUPS))
92 {
93 /* Check if we should add menu items for the common start menu */
94 hRet = SHGetFolderPath(m_Owner,
95 CSIDL_COMMON_STARTMENU,
96 NULL,
97 SHGFP_TYPE_CURRENT,
98 szBuf);
99 if (SUCCEEDED(hRet) && hRet != S_FALSE)
100 {
101 /* The directory exists, but only show the items if the
102 user can actually make any changes to the common start
103 menu. This is most likely only the case if the user
104 has administrative rights! */
105 if (IsUserAnAdmin())
106 {
107 AppendMenu(hPopup,
108 MF_SEPARATOR,
109 0,
110 NULL);
111
112 /* Add the "Open All Users" menu item */
113 if (LoadStringW(hExplorerInstance,
114 IDS_OPEN_ALL_USERS,
115 szBuf,
116 _countof(szBuf)))
117 {
118 AppendMenu(hPopup,
119 MF_STRING,
120 ID_SHELL_CMD_OPEN_ALL_USERS,
121 szBuf);
122 }
123
124 /* Add the "Explore All Users" menu item */
125 if (LoadStringW(hExplorerInstance,
126 IDS_EXPLORE_ALL_USERS,
127 szBuf,
128 _countof(szBuf)))
129 {
130 AppendMenu(hPopup,
131 MF_STRING,
132 ID_SHELL_CMD_EXPLORE_ALL_USERS,
133 szBuf);
134 }
135 }
136 }
137 }
138 }
139
140 public:
Initialize(ITrayWindow * pTrayWnd,IN HWND hWndOwner)141 HRESULT Initialize(ITrayWindow * pTrayWnd, IN HWND hWndOwner)
142 {
143 m_TrayWnd = pTrayWnd;
144 m_Owner = hWndOwner;
145 return S_OK;
146 }
147
148 virtual HRESULT STDMETHODCALLTYPE
QueryContextMenu(HMENU hPopup,UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags)149 QueryContextMenu(HMENU hPopup,
150 UINT indexMenu,
151 UINT idCmdFirst,
152 UINT idCmdLast,
153 UINT uFlags)
154 {
155 LPITEMIDLIST pidlStart;
156 CComPtr<IShellFolder> psfDesktop;
157 HRESULT hRet = S_OK;
158 UINT idInnerFirst = idCmdFirst + INNERIDOFFSET;
159
160 psfDesktop = NULL;
161 m_Inner = NULL;
162
163 pidlStart = SHCloneSpecialIDList(m_Owner, CSIDL_STARTMENU, TRUE);
164 if (pidlStart != NULL)
165 {
166 m_FolderPidl = ILClone(ILFindLastID(pidlStart));
167 ILRemoveLastID(pidlStart);
168
169 if (m_FolderPidl != NULL)
170 {
171 hRet = SHGetDesktopFolder(&psfDesktop);
172 if (SUCCEEDED(hRet))
173 {
174 hRet = psfDesktop->BindToObject(pidlStart, NULL, IID_PPV_ARG(IShellFolder, &m_Folder));
175 if (SUCCEEDED(hRet))
176 {
177 hRet = CreateContextMenuFromShellFolderPidl(hPopup, idInnerFirst, idCmdLast);
178 }
179 }
180 }
181
182 ILFree(pidlStart);
183 }
184 if (idCmdLast - idCmdFirst >= ID_SHELL_CMD_LAST - ID_SHELL_CMD_FIRST)
185 {
186 AddStartContextMenuItems(hPopup);
187 hRet = SUCCEEDED(hRet) ? hRet + idInnerFirst : idInnerFirst;
188 }
189 return hRet;
190 }
191
192 virtual HRESULT STDMETHODCALLTYPE
InvokeCommand(LPCMINVOKECOMMANDINFO lpici)193 InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
194 {
195 UINT uiCmdId = PtrToUlong(lpici->lpVerb);
196 if (!IsShellCmdId((UINT_PTR)lpici->lpVerb))
197 {
198 CMINVOKECOMMANDINFO cmici = { 0 };
199 CHAR szDir[MAX_PATH];
200
201 /* Setup and invoke the shell command */
202 cmici.cbSize = sizeof(cmici);
203 cmici.hwnd = m_Owner;
204 if (IS_INTRESOURCE(lpici->lpVerb))
205 cmici.lpVerb = MAKEINTRESOURCEA(uiCmdId - INNERIDOFFSET);
206 else
207 cmici.lpVerb = lpici->lpVerb;
208 cmici.nShow = SW_NORMAL;
209
210 /* FIXME: Support Unicode!!! */
211 if (SHGetPathFromIDListA(m_FolderPidl, szDir))
212 {
213 cmici.lpDirectory = szDir;
214 }
215
216 return m_Inner->InvokeCommand(&cmici);
217 }
218 m_TrayWnd->ExecContextMenuCmd(uiCmdId);
219 return S_OK;
220 }
221
222 virtual HRESULT STDMETHODCALLTYPE
GetCommandString(UINT_PTR idCmd,UINT uType,UINT * pwReserved,LPSTR pszName,UINT cchMax)223 GetCommandString(UINT_PTR idCmd,
224 UINT uType,
225 UINT *pwReserved,
226 LPSTR pszName,
227 UINT cchMax)
228 {
229 if (!IsShellCmdId(idCmd) && m_Inner)
230 return m_Inner->GetCommandString(idCmd, uType, pwReserved, pszName, cchMax);
231 return E_NOTIMPL;
232 }
233
CStartMenuBtnCtxMenu()234 CStartMenuBtnCtxMenu()
235 {
236 }
237
~CStartMenuBtnCtxMenu()238 virtual ~CStartMenuBtnCtxMenu()
239 {
240 if (m_FolderPidl)
241 ILFree(m_FolderPidl);
242 }
243
244 BEGIN_COM_MAP(CStartMenuBtnCtxMenu)
245 COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
246 END_COM_MAP()
247 };
248
CStartMenuBtnCtxMenu_CreateInstance(ITrayWindow * m_TrayWnd,IN HWND m_Owner,IContextMenu ** ppCtxMenu)249 HRESULT CStartMenuBtnCtxMenu_CreateInstance(ITrayWindow * m_TrayWnd, IN HWND m_Owner, IContextMenu ** ppCtxMenu)
250 {
251 return ShellObjectCreatorInit<CStartMenuBtnCtxMenu>(m_TrayWnd, m_Owner, IID_PPV_ARG(IContextMenu, ppCtxMenu));
252 }
253