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 class CStartMenuSite :
24     public CComCoClass<CStartMenuSite>,
25     public CComObjectRootEx<CComMultiThreadModelNoCS>,
26     public IServiceProvider,
27     public ITrayPriv,
28     public IOleCommandTarget,
29     public IMenuPopup
30 {
31     CComPtr<ITrayWindow> m_Tray;
32 
33 public:
34     CStartMenuSite()
35     {
36     }
37 
38     virtual ~CStartMenuSite() {}
39 
40     /*******************************************************************/
41 
42     virtual HRESULT STDMETHODCALLTYPE QueryService(
43         IN REFGUID guidService,
44         IN REFIID riid,
45         OUT PVOID *ppvObject)
46     {
47         if (IsEqualGUID(guidService, SID_SMenuPopup))
48         {
49             return QueryInterface(riid, ppvObject);
50         }
51 
52         return E_NOINTERFACE;
53     }
54 
55     /*******************************************************************/
56 
57     virtual HRESULT STDMETHODCALLTYPE GetWindow(
58         OUT HWND *phwnd)
59     {
60         TRACE("ITrayPriv::GetWindow\n");
61 
62         *phwnd = m_Tray->GetHWND();
63         if (*phwnd != NULL)
64             return S_OK;
65 
66         return E_FAIL;
67     }
68 
69     virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(
70         IN BOOL fEnterMode)
71     {
72         TRACE("ITrayPriv::ContextSensitiveHelp\n");
73         return E_NOTIMPL;
74     }
75 
76     virtual HRESULT STDMETHODCALLTYPE Execute(
77         IN IShellFolder *pShellFolder,
78         IN LPCITEMIDLIST pidl)
79     {
80         HRESULT ret = S_FALSE;
81 
82         TRACE("ITrayPriv::Execute\n");
83 
84         ret = SHInvokeDefaultCommand(m_Tray->GetHWND(), pShellFolder, pidl);
85 
86         return ret;
87     }
88 
89     virtual HRESULT STDMETHODCALLTYPE Unknown(
90         IN PVOID Unknown1,
91         IN PVOID Unknown2,
92         IN PVOID Unknown3,
93         IN PVOID Unknown4)
94     {
95         TRACE("ITrayPriv::Unknown(0x%p,0x%p,0x%p,0x%p)\n", Unknown1, Unknown2, Unknown3, Unknown4);
96         return E_NOTIMPL;
97     }
98 
99     virtual BOOL
100         ShowUndockMenuItem(VOID)
101     {
102         TRACE("ShowUndockMenuItem() not implemented!\n");
103         /* FIXME: How do we detect this?! */
104         return FALSE;
105     }
106 
107     virtual BOOL
108         ShowSynchronizeMenuItem(VOID)
109     {
110         TRACE("ShowSynchronizeMenuItem() not implemented!\n");
111         /* FIXME: How do we detect this?! */
112         return FALSE;
113     }
114 
115     virtual HRESULT STDMETHODCALLTYPE AppendMenu(
116         OUT HMENU* phMenu)
117     {
118         HMENU hMenu, hSettingsMenu;
119         DWORD dwLogoff;
120         BOOL bWantLogoff;
121         UINT uLastItemsCount = 5; /* 5 menu items below the last separator */
122         WCHAR szUser[128];
123 
124         TRACE("ITrayPriv::AppendMenu\n");
125 
126         hMenu = LoadPopupMenu(hExplorerInstance, MAKEINTRESOURCEW(IDM_STARTMENU));
127         *phMenu = hMenu;
128         if (hMenu == NULL)
129             return E_FAIL;
130 
131         /* Remove menu items that don't apply */
132 
133         /* Favorites */
134         if (SHRestricted(REST_NOFAVORITESMENU) ||
135             !GetAdvancedBool(L"StartMenuFavorites", FALSE))
136         {
137             DeleteMenu(hMenu, IDM_FAVORITES, MF_BYCOMMAND);
138         }
139 
140         /* Documents */
141         if (SHRestricted(REST_NORECENTDOCSMENU) ||
142             !GetAdvancedBool(L"Start_ShowRecentDocs", TRUE))
143         {
144             DeleteMenu(hMenu, IDM_DOCUMENTS, MF_BYCOMMAND);
145         }
146 
147         /* Settings */
148         hSettingsMenu = FindSubMenu(hMenu, IDM_SETTINGS, FALSE);
149 
150         /* Control Panel */
151         if (SHRestricted(REST_NOSETFOLDERS) ||
152             SHRestricted(REST_NOCONTROLPANEL) ||
153             !GetAdvancedBool(L"Start_ShowControlPanel", TRUE))
154         {
155             DeleteMenu(hSettingsMenu, IDM_CONTROLPANEL, MF_BYCOMMAND);
156 
157             /* Delete the separator below it */
158             DeleteMenu(hSettingsMenu, 0, MF_BYPOSITION);
159         }
160 
161         /* Network Connections */
162         if (SHRestricted(REST_NOSETFOLDERS) ||
163             SHRestricted(REST_NONETWORKCONNECTIONS) ||
164             !GetAdvancedBool(L"Start_ShowNetConn", TRUE))
165         {
166             DeleteMenu(hSettingsMenu, IDM_NETWORKCONNECTIONS, MF_BYCOMMAND);
167         }
168 
169         /* Printers and Faxes */
170         if (SHRestricted(REST_NOSETFOLDERS) ||
171             !GetAdvancedBool(L"Start_ShowPrinters", TRUE))
172         {
173             DeleteMenu(hSettingsMenu, IDM_PRINTERSANDFAXES, MF_BYCOMMAND);
174         }
175 
176         /* Security */
177         if (SHRestricted(REST_NOSETFOLDERS) ||
178             GetSystemMetrics(SM_REMOTECONTROL) == 0 ||
179             SHRestricted(REST_NOSECURITY))
180         {
181             DeleteMenu(hSettingsMenu, IDM_SECURITY, MF_BYCOMMAND);
182         }
183 
184         /* Delete Settings menu if it was empty */
185         if (GetMenuItemCount(hSettingsMenu) == 0)
186         {
187             DeleteMenu(hMenu, IDM_SETTINGS, MF_BYCOMMAND);
188         }
189 
190         /* Search */
191         if (SHRestricted(REST_NOFIND) ||
192             !GetAdvancedBool(L"Start_ShowSearch", TRUE))
193         {
194             DeleteMenu(hMenu, IDM_SEARCH, MF_BYCOMMAND);
195         }
196 
197         /* Help */
198         if (SHRestricted(REST_NOSMHELP) ||
199             !GetAdvancedBool(L"Start_ShowHelp", TRUE))
200         {
201             DeleteMenu(hMenu, IDM_HELPANDSUPPORT, MF_BYCOMMAND);
202         }
203 
204         /* Run */
205         if (SHRestricted(REST_NORUN) ||
206             !GetAdvancedBool(L"StartMenuRun", TRUE))
207         {
208             DeleteMenu(hMenu, IDM_RUN, MF_BYCOMMAND);
209         }
210 
211         /* Synchronize */
212         if (!ShowSynchronizeMenuItem())
213         {
214             DeleteMenu(hMenu, IDM_SYNCHRONIZE, MF_BYCOMMAND);
215             uLastItemsCount--;
216         }
217 
218         /* Log off */
219         dwLogoff = SHRestricted(REST_STARTMENULOGOFF);
220         bWantLogoff = (dwLogoff == 2 ||
221                        SHRestricted(REST_FORCESTARTMENULOGOFF) ||
222                        GetAdvancedBool(L"StartMenuLogoff", FALSE));
223         if (dwLogoff != 1 && bWantLogoff)
224         {
225             /* FIXME: We need a more sophisticated way to determine whether to show
226                       or hide it, it might be hidden in too many cases!!! */
227 
228             /* Update Log Off menu item */
229             if (!GetCurrentLoggedOnUserName(szUser, _countof(szUser)))
230             {
231                 szUser[0] = _T('\0');
232             }
233 
234             if (!FormatMenuString(hMenu,
235                 IDM_LOGOFF,
236                 MF_BYCOMMAND,
237                 szUser))
238             {
239                 /* We couldn't update the menu item, delete it... */
240                 DeleteMenu(hMenu, IDM_LOGOFF, MF_BYCOMMAND);
241             }
242         }
243         else
244         {
245             DeleteMenu(hMenu, IDM_LOGOFF, MF_BYCOMMAND);
246             uLastItemsCount--;
247         }
248 
249         /* Disconnect */
250         if (SHRestricted(REST_NODISCONNECT) ||
251             GetSystemMetrics(SM_REMOTECONTROL) == 0)
252         {
253             DeleteMenu(hMenu, IDM_DISCONNECT, MF_BYCOMMAND);
254             uLastItemsCount--;
255         }
256 
257         /* Undock computer */
258         if (!ShowUndockMenuItem())
259         {
260             DeleteMenu(hMenu, IDM_UNDOCKCOMPUTER, MF_BYCOMMAND);
261             uLastItemsCount--;
262         }
263 
264         /* Shut down */
265         if (SHRestricted(REST_NOCLOSE))
266         {
267             DeleteMenu(hMenu, IDM_SHUTDOWN, MF_BYCOMMAND);
268             uLastItemsCount--;
269         }
270 
271         if (uLastItemsCount == 0)
272         {
273             /* Remove the separator at the end of the menu */
274             DeleteMenu(hMenu, IDM_LASTSTARTMENU_SEPARATOR, MF_BYCOMMAND);
275         }
276 
277         return S_OK;
278     }
279 
280     /*******************************************************************/
281 
282     virtual HRESULT STDMETHODCALLTYPE QueryStatus(
283         IN const GUID *pguidCmdGroup  OPTIONAL,
284         IN ULONG cCmds,
285         IN OUT OLECMD *prgCmds,
286         IN OUT OLECMDTEXT *pCmdText  OPTIONAL)
287     {
288         return E_NOTIMPL;
289     }
290 
291     virtual HRESULT STDMETHODCALLTYPE Exec(
292         IN const GUID *pguidCmdGroup  OPTIONAL,
293         IN DWORD nCmdID,
294         IN DWORD nCmdExecOpt,
295         IN VARIANTARG *pvaIn  OPTIONAL,
296         IN VARIANTARG *pvaOut  OPTIONAL)
297     {
298         return E_NOTIMPL;
299     }
300 
301     /*******************************************************************/
302 
303     virtual HRESULT STDMETHODCALLTYPE SetClient(IUnknown *punkClient)
304     {
305         return E_NOTIMPL;
306     }
307 
308     virtual HRESULT STDMETHODCALLTYPE GetClient(IUnknown ** ppunkClient)
309     {
310         return E_NOTIMPL;
311     }
312 
313     virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(RECT *prc)
314     {
315         return E_NOTIMPL;
316     }
317 
318     virtual HRESULT STDMETHODCALLTYPE Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
319     {
320         return E_NOTIMPL;
321     }
322 
323     virtual HRESULT STDMETHODCALLTYPE OnSelect(DWORD dwSelectType)
324     {
325         return E_NOTIMPL;
326     }
327 
328     virtual HRESULT STDMETHODCALLTYPE SetSubMenu(IMenuPopup *pmp, BOOL fSet)
329     {
330         if (!fSet)
331         {
332             return Tray_OnStartMenuDismissed(m_Tray);
333         }
334 
335         return S_OK;
336     }
337 
338     /*******************************************************************/
339 
340     HRESULT Initialize(IN ITrayWindow *tray)
341     {
342         m_Tray = tray;
343         return S_OK;
344     }
345 
346     DECLARE_NOT_AGGREGATABLE(CStartMenuSite)
347 
348     DECLARE_PROTECT_FINAL_CONSTRUCT()
349     BEGIN_COM_MAP(CStartMenuSite)
350         COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
351         COM_INTERFACE_ENTRY_IID(IID_ITrayPriv, ITrayPriv)
352         COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
353         COM_INTERFACE_ENTRY_IID(IID_IMenuPopup, IMenuPopup)
354         COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
355     END_COM_MAP()
356 };
357 
358 HRESULT CStartMenuSite_CreateInstance(IN OUT ITrayWindow *Tray, const IID & riid, PVOID * ppv)
359 {
360     return ShellObjectCreatorInit<CStartMenuSite>(Tray, riid, ppv);
361 }
362