4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
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.
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.
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
24 * Start menu button context menu
27 typedef struct _STARTMNU_CTMENU_CTX
31 } STARTMNU_CTMENU_CTX
, *PSTARTMNU_CTMENU_CTX
;
34 CreateStartContextMenu(IN HWND hWndOwner
,
35 IN PVOID
*ppcmContext
,
36 IN PVOID Context OPTIONAL
);
39 OnStartContextMenuCommand(IN HWND hWndOwner
,
41 IN PVOID pcmContext OPTIONAL
,
42 IN PVOID Context OPTIONAL
);
44 const TRAYWINDOW_CTXMENU StartMenuBtnCtxMenu
= {
45 CreateStartContextMenu
,
46 OnStartContextMenuCommand
50 CreateContextMenuFromShellFolderPidl(IN HWND hWndOwner
,
51 IN OUT IShellFolder
*psf
,
52 IN OUT LPITEMIDLIST pidl
,
53 OUT IContextMenu
**ppcm
)
59 hRet
= IShellFolder_GetUIObjectOf(psf
,
62 (LPCITEMIDLIST
*)&pidl
,
68 hPopup
= CreatePopupMenu();
72 hRet
= IContextMenu_QueryContextMenu(pcm
,
88 IContextMenu_Release(pcm
);
95 OnStartContextMenuCommand(IN HWND hWndOwner
,
97 IN PVOID pcmContext OPTIONAL
,
98 IN PVOID Context OPTIONAL
)
100 PSTARTMNU_CTMENU_CTX psmcmc
= pcmContext
;
104 if ((uiCmdId
>= ID_SHELL_CMD_FIRST
) && (uiCmdId
<= ID_SHELL_CMD_LAST
))
106 CMINVOKECOMMANDINFO cmici
= {0};
107 CHAR szDir
[MAX_PATH
];
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
;
115 /* FIXME: Support Unicode!!! */
116 if (SHGetPathFromIDListA(psmcmc
->pidl
,
119 cmici
.lpDirectory
= szDir
;
122 IContextMenu_InvokeCommand(psmcmc
->pcm
,
127 ITrayWindow_ExecContextMenuCmd((ITrayWindow
*)Context
,
132 IContextMenu_Release(psmcmc
->pcm
);
134 HeapFree(hProcessHeap
,
140 AddStartContextMenuItems(IN HWND hWndOwner
,
143 TCHAR szBuf
[MAX_PATH
];
146 /* Add the "Open All Users" menu item */
147 if (LoadString(hExplorerInstance
,
150 sizeof(szBuf
) / sizeof(szBuf
[0])))
154 ID_SHELL_CMD_PROPERTIES
,
158 if (!SHRestricted(REST_NOCOMMONGROUPS
))
160 /* Check if we should add menu items for the common start menu */
161 hRet
= SHGetFolderPath(hWndOwner
,
162 CSIDL_COMMON_STARTMENU
,
166 if (SUCCEEDED(hRet
) && hRet
!= S_FALSE
)
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! */
179 /* Add the "Open All Users" menu item */
180 if (LoadString(hExplorerInstance
,
183 sizeof(szBuf
) / sizeof(szBuf
[0])))
187 ID_SHELL_CMD_OPEN_ALL_USERS
,
191 /* Add the "Explore All Users" menu item */
192 if (LoadString(hExplorerInstance
,
193 IDS_EXPLORE_ALL_USERS
,
195 sizeof(szBuf
) / sizeof(szBuf
[0])))
199 ID_SHELL_CMD_EXPLORE_ALL_USERS
,
208 CreateStartContextMenu(IN HWND hWndOwner
,
209 IN PVOID
*ppcmContext
,
210 IN PVOID Context OPTIONAL
)
212 LPITEMIDLIST pidlStart
, pidlLast
;
213 IShellFolder
*psfStart
, *psfDesktop
;
218 pidlStart
= SHCloneSpecialIDList(hWndOwner
,
222 if (pidlStart
!= NULL
)
224 pidlLast
= ILClone(ILFindLastID(pidlStart
));
225 ILRemoveLastID(pidlStart
);
227 if (pidlLast
!= NULL
)
229 hRet
= SHGetDesktopFolder(&psfDesktop
);
232 hRet
= IShellFolder_BindToObject(psfDesktop
,
239 hPopup
= CreateContextMenuFromShellFolderPidl(hWndOwner
,
246 PSTARTMNU_CTMENU_CTX psmcmc
;
248 psmcmc
= HeapAlloc(hProcessHeap
,
254 psmcmc
->pidl
= pidlLast
;
256 AddStartContextMenuItems(hWndOwner
,
259 *ppcmContext
= psmcmc
;
264 IContextMenu_Release(pcm
);
271 IShellFolder_Release(psfStart
);
274 IShellFolder_Release(psfDesktop
);
286 /*****************************************************************************
287 ** IStartMenuSite ***********************************************************
288 *****************************************************************************/
290 static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl
;
291 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl
;
292 static const ITrayPrivVtbl ITrayPrivImpl_Vtbl
;
293 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl
;
297 const IStartMenuSiteVtbl
*lpVtbl
;
298 const IServiceProviderVtbl
*lpServiceProviderVtbl
;
299 const ITrayPrivVtbl
*lpStartMenuCallbackVtbl
;
300 const IOleCommandTargetVtbl
*lpOleCommandTargetVtbl
;
304 } IStartMenuSiteImpl
;
307 IUnknown_from_IStartMenuSiteImpl(IStartMenuSiteImpl
*This
)
309 return (IUnknown
*)&This
->lpVtbl
;
312 IMPL_CASTS(IStartMenuSite
, IStartMenuSite
, lpVtbl
)
313 IMPL_CASTS(IServiceProvider
, IStartMenuSite
, lpServiceProviderVtbl
)
314 IMPL_CASTS(ITrayPriv
, IStartMenuSite
, lpStartMenuCallbackVtbl
)
315 IMPL_CASTS(IOleCommandTarget
, IStartMenuSite
, lpOleCommandTargetVtbl
)
317 /*******************************************************************/
319 static ULONG STDMETHODCALLTYPE
320 IStartMenuSiteImpl_AddRef(IN OUT IStartMenuSite
*iface
)
322 IStartMenuSiteImpl
*This
= IStartMenuSiteImpl_from_IStartMenuSite(iface
);
324 return InterlockedIncrement(&This
->Ref
);
328 IStartMenuSiteImpl_Free(IN OUT IStartMenuSiteImpl
*This
)
330 HeapFree(hProcessHeap
,
335 static ULONG STDMETHODCALLTYPE
336 IStartMenuSiteImpl_Release(IN OUT IStartMenuSite
*iface
)
338 IStartMenuSiteImpl
*This
= IStartMenuSiteImpl_from_IStartMenuSite(iface
);
341 Ret
= InterlockedDecrement(&This
->Ref
);
344 IStartMenuSiteImpl_Free(This
);
349 static HRESULT STDMETHODCALLTYPE
350 IStartMenuSiteImpl_QueryInterface(IN OUT IStartMenuSite
*iface
,
354 IStartMenuSiteImpl
*This
;
359 This
= IStartMenuSiteImpl_from_IStartMenuSite(iface
);
364 *ppvObj
= IUnknown_from_IStartMenuSiteImpl(This
);
366 else if (IsEqualIID(riid
,
367 &IID_IServiceProvider
))
369 *ppvObj
= IServiceProvider_from_IStartMenuSiteImpl(This
);
371 else if (IsEqualIID(riid
,
376 *ppvObj
= ITrayPriv_from_IStartMenuSiteImpl(This
);
378 else if (IsEqualIID(riid
,
379 &IID_IOleCommandTarget
))
381 *ppvObj
= IOleCommandTarget_from_IStartMenuSiteImpl(This
);
385 DbgPrint("IStartMenuSite::QueryInterface queried unsupported interface: "
386 "{0x%8x,0x%4x,0x%4x,{0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x}}\n",
387 riid
->Data1
, riid
->Data2
, riid
->Data3
, riid
->Data4
[0], riid
->Data4
[1],
388 riid
->Data4
[2], riid
->Data4
[3], riid
->Data4
[4], riid
->Data4
[5],
389 riid
->Data4
[6], riid
->Data4
[7]);
391 return E_NOINTERFACE
;
394 IStartMenuSiteImpl_AddRef(iface
);
398 static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl
=
400 /*** IUnknown methods ***/
401 IStartMenuSiteImpl_QueryInterface
,
402 IStartMenuSiteImpl_AddRef
,
403 IStartMenuSiteImpl_Release
,
404 /*** IStartMenuSite methods ***/
407 /*******************************************************************/
409 METHOD_IUNKNOWN_INHERITED_ADDREF(IServiceProvider
, IStartMenuSite
)
410 METHOD_IUNKNOWN_INHERITED_RELEASE(IServiceProvider
, IStartMenuSite
)
411 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IServiceProvider
, IStartMenuSite
)
413 static HRESULT STDMETHODCALLTYPE
414 IStartMenuSiteImpl_QueryService(IN OUT IServiceProvider
*iface
,
415 IN REFGUID guidService
,
417 OUT PVOID
*ppvObject
)
419 IStartMenuSiteImpl
*This
= IStartMenuSiteImpl_from_IServiceProvider(iface
);
421 if (IsEqualGUID(guidService
,
424 return IStartMenuSiteImpl_QueryInterface(IStartMenuSite_from_IStartMenuSiteImpl(This
),
429 return E_NOINTERFACE
;
432 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl
=
434 /*** IUnknown methods ***/
435 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IServiceProvider
, IStartMenuSite
),
436 METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IServiceProvider
, IStartMenuSite
),
437 METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IServiceProvider
, IStartMenuSite
),
438 /*** IServiceProvider methods ***/
439 IStartMenuSiteImpl_QueryService
442 /*******************************************************************/
444 METHOD_IUNKNOWN_INHERITED_ADDREF(ITrayPriv
, IStartMenuSite
)
445 METHOD_IUNKNOWN_INHERITED_RELEASE(ITrayPriv
, IStartMenuSite
)
446 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(ITrayPriv
, IStartMenuSite
)
448 static HRESULT STDMETHODCALLTYPE
449 IStartMenuSiteImpl_GetWindow(IN OUT ITrayPriv
*iface
,
452 IStartMenuSiteImpl
*This
= IStartMenuSiteImpl_from_ITrayPriv(iface
);
453 DbgPrint("ITrayPriv::GetWindow\n");
455 *phwnd
= ITrayWindow_GetHWND(This
->Tray
);
462 static HRESULT STDMETHODCALLTYPE
463 IStartMenuSiteImpl_ContextSensitiveHelp(IN OUT ITrayPriv
*iface
,
466 DbgPrint("ITrayPriv::ContextSensitiveHelp\n");
470 static HRESULT STDMETHODCALLTYPE
471 IStartMenuSiteImpl_Execute(IN OUT ITrayPriv
*iface
,
472 IN IShellFolder
*pShellFolder
,
473 IN LPCITEMIDLIST pidl
)
476 HRESULT ret
= S_FALSE
;
478 IStartMenuSiteImpl
*This
= IStartMenuSiteImpl_from_ITrayPriv(iface
);
480 DbgPrint("ITrayPriv::Execute\n");
482 hShlwapi
= GetModuleHandle(TEXT("SHLWAPI.DLL"));
483 if (hShlwapi
!= NULL
)
485 SHINVDEFCMD SHInvokeDefCmd
;
487 /* SHInvokeDefaultCommand */
488 SHInvokeDefCmd
= (SHINVDEFCMD
)GetProcAddress(hShlwapi
,
489 (LPCSTR
)((LONG
)279));
490 if (SHInvokeDefCmd
!= NULL
)
492 ret
= SHInvokeDefCmd(ITrayWindow_GetHWND(This
->Tray
),
501 static HRESULT STDMETHODCALLTYPE
502 IStartMenuSiteImpl_Unknown(IN OUT ITrayPriv
*iface
,
508 DbgPrint("ITrayPriv::Unknown(0x%p,0x%p,0x%p,0x%p)\n", Unknown1
, Unknown2
, Unknown3
, Unknown4
);
513 ShowUndockMenuItem(VOID
)
515 DbgPrint("ShowUndockMenuItem() not implemented!\n");
516 /* FIXME: How do we detect this?! */
521 ShowSynchronizeMenuItem(VOID
)
523 DbgPrint("ShowSynchronizeMenuItem() not implemented!\n");
524 /* FIXME: How do we detect this?! */
528 static HRESULT STDMETHODCALLTYPE
529 IStartMenuSiteImpl_AppendMenu(IN OUT ITrayPriv
*iface
,
532 HMENU hMenu
, hSettingsMenu
;
535 UINT uLastItemsCount
= 5; /* 5 menu items below the last separator */
538 DbgPrint("ITrayPriv::AppendMenu\n");
540 hMenu
= LoadPopupMenu(hExplorerInstance
,
541 MAKEINTRESOURCE(IDM_STARTMENU
));
546 /* Remove menu items that don't apply */
548 dwLogoff
= SHRestricted(REST_STARTMENULOGOFF
);
549 bWantLogoff
= (dwLogoff
== 2 ||
550 SHRestricted(REST_FORCESTARTMENULOGOFF
) ||
551 GetExplorerRegValueSet(HKEY_CURRENT_USER
,
553 TEXT("StartMenuLogoff")));
555 /* FIXME: Favorites */
558 if (SHRestricted(REST_NORECENTDOCSMENU
))
566 hSettingsMenu
= FindSubMenu(hMenu
,
569 if (hSettingsMenu
!= NULL
)
571 if (SHRestricted(REST_NOSETFOLDERS
))
574 if (SHRestricted(REST_NOCONTROLPANEL
))
576 DeleteMenu(hSettingsMenu
,
580 /* Delete the separator below it */
581 DeleteMenu(hSettingsMenu
,
586 /* Network Connections */
587 if (SHRestricted(REST_NONETWORKCONNECTIONS
))
589 DeleteMenu(hSettingsMenu
,
590 IDM_NETWORKCONNECTIONS
,
594 /* Printers and Faxes */
595 DeleteMenu(hSettingsMenu
,
596 IDM_PRINTERSANDFAXES
,
601 if (GetSystemMetrics(SM_REMOTECONTROL
) == 0 ||
602 SHRestricted(REST_NOSECURITY
))
604 DeleteMenu(hSettingsMenu
,
609 if (GetMenuItemCount(hSettingsMenu
) == 0)
618 if (SHRestricted(REST_NOFIND
))
628 if (SHRestricted(REST_NORUN
))
636 if (!ShowSynchronizeMenuItem())
645 if (dwLogoff
!= 1 && bWantLogoff
)
647 /* FIXME: We need a more sophisticated way to determine whether to show
648 or hide it, it might be hidden in too many cases!!! */
650 /* Update Log Off menu item */
651 if (!GetCurrentLoggedOnUserName(szUser
,
652 sizeof(szUser
) / sizeof(szUser
[0])))
654 szUser
[0] = _T('\0');
657 if (!FormatMenuString(hMenu
,
662 /* We couldn't update the menu item, delete it... */
678 if (GetSystemMetrics(SM_REMOTECONTROL
) == 0)
686 /* Undock computer */
687 if (!ShowUndockMenuItem())
696 if (SHRestricted(REST_NOCLOSE
))
704 if (uLastItemsCount
== 0)
706 /* Remove the separator at the end of the menu */
708 IDM_LASTSTARTMENU_SEPARATOR
,
715 static const ITrayPrivVtbl ITrayPrivImpl_Vtbl
=
717 /*** IUnknown methods ***/
718 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(ITrayPriv
, IStartMenuSite
),
719 METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(ITrayPriv
, IStartMenuSite
),
720 METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(ITrayPriv
, IStartMenuSite
),
721 /*** IOleWindow methods ***/
722 IStartMenuSiteImpl_GetWindow
,
723 IStartMenuSiteImpl_ContextSensitiveHelp
,
724 /*** ITrayPriv methods ***/
725 IStartMenuSiteImpl_Execute
,
726 IStartMenuSiteImpl_Unknown
,
727 IStartMenuSiteImpl_AppendMenu
730 /*******************************************************************/
732 METHOD_IUNKNOWN_INHERITED_ADDREF(IOleCommandTarget
, IStartMenuSite
)
733 METHOD_IUNKNOWN_INHERITED_RELEASE(IOleCommandTarget
, IStartMenuSite
)
734 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IOleCommandTarget
, IStartMenuSite
)
736 static HRESULT STDMETHODCALLTYPE
737 IStartMenuSiteImpl_QueryStatus(IN OUT IOleCommandTarget
*iface
,
738 IN
const GUID
*pguidCmdGroup OPTIONAL
,
740 IN OUT OLECMD
*prgCmds
,
741 IN OUT OLECMDTEXT
*pCmdText OPTIONAL
)
746 static HRESULT STDMETHODCALLTYPE
747 IStartMenuSiteImpl_Exec(IN OUT IOleCommandTarget
*iface
,
748 IN
const GUID
*pguidCmdGroup OPTIONAL
,
750 IN DWORD nCmdExecOpt
,
751 IN VARIANTARG
*pvaIn OPTIONAL
,
752 IN VARIANTARG
*pvaOut OPTIONAL
)
757 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl
=
759 /*** IUnknown methods ***/
760 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IOleCommandTarget
, IStartMenuSite
),
761 METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IOleCommandTarget
, IStartMenuSite
),
762 METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IOleCommandTarget
, IStartMenuSite
),
763 /*** IOleCommandTarget ***/
764 IStartMenuSiteImpl_QueryStatus
,
765 IStartMenuSiteImpl_Exec
768 /*******************************************************************/
770 static IStartMenuSiteImpl
*
771 IStartMenuSiteImpl_Construct(IN ITrayWindow
*Tray
)
773 IStartMenuSiteImpl
*This
;
775 This
= HeapAlloc(hProcessHeap
,
781 This
->lpVtbl
= &IStartMenuSiteImpl_Vtbl
;
782 This
->lpServiceProviderVtbl
= &IServiceProviderImpl_Vtbl
;
783 This
->lpStartMenuCallbackVtbl
= &ITrayPrivImpl_Vtbl
;
784 This
->lpOleCommandTargetVtbl
= &IOleCommandTargetImpl_Vtbl
;
792 static IStartMenuSite
*
793 CreateStartMenuSite(IN ITrayWindow
*Tray
)
795 IStartMenuSiteImpl
*This
;
797 This
= IStartMenuSiteImpl_Construct(Tray
);
800 return IStartMenuSite_from_IStartMenuSiteImpl(This
);
807 UpdateStartMenu(IN OUT IMenuPopup
*pMenuPopup
,
808 IN HBITMAP hbmBanner OPTIONAL
,
814 hRet
= IMenuPopup_QueryInterface(pMenuPopup
,
819 hRet
= IBanneredBar_SetBitmap(pbb
, hbmBanner
);
821 /* Update the icon size */
822 hRet
= IBanneredBar_SetIconSize(pbb
,
823 bSmallIcons
? BMICON_SMALL
: BMICON_LARGE
);
825 IBanneredBar_Release(pbb
);
832 CreateStartMenu(IN ITrayWindow
*Tray
,
833 OUT IMenuBand
**ppMenuBand
,
834 IN HBITMAP hbmBanner OPTIONAL
,
838 IObjectWithSite
*pOws
= NULL
;
839 IMenuPopup
*pMp
= NULL
;
840 IStartMenuSite
*pSms
= NULL
;
841 IMenuBand
*pMb
= NULL
;
842 IInitializeObject
*pIo
;
843 IUnknown
*pUnk
= NULL
;
844 IBandSite
*pBs
= NULL
;
847 pSms
= CreateStartMenuSite(Tray
);
851 hr
= CoCreateInstance(&CLSID_StartMenu
,
853 CLSCTX_INPROC_SERVER
,
858 DbgPrint("CoCreateInstance failed: %x\n", hr
);
862 hr
= IMenuPopup_QueryInterface(pMp
,
863 &IID_IObjectWithSite
,
867 DbgPrint("IMenuPopup_QueryInterface failed: %x\n", hr
);
871 /* Set the menu site so we can handle messages */
872 hr
= IObjectWithSite_SetSite(pOws
, (IUnknown
*)pSms
);
875 DbgPrint("IObjectWithSite_SetSite failed: %x\n", hr
);
879 /* Initialize the menu object */
880 hr
= IMenuPopup_QueryInterface(pMp
, &IID_IInitializeObject
, (PVOID
*)&pIo
);
883 hr
= IInitializeObject_Initialize(pIo
);
884 IInitializeObject_Release(pIo
);
889 /* Everything is initialized now. Let's get the IMenuBand interface. */
892 DbgPrint("IMenuPopup_QueryInterface failed: %x\n", hr
);
896 hr
= IMenuPopup_GetClient(pMp
, &pUnk
);
899 DbgPrint("IMenuPopup_GetClient failed: %x\n", hr
);
903 hr
= IUnknown_QueryInterface(pUnk
, &IID_IBandSite
, (PVOID
*)&pBs
);
906 DbgPrint("IUnknown_QueryInterface pBs failed: %x\n", hr
);
910 /* Finally we have the IBandSite interface, there's only one
911 band in it that apparently provides the IMenuBand interface */
912 hr
= IBandSite_EnumBands(pBs
, 0, &dwBandId
);
915 DbgPrint("IBandSite_EnumBands failed: %x\n", hr
);
919 hr
= IBandSite_GetBandObject(pBs
, dwBandId
, &IID_IMenuBand
, (PVOID
*)&pMb
);
922 DbgPrint("IBandSite_GetBandObject failed: %x\n", hr
);
933 else if (pMb
!= NULL
)
934 IMenuBand_Release(pMb
);
937 IBandSite_Release(pBs
);
939 IUnknown_Release(pUnk
);
941 IObjectWithSite_Release(pOws
);
943 IMenuPopup_Release(pMp
);
945 IStartMenuSite_Release(pSms
);