ae8ac0100dd47627554dab361c1f474e28702273
[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 /* Favorites */
556 if (!GetExplorerRegValueSet(HKEY_CURRENT_USER,
557 TEXT("Advanced"),
558 TEXT("StartMenuFavorites")))
559 {
560 DeleteMenu(hMenu,
561 IDM_FAVORITES,
562 MF_BYCOMMAND);
563 }
564
565 /* Documents */
566 if (SHRestricted(REST_NORECENTDOCSMENU))
567 {
568 DeleteMenu(hMenu,
569 IDM_DOCUMENTS,
570 MF_BYCOMMAND);
571 }
572
573 /* Settings */
574 hSettingsMenu = FindSubMenu(hMenu,
575 IDM_SETTINGS,
576 FALSE);
577 if (hSettingsMenu != NULL)
578 {
579 if (SHRestricted(REST_NOSETFOLDERS))
580 {
581 /* Control Panel */
582 if (SHRestricted(REST_NOCONTROLPANEL))
583 {
584 DeleteMenu(hSettingsMenu,
585 IDM_CONTROLPANEL,
586 MF_BYCOMMAND);
587
588 /* Delete the separator below it */
589 DeleteMenu(hSettingsMenu,
590 0,
591 MF_BYPOSITION);
592 }
593
594 /* Network Connections */
595 if (SHRestricted(REST_NONETWORKCONNECTIONS))
596 {
597 DeleteMenu(hSettingsMenu,
598 IDM_NETWORKCONNECTIONS,
599 MF_BYCOMMAND);
600 }
601
602 /* Printers and Faxes */
603 DeleteMenu(hSettingsMenu,
604 IDM_PRINTERSANDFAXES,
605 MF_BYCOMMAND);
606 }
607
608 /* Security */
609 if (GetSystemMetrics(SM_REMOTECONTROL) == 0 ||
610 SHRestricted(REST_NOSECURITY))
611 {
612 DeleteMenu(hSettingsMenu,
613 IDM_SECURITY,
614 MF_BYCOMMAND);
615 }
616
617 if (GetMenuItemCount(hSettingsMenu) == 0)
618 {
619 DeleteMenu(hMenu,
620 IDM_SETTINGS,
621 MF_BYCOMMAND);
622 }
623 }
624
625 /* Search */
626 if (SHRestricted(REST_NOFIND))
627 {
628 DeleteMenu(hMenu,
629 IDM_SEARCH,
630 MF_BYCOMMAND);
631 }
632
633 /* FIXME: Help */
634
635 /* Run */
636 if (SHRestricted(REST_NORUN))
637 {
638 DeleteMenu(hMenu,
639 IDM_RUN,
640 MF_BYCOMMAND);
641 }
642
643 /* Synchronize */
644 if (!ShowSynchronizeMenuItem())
645 {
646 DeleteMenu(hMenu,
647 IDM_SYNCHRONIZE,
648 MF_BYCOMMAND);
649 uLastItemsCount--;
650 }
651
652 /* Log off */
653 if (dwLogoff != 1 && bWantLogoff)
654 {
655 /* FIXME: We need a more sophisticated way to determine whether to show
656 or hide it, it might be hidden in too many cases!!! */
657
658 /* Update Log Off menu item */
659 if (!GetCurrentLoggedOnUserName(szUser,
660 sizeof(szUser) / sizeof(szUser[0])))
661 {
662 szUser[0] = _T('\0');
663 }
664
665 if (!FormatMenuString(hMenu,
666 IDM_LOGOFF,
667 MF_BYCOMMAND,
668 szUser))
669 {
670 /* We couldn't update the menu item, delete it... */
671 DeleteMenu(hMenu,
672 IDM_LOGOFF,
673 MF_BYCOMMAND);
674 }
675 }
676 else
677 {
678 DeleteMenu(hMenu,
679 IDM_LOGOFF,
680 MF_BYCOMMAND);
681 uLastItemsCount--;
682 }
683
684
685 /* Disconnect */
686 if (GetSystemMetrics(SM_REMOTECONTROL) == 0)
687 {
688 DeleteMenu(hMenu,
689 IDM_DISCONNECT,
690 MF_BYCOMMAND);
691 uLastItemsCount--;
692 }
693
694 /* Undock computer */
695 if (!ShowUndockMenuItem())
696 {
697 DeleteMenu(hMenu,
698 IDM_UNDOCKCOMPUTER,
699 MF_BYCOMMAND);
700 uLastItemsCount--;
701 }
702
703 /* Shut down */
704 if (SHRestricted(REST_NOCLOSE))
705 {
706 DeleteMenu(hMenu,
707 IDM_SHUTDOWN,
708 MF_BYCOMMAND);
709 uLastItemsCount--;
710 }
711
712 if (uLastItemsCount == 0)
713 {
714 /* Remove the separator at the end of the menu */
715 DeleteMenu(hMenu,
716 IDM_LASTSTARTMENU_SEPARATOR,
717 MF_BYCOMMAND);
718 }
719
720 return S_OK;
721 }
722
723 static const ITrayPrivVtbl ITrayPrivImpl_Vtbl =
724 {
725 /*** IUnknown methods ***/
726 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(ITrayPriv, IStartMenuSite),
727 METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(ITrayPriv, IStartMenuSite),
728 METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(ITrayPriv, IStartMenuSite),
729 /*** IOleWindow methods ***/
730 IStartMenuSiteImpl_GetWindow,
731 IStartMenuSiteImpl_ContextSensitiveHelp,
732 /*** ITrayPriv methods ***/
733 IStartMenuSiteImpl_Execute,
734 IStartMenuSiteImpl_Unknown,
735 IStartMenuSiteImpl_AppendMenu
736 };
737
738 /*******************************************************************/
739
740 METHOD_IUNKNOWN_INHERITED_ADDREF(IOleCommandTarget, IStartMenuSite)
741 METHOD_IUNKNOWN_INHERITED_RELEASE(IOleCommandTarget, IStartMenuSite)
742 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IOleCommandTarget, IStartMenuSite)
743
744 static HRESULT STDMETHODCALLTYPE
745 IStartMenuSiteImpl_QueryStatus(IN OUT IOleCommandTarget *iface,
746 IN const GUID *pguidCmdGroup OPTIONAL,
747 IN ULONG cCmds,
748 IN OUT OLECMD *prgCmds,
749 IN OUT OLECMDTEXT *pCmdText OPTIONAL)
750 {
751 return E_NOTIMPL;
752 }
753
754 static HRESULT STDMETHODCALLTYPE
755 IStartMenuSiteImpl_Exec(IN OUT IOleCommandTarget *iface,
756 IN const GUID *pguidCmdGroup OPTIONAL,
757 IN DWORD nCmdID,
758 IN DWORD nCmdExecOpt,
759 IN VARIANTARG *pvaIn OPTIONAL,
760 IN VARIANTARG *pvaOut OPTIONAL)
761 {
762 return E_NOTIMPL;
763 }
764
765 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
766 {
767 /*** IUnknown methods ***/
768 METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IOleCommandTarget, IStartMenuSite),
769 METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IOleCommandTarget, IStartMenuSite),
770 METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IOleCommandTarget, IStartMenuSite),
771 /*** IOleCommandTarget ***/
772 IStartMenuSiteImpl_QueryStatus,
773 IStartMenuSiteImpl_Exec
774 };
775
776 /*******************************************************************/
777
778 static IStartMenuSiteImpl*
779 IStartMenuSiteImpl_Construct(IN ITrayWindow *Tray)
780 {
781 IStartMenuSiteImpl *This;
782
783 This = HeapAlloc(hProcessHeap,
784 HEAP_ZERO_MEMORY,
785 sizeof(*This));
786 if (This == NULL)
787 return NULL;
788
789 This->lpVtbl = &IStartMenuSiteImpl_Vtbl;
790 This->lpServiceProviderVtbl = &IServiceProviderImpl_Vtbl;
791 This->lpStartMenuCallbackVtbl = &ITrayPrivImpl_Vtbl;
792 This->lpOleCommandTargetVtbl = &IOleCommandTargetImpl_Vtbl;
793 This->Ref = 1;
794
795 This->Tray = Tray;
796
797 return This;
798 }
799
800 static IStartMenuSite*
801 CreateStartMenuSite(IN ITrayWindow *Tray)
802 {
803 IStartMenuSiteImpl *This;
804
805 This = IStartMenuSiteImpl_Construct(Tray);
806 if (This != NULL)
807 {
808 return IStartMenuSite_from_IStartMenuSiteImpl(This);
809 }
810
811 return NULL;
812 }
813
814 HRESULT
815 UpdateStartMenu(IN OUT IMenuPopup *pMenuPopup,
816 IN HBITMAP hbmBanner OPTIONAL,
817 IN BOOL bSmallIcons)
818 {
819 IBanneredBar *pbb;
820 HRESULT hRet;
821
822 hRet = IMenuPopup_QueryInterface(pMenuPopup,
823 &IID_IBanneredBar,
824 (PVOID *)&pbb);
825 if (SUCCEEDED(hRet))
826 {
827 hRet = IBanneredBar_SetBitmap(pbb, hbmBanner);
828
829 /* Update the icon size */
830 hRet = IBanneredBar_SetIconSize(pbb,
831 bSmallIcons ? BMICON_SMALL : BMICON_LARGE);
832
833 IBanneredBar_Release(pbb);
834 }
835
836 return hRet;
837 }
838
839 IMenuPopup *
840 CreateStartMenu(IN ITrayWindow *Tray,
841 OUT IMenuBand **ppMenuBand,
842 IN HBITMAP hbmBanner OPTIONAL,
843 IN BOOL bSmallIcons)
844 {
845 HRESULT hr;
846 IObjectWithSite *pOws = NULL;
847 IMenuPopup *pMp = NULL;
848 IStartMenuSite *pSms = NULL;
849 IMenuBand *pMb = NULL;
850 IInitializeObject *pIo;
851 IUnknown *pUnk = NULL;
852 IBandSite *pBs = NULL;
853 DWORD dwBandId = 0;
854
855 pSms = CreateStartMenuSite(Tray);
856 if (pSms == NULL)
857 return NULL;
858
859 #if 0
860 hr = CoCreateInstance(&CLSID_StartMenu,
861 NULL,
862 CLSCTX_INPROC_SERVER,
863 &IID_IMenuPopup,
864 (PVOID *)&pMp);
865 #else
866 hr = CStartMenu_Constructor(&IID_IMenuPopup,(PVOID *)&pMp);
867 #endif
868 if (FAILED(hr))
869 {
870 DbgPrint("CoCreateInstance failed: %x\n", hr);
871 goto cleanup;
872 }
873
874 hr = IMenuPopup_QueryInterface(pMp,
875 &IID_IObjectWithSite,
876 (PVOID *)&pOws);
877 if (FAILED(hr))
878 {
879 DbgPrint("IMenuPopup_QueryInterface failed: %x\n", hr);
880 goto cleanup;
881 }
882
883 /* Set the menu site so we can handle messages */
884 hr = IObjectWithSite_SetSite(pOws, (IUnknown *)pSms);
885 if (FAILED(hr))
886 {
887 DbgPrint("IObjectWithSite_SetSite failed: %x\n", hr);
888 goto cleanup;
889 }
890
891 /* Initialize the menu object */
892 hr = IMenuPopup_QueryInterface(pMp, &IID_IInitializeObject, (PVOID*)&pIo);
893 if (SUCCEEDED(hr))
894 {
895 hr = IInitializeObject_Initialize(pIo);
896 IInitializeObject_Release(pIo);
897 }
898 else
899 hr = S_OK;
900
901 /* Everything is initialized now. Let's get the IMenuBand interface. */
902 if (FAILED(hr))
903 {
904 DbgPrint("IMenuPopup_QueryInterface failed: %x\n", hr);
905 goto cleanup;
906 }
907
908 hr = IMenuPopup_GetClient(pMp, &pUnk);
909 if (FAILED(hr))
910 {
911 DbgPrint("IMenuPopup_GetClient failed: %x\n", hr);
912 goto cleanup;
913 }
914
915 hr = IUnknown_QueryInterface(pUnk, &IID_IBandSite, (PVOID *)&pBs);
916 if (FAILED(hr))
917 {
918 DbgPrint("IUnknown_QueryInterface pBs failed: %x\n", hr);
919 goto cleanup;
920 }
921
922 /* Finally we have the IBandSite interface, there's only one
923 band in it that apparently provides the IMenuBand interface */
924 hr = IBandSite_EnumBands(pBs, 0, &dwBandId);
925 if (FAILED(hr))
926 {
927 DbgPrint("IBandSite_EnumBands failed: %x\n", hr);
928 goto cleanup;
929 }
930
931 hr = IBandSite_GetBandObject(pBs, dwBandId, &IID_IMenuBand, (PVOID *)&pMb);
932 if (FAILED(hr))
933 {
934 DbgPrint("IBandSite_GetBandObject failed: %x\n", hr);
935 goto cleanup;
936 }
937
938 UpdateStartMenu(pMp,
939 hbmBanner,
940 bSmallIcons);
941
942 cleanup:
943 if (SUCCEEDED(hr))
944 *ppMenuBand = pMb;
945 else if (pMb != NULL)
946 IMenuBand_Release(pMb);
947
948 if (pBs != NULL)
949 IBandSite_Release(pBs);
950 if (pUnk != NULL)
951 IUnknown_Release(pUnk);
952 if (pOws != NULL)
953 IObjectWithSite_Release(pOws);
954 if (pMp != NULL)
955 IMenuPopup_Release(pMp);
956 if (pSms != NULL)
957 IStartMenuSite_Release(pSms);
958
959 if (FAILED(hr))
960 return NULL;
961 return pMp;
962 }