Synchronize with trunk r58528.
[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
295 typedef struct
296 {
297 const IStartMenuSiteVtbl *lpVtbl;
298 const IServiceProviderVtbl *lpServiceProviderVtbl;
299 const ITrayPrivVtbl *lpStartMenuCallbackVtbl;
300 const IOleCommandTargetVtbl *lpOleCommandTargetVtbl;
301 LONG Ref;
302
303 ITrayWindow *Tray;
304 } IStartMenuSiteImpl;
305
306 static IUnknown *
307 IUnknown_from_IStartMenuSiteImpl(IStartMenuSiteImpl *This)
308 {
309 return (IUnknown *)&This->lpVtbl;
310 }
311
312 IMPL_CASTS(IStartMenuSite, IStartMenuSite, lpVtbl)
313 IMPL_CASTS(IServiceProvider, IStartMenuSite, lpServiceProviderVtbl)
314 IMPL_CASTS(ITrayPriv, IStartMenuSite, lpStartMenuCallbackVtbl)
315 IMPL_CASTS(IOleCommandTarget, IStartMenuSite, lpOleCommandTargetVtbl)
316
317 /*******************************************************************/
318
319 static ULONG STDMETHODCALLTYPE
320 IStartMenuSiteImpl_AddRef(IN OUT IStartMenuSite *iface)
321 {
322 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IStartMenuSite(iface);
323
324 return InterlockedIncrement(&This->Ref);
325 }
326
327 static VOID
328 IStartMenuSiteImpl_Free(IN OUT IStartMenuSiteImpl *This)
329 {
330 HeapFree(hProcessHeap,
331 0,
332 This);
333 }
334
335 static ULONG STDMETHODCALLTYPE
336 IStartMenuSiteImpl_Release(IN OUT IStartMenuSite *iface)
337 {
338 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IStartMenuSite(iface);
339 ULONG Ret;
340
341 Ret = InterlockedDecrement(&This->Ref);
342
343 if (Ret == 0)
344 IStartMenuSiteImpl_Free(This);
345
346 return Ret;
347 }
348
349 static HRESULT STDMETHODCALLTYPE
350 IStartMenuSiteImpl_QueryInterface(IN OUT IStartMenuSite *iface,
351 IN REFIID riid,
352 OUT LPVOID *ppvObj)
353 {
354 IStartMenuSiteImpl *This;
355
356 if (ppvObj == NULL)
357 return E_POINTER;
358
359 This = IStartMenuSiteImpl_from_IStartMenuSite(iface);
360
361 if (IsEqualIID(riid,
362 &IID_IUnknown))
363 {
364 *ppvObj = IUnknown_from_IStartMenuSiteImpl(This);
365 }
366 else if (IsEqualIID(riid,
367 &IID_IServiceProvider))
368 {
369 *ppvObj = IServiceProvider_from_IStartMenuSiteImpl(This);
370 }
371 else if (IsEqualIID(riid,
372 &IID_ITrayPriv) ||
373 IsEqualIID(riid,
374 &IID_IOleWindow))
375 {
376 *ppvObj = ITrayPriv_from_IStartMenuSiteImpl(This);
377 }
378 else if (IsEqualIID(riid,
379 &IID_IOleCommandTarget))
380 {
381 *ppvObj = IOleCommandTarget_from_IStartMenuSiteImpl(This);
382 }
383 else
384 {
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]);
390 *ppvObj = NULL;
391 return E_NOINTERFACE;
392 }
393
394 IStartMenuSiteImpl_AddRef(iface);
395 return S_OK;
396 }
397
398 static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl =
399 {
400 /*** IUnknown methods ***/
401 IStartMenuSiteImpl_QueryInterface,
402 IStartMenuSiteImpl_AddRef,
403 IStartMenuSiteImpl_Release,
404 /*** IStartMenuSite methods ***/
405 };
406
407 /*******************************************************************/
408
409 METHOD_IUNKNOWN_INHERITED_ADDREF(IServiceProvider, IStartMenuSite)
410 METHOD_IUNKNOWN_INHERITED_RELEASE(IServiceProvider, IStartMenuSite)
411 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IServiceProvider, IStartMenuSite)
412
413 static HRESULT STDMETHODCALLTYPE
414 IStartMenuSiteImpl_QueryService(IN OUT IServiceProvider *iface,
415 IN REFGUID guidService,
416 IN REFIID riid,
417 OUT PVOID *ppvObject)
418 {
419 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IServiceProvider(iface);
420
421 if (IsEqualGUID(guidService,
422 &SID_SMenuPopup))
423 {
424 return IStartMenuSiteImpl_QueryInterface(IStartMenuSite_from_IStartMenuSiteImpl(This),
425 riid,
426 ppvObject);
427 }
428
429 return E_NOINTERFACE;
430 }
431
432 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
433 {
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
440 };
441
442 /*******************************************************************/
443
444 METHOD_IUNKNOWN_INHERITED_ADDREF(ITrayPriv, IStartMenuSite)
445 METHOD_IUNKNOWN_INHERITED_RELEASE(ITrayPriv, IStartMenuSite)
446 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(ITrayPriv, IStartMenuSite)
447
448 static HRESULT STDMETHODCALLTYPE
449 IStartMenuSiteImpl_GetWindow(IN OUT ITrayPriv *iface,
450 OUT HWND *phwnd)
451 {
452 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_ITrayPriv(iface);
453 DbgPrint("ITrayPriv::GetWindow\n");
454
455 *phwnd = ITrayWindow_GetHWND(This->Tray);
456 if (*phwnd != NULL)
457 return S_OK;
458
459 return E_FAIL;
460 }
461
462 static HRESULT STDMETHODCALLTYPE
463 IStartMenuSiteImpl_ContextSensitiveHelp(IN OUT ITrayPriv *iface,
464 IN BOOL fEnterMode)
465 {
466 DbgPrint("ITrayPriv::ContextSensitiveHelp\n");
467 return E_NOTIMPL;
468 }
469
470 static HRESULT STDMETHODCALLTYPE
471 IStartMenuSiteImpl_Execute(IN OUT ITrayPriv *iface,
472 IN IShellFolder *pShellFolder,
473 IN LPCITEMIDLIST pidl)
474 {
475 HMODULE hShlwapi;
476 HRESULT ret = S_FALSE;
477
478 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_ITrayPriv(iface);
479
480 DbgPrint("ITrayPriv::Execute\n");
481
482 hShlwapi = GetModuleHandle(TEXT("SHLWAPI.DLL"));
483 if (hShlwapi != NULL)
484 {
485 SHINVDEFCMD SHInvokeDefCmd;
486
487 /* SHInvokeDefaultCommand */
488 SHInvokeDefCmd = (SHINVDEFCMD)GetProcAddress(hShlwapi,
489 (LPCSTR)((LONG)279));
490 if (SHInvokeDefCmd != NULL)
491 {
492 ret = SHInvokeDefCmd(ITrayWindow_GetHWND(This->Tray),
493 pShellFolder,
494 pidl);
495 }
496 }
497
498 return ret;
499 }
500
501 static HRESULT STDMETHODCALLTYPE
502 IStartMenuSiteImpl_Unknown(IN OUT ITrayPriv *iface,
503 IN PVOID Unknown1,
504 IN PVOID Unknown2,
505 IN PVOID Unknown3,
506 IN PVOID Unknown4)
507 {
508 DbgPrint("ITrayPriv::Unknown(0x%p,0x%p,0x%p,0x%p)\n", Unknown1, Unknown2, Unknown3, Unknown4);
509 return E_NOTIMPL;
510 }
511
512 static BOOL
513 ShowUndockMenuItem(VOID)
514 {
515 DbgPrint("ShowUndockMenuItem() not implemented!\n");
516 /* FIXME: How do we detect this?! */
517 return FALSE;
518 }
519
520 static BOOL
521 ShowSynchronizeMenuItem(VOID)
522 {
523 DbgPrint("ShowSynchronizeMenuItem() not implemented!\n");
524 /* FIXME: How do we detect this?! */
525 return FALSE;
526 }
527
528 static HRESULT STDMETHODCALLTYPE
529 IStartMenuSiteImpl_AppendMenu(IN OUT ITrayPriv *iface,
530 OUT HMENU* phMenu)
531 {
532 HMENU hMenu, hSettingsMenu;
533 DWORD dwLogoff;
534 BOOL bWantLogoff;
535 UINT uLastItemsCount = 5; /* 5 menu items below the last separator */
536 TCHAR szUser[128];
537
538 DbgPrint("ITrayPriv::AppendMenu\n");
539
540 hMenu = LoadPopupMenu(hExplorerInstance,
541 MAKEINTRESOURCE(IDM_STARTMENU));
542 *phMenu = hMenu;
543 if (hMenu == NULL)
544 return E_FAIL;
545
546 /* Remove menu items that don't apply */
547
548 dwLogoff = SHRestricted(REST_STARTMENULOGOFF);
549 bWantLogoff = (dwLogoff == 2 ||
550 SHRestricted(REST_FORCESTARTMENULOGOFF) ||
551 GetExplorerRegValueSet(HKEY_CURRENT_USER,
552 TEXT("Advanced"),
553 TEXT("StartMenuLogoff")));
554
555 /* FIXME: Favorites */
556
557 /* Documents */
558 if (SHRestricted(REST_NORECENTDOCSMENU))
559 {
560 DeleteMenu(hMenu,
561 IDM_DOCUMENTS,
562 MF_BYCOMMAND);
563 }
564
565 /* Settings */
566 hSettingsMenu = FindSubMenu(hMenu,
567 IDM_SETTINGS,
568 FALSE);
569 if (hSettingsMenu != NULL)
570 {
571 if (SHRestricted(REST_NOSETFOLDERS))
572 {
573 /* Control Panel */
574 if (SHRestricted(REST_NOCONTROLPANEL))
575 {
576 DeleteMenu(hSettingsMenu,
577 IDM_CONTROLPANEL,
578 MF_BYCOMMAND);
579
580 /* Delete the separator below it */
581 DeleteMenu(hSettingsMenu,
582 0,
583 MF_BYPOSITION);
584 }
585
586 /* Network Connections */
587 if (SHRestricted(REST_NONETWORKCONNECTIONS))
588 {
589 DeleteMenu(hSettingsMenu,
590 IDM_NETWORKCONNECTIONS,
591 MF_BYCOMMAND);
592 }
593
594 /* Printers and Faxes */
595 DeleteMenu(hSettingsMenu,
596 IDM_PRINTERSANDFAXES,
597 MF_BYCOMMAND);
598 }
599
600 /* Security */
601 if (GetSystemMetrics(SM_REMOTECONTROL) == 0 ||
602 SHRestricted(REST_NOSECURITY))
603 {
604 DeleteMenu(hSettingsMenu,
605 IDM_SECURITY,
606 MF_BYCOMMAND);
607 }
608
609 if (GetMenuItemCount(hSettingsMenu) == 0)
610 {
611 DeleteMenu(hMenu,
612 IDM_SETTINGS,
613 MF_BYCOMMAND);
614 }
615 }
616
617 /* Search */
618 if (SHRestricted(REST_NOFIND))
619 {
620 DeleteMenu(hMenu,
621 IDM_SEARCH,
622 MF_BYCOMMAND);
623 }
624
625 /* FIXME: Help */
626
627 /* Run */
628 if (SHRestricted(REST_NORUN))
629 {
630 DeleteMenu(hMenu,
631 IDM_RUN,
632 MF_BYCOMMAND);
633 }
634
635 /* Synchronize */
636 if (!ShowSynchronizeMenuItem())
637 {
638 DeleteMenu(hMenu,
639 IDM_SYNCHRONIZE,
640 MF_BYCOMMAND);
641 uLastItemsCount--;
642 }
643
644 /* Log off */
645 if (dwLogoff != 1 && bWantLogoff)
646 {
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!!! */
649
650 /* Update Log Off menu item */
651 if (!GetCurrentLoggedOnUserName(szUser,
652 sizeof(szUser) / sizeof(szUser[0])))
653 {
654 szUser[0] = _T('\0');
655 }
656
657 if (!FormatMenuString(hMenu,
658 IDM_LOGOFF,
659 MF_BYCOMMAND,
660 szUser))
661 {
662 /* We couldn't update the menu item, delete it... */
663 DeleteMenu(hMenu,
664 IDM_LOGOFF,
665 MF_BYCOMMAND);
666 }
667 }
668 else
669 {
670 DeleteMenu(hMenu,
671 IDM_LOGOFF,
672 MF_BYCOMMAND);
673 uLastItemsCount--;
674 }
675
676
677 /* Disconnect */
678 if (GetSystemMetrics(SM_REMOTECONTROL) == 0)
679 {
680 DeleteMenu(hMenu,
681 IDM_DISCONNECT,
682 MF_BYCOMMAND);
683 uLastItemsCount--;
684 }
685
686 /* Undock computer */
687 if (!ShowUndockMenuItem())
688 {
689 DeleteMenu(hMenu,
690 IDM_UNDOCKCOMPUTER,
691 MF_BYCOMMAND);
692 uLastItemsCount--;
693 }
694
695 /* Shut down */
696 if (SHRestricted(REST_NOCLOSE))
697 {
698 DeleteMenu(hMenu,
699 IDM_SHUTDOWN,
700 MF_BYCOMMAND);
701 uLastItemsCount--;
702 }
703
704 if (uLastItemsCount == 0)
705 {
706 /* Remove the separator at the end of the menu */
707 DeleteMenu(hMenu,
708 IDM_LASTSTARTMENU_SEPARATOR,
709 MF_BYCOMMAND);
710 }
711
712 return S_OK;
713 }
714
715 static const ITrayPrivVtbl ITrayPrivImpl_Vtbl =
716 {
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
728 };
729
730 /*******************************************************************/
731
732 METHOD_IUNKNOWN_INHERITED_ADDREF(IOleCommandTarget, IStartMenuSite)
733 METHOD_IUNKNOWN_INHERITED_RELEASE(IOleCommandTarget, IStartMenuSite)
734 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IOleCommandTarget, IStartMenuSite)
735
736 static HRESULT STDMETHODCALLTYPE
737 IStartMenuSiteImpl_QueryStatus(IN OUT IOleCommandTarget *iface,
738 IN const GUID *pguidCmdGroup OPTIONAL,
739 IN ULONG cCmds,
740 IN OUT OLECMD *prgCmds,
741 IN OUT OLECMDTEXT *pCmdText OPTIONAL)
742 {
743 return E_NOTIMPL;
744 }
745
746 static HRESULT STDMETHODCALLTYPE
747 IStartMenuSiteImpl_Exec(IN OUT IOleCommandTarget *iface,
748 IN const GUID *pguidCmdGroup OPTIONAL,
749 IN DWORD nCmdID,
750 IN DWORD nCmdExecOpt,
751 IN VARIANTARG *pvaIn OPTIONAL,
752 IN VARIANTARG *pvaOut OPTIONAL)
753 {
754 return E_NOTIMPL;
755 }
756
757 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
758 {
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
766 };
767
768 /*******************************************************************/
769
770 static IStartMenuSiteImpl*
771 IStartMenuSiteImpl_Construct(IN ITrayWindow *Tray)
772 {
773 IStartMenuSiteImpl *This;
774
775 This = HeapAlloc(hProcessHeap,
776 HEAP_ZERO_MEMORY,
777 sizeof(*This));
778 if (This == NULL)
779 return NULL;
780
781 This->lpVtbl = &IStartMenuSiteImpl_Vtbl;
782 This->lpServiceProviderVtbl = &IServiceProviderImpl_Vtbl;
783 This->lpStartMenuCallbackVtbl = &ITrayPrivImpl_Vtbl;
784 This->lpOleCommandTargetVtbl = &IOleCommandTargetImpl_Vtbl;
785 This->Ref = 1;
786
787 This->Tray = Tray;
788
789 return This;
790 }
791
792 static IStartMenuSite*
793 CreateStartMenuSite(IN ITrayWindow *Tray)
794 {
795 IStartMenuSiteImpl *This;
796
797 This = IStartMenuSiteImpl_Construct(Tray);
798 if (This != NULL)
799 {
800 return IStartMenuSite_from_IStartMenuSiteImpl(This);
801 }
802
803 return NULL;
804 }
805
806 HRESULT
807 UpdateStartMenu(IN OUT IMenuPopup *pMenuPopup,
808 IN HBITMAP hbmBanner OPTIONAL,
809 IN BOOL bSmallIcons)
810 {
811 IBanneredBar *pbb;
812 HRESULT hRet;
813
814 hRet = IMenuPopup_QueryInterface(pMenuPopup,
815 &IID_IBanneredBar,
816 (PVOID *)&pbb);
817 if (SUCCEEDED(hRet))
818 {
819 hRet = IBanneredBar_SetBitmap(pbb, hbmBanner);
820
821 /* Update the icon size */
822 hRet = IBanneredBar_SetIconSize(pbb,
823 bSmallIcons ? BMICON_SMALL : BMICON_LARGE);
824
825 IBanneredBar_Release(pbb);
826 }
827
828 return hRet;
829 }
830
831 IMenuPopup *
832 CreateStartMenu(IN ITrayWindow *Tray,
833 OUT IMenuBand **ppMenuBand,
834 IN HBITMAP hbmBanner OPTIONAL,
835 IN BOOL bSmallIcons)
836 {
837 HRESULT hr;
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;
845 DWORD dwBandId = 0;
846
847 pSms = CreateStartMenuSite(Tray);
848 if (pSms == NULL)
849 return NULL;
850
851 hr = CoCreateInstance(&CLSID_StartMenu,
852 NULL,
853 CLSCTX_INPROC_SERVER,
854 &IID_IMenuPopup,
855 (PVOID *)&pMp);
856 if (FAILED(hr))
857 {
858 DbgPrint("CoCreateInstance failed: %x\n", hr);
859 goto cleanup;
860 }
861
862 hr = IMenuPopup_QueryInterface(pMp,
863 &IID_IObjectWithSite,
864 (PVOID *)&pOws);
865 if (FAILED(hr))
866 {
867 DbgPrint("IMenuPopup_QueryInterface failed: %x\n", hr);
868 goto cleanup;
869 }
870
871 /* Set the menu site so we can handle messages */
872 hr = IObjectWithSite_SetSite(pOws, (IUnknown *)pSms);
873 if (FAILED(hr))
874 {
875 DbgPrint("IObjectWithSite_SetSite failed: %x\n", hr);
876 goto cleanup;
877 }
878
879 /* Initialize the menu object */
880 hr = IMenuPopup_QueryInterface(pMp, &IID_IInitializeObject, (PVOID*)&pIo);
881 if (SUCCEEDED(hr))
882 {
883 hr = IInitializeObject_Initialize(pIo);
884 IInitializeObject_Release(pIo);
885 }
886 else
887 hr = S_OK;
888
889 /* Everything is initialized now. Let's get the IMenuBand interface. */
890 if (FAILED(hr))
891 {
892 DbgPrint("IMenuPopup_QueryInterface failed: %x\n", hr);
893 goto cleanup;
894 }
895
896 hr = IMenuPopup_GetClient(pMp, &pUnk);
897 if (FAILED(hr))
898 {
899 DbgPrint("IMenuPopup_GetClient failed: %x\n", hr);
900 goto cleanup;
901 }
902
903 hr = IUnknown_QueryInterface(pUnk, &IID_IBandSite, (PVOID *)&pBs);
904 if (FAILED(hr))
905 {
906 DbgPrint("IUnknown_QueryInterface pBs failed: %x\n", hr);
907 goto cleanup;
908 }
909
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);
913 if (FAILED(hr))
914 {
915 DbgPrint("IBandSite_EnumBands failed: %x\n", hr);
916 goto cleanup;
917 }
918
919 hr = IBandSite_GetBandObject(pBs, dwBandId, &IID_IMenuBand, (PVOID *)&pMb);
920 if (FAILED(hr))
921 {
922 DbgPrint("IBandSite_GetBandObject failed: %x\n", hr);
923 goto cleanup;
924 }
925
926 UpdateStartMenu(pMp,
927 hbmBanner,
928 bSmallIcons);
929
930 cleanup:
931 if (SUCCEEDED(hr))
932 *ppMenuBand = pMb;
933 else if (pMb != NULL)
934 IMenuBand_Release(pMb);
935
936 if (pBs != NULL)
937 IBandSite_Release(pBs);
938 if (pUnk != NULL)
939 IUnknown_Release(pUnk);
940 if (pOws != NULL)
941 IObjectWithSite_Release(pOws);
942 if (pMp != NULL)
943 IMenuPopup_Release(pMp);
944 if (pSms != NULL)
945 IStartMenuSite_Release(pSms);
946
947 if (FAILED(hr))
948 return NULL;
949 return pMp;
950 }