[CMAKE]
[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, /* FIXME: shouldn't need a typecast! */
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 IContextMenu_Release(pcm);
86 DestroyMenu(hPopup);
87 }
88 }
89
90 return NULL;
91 }
92
93 static VOID
94 OnStartContextMenuCommand(IN HWND hWndOwner,
95 IN UINT uiCmdId,
96 IN PVOID pcmContext OPTIONAL,
97 IN PVOID Context OPTIONAL)
98 {
99 PSTARTMNU_CTMENU_CTX psmcmc = (PSTARTMNU_CTMENU_CTX)pcmContext;
100
101 if (uiCmdId != 0)
102 {
103 if ((uiCmdId >= ID_SHELL_CMD_FIRST) && (uiCmdId <= ID_SHELL_CMD_LAST))
104 {
105 CMINVOKECOMMANDINFO cmici = {0};
106 CHAR szDir[MAX_PATH];
107
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;
113
114 /* FIXME: Support Unicode!!! */
115 if (SHGetPathFromIDListA(psmcmc->pidl,
116 szDir))
117 {
118 cmici.lpDirectory = szDir;
119 }
120
121 IContextMenu_InvokeCommand(psmcmc->pcm,
122 &cmici);
123 }
124 else
125 {
126 ITrayWindow_ExecContextMenuCmd((ITrayWindow *)Context,
127 uiCmdId);
128 }
129 }
130
131 IContextMenu_Release(psmcmc->pcm);
132
133 HeapFree(hProcessHeap,
134 0,
135 psmcmc);
136 }
137
138 static VOID
139 AddStartContextMenuItems(IN HWND hWndOwner,
140 IN HMENU hPopup)
141 {
142 TCHAR szBuf[MAX_PATH];
143 HRESULT hRet;
144
145 /* Add the "Open All Users" menu item */
146 if (LoadString(hExplorerInstance,
147 IDS_PROPERTIES,
148 szBuf,
149 sizeof(szBuf) / sizeof(szBuf[0])))
150 {
151 AppendMenu(hPopup,
152 MF_STRING,
153 ID_SHELL_CMD_PROPERTIES,
154 szBuf);
155 }
156
157 if (!SHRestricted(REST_NOCOMMONGROUPS))
158 {
159 /* Check if we should add menu items for the common start menu */
160 hRet = SHGetFolderPath(hWndOwner,
161 CSIDL_COMMON_STARTMENU,
162 NULL,
163 SHGFP_TYPE_CURRENT,
164 szBuf);
165 if (SUCCEEDED(hRet) && hRet != S_FALSE)
166 {
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! */
171 if (IsUserAnAdmin())
172 {
173 AppendMenu(hPopup,
174 MF_SEPARATOR,
175 0,
176 NULL);
177
178 /* Add the "Open All Users" menu item */
179 if (LoadString(hExplorerInstance,
180 IDS_OPEN_ALL_USERS,
181 szBuf,
182 sizeof(szBuf) / sizeof(szBuf[0])))
183 {
184 AppendMenu(hPopup,
185 MF_STRING,
186 ID_SHELL_CMD_OPEN_ALL_USERS,
187 szBuf);
188 }
189
190 /* Add the "Explore All Users" menu item */
191 if (LoadString(hExplorerInstance,
192 IDS_EXPLORE_ALL_USERS,
193 szBuf,
194 sizeof(szBuf) / sizeof(szBuf[0])))
195 {
196 AppendMenu(hPopup,
197 MF_STRING,
198 ID_SHELL_CMD_EXPLORE_ALL_USERS,
199 szBuf);
200 }
201 }
202 }
203 }
204 }
205
206 static HMENU
207 CreateStartContextMenu(IN HWND hWndOwner,
208 IN PVOID *ppcmContext,
209 IN PVOID Context OPTIONAL)
210 {
211 LPITEMIDLIST pidlStart, pidlLast;
212 IShellFolder *psfStart, *psfDesktop;
213 IContextMenu *pcm;
214 HRESULT hRet;
215 HMENU hPopup;
216
217 pidlStart = SHCloneSpecialIDList(hWndOwner,
218 CSIDL_STARTMENU,
219 TRUE);
220
221 if (pidlStart != NULL)
222 {
223 pidlLast = ILClone(ILFindLastID(pidlStart));
224 ILRemoveLastID(pidlStart);
225
226 if (pidlLast != NULL)
227 {
228 hRet = SHGetDesktopFolder(&psfDesktop);
229 if (SUCCEEDED(hRet))
230 {
231 hRet = IShellFolder_BindToObject(psfDesktop,
232 pidlStart,
233 NULL,
234 (REFIID)&IID_IShellFolder, /* FIXME: Shouldn't require a typecast */
235 (PVOID*)&psfStart);
236 if (SUCCEEDED(hRet))
237 {
238 hPopup = CreateContextMenuFromShellFolderPidl(hWndOwner,
239 psfStart,
240 pidlLast,
241 &pcm);
242
243 if (hPopup != NULL)
244 {
245 PSTARTMNU_CTMENU_CTX psmcmc;
246
247 psmcmc = HeapAlloc(hProcessHeap,
248 0,
249 sizeof(*psmcmc));
250 if (psmcmc != NULL)
251 {
252 psmcmc->pcm = pcm;
253 psmcmc->pidl = pidlLast;
254
255 AddStartContextMenuItems(hWndOwner,
256 hPopup);
257
258 *((PSTARTMNU_CTMENU_CTX*)ppcmContext) = psmcmc;
259 return hPopup;
260 }
261 else
262 {
263 IContextMenu_Release(pcm);
264
265 DestroyMenu(hPopup);
266 hPopup = NULL;
267 }
268 }
269
270 IShellFolder_Release(psfStart);
271 }
272
273 IShellFolder_Release(psfDesktop);
274 }
275
276 ILFree(pidlLast);
277 }
278
279 ILFree(pidlStart);
280 }
281
282 return NULL;
283 }
284
285 /*****************************************************************************
286 ** IStartMenuSite ***********************************************************
287 *****************************************************************************/
288
289 static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl;
290 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
291 static const ITrayPrivVtbl ITrayPrivImpl_Vtbl;
292 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
293
294 typedef struct
295 {
296 const IStartMenuSiteVtbl *lpVtbl;
297 const IServiceProviderVtbl *lpServiceProviderVtbl;
298 const ITrayPrivVtbl *lpStartMenuCallbackVtbl;
299 const IOleCommandTargetVtbl *lpOleCommandTargetVtbl;
300 LONG Ref;
301
302 ITrayWindow *Tray;
303 } IStartMenuSiteImpl;
304
305 static IUnknown *
306 IUnknown_from_IStartMenuSiteImpl(IStartMenuSiteImpl *This)
307 {
308 return (IUnknown *)&This->lpVtbl;
309 }
310
311 IMPL_CASTS(IStartMenuSite, IStartMenuSite, lpVtbl)
312 IMPL_CASTS(IServiceProvider, IStartMenuSite, lpServiceProviderVtbl)
313 IMPL_CASTS(ITrayPriv, IStartMenuSite, lpStartMenuCallbackVtbl)
314 IMPL_CASTS(IOleCommandTarget, IStartMenuSite, lpOleCommandTargetVtbl)
315
316 /*******************************************************************/
317
318 static ULONG STDMETHODCALLTYPE
319 IStartMenuSiteImpl_AddRef(IN OUT IStartMenuSite *iface)
320 {
321 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IStartMenuSite(iface);
322
323 return InterlockedIncrement(&This->Ref);
324 }
325
326 static VOID
327 IStartMenuSiteImpl_Free(IN OUT IStartMenuSiteImpl *This)
328 {
329 HeapFree(hProcessHeap,
330 0,
331 This);
332 }
333
334 static ULONG STDMETHODCALLTYPE
335 IStartMenuSiteImpl_Release(IN OUT IStartMenuSite *iface)
336 {
337 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IStartMenuSite(iface);
338 ULONG Ret;
339
340 Ret = InterlockedDecrement(&This->Ref);
341
342 if (Ret == 0)
343 IStartMenuSiteImpl_Free(This);
344
345 return Ret;
346 }
347
348 static HRESULT STDMETHODCALLTYPE
349 IStartMenuSiteImpl_QueryInterface(IN OUT IStartMenuSite *iface,
350 IN REFIID riid,
351 OUT LPVOID *ppvObj)
352 {
353 IStartMenuSiteImpl *This;
354
355 if (ppvObj == NULL)
356 return E_POINTER;
357
358 This = IStartMenuSiteImpl_from_IStartMenuSite(iface);
359
360 if (IsEqualIID(riid,
361 &IID_IUnknown))
362 {
363 *ppvObj = IUnknown_from_IStartMenuSiteImpl(This);
364 }
365 else if (IsEqualIID(riid,
366 &IID_IServiceProvider))
367 {
368 *ppvObj = IServiceProvider_from_IStartMenuSiteImpl(This);
369 }
370 else if (IsEqualIID(riid,
371 &IID_ITrayPriv) ||
372 IsEqualIID(riid,
373 &IID_IOleWindow))
374 {
375 *ppvObj = ITrayPriv_from_IStartMenuSiteImpl(This);
376 }
377 else if (IsEqualIID(riid,
378 &IID_IOleCommandTarget))
379 {
380 *ppvObj = IOleCommandTarget_from_IStartMenuSiteImpl(This);
381 }
382 else
383 {
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]);
389 *ppvObj = NULL;
390 return E_NOINTERFACE;
391 }
392
393 IStartMenuSiteImpl_AddRef(iface);
394 return S_OK;
395 }
396
397 static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl =
398 {
399 /*** IUnknown methods ***/
400 IStartMenuSiteImpl_QueryInterface,
401 IStartMenuSiteImpl_AddRef,
402 IStartMenuSiteImpl_Release,
403 /*** IStartMenuSite methods ***/
404 };
405
406 /*******************************************************************/
407
408 METHOD_IUNKNOWN_INHERITED_ADDREF(IServiceProvider, IStartMenuSite)
409 METHOD_IUNKNOWN_INHERITED_RELEASE(IServiceProvider, IStartMenuSite)
410 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IServiceProvider, IStartMenuSite)
411
412 static HRESULT STDMETHODCALLTYPE
413 IStartMenuSiteImpl_QueryService(IN OUT IServiceProvider *iface,
414 IN REFGUID guidService,
415 IN REFIID riid,
416 OUT PVOID *ppvObject)
417 {
418 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IServiceProvider(iface);
419
420 if (IsEqualGUID(guidService,
421 &SID_SMenuPopup))
422 {
423 return IStartMenuSiteImpl_QueryInterface(IStartMenuSite_from_IStartMenuSiteImpl(This),
424 riid,
425 ppvObject);
426 }
427
428 return E_NOINTERFACE;
429 }
430
431 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
432 {
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
439 };
440
441 /*******************************************************************/
442
443 METHOD_IUNKNOWN_INHERITED_ADDREF(ITrayPriv, IStartMenuSite)
444 METHOD_IUNKNOWN_INHERITED_RELEASE(ITrayPriv, IStartMenuSite)
445 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(ITrayPriv, IStartMenuSite)
446
447 static HRESULT STDMETHODCALLTYPE
448 IStartMenuSiteImpl_GetWindow(IN OUT ITrayPriv *iface,
449 OUT HWND *phwnd)
450 {
451 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_ITrayPriv(iface);
452 DbgPrint("ITrayPriv::GetWindow\n");
453
454 *phwnd = ITrayWindow_GetHWND(This->Tray);
455 if (*phwnd != NULL)
456 return S_OK;
457
458 return E_FAIL;
459 }
460
461 static HRESULT STDMETHODCALLTYPE
462 IStartMenuSiteImpl_ContextSensitiveHelp(IN OUT ITrayPriv *iface,
463 IN BOOL fEnterMode)
464 {
465 DbgPrint("ITrayPriv::ContextSensitiveHelp\n");
466 return E_NOTIMPL;
467 }
468
469 static HRESULT STDMETHODCALLTYPE
470 IStartMenuSiteImpl_Execute(IN OUT ITrayPriv *iface,
471 IN IShellFolder *pShellFolder,
472 IN LPCITEMIDLIST pidl)
473 {
474 HMODULE hShlwapi;
475 HRESULT ret = S_FALSE;
476
477 IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_ITrayPriv(iface);
478
479 DbgPrint("ITrayPriv::Execute\n");
480
481 hShlwapi = GetModuleHandle(TEXT("SHLWAPI.DLL"));
482 if (hShlwapi != NULL)
483 {
484 SHINVDEFCMD SHInvokeDefCmd;
485
486 /* SHInvokeDefaultCommand */
487 SHInvokeDefCmd = (SHINVDEFCMD)GetProcAddress(hShlwapi,
488 (LPCSTR)((LONG)279));
489 if (SHInvokeDefCmd != NULL)
490 {
491 ret = SHInvokeDefCmd(ITrayWindow_GetHWND(This->Tray),
492 pShellFolder,
493 pidl);
494 }
495 }
496
497 return ret;
498 }
499
500 static HRESULT STDMETHODCALLTYPE
501 IStartMenuSiteImpl_Unknown(IN OUT ITrayPriv *iface,
502 IN PVOID Unknown1,
503 IN PVOID Unknown2,
504 IN PVOID Unknown3,
505 IN PVOID Unknown4)
506 {
507 DbgPrint("ITrayPriv::Unknown(0x%p,0x%p,0x%p,0x%p)\n", Unknown1, Unknown2, Unknown3, Unknown4);
508 return E_NOTIMPL;
509 }
510
511 static BOOL
512 ShowUndockMenuItem(VOID)
513 {
514 DbgPrint("ShowUndockMenuItem() not implemented!\n");
515 /* FIXME: How do we detect this?! */
516 return FALSE;
517 }
518
519 static BOOL
520 ShowSynchronizeMenuItem(VOID)
521 {
522 DbgPrint("ShowSynchronizeMenuItem() not implemented!\n");
523 /* FIXME: How do we detect this?! */
524 return FALSE;
525 }
526
527 static HRESULT STDMETHODCALLTYPE
528 IStartMenuSiteImpl_AppendMenu(IN OUT ITrayPriv *iface,
529 OUT HMENU* phMenu)
530 {
531 HMENU hMenu, hSettingsMenu;
532 DWORD dwLogoff;
533 BOOL bWantLogoff;
534 UINT uLastItemsCount = 5; /* 5 menu items below the last separator */
535 TCHAR szUser[128];
536
537 DbgPrint("ITrayPriv::AppendMenu\n");
538
539 hMenu = LoadPopupMenu(hExplorerInstance,
540 MAKEINTRESOURCE(IDM_STARTMENU));
541 *phMenu = hMenu;
542 if (hMenu == NULL)
543 return E_FAIL;
544
545 /* Remove menu items that don't apply */
546
547 dwLogoff = SHRestricted(REST_STARTMENULOGOFF);
548 bWantLogoff = (dwLogoff == 2 ||
549 SHRestricted(REST_FORCESTARTMENULOGOFF) ||
550 GetExplorerRegValueSet(HKEY_CURRENT_USER,
551 TEXT("Advanced"),
552 TEXT("StartMenuLogoff")));
553
554 /* FIXME: Favorites */
555
556 /* Documents */
557 if (SHRestricted(REST_NORECENTDOCSMENU))
558 {
559 DeleteMenu(hMenu,
560 IDM_DOCUMENTS,
561 MF_BYCOMMAND);
562 }
563
564 /* Settings */
565 hSettingsMenu = FindSubMenu(hMenu,
566 IDM_SETTINGS,
567 FALSE);
568 if (hSettingsMenu != NULL)
569 {
570 if (SHRestricted(REST_NOSETFOLDERS))
571 {
572 /* Control Panel */
573 if (SHRestricted(REST_NOCONTROLPANEL))
574 {
575 DeleteMenu(hSettingsMenu,
576 IDM_CONTROLPANEL,
577 MF_BYCOMMAND);
578
579 /* Delete the separator below it */
580 DeleteMenu(hSettingsMenu,
581 0,
582 MF_BYPOSITION);
583 }
584
585 /* Network Connections */
586 if (SHRestricted(REST_NONETWORKCONNECTIONS))
587 {
588 DeleteMenu(hSettingsMenu,
589 IDM_NETWORKCONNECTIONS,
590 MF_BYCOMMAND);
591 }
592
593 /* Printers and Faxes */
594 DeleteMenu(hSettingsMenu,
595 IDM_PRINTERSANDFAXES,
596 MF_BYCOMMAND);
597 }
598
599 /* Security */
600 if (GetSystemMetrics(SM_REMOTECONTROL) == 0 ||
601 SHRestricted(REST_NOSECURITY))
602 {
603 DeleteMenu(hSettingsMenu,
604 IDM_SECURITY,
605 MF_BYCOMMAND);
606 }
607
608 if (GetMenuItemCount(hSettingsMenu) == 0)
609 {
610 DeleteMenu(hMenu,
611 IDM_SETTINGS,
612 MF_BYCOMMAND);
613 }
614 }
615
616 /* Search */
617 if (SHRestricted(REST_NOFIND))
618 {
619 DeleteMenu(hMenu,
620 IDM_SEARCH,
621 MF_BYCOMMAND);
622 }
623
624 /* FIXME: Help */
625
626 /* Run */
627 if (SHRestricted(REST_NORUN))
628 {
629 DeleteMenu(hMenu,
630 IDM_RUN,
631 MF_BYCOMMAND);
632 }
633
634 /* Synchronize */
635 if (!ShowSynchronizeMenuItem())
636 {
637 DeleteMenu(hMenu,
638 IDM_SYNCHRONIZE,
639 MF_BYCOMMAND);
640 uLastItemsCount--;
641 }
642
643 /* Log off */
644 if (dwLogoff != 1 && bWantLogoff)
645 {
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!!! */
648
649 /* Update Log Off menu item */
650 if (!GetCurrentLoggedOnUserName(szUser,
651 sizeof(szUser) / sizeof(szUser[0])))
652 {
653 szUser[0] = _T('\0');
654 }
655
656 if (!FormatMenuString(hMenu,
657 IDM_LOGOFF,
658 MF_BYCOMMAND,
659 szUser))
660 {
661 /* We couldn't update the menu item, delete it... */
662 DeleteMenu(hMenu,
663 IDM_LOGOFF,
664 MF_BYCOMMAND);
665 }
666 }
667 else
668 {
669 DeleteMenu(hMenu,
670 IDM_LOGOFF,
671 MF_BYCOMMAND);
672 uLastItemsCount--;
673 }
674
675
676 /* Disconnect */
677 if (GetSystemMetrics(SM_REMOTECONTROL) == 0)
678 {
679 DeleteMenu(hMenu,
680 IDM_DISCONNECT,
681 MF_BYCOMMAND);
682 uLastItemsCount--;
683 }
684
685 /* Undock computer */
686 if (!ShowUndockMenuItem())
687 {
688 DeleteMenu(hMenu,
689 IDM_UNDOCKCOMPUTER,
690 MF_BYCOMMAND);
691 uLastItemsCount--;
692 }
693
694 /* Shut down */
695 if (SHRestricted(REST_NOCLOSE))
696 {
697 DeleteMenu(hMenu,
698 IDM_SHUTDOWN,
699 MF_BYCOMMAND);
700 uLastItemsCount--;
701 }
702
703 if (uLastItemsCount == 0)
704 {
705 /* Remove the separator at the end of the menu */
706 DeleteMenu(hMenu,
707 IDM_LASTSTARTMENU_SEPARATOR,
708 MF_BYCOMMAND);
709 }
710
711 return S_OK;
712 }
713
714 static const ITrayPrivVtbl ITrayPrivImpl_Vtbl =
715 {
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
727 };
728
729 /*******************************************************************/
730
731 METHOD_IUNKNOWN_INHERITED_ADDREF(IOleCommandTarget, IStartMenuSite)
732 METHOD_IUNKNOWN_INHERITED_RELEASE(IOleCommandTarget, IStartMenuSite)
733 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IOleCommandTarget, IStartMenuSite)
734
735 static HRESULT STDMETHODCALLTYPE
736 IStartMenuSiteImpl_QueryStatus(IN OUT IOleCommandTarget *iface,
737 IN const GUID *pguidCmdGroup OPTIONAL,
738 IN ULONG cCmds,
739 IN OUT OLECMD *prgCmds,
740 IN OUT OLECMDTEXT *pCmdText OPTIONAL)
741 {
742 return E_NOTIMPL;
743 }
744
745 static HRESULT STDMETHODCALLTYPE
746 IStartMenuSiteImpl_Exec(IN OUT IOleCommandTarget *iface,
747 IN const GUID *pguidCmdGroup OPTIONAL,
748 IN DWORD nCmdID,
749 IN DWORD nCmdExecOpt,
750 IN VARIANTARG *pvaIn OPTIONAL,
751 IN VARIANTARG *pvaOut OPTIONAL)
752 {
753 return E_NOTIMPL;
754 }
755
756 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
757 {
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
765 };
766
767 /*******************************************************************/
768
769 static IStartMenuSiteImpl*
770 IStartMenuSiteImpl_Construct(IN ITrayWindow *Tray)
771 {
772 IStartMenuSiteImpl *This;
773
774 This = HeapAlloc(hProcessHeap,
775 0,
776 sizeof(*This));
777 if (This == NULL)
778 return NULL;
779
780 ZeroMemory(This,
781 sizeof(*This));
782
783 This->lpVtbl = &IStartMenuSiteImpl_Vtbl;
784 This->lpServiceProviderVtbl = &IServiceProviderImpl_Vtbl;
785 This->lpStartMenuCallbackVtbl = &ITrayPrivImpl_Vtbl;
786 This->lpOleCommandTargetVtbl = &IOleCommandTargetImpl_Vtbl;
787 This->Ref = 1;
788
789 This->Tray = Tray;
790
791 return This;
792 }
793
794 static IStartMenuSite*
795 CreateStartMenuSite(IN ITrayWindow *Tray)
796 {
797 IStartMenuSiteImpl *This;
798
799 This = IStartMenuSiteImpl_Construct(Tray);
800 if (This != NULL)
801 {
802 return IStartMenuSite_from_IStartMenuSiteImpl(This);
803 }
804
805 return NULL;
806 }
807
808 HRESULT
809 UpdateStartMenu(IN OUT IMenuPopup *pMenuPopup,
810 IN HBITMAP hbmBanner OPTIONAL,
811 IN BOOL bSmallIcons)
812 {
813 IBanneredBar *pbb;
814 HRESULT hRet;
815
816 hRet = IMenuPopup_QueryInterface(pMenuPopup,
817 &IID_IBanneredBar,
818 (PVOID)&pbb);
819 if (SUCCEEDED(hRet))
820 {
821 // hRet = IBanneredBar_SetBitmap(pbb,
822 // hbmBanner);
823 hRet = pbb->lpVtbl->SetBitmap(pbb,
824 hbmBanner);
825
826
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);
832
833 //IBanneredBar_Release(pbb);
834 pbb->lpVtbl->Release(pbb);
835 }
836
837 return hRet;
838 }
839
840 IMenuPopup*
841 CreateStartMenu(IN ITrayWindow *Tray,
842 OUT IMenuBand **ppMenuBand,
843 IN HBITMAP hbmBanner OPTIONAL,
844 IN BOOL bSmallIcons)
845 {
846 HRESULT hRet;
847 IObjectWithSite *pOws = NULL;
848 IMenuPopup *pMp = NULL;
849 IStartMenuSite *pSms = NULL;
850 IMenuBand *pMb = NULL;
851 IInitializeObject *pIo;
852 IUnknown *pUnk;
853 IBandSite *pBs;
854 DWORD dwBandId = 0;
855
856 pSms = CreateStartMenuSite(Tray);
857 if (pSms == NULL)
858 return NULL;
859
860 hRet = CoCreateInstance(&CLSID_StartMenu,
861 NULL,
862 CLSCTX_INPROC_SERVER,
863 &IID_IMenuPopup,
864 (PVOID*)&pMp);
865 if (SUCCEEDED(hRet))
866 {
867 hRet = IMenuPopup_QueryInterface(pMp,
868 &IID_IObjectWithSite,
869 (PVOID*)&pOws);
870 if (SUCCEEDED(hRet))
871 {
872 /* Set the menu site so we can handle messages */
873 hRet = IObjectWithSite_SetSite(pOws,
874 (IUnknown*)pSms);
875 if (SUCCEEDED(hRet))
876 {
877 /* Initialize the menu object */
878 hRet = IMenuPopup_QueryInterface(pMp,
879 &IID_IInitializeObject,
880 (PVOID*)&pIo);
881 if (SUCCEEDED(hRet))
882 {
883 //hRet = IInitializeObject_Initialize(pIo);
884 hRet = pIo->lpVtbl->Initialize(pIo);
885
886 //IInitializeObject_Release(pIo);
887 pIo->lpVtbl->Release(pIo);
888 }
889 else
890 hRet = S_OK;
891
892 /* Everything is initialized now. Let's get the IMenuBand interface. */
893 if (SUCCEEDED(hRet))
894 {
895 hRet = IMenuPopup_GetClient(pMp,
896 &pUnk);
897
898 if (SUCCEEDED(hRet))
899 {
900 hRet = IUnknown_QueryInterface(pUnk,
901 &IID_IBandSite,
902 (PVOID*)&pBs);
903
904 if (SUCCEEDED(hRet))
905 {
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,
909 0,
910 &dwBandId);
911 if (SUCCEEDED(hRet))
912 {
913 hRet = IBandSite_GetBandObject(pBs,
914 dwBandId,
915 &IID_IMenuBand,
916 (PVOID*)&pMb);
917 }
918
919 IBandSite_Release(pBs);
920 }
921
922 IUnknown_Release(pUnk);
923 }
924 }
925 }
926
927 IObjectWithSite_Release(pOws);
928 }
929 }
930
931 IStartMenuSite_Release(pSms);
932
933 if (!SUCCEEDED(hRet))
934 {
935 DbgPrint("Failed to initialize the start menu: 0x%x!\n", hRet);
936
937 if (pMp != NULL)
938 IMenuPopup_Release(pMp);
939
940 if (pMb != NULL)
941 IMenuBand_Release(pMb);
942
943 return NULL;
944 }
945
946 UpdateStartMenu(pMp,
947 hbmBanner,
948 bSmallIcons);
949
950 *ppMenuBand = pMb;
951 return pMp;
952 }