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
23 static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu
;
25 #define WM_APP_TRAYDESTROY (WM_APP + 0x100)
27 static LONG TrayWndCount
= 0;
29 static const TCHAR szTrayWndClass
[] = TEXT("Shell_TrayWnd");
31 static const ITrayWindowVtbl ITrayWindowImpl_Vtbl
;
32 static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl
;
38 const GUID IID_IShellDesktopTray
= {0x213e2df9, 0x9a14, 0x4328, {0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9}};
42 const ITrayWindowVtbl
*lpVtbl
;
43 const IShellDesktopTrayVtbl
*lpVtblShellDesktopTray
;
51 HIMAGELIST himlStartBtn
;
56 ITrayBandSite
*TrayBandSite
;
63 HMONITOR PreviousMonitor
;
64 DWORD DraggingPosition
;
65 HMONITOR DraggingMonitor
;
76 DWORD AlwaysOnTop
: 1;
77 DWORD SmSmallIcons
: 1;
91 IMenuBand
*StartMenuBand
;
92 IMenuPopup
*StartMenuPopup
;
95 HWND hwndTrayPropertiesOwner
;
96 HWND hwndRunFileDlgOwner
;
99 BOOL
LaunchCPanel(HWND hwnd
, LPCTSTR applet
)
101 TCHAR szParams
[MAX_PATH
];
103 StringCbCopy(szParams
, sizeof(szParams
),
104 TEXT("shell32.dll,Control_RunDLL "));
105 if (FAILED(StringCbCat(szParams
, sizeof(szParams
),
109 return (ShellExecute(hwnd
, TEXT("open"), TEXT("rundll32.exe"), szParams
, NULL
, SW_SHOWDEFAULT
) > (HINSTANCE
)32);
113 IUnknown_from_impl(ITrayWindowImpl
*This
)
115 return (IUnknown
*)&This
->lpVtbl
;
119 ITrayWindow_from_impl(ITrayWindowImpl
*This
)
121 return (ITrayWindow
*)&This
->lpVtbl
;
124 static IShellDesktopTray
*
125 IShellDesktopTray_from_impl(ITrayWindowImpl
*This
)
127 return (IShellDesktopTray
*)&This
->lpVtblShellDesktopTray
;
130 static ITrayWindowImpl
*
131 impl_from_ITrayWindow(ITrayWindow
*iface
)
133 return (ITrayWindowImpl
*)((ULONG_PTR
)iface
- FIELD_OFFSET(ITrayWindowImpl
,
137 static ITrayWindowImpl
*
138 impl_from_IShellDesktopTray(IShellDesktopTray
*iface
)
140 return (ITrayWindowImpl
*)((ULONG_PTR
)iface
- FIELD_OFFSET(ITrayWindowImpl
,
141 lpVtblShellDesktopTray
));
149 ITrayWindowImpl_UpdateNonClientMetrics(IN OUT ITrayWindowImpl
*This
)
151 This
->ncm
.cbSize
= sizeof(This
->ncm
);
152 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
157 if (This
->hFont
!= NULL
)
158 DeleteObject(This
->hFont
);
160 This
->hFont
= CreateFontIndirect(&This
->ncm
.lfMessageFont
);
168 ITrayWindowImpl_SetWindowsFont(IN OUT ITrayWindowImpl
*This
)
170 if (This
->hwndTrayNotify
!= NULL
)
172 SendMessage(This
->hwndTrayNotify
,
180 ITrayWindowImpl_GetScreenRectFromRect(IN OUT ITrayWindowImpl
*This
,
187 mi
.cbSize
= sizeof(mi
);
188 hMon
= MonitorFromRect(pRect
,
194 *pRect
= mi
.rcMonitor
;
200 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
201 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
210 ITrayWindowImpl_GetMonitorFromRect(IN OUT ITrayWindowImpl
*This
,
211 IN
const RECT
*pRect
)
215 /* In case the monitor sizes or saved sizes differ a bit (probably
216 not a lot, only so the tray window overlaps into another monitor
217 now), minimize the risk that we determine a wrong monitor by
218 using the center point of the tray window if we can't determine
219 it using the rectangle. */
220 hMon
= MonitorFromRect(pRect
,
221 MONITOR_DEFAULTTONULL
);
226 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
227 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
229 /* be less error-prone, find the nearest monitor */
230 hMon
= MonitorFromPoint(pt
,
231 MONITOR_DEFAULTTONEAREST
);
238 ITrayWindowImpl_GetScreenRect(IN OUT ITrayWindowImpl
*This
,
239 IN HMONITOR hMonitor
,
242 HMONITOR hMon
= NULL
;
244 if (hMonitor
!= NULL
)
248 mi
.cbSize
= sizeof(mi
);
249 if (!GetMonitorInfo(hMonitor
,
252 /* Hm, the monitor is gone? Try to find a monitor where it
253 could be located now */
254 hMon
= ITrayWindowImpl_GetMonitorFromRect(This
,
257 !GetMonitorInfo(hMon
,
265 *pRect
= mi
.rcMonitor
;
272 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
273 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
280 ITrayWindowImpl_MakeTrayRectWithSize(IN DWORD Position
,
281 IN
const SIZE
*pTraySize
,
287 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
291 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
295 pRect
->left
= pRect
->right
- pTraySize
->cx
;
300 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
306 ITrayWindowImpl_GetTrayRectFromScreenRect(IN OUT ITrayWindowImpl
*This
,
308 IN
const RECT
*pScreen
,
309 IN
const SIZE
*pTraySize OPTIONAL
,
312 if (pTraySize
== NULL
)
313 pTraySize
= &This
->TraySize
;
317 /* Move the border outside of the screen */
319 GetSystemMetrics(SM_CXEDGE
),
320 GetSystemMetrics(SM_CYEDGE
));
322 ITrayWindowImpl_MakeTrayRectWithSize(Position
,
328 ITrayWindowImpl_IsPosHorizontal(IN OUT ITrayWindowImpl
*This
)
330 return This
->Position
== ABE_TOP
|| This
->Position
== ABE_BOTTOM
;
334 ITrayWindowImpl_CalculateValidSize(IN OUT ITrayWindowImpl
*This
,
343 //Horizontal = ITrayWindowImpl_IsPosHorizontal(This);
345 szWnd
.cx
= pRect
->right
- pRect
->left
;
346 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
349 hMon
= ITrayWindowImpl_GetScreenRectFromRect(This
,
351 MONITOR_DEFAULTTONEAREST
);
353 /* Calculate the maximum size of the tray window and limit the window
354 size to half of the screen's size. */
355 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
356 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
357 if (szWnd
.cx
> szMax
.cx
)
359 if (szWnd
.cy
> szMax
.cy
)
362 /* FIXME - calculate */
364 ITrayWindowImpl_GetTrayRectFromScreenRect(This
,
375 ITrayWindowImpl_GetMinimumWindowSize(IN OUT ITrayWindowImpl
*This
,
380 AdjustWindowRectEx(&rcMin
,
381 GetWindowLong(This
->hWnd
,
384 GetWindowLong(This
->hWnd
,
393 ITrayWindowImpl_GetDraggingRectFromPt(IN OUT ITrayWindowImpl
*This
,
396 OUT HMONITOR
*phMonitor
)
398 HMONITOR hMon
, hMonNew
;
399 DWORD PosH
, PosV
, Pos
;
400 SIZE DeltaPt
, ScreenOffset
;
406 /* Determine the screen rectangle */
407 hMon
= MonitorFromPoint(pt
,
408 MONITOR_DEFAULTTONULL
);
414 mi
.cbSize
= sizeof(mi
);
415 if (!GetMonitorInfo(hMon
,
419 goto GetPrimaryScreenRect
;
422 /* make left top corner of the screen zero based to
423 make calculations easier */
424 pt
.x
-= mi
.rcMonitor
.left
;
425 pt
.y
-= mi
.rcMonitor
.top
;
427 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
428 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
429 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
430 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
434 GetPrimaryScreenRect
:
437 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
438 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
441 /* Calculate the nearest screen border */
442 if (pt
.x
< rcScreen
.right
/ 2)
449 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
453 if (pt
.y
< rcScreen
.bottom
/ 2)
460 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
464 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
466 /* Fix the screen origin to be relative to the primary monitor again */
467 OffsetRect(&rcScreen
,
471 hMonNew
= ITrayWindowImpl_GetMonitorFromRect(This
,
472 &This
->rcTrayWnd
[Pos
]);
477 /* Recalculate the rectangle, we're dragging to another monitor.
478 We don't need to recalculate the rect on single monitor systems. */
479 szTray
.cx
= This
->rcTrayWnd
[Pos
].right
- This
->rcTrayWnd
[Pos
].left
;
480 szTray
.cy
= This
->rcTrayWnd
[Pos
].bottom
- This
->rcTrayWnd
[Pos
].top
;
482 ITrayWindowImpl_GetTrayRectFromScreenRect(This
,
492 /* The user is dragging the tray window on the same monitor. We don't need
493 to recalculate the rectangle */
494 *pRect
= This
->rcTrayWnd
[Pos
];
503 ITrayWindowImpl_GetDraggingRectFromRect(IN OUT ITrayWindowImpl
*This
,
505 OUT HMONITOR
*phMonitor
)
509 /* Calculate the center of the rectangle. We call
510 ITrayWindowImpl_GetDraggingRectFromPt to calculate a valid
511 dragging rectangle */
512 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
513 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
515 return ITrayWindowImpl_GetDraggingRectFromPt(This
,
522 ITrayWindowImpl_ChangingWinPos(IN OUT ITrayWindowImpl
*This
,
523 IN OUT LPWINDOWPOS pwp
)
527 if (This
->IsDragging
)
529 rcTray
.left
= pwp
->x
;
531 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
532 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
534 if (!EqualRect(&rcTray
,
535 &This
->rcTrayWnd
[This
->DraggingPosition
]))
537 /* Recalculate the rectangle, the user dragged the tray
538 window to another monitor or the window was somehow else
540 This
->DraggingPosition
= ITrayWindowImpl_GetDraggingRectFromRect(This
,
542 &This
->DraggingMonitor
);
543 //This->rcTrayWnd[This->DraggingPosition] = rcTray;
546 //This->Monitor = ITrayWindowImpl_CalculateValidSize(This,
547 // This->DraggingPosition,
550 This
->Monitor
= This
->DraggingMonitor
;
551 This
->Position
= This
->DraggingPosition
;
552 This
->IsDragging
= FALSE
;
554 This
->rcTrayWnd
[This
->Position
] = rcTray
;
557 else if (GetWindowRect(This
->hWnd
,
560 if (This
->InSizeMove
)
562 if (!(pwp
->flags
& SWP_NOMOVE
))
564 rcTray
.left
= pwp
->x
;
568 if (!(pwp
->flags
& SWP_NOSIZE
))
570 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
571 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
574 This
->Position
= ITrayWindowImpl_GetDraggingRectFromRect(This
,
578 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
585 ITrayWindowImpl_MakeTrayRectWithSize(This
->Position
,
590 This
->rcTrayWnd
[This
->Position
] = rcTray
;
594 /* If the user isn't resizing the tray window we need to make sure the
595 new size or position is valid. This is to prevent changes to the window
596 without user interaction. */
597 rcTray
= This
->rcTrayWnd
[This
->Position
];
601 This
->TraySize
.cx
= rcTray
.right
- rcTray
.left
;
602 This
->TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
604 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
605 pwp
->x
= rcTray
.left
;
607 pwp
->cx
= This
->TraySize
.cx
;
608 pwp
->cy
= This
->TraySize
.cy
;
613 ITrayWindowImpl_ApplyClipping(IN OUT ITrayWindowImpl
*This
,
616 RECT rcClip
, rcWindow
;
619 if (GetWindowRect(This
->hWnd
,
622 /* Disable clipping on systems with only one monitor */
623 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
630 ITrayWindowImpl_GetScreenRect(This
,
634 if (!IntersectRect(&rcClip
,
645 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
650 /* Set the clipping region or make sure the window isn't clipped
651 by disabling it explicitly. */
652 SetWindowRgn(This
->hWnd
,
659 ITrayWindowImpl_ResizeWorkArea(IN OUT ITrayWindowImpl
*This
)
661 RECT rcTray
,rcWorkArea
;
663 /* If monitor has changed then fix the previous monitors work area */
664 if (This
->PreviousMonitor
!= This
->Monitor
)
666 ITrayWindowImpl_GetScreenRect(This
,
667 This
->PreviousMonitor
,
669 SystemParametersInfo(SPI_SETWORKAREA
,
675 rcTray
= This
->rcTrayWnd
[This
->Position
];
677 ITrayWindowImpl_GetScreenRect(This
,
680 This
->PreviousMonitor
= This
->Monitor
;
682 /* If AutoHide is false then change the workarea to exclude the area that
683 the taskbar covers. */
686 switch (This
->Position
)
689 rcWorkArea
.top
= rcTray
.bottom
;
692 rcWorkArea
.left
= rcTray
.right
;
695 rcWorkArea
.right
= rcTray
.left
;
698 rcWorkArea
.bottom
= rcTray
.top
;
703 SystemParametersInfo(SPI_SETWORKAREA
,
710 ITrayWindowImpl_CheckTrayWndPosition(IN OUT ITrayWindowImpl
*This
)
714 rcTray
= This
->rcTrayWnd
[This
->Position
];
715 // DbgPrint("CheckTray: %d: %d,%d,%d,%d\n", This->Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
717 /* Move the tray window */
718 SetWindowPos(This
->hWnd
,
722 rcTray
.right
- rcTray
.left
,
723 rcTray
.bottom
- rcTray
.top
,
726 ITrayWindowImpl_ResizeWorkArea(This
);
728 ITrayWindowImpl_ApplyClipping(This
,
732 typedef struct _TW_STUCKRECTS2
740 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
743 ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl
*This
)
748 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
749 DWORD cbSize
= sizeof(sr
);
751 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
752 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
753 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
754 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
756 if (SHGetValue(hkExplorer
,
761 &cbSize
) == ERROR_SUCCESS
&&
762 sr
.cbSize
== sizeof(sr
))
764 This
->AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
765 This
->AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
766 This
->SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
767 This
->HideClock
= (sr
.dwFlags
& 0x8) != 0;
769 /* FIXME: Are there more flags? */
771 if (This
->hWnd
!= NULL
)
772 SetWindowPos (This
->hWnd
,
773 This
->AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
778 SWP_NOMOVE
| SWP_NOSIZE
);
780 if (sr
.Position
> ABE_BOTTOM
)
781 This
->Position
= ABE_BOTTOM
;
783 This
->Position
= sr
.Position
;
785 /* Try to find out which monitor the tray window was located on last.
786 Here we're only interested in the monitor screen that we think
787 is the last one used. We're going to determine on which monitor
788 we really are after calculating the docked position. */
790 ITrayWindowImpl_GetScreenRectFromRect(This
,
792 MONITOR_DEFAULTTONEAREST
);
796 This
->Position
= ABE_BOTTOM
;
798 /* Use the minimum size of the taskbar, we'll use the start
799 button as a minimum for now. Make sure we calculate the
800 entire window size, not just the client size. However, we
801 use a thinner border than a standard thick border, so that
802 the start button and bands are not stuck to the screen border. */
803 sr
.Size
.cx
= This
->StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
804 sr
.Size
.cy
= This
->StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
806 /* Use the primary screen by default */
809 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
810 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
811 ITrayWindowImpl_GetScreenRectFromRect(This
,
813 MONITOR_DEFAULTTOPRIMARY
);
816 /* Determine a minimum tray window rectangle. The "client" height is
817 zero here since we cannot determine an optimal minimum width when
818 loaded as a vertical tray window. We just need to make sure the values
819 loaded from the registry are at least. The windows explorer behaves
820 the same way, it allows the user to save a zero width vertical tray
821 window, but not a zero height horizontal tray window. */
822 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
823 WndSize
.cy
= This
->StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
825 if (WndSize
.cx
< sr
.Size
.cx
)
826 WndSize
.cx
= sr
.Size
.cx
;
827 if (WndSize
.cy
< sr
.Size
.cy
)
828 WndSize
.cy
= sr
.Size
.cy
;
830 /* Save the calculated size */
831 This
->TraySize
= WndSize
;
833 /* Calculate all docking rectangles. We need to do this here so they're
834 initialized and dragging the tray window to another position gives
840 ITrayWindowImpl_GetTrayRectFromScreenRect(This
,
844 &This
->rcTrayWnd
[Pos
]);
845 // DbgPrint("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, This->Position, This->rcTrayWnd[Pos].left, This->rcTrayWnd[Pos].top, This->rcTrayWnd[Pos].right, This->rcTrayWnd[Pos].bottom);
848 /* Determine which monitor we are on. It shouldn't matter which docked
849 position rectangle we use */
850 This
->Monitor
= ITrayWindowImpl_GetMonitorFromRect(This
,
851 &This
->rcTrayWnd
[ABE_LEFT
]);
855 ITrayWindowImpl_TrackMenu(IN OUT ITrayWindowImpl
*This
,
857 IN POINT
*ppt OPTIONAL
,
858 IN HWND hwndExclude OPTIONAL
,
860 IN BOOL IsContextMenu
)
862 TPMPARAMS tmp
, *ptmp
= NULL
;
867 if (hwndExclude
!= NULL
)
869 /* Get the client rectangle and map it to screen coordinates */
870 if (GetClientRect(hwndExclude
,
872 MapWindowPoints(hwndExclude
,
874 (LPPOINT
)&tmp
.rcExclude
,
884 GetClientRect(This
->hWnd
,
886 MapWindowPoints(This
->hWnd
,
888 (LPPOINT
)&tmp
.rcExclude
,
896 /* NOTE: TrackPopupMenuEx will eventually align the track position
897 for us, no need to take care of it here as long as the
898 coordinates are somewhere within the exclusion rectangle */
899 pt
.x
= ptmp
->rcExclude
.left
;
900 pt
.y
= ptmp
->rcExclude
.top
;
908 tmp
.cbSize
= sizeof(tmp
);
910 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
911 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
913 fuFlags
|= TPM_RIGHTBUTTON
;
915 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
917 cmdId
= TrackPopupMenuEx(hMenu
,
928 ITrayWindowImpl_TrackCtxMenu(IN OUT ITrayWindowImpl
*This
,
929 IN
const TRAYWINDOW_CTXMENU
*pMenu
,
930 IN POINT
*ppt OPTIONAL
,
931 IN HWND hwndExclude OPTIONAL
,
933 IN PVOID Context OPTIONAL
)
937 PVOID pcmContext
= NULL
;
939 hPopup
= pMenu
->CreateCtxMenu(This
->hWnd
,
944 cmdId
= ITrayWindowImpl_TrackMenu(This
,
951 pMenu
->CtxMenuCommand(This
->hWnd
,
961 ITrayWindowImpl_Free(ITrayWindowImpl
*This
)
963 HeapFree(hProcessHeap
,
969 static ULONG STDMETHODCALLTYPE
970 ITrayWindowImpl_Release(IN OUT ITrayWindow
*iface
)
972 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
975 Ret
= InterlockedDecrement(&This
->Ref
);
977 ITrayWindowImpl_Free(This
);
983 ITrayWindowImpl_Destroy(ITrayWindowImpl
*This
)
985 (void)InterlockedExchangePointer((PVOID
*)&This
->hWnd
,
988 if (This
->himlStartBtn
!= NULL
)
990 ImageList_Destroy(This
->himlStartBtn
);
991 This
->himlStartBtn
= NULL
;
994 if (This
->hCaptionFont
!= NULL
)
996 DeleteObject(This
->hCaptionFont
);
997 This
->hCaptionFont
= NULL
;
1000 if (This
->hStartBtnFont
!= NULL
)
1002 DeleteObject(This
->hStartBtnFont
);
1003 This
->hStartBtnFont
= NULL
;
1006 if (This
->hFont
!= NULL
)
1008 DeleteObject(This
->hFont
);
1012 if (This
->StartMenuPopup
!= NULL
)
1014 IMenuPopup_Release(This
->StartMenuPopup
);
1015 This
->StartMenuPopup
= NULL
;
1018 if (This
->hbmStartMenu
!= NULL
)
1020 DeleteObject(This
->hbmStartMenu
);
1021 This
->hbmStartMenu
= NULL
;
1024 if (This
->StartMenuBand
!= NULL
)
1026 IMenuBand_Release(This
->StartMenuBand
);
1027 This
->StartMenuBand
= NULL
;
1030 if (This
->TrayBandSite
!= NULL
)
1032 /* FIXME: Unload bands */
1033 ITrayBandSite_Release(This
->TrayBandSite
);
1034 This
->TrayBandSite
= NULL
;
1037 if (This
->TaskbarTheme
)
1039 CloseThemeData(This
->TaskbarTheme
);
1040 This
->TaskbarTheme
= NULL
;
1043 ITrayWindowImpl_Release(ITrayWindow_from_impl(This
));
1045 if (InterlockedDecrement(&TrayWndCount
) == 0)
1049 static ULONG STDMETHODCALLTYPE
1050 ITrayWindowImpl_AddRef(IN OUT ITrayWindow
*iface
)
1052 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1054 return InterlockedIncrement(&This
->Ref
);
1059 ITrayWindowImpl_NCCreate(IN OUT ITrayWindowImpl
*This
)
1061 ITrayWindowImpl_AddRef(ITrayWindow_from_impl(This
));
1067 ITrayWindowImpl_UpdateStartButton(IN OUT ITrayWindowImpl
*This
,
1068 IN HBITMAP hbmStart OPTIONAL
)
1070 SIZE Size
= { 0, 0 };
1072 if (This
->himlStartBtn
== NULL
||
1073 !SendMessage(This
->hwndStart
,
1078 Size
.cx
= GetSystemMetrics(SM_CXEDGE
);
1079 Size
.cy
= GetSystemMetrics(SM_CYEDGE
);
1081 if (hbmStart
== NULL
)
1083 hbmStart
= (HBITMAP
)SendMessage(This
->hwndStart
,
1089 if (hbmStart
!= NULL
)
1093 if (GetObject(hbmStart
,
1097 Size
.cx
+= bmp
.bmWidth
;
1098 Size
.cy
+= max(bmp
.bmHeight
,
1099 GetSystemMetrics(SM_CYCAPTION
));
1103 /* Huh?! Shouldn't happen... */
1110 Size
.cx
+= GetSystemMetrics(SM_CXMINIMIZED
);
1111 Size
.cy
+= GetSystemMetrics(SM_CYCAPTION
);
1115 /* Save the size of the start button */
1116 This
->StartBtnSize
= Size
;
1120 ITrayWindowImpl_AlignControls(IN OUT ITrayWindowImpl
*This
,
1121 IN PRECT prcClient OPTIONAL
)
1124 SIZE TraySize
, StartSize
;
1125 POINT ptTrayNotify
= { 0, 0 };
1129 ITrayWindowImpl_UpdateStartButton(This
, NULL
);
1130 if (prcClient
!= NULL
)
1132 rcClient
= *prcClient
;
1136 if (!GetClientRect(This
->hWnd
,
1143 Horizontal
= ITrayWindowImpl_IsPosHorizontal(This
);
1145 /* We're about to resize/move the start button, the rebar control and
1146 the tray notification control */
1147 dwp
= BeginDeferWindowPos(3);
1151 /* Limit the Start button width to the client width, if neccessary */
1152 StartSize
= This
->StartBtnSize
;
1153 if (StartSize
.cx
> rcClient
.right
)
1154 StartSize
.cx
= rcClient
.right
;
1156 if (This
->hwndStart
!= NULL
)
1158 /* Resize and reposition the button */
1159 dwp
= DeferWindowPos(dwp
,
1166 SWP_NOZORDER
| SWP_NOACTIVATE
);
1171 /* Determine the size that the tray notification window needs */
1175 TraySize
.cy
= rcClient
.bottom
;
1179 TraySize
.cx
= rcClient
.right
;
1183 if (This
->hwndTrayNotify
!= NULL
&&
1184 SendMessage(This
->hwndTrayNotify
,
1185 TNWM_GETMINIMUMSIZE
,
1189 /* Move the tray notification window to the desired location */
1191 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1193 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1195 dwp
= DeferWindowPos(dwp
,
1196 This
->hwndTrayNotify
,
1202 SWP_NOZORDER
| SWP_NOACTIVATE
);
1207 /* Resize/Move the rebar control */
1208 if (This
->hwndRebar
!= NULL
)
1210 POINT ptRebar
= { 0, 0 };
1213 SetWindowStyle(This
->hwndRebar
,
1215 Horizontal
? 0 : CCS_VERT
);
1219 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1220 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1221 szRebar
.cy
= rcClient
.bottom
;
1225 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1226 szRebar
.cx
= rcClient
.right
;
1227 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1230 dwp
= DeferWindowPos(dwp
,
1237 SWP_NOZORDER
| SWP_NOACTIVATE
);
1241 EndDeferWindowPos(dwp
);
1243 if (This
->hwndTaskSwitch
!= NULL
)
1245 /* Update the task switch window configuration */
1246 SendMessage(This
->hwndTaskSwitch
,
1247 TSWM_UPDATETASKBARPOS
,
1254 ITrayWindowImpl_CreateStartBtnImageList(IN OUT ITrayWindowImpl
*This
)
1259 if (This
->himlStartBtn
!= NULL
)
1262 IconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
1263 IconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
1265 /* Load the start button icon and create a image list for it */
1266 hIconStart
= LoadImage(hExplorerInstance
,
1267 MAKEINTRESOURCE(IDI_START
),
1271 LR_SHARED
| LR_DEFAULTCOLOR
);
1273 if (hIconStart
!= NULL
)
1275 This
->himlStartBtn
= ImageList_Create(IconSize
.cx
,
1277 ILC_COLOR32
| ILC_MASK
,
1280 if (This
->himlStartBtn
!= NULL
)
1282 if (ImageList_AddIcon(This
->himlStartBtn
,
1288 /* Failed to add the icon! */
1289 ImageList_Destroy(This
->himlStartBtn
);
1290 This
->himlStartBtn
= NULL
;
1298 ITrayWindowImpl_CreateStartButtonBitmap(IN OUT ITrayWindowImpl
*This
)
1300 TCHAR szStartCaption
[32];
1303 HDC hDCScreen
= NULL
;
1304 SIZE Size
, SmallIcon
;
1305 HBITMAP hbmpOld
, hbmp
= NULL
;
1306 HBITMAP hBitmap
= NULL
;
1312 /* NOTE: This is the backwards compatibility code that is used if the
1313 Common Controls Version 6.0 are not available! */
1315 if (!LoadString(hExplorerInstance
,
1318 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1323 /* Load the start button icon */
1324 SmallIcon
.cx
= GetSystemMetrics(SM_CXSMICON
);
1325 SmallIcon
.cy
= GetSystemMetrics(SM_CYSMICON
);
1326 hIconStart
= LoadImage(hExplorerInstance
,
1327 MAKEINTRESOURCE(IDI_START
),
1331 LR_SHARED
| LR_DEFAULTCOLOR
);
1333 hDCScreen
= GetDC(NULL
);
1334 if (hDCScreen
== NULL
)
1337 hDC
= CreateCompatibleDC(hDCScreen
);
1341 hFontOld
= SelectObject(hDC
,
1342 This
->hStartBtnFont
);
1344 Ret
= GetTextExtentPoint32(hDC
,
1346 _tcslen(szStartCaption
),
1354 /* Make sure the height is at least the size of a caption icon. */
1355 if (hIconStart
!= NULL
)
1356 Size
.cx
+= SmallIcon
.cx
+ 4;
1357 Size
.cy
= max(Size
.cy
,
1360 /* Create the bitmap */
1361 hbmp
= CreateCompatibleBitmap(hDCScreen
,
1367 /* Caluclate the button rect */
1370 rcButton
.right
= Size
.cx
;
1371 rcButton
.bottom
= Size
.cy
;
1373 /* Draw the button */
1374 hbmpOld
= SelectObject(hDC
,
1377 Flags
= DC_TEXT
| DC_INBUTTON
;
1378 if (hIconStart
!= NULL
)
1381 if (DrawCapTemp
!= NULL
)
1383 Ret
= DrawCapTemp(NULL
,
1386 This
->hStartBtnFont
,
1398 /* We successfully created the bitmap! */
1403 if (hDCScreen
!= NULL
)
1419 ITrayWindowImpl_UpdateTheme(IN OUT ITrayWindowImpl
*This
)
1421 if (This
->TaskbarTheme
)
1422 CloseThemeData(This
->TaskbarTheme
);
1424 if (IsThemeActive())
1425 This
->TaskbarTheme
= OpenThemeData(This
->hWnd
, L
"Taskbar");
1427 This
->TaskbarTheme
= 0;
1431 ITrayWindowImpl_Create(IN OUT ITrayWindowImpl
*This
)
1433 TCHAR szStartCaption
[32];
1435 SetWindowTheme(This
->hWnd
, L
"TaskBar", NULL
);
1436 ITrayWindowImpl_UpdateTheme(This
);
1438 InterlockedIncrement(&TrayWndCount
);
1440 if (!LoadString(hExplorerInstance
,
1443 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1445 szStartCaption
[0] = TEXT('\0');
1448 if (This
->hStartBtnFont
== NULL
|| This
->hCaptionFont
== NULL
)
1450 NONCLIENTMETRICS ncm
;
1452 /* Get the system fonts, we use the caption font,
1453 always bold, though. */
1454 ncm
.cbSize
= sizeof(ncm
);
1455 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1460 if (This
->hCaptionFont
== NULL
)
1462 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
1463 This
->hCaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1466 if (This
->hStartBtnFont
== NULL
)
1468 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
1469 This
->hStartBtnFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1474 /* Create the Start button */
1475 This
->hwndStart
= CreateWindowEx(0,
1478 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1479 BS_PUSHBUTTON
| BS_CENTER
| BS_VCENTER
| BS_BITMAP
,
1485 (HMENU
)IDC_STARTBTN
,
1488 if (This
->hwndStart
)
1490 SetWindowTheme(This
->hwndStart
, L
"Start", NULL
);
1491 SendMessage(This
->hwndStart
,
1493 (WPARAM
)This
->hStartBtnFont
,
1496 if (ITrayWindowImpl_CreateStartBtnImageList(This
))
1498 BUTTON_IMAGELIST bil
;
1500 /* Try to set the start button image. This requires the Common
1501 Controls 6.0 to be present (XP and later) */
1502 bil
.himl
= This
->himlStartBtn
;
1503 bil
.margin
.left
= bil
.margin
.right
= 1;
1504 bil
.margin
.top
= bil
.margin
.bottom
= 1;
1505 bil
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
1507 if (!SendMessage(This
->hwndStart
,
1512 /* Fall back to the deprecated method on older systems that don't
1513 support Common Controls 6.0 */
1514 ImageList_Destroy(This
->himlStartBtn
);
1515 This
->himlStartBtn
= NULL
;
1517 goto SetStartBtnImage
;
1520 /* We're using the image list, remove the BS_BITMAP style and
1521 don't center it horizontally */
1522 SetWindowStyle(This
->hwndStart
,
1523 BS_BITMAP
| BS_RIGHT
,
1526 ITrayWindowImpl_UpdateStartButton(This
,
1531 HBITMAP hbmStart
, hbmOld
;
1534 hbmStart
= ITrayWindowImpl_CreateStartButtonBitmap(This
);
1535 if (hbmStart
!= NULL
)
1537 ITrayWindowImpl_UpdateStartButton(This
,
1540 hbmOld
= (HBITMAP
)SendMessage(This
->hwndStart
,
1546 DeleteObject(hbmOld
);
1551 /* Load the saved tray window settings */
1552 ITrayWindowImpl_RegLoadSettings(This
);
1554 /* Create and initialize the start menu */
1555 This
->hbmStartMenu
= LoadBitmap(hExplorerInstance
,
1556 MAKEINTRESOURCE(IDB_STARTMENU
));
1557 This
->StartMenuPopup
= CreateStartMenu(ITrayWindow_from_impl(This
),
1558 &This
->StartMenuBand
,
1562 /* Load the tray band site */
1563 if (This
->TrayBandSite
!= NULL
)
1565 ITrayBandSite_Release(This
->TrayBandSite
);
1568 This
->TrayBandSite
= CreateTrayBandSite(ITrayWindow_from_impl(This
),
1570 &This
->hwndTaskSwitch
);
1571 SetWindowTheme(This
->hwndRebar
, L
"TaskBar", NULL
);
1573 /* Create the tray notification window */
1574 This
->hwndTrayNotify
= CreateTrayNotifyWnd(ITrayWindow_from_impl(This
),
1577 if (ITrayWindowImpl_UpdateNonClientMetrics(This
))
1579 ITrayWindowImpl_SetWindowsFont(This
);
1582 /* Move the tray window to the right position and resize it if neccessary */
1583 ITrayWindowImpl_CheckTrayWndPosition(This
);
1585 /* Align all controls on the tray window */
1586 ITrayWindowImpl_AlignControls(This
,
1590 static HRESULT STDMETHODCALLTYPE
1591 ITrayWindowImpl_QueryInterface(IN OUT ITrayWindow
*iface
,
1595 ITrayWindowImpl
*This
;
1600 This
= impl_from_ITrayWindow(iface
);
1602 if (IsEqualIID(riid
,
1605 *ppvObj
= IUnknown_from_impl(This
);
1607 else if (IsEqualIID(riid
,
1608 &IID_IShellDesktopTray
))
1610 *ppvObj
= IShellDesktopTray_from_impl(This
);
1615 return E_NOINTERFACE
;
1618 ITrayWindowImpl_AddRef(iface
);
1622 static ITrayWindowImpl
*
1623 ITrayWindowImpl_Construct(VOID
)
1625 ITrayWindowImpl
*This
;
1627 This
= HeapAlloc(hProcessHeap
,
1633 This
->lpVtbl
= &ITrayWindowImpl_Vtbl
;
1634 This
->lpVtblShellDesktopTray
= &IShellDesktopTrayImpl_Vtbl
;
1636 This
->Position
= (DWORD
)-1;
1641 static HRESULT STDMETHODCALLTYPE
1642 ITrayWindowImpl_Open(IN OUT ITrayWindow
*iface
)
1644 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1649 /* Check if there's already a window created and try to show it.
1650 If it was somehow destroyed just create a new tray window. */
1651 if (This
->hWnd
!= NULL
)
1653 if (IsWindow(This
->hWnd
))
1655 if (!IsWindowVisible(This
->hWnd
))
1657 ITrayWindowImpl_CheckTrayWndPosition(This
);
1659 ShowWindow(This
->hWnd
,
1664 goto TryCreateTrayWnd
;
1671 dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1672 if (This
->AlwaysOnTop
)
1673 dwExStyle
|= WS_EX_TOPMOST
;
1675 if (This
->Position
!= (DWORD
)-1)
1676 rcWnd
= This
->rcTrayWnd
[This
->Position
];
1683 hWnd
= CreateWindowEx(dwExStyle
,
1686 WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
1687 WS_BORDER
| WS_THICKFRAME
,
1690 rcWnd
.right
- rcWnd
.left
,
1691 rcWnd
.bottom
- rcWnd
.top
,
1703 static HRESULT STDMETHODCALLTYPE
1704 ITrayWindowImpl_Close(IN OUT ITrayWindow
*iface
)
1706 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1708 if (This
->hWnd
!= NULL
)
1710 SendMessage(This
->hWnd
,
1719 static HWND STDMETHODCALLTYPE
1720 ITrayWindowImpl_GetHWND(IN OUT ITrayWindow
*iface
)
1722 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1727 static BOOL STDMETHODCALLTYPE
1728 ITrayWindowImpl_IsSpecialHWND(IN OUT ITrayWindow
*iface
,
1731 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1733 return (hWnd
== This
->hWnd
||
1734 (This
->hWndDesktop
!= NULL
&& hWnd
== This
->hWndDesktop
));
1737 static BOOL STDMETHODCALLTYPE
1738 ITrayWindowImpl_IsHorizontal(IN OUT ITrayWindow
*iface
)
1740 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1741 return ITrayWindowImpl_IsPosHorizontal(This
);
1744 static HFONT STDMETHODCALLTYPE
1745 ITrayWIndowImpl_GetCaptionFonts(IN OUT ITrayWindow
*iface
,
1746 OUT HFONT
*phBoldCaption OPTIONAL
)
1748 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1750 if (phBoldCaption
!= NULL
)
1751 *phBoldCaption
= This
->hStartBtnFont
;
1753 return This
->hCaptionFont
;
1757 TrayPropertiesThread(IN OUT PVOID pParam
)
1759 ITrayWindowImpl
*This
= pParam
;
1763 GetWindowRect(This
->hwndStart
, &posRect
);
1764 hwnd
= CreateWindowEx(0,
1767 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1770 posRect
.right
- posRect
.left
,
1771 posRect
.bottom
- posRect
.top
,
1777 This
->hwndTrayPropertiesOwner
= hwnd
;
1779 DisplayTrayProperties(hwnd
);
1781 This
->hwndTrayPropertiesOwner
= NULL
;
1782 DestroyWindow(hwnd
);
1787 static HWND STDMETHODCALLTYPE
1788 ITrayWindowImpl_DisplayProperties(IN OUT ITrayWindow
*iface
)
1790 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1793 if (This
->hwndTrayPropertiesOwner
)
1795 hTrayProp
= GetLastActivePopup(This
->hwndTrayPropertiesOwner
);
1796 if (hTrayProp
!= NULL
&&
1797 hTrayProp
!= This
->hwndTrayPropertiesOwner
)
1799 SetForegroundWindow(hTrayProp
);
1804 CloseHandle(CreateThread(NULL
, 0, TrayPropertiesThread
, This
, 0, NULL
));
1809 OpenCommonStartMenuDirectory(IN HWND hWndOwner
,
1810 IN LPCTSTR lpOperation
)
1812 TCHAR szDir
[MAX_PATH
];
1814 if (SHGetSpecialFolderPath(hWndOwner
,
1816 CSIDL_COMMON_STARTMENU
,
1819 ShellExecute(hWndOwner
,
1829 OpenTaskManager(IN HWND hWndOwner
)
1831 ShellExecute(hWndOwner
,
1833 TEXT("taskmgr.exe"),
1839 static BOOL STDMETHODCALLTYPE
1840 ITrayWindowImpl_ExecContextMenuCmd(IN OUT ITrayWindow
*iface
,
1843 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1844 BOOL bHandled
= TRUE
;
1848 case ID_SHELL_CMD_PROPERTIES
:
1849 ITrayWindow_DisplayProperties(iface
);
1852 case ID_SHELL_CMD_OPEN_ALL_USERS
:
1853 OpenCommonStartMenuDirectory(This
->hWnd
,
1857 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
1858 OpenCommonStartMenuDirectory(This
->hWnd
,
1862 case ID_LOCKTASKBAR
:
1863 if (SHRestricted(REST_CLASSICSHELL
) == 0)
1865 ITrayWindow_Lock(iface
,
1870 case ID_SHELL_CMD_OPEN_TASKMGR
:
1871 OpenTaskManager(This
->hWnd
);
1874 case ID_SHELL_CMD_UNDO_ACTION
:
1877 case ID_SHELL_CMD_SHOW_DESKTOP
:
1880 case ID_SHELL_CMD_TILE_WND_H
:
1881 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
1884 case ID_SHELL_CMD_TILE_WND_V
:
1885 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
1888 case ID_SHELL_CMD_CASCADE_WND
:
1889 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
1892 case ID_SHELL_CMD_CUST_NOTIF
:
1895 case ID_SHELL_CMD_ADJUST_DAT
:
1896 LaunchCPanel(NULL
, TEXT("timedate.cpl"));
1900 DbgPrint("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
1908 static BOOL STDMETHODCALLTYPE
1909 ITrayWindowImpl_Lock(IN OUT ITrayWindow
*iface
,
1913 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1915 bPrevLock
= This
->Locked
;
1916 if (This
->Locked
!= bLock
)
1918 This
->Locked
= bLock
;
1920 if (This
->TrayBandSite
!= NULL
)
1922 if (!SUCCEEDED(ITrayBandSite_Lock(This
->TrayBandSite
,
1926 This
->Locked
= bPrevLock
;
1934 static const ITrayWindowVtbl ITrayWindowImpl_Vtbl
=
1937 ITrayWindowImpl_QueryInterface
,
1938 ITrayWindowImpl_AddRef
,
1939 ITrayWindowImpl_Release
,
1941 ITrayWindowImpl_Open
,
1942 ITrayWindowImpl_Close
,
1943 ITrayWindowImpl_GetHWND
,
1944 ITrayWindowImpl_IsSpecialHWND
,
1945 ITrayWindowImpl_IsHorizontal
,
1946 ITrayWIndowImpl_GetCaptionFonts
,
1947 ITrayWindowImpl_DisplayProperties
,
1948 ITrayWindowImpl_ExecContextMenuCmd
,
1949 ITrayWindowImpl_Lock
1953 ITrayWindowImpl_DrawBackground(IN ITrayWindowImpl
*This
,
1959 GetClientRect(This
->hWnd
, &rect
);
1960 switch (This
->Position
)
1963 backoundPart
= TBP_BACKGROUNDLEFT
;
1966 backoundPart
= TBP_BACKGROUNDTOP
;
1969 backoundPart
= TBP_BACKGROUNDRIGHT
;
1973 backoundPart
= TBP_BACKGROUNDBOTTOM
;
1976 DrawThemeBackground(This
->TaskbarTheme
, dc
, backoundPart
, 0, &rect
, 0);
1981 ITrayWindowImpl_DrawSizer(IN ITrayWindowImpl
*This
,
1988 GetWindowRect(This
->hWnd
, &rect
);
1989 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1991 hdc
= GetDCEx(This
->hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
1993 switch (This
->Position
)
1996 backoundPart
= TBP_SIZINGBARLEFT
;
1997 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
2000 backoundPart
= TBP_SIZINGBARTOP
;
2001 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
2004 backoundPart
= TBP_SIZINGBARRIGHT
;
2005 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
2009 backoundPart
= TBP_SIZINGBARBOTTOM
;
2010 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
2014 DrawThemeBackground(This
->TaskbarTheme
, hdc
, backoundPart
, 0, &rect
, 0);
2016 ReleaseDC(This
->hWnd
, hdc
);
2021 RunFileDlgThread(IN OUT PVOID pParam
)
2023 ITrayWindowImpl
*This
= pParam
;
2025 RUNFILEDLG RunFileDlg
;
2029 GetWindowRect(This
->hwndStart
,&posRect
);
2031 hwnd
= CreateWindowEx(0,
2034 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
2037 posRect
.right
- posRect
.left
,
2038 posRect
.bottom
- posRect
.top
,
2044 This
->hwndRunFileDlgOwner
= hwnd
;
2046 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
2047 RunFileDlg
= (RUNFILEDLG
)GetProcAddress(hShell32
, (LPCSTR
)61);
2049 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
2051 This
->hwndRunFileDlgOwner
= NULL
;
2052 DestroyWindow(hwnd
);
2058 ITrayWindowImpl_DisplayRunFileDlg(IN ITrayWindowImpl
*This
)
2061 if (This
->hwndRunFileDlgOwner
)
2063 hRunDlg
= GetLastActivePopup(This
->hwndRunFileDlgOwner
);
2064 if (hRunDlg
!= NULL
&&
2065 hRunDlg
!= This
->hwndRunFileDlgOwner
)
2067 SetForegroundWindow(hRunDlg
);
2072 CloseHandle(CreateThread(NULL
, 0, RunFileDlgThread
, This
, 0, NULL
));
2075 static void PopupStartMenu(IN ITrayWindowImpl
*This
)
2077 if (This
->StartMenuPopup
!= NULL
)
2083 if (GetWindowRect(This
->hwndStart
,
2084 (RECT
*) &rcExclude
))
2086 switch (This
->Position
)
2089 pt
.x
= rcExclude
.left
;
2090 pt
.y
= rcExclude
.top
;
2091 dwFlags
|= MPPF_BOTTOM
;
2095 pt
.x
= rcExclude
.left
;
2096 pt
.y
= rcExclude
.bottom
;
2097 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_RIGHT
;
2100 pt
.x
= rcExclude
.right
;
2101 pt
.y
= rcExclude
.bottom
;
2102 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_LEFT
;
2106 IMenuPopup_Popup(This
->StartMenuPopup
,
2114 static LRESULT CALLBACK
2115 TrayWndProc(IN HWND hwnd
,
2120 ITrayWindowImpl
*This
= NULL
;
2121 LRESULT Ret
= FALSE
;
2123 if (uMsg
!= WM_NCCREATE
)
2125 This
= (ITrayWindowImpl
*)GetWindowLongPtr(hwnd
,
2129 if (This
!= NULL
|| uMsg
== WM_NCCREATE
)
2131 if (This
!= NULL
&& This
->StartMenuBand
!= NULL
)
2138 Msg
.wParam
= wParam
;
2139 Msg
.lParam
= lParam
;
2141 if (IMenuBand_TranslateMenuMessage(This
->StartMenuBand
,
2148 wParam
= Msg
.wParam
;
2149 lParam
= Msg
.lParam
;
2156 if (This
->hwndTrayNotify
)
2158 TrayNotify_NotifyMsg(This
->hwndTrayNotify
,
2164 case WM_THEMECHANGED
:
2165 ITrayWindowImpl_UpdateTheme(This
);
2168 if (!This
->TaskbarTheme
)
2170 return ITrayWindowImpl_DrawSizer(This
,
2173 if (!This
->TaskbarTheme
)
2175 return ITrayWindowImpl_DrawBackground(This
,
2177 case WM_CTLCOLORBTN
:
2178 SetBkMode((HDC
)wParam
, TRANSPARENT
);
2179 return (LRESULT
)GetStockObject(HOLLOW_BRUSH
);
2187 /* The user may not be able to resize the tray window.
2188 Pretend like the window is not sizeable when the user
2189 clicks on the border. */
2193 SetLastError(ERROR_SUCCESS
);
2194 if (GetClientRect(hwnd
,
2196 (MapWindowPoints(hwnd
,
2199 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2201 pt
.x
= (SHORT
)LOWORD(lParam
);
2202 pt
.y
= (SHORT
)HIWORD(lParam
);
2204 if (PtInRect(&rcClient
,
2207 /* The user is trying to drag the tray window */
2211 /* Depending on the position of the tray window, allow only
2212 changing the border next to the monitor working area */
2213 switch (This
->Position
)
2216 if (pt
.y
> rcClient
.bottom
)
2220 if (pt
.x
> rcClient
.right
)
2224 if (pt
.x
< rcClient
.left
)
2229 if (pt
.y
< rcClient
.top
)
2239 PRECT pRect
= (PRECT
)lParam
;
2241 /* We need to ensure that an application can not accidently
2242 move the tray window (using SetWindowPos). However, we still
2243 need to be able to move the window in case the user wants to
2244 drag the tray window to another position or in case the user
2245 wants to resize the tray window. */
2246 if (!This
->Locked
&& GetCursorPos(&ptCursor
))
2248 This
->IsDragging
= TRUE
;
2249 This
->DraggingPosition
= ITrayWindowImpl_GetDraggingRectFromPt(This
,
2252 &This
->DraggingMonitor
);
2256 *pRect
= This
->rcTrayWnd
[This
->Position
];
2263 PRECT pRect
= (PRECT
)lParam
;
2267 ITrayWindowImpl_CalculateValidSize(This
,
2273 *pRect
= This
->rcTrayWnd
[This
->Position
];
2278 case WM_WINDOWPOSCHANGING
:
2280 ITrayWindowImpl_ChangingWinPos(This
,
2281 (LPWINDOWPOS
)lParam
);
2288 InvalidateRect(This
->hWnd
, NULL
, TRUE
);
2289 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2291 ITrayWindowImpl_ResizeWorkArea(This
);
2292 /* Clip the tray window on multi monitor systems so the edges can't
2293 overlap into another monitor */
2294 ITrayWindowImpl_ApplyClipping(This
,
2297 if (!GetClientRect(This
->hWnd
,
2305 rcClient
.left
= rcClient
.top
= 0;
2306 rcClient
.right
= LOWORD(lParam
);
2307 rcClient
.bottom
= HIWORD(lParam
);
2310 ITrayWindowImpl_AlignControls(This
,
2315 case WM_ENTERSIZEMOVE
:
2316 This
->InSizeMove
= TRUE
;
2317 This
->IsDragging
= FALSE
;
2320 /* Remove the clipping on multi monitor systems while dragging around */
2321 ITrayWindowImpl_ApplyClipping(This
,
2326 case WM_EXITSIZEMOVE
:
2327 This
->InSizeMove
= FALSE
;
2330 /* Apply clipping */
2331 PostMessage(This
->hWnd
,
2343 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2344 The tray window needs to handle this specially, since it normally doesn't have
2347 static const UINT uidDisableItem
[] = {
2358 /* temporarily enable the system menu */
2359 SetWindowStyle(hwnd
,
2363 hSysMenu
= GetSystemMenu(hwnd
,
2365 if (hSysMenu
!= NULL
)
2367 /* Disable all items that are not relevant */
2368 for (i
= 0; i
!= sizeof(uidDisableItem
) / sizeof(uidDisableItem
[0]); i
++)
2370 EnableMenuItem(hSysMenu
,
2372 MF_BYCOMMAND
| MF_GRAYED
);
2375 EnableMenuItem(hSysMenu
,
2378 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2380 /* Display the system menu */
2381 uId
= ITrayWindowImpl_TrackMenu(This
,
2385 This
->Position
!= ABE_TOP
,
2389 SendMessage(This
->hWnd
,
2396 /* revert the system menu window style */
2397 SetWindowStyle(hwnd
,
2408 case WM_NCRBUTTONUP
:
2409 /* We want the user to be able to get a context menu even on the nonclient
2410 area (including the sizing border)! */
2411 uMsg
= WM_CONTEXTMENU
;
2412 wParam
= (WPARAM
)hwnd
;
2415 case WM_CONTEXTMENU
:
2417 POINT pt
, *ppt
= NULL
;
2418 HWND hWndExclude
= NULL
;
2420 /* Check if the administrator has forbidden access to context menus */
2421 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2424 pt
.x
= (SHORT
)LOWORD(lParam
);
2425 pt
.y
= (SHORT
)HIWORD(lParam
);
2427 if (pt
.x
!= -1 || pt
.y
!= -1)
2430 hWndExclude
= This
->hwndStart
;
2432 if ((HWND
)wParam
== This
->hwndStart
)
2434 /* Make sure we can't track the context menu if the start
2435 menu is currently being shown */
2436 if (!(SendMessage(This
->hwndStart
,
2441 ITrayWindowImpl_TrackCtxMenu(This
,
2442 &StartMenuBtnCtxMenu
,
2445 This
->Position
== ABE_BOTTOM
,
2451 /* See if the context menu should be handled by the task band site */
2452 if (ppt
!= NULL
&& This
->TrayBandSite
!= NULL
)
2455 POINT ptClient
= *ppt
;
2457 /* Convert the coordinates to client-coordinates */
2458 MapWindowPoints(NULL
,
2463 hWndAtPt
= ChildWindowFromPoint(This
->hWnd
,
2465 if (hWndAtPt
!= NULL
&&
2466 (hWndAtPt
== This
->hwndRebar
|| IsChild(This
->hwndRebar
,
2469 /* Check if the user clicked on the task switch window */
2471 MapWindowPoints(NULL
,
2476 hWndAtPt
= ChildWindowFromPointEx(This
->hwndRebar
,
2478 CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2479 if (hWndAtPt
== This
->hwndTaskSwitch
)
2480 goto HandleTrayContextMenu
;
2482 /* Forward the message to the task band site */
2483 ITrayBandSite_ProcessMessage(This
->TrayBandSite
,
2491 goto HandleTrayContextMenu
;
2495 HandleTrayContextMenu
:
2496 /* Tray the default tray window context menu */
2497 ITrayWindowImpl_TrackCtxMenu(This
,
2510 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2511 the rebar control! But we shouldn't forward messages that the band
2512 site doesn't handle, such as other controls (start button, tray window */
2513 if (This
->TrayBandSite
== NULL
||
2514 !SUCCEEDED(ITrayBandSite_ProcessMessage(This
->TrayBandSite
,
2521 const NMHDR
*nmh
= (const NMHDR
*)lParam
;
2523 if (nmh
->hwndFrom
== This
->hwndTrayNotify
)
2528 /* Cause all controls to be aligned */
2529 PostMessage(This
->hWnd
,
2540 case WM_NCLBUTTONDBLCLK
:
2542 /* We "handle" this message so users can't cause a weird maximize/restore
2543 window animation when double-clicking the tray window! */
2545 /* We should forward mouse messages to child windows here.
2546 Right now, this is only clock double-click */
2548 if (TrayNotify_GetClockRect(This
->hwndTrayNotify
, &rcClock
))
2551 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2552 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2553 if (PtInRect(&rcClock
, ptClick
))
2554 LaunchCPanel(NULL
, TEXT("timedate.cpl"));
2561 LPCREATESTRUCT CreateStruct
= (LPCREATESTRUCT
)lParam
;
2562 This
= (ITrayWindowImpl
*)CreateStruct
->lpCreateParams
;
2564 if (InterlockedCompareExchangePointer((PVOID
*)&This
->hWnd
,
2568 /* Somebody else was faster... */
2572 SetWindowLongPtr(hwnd
,
2576 return ITrayWindowImpl_NCCreate(This
);
2580 ITrayWindowImpl_Create(This
);
2584 ITrayWindowImpl_Destroy(This
);
2587 case WM_APP_TRAYDESTROY
:
2588 DestroyWindow(hwnd
);
2591 case TWM_OPENSTARTMENU
:
2594 HRESULT hr
= IUnknown_GetWindow((IUnknown
*)This
->StartMenuPopup
, &hwndStartMenu
);
2598 if (IsWindowVisible(hwndStartMenu
))
2599 SetWindowPos(hwndStartMenu
, 0,0,0,0,0, SWP_HIDEWINDOW
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
);
2601 SendMessage(This
->hWnd
, WM_COMMAND
, MAKEWPARAM(BN_CLICKED
, IDC_STARTBTN
), (LPARAM
)This
->hwndStart
);
2606 if ((HWND
)lParam
== This
->hwndStart
)
2608 PopupStartMenu(This
);
2612 if (This
->TrayBandSite
== NULL
||
2613 !SUCCEEDED(ITrayBandSite_ProcessMessage(This
->TrayBandSite
,
2620 switch (LOWORD(wParam
))
2622 /* FIXME: Handle these commands as well */
2623 case IDM_TASKBARANDSTARTMENU
:
2625 ITrayWindowImpl_DisplayProperties(ITrayWindow_from_impl(This
));
2629 case IDM_HELPANDSUPPORT
:
2634 ITrayWindowImpl_DisplayRunFileDlg(This
);
2638 /* FIXME: Handle these commands as well */
2639 case IDM_SYNCHRONIZE
:
2641 case IDM_DISCONNECT
:
2642 case IDM_UNDOCKCOMPUTER
:
2648 EXITWINDLG ExitWinDlg
;
2650 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
2651 ExitWinDlg
= (EXITWINDLG
)GetProcAddress(hShell32
, (LPCSTR
)60);
2667 Ret
= DefWindowProc(hwnd
,
2677 * Tray Window Context Menu
2681 CreateTrayWindowContextMenu(IN HWND hWndOwner
,
2682 IN PVOID
*ppcmContext
,
2683 IN PVOID Context OPTIONAL
)
2685 ITrayWindowImpl
*This
= (ITrayWindowImpl
*)Context
;
2686 IContextMenu
*pcm
= NULL
;
2689 hPopup
= LoadPopupMenu(hExplorerInstance
,
2690 MAKEINTRESOURCE(IDM_TRAYWND
));
2694 if (SHRestricted(REST_CLASSICSHELL
) != 0)
2701 CheckMenuItem(hPopup
,
2703 MF_BYCOMMAND
| (This
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
2705 if (This
->TrayBandSite
!= NULL
)
2707 if (SUCCEEDED(ITrayBandSite_AddContextMenus(This
->TrayBandSite
,
2715 DbgPrint("ITrayBandSite::AddContextMenus succeeded!\n");
2716 *(IContextMenu
**)ppcmContext
= pcm
;
2725 OnTrayWindowContextMenuCommand(IN HWND hWndOwner
,
2727 IN PVOID pcmContext OPTIONAL
,
2728 IN PVOID Context OPTIONAL
)
2730 ITrayWindowImpl
*This
= (ITrayWindowImpl
*)Context
;
2731 IContextMenu
*pcm
= (IContextMenu
*)pcmContext
;
2735 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
2737 CMINVOKECOMMANDINFO cmici
= {0};
2741 /* Setup and invoke the shell command */
2742 cmici
.cbSize
= sizeof(cmici
);
2743 cmici
.hwnd
= hWndOwner
;
2744 cmici
.lpVerb
= (LPCSTR
)MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
2745 cmici
.nShow
= SW_NORMAL
;
2747 IContextMenu_InvokeCommand(pcm
,
2753 ITrayWindow_ExecContextMenuCmd(ITrayWindow_from_impl(This
),
2759 IContextMenu_Release(pcm
);
2762 static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu
= {
2763 CreateTrayWindowContextMenu
,
2764 OnTrayWindowContextMenuCommand
2767 /*****************************************************************************/
2770 RegisterTrayWindowClass(VOID
)
2775 if (!RegisterTrayNotifyWndClass())
2778 wcTrayWnd
.style
= CS_DBLCLKS
;
2779 wcTrayWnd
.lpfnWndProc
= TrayWndProc
;
2780 wcTrayWnd
.cbClsExtra
= 0;
2781 wcTrayWnd
.cbWndExtra
= sizeof(ITrayWindowImpl
*);
2782 wcTrayWnd
.hInstance
= hExplorerInstance
;
2783 wcTrayWnd
.hIcon
= NULL
;
2784 wcTrayWnd
.hCursor
= LoadCursor(NULL
,
2786 wcTrayWnd
.hbrBackground
= (HBRUSH
)(COLOR_3DFACE
+ 1);
2787 wcTrayWnd
.lpszMenuName
= NULL
;
2788 wcTrayWnd
.lpszClassName
= szTrayWndClass
;
2790 Ret
= RegisterClass(&wcTrayWnd
) != 0;
2793 UnregisterTrayNotifyWndClass();
2799 UnregisterTrayWindowClass(VOID
)
2801 UnregisterTrayNotifyWndClass();
2803 UnregisterClass(szTrayWndClass
,
2808 CreateTrayWindow(VOID
)
2810 ITrayWindowImpl
*This
;
2811 ITrayWindow
*TrayWindow
;
2813 This
= ITrayWindowImpl_Construct();
2816 TrayWindow
= ITrayWindow_from_impl(This
);
2818 ITrayWindowImpl_Open(TrayWindow
);
2827 TrayProcessMessages(IN OUT ITrayWindow
*Tray
)
2829 ITrayWindowImpl
*This
;
2832 This
= impl_from_ITrayWindow(Tray
);
2834 /* FIXME: We should keep a reference here... */
2836 while (PeekMessage(&Msg
,
2842 if (Msg
.message
== WM_QUIT
)
2845 if (This
->StartMenuBand
== NULL
||
2846 IMenuBand_IsMenuMessage(This
->StartMenuBand
,
2849 TranslateMessage(&Msg
);
2850 DispatchMessage(&Msg
);
2856 TrayMessageLoop(IN OUT ITrayWindow
*Tray
)
2858 ITrayWindowImpl
*This
;
2862 This
= impl_from_ITrayWindow(Tray
);
2864 /* FIXME: We should keep a reference here... */
2868 Ret
= GetMessage(&Msg
,
2873 if (!Ret
|| Ret
== -1)
2876 if (Msg
.message
== WM_HOTKEY
)
2880 case IDHK_RUN
: /* Win+R */
2881 ITrayWindowImpl_DisplayRunFileDlg(This
);
2886 if (This
->StartMenuBand
== NULL
||
2887 IMenuBand_IsMenuMessage(This
->StartMenuBand
,
2890 TranslateMessage(&Msg
);
2891 DispatchMessage(&Msg
);
2899 * NOTE: This is a very windows-specific COM interface used by SHCreateDesktop()!
2900 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2901 * The reason we implement it is because we have to use SHCreateDesktop() so
2902 * that the shell provides the desktop window and all the features that come
2903 * with it (especially positioning of desktop icons)
2906 static HRESULT STDMETHODCALLTYPE
2907 ITrayWindowImpl_IShellDesktopTray_QueryInterface(IN OUT IShellDesktopTray
*iface
,
2911 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
2912 ITrayWindow
*tray
= ITrayWindow_from_impl(This
);
2914 DbgPrint("IShellDesktopTray::QueryInterface(0x%p, 0x%p)\n", riid
, ppvObj
);
2915 return ITrayWindowImpl_QueryInterface(tray
,
2920 static ULONG STDMETHODCALLTYPE
2921 ITrayWindowImpl_IShellDesktopTray_Release(IN OUT IShellDesktopTray
*iface
)
2923 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
2924 ITrayWindow
*tray
= ITrayWindow_from_impl(This
);
2926 DbgPrint("IShellDesktopTray::Release()\n");
2927 return ITrayWindowImpl_Release(tray
);
2930 static ULONG STDMETHODCALLTYPE
2931 ITrayWindowImpl_IShellDesktopTray_AddRef(IN OUT IShellDesktopTray
*iface
)
2933 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
2934 ITrayWindow
*tray
= ITrayWindow_from_impl(This
);
2936 DbgPrint("IShellDesktopTray::AddRef()\n");
2937 return ITrayWindowImpl_AddRef(tray
);
2940 static ULONG STDMETHODCALLTYPE
2941 ITrayWindowImpl_IShellDesktopTray_GetState(IN OUT IShellDesktopTray
*iface
)
2943 /* FIXME: Return ABS_ flags? */
2944 DbgPrint("IShellDesktopTray::GetState() unimplemented!\n");
2948 static HRESULT STDMETHODCALLTYPE
2949 ITrayWindowImpl_IShellDesktopTray_GetTrayWindow(IN OUT IShellDesktopTray
*iface
,
2950 OUT HWND
*phWndTray
)
2952 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
2953 DbgPrint("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2954 *phWndTray
= This
->hWnd
;
2958 static HRESULT STDMETHODCALLTYPE
2959 ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow(IN OUT IShellDesktopTray
*iface
,
2960 IN HWND hWndDesktop
)
2962 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
2963 DbgPrint("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2965 This
->hWndDesktop
= hWndDesktop
;
2969 static HRESULT STDMETHODCALLTYPE
2970 ITrayWindowImpl_IShellDesktopTray_Unknown(IN OUT IShellDesktopTray
*iface
,
2971 IN DWORD dwUnknown1
,
2972 IN DWORD dwUnknown2
)
2974 DbgPrint("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2978 static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl
=
2981 ITrayWindowImpl_IShellDesktopTray_QueryInterface
,
2982 ITrayWindowImpl_IShellDesktopTray_AddRef
,
2983 ITrayWindowImpl_IShellDesktopTray_Release
,
2984 /*** IShellDesktopTray ***/
2985 ITrayWindowImpl_IShellDesktopTray_GetState
,
2986 ITrayWindowImpl_IShellDesktopTray_GetTrayWindow
,
2987 ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow
,
2988 ITrayWindowImpl_IShellDesktopTray_Unknown