[EXPLORER-NEW]
[reactos.git] / base / shell / explorer-new / startmnu.c
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 typedef struct _STARTMNU_CTMENU_CTX
28 {
29 IContextMenu *pcm;
30 LPITEMIDLIST pidl;
31 } STARTMNU_CTMENU_CTX, *PSTARTMNU_CTMENU_CTX;
32
33 static HMENU
34 CreateStartContextMenu(IN HWND hWndOwner,
35 IN PVOID *ppcmContext,
36 IN PVOID Context OPTIONAL);
37
38 static VOID
39 OnStartContextMenuCommand(IN HWND hWndOwner,
40 IN UINT uiCmdId,
41 IN PVOID pcmContext OPTIONAL,
42 IN PVOID Context OPTIONAL);
43
44 const TRAYWINDOW_CTXMENU StartMenuBtnCtxMenu = {
45 CreateStartContextMenu,
46 OnStartContextMenuCommand
47 };
48
49 static HMENU
50 CreateContextMenuFromShellFolderPidl(IN HWND hWndOwner,
51 IN OUT IShellFolder *psf,
52 IN OUT LPITEMIDLIST pidl,
53 OUT IContextMenu **ppcm)
54 {
55 IContextMenu *pcm;
56 HRESULT hRet;
57 HMENU hPopup;
58
59 hRet = IShellFolder_GetUIObjectOf(psf,
60 hWndOwner,
61 1,
62 (LPCITEMIDLIST *)&pidl,
63 &IID_IContextMenu,
64 NULL,
65 (PVOID *)&pcm);
66 if (SUCCEEDED(hRet))
67 {
68 hPopup = CreatePopupMenu();
69
70 if (hPopup != NULL)
71 {
72 hRet = IContextMenu_QueryContextMenu(pcm,
73 hPopup,
74 0,
75 ID_SHELL_CMD_FIRST,
76 ID_SHELL_CMD_LAST,
77 CMF_VERBSONLY);
78
79 if (SUCCEEDED(hRet))
80 {
81 *ppcm = pcm;
82 return hPopup;
83 }
84
85 DestroyMenu(hPopup);
86 }
87
88 IContextMenu_Release(pcm);
89 }
90
91 return NULL;
92 }
93
94 static VOID
95 OnStartContextMenuCommand(IN HWND hWndOwner,
96 IN UINT uiCmdId,
97 IN PVOID pcmContext OPTIONAL,
98 IN PVOID Context OPTIONAL)
99 {
100 PSTARTMNU_CTMENU_CTX psmcmc = pcmContext;
101
102 if (uiCmdId != 0)
103 {
104 if ((uiCmdId >= ID_SHELL_CMD_FIRST) && (uiCmdId <= ID_SHELL_CMD_LAST))
105 {
106 CMINVOKECOMMANDINFO cmici = {0};
107 CHAR szDir[MAX_PATH];
108
109 /* Setup and invoke the shell command */
110 cmici.cbSize = sizeof(cmici);
111 cmici.hwnd = hWndOwner;
112 cmici.lpVerb = (LPCSTR)MAKEINTRESOURCE(uiCmdId - ID_SHELL_CMD_FIRST);
113 cmici.nShow = SW_NORMAL;
114
115 /* FIXME: Support Unicode!!! */
116 if (SHGetPathFromIDListA(psmcmc->pidl,
117 szDir))
118 {
119 cmici.lpDirectory = szDir;
120 }
121
122 IContextMenu_InvokeCommand(psmcmc->pcm,
123 &cmici);
124 }
125 else
126 {
127 ITrayWindow_ExecContextMenuCmd((ITrayWindow *)Context,
128 uiCmdId);
129 }
130 }
131
132 IContextMenu_Release(psmcmc->pcm);
133
134 HeapFree(hProcessHeap,
135 0,
136 psmcmc);
137 }
138
139 static VOID
140 AddStartContextMenuItems(IN HWND hWndOwner,
141 IN HMENU hPopup)
142 {
143 TCHAR szBuf[MAX_PATH];
144 HRESULT hRet;
145
146 /* Add the "Open All Users" menu item */
147 if (LoadString(hExplorerInstance,
148 IDS_PROPERTIES,
149 szBuf,
150 sizeof(szBuf) / sizeof(szBuf[0])))
151 {
152 AppendMenu(hPopup,
153 MF_STRING,
154 ID_SHELL_CMD_PROPERTIES,
155 szBuf);
156 }
157
158 if (!SHRestricted(REST_NOCOMMONGROUPS))
159 {
160 /* Check if we should add menu items for the common start menu */
161 hRet = SHGetFolderPath(hWndOwner,
162 CSIDL_COMMON_STARTMENU,
163 NULL,
164 SHGFP_TYPE_CURRENT,
165 szBuf);
166 if (SUCCEEDED(hRet) && hRet != S_FALSE)
167 {
168 /* The directory exists, but only show the items if the
169 user can actually make any changes to the common start
170 menu. This is most likely only the case if the user
171 has administrative rights! */
172 if (IsUserAnAdmin())
173 {
174 AppendMenu(hPopup,
175 MF_SEPARATOR,
176 0,
177 NULL);
178
179 /* Add the "Open All Users" menu item */
180 if (LoadString(hExplorerInstance,
181 IDS_OPEN_ALL_USERS,
182 szBuf,
183 sizeof(szBuf) / sizeof(szBuf[0])))
184 {
185 AppendMenu(hPopup,
186 MF_STRING,
187 ID_SHELL_CMD_OPEN_ALL_USERS,
188 szBuf);
189 }
190
191 /* Add the "Explore All Users" menu item */
192 if (LoadString(hExplorerInstance,
193 IDS_EXPLORE_ALL_USERS,
194 szBuf,
195 sizeof(szBuf) / sizeof(szBuf[0])))
196 {
197 AppendMenu(hPopup,
198 MF_STRING,
199 ID_SHELL_CMD_EXPLORE_ALL_USERS,
200 szBuf);
201 }
202 }
203 }
204 }
205 }
206
207 static HMENU
208 CreateStartContextMenu(IN HWND hWndOwner,
209 IN PVOID *ppcmContext,
210 IN PVOID Context OPTIONAL)
211 {
212 LPITEMIDLIST pidlStart, pidlLast;
213 IShellFolder *psfStart, *psfDesktop;
214 IContextMenu *pcm;
215 HRESULT hRet;
216 HMENU hPopup;
217
218 pidlStart = SHCloneSpecialIDList(hWndOwner,
219 CSIDL_STARTMENU,
220 TRUE);
221
222 if (pidlStart != NULL)
223 {
224 pidlLast = ILClone(ILFindLastID(pidlStart));
225 ILRemoveLastID(pidlStart);
226
227 if (pidlLast != NULL)
228 {
229 hRet = SHGetDesktopFolder(&psfDesktop);
230 if (SUCCEEDED(hRet))
231 {
232 hRet = IShellFolder_BindToObject(psfDesktop,
233 pidlStart,
234 NULL,
235 &IID_IShellFolder,
236 (PVOID*)&psfStart);
237 if (SUCCEEDED(hRet))
238 {
239 hPopup = CreateContextMenuFromShellFolderPidl(hWndOwner,
240 psfStart,
241 pidlLast,
242 &pcm);
243
244 if (hPopup != NULL)
245 {
246 PSTARTMNU_CTMENU_CTX psmcmc;
247
248 psmcmc = HeapAlloc(hProcessHeap,
249 0,
250 sizeof(*psmcmc));
251 if (psmcmc != NULL)
252 {
253 psmcmc->pcm = pcm;
254 psmcmc->pidl = pidlLast;
255
256 AddStartContextMenuItems(hWndOwner,
257 hPopup);
258
259 *ppcmContext = psmcmc;
260 return hPopup;
261 }
262 else
263 {
264 IContextMenu_Release(pcm);
265
266 DestroyMenu(hPopup);
267 hPopup = NULL;
268 }
269 }
270
271 IShellFolder_Release(psfStart);
272 }
273
274 IShellFolder_Release(psfDesktop);
275 }
276
277 ILFree(pidlLast);
278 }
279
280 ILFree(pidlStart);
281 }
282
283 return NULL;
284 }
285
286 /*****************************************************************************
287 ** IStartMenuSite ***********************************************************
288 *****************************************************************************/
289
290 static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl;
291 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
292 static const ITrayPrivVtbl ITrayPrivImpl_Vtbl;
293 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
294 static const IMenuPopupVtbl IMenuPopupImpl_Vtbl;
295
296 typedef struct
297 {
298 const IStartMenuSiteVtbl *lpVtbl;
299 const IServiceProviderVtbl *lpServiceProviderVtbl;
300 const ITrayPrivVtbl *lpStartMenuCallbackVtbl;
301 const IOleCommandTargetVtbl *lpOleCommandTargetVtbl;
302 const IMenuPopupVtbl *lpMenuPopupVtbl;
303 LONG Ref;
304
305 ITrayWindow *Tray;
306
307 IMenuPopup * StartMenuPopup;
308 } IStartMenuSiteImpl;
309
310 static IUnknown *
311 IUnknown_from_IStartMenuSiteImpl(IStartMenuSiteImpl *This)
312 {
313 return (IUnknown *)&This->lpVtbl;
314 }
315
316 IMPL_CASTS(IStartMenuSite, IStartMenuSite, lpVtbl)
317 IMPL_CASTS(IServiceProvider, IStartMenuSite, lpServiceProviderVtbl)
318 IMPL_CASTS(ITrayPriv, IStartMenuSite, lpStartMenuCallbackVtbl)
319 IMPL_CASTS(IOleCommandTarget, IStartMenuSite, lpOleCommandTargetVtbl)
320 IMPL_CASTS(IDeskBar, IStartMenuSite, lpMenuPopupVtbl)
321 IMPL_CASTS(IMenuPopup, IStartMenuSite, lpMenuPopupVtbl)
322
323 /*******************************************************************/
324
325 static ULONG STDMETHODCALLTYPE
326 IStartMenuSiteImpl_AddRef(IN OUT IStartMenuSite *iface)
327 {
328 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IStartMenuSite(iface);
329
330 return InterlockedIncrement(&This->Ref);
331 }
332
333 static VOID
334 IStartMenuSiteImpl_Free(IN OUT IStartMenuSiteImpl *This)
335 {
336 HeapFree(hProcessHeap,
337 0,
338 This);
339 }
340
341 static ULONG STDMETHODCALLTYPE
342 IStartMenuSiteImpl_Release(IN OUT IStartMenuSite *iface)
343 {
344 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IStartMenuSite(iface);
345 ULONG Ret;
346
347 Ret = InterlockedDecrement(&This->Ref);
348
349 if (Ret == 0)
350 IStartMenuSiteImpl_Free(This);
351
352 return Ret;
353 }
354
355 static HRESULT STDMETHODCALLTYPE
356 IStartMenuSiteImpl_QueryInterface(IN OUT IStartMenuSite *iface,
357 IN REFIID riid,
358 OUT LPVOID *ppvObj)
359 {
360 IStartMenuSiteImpl *This;
361
362 if (ppvObj == NULL)
363 return E_POINTER;
364
365 This = IStartMenuSiteImpl_from_IStartMenuSite(iface);
366
367 if (IsEqualIID(riid,
368 &IID_IUnknown))
369 {
370 *ppvObj = IUnknown_from_IStartMenuSiteImpl(This);
371 }
372 else if (IsEqualIID(riid,
373 &IID_IServiceProvider))
374 {
375 *ppvObj = IServiceProvider_from_IStartMenuSiteImpl(This);
376 }
377 else if (IsEqualIID(riid,
378 &IID_ITrayPriv) ||
379 IsEqualIID(riid,
380 &IID_IOleWindow))
381 {
382 *ppvObj = ITrayPriv_from_IStartMenuSiteImpl(This);
383 }
384 else if (IsEqualIID(riid,
385 &IID_IOleCommandTarget))
386 {
387 *ppvObj = IOleCommandTarget_from_IStartMenuSiteImpl(This);
388 }
389 else if (IsEqualIID(riid,
390 &IID_IDeskBar))
391 {
392 *ppvObj = IDeskBar_from_IStartMenuSiteImpl(This);
393 }
394 else if (IsEqualIID(riid,
395 &IID_IMenuPopup))
396 {
397 *ppvObj = IMenuPopup_from_IStartMenuSiteImpl(This);
398 }
399 else
400 {
401 TRACE("IStartMenuSite::QueryInterface queried unsupported interface: "
402 "{0x%8x,0x%4x,0x%4x,{0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x}}\n",
403 riid->Data1, riid->Data2, riid->Data3, riid->Data4[0], riid->Data4[1],
404 riid->Data4[2], riid->Data4[3], riid->Data4[4], riid->Data4[5],
405 riid->Data4[6], riid->Data4[7]);
406 *ppvObj = NULL;
407 return E_NOINTERFACE;
408 }
409
410 IStartMenuSiteImpl_AddRef(iface);
411 return S_OK;
412 }
413
414 static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl =
415 {
416 /*** IUnknown methods ***/
417 IStartMenuSiteImpl_QueryInterface,
418 IStartMenuSiteImpl_AddRef,
419 IStartMenuSiteImpl_Release,
420 /*** IStartMenuSite methods ***/
421 };
422
423 /*******************************************************************/
424
425 METHOD_IUNKNOWN_INHERITED_ADDREF(IServiceProvider, IStartMenuSite)
426 METHOD_IUNKNOWN_INHERITED_RELEASE(IServiceProvider, IStartMenuSite)
427 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IServiceProvider, IStartMenuSite)
428
429 static HRESULT STDMETHODCALLTYPE
430 IStartMenuSiteImpl_QueryService(IN OUT IServiceProvider *iface,
431 IN REFGUID guidService,
432 IN REFIID riid,
433 OUT PVOID *ppvObject)
434 {
435 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IServiceProvider(iface);
436
437 if (IsEqualGUID(guidService,
438 &SID_SMenuPopup))
439 {
440 return IStartMenuSiteImpl_QueryInterface(IStartMenuSite_from_IStartMenuSiteImpl(This),
441 riid,
442 ppvObject);
443 }
444
445 return E_NOINTERFACE;
446 }
447
448 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
449 {
450 /*** IUnknown methods ***/
451 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IServiceProvider, IStartMenuSite),
452 METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IServiceProvider, IStartMenuSite),
453 METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IServiceProvider, IStartMenuSite),
454 /*** IServiceProvider methods ***/
455 IStartMenuSiteImpl_QueryService
456 };
457
458 /*******************************************************************/
459
460 METHOD_IUNKNOWN_INHERITED_ADDREF(ITrayPriv, IStartMenuSite)
461 METHOD_IUNKNOWN_INHERITED_RELEASE(ITrayPriv, IStartMenuSite)
462 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(ITrayPriv, IStartMenuSite)
463
464 static HRESULT STDMETHODCALLTYPE
465 IStartMenuSiteImpl_GetWindow(IN OUT ITrayPriv *iface,
466 OUT HWND *phwnd)
467 {
468 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_ITrayPriv(iface);
469 TRACE("ITrayPriv::GetWindow\n");
470
471 *phwnd = ITrayWindow_GetHWND(This->Tray);
472 if (*phwnd != NULL)
473 return S_OK;
474
475 return E_FAIL;
476 }
477
478 static HRESULT STDMETHODCALLTYPE
479 IStartMenuSiteImpl_ContextSensitiveHelp(IN OUT ITrayPriv *iface,
480 IN BOOL fEnterMode)
481 {
482 TRACE("ITrayPriv::ContextSensitiveHelp\n");
483 return E_NOTIMPL;
484 }
485
486 static HRESULT STDMETHODCALLTYPE
487 IStartMenuSiteImpl_Execute(IN OUT ITrayPriv *iface,
488 IN IShellFolder *pShellFolder,
489 IN LPCITEMIDLIST pidl)
490 {
491 HMODULE hShlwapi;
492 HRESULT ret = S_FALSE;
493
494 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_ITrayPriv(iface);
495
496 TRACE("ITrayPriv::Execute\n");
497
498 hShlwapi = GetModuleHandle(TEXT("SHLWAPI.DLL"));
499 if (hShlwapi != NULL)
500 {
501 SHINVDEFCMD SHInvokeDefCmd;
502
503 /* SHInvokeDefaultCommand */
504 SHInvokeDefCmd = (SHINVDEFCMD)GetProcAddress(hShlwapi,
505 (LPCSTR)((LONG)279));
506 if (SHInvokeDefCmd != NULL)
507 {
508 ret = SHInvokeDefCmd(ITrayWindow_GetHWND(This->Tray),
509 pShellFolder,
510 pidl);
511 }
512 }
513
514 return ret;
515 }
516
517 static HRESULT STDMETHODCALLTYPE
518 IStartMenuSiteImpl_Unknown(IN OUT ITrayPriv *iface,
519 IN PVOID Unknown1,
520 IN PVOID Unknown2,
521 IN PVOID Unknown3,
522 IN PVOID Unknown4)
523 {
524 TRACE("ITrayPriv::Unknown(0x%p,0x%p,0x%p,0x%p)\n", Unknown1, Unknown2, Unknown3, Unknown4);
525 return E_NOTIMPL;
526 }
527
528 static BOOL
529 ShowUndockMenuItem(VOID)
530 {
531 TRACE("ShowUndockMenuItem() not implemented!\n");
532 /* FIXME: How do we detect this?! */
533 return FALSE;
534 }
535
536 static BOOL
537 ShowSynchronizeMenuItem(VOID)
538 {
539 TRACE("ShowSynchronizeMenuItem() not implemented!\n");
540 /* FIXME: How do we detect this?! */
541 return FALSE;
542 }
543
544 static HRESULT STDMETHODCALLTYPE
545 IStartMenuSiteImpl_AppendMenu(IN OUT ITrayPriv *iface,
546 OUT HMENU* phMenu)
547 {
548 HMENU hMenu, hSettingsMenu;
549 DWORD dwLogoff;
550 BOOL bWantLogoff;
551 UINT uLastItemsCount = 5; /* 5 menu items below the last separator */
552 TCHAR szUser[128];
553
554 TRACE("ITrayPriv::AppendMenu\n");
555
556 hMenu = LoadPopupMenu(hExplorerInstance,
557 MAKEINTRESOURCE(IDM_STARTMENU));
558 *phMenu = hMenu;
559 if (hMenu == NULL)
560 return E_FAIL;
561
562 /* Remove menu items that don't apply */
563
564 dwLogoff = SHRestricted(REST_STARTMENULOGOFF);
565 bWantLogoff = (dwLogoff == 2 ||
566 SHRestricted(REST_FORCESTARTMENULOGOFF) ||
567 GetExplorerRegValueSet(HKEY_CURRENT_USER,
568 TEXT("Advanced"),
569 TEXT("StartMenuLogoff")));
570
571 /* Favorites */
572 if (!GetExplorerRegValueSet(HKEY_CURRENT_USER,
573 TEXT("Advanced"),
574 TEXT("StartMenuFavorites")))
575 {
576 DeleteMenu(hMenu,
577 IDM_FAVORITES,
578 MF_BYCOMMAND);
579 }
580
581 /* Documents */
582 if (SHRestricted(REST_NORECENTDOCSMENU))
583 {
584 DeleteMenu(hMenu,
585 IDM_DOCUMENTS,
586 MF_BYCOMMAND);
587 }
588
589 /* Settings */
590 hSettingsMenu = FindSubMenu(hMenu,
591 IDM_SETTINGS,
592 FALSE);
593 if (hSettingsMenu != NULL)
594 {
595 if (SHRestricted(REST_NOSETFOLDERS))
596 {
597 /* Control Panel */
598 if (SHRestricted(REST_NOCONTROLPANEL))
599 {
600 DeleteMenu(hSettingsMenu,
601 IDM_CONTROLPANEL,
602 MF_BYCOMMAND);
603
604 /* Delete the separator below it */
605 DeleteMenu(hSettingsMenu,
606 0,
607 MF_BYPOSITION);
608 }
609
610 /* Network Connections */
611 if (SHRestricted(REST_NONETWORKCONNECTIONS))
612 {
613 DeleteMenu(hSettingsMenu,
614 IDM_NETWORKCONNECTIONS,
615 MF_BYCOMMAND);
616 }
617
618 /* Printers and Faxes */
619 DeleteMenu(hSettingsMenu,
620 IDM_PRINTERSANDFAXES,
621 MF_BYCOMMAND);
622 }
623
624 /* Security */
625 if (GetSystemMetrics(SM_REMOTECONTROL) == 0 ||
626 SHRestricted(REST_NOSECURITY))
627 {
628 DeleteMenu(hSettingsMenu,
629 IDM_SECURITY,
630 MF_BYCOMMAND);
631 }
632
633 if (GetMenuItemCount(hSettingsMenu) == 0)
634 {
635 DeleteMenu(hMenu,
636 IDM_SETTINGS,
637 MF_BYCOMMAND);
638 }
639 }
640
641 /* Search */
642 /* FIXME: Enable after implementing */
643 /* if (SHRestricted(REST_NOFIND)) */
644 {
645 DeleteMenu(hMenu,
646 IDM_SEARCH,
647 MF_BYCOMMAND);
648 }
649
650 /* FIXME: Help */
651
652 /* Run */
653 if (SHRestricted(REST_NORUN))
654 {
655 DeleteMenu(hMenu,
656 IDM_RUN,
657 MF_BYCOMMAND);
658 }
659
660 /* Synchronize */
661 if (!ShowSynchronizeMenuItem())
662 {
663 DeleteMenu(hMenu,
664 IDM_SYNCHRONIZE,
665 MF_BYCOMMAND);
666 uLastItemsCount--;
667 }
668
669 /* Log off */
670 if (dwLogoff != 1 && bWantLogoff)
671 {
672 /* FIXME: We need a more sophisticated way to determine whether to show
673 or hide it, it might be hidden in too many cases!!! */
674
675 /* Update Log Off menu item */
676 if (!GetCurrentLoggedOnUserName(szUser,
677 sizeof(szUser) / sizeof(szUser[0])))
678 {
679 szUser[0] = _T('\0');
680 }
681
682 if (!FormatMenuString(hMenu,
683 IDM_LOGOFF,
684 MF_BYCOMMAND,
685 szUser))
686 {
687 /* We couldn't update the menu item, delete it... */
688 DeleteMenu(hMenu,
689 IDM_LOGOFF,
690 MF_BYCOMMAND);
691 }
692 }
693 else
694 {
695 DeleteMenu(hMenu,
696 IDM_LOGOFF,
697 MF_BYCOMMAND);
698 uLastItemsCount--;
699 }
700
701
702 /* Disconnect */
703 if (GetSystemMetrics(SM_REMOTECONTROL) == 0)
704 {
705 DeleteMenu(hMenu,
706 IDM_DISCONNECT,
707 MF_BYCOMMAND);
708 uLastItemsCount--;
709 }
710
711 /* Undock computer */
712 if (!ShowUndockMenuItem())
713 {
714 DeleteMenu(hMenu,
715 IDM_UNDOCKCOMPUTER,
716 MF_BYCOMMAND);
717 uLastItemsCount--;
718 }
719
720 /* Shut down */
721 if (SHRestricted(REST_NOCLOSE))
722 {
723 DeleteMenu(hMenu,
724 IDM_SHUTDOWN,
725 MF_BYCOMMAND);
726 uLastItemsCount--;
727 }
728
729 if (uLastItemsCount == 0)
730 {
731 /* Remove the separator at the end of the menu */
732 DeleteMenu(hMenu,
733 IDM_LASTSTARTMENU_SEPARATOR,
734 MF_BYCOMMAND);
735 }
736
737 return S_OK;
738 }
739
740 static const ITrayPrivVtbl ITrayPrivImpl_Vtbl =
741 {
742 /*** IUnknown methods ***/
743 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(ITrayPriv, IStartMenuSite),
744 METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(ITrayPriv, IStartMenuSite),
745 METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(ITrayPriv, IStartMenuSite),
746 /*** IOleWindow methods ***/
747 IStartMenuSiteImpl_GetWindow,
748 IStartMenuSiteImpl_ContextSensitiveHelp,
749 /*** ITrayPriv methods ***/
750 IStartMenuSiteImpl_Execute,
751 IStartMenuSiteImpl_Unknown,
752 IStartMenuSiteImpl_AppendMenu
753 };
754
755 /*******************************************************************/
756
757 METHOD_IUNKNOWN_INHERITED_ADDREF(IOleCommandTarget, IStartMenuSite)
758 METHOD_IUNKNOWN_INHERITED_RELEASE(IOleCommandTarget, IStartMenuSite)
759 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IOleCommandTarget, IStartMenuSite)
760
761 static HRESULT STDMETHODCALLTYPE
762 IStartMenuSiteImpl_QueryStatus(IN OUT IOleCommandTarget *iface,
763 IN const GUID *pguidCmdGroup OPTIONAL,
764 IN ULONG cCmds,
765 IN OUT OLECMD *prgCmds,
766 IN OUT OLECMDTEXT *pCmdText OPTIONAL)
767 {
768 return E_NOTIMPL;
769 }
770
771 static HRESULT STDMETHODCALLTYPE
772 IStartMenuSiteImpl_Exec(IN OUT IOleCommandTarget *iface,
773 IN const GUID *pguidCmdGroup OPTIONAL,
774 IN DWORD nCmdID,
775 IN DWORD nCmdExecOpt,
776 IN VARIANTARG *pvaIn OPTIONAL,
777 IN VARIANTARG *pvaOut OPTIONAL)
778 {
779 return E_NOTIMPL;
780 }
781
782 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
783 {
784 /*** IUnknown methods ***/
785 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IOleCommandTarget, IStartMenuSite),
786 METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IOleCommandTarget, IStartMenuSite),
787 METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IOleCommandTarget, IStartMenuSite),
788 /*** IOleCommandTarget ***/
789 IStartMenuSiteImpl_QueryStatus,
790 IStartMenuSiteImpl_Exec
791 };
792
793 /*******************************************************************/
794
795 METHOD_IUNKNOWN_INHERITED_ADDREF(IMenuPopup, IStartMenuSite)
796 METHOD_IUNKNOWN_INHERITED_RELEASE(IMenuPopup, IStartMenuSite)
797 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IMenuPopup, IStartMenuSite)
798
799 static HRESULT STDMETHODCALLTYPE
800 IStartMenuSiteImpl_IMenuPopup_GetWindow(IN OUT IMenuPopup *iface, OUT HWND *phwnd)
801 {
802 IStartMenuSiteImpl * This = IStartMenuSiteImpl_from_IMenuPopup(iface);
803 ITrayPriv * tp = ITrayPriv_from_IStartMenuSiteImpl(This);
804 return IStartMenuSiteImpl_GetWindow(tp, phwnd);
805 }
806
807 static HRESULT STDMETHODCALLTYPE
808 IStartMenuSiteImpl_IMenuPopup_ContextSensitiveHelp(IN OUT IMenuPopup *iface, IN BOOL fEnterMode)
809 {
810 IStartMenuSiteImpl * This = IStartMenuSiteImpl_from_IMenuPopup(iface);
811 ITrayPriv * tp = ITrayPriv_from_IStartMenuSiteImpl(This);
812 return IStartMenuSiteImpl_ContextSensitiveHelp(tp, fEnterMode);
813 }
814
815 static HRESULT STDMETHODCALLTYPE
816 IStartMenuSiteImpl_SetClient(IN OUT IMenuPopup *iface, IUnknown *punkClient)
817 {
818 return E_NOTIMPL;
819 }
820
821 static HRESULT STDMETHODCALLTYPE
822 IStartMenuSiteImpl_GetClient(IN OUT IMenuPopup *iface, IUnknown ** ppunkClient)
823 {
824 return E_NOTIMPL;
825 }
826
827 static HRESULT STDMETHODCALLTYPE
828 IStartMenuSiteImpl_OnPosRectChangeDB(IN OUT IMenuPopup *iface, RECT *prc)
829 {
830 return E_NOTIMPL;
831 }
832
833 static HRESULT STDMETHODCALLTYPE
834 IStartMenuSiteImpl_Popup(IN OUT IMenuPopup *iface, POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
835 {
836 return E_NOTIMPL;
837 }
838
839 static HRESULT STDMETHODCALLTYPE
840 IStartMenuSiteImpl_OnSelect(IN OUT IMenuPopup *iface, DWORD dwSelectType)
841 {
842 return E_NOTIMPL;
843 }
844
845 static HRESULT STDMETHODCALLTYPE
846 IStartMenuSiteImpl_SetSubMenu(IN OUT IMenuPopup *iface, IMenuPopup *pmp, BOOL fSet)
847 {
848 if (!fSet)
849 {
850 return Tray_OnStartMenuDismissed();
851 }
852
853 return S_OK;
854 }
855
856 static const IMenuPopupVtbl IMenuPopupImpl_Vtbl =
857 {
858 /*** IUnknown methods ***/
859 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IMenuPopup, IStartMenuSite),
860 METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IMenuPopup, IStartMenuSite),
861 METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IMenuPopup, IStartMenuSite),
862 /*** IOleWindow methods ***/
863 IStartMenuSiteImpl_IMenuPopup_GetWindow,
864 IStartMenuSiteImpl_IMenuPopup_ContextSensitiveHelp,
865 /*** IDeskBar methods ***/
866 IStartMenuSiteImpl_SetClient,
867 IStartMenuSiteImpl_GetClient,
868 IStartMenuSiteImpl_OnPosRectChangeDB,
869 /*** IMenuPopup ***/
870 IStartMenuSiteImpl_Popup,
871 IStartMenuSiteImpl_OnSelect,
872 IStartMenuSiteImpl_SetSubMenu
873 };
874
875
876 /*******************************************************************/
877
878 static IStartMenuSiteImpl*
879 IStartMenuSiteImpl_Construct(IN ITrayWindow *Tray)
880 {
881 IStartMenuSiteImpl *This;
882
883 This = HeapAlloc(hProcessHeap,
884 HEAP_ZERO_MEMORY,
885 sizeof(*This));
886 if (This == NULL)
887 return NULL;
888
889 This->lpVtbl = &IStartMenuSiteImpl_Vtbl;
890 This->lpServiceProviderVtbl = &IServiceProviderImpl_Vtbl;
891 This->lpStartMenuCallbackVtbl = &ITrayPrivImpl_Vtbl;
892 This->lpOleCommandTargetVtbl = &IOleCommandTargetImpl_Vtbl;
893 This->lpMenuPopupVtbl = &IMenuPopupImpl_Vtbl;
894 This->Ref = 1;
895
896 This->Tray = Tray;
897
898 return This;
899 }
900
901 static IStartMenuSite*
902 CreateStartMenuSite(IN ITrayWindow *Tray)
903 {
904 IStartMenuSiteImpl *This;
905
906 This = IStartMenuSiteImpl_Construct(Tray);
907 if (This != NULL)
908 {
909 return IStartMenuSite_from_IStartMenuSiteImpl(This);
910 }
911
912 return NULL;
913 }
914
915 HRESULT
916 UpdateStartMenu(IN OUT IMenuPopup *pMenuPopup,
917 IN HBITMAP hbmBanner OPTIONAL,
918 IN BOOL bSmallIcons)
919 {
920 IBanneredBar *pbb;
921 HRESULT hRet;
922
923 hRet = IMenuPopup_QueryInterface(pMenuPopup,
924 &IID_IBanneredBar,
925 (PVOID *)&pbb);
926 if (SUCCEEDED(hRet))
927 {
928 hRet = IBanneredBar_SetBitmap(pbb, hbmBanner);
929
930 /* Update the icon size */
931 hRet = IBanneredBar_SetIconSize(pbb,
932 bSmallIcons ? BMICON_SMALL : BMICON_LARGE);
933
934 IBanneredBar_Release(pbb);
935 }
936
937 return hRet;
938 }
939
940 IMenuPopup *
941 CreateStartMenu(IN ITrayWindow *Tray,
942 OUT IMenuBand **ppMenuBand,
943 IN HBITMAP hbmBanner OPTIONAL,
944 IN BOOL bSmallIcons)
945 {
946 HRESULT hr;
947 IObjectWithSite *pOws = NULL;
948 IMenuPopup *pMp = NULL;
949 IStartMenuSite *pSms = NULL;
950 IMenuBand *pMb = NULL;
951 IInitializeObject *pIo;
952 IUnknown *pUnk = NULL;
953 IBandSite *pBs = NULL;
954 DWORD dwBandId = 0;
955
956 pSms = CreateStartMenuSite(Tray);
957 if (pSms == NULL)
958 return NULL;
959
960 #if 0
961 hr = CoCreateInstance(&CLSID_StartMenu,
962 NULL,
963 CLSCTX_INPROC_SERVER,
964 &IID_IMenuPopup,
965 (PVOID *)&pMp);
966 #else
967 hr = CStartMenu_Constructor(&IID_IMenuPopup,(PVOID *)&pMp);
968 #endif
969 if (FAILED(hr))
970 {
971 TRACE("CoCreateInstance failed: %x\n", hr);
972 goto cleanup;
973 }
974
975 hr = IMenuPopup_QueryInterface(pMp,
976 &IID_IObjectWithSite,
977 (PVOID *)&pOws);
978 if (FAILED(hr))
979 {
980 TRACE("IMenuPopup_QueryInterface failed: %x\n", hr);
981 goto cleanup;
982 }
983
984 /* Set the menu site so we can handle messages */
985 hr = IObjectWithSite_SetSite(pOws, (IUnknown *)pSms);
986 if (FAILED(hr))
987 {
988 TRACE("IObjectWithSite_SetSite failed: %x\n", hr);
989 goto cleanup;
990 }
991
992 /* Initialize the menu object */
993 hr = IMenuPopup_QueryInterface(pMp, &IID_IInitializeObject, (PVOID*)&pIo);
994 if (SUCCEEDED(hr))
995 {
996 hr = IInitializeObject_Initialize(pIo);
997 IInitializeObject_Release(pIo);
998 }
999 else
1000 hr = S_OK;
1001
1002 /* Everything is initialized now. Let's get the IMenuBand interface. */
1003 if (FAILED(hr))
1004 {
1005 TRACE("IMenuPopup_QueryInterface failed: %x\n", hr);
1006 goto cleanup;
1007 }
1008
1009 hr = IMenuPopup_GetClient(pMp, &pUnk);
1010 if (FAILED(hr))
1011 {
1012 TRACE("IMenuPopup_GetClient failed: %x\n", hr);
1013 goto cleanup;
1014 }
1015
1016 hr = IUnknown_QueryInterface(pUnk, &IID_IBandSite, (PVOID *)&pBs);
1017 if (FAILED(hr))
1018 {
1019 TRACE("IUnknown_QueryInterface pBs failed: %x\n", hr);
1020 goto cleanup;
1021 }
1022
1023 /* Finally we have the IBandSite interface, there's only one
1024 band in it that apparently provides the IMenuBand interface */
1025 hr = IBandSite_EnumBands(pBs, 0, &dwBandId);
1026 if (FAILED(hr))
1027 {
1028 TRACE("IBandSite_EnumBands failed: %x\n", hr);
1029 goto cleanup;
1030 }
1031
1032 hr = IBandSite_GetBandObject(pBs, dwBandId, &IID_IMenuBand, (PVOID *)&pMb);
1033 if (FAILED(hr))
1034 {
1035 TRACE("IBandSite_GetBandObject failed: %x\n", hr);
1036 goto cleanup;
1037 }
1038
1039 UpdateStartMenu(pMp,
1040 hbmBanner,
1041 bSmallIcons);
1042
1043 cleanup:
1044 if (SUCCEEDED(hr))
1045 *ppMenuBand = pMb;
1046 else if (pMb != NULL)
1047 IMenuBand_Release(pMb);
1048
1049 if (pBs != NULL)
1050 IBandSite_Release(pBs);
1051 if (pUnk != NULL)
1052 IUnknown_Release(pUnk);
1053 if (pOws != NULL)
1054 IObjectWithSite_Release(pOws);
1055 if (pMp != NULL)
1056 IMenuPopup_Release(pMp);
1057 if (pSms != NULL)
1058 IStartMenuSite_Release(pSms);
1059
1060 if (FAILED(hr))
1061 return NULL;
1062 return pMp;
1063 }