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
, /* FIXME: shouldn't need a typecast! */
68 hPopup
= CreatePopupMenu();
72 hRet
= IContextMenu_QueryContextMenu(pcm
,
85 IContextMenu_Release(pcm
);
94 OnStartContextMenuCommand(IN HWND hWndOwner
,
96 IN PVOID pcmContext OPTIONAL
,
97 IN PVOID Context OPTIONAL
)
99 PSTARTMNU_CTMENU_CTX psmcmc
= (PSTARTMNU_CTMENU_CTX
)pcmContext
;
103 if ((uiCmdId
>= ID_SHELL_CMD_FIRST
) && (uiCmdId
<= ID_SHELL_CMD_LAST
))
105 CMINVOKECOMMANDINFO cmici
= {0};
106 CHAR szDir
[MAX_PATH
];
108 /* Setup and invoke the shell command */
109 cmici
.cbSize
= sizeof(cmici
);
110 cmici
.hwnd
= hWndOwner
;
111 cmici
.lpVerb
= (LPCSTR
)MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
112 cmici
.nShow
= SW_NORMAL
;
114 /* FIXME: Support Unicode!!! */
115 if (SHGetPathFromIDListA(psmcmc
->pidl
,
118 cmici
.lpDirectory
= szDir
;
121 IContextMenu_InvokeCommand(psmcmc
->pcm
,
126 ITrayWindow_ExecContextMenuCmd((ITrayWindow
*)Context
,
131 IContextMenu_Release(psmcmc
->pcm
);
133 HeapFree(hProcessHeap
,
139 AddStartContextMenuItems(IN HWND hWndOwner
,
142 TCHAR szBuf
[MAX_PATH
];
145 /* Add the "Open All Users" menu item */
146 if (LoadString(hExplorerInstance
,
149 sizeof(szBuf
) / sizeof(szBuf
[0])))
153 ID_SHELL_CMD_PROPERTIES
,
157 if (!SHRestricted(REST_NOCOMMONGROUPS
))
159 /* Check if we should add menu items for the common start menu */
160 hRet
= SHGetFolderPath(hWndOwner
,
161 CSIDL_COMMON_STARTMENU
,
165 if (SUCCEEDED(hRet
) && hRet
!= S_FALSE
)
167 /* The directory exists, but only show the items if the
168 user can actually make any changes to the common start
169 menu. This is most likely only the case if the user
170 has administrative rights! */
178 /* Add the "Open All Users" menu item */
179 if (LoadString(hExplorerInstance
,
182 sizeof(szBuf
) / sizeof(szBuf
[0])))
186 ID_SHELL_CMD_OPEN_ALL_USERS
,
190 /* Add the "Explore All Users" menu item */
191 if (LoadString(hExplorerInstance
,
192 IDS_EXPLORE_ALL_USERS
,
194 sizeof(szBuf
) / sizeof(szBuf
[0])))
198 ID_SHELL_CMD_EXPLORE_ALL_USERS
,
207 CreateStartContextMenu(IN HWND hWndOwner
,
208 IN PVOID
*ppcmContext
,
209 IN PVOID Context OPTIONAL
)
211 LPITEMIDLIST pidlStart
, pidlLast
;
212 IShellFolder
*psfStart
, *psfDesktop
;
217 pidlStart
= SHCloneSpecialIDList(hWndOwner
,
221 if (pidlStart
!= NULL
)
223 pidlLast
= ILClone(ILFindLastID(pidlStart
));
224 ILRemoveLastID(pidlStart
);
226 if (pidlLast
!= NULL
)
228 hRet
= SHGetDesktopFolder(&psfDesktop
);
231 hRet
= IShellFolder_BindToObject(psfDesktop
,
234 (REFIID
)&IID_IShellFolder
, /* FIXME: Shouldn't require a typecast */
238 hPopup
= CreateContextMenuFromShellFolderPidl(hWndOwner
,
245 PSTARTMNU_CTMENU_CTX psmcmc
;
247 psmcmc
= HeapAlloc(hProcessHeap
,
253 psmcmc
->pidl
= pidlLast
;
255 AddStartContextMenuItems(hWndOwner
,
258 *((PSTARTMNU_CTMENU_CTX
*)ppcmContext
) = psmcmc
;
263 IContextMenu_Release(pcm
);
270 IShellFolder_Release(psfStart
);
273 IShellFolder_Release(psfDesktop
);
285 /*****************************************************************************
286 ** IStartMenuSite ***********************************************************
287 *****************************************************************************/
289 static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl
;
290 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl
;
291 static const ITrayPrivVtbl ITrayPrivImpl_Vtbl
;
292 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl
;
296 const IStartMenuSiteVtbl
*lpVtbl
;
297 const IServiceProviderVtbl
*lpServiceProviderVtbl
;
298 const ITrayPrivVtbl
*lpStartMenuCallbackVtbl
;
299 const IOleCommandTargetVtbl
*lpOleCommandTargetVtbl
;
303 } IStartMenuSiteImpl
;
306 IUnknown_from_IStartMenuSiteImpl(IStartMenuSiteImpl
*This
)
308 return (IUnknown
*)&This
->lpVtbl
;
311 IMPL_CASTS(IStartMenuSite
, IStartMenuSite
, lpVtbl
)
312 IMPL_CASTS(IServiceProvider
, IStartMenuSite
, lpServiceProviderVtbl
)
313 IMPL_CASTS(ITrayPriv
, IStartMenuSite
, lpStartMenuCallbackVtbl
)
314 IMPL_CASTS(IOleCommandTarget
, IStartMenuSite
, lpOleCommandTargetVtbl
)
316 /*******************************************************************/
318 static ULONG STDMETHODCALLTYPE
319 IStartMenuSiteImpl_AddRef(IN OUT IStartMenuSite
*iface
)
321 IStartMenuSiteImpl
*This
= IStartMenuSiteImpl_from_IStartMenuSite(iface
);
323 return InterlockedIncrement(&This
->Ref
);
327 IStartMenuSiteImpl_Free(IN OUT IStartMenuSiteImpl
*This
)
329 HeapFree(hProcessHeap
,
334 static ULONG STDMETHODCALLTYPE
335 IStartMenuSiteImpl_Release(IN OUT IStartMenuSite
*iface
)
337 IStartMenuSiteImpl
*This
= IStartMenuSiteImpl_from_IStartMenuSite(iface
);
340 Ret
= InterlockedDecrement(&This
->Ref
);
343 IStartMenuSiteImpl_Free(This
);
348 static HRESULT STDMETHODCALLTYPE
349 IStartMenuSiteImpl_QueryInterface(IN OUT IStartMenuSite
*iface
,
353 IStartMenuSiteImpl
*This
;
358 This
= IStartMenuSiteImpl_from_IStartMenuSite(iface
);
363 *ppvObj
= IUnknown_from_IStartMenuSiteImpl(This
);
365 else if (IsEqualIID(riid
,
366 &IID_IServiceProvider
))
368 *ppvObj
= IServiceProvider_from_IStartMenuSiteImpl(This
);
370 else if (IsEqualIID(riid
,
375 *ppvObj
= ITrayPriv_from_IStartMenuSiteImpl(This
);
377 else if (IsEqualIID(riid
,
378 &IID_IOleCommandTarget
))
380 *ppvObj
= IOleCommandTarget_from_IStartMenuSiteImpl(This
);
384 DbgPrint("IStartMenuSite::QueryInterface queried unsupported interface: "
385 "{0x%8x,0x%4x,0x%4x,{0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x}}\n",
386 riid
->Data1
, riid
->Data2
, riid
->Data3
, riid
->Data4
[0], riid
->Data4
[1],
387 riid
->Data4
[2], riid
->Data4
[3], riid
->Data4
[4], riid
->Data4
[5],
388 riid
->Data4
[6], riid
->Data4
[7]);
390 return E_NOINTERFACE
;
393 IStartMenuSiteImpl_AddRef(iface
);
397 static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl
=
399 /*** IUnknown methods ***/
400 IStartMenuSiteImpl_QueryInterface
,
401 IStartMenuSiteImpl_AddRef
,
402 IStartMenuSiteImpl_Release
,
403 /*** IStartMenuSite methods ***/
406 /*******************************************************************/
408 METHOD_IUNKNOWN_INHERITED_ADDREF(IServiceProvider
, IStartMenuSite
)
409 METHOD_IUNKNOWN_INHERITED_RELEASE(IServiceProvider
, IStartMenuSite
)
410 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IServiceProvider
, IStartMenuSite
)
412 static HRESULT STDMETHODCALLTYPE
413 IStartMenuSiteImpl_QueryService(IN OUT IServiceProvider
*iface
,
414 IN REFGUID guidService
,
416 OUT PVOID
*ppvObject
)
418 IStartMenuSiteImpl
*This
= IStartMenuSiteImpl_from_IServiceProvider(iface
);
420 if (IsEqualGUID(guidService
,
423 return IStartMenuSiteImpl_QueryInterface(IStartMenuSite_from_IStartMenuSiteImpl(This
),
428 return E_NOINTERFACE
;
431 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl
=
433 /*** IUnknown methods ***/
434 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IServiceProvider
, IStartMenuSite
),
435 METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IServiceProvider
, IStartMenuSite
),
436 METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IServiceProvider
, IStartMenuSite
),
437 /*** IServiceProvider methods ***/
438 IStartMenuSiteImpl_QueryService
441 /*******************************************************************/
443 METHOD_IUNKNOWN_INHERITED_ADDREF(ITrayPriv
, IStartMenuSite
)
444 METHOD_IUNKNOWN_INHERITED_RELEASE(ITrayPriv
, IStartMenuSite
)
445 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(ITrayPriv
, IStartMenuSite
)
447 static HRESULT STDMETHODCALLTYPE
448 IStartMenuSiteImpl_GetWindow(IN OUT ITrayPriv
*iface
,
451 IStartMenuSiteImpl
*This
= IStartMenuSiteImpl_from_ITrayPriv(iface
);
452 DbgPrint("ITrayPriv::GetWindow\n");
454 *phwnd
= ITrayWindow_GetHWND(This
->Tray
);
461 static HRESULT STDMETHODCALLTYPE
462 IStartMenuSiteImpl_ContextSensitiveHelp(IN OUT ITrayPriv
*iface
,
465 DbgPrint("ITrayPriv::ContextSensitiveHelp\n");
469 static HRESULT STDMETHODCALLTYPE
470 IStartMenuSiteImpl_Execute(IN OUT ITrayPriv
*iface
,
471 IN IShellFolder
*pShellFolder
,
472 IN LPCITEMIDLIST pidl
)
475 HRESULT ret
= S_FALSE
;
477 IStartMenuSiteImpl
*This
= IStartMenuSiteImpl_from_ITrayPriv(iface
);
479 DbgPrint("ITrayPriv::Execute\n");
481 hShlwapi
= GetModuleHandle(TEXT("SHLWAPI.DLL"));
482 if (hShlwapi
!= NULL
)
484 SHINVDEFCMD SHInvokeDefCmd
;
486 /* SHInvokeDefaultCommand */
487 SHInvokeDefCmd
= (SHINVDEFCMD
)GetProcAddress(hShlwapi
,
488 (LPCSTR
)((LONG
)279));
489 if (SHInvokeDefCmd
!= NULL
)
491 ret
= SHInvokeDefCmd(ITrayWindow_GetHWND(This
->Tray
),
500 static HRESULT STDMETHODCALLTYPE
501 IStartMenuSiteImpl_Unknown(IN OUT ITrayPriv
*iface
,
507 DbgPrint("ITrayPriv::Unknown(0x%p,0x%p,0x%p,0x%p)\n", Unknown1
, Unknown2
, Unknown3
, Unknown4
);
512 ShowUndockMenuItem(VOID
)
514 DbgPrint("ShowUndockMenuItem() not implemented!\n");
515 /* FIXME: How do we detect this?! */
520 ShowSynchronizeMenuItem(VOID
)
522 DbgPrint("ShowSynchronizeMenuItem() not implemented!\n");
523 /* FIXME: How do we detect this?! */
527 static HRESULT STDMETHODCALLTYPE
528 IStartMenuSiteImpl_AppendMenu(IN OUT ITrayPriv
*iface
,
531 HMENU hMenu
, hSettingsMenu
;
534 UINT uLastItemsCount
= 5; /* 5 menu items below the last separator */
537 DbgPrint("ITrayPriv::AppendMenu\n");
539 hMenu
= LoadPopupMenu(hExplorerInstance
,
540 MAKEINTRESOURCE(IDM_STARTMENU
));
545 /* Remove menu items that don't apply */
547 dwLogoff
= SHRestricted(REST_STARTMENULOGOFF
);
548 bWantLogoff
= (dwLogoff
== 2 ||
549 SHRestricted(REST_FORCESTARTMENULOGOFF
) ||
550 GetExplorerRegValueSet(HKEY_CURRENT_USER
,
552 TEXT("StartMenuLogoff")));
554 /* FIXME: Favorites */
557 if (SHRestricted(REST_NORECENTDOCSMENU
))
565 hSettingsMenu
= FindSubMenu(hMenu
,
568 if (hSettingsMenu
!= NULL
)
570 if (SHRestricted(REST_NOSETFOLDERS
))
573 if (SHRestricted(REST_NOCONTROLPANEL
))
575 DeleteMenu(hSettingsMenu
,
579 /* Delete the separator below it */
580 DeleteMenu(hSettingsMenu
,
585 /* Network Connections */
586 if (SHRestricted(REST_NONETWORKCONNECTIONS
))
588 DeleteMenu(hSettingsMenu
,
589 IDM_NETWORKCONNECTIONS
,
593 /* Printers and Faxes */
594 DeleteMenu(hSettingsMenu
,
595 IDM_PRINTERSANDFAXES
,
600 if (GetSystemMetrics(SM_REMOTECONTROL
) == 0 ||
601 SHRestricted(REST_NOSECURITY
))
603 DeleteMenu(hSettingsMenu
,
608 if (GetMenuItemCount(hSettingsMenu
) == 0)
617 if (SHRestricted(REST_NOFIND
))
627 if (SHRestricted(REST_NORUN
))
635 if (!ShowSynchronizeMenuItem())
644 if (dwLogoff
!= 1 && bWantLogoff
)
646 /* FIXME: We need a more sophisticated way to determine whether to show
647 or hide it, it might be hidden in too many cases!!! */
649 /* Update Log Off menu item */
650 if (!GetCurrentLoggedOnUserName(szUser
,
651 sizeof(szUser
) / sizeof(szUser
[0])))
653 szUser
[0] = _T('\0');
656 if (!FormatMenuString(hMenu
,
661 /* We couldn't update the menu item, delete it... */
677 if (GetSystemMetrics(SM_REMOTECONTROL
) == 0)
685 /* Undock computer */
686 if (!ShowUndockMenuItem())
695 if (SHRestricted(REST_NOCLOSE
))
703 if (uLastItemsCount
== 0)
705 /* Remove the separator at the end of the menu */
707 IDM_LASTSTARTMENU_SEPARATOR
,
714 static const ITrayPrivVtbl ITrayPrivImpl_Vtbl
=
716 /*** IUnknown methods ***/
717 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(ITrayPriv
, IStartMenuSite
),
718 METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(ITrayPriv
, IStartMenuSite
),
719 METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(ITrayPriv
, IStartMenuSite
),
720 /*** IOleWindow methods ***/
721 IStartMenuSiteImpl_GetWindow
,
722 IStartMenuSiteImpl_ContextSensitiveHelp
,
723 /*** ITrayPriv methods ***/
724 IStartMenuSiteImpl_Execute
,
725 IStartMenuSiteImpl_Unknown
,
726 IStartMenuSiteImpl_AppendMenu
729 /*******************************************************************/
731 METHOD_IUNKNOWN_INHERITED_ADDREF(IOleCommandTarget
, IStartMenuSite
)
732 METHOD_IUNKNOWN_INHERITED_RELEASE(IOleCommandTarget
, IStartMenuSite
)
733 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IOleCommandTarget
, IStartMenuSite
)
735 static HRESULT STDMETHODCALLTYPE
736 IStartMenuSiteImpl_QueryStatus(IN OUT IOleCommandTarget
*iface
,
737 IN
const GUID
*pguidCmdGroup OPTIONAL
,
739 IN OUT OLECMD
*prgCmds
,
740 IN OUT OLECMDTEXT
*pCmdText OPTIONAL
)
745 static HRESULT STDMETHODCALLTYPE
746 IStartMenuSiteImpl_Exec(IN OUT IOleCommandTarget
*iface
,
747 IN
const GUID
*pguidCmdGroup OPTIONAL
,
749 IN DWORD nCmdExecOpt
,
750 IN VARIANTARG
*pvaIn OPTIONAL
,
751 IN VARIANTARG
*pvaOut OPTIONAL
)
756 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl
=
758 /*** IUnknown methods ***/
759 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IOleCommandTarget
, IStartMenuSite
),
760 METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IOleCommandTarget
, IStartMenuSite
),
761 METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IOleCommandTarget
, IStartMenuSite
),
762 /*** IOleCommandTarget ***/
763 IStartMenuSiteImpl_QueryStatus
,
764 IStartMenuSiteImpl_Exec
767 /*******************************************************************/
769 static IStartMenuSiteImpl
*
770 IStartMenuSiteImpl_Construct(IN ITrayWindow
*Tray
)
772 IStartMenuSiteImpl
*This
;
774 This
= HeapAlloc(hProcessHeap
,
783 This
->lpVtbl
= &IStartMenuSiteImpl_Vtbl
;
784 This
->lpServiceProviderVtbl
= &IServiceProviderImpl_Vtbl
;
785 This
->lpStartMenuCallbackVtbl
= &ITrayPrivImpl_Vtbl
;
786 This
->lpOleCommandTargetVtbl
= &IOleCommandTargetImpl_Vtbl
;
794 static IStartMenuSite
*
795 CreateStartMenuSite(IN ITrayWindow
*Tray
)
797 IStartMenuSiteImpl
*This
;
799 This
= IStartMenuSiteImpl_Construct(Tray
);
802 return IStartMenuSite_from_IStartMenuSiteImpl(This
);
809 UpdateStartMenu(IN OUT IMenuPopup
*pMenuPopup
,
810 IN HBITMAP hbmBanner OPTIONAL
,
816 hRet
= IMenuPopup_QueryInterface(pMenuPopup
,
821 // hRet = IBanneredBar_SetBitmap(pbb,
823 hRet
= pbb
->lpVtbl
->SetBitmap(pbb
,
827 /* Update the icon size */
828 //hRet = IBanneredBar_SetIconSize(pbb,
829 // bSmallIcons ? BMICON_SMALL : BMICON_LARGE);
830 hRet
= pbb
->lpVtbl
->SetIconSize(pbb
,
831 bSmallIcons
? BMICON_SMALL
: BMICON_LARGE
);
833 //IBanneredBar_Release(pbb);
834 pbb
->lpVtbl
->Release(pbb
);
841 CreateStartMenu(IN ITrayWindow
*Tray
,
842 OUT IMenuBand
**ppMenuBand
,
843 IN HBITMAP hbmBanner OPTIONAL
,
847 IObjectWithSite
*pOws
= NULL
;
848 IMenuPopup
*pMp
= NULL
;
849 IStartMenuSite
*pSms
= NULL
;
850 IMenuBand
*pMb
= NULL
;
851 IInitializeObject
*pIo
;
856 pSms
= CreateStartMenuSite(Tray
);
860 hRet
= CoCreateInstance(&CLSID_StartMenu
,
862 CLSCTX_INPROC_SERVER
,
867 hRet
= IMenuPopup_QueryInterface(pMp
,
868 &IID_IObjectWithSite
,
872 /* Set the menu site so we can handle messages */
873 hRet
= IObjectWithSite_SetSite(pOws
,
877 /* Initialize the menu object */
878 hRet
= IMenuPopup_QueryInterface(pMp
,
879 &IID_IInitializeObject
,
883 //hRet = IInitializeObject_Initialize(pIo);
884 hRet
= pIo
->lpVtbl
->Initialize(pIo
);
886 //IInitializeObject_Release(pIo);
887 pIo
->lpVtbl
->Release(pIo
);
892 /* Everything is initialized now. Let's get the IMenuBand interface. */
895 hRet
= IMenuPopup_GetClient(pMp
,
900 hRet
= IUnknown_QueryInterface(pUnk
,
906 /* Finally we have the IBandSite interface, there's only one
907 band in it that apparently provides the IMenuBand interface */
908 hRet
= IBandSite_EnumBands(pBs
,
913 hRet
= IBandSite_GetBandObject(pBs
,
919 IBandSite_Release(pBs
);
922 IUnknown_Release(pUnk
);
927 IObjectWithSite_Release(pOws
);
931 IStartMenuSite_Release(pSms
);
933 if (!SUCCEEDED(hRet
))
935 DbgPrint("Failed to initialize the start menu: 0x%x!\n", hRet
);
938 IMenuPopup_Release(pMp
);
941 IMenuBand_Release(pMb
);