// Classic Shell (c) 2009-2017, Ivo Beltchev // Open-Shell (c) 2017-2018, The Open-Shell Team // Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author #include "stdafx.h" #include "resource.h" #include "StartMenuDLL.h" #include "StartButton.h" #include "MenuContainer.h" #include "SettingsParser.h" #include "Translations.h" #include "Settings.h" #include "SettingsUI.h" #include "ResourceHelper.h" #include "LogManager.h" #include "TouchHelper.h" #include "IatHookHelper.h" #include "dllmain.h" #include #include #include #include #include #include #define HOOK_DROPTARGET // define this to replace the IDropTarget of the start button #define START_TOUCH // touch support for the start button #ifdef BUILD_SETUP #ifndef HOOK_DROPTARGET #define HOOK_DROPTARGET // make sure it is defined in Setup #endif #endif const int MAIN_TASK_BAR=0; typedef std::map id_taskbar_map; id_taskbar_map g_TaskbarInfos; static int g_LastTaskbar=MAIN_TASK_BAR; static int g_NextTaskbar=0; HWND g_TaskBar, g_OwnerWindow; HWND g_TopWin7Menu, g_AllPrograms, g_ProgramsButton, g_UserPic; // from the Windows menu HWND g_ProgWin; HMONITOR g_WSMHMonitor; static HWND g_WinStartButton; static UINT g_StartMenuMsg; static HWND g_Tooltip; static TOOLINFO g_StartButtonTool; static bool g_bHotkeyShift; static int g_HotkeyCSM, g_HotkeyWSM, g_HotkeyShiftID, g_HotkeyCSMID, g_HotkeyWSMID; static HHOOK g_ProgHook, g_StartHook, g_StartMouseHook, g_AppManagerHook, g_NewWindowHook, g_StartMenuHook; static bool g_bAllProgramsTimer; static bool g_bInMenu; static DWORD g_LastClickTime; static DWORD g_LastHoverPos; static bool g_bCrashDump; static int g_SkipMetroCount; static DWORD g_StartButtonOldSizes[12]; const int FIRST_BUTTON_BITMAP=6801; static HWND g_TopDesktopBar; static DWORD g_AppManagerThread; static std::set g_EdgeWindows; static bool g_bTrimHooks; static DWORD g_TaskbarThreadId; static HWND g_CurrentTaskList, g_CurrentTaskChevron, g_CurrentRebar, g_CurrentTaskbarPart, g_CurrentTaskbarButton, g_CurrentDesktopButton; static HBITMAP g_TaskbarTexture; static SIZE g_TaskbarTextureSize; static TTaskbarTile g_TaskbarTileH, g_TaskbarTileV; static RECT g_TaskbarMargins; int g_CurrentCSMTaskbar=-1, g_CurrentWSMTaskbar=-1; static void FindWindowsMenu( void ); static void RecreateStartButton( size_t taskbarId ); static bool WindowsMenuOpened( void ); static tSetWindowCompositionAttribute SetWindowCompositionAttribute; enum { OPEN_NOTHING, OPEN_CLASSIC, OPEN_WINDOWS, OPEN_CUSTOM, OPEN_BOTH, OPEN_DESKTOP, OPEN_CORTANA, }; // MiniDumpNormal - minimal information // MiniDumpWithDataSegs - include global variables // MiniDumpWithFullMemory - include heap MINIDUMP_TYPE MiniDumpType=MiniDumpNormal; static DWORD WINAPI SaveCrashDump( void *pExceptionInfo ) { HMODULE dbghelp=NULL; { wchar_t path[_MAX_PATH]=L"%LOCALAPPDATA%"; DoEnvironmentSubst(path,_countof(path)); dbghelp=LoadLibrary(L"dbghelp.dll"); LPCTSTR szResult = NULL; typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam ); MINIDUMPWRITEDUMP dump=NULL; if (dbghelp) dump=(MINIDUMPWRITEDUMP)GetProcAddress(dbghelp,"MiniDumpWriteDump"); if (dump) { HANDLE file; for (int i=1;;i++) { wchar_t fname[_MAX_PATH]; Sprintf(fname,_countof(fname),L"%s\\CSM_Crash%d.dmp",path,i); file=CreateFile(fname,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL); if (file!=INVALID_HANDLE_VALUE || GetLastError()!=ERROR_FILE_EXISTS) break; } if (file!=INVALID_HANDLE_VALUE) { _MINIDUMP_EXCEPTION_INFORMATION ExInfo; ExInfo.ThreadId = GetCurrentThreadId(); ExInfo.ExceptionPointers = (_EXCEPTION_POINTERS*)pExceptionInfo; ExInfo.ClientPointers = NULL; dump(GetCurrentProcess(),GetCurrentProcessId(),file,MiniDumpType,&ExInfo,NULL,NULL); CloseHandle(file); } } } if (dbghelp) FreeLibrary(dbghelp); TerminateProcess(GetCurrentProcess(),10); return 0; } LONG _stdcall TopLevelFilter( _EXCEPTION_POINTERS *pExceptionInfo ) { if (pExceptionInfo->ExceptionRecord->ExceptionCode==EXCEPTION_STACK_OVERFLOW) { // start a new thread to get a fresh stack (hoping there is enough stack left for CreateThread) HANDLE thread=CreateThread(NULL,0,SaveCrashDump,pExceptionInfo,0,NULL); WaitForSingleObject(thread,INFINITE); CloseHandle(thread); } else SaveCrashDump(pExceptionInfo); return EXCEPTION_CONTINUE_SEARCH; } void InvalidParameterHandler( const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved ) { *(int*)0=0; // force a crash to generate a dump } /////////////////////////////////////////////////////////////////////////////// interface ISwitchModeManager: public IUnknown { STDMETHOD(method3)(); STDMETHOD(method4)(); STDMETHOD(method5)(); STDMETHOD(method6)(); STDMETHOD(method7)(); STDMETHOD(ShowLauncherTipContextMenu)( POINT *pt ); }; interface IImmersiveLauncherThumbnailProvider: public IUnknown { STDMETHOD(GetBitmap)( SIZE size, int scale, int, ISharedBitmap **ppBitmap ); }; interface IImmersiveMonitor: public IUnknown { STDMETHOD(method3)(); STDMETHOD(method4)(); STDMETHOD(GetHandle)(HMONITOR*); }; interface IImmersiveLauncher80: public IUnknown { STDMETHOD(ShowStartView)( int method ); STDMETHOD(method4)(); STDMETHOD(method5)(); STDMETHOD(method6)(); STDMETHOD(method7)(); STDMETHOD(Dismiss)( int method ); }; interface IImmersiveLauncher81: public IUnknown { STDMETHOD(ShowStartView)( int method, int flags ); STDMETHOD(method4)(); STDMETHOD(method5)(); STDMETHOD(method6)(); STDMETHOD(method7)(); STDMETHOD(method8)(); STDMETHOD(method9)(); STDMETHOD(IsVisible)(BOOL *); STDMETHOD(method11)(); STDMETHOD(method12)(); STDMETHOD(method13)(); STDMETHOD(method14)(); STDMETHOD(method15)(); STDMETHOD(method16)(); STDMETHOD(method17)(); STDMETHOD(ConnectToMonitor)(IUnknown *); STDMETHOD(GetMonitor)(IImmersiveMonitor **); }; interface IImmersiveLauncher10RS: public IUnknown { STDMETHOD(ShowStartView)( int method, int flags ); STDMETHOD(method4)(); STDMETHOD(method5)(); STDMETHOD(method6)(); STDMETHOD(IsVisible)(BOOL *); STDMETHOD(method8)(); STDMETHOD(method9)(); STDMETHOD(ConnectToMonitor)(IUnknown *); STDMETHOD(GetMonitor)(IImmersiveMonitor **); }; static const GUID SID_SwitchModeManager={0x085920a1,0x28d3,0x44c1,{0x89,0x7d,0x3b,0xe6,0xd0,0x4b,0x2e,0x07}}; static const GUID IID_ISwitchModeManager={0x976c17be,0xe2d5,0x4f36,{0x93,0x4a,0x7e,0x82,0xf7,0x10,0xea,0xe1}}; static const GUID SID_ImmersiveLauncherThumbnailProvider={0x66ce8036,0x400c,0x42f7,{0x99,0x34,0x02,0xf8,0x84,0xfe,0x27,0x4f}}; static const GUID IID_IImmersiveLauncherThumbnailProvider={0x35c01454,0x53f4,0x4818,{0xba,0x8c,0x7a,0xba,0xdc,0x0f,0xfe,0xe6}}; static const GUID SID_ImmersiveLauncher={0x6f86e01c,0xc649,0x4d61,{0xbe,0x23,0xf1,0x32,0x2d,0xde,0xca,0x9d}}; static const GUID IID_IImmersiveLauncher80={0xfd8b3e33,0xa1f7,0x4e9a,{0x80,0xad,0x80,0x02,0xc7,0x46,0xbe,0x37}}; static const GUID IID_IImmersiveLauncher81={0x93f91f5a,0xa4ca,0x4205,{0x9b,0xeb,0xce,0x4d,0x17,0xc7,0x08,0xf9}}; static const GUID IID_IImmersiveLauncher10RS={0xd8d60399,0xa0f1,0xf987,{0x55,0x51,0x32,0x1f,0xd1,0xb4,0x98,0x64}}; // 14257 static const GUID IID_IImmersiveLauncherProvider={0x6d5140c1,0x7436,0x11ce,{0x80,0x34,0x00,0xaa,0x00,0x60,0x09,0xfa}}; static const CLSID CLSID_ImmersiveShell={0xc2f03a33, 0x21f5, 0x47fa, {0xb4, 0xbb, 0x15, 0x63, 0x62, 0xa2, 0xf2, 0x39}}; static const GUID SID_LauncherTipContextMenu={0xb8c1db5f, 0xcbb3, 0x48bc, {0xaf, 0xd9, 0xce, 0x6b, 0x88, 0x0c, 0x79, 0xed}}; interface ILauncherTipContextMenu: public IUnknown { STDMETHOD(ShowLauncherTipContextMenu)( POINT *pt ); }; interface IImmersiveMonitorService: public IUnknown { STDMETHOD(method3)(); STDMETHOD(method4)(); STDMETHOD(method5)(); STDMETHOD(GetFromHandle)(HMONITOR, IUnknown **); STDMETHOD(method7)(); STDMETHOD(method8)(); STDMETHOD(method9)(); STDMETHOD(method10)(); STDMETHOD(method11)(); STDMETHOD(method12)(); STDMETHOD(method13)(); STDMETHOD(SetImmersiveMonitor)(IUnknown *); }; static const GUID SID_IImmersiveMonitorService={0x47094e3a,0x0cf2,0x430f,{0x80,0x6f,0xcf,0x9e,0x4f,0x0f,0x12,0xdd}}; static const GUID IID_IImmersiveMonitorService={0x4d4c1e64,0xe410,0x4faa,{0xba,0xfa,0x59,0xca,0x06,0x9b,0xfe,0xc2}}; struct StartScreenThumbInfo { SIZE size; HBITMAP bitmap; HANDLE event; }; static bool CreateImmersiveShell( CComPtr &ptr ) { if (GetWinVersion() { public: DECLARE_WND_CLASS_EX(L"OpenShell.COwnerWindow",0,COLOR_MENU) // message handlers BEGIN_MSG_MAP( COwnerWindow ) MESSAGE_HANDLER( WM_ACTIVATE, OnActivate ) MESSAGE_HANDLER( WM_SYSCOLORCHANGE, OnColorChange ) MESSAGE_HANDLER( WM_SETTINGCHANGE, OnSettingChange ) MESSAGE_HANDLER( WM_DISPLAYCHANGE, OnDisplayChange ) END_MSG_MAP() protected: LRESULT OnActivate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { if (LOWORD(wParam)!=WA_INACTIVE) return 0; if (CMenuContainer::s_bPreventClosing) return 0; // check if another menu window is being activated // if not, close all menus for (std::vector::const_iterator it=CMenuContainer::s_Menus.begin();it!=CMenuContainer::s_Menus.end();++it) if ((*it)->m_hWnd==(HWND)lParam) return 0; for (std::vector::reverse_iterator it=CMenuContainer::s_Menus.rbegin();it!=CMenuContainer::s_Menus.rend();++it) if (!(*it)->m_bDestroyed) (*it)->PostMessage(WM_CLOSE); return 0; } LRESULT OnColorChange( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { CMenuContainer::s_Skin.Hash=0; return 0; } LRESULT OnSettingChange( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { if (wParam==SPI_SETWORKAREA) { if (!CMenuContainer::s_Menus.empty()) CMenuContainer::s_Menus[0]->NotifyDisplayChange(); } return 0; } LRESULT OnDisplayChange( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { if (!CMenuContainer::s_Menus.empty()) CMenuContainer::s_Menus[0]->NotifyDisplayChange(); return 0; } }; static COwnerWindow g_Owner; /////////////////////////////////////////////////////////////////////////////// bool TaskbarInfo::HasPart( HWND part ) const { for (std::vector::const_iterator it=taskbarParts.begin();it!=taskbarParts.end();++it) if (*it==part) return true; return false; } static const TaskbarInfo *GetDefaultTaskbarInfo( void ) { if (GetSettingBool(L"AllTaskbars")) { HMONITOR monitor=MonitorFromPoint(CPoint(GetMessagePos()),MONITOR_DEFAULTTONEAREST); for (std::map::const_iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it) { MONITORINFO info; HMONITOR monitor2=NULL; if (GetTaskbarPosition(it->second.taskBar,&info,&monitor2,NULL)!=0xFFFFFFFF && monitor2==monitor) return &it->second; } id_taskbar_map::const_iterator it=g_TaskbarInfos.find(g_LastTaskbar); if (it!=g_TaskbarInfos.end()) return &it->second; } return &g_TaskbarInfos.begin()->second; } TaskbarInfo *GetTaskbarInfo( size_t taskbarId ) { std::map::iterator it=g_TaskbarInfos.find(taskbarId); return (it==g_TaskbarInfos.end())?NULL:&it->second; } static TaskbarInfo *FindTaskBarInfoButton( HWND button ) { for (id_taskbar_map::iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it) if (it->second.startButton==button || it->second.oldButton==button) return &it->second; return NULL; } static TaskbarInfo *FindTaskBarInfoBar( HWND bar ) { for (id_taskbar_map::iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it) if (it->second.taskBar==bar) return &it->second; return NULL; } static LRESULT CALLBACK HookProgManThread( int code, WPARAM wParam, LPARAM lParam ); static LRESULT CALLBACK HookDesktopThread( int code, WPARAM wParam, LPARAM lParam ); static LRESULT CALLBACK HookDesktopThreadMouse(int code, WPARAM wParam, LPARAM lParam); static BOOL CALLBACK FindTooltipEnum( HWND hwnd, LPARAM lParam ) { // look for tooltip control in the current thread that has a tool for g_TaskBar+g_StartButton wchar_t name[256]; GetClassName(hwnd,name,_countof(name)); if (_wcsicmp(name,TOOLTIPS_CLASS)!=0) return TRUE; TOOLINFO info={sizeof(info),0,g_TaskBar,(UINT_PTR)g_WinStartButton}; if (SendMessage(hwnd,TTM_GETTOOLINFO,0,(LPARAM)&info)) { g_Tooltip=hwnd; return FALSE; } return TRUE; } static BOOL CALLBACK FindStartButtonEnum( HWND hwnd, LPARAM lParam ) { // look for top-level window in the current thread with class "button" wchar_t name[256]; GetClassName(hwnd,name,_countof(name)); if (_wcsicmp(name,L"button")!=0) return TRUE; g_WinStartButton=hwnd; return FALSE; } static BOOL CALLBACK FindTaskBarEnum( HWND hwnd, LPARAM lParam ) { // look for top-level window with class "Shell_TrayWnd" and process ID=lParam DWORD process; GetWindowThreadProcessId(hwnd,&process); if (process!=lParam) return TRUE; wchar_t name[256]; GetClassName(hwnd,name,_countof(name)); if (_wcsicmp(name,L"Shell_TrayWnd")!=0) return TRUE; g_TaskBar=hwnd; return FALSE; } // Find the taskbar window for the given process STARTMENUAPI HWND FindTaskBar( DWORD process ) { g_WinStartButton=NULL; g_TaskBar=NULL; g_Tooltip=NULL; // find the taskbar EnumWindows(FindTaskBarEnum,process); if (!g_TaskBar) g_TaskBar=FindWindowEx(GetDesktopWindow(),NULL,L"Shell_TrayWnd",NULL); if (g_TaskBar) { // find start button if (GetWinVersion()==WIN_VER_WIN7) EnumThreadWindows(GetWindowThreadProcessId(g_TaskBar,NULL),FindStartButtonEnum,NULL); if (GetWindowThreadProcessId(g_TaskBar,NULL)==GetCurrentThreadId()) { // find tooltip if (g_WinStartButton) { EnumThreadWindows(GetWindowThreadProcessId(g_TaskBar,NULL),FindTooltipEnum,NULL); if (g_Tooltip) { g_StartButtonTool.cbSize=sizeof(g_StartButtonTool); g_StartButtonTool.hwnd=g_TaskBar; g_StartButtonTool.uId=(UINT_PTR)g_WinStartButton; SendMessage(g_Tooltip,TTM_GETTOOLINFO,0,(LPARAM)&g_StartButtonTool); } } g_OwnerWindow=g_Owner.Create(NULL,0,0,WS_POPUP,WS_EX_TOOLWINDOW|WS_EX_TOPMOST); } } return g_TaskBar; } #ifdef HOOK_DROPTARGET class CStartMenuTarget: public IDropTarget { public: CStartMenuTarget( int taskbarId ) { m_RefCount=1; m_TaskbarId=taskbarId; } // IUnknown virtual STDMETHODIMP QueryInterface( REFIID riid, void **ppvObject ) { *ppvObject=NULL; if (IID_IUnknown==riid || IID_IDropTarget==riid) { AddRef(); *ppvObject=(IDropTarget*)this; return S_OK; } return E_NOINTERFACE; } virtual ULONG STDMETHODCALLTYPE AddRef( void ) { return InterlockedIncrement(&m_RefCount); } virtual ULONG STDMETHODCALLTYPE Release( void ) { long nTemp=InterlockedDecrement(&m_RefCount); if (!nTemp) delete this; return nTemp; } // IDropTarget virtual HRESULT STDMETHODCALLTYPE DragEnter( IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect ) { FORMATETC format1={(CLIPFORMAT)RegisterClipboardFormat(CFSTR_SHELLIDLIST),NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL}; FORMATETC format2={(CLIPFORMAT)RegisterClipboardFormat(CFSTR_INETURL),NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL}; if (pDataObj->QueryGetData(&format1)==S_OK || pDataObj->QueryGetData(&format2)==S_OK) { PostMessage(g_TaskBar,g_StartMenuMsg,(grfKeyState&MK_SHIFT)?MSG_SHIFTDRAG:MSG_DRAG,m_TaskbarId); } *pdwEffect=DROPEFFECT_NONE; return S_OK; } virtual HRESULT STDMETHODCALLTYPE DragOver( DWORD grfKeyState, POINTL pt, DWORD *pdwEffect ) { return *pdwEffect=DROPEFFECT_NONE; return S_OK; } virtual HRESULT STDMETHODCALLTYPE DragLeave( void ) { return S_OK; } virtual HRESULT STDMETHODCALLTYPE Drop( IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect ) { return *pdwEffect=DROPEFFECT_NONE; return S_OK; } private: LONG m_RefCount; int m_TaskbarId; }; #endif static CComPtr g_pOriginalTarget; static void FindTaskBar( void ) { if (!g_TaskBar) { g_StartMenuMsg=RegisterWindowMessage(L"OpenShellMenu.StartMenuMsg"); FindTaskBar(GetCurrentProcessId()); if (g_TaskBar) { g_HotkeyShiftID=GlobalAddAtom(L"OpenShellMenu.HotkeyShift"); g_HotkeyCSMID=GlobalAddAtom(L"OpenShellMenu.HotkeyCSM"); g_HotkeyWSMID=GlobalAddAtom(L"OpenShellMenu.HotkeyWSM"); EnableHotkeys(HOTKEYS_NORMAL); srand(GetTickCount()); } if (!g_TaskBar) g_TaskBar=(HWND)1; } } void EnableStartTooltip( bool bEnable ) { if (g_Tooltip) { SendMessage(g_Tooltip,TTM_POP,0,0); if (bEnable) SendMessage(g_Tooltip,TTM_UPDATETIPTEXT,0,(LPARAM)&g_StartButtonTool); else { TOOLINFO info=g_StartButtonTool; info.lpszText=(LPWSTR)L""; SendMessage(g_Tooltip,TTM_UPDATETIPTEXT,0,(LPARAM)&info); } } } // Restore the original drop target static void UnhookDropTarget( void ) { if (g_pOriginalTarget) { RevokeDragDrop(g_WinStartButton); if (g_pOriginalTarget) RegisterDragDrop(g_WinStartButton,g_pOriginalTarget); g_pOriginalTarget=NULL; } } // Toggle the start menu. bKeyboard - set to true to show the keyboard cues STARTMENUAPI HWND ToggleStartMenu( int taskbarId, bool bKeyboard ) { if (taskbarId==-1) { if (g_TaskbarInfos.find(-1)==g_TaskbarInfos.end()) { g_TaskbarInfos[-1].taskBar=g_TaskBar; } } g_LastTaskbar=taskbarId; return CMenuContainer::ToggleStartMenu(taskbarId,bKeyboard,false); } UINT GetTaskbarPosition( HWND taskBar, MONITORINFO *pInfo, HMONITOR *pMonitor, RECT *pRc ) { if (!IsWindow(taskBar)) return 0xFFFFFFFF; if (taskBar==g_TaskBar) { APPBARDATA appbar={sizeof(appbar),taskBar}; SHAppBarMessage(ABM_GETTASKBARPOS,&appbar); if (pRc) { *pRc=appbar.rc; RECT rc; GetWindowRect(taskBar,&rc); if (appbar.uEdge==ABE_LEFT || appbar.uEdge==ABE_RIGHT) { if (pRc->toptop=rc.top; if (pRc->bottom>rc.bottom) pRc->bottom=rc.bottom; } else if (appbar.uEdge==ABE_TOP || appbar.uEdge==ABE_BOTTOM) { if (pRc->leftleft=rc.left; if (pRc->right>rc.right) pRc->right=rc.right; } } HMONITOR monitor=MonitorFromRect(&appbar.rc,MONITOR_DEFAULTTONEAREST); if (pMonitor) *pMonitor=monitor; if (pInfo) { pInfo->cbSize=sizeof(MONITORINFO); GetMonitorInfo(monitor,pInfo); } return appbar.uEdge; } RECT rc; if (GetWindowRgnBox(taskBar,&rc)!=ERROR) MapWindowPoints(taskBar,NULL,(POINT*)&rc,2); else GetWindowRect(taskBar,&rc); MONITORINFO info={sizeof(info)}; HMONITOR monitor=MonitorFromRect(&rc,MONITOR_DEFAULTTONEAREST); GetMonitorInfo(monitor,&info); if (pMonitor) *pMonitor=monitor; int dx=rc.left+rc.right-info.rcWork.left-info.rcWork.right; int dy=rc.top+rc.bottom-info.rcWork.top-info.rcWork.bottom; if (pInfo) *pInfo=info; bool bAutoHide=false; if (pRc) { GetWindowRect(taskBar,pRc); APPBARDATA appbar={sizeof(appbar)}; bAutoHide=(SHAppBarMessage(ABM_GETSTATE,&appbar)&ABS_AUTOHIDE)!=0; } if (dx<-abs(dy)) { if (bAutoHide && pRc->leftleft,0); return ABE_LEFT; } if (dx>abs(dy)) { if (bAutoHide && pRc->right>info.rcWork.right) OffsetRect(pRc,info.rcWork.right-pRc->right,0); return ABE_RIGHT; } if (dy<-abs(dx)) { if (bAutoHide && pRc->toptop); return ABE_TOP; } if (bAutoHide && pRc->bottom>info.rcWork.bottom) OffsetRect(pRc,0,info.rcWork.bottom-pRc->bottom); return ABE_BOTTOM; } // Returns true if the mouse is on the taskbar portion of the start button bool PointAroundStartButton( size_t taskbarId, const CPoint &pt ) { const TaskbarInfo *taskBar=GetTaskbarInfo(taskbarId); if (!taskBar || !(taskBar->startButton || taskBar->oldButton)) return false; CRect rc; GetWindowRect(taskBar->taskBar,&rc); if (!PtInRect(&rc,pt)) return false; bool rtl=GetWindowLongPtr(taskBar->taskBar,GWL_EXSTYLE)&WS_EX_LAYOUTRTL; CRect rcStart; if (taskBar->startButton) GetWindowRect(taskBar->startButton,&rcStart); CRect rcOld; if (taskBar->oldButton) { GetWindowRect(taskBar->oldButton,&rcOld); if (IsWin11()) { // on Win11 the Start button rectangle is a bit smaller that actual XAML active area // lets make it a bit wider to avoid accidental original Start menu triggers const int adjust=ScaleForDpi(taskBar->taskBar,1); if (rtl) rcOld.left-=adjust; else rcOld.right+=adjust; } } rc.UnionRect(&rcStart,&rcOld); // check if the point is inside the start button rect UINT uEdge=GetTaskbarPosition(taskBar->taskBar,NULL,NULL,NULL); if (uEdge==ABE_LEFT || uEdge==ABE_RIGHT) return pt.y>=rc.top && pt.yrc.left && pt.x<=rc.right; else return pt.x>=rc.left && pt.x::const_iterator it=g_EdgeWindows.begin();it!=g_EdgeWindows.end();++it) ShowWindow(*it,SW_SHOW); g_EdgeWindows.clear(); } void RedrawTaskbars( void ) { for (id_taskbar_map::const_iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it) InvalidateRect(it->second.taskBar,NULL,TRUE); } static CComPtr g_pAppVisibility; static DWORD g_AppVisibilityMonitorCookie; class CMonitorModeEvents: public IAppVisibilityEvents { public: CMonitorModeEvents( void ) { m_RefCount=1; } // IUnknown virtual STDMETHODIMP QueryInterface( REFIID riid, void **ppvObject ) { *ppvObject=NULL; if (IID_IUnknown==riid || __uuidof(IAppVisibilityEvents)==riid) { AddRef(); *ppvObject=(IDropTarget*)this; return S_OK; } return E_NOINTERFACE; } virtual ULONG STDMETHODCALLTYPE AddRef( void ) { return InterlockedIncrement(&m_RefCount); } virtual ULONG STDMETHODCALLTYPE Release( void ) { long nTemp=InterlockedDecrement(&m_RefCount); if (!nTemp) delete this; return nTemp; } // IAppVisibilityEvents virtual HRESULT STDMETHODCALLTYPE AppVisibilityOnMonitorChanged( HMONITOR hMonitor, MONITOR_APP_VISIBILITY previousMode, MONITOR_APP_VISIBILITY currentMode ) { if (GetWinVersion() pImmersiveShell; if (GetWinVersion()>=WIN_VER_WIN10 && CreateImmersiveShell(pImmersiveShell)) { int taskbarId=-1; if (currentVisibleState) { taskbarId=MAIN_TASK_BAR; CComPtr pMonitor; { CComPtr pLauncher; IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher81,(void**)&pLauncher); if (pLauncher) pLauncher->GetMonitor(&pMonitor); } if (!pMonitor) { CComPtr pLauncher; IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher10RS,(void**)&pLauncher); if (pLauncher) pLauncher->GetMonitor(&pMonitor); } if (pMonitor) { HMONITOR monitor; if (SUCCEEDED(pMonitor->GetHandle(&monitor))) { for (id_taskbar_map::const_iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it) { if (monitor==MonitorFromWindow(it->second.taskBar,MONITOR_DEFAULTTONULL)) { taskbarId=it->second.taskbarId; break; } } } } } if (g_CurrentWSMTaskbar!=taskbarId) { if (g_CurrentWSMTaskbar!=-1 && g_CurrentWSMTaskbar!=g_CurrentCSMTaskbar) PressStartButton(g_CurrentWSMTaskbar,false); g_CurrentWSMTaskbar=taskbarId; if (g_CurrentWSMTaskbar!=-1) PressStartButton(g_CurrentWSMTaskbar,true); } } else { ResetHotCorners(); if (IsWin81Update1() && GetSettingBool(L"CustomTaskbar")) PostMessage(g_TaskBar,g_StartMenuMsg,MSG_REDRAWTASKBAR,0); } return S_OK; } private: LONG m_RefCount; }; static const CLSID CLSID_MetroMode={0x7E5FE3D9,0x985F,0x4908,{0x91, 0xF9, 0xEE, 0x19, 0xF9, 0xFD, 0x15, 0x14}}; BOOL CALLBACK AppVisibleProc( HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData ) { bool *pData=(bool*)dwData; MONITOR_APP_VISIBILITY mode; if (SUCCEEDED(g_pAppVisibility->GetAppVisibilityOnMonitor(hMonitor,&mode)) && mode==MAV_APP_VISIBLE) *pData=true; return !*pData; } enum TMetroMode { METRO_NONE, METRO_LAUNCHER, METRO_APP, }; static TMetroMode GetMetroMode( HMONITOR hMonitor ) { if (!g_pAppVisibility) return METRO_NONE; BOOL bLauncher; if (SUCCEEDED(g_pAppVisibility->IsLauncherVisible(&bLauncher)) && bLauncher) { if (!hMonitor) return METRO_LAUNCHER; HWND launcher=FindWindow(L"ImmersiveLauncher",NULL); if (launcher && hMonitor==MonitorFromWindow(launcher,MONITOR_DEFAULTTONULL)) return METRO_LAUNCHER; } if (hMonitor) { MONITOR_APP_VISIBILITY mode; if (SUCCEEDED(g_pAppVisibility->GetAppVisibilityOnMonitor(hMonitor,&mode)) && mode==MAV_APP_VISIBLE) return METRO_APP; } else { bool bAppVisible=false; EnumDisplayMonitors(NULL,NULL,AppVisibleProc,(LPARAM)&bAppVisible); if (bAppVisible) return METRO_APP; } return METRO_NONE; } static bool GetWin10TabletMode( void ) { CRegKey regKey; if (regKey.Open(HKEY_CURRENT_USER,L"Software\\Microsoft\\Windows\\CurrentVersion\\ImmersiveShell",KEY_READ|KEY_WOW64_64KEY)==ERROR_SUCCESS) { DWORD val; return regKey.QueryDWORDValue(L"TabletMode",val)==ERROR_SUCCESS && val; } return false; } static LRESULT CALLBACK HookAppManager( int code, WPARAM wParam, LPARAM lParam ) { if (code==HC_ACTION && wParam) { MSG *msg=(MSG*)lParam; if (msg->message==g_StartMenuMsg && (msg->wParam==MSG_WINXMENU || msg->wParam==MSG_METROTHUMBNAIL || msg->wParam==MSG_SHIFTWIN)) { HWND hwnd=FindWindow(L"ModeInputWnd",NULL); if (hwnd) { DWORD process; GetWindowThreadProcessId(hwnd,&process); if (process==GetCurrentProcessId()) { IObjectWithSite *pObject=(IObjectWithSite*)GetWindowLongPtr(hwnd,0); if (pObject) { CComPtr pSite; pObject->GetSite(IID_IUnknown,(void**)&pSite); if (pSite) { if (msg->wParam==MSG_WINXMENU) { CPoint pt(msg->lParam); CComPtr pSwitchModeManager; IUnknown_QueryService(pSite,SID_SwitchModeManager,IID_ISwitchModeManager,(void**)&pSwitchModeManager); if (pSwitchModeManager) { pSwitchModeManager->ShowLauncherTipContextMenu(&pt); // set the current immersive monitor AFTER the menu returns (this way Search is shown in the correct monitor) CComPtr pMonitorService; IUnknown_QueryService(pSite,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService); if (pMonitorService) { HMONITOR monitor=MonitorFromPoint(pt,MONITOR_DEFAULTTONEAREST); if (GetWinVersion()==WIN_VER_WIN8) { CComPtr pMonitor; pMonitorService->GetFromHandle(monitor,&pMonitor); if (pMonitor) pMonitorService->SetImmersiveMonitor(pMonitor); } else if (GetWinVersion()>WIN_VER_WIN8) { // doesn't seem to be doing anything on 8.1, but do it just in case CComPtr pMonitor; pMonitorService->GetFromHandle(monitor,&pMonitor); if (pMonitor) { CComPtr pLauncher; IUnknown_QueryService(pSite,SID_ImmersiveLauncher,IID_IImmersiveLauncher81,(void**)&pLauncher); if (pLauncher) pLauncher->ConnectToMonitor(pMonitor); } } } } } if (msg->wParam==MSG_METROTHUMBNAIL) { StartScreenThumbInfo &info=*(StartScreenThumbInfo*)msg->lParam; CComPtr pLauncher; IUnknown_QueryService(pSite,SID_ImmersiveLauncher,IID_IImmersiveLauncherProvider,(void**)&pLauncher); if (pLauncher) { CComPtr pProvider; IUnknown_QueryService(pLauncher,SID_ImmersiveLauncherThumbnailProvider,IID_IImmersiveLauncherThumbnailProvider,(void**)&pProvider); if (pProvider) { CComPtr pBitmap; if (SUCCEEDED(pProvider->GetBitmap(info.size,100,1,&pBitmap)) && pBitmap) { pBitmap->Detach(&info.bitmap); } } } } if (msg->wParam==MSG_SHIFTWIN) { if (GetWinVersion()==WIN_VER_WIN8) { HMONITOR monitor=(HMONITOR)msg->lParam; if (monitor) { CComPtr pMonitorService; IUnknown_QueryService(pSite,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService); if (pMonitorService) { CComPtr pMonitor; pMonitorService->GetFromHandle(monitor,&pMonitor); if (pMonitor) pMonitorService->SetImmersiveMonitor(pMonitor); } } CComPtr pLauncher; IUnknown_QueryService(pSite,SID_ImmersiveLauncher,IID_IImmersiveLauncher80,(void**)&pLauncher); if (pLauncher) pLauncher->ShowStartView(5); } } } } } } if (msg->wParam==MSG_METROTHUMBNAIL) { // set the event no matter if successful StartScreenThumbInfo &info=*(StartScreenThumbInfo*)msg->lParam; SetEvent(info.event); } } int corner; if ((msg->message==WM_MOUSEMOVE || msg->message==WM_LBUTTONDOWN) && (corner=GetSettingInt(L"DisableHotCorner"))>0) { { // ignore the mouse messages if there is a menu GUITHREADINFO info={sizeof(info)}; if (GetGUIThreadInfo(GetCurrentThreadId(),&info) && (info.flags&GUI_INMENUMODE)) return CallNextHookEx(NULL,code,wParam,lParam); } CPoint pt(GetMessagePos()); HMONITOR monitor=MonitorFromPoint(pt,MONITOR_DEFAULTTONEAREST); if (GetMetroMode(monitor)!=METRO_NONE) { if (!IsWin81Update1()) return CallNextHookEx(NULL,code,wParam,lParam); typedef BOOL (WINAPI *tGetWindowBand)(HWND,DWORD*); static tGetWindowBand GetWindowBand=(tGetWindowBand)GetProcAddress(GetModuleHandle(L"user32.dll"),"GetWindowBand"); for (id_taskbar_map::const_iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it) { DWORD band; if (!GetWindowBand || !GetWindowBand(it->second.taskBar,&band) || band==1) continue; UINT uEdge=GetTaskbarPosition(it->second.taskBar,NULL,NULL,NULL); if (uEdge!=ABE_BOTTOM) continue; // check if the mouse is over the taskbar RECT taskRect; GetWindowRect(it->second.taskBar,&taskRect); if (PtInRect(&taskRect,pt)) { POINT pt2=pt; ScreenToClient(it->second.taskBar,&pt2); if (pt2.x<32) { if (msg->message==WM_LBUTTONDOWN) { // forward the mouse click to the taskbar PostMessage(it->second.taskBar,WM_NCLBUTTONDOWN,MK_LBUTTON,MAKELONG(pt.x,pt.y)); msg->message=WM_NULL; } wchar_t className[256]={0}; GetClassName(msg->hwnd,className,_countof(className)); if (wcscmp(className,L"ImmersiveSwitchList")==0) { // suppress the opening of the ImmersiveSwitchList msg->message=WM_NULL; ShowWindow(msg->hwnd,SW_HIDE); // hide the popup } if (wcscmp(className,L"EdgeUiInputWndClass")==0) { // suppress the hot corners msg->message=WM_NULL; } } break; } } return CallNextHookEx(NULL,code,wParam,lParam); } if (corner==1) { for (id_taskbar_map::const_iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it) { UINT uEdge=GetTaskbarPosition(it->second.taskBar,NULL,NULL,NULL); if (uEdge==ABE_BOTTOM) { // check if the mouse is over the taskbar RECT taskRect; GetWindowRect(it->second.taskBar,&taskRect); if (PtInRect(&taskRect,pt)) { POINT pt2=pt; ScreenToClient(it->second.taskBar,&pt2); if (pt2.x<32) { corner=2; if (msg->message==WM_LBUTTONDOWN) { // forward the mouse click to the taskbar PostMessage(it->second.taskBar,WM_NCLBUTTONDOWN,MK_LBUTTON,MAKELONG(pt.x,pt.y)); msg->message=WM_NULL; } wchar_t className[256]={0}; GetClassName(msg->hwnd,className,_countof(className)); if (wcscmp(className,L"ImmersiveSwitchList")==0) { // suppress the opening of the ImmersiveSwitchList msg->message=WM_NULL; ShowWindow(msg->hwnd,SW_HIDE); // hide the popup } } break; } } } } if (corner==2) { wchar_t className[256]={0}; GetClassName(msg->hwnd,className,_countof(className)); if (wcscmp(className,L"EdgeUiInputWndClass")==0) { // suppress the hot corners msg->message=WM_NULL; ShowWindow(msg->hwnd,SW_HIDE); g_EdgeWindows.insert(msg->hwnd); } } } } return CallNextHookEx(NULL,code,wParam,lParam); } static LRESULT CALLBACK HookNewWindow( int code, WPARAM wParam, LPARAM lParam ) { if (code==HCBT_CREATEWND) { CBT_CREATEWND *pCreate=(CBT_CREATEWND*)lParam; if (pCreate->lpcs->lpszClass>(LPTSTR)0xFFFF && (_wcsicmp(pCreate->lpcs->lpszClass,L"Shell_SecondaryTrayWnd")==0 || _wcsicmp(pCreate->lpcs->lpszClass,L"ToolbarWindow32")==0 || _wcsicmp(pCreate->lpcs->lpszClass,L"TrayClockWClass")==0 || _wcsicmp(pCreate->lpcs->lpszClass,L"ClockButton")==0)) PostMessage(g_TaskBar,g_StartMenuMsg,MSG_NEWTASKBAR,wParam); } return CallNextHookEx(NULL,code,wParam,lParam); } // Set the hotkeys and controls for the start menu void EnableHotkeys( THotkeys enable ) { if (g_bTrimHooks) return; if (!g_TaskBar) return; if (GetWindowThreadProcessId(g_TaskBar,NULL)!=GetCurrentThreadId()) { PostMessage(g_TaskBar,g_StartMenuMsg,MSG_HOTKEYS,enable); return; } // must be executed in the same thread as the start button (otherwise RegisterHotKey doesn't work). also prevents race conditions bool bHook=(enable==HOTKEYS_SETTINGS || (enable==HOTKEYS_NORMAL && GetSettingInt(L"ShiftWin")!=0)); if (bHook) { RegisterHotKey(g_TaskBar,g_HotkeyShiftID,MOD_SHIFT|MOD_WIN,0); g_bHotkeyShift=true; } else if (g_bHotkeyShift) { UnregisterHotKey(g_TaskBar,g_HotkeyShiftID); g_bHotkeyShift=false; } if (g_HotkeyCSM) UnregisterHotKey(g_TaskBar,g_HotkeyCSMID); g_HotkeyCSM=0; if (g_HotkeyWSM) UnregisterHotKey(g_TaskBar,g_HotkeyWSMID); g_HotkeyWSM=0; if (enable==HOTKEYS_NORMAL) { g_HotkeyCSM=GetSettingInt(L"CSMHotkey"); if (g_HotkeyCSM) { int mod=MOD_NOREPEAT; if (g_HotkeyCSM&(HOTKEYF_SHIFT<<8)) mod|=MOD_SHIFT; if (g_HotkeyCSM&(HOTKEYF_CONTROL<<8)) mod|=MOD_CONTROL; if (g_HotkeyCSM&(HOTKEYF_ALT<<8)) mod|=MOD_ALT; RegisterHotKey(g_TaskBar,g_HotkeyCSMID,mod,g_HotkeyCSM&255); } g_HotkeyWSM=GetSettingInt(L"WSMHotkey"); if (g_HotkeyWSM) { int mod=MOD_NOREPEAT; if (g_HotkeyWSM&(HOTKEYF_SHIFT<<8)) mod|=MOD_SHIFT; if (g_HotkeyWSM&(HOTKEYF_CONTROL<<8)) mod|=MOD_CONTROL; if (g_HotkeyWSM&(HOTKEYF_ALT<<8)) mod|=MOD_ALT; RegisterHotKey(g_TaskBar,g_HotkeyWSMID,mod,g_HotkeyWSM&255); } } } static void UpdateStartButtonPosition(const TaskbarInfo* taskBar, const WINDOWPOS* pPos) { if (IsStartButtonSmallIcons(taskBar->taskbarId) != IsTaskbarSmallIcons()) RecreateStartButton(taskBar->taskbarId); RECT rcTask; GetWindowRect(taskBar->taskBar, &rcTask); MONITORINFO info; UINT uEdge = GetTaskbarPosition(taskBar->taskBar, &info, NULL, NULL); DWORD buttonFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE; if (IsWindowVisible(taskBar->taskBar)) buttonFlags |= SWP_SHOWWINDOW; else buttonFlags |= SWP_HIDEWINDOW; APPBARDATA appbar = { sizeof(appbar) }; if (SHAppBarMessage(ABM_GETSTATE, &appbar) & ABS_AUTOHIDE) { bool bHide = false; if (uEdge == ABE_LEFT) bHide = (rcTask.right < info.rcMonitor.left + 5); else if (uEdge == ABE_RIGHT) bHide = (rcTask.left > info.rcMonitor.right - 5); else if (uEdge == ABE_TOP) bHide = (rcTask.bottom < info.rcMonitor.top + 5); else bHide = (rcTask.top > info.rcMonitor.bottom - 5); if (bHide) buttonFlags = (buttonFlags & ~SWP_SHOWWINDOW) | SWP_HIDEWINDOW; } if (uEdge == ABE_TOP || uEdge == ABE_BOTTOM) { if (rcTask.left < info.rcMonitor.left) rcTask.left = info.rcMonitor.left; if (rcTask.right > info.rcMonitor.right) rcTask.right = info.rcMonitor.right; } else { if (rcTask.top < info.rcMonitor.top) rcTask.top = info.rcMonitor.top; } HWND zPos = NULL; if (pPos->flags & SWP_NOZORDER) buttonFlags |= SWP_NOZORDER; else { zPos = pPos->hwndInsertAfter; if (zPos == HWND_TOP && !(GetWindowLongPtr(taskBar->startButton, GWL_EXSTYLE) & WS_EX_TOPMOST)) zPos = HWND_TOPMOST; if (zPos == HWND_TOPMOST && !(GetWindowLongPtr(taskBar->taskBar, GWL_EXSTYLE) & WS_EX_TOPMOST)) zPos = HWND_TOP; if (zPos == HWND_BOTTOM) buttonFlags |= SWP_NOZORDER; if (zPos == taskBar->startButton) buttonFlags |= SWP_NOZORDER; } if (!IsStartButtonSmallIcons(taskBar->taskbarId)) { bool bClassic; if (GetWinVersion() < WIN_VER_WIN8) bClassic = !IsAppThemed(); else { HIGHCONTRAST contrast = { sizeof(contrast) }; bClassic = (SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(contrast), &contrast, 0) && (contrast.dwFlags & HCF_HIGHCONTRASTON)); } if (!bClassic) { if (uEdge == ABE_TOP) OffsetRect(&rcTask, 0, -1); else if (uEdge == ABE_BOTTOM) OffsetRect(&rcTask, 0, 1); } } RECT rcOldButton; if (taskBar->oldButton) GetWindowRect(taskBar->oldButton, &rcOldButton); int x, y; if (uEdge == ABE_LEFT || uEdge == ABE_RIGHT) { if (GetSettingInt(L"StartButtonType") != START_BUTTON_CUSTOM || !GetSettingBool(L"StartButtonAlign")) x = (rcTask.left + rcTask.right - taskBar->startButtonSize.cx) / 2; else if (uEdge == ABE_LEFT) x = rcTask.left; else x = rcTask.right - taskBar->startButtonSize.cx; y = taskBar->oldButton ? rcOldButton.top : rcTask.top; } else { if (GetWindowLongPtr(taskBar->rebar, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) x = (taskBar->oldButton ? rcOldButton.right : rcTask.right) - taskBar->startButtonSize.cx; else x = taskBar->oldButton ? rcOldButton.left : rcTask.left; if (GetSettingInt(L"StartButtonType") != START_BUTTON_CUSTOM || !GetSettingBool(L"StartButtonAlign")) y = (rcTask.top + rcTask.bottom - taskBar->startButtonSize.cy) / 2; else if (uEdge == ABE_TOP) y = rcTask.top; else y = rcTask.bottom - taskBar->startButtonSize.cy; // Start button on Win11 is a bit shifted to the right // We will shift our Aero button to cover original button if (IsWin11() && (x == info.rcMonitor.left) && (GetStartButtonType() == START_BUTTON_AERO)) x += ScaleForDpi(taskBar->taskBar, 6); } RECT rcButton = { x, y, x + taskBar->startButtonSize.cx, y + taskBar->startButtonSize.cy }; RECT rc; IntersectRect(&rc, &rcButton, &info.rcMonitor); HRGN rgn = CreateRectRgn(rc.left - x, rc.top - y, rc.right - x, rc.bottom - y); if (!SetWindowRgn(taskBar->startButton, rgn, FALSE)) { AddTrackedObject(rgn); DeleteObject(rgn); } SetWindowPos(taskBar->startButton, zPos, x, y, 0, 0, buttonFlags); if (buttonFlags & SWP_SHOWWINDOW) UpdateStartButton(taskBar->taskbarId); } static LRESULT CALLBACK SubclassWin81StartButton( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { TaskbarInfo* taskBar = GetTaskbarInfo((int)dwRefData); if (uMsg==WM_WINDOWPOSCHANGING) { // keep the original start button hidden at all times if (taskBar && taskBar->bHideButton) { ((WINDOWPOS*)lParam)->flags&=~SWP_SHOWWINDOW; } } if (uMsg==WM_WINDOWPOSCHANGED) { if (taskBar && taskBar->bReplaceButton) { UpdateStartButtonPosition(taskBar,(WINDOWPOS*)lParam); } } if (uMsg==WM_SIZE) { RECT rc; GetWindowRect(hWnd,&rc); rc.right-=rc.left; rc.bottom-=rc.top; if (taskBar && (taskBar->oldButtonSize.cx!=rc.right || taskBar->oldButtonSize.cy!=rc.bottom)) { taskBar->oldButtonSize.cx=rc.right; taskBar->oldButtonSize.cy=rc.bottom; RECT rcTask; GetWindowRect(taskBar->taskBar,&rcTask); PostMessage(taskBar->taskBar,WM_SIZE,SIZE_RESTORED,MAKELONG(rcTask.right-rcTask.left,rcTask.bottom-rcTask.top)); } } if (uMsg==WM_POINTERACTIVATE && CMenuContainer::IsMenuOpened()) return MA_NOACTIVATE; #ifdef START_TOUCH if (uMsg==WM_POINTERUP || uMsg==WM_POINTERUPDATE || uMsg==WM_POINTERUP) { POINTER_INPUT_TYPE type; GetPointerType2(GET_POINTERID_WPARAM(wParam),&type); if (type==PT_TOUCH) { return SendMessage(GetParent(hWnd),uMsg,wParam,lParam); } } #endif if (uMsg==WM_PAINT && GetWinVersion()>=WIN_VER_WIN10) { g_CurrentTaskbarButton=hWnd; LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam); g_CurrentTaskbarButton=NULL; return res; } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } static bool g_bSuppressMessage243; static LRESULT CALLBACK SubclassWin7StartButton( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==243 && g_bSuppressMessage243) { // HACK: if the start button is smaller than the original, some NC clicks on the taskbar may be interpreted as clicks on the start button and open the WSM // This is prevented by suppressing message 243 while processing WM_NCLBUTTONDOWN on the taskbar return 0; } if (uMsg==WM_WINDOWPOSCHANGING) { // keep the Win7 start button hidden at all times ((WINDOWPOS*)lParam)->flags&=~SWP_SHOWWINDOW; } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } static LRESULT CALLBACK SubclassUserPicProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_WINDOWPOSCHANGING && !(((WINDOWPOS*)lParam)->flags&SWP_NOMOVE)) { if (GetSettingBool(L"HideUserPic")) { ((WINDOWPOS*)lParam)->x=-32000; ((WINDOWPOS*)lParam)->y=-32000; } } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } static LRESULT CALLBACK SubclassTopMenuProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_ACTIVATE && GetSettingBool(L"CascadeAll")) { if (!wParam) { if (CMenuContainer::s_bPreventClosing) return 0; // check if another menu window is being activated // if not, close all menus for (std::vector::const_iterator it=CMenuContainer::s_Menus.begin();it!=CMenuContainer::s_Menus.end();++it) if ((*it)->m_hWnd==(HWND)lParam) return 0; } } if (uMsg==WM_WINDOWPOSCHANGED && (((WINDOWPOS*)lParam)->flags&SWP_SHOWWINDOW)) { g_LastHoverPos=GetMessagePos(); if (g_ProgramsButton && GetSettingInt(L"InitiallySelect")==1) PostMessage(hWnd,WM_CLEAR,'CLSH',0); g_CurrentWSMTaskbar=MAIN_TASK_BAR; PressStartButton(MAIN_TASK_BAR,true); } if (uMsg==WM_CLEAR && wParam=='CLSH' && g_ProgramsButton) { SetFocus(g_ProgramsButton); return 0; } if (uMsg==WM_SHOWWINDOW) { if (!wParam) { CMenuContainer::CloseProgramsMenu(); g_CurrentWSMTaskbar=-1; PressStartButton(MAIN_TASK_BAR,false); } g_bAllProgramsTimer=false; if (g_ProgramsButton) KillTimer(g_ProgramsButton,'CLSM'); } if (uMsg==WM_DESTROY) g_TopWin7Menu=NULL; if (uMsg==WM_ACTIVATEAPP && !wParam) { if (CMenuContainer::s_bPreventClosing) return 0; } if (uMsg==WM_MOUSEACTIVATE && GetSettingBool(L"CascadeAll") && CMenuContainer::IsMenuOpened()) { CPoint pt(GetMessagePos()); if (g_ProgramsButton && WindowFromPoint(pt)==g_ProgramsButton) return MA_NOACTIVATEANDEAT; CMenuContainer::CloseProgramsMenu(); return MA_ACTIVATEANDEAT; } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } static LRESULT CALLBACK SubclassProgramsProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_COMMAND && wParam==IDOK && GetSettingBool(L"CascadeAll")) { if (GetKeyState(VK_SHIFT)<0) { if (CMenuContainer::IsMenuOpened()) return 0; // ignore shift+click when the menu is opened } else { if (!CMenuContainer::IsMenuOpened()) CMenuContainer::ToggleStartMenu(MAIN_TASK_BAR,GetKeyState(VK_SPACE)<0 || GetKeyState(VK_RETURN)<0 || GetKeyState(VK_LEFT)<0 || GetKeyState(VK_RIGHT)<0,true); return 0; } } if (uMsg==WM_DRAWITEM && wParam==IDOK && CMenuContainer::IsMenuOpened()) { DRAWITEMSTRUCT *pDraw=(DRAWITEMSTRUCT*)lParam; pDraw->itemState=ODS_HOTLIGHT; // draw highlighted when the menu is open } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } static BOOL CALLBACK FindWindowsMenuProc( HWND hwnd, LPARAM lParam ) { wchar_t name[100]; GetClassName(hwnd,name,_countof(name)); if (_wcsicmp(name,L"DV2ControlHost")==0) { HWND w1=hwnd; if (GetWinVersion()==WIN_VER_VISTA) { w1=FindWindowEx(w1,NULL,L"Desktop Open Pane Host",NULL); if (!w1) return TRUE; } w1=FindWindowEx(w1,NULL,L"Desktop More Programs Pane",NULL); if (!w1) return TRUE; g_TopWin7Menu=hwnd; g_AllPrograms=w1; g_ProgramsButton=GetDlgItem(w1,IDOK); // this may not exist return FALSE; } return TRUE; } static void FindWindowsMenu( void ) { if (g_TopWin7Menu) return; if (GetWinVersion()=rcPaint.bottom) break; for (int x=0;x=rcPaint.right) break; MarginsBlit(hsrc,hdc,rSrc,rDst,g_TaskbarMargins,true); } } SelectObject(hsrc,bmp0); DeleteDC(hsrc); } static void ComputeTaskbarColors( int *data ) { bool bDefLook; int look=GetSettingInt(L"TaskbarLook",bDefLook); if (GetWinVersion()255) a=255; bool bDefColor; DWORD color=GetSettingInt(L"TaskbarColor",bDefColor); if (bDefColor) color=color0; data[2]=(color&0xFFFFFF)|(a<<24); } data[3]=0; } static void ShowWinX( void ) { if (IsWin11()) { HWND hwnd=FindWindowEx(NULL,NULL,L"Shell_TrayWnd",NULL); if (hwnd) PostMessage(hwnd,WM_HOTKEY,590,MAKELPARAM(MOD_WIN,'X')); return; } if (GetWinVersion()>=WIN_VER_WIN10) { CComPtr pImmersiveShell; if (CreateImmersiveShell(pImmersiveShell)) { CComPtr pMonitorService; IUnknown_QueryService(pImmersiveShell,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService); if (pMonitorService) { CPoint pt(GetMessagePos()); HMONITOR monitor=MonitorFromPoint(pt,MONITOR_DEFAULTTONEAREST); CComPtr pMonitor; pMonitorService->GetFromHandle(monitor,&pMonitor); if (pMonitorService) { CComPtr pMenu; IUnknown_QueryService(pMonitor,SID_LauncherTipContextMenu,SID_LauncherTipContextMenu,(void**)&pMenu); if (pMenu) pMenu->ShowLauncherTipContextMenu(&pt); } } } } else if (g_AppManagerThread) PostThreadMessage(g_AppManagerThread,g_StartMenuMsg,MSG_WINXMENU,GetMessagePos()); } static LRESULT CALLBACK SubclassTrayButtonProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_WINDOWPOSCHANGING) { const TaskbarInfo *taskBar=GetTaskbarInfo((int)dwRefData); if (taskBar && (taskBar->bReplaceButton || taskBar->bHideButton)) { WINDOWPOS *pPos=(WINDOWPOS*)lParam; if (!(pPos->flags&SWP_NOMOVE) || !(pPos->flags&SWP_NOSIZE)) { if (pPos->flags&(SWP_NOMOVE|SWP_NOSIZE)) { RECT rc; GetWindowRect(hWnd,&rc); MapWindowPoints(NULL,GetParent(hWnd),(POINT*)&rc,2); if (pPos->flags&SWP_NOMOVE) { pPos->x=rc.left; pPos->y=rc.top; } else { pPos->cx=rc.right-rc.left; pPos->cy=rc.bottom-rc.top; } } int dx=0, dy=0; UINT uEdge=GetTaskbarPosition(taskBar->taskBar,NULL,NULL,NULL); if (uEdge==ABE_LEFT || uEdge==ABE_RIGHT) { dy=taskBar->startButtonSize.cy-taskBar->oldButtonSize.cy; } else { dx=taskBar->startButtonSize.cx-taskBar->oldButtonSize.cx; } if (dx || dy) { pPos->x+=dx; pPos->y+=dy; pPos->flags&=~(SWP_NOMOVE); } } } } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } static LRESULT CALLBACK SubclassTaskBarProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_MOUSEACTIVATE && (HIWORD(lParam)==WM_MBUTTONDOWN || GetWinVersion()>=WIN_VER_WIN10)) { if (GetWinVersion()>=WIN_VER_WIN10 && CMenuContainer::IsMenuOpened() && CMenuContainer::HasInputHandler() && GetFocus()) { // Win10: if the taskbar is clicked while the menu is opened, check if the touch keyboard button was clicked and ignore the activation // Otherwise the click on the touch keyboard button will deactivate the menu (possibly because both run on the same thread) // On Win8.1 the button already handles this and returns MA_NOACTIVATE HWND hwnd=WindowFromPoint(CPoint(GetMessagePos())); if (hwnd) { wchar_t className[256]; GetClassName(hwnd,className,_countof(className)); if (_wcsicmp(className,L"TIPBand")==0) return MA_NOACTIVATE; } } FindWindowsMenu(); if (g_TopWin7Menu && WindowsMenuOpened()) { DefSubclassProc(hWnd,uMsg,wParam,lParam); return MA_ACTIVATEANDEAT; // ignore the next middle click, so it doesn't re-open the start menu } } TaskbarInfo *taskBar=GetTaskbarInfo((int)dwRefData); if (taskBar && (uMsg==WM_NCMOUSEMOVE || uMsg==WM_MOUSEMOVE) && PointAroundStartButton((int)dwRefData)) TaskBarMouseMove(taskBar->taskbarId); if (taskBar && uMsg==WM_POINTERACTIVATE && CMenuContainer::IsMenuOpened()) return MA_NOACTIVATE; static int touchTime; #ifdef START_TOUCH if (taskBar && (uMsg==WM_NCPOINTERDOWN || (uMsg==WM_POINTERDOWN && IS_POINTER_INCONTACT_WPARAM(wParam) && IS_POINTER_PRIMARY_WPARAM(wParam) && IS_POINTER_FIRSTBUTTON_WPARAM(wParam)))) { POINTER_INPUT_TYPE type; GetPointerType2(GET_POINTERID_WPARAM(wParam),&type); if (type==PT_TOUCH) { if (PointAroundStartButton((int)dwRefData,CPoint(lParam))) { taskBar->pointerId=GET_POINTERID_WPARAM(wParam); touchTime=GetMessageTime(); return 0; } } } if (taskBar && (uMsg==WM_NCPOINTERUPDATE || uMsg==WM_POINTERUPDATE) && taskBar->pointerId==GET_POINTERID_WPARAM(wParam)) { if (uMsg==WM_NCPOINTERUPDATE) { POINTER_INFO info; if (GetPointerInfo2(taskBar->pointerId,&info) && (info.pointerFlags&4)!=0) { int time=GetMessageTime(); if (time-touchTime>500) { taskBar->pointerId=0; ShowWinX(); return 0; } } } else if (IS_POINTER_INCONTACT_WPARAM(wParam)) { int time=GetMessageTime(); if (time-touchTime>500) { taskBar->pointerId=0; PostMessage(taskBar->startButton,WM_RBUTTONUP,0,MAKELPARAM(-1,-1)); return 0; } } else uMsg=WM_POINTERUP; } if (taskBar && (uMsg==WM_POINTERUP || uMsg==WM_NCPOINTERUP) && taskBar->pointerId==GET_POINTERID_WPARAM(wParam)) { if (PointAroundStartButton((int)dwRefData,CPoint(lParam))) { int control=GetSettingInt(L"MouseClick"); if (control==OPEN_BOTH && GetWinVersion()>=WIN_VER_WIN10) control=GetWin10TabletMode()?OPEN_WINDOWS:OPEN_CLASSIC; if (control==OPEN_CLASSIC) ToggleStartMenu(taskBar->taskbarId,false); else if (control==OPEN_WINDOWS) PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMM'); } taskBar->pointerId=0; return 0; } #endif if (uMsg==WM_SHOWWINDOW && taskBar) { if (taskBar->bReplaceButton) ShowWindow(taskBar->startButton,wParam?SW_SHOW:SW_HIDE); } if (uMsg==WM_WINDOWPOSCHANGING && taskBar && taskBar->bReplaceButton) { WINDOWPOS *pPos=(WINDOWPOS*)lParam; if (!(pPos->flags&SWP_NOZORDER) && pPos->hwndInsertAfter==HWND_BOTTOM) { SetWindowPos(taskBar->startButton,HWND_BOTTOM,0,0,0,0,SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOMOVE); pPos->hwndInsertAfter=taskBar->startButton; } } if (uMsg==WM_WINDOWPOSCHANGED && taskBar) { if (taskBar->bReplaceButton) { UpdateStartButtonPosition(taskBar,(WINDOWPOS*)lParam); } if (taskBar->oldButton && GetWinVersion()oldButton,NULL,x,0,0,0,SWP_NOSIZE|SWP_NOZORDER); } } if (uMsg==WM_THEMECHANGED && taskBar) { if (taskBar->bReplaceButton) { RecreateStartButton((int)dwRefData); } taskBar->bThemeChanging=true; LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam); taskBar->bThemeChanging=false; return res; } if ((uMsg==WM_DWMCOLORIZATIONCOLORCHANGED || uMsg==WM_SETTINGCHANGE || uMsg==0x5CB || uMsg==0x5BB) && taskBar && taskBar->bCustomLook && SetWindowCompositionAttribute && GetWinVersion()>=WIN_VER_WIN10) { LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam); int data[4]; ComputeTaskbarColors(data); WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)}; SetWindowCompositionAttribute(hWnd,&attrData); return res; } if ((uMsg==WM_DWMCOLORIZATIONCOLORCHANGED || uMsg==WM_SETTINGCHANGE) && taskBar && taskBar->bCustomLook && SetWindowCompositionAttribute && GetWinVersion()bCustomLook) { TTaskbarLook look=(TTaskbarLook)GetSettingInt(L"TaskbarLook"); WORD winVer=GetWinVersion(); BOOL blurBehind; int margin; enum { FLAG_BLUR=1, FLAG_MARGIN=2, FLAG_ATTRIBUTE=4}; int flags=0; if (winVer==WIN_VER_WIN7) { blurBehind=look==TASKBAR_GLASS; margin=look==TASKBAR_OPAQUE?0:-1; flags=FLAG_BLUR|FLAG_MARGIN; } else if (winVer==WIN_VER_WIN8) { blurBehind=look==TASKBAR_OPAQUE; margin=look==TASKBAR_OPAQUE?0:-1; flags=FLAG_BLUR|FLAG_MARGIN|((look==TASKBAR_TRANSPARENT && g_TaskbarTexture)?FLAG_ATTRIBUTE:0); } else if (winVer==WIN_VER_WIN81) { blurBehind=look==TASKBAR_OPAQUE; margin=look==TASKBAR_OPAQUE?0:-1; flags=FLAG_BLUR|FLAG_MARGIN|((look==TASKBAR_OPAQUE || g_TaskbarTexture)?FLAG_ATTRIBUTE:0); } else if (winVer>=WIN_VER_WIN10) { blurBehind=TRUE; margin=look==TASKBAR_OPAQUE?0:-1; flags=(look==TASKBAR_AEROGLASS?FLAG_BLUR:0)|(look!=TASKBAR_GLASS?FLAG_MARGIN:0)|FLAG_ATTRIBUTE; } if (flags&FLAG_BLUR) { DWM_BLURBEHIND blur={DWM_BB_ENABLE,blurBehind}; DwmEnableBlurBehindWindow(hWnd,&blur); } if (flags&FLAG_MARGIN) { MARGINS margins={margin}; DwmExtendFrameIntoClientArea(hWnd,&margins); } if (SetWindowCompositionAttribute && (flags&FLAG_ATTRIBUTE)) { int data[4]; ComputeTaskbarColors(data); WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)}; SetWindowCompositionAttribute(hWnd,&attrData); } if (g_TaskbarTexture && IsAppThemed()) { // draw taskbar background (behind start button and separators) PAINTSTRUCT ps; HDC hdc=BeginPaint(hWnd,&ps); RECT rc; GetClientRect(hWnd,&rc); UINT uEdge=GetTaskbarPosition(hWnd,NULL,NULL,NULL); PrintTaskbarBackground(hdc,rc,ps.rcPaint,uEdge); EndPaint(hWnd,&ps); return 0; } } if (taskBar->bReplaceButton && g_WinStartButton && !IsAppThemed()) { // prevent painting of the default classic button PAINTSTRUCT ps; HDC hdc=BeginPaint(hWnd,&ps); EndPaint(hWnd,&ps); return 0; } } if (uMsg==WM_PRINTCLIENT && g_TaskbarTexture) { // print taskbar background - for background of buttons and tray area HDC hdc=(HDC)wParam; RECT rc; GetClientRect(hWnd,&rc); UINT uEdge=GetTaskbarPosition(hWnd,NULL,NULL,NULL); PrintTaskbarBackground(hdc,rc,rc,uEdge); return 0; } if (uMsg==0x5C5 && taskBar && taskBar->bCustomLook && IsWin81Update1()) // some secret message when the taskbar is raised to the top { // reset the opaqueness PostMessage(g_TaskBar,g_StartMenuMsg,MSG_REDRAWTASKBAR,(LPARAM)hWnd); } if (uMsg==WM_DESTROY && taskBar) { if (taskBar->bReplaceButton) DestroyStartButton(taskBar->taskbarId); g_TaskbarInfos.erase(g_TaskbarInfos.find(taskBar->taskbarId)); } if (uMsg==WM_TIMER && wParam=='CLSM') { if (GetMetroMode(NULL)==METRO_NONE) { KillTimer(hWnd,'CLSM'); return 0; } SetForegroundWindow(hWnd); LogToFile(STARTUP_LOG,L"StartMenu DLL: skipping Metro"); if (GetSettingInt(L"SkipMetroCount")<0) { INPUT inputs[4]={ {INPUT_KEYBOARD}, {INPUT_KEYBOARD}, {INPUT_KEYBOARD}, {INPUT_KEYBOARD}, }; inputs[0].ki.wVk=VK_LWIN; inputs[1].ki.wVk='D'; inputs[2].ki.wVk='D'; inputs[2].ki.dwFlags=KEYEVENTF_KEYUP; inputs[3].ki.wVk=VK_LWIN; inputs[3].ki.dwFlags=KEYEVENTF_KEYUP; SendInput(_countof(inputs),inputs,sizeof(INPUT)); } else { HWND hwnd=FindWindow(L"ModeInputWnd",NULL); if (hwnd) { DWORD process; GetWindowThreadProcessId(hwnd,&process); if (process==GetCurrentProcessId()) { IObjectWithSite *pObject=(IObjectWithSite*)GetWindowLongPtr(hwnd,0); if (pObject) { CComPtr pSite; pObject->GetSite(IID_IUnknown,(void**)&pSite); if (pSite) { CComPtr pLauncher; IUnknown_QueryService(pSite,SID_ImmersiveLauncher,IID_IImmersiveLauncher80,(void**)&pLauncher); if (pLauncher) pLauncher->Dismiss(5); } } } } } g_SkipMetroCount--; if (g_SkipMetroCount<=0) KillTimer(hWnd,'CLSM'); return 0; } if (uMsg==WM_MOVE) { ResetHotCorners(); } if (uMsg==WM_NCLBUTTONDOWN && taskBar && GetWinVersion()==WIN_VER_WIN7 && taskBar->bReplaceButton) { g_bSuppressMessage243=true; LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam); g_bSuppressMessage243=false; return res; } if (uMsg==WM_PARENTNOTIFY && taskBar && LOWORD(wParam)==WM_CREATE && GetWinVersion()>=WIN_VER_WIN10) { wchar_t name[100]; HWND child=(HWND)lParam; GetClassName(child,name,_countof(name)); if (_wcsicmp(name,L"TrayButton")==0 && GetParent(child)==hWnd) { bool bFound=false; for (std::vector::const_iterator it=taskBar->trayButtons.begin();it!=taskBar->trayButtons.end();++it) if (*it==child) { bFound=true; break; } if (!bFound) { taskBar->trayButtons.push_back(child); SetWindowSubclass(child,SubclassTrayButtonProc,'CLSH',taskBar->taskbarId); } } } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } static LRESULT CALLBACK SubclassTaskListProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_PAINT && g_TaskbarTexture) { wchar_t name[100]; GetClassName(hWnd,name,_countof(name)); if (_wcsicmp(name,L"MSTaskSwWClass")==0) { // draw taskbar background (behind task list) PAINTSTRUCT ps; HDC hdc=BeginPaint(hWnd,&ps); DrawThemeParentBackground(hWnd,hdc,NULL); EndPaint(hWnd,&ps); return 0; } } if (uMsg==WM_PAINT || uMsg==WM_PRINT || uMsg==WM_PRINTCLIENT) { g_CurrentTaskList=hWnd; LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam); g_CurrentTaskList=NULL; return res; } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } static LRESULT CALLBACK SubclassTrayChevronProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_PAINT || uMsg==WM_PRINT || uMsg==WM_PRINTCLIENT) { g_CurrentTaskChevron=hWnd; LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam); g_CurrentTaskChevron=NULL; return res; } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } static LRESULT CALLBACK SubclassDesktopButtonProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_PAINT || uMsg==WM_PRINT || uMsg==WM_PRINTCLIENT) { g_CurrentDesktopButton=hWnd; LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam); g_CurrentDesktopButton=NULL; return res; } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } static LRESULT CALLBACK SubclassRebarProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_WINDOWPOSCHANGING) { const TaskbarInfo *taskBar=GetTaskbarInfo((int)dwRefData); if (taskBar && (taskBar->bReplaceButton || taskBar->bHideButton)) { WINDOWPOS *pPos=(WINDOWPOS*)lParam; if (!(pPos->flags&SWP_NOMOVE) || !(pPos->flags&SWP_NOSIZE)) { if (pPos->flags&(SWP_NOMOVE|SWP_NOSIZE)) { RECT rc; GetWindowRect(hWnd,&rc); MapWindowPoints(NULL,GetParent(hWnd),(POINT*)&rc,2); if (pPos->flags&SWP_NOMOVE) { pPos->x=rc.left; pPos->y=rc.top; } else { pPos->cx=rc.right-rc.left; pPos->cy=rc.bottom-rc.top; } } int dx=0, dy=0; UINT uEdge=GetTaskbarPosition(taskBar->taskBar,NULL,NULL,NULL); if (taskBar->oldButton) { if (uEdge==ABE_LEFT || uEdge==ABE_RIGHT) { dy=taskBar->startButtonSize.cy-taskBar->oldButtonSize.cy; } else { dx=taskBar->startButtonSize.cx-taskBar->oldButtonSize.cx; } } else { if (uEdge==ABE_LEFT || uEdge==ABE_RIGHT) { dy=taskBar->startButtonSize.cy-pPos->y; } else { dx=taskBar->startButtonSize.cx-pPos->x; } } if (dx || dy) { pPos->x+=dx; pPos->cx-=dx; pPos->y+=dy; pPos->cy-=dy; pPos->flags&=~(SWP_NOMOVE|SWP_NOSIZE); } } } } if (uMsg==WM_PAINT || uMsg==WM_PRINT || uMsg==WM_PRINTCLIENT) { g_CurrentRebar=hWnd; LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam); g_CurrentRebar=NULL; return res; } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } static LRESULT CALLBACK SubclassTaskbarPartProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_PAINT || uMsg==WM_PRINT || uMsg==WM_PRINTCLIENT) { g_CurrentTaskbarPart=hWnd; LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam); g_CurrentTaskbarPart=NULL; return res; } if (uMsg==WM_NCDESTROY) { TaskbarInfo *info=GetTaskbarInfo((int)dwRefData); if (info) { for (std::vector::const_iterator it=info->taskbarParts.begin();it!=info->taskbarParts.end();++it) if (*it==hWnd) { info->taskbarParts.erase(it); break; } } } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } static void HandleTaskbarParts( TaskbarInfo &taskBar, bool bPrimary ) { if (taskBar.rebar) { int count=(int)SendMessage(taskBar.rebar,RB_GETBANDCOUNT,0,0); for (int i=0;i=WIN_VER_WIN10) { HWND clock=FindWindowEx(taskBar.taskBar,NULL,L"ClockButton",NULL); if (clock && !taskBar.HasPart(clock)) { SetWindowSubclass(clock,SubclassTaskbarPartProc,'CLSH',taskBar.taskbarId); taskBar.taskbarParts.push_back(clock); } } } static void HandleSecondaryTaskbar( HWND hwnd ) { int taskbarId=g_NextTaskbar++; TaskbarInfo &taskBar=g_TaskbarInfos[taskbarId]; taskBar.taskBar=hwnd; taskBar.taskbarId=taskbarId; taskBar.rebar=FindWindowEx(hwnd,NULL,L"WorkerW",NULL); if (taskBar.rebar) { SetWindowSubclass(taskBar.rebar,SubclassRebarProc,'CLSH',taskbarId); taskBar.taskList=FindWindowEx(taskBar.rebar,NULL,L"MSTaskListWClass",NULL); if (taskBar.taskList) SetWindowSubclass(taskBar.taskList,SubclassTaskListProc,'CLSH',taskbarId); } if (GetWinVersion()>WIN_VER_WIN8) { taskBar.oldButton=FindWindowEx(taskBar.taskBar,NULL,L"Start",NULL); if (taskBar.oldButton) { if (GetWinVersion()>=WIN_VER_WIN10) { taskBar.pOriginalTarget=(IDropTarget*)GetProp(taskBar.oldButton,L"OleDropTargetInterface"); if (taskBar.pOriginalTarget) RevokeDragDrop(taskBar.oldButton); } CStartMenuTarget *pNewTarget=new CStartMenuTarget(taskBar.taskbarId); RegisterDragDrop(taskBar.oldButton,pNewTarget); pNewTarget->Release(); if (GetWinVersion()=WIN_VER_WIN10) { for (HWND button=FindWindowEx(taskBar.taskBar,NULL,L"TrayButton",NULL);button;button=FindWindowEx(taskBar.taskBar,button,L"TrayButton",NULL)) { taskBar.trayButtons.push_back(button); SetWindowSubclass(button,SubclassTrayButtonProc,'CLSH',taskBar.taskbarId); } HWND search=FindWindowEx(taskBar.taskBar,NULL,L"TrayDummySearchControl",NULL); if (search) { taskBar.trayButtons.push_back(search); SetWindowSubclass(search,SubclassTrayButtonProc,'CLSH',taskBar.taskbarId); } } HandleTaskbarParts(taskBar,false); SetWindowSubclass(taskBar.taskBar,SubclassTaskBarProc,'CLSH',taskbarId); UpdateTaskBars(TASKBAR_UPDATE); UpdateTaskBars(TASKBAR_UPDATE_TEXTURE); } static BOOL CALLBACK HookAllTaskbarsEnum( HWND hwnd, LPARAM lParam ) { // look for top-level windows with class "Shell_SecondaryTrayWnd" in the current thread if (GetWindowThreadProcessId(hwnd,NULL)!=GetCurrentThreadId()) return TRUE; wchar_t name[256]; GetClassName(hwnd,name,_countof(name)); if (_wcsicmp(name,L"Shell_SecondaryTrayWnd")==0) HandleSecondaryTaskbar(hwnd); return TRUE; } void UpdateTaskBars( TUpdateTaskbar update ) { if (update==TASKBAR_UPDATE_TEXTURE) { if (g_TaskbarTexture) DeleteObject(g_TaskbarTexture); g_TaskbarTexture=NULL; if (GetSettingBool(L"CustomTaskbar")) { g_TaskbarTileH=g_TaskbarTileV=TILE_STRETCH; g_TaskbarMargins.left=g_TaskbarMargins.right=g_TaskbarMargins.top=g_TaskbarMargins.bottom=0; TTaskbarLook look=(TTaskbarLook)GetSettingInt(L"TaskbarLook"); bool bDefOpacity; int opacity=GetSettingInt(L"TaskbarOpacity",bDefOpacity); if (look==TASKBAR_OPAQUE) opacity=100, bDefOpacity=true; bool bDefColor; COLORREF color=GetSettingInt(L"TaskbarColor",bDefColor); wchar_t fname[_MAX_PATH]; Strcpy(fname,_countof(fname),GetSettingString(L"TaskbarTexture")); DoEnvironmentSubst(fname,_countof(fname)); if (*fname) { g_TaskbarTexture=LoadImageResource(NULL,fname,false,true); g_TaskbarTileH=(TTaskbarTile)GetSettingInt(L"TaskbarTileH"); g_TaskbarTileV=(TTaskbarTile)GetSettingInt(L"TaskbarTileV"); if (g_TaskbarTileH==TILE_STRETCH) { CString borders=GetSettingString(L"TaskbarBordersH"); if (!borders.IsEmpty()) { wchar_t token[256]; const wchar_t *str=GetToken(borders,token,_countof(token),L", \t"); g_TaskbarMargins.left=_wtol(token); if (g_TaskbarMargins.left<0) g_TaskbarMargins.left=0; str=GetToken(str,token,_countof(token),L", \t"); g_TaskbarMargins.right=_wtol(token); if (g_TaskbarMargins.right<0) g_TaskbarMargins.right=0; } } if (g_TaskbarTileV==TILE_STRETCH) { CString borders=GetSettingString(L"TaskbarBordersV"); if (!borders.IsEmpty()) { wchar_t token[256]; const wchar_t *str=GetToken(borders,token,_countof(token),L", \t"); g_TaskbarMargins.top=_wtol(token); if (g_TaskbarMargins.top<0) g_TaskbarMargins.top=0; str=GetToken(str,token,_countof(token),L", \t"); g_TaskbarMargins.bottom=_wtol(token); if (g_TaskbarMargins.bottom<0) g_TaskbarMargins.bottom=0; } } } else if (GetWinVersion()WIN_VER_WIN7) { color=GetSystemGlassColor8(); color=((color&0xFF)<<16)|(color&0xFF00)|((color>>16)&0xFF); } BITMAPINFO bi={0}; bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth=bi.bmiHeader.biHeight=32; bi.bmiHeader.biPlanes=1; bi.bmiHeader.biBitCount=32; HDC hdc=CreateCompatibleDC(NULL); unsigned int *bits; g_TaskbarTexture=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,(void**)&bits,NULL,0); if (g_TaskbarTexture) { unsigned int val=((color&0xFF)<<16)|(color&0x00FF00)|((color>>16)&0xFF)|0xFF000000; int count=bi.bmiHeader.biWidth*bi.bmiHeader.biHeight; for (int i=0;i1 || countV>1) { // pretile texture BITMAPINFO bi={0}; bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth=countH*info.bmWidth; bi.bmiHeader.biHeight=countV*info.bmHeight; bi.bmiHeader.biPlanes=1; bi.bmiHeader.biBitCount=32; HDC hdc=CreateCompatibleDC(NULL); HDC hsrc=CreateCompatibleDC(hdc); unsigned int *bits; HBITMAP bmp=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,(void**)&bits,NULL,0); if (bmp) { HGDIOBJ bmp01=SelectObject(hdc,bmp); HGDIOBJ bmp02=SelectObject(hsrc,g_TaskbarTexture); for (int y=0;ysecond.taskBar,NULL,NULL,RDW_INVALIDATE|RDW_ALLCHILDREN); } return; } bool bButton=false, bCustomLook= false, bAll= false; if (update==TASKBAR_CLEAR) { if (g_TaskbarTexture) DeleteObject(g_TaskbarTexture); g_TaskbarTexture=NULL; } else { bButton=GetSettingBool(L"EnableStartButton"); bCustomLook=GetSettingBool(L"CustomTaskbar"); bAll=GetSettingBool(L"AllTaskbars"); } if (g_bTrimHooks) bButton=false; for (id_taskbar_map::iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it) { TaskbarInfo &taskBar=it->second; bool bButton2=bButton && (bAll || taskBar.taskBar==g_TaskBar); bool bHideButton2=bButton; if (taskBar.oldButton) { if (bHideButton2 && !bButton2) { // reposition rebar if (taskBar.oldButton) { RECT rc; GetWindowRect(taskBar.oldButton,&rc); taskBar.oldButtonSize.cx=rc.right-rc.left; taskBar.oldButtonSize.cy=rc.bottom-rc.top; } RECT rcTask; GetWindowRect(taskBar.taskBar,&rcTask); PostMessage(taskBar.taskBar,WM_SIZE,SIZE_RESTORED,MAKELONG(rcTask.right-rcTask.left,rcTask.bottom-rcTask.top)); } if (taskBar.bHideButton!=bHideButton2) { // show/hide 8.1 button taskBar.bHideButton=bHideButton2; if (bHideButton2) { ShowWindow(taskBar.oldButton,SW_HIDE); } else { ShowWindow(taskBar.oldButton,SW_SHOW); } } } if (taskBar.bReplaceButton!=bButton2) { // create or destroy button taskBar.bReplaceButton=bButton2; if (bButton2) { RecreateStartButton(it->first); if (g_WinStartButton) { ShowWindow(g_WinStartButton,SW_HIDE); SetWindowSubclass(g_WinStartButton,SubclassWin7StartButton,'CLSH',0); if (GetWinVersion()==WIN_VER_WIN7) { // Windows 7 draws the start button on the taskbar as well // so we zero out the bitmap resources HMODULE hExplorer=GetModuleHandle(NULL); for (int res=0;res<_countof(g_StartButtonOldSizes);res++) { HRSRC hrSrc=FindResource(hExplorer,MAKEINTRESOURCE(res+FIRST_BUTTON_BITMAP),RT_BITMAP); if (hrSrc) { HGLOBAL hRes=LoadResource(hExplorer,hrSrc); if (hRes) { void *pRes=LockResource(hRes); if (pRes) { DWORD old; BITMAPINFOHEADER *pHeader=(BITMAPINFOHEADER*)pRes; if (pHeader->biWidth) { g_StartButtonOldSizes[res]=MAKELONG(pHeader->biWidth,pHeader->biHeight); VirtualProtect(pRes,sizeof(BITMAPINFOHEADER),PAGE_READWRITE,&old); pHeader->biHeight=pHeader->biWidth=0; VirtualProtect(pRes,sizeof(BITMAPINFOHEADER),old,&old); } } } } } } SendMessage(taskBar.taskBar,WM_SETTINGCHANGE,0,0); } } else { if (taskBar.startButton && taskBar.startButton!=g_WinStartButton) { RevokeDragDrop(taskBar.startButton); DestroyStartButton(taskBar.taskbarId); } taskBar.startButton=taskBar.taskBar==g_TaskBar?g_WinStartButton:NULL; taskBar.startButtonSize.cx=taskBar.startButtonSize.cy=0; if (g_WinStartButton && g_WinStartButton==taskBar.startButton) { // restore the bitmap sizes HMODULE hExplorer=GetModuleHandle(NULL); for (int res=0;res<_countof(g_StartButtonOldSizes);res++) { HRSRC hrSrc=FindResource(hExplorer,MAKEINTRESOURCE(res+FIRST_BUTTON_BITMAP),RT_BITMAP); if (hrSrc) { HGLOBAL hRes=LoadResource(hExplorer,hrSrc); if (hRes) { void *pRes=LockResource(hRes); if (pRes) { DWORD old; BITMAPINFOHEADER *pHeader=(BITMAPINFOHEADER*)pRes; if (g_StartButtonOldSizes[res]) { VirtualProtect(pRes,sizeof(BITMAPINFOHEADER),PAGE_READWRITE,&old); pHeader->biWidth=LOWORD(g_StartButtonOldSizes[res]); pHeader->biHeight=HIWORD(g_StartButtonOldSizes[res]); VirtualProtect(pRes,sizeof(BITMAPINFOHEADER),old,&old); } } } } } RemoveWindowSubclass(g_WinStartButton,SubclassWin7StartButton,'CLSH'); SendMessage(g_WinStartButton,WM_THEMECHANGED,0,0); ShowWindow(g_WinStartButton,SW_SHOW); } } } else if (update==TASKBAR_RECREATE_BUTTONS && bButton2) { RecreateStartButton(it->first); } if (taskBar.bCustomLook!=bCustomLook) { // set custom look taskBar.bCustomLook=bCustomLook; if (!bCustomLook && GetWinVersion()second; SendMessage(taskBar.taskBar,WM_SETTINGCHANGE,0,0); InvalidateRect(taskBar.taskBar,NULL,TRUE); PostMessage(taskBar.taskBar,WM_THEMECHANGED,0,0); } } /////////////////////////////////////////////////////////////////////////////// // hooks for animating the start button typedef void (WINAPI *tDwmpBeginTransitionRequest)(int param); typedef void (WINAPI *tDwmpTransitionWindowWithRects)(HWND,int,RECT*,RECT*,RECT*,RECT*,RECT*); typedef void (WINAPI *tDwmpEndTransitionRequest)(int param); static IatHookData *g_DwmpBTRHook, *g_DwmpTWWRHook, *g_DwmpETRHook; static tDwmpBeginTransitionRequest g_DwmpBeginTransitionRequest; static tDwmpTransitionWindowWithRects g_DwmpTransitionWindowWithRects; static tDwmpEndTransitionRequest g_DwmpEndTransitionRequest; static HWND g_TransitionButton; static HWND g_TransitionBar; static RECT g_TransitionClip; static POINT g_TransitionVector; static bool g_bTransitionIn; void WINAPI DwmpBeginTransitionRequest2( int param ) { g_TransitionButton=NULL; ((tDwmpBeginTransitionRequest)g_DwmpBTRHook->oldProc)(param); } void WINAPI DwmpTransitionWindowWithRects2( HWND hWnd, int flags, RECT *prcClient1, RECT *prcStart, RECT *prcClient2, RECT *prcEnd, RECT *prcClip ) { g_TransitionButton=NULL; const TaskbarInfo *taskBar=FindTaskBarInfoBar(hWnd); if (taskBar && taskBar->bCustomLook) { g_TransitionBar=hWnd; TTaskbarLook look=(TTaskbarLook)GetSettingInt(L"TaskbarLook"); DWM_BLURBEHIND blur={DWM_BB_ENABLE,look==TASKBAR_OPAQUE}; DwmEnableBlurBehindWindow(hWnd,&blur); int data[4]; ComputeTaskbarColors(data); WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)}; SetWindowCompositionAttribute(hWnd,&attrData); } if (taskBar && taskBar->startButton && prcStart && prcEnd && prcClip) { g_TransitionButton=taskBar->startButton; g_TransitionVector.x=prcEnd->left-prcStart->left; g_TransitionVector.y=prcEnd->top-prcStart->top; g_TransitionClip=*prcClip; g_bTransitionIn=true; switch (GetTaskbarPosition(taskBar->taskBar,NULL,NULL,NULL)) { case ABE_LEFT: g_bTransitionIn=g_TransitionVector.x>0; break; case ABE_TOP: g_bTransitionIn=g_TransitionVector.y>0; break; case ABE_RIGHT: g_bTransitionIn=g_TransitionVector.x<0; break; default: g_bTransitionIn=g_TransitionVector.y<0; } } ((tDwmpTransitionWindowWithRects)g_DwmpTWWRHook->oldProc)(hWnd,flags,prcClient1,prcStart,prcClient2,prcEnd,prcClip); } void WINAPI DwmpEndTransitionRequest2( int param ) { ((tDwmpEndTransitionRequest)g_DwmpETRHook->oldProc)(param); if (g_TransitionBar) { TTaskbarLook look=(TTaskbarLook)GetSettingInt(L"TaskbarLook"); DWM_BLURBEHIND blur={DWM_BB_ENABLE,look==TASKBAR_OPAQUE}; DwmEnableBlurBehindWindow(g_TransitionBar,&blur); int data[4]; ComputeTaskbarColors(data); WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)}; SetWindowCompositionAttribute(g_TransitionBar,&attrData); g_TransitionBar=NULL; } if (g_TransitionButton) { HWND button=g_TransitionButton; g_TransitionButton=NULL; g_DwmpBeginTransitionRequest(15); RECT rcClient; GetClientRect(button,&rcClient); RECT rcStart, rcEnd; if (g_bTransitionIn) { GetWindowRect(button,&rcEnd); rcStart=rcEnd; OffsetRect(&rcStart,-g_TransitionVector.x,-g_TransitionVector.y); } else { GetWindowRect(button,&rcStart); rcEnd=rcStart; int dx=0, dy=0; if (g_TransitionVector.x<0) // left { dx=g_TransitionClip.left-rcStart.right; if (dx>0) dx=g_TransitionVector.x; } else if (g_TransitionVector.x>0) // right { dx=g_TransitionClip.right-rcStart.left; if (dx<0) dx=g_TransitionVector.x; } else if (g_TransitionVector.y<0) // top { dy=g_TransitionClip.top-rcStart.bottom; if (dy>0) dy=g_TransitionVector.y; } else if (g_TransitionVector.y>0) // bottom { dy=g_TransitionClip.bottom-rcStart.top; if (dy<0) dy=g_TransitionVector.y; } OffsetRect(&rcEnd,dx,dy); } g_DwmpTransitionWindowWithRects(button,0x21800046,&rcClient,&rcStart,&rcClient,&rcEnd,&g_TransitionClip); g_DwmpEndTransitionRequest(15); } } /////////////////////////////////////////////////////////////////////////////// // hooks for skinning the taskbar typedef void (WINAPI *tSHFillRectClr)(HDC hdc, const RECT *pRect, COLORREF color); static IatHookData *g_SHFillRectClrHook, *g_StretchDIBitsHook; static IatHookData *g_DrawThemeBackgroundHook, *g_DrawThemeTextHook, *g_DrawThemeTextExHook, *g_DrawThemeTextCtlHook, *g_SetWindowCompositionAttributeHook; static tSHFillRectClr g_SHFillRectClr; static void WINAPI SHFillRectClr2( HDC hdc, const RECT *pRect, COLORREF color ) { if (!g_CurrentTaskList || !g_TaskbarTexture || GetCurrentThreadId()!=g_TaskbarThreadId) g_SHFillRectClr(hdc,pRect,color); } static HRESULT STDAPICALLTYPE DrawThemeBackground2( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect, LPCRECT pClipRect ) { if (g_CurrentTaskList && g_TaskbarTexture && iPartId==1 && iStateId==0 && GetCurrentThreadId()==g_TaskbarThreadId) { HWND taskbar=GetAncestor(g_CurrentTaskList,GA_ROOT); RECT rcClient; GetClientRect(taskbar,&rcClient); MapWindowPoints(taskbar,g_CurrentTaskList,(POINT*)&rcClient,2); PrintTaskbarBackground(hdc,rcClient,*pRect,0); return S_OK; } if (g_CurrentDesktopButton && g_TaskbarTexture && GetCurrentThreadId()==g_TaskbarThreadId && hTheme==GetWindowTheme(g_CurrentDesktopButton)) { HWND taskbar=GetAncestor(g_CurrentDesktopButton,GA_ROOT); RECT rcClient; GetClientRect(taskbar,&rcClient); MapWindowPoints(taskbar,g_CurrentDesktopButton,(POINT*)&rcClient,2); UINT uEdge=GetTaskbarPosition(taskbar,NULL,NULL,NULL); PrintTaskbarBackground(hdc,rcClient,*pRect,uEdge); return DrawThemeBackground(hTheme,hdc,iPartId,iStateId,pRect,pClipRect); } return DrawThemeBackground(hTheme,hdc,iPartId,iStateId,pRect,pClipRect); } // toolbar text, rebar band titles, clock static HRESULT STDAPICALLTYPE DrawThemeText2( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect ) { if ((g_CurrentRebar || g_CurrentTaskbarPart) && GetCurrentThreadId()==g_TaskbarThreadId && GetSettingBool(L"CustomTaskbar")) { bool bDef; COLORREF color=GetSettingInt(L"TaskbarTextColor",bDef)&0xFFFFFF; if (!bDef) { // change the color for the toolbar titles, the toolbar buttons and the clock DTTOPTS options={sizeof(options),DTT_TEXTCOLOR}; options.crText=color; return DrawThemeTextEx(hTheme,hdc,iPartId,iStateId,pszText,iCharCount,dwTextFlags,(RECT*)pRect,&options); } } return DrawThemeText(hTheme,hdc,iPartId,iStateId,pszText,iCharCount,dwTextFlags,dwTextFlags2,pRect); } // taskbar text static HRESULT STDAPICALLTYPE DrawThemeTextEx2( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwFlags, LPRECT pRect, const DTTOPTS *pOptions ) { if ((g_CurrentTaskList || g_CurrentTaskbarPart) && GetCurrentThreadId()==g_TaskbarThreadId && GetSettingBool(L"CustomTaskbar")) { bool bDef; COLORREF color=GetSettingInt(L"TaskbarTextColor",bDef)&0xFFFFFF; if (!bDef) { // change the color dor the taskbar buttons DTTOPTS options=*pOptions; options.dwFlags|=DTT_TEXTCOLOR; options.crText=color; return DrawThemeTextEx(hTheme,hdc,iPartId,iStateId,pszText,iCharCount,dwFlags,pRect,&options); } } return DrawThemeTextEx(hTheme,hdc,iPartId,iStateId,pszText,iCharCount,dwFlags,pRect,pOptions); } static BLENDFUNCTION g_AlphaFunc={AC_SRC_OVER,0,255,AC_SRC_ALPHA}; static int WINAPI StretchDIBits2( HDC hdc, int xDest, int yDest, int DestWidth, int DestHeight, int xSrc, int ySrc, int SrcWidth, int SrcHeight, CONST VOID *lpBits, CONST BITMAPINFO *lpbmi, UINT iUsage, DWORD rop ) { if ((g_CurrentTaskChevron || g_CurrentTaskbarButton) && g_TaskbarTexture && GetCurrentThreadId()==g_TaskbarThreadId) { HDC hsrc=CreateCompatibleDC(hdc); BITMAPINFO bi={0}; bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth=DestWidth; bi.bmiHeader.biHeight=DestHeight; bi.bmiHeader.biPlanes=1; bi.bmiHeader.biBitCount=32; HBITMAP bitmap=CreateDIBSection(hsrc,&bi,DIB_RGB_COLORS,NULL,NULL,0); HGDIOBJ bmp0=SelectObject(hsrc,bitmap); int res=StretchDIBits(hsrc,0,0,DestWidth,DestHeight,xSrc,ySrc,SrcWidth,SrcHeight,lpBits,lpbmi,iUsage,SRCCOPY); AlphaBlend(hdc,xDest,yDest,DestWidth,DestHeight,hsrc,0,0,DestWidth,DestHeight,g_AlphaFunc); SelectObject(hsrc,bmp0); DeleteObject(bitmap); DeleteDC(hsrc); return res; } return StretchDIBits(hdc,xDest,yDest,DestWidth,DestHeight,xSrc,ySrc,SrcWidth,SrcHeight,lpBits,lpbmi,iUsage,rop); } static BOOL WINAPI SetWindowCompositionAttribute2( HWND hwnd, WINCOMPATTRDATA *pAttrData ) { if (pAttrData->attribute==0x13 && GetCurrentThreadId()==g_TaskbarThreadId) { const TaskbarInfo *taskBar=FindTaskBarInfoBar(hwnd); if (taskBar && taskBar->bCustomLook) { int data[4]; ComputeTaskbarColors(data); WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)}; if (data[0]==3 && taskBar->bThemeChanging) { // send extra attribute when dealing with glass. without it the image behind the glass may not update when the taskbar is resized SetWindowCompositionAttribute(hwnd,pAttrData); } return SetWindowCompositionAttribute(hwnd,&attrData); } } return SetWindowCompositionAttribute(hwnd,pAttrData); } /////////////////////////////////////////////////////////////////////////////// // hooks for preventing shell hotkeys registration on Win11 using ShellRegisterHotKey_t = BOOL(WINAPI*)(HWND, int, UINT, UINT, HWND); static IatHookData* g_ShellRegisterHotKeyHook; static ShellRegisterHotKey_t g_ShellRegisterHotKey; static BOOL WINAPI ShellRegisterHotKeyHook(HWND hWnd, int id, UINT fsModifiers, UINT vk, HWND hWndTarget) { // Win key if (fsModifiers == MOD_WIN && vk == 0) return FALSE; // Ctrl+Esc if (fsModifiers == MOD_CONTROL && vk == VK_ESCAPE) return FALSE; return g_ShellRegisterHotKey(hWnd, id, fsModifiers, vk, hWndTarget); } // one-time APC function to unregister shell hotkeys void NTAPI DisableShellHotkeysFunc(ULONG_PTR Parameter) { UnregisterHotKey(NULL, 1); UnregisterHotKey(NULL, 2); } /////////////////////////////////////////////////////////////////////////////// static void OpenCortana( void ) { if (GetWinVersion()>=WIN_VER_WIN10) ShellExecute(NULL,NULL,L"shell:::{2559a1f8-21d7-11d4-bdaf-00c04f60b9f0}",NULL,NULL,SW_SHOWNORMAL); } static void InitStartMenuDLL( void ) { LogToFile(STARTUP_LOG, L"StartMenu DLL: InitStartMenuDLL"); WaitDllInitThread(); InitializeIatHooks(); if (IsWin81Update1()) { HMODULE dwm=GetModuleHandle(L"dwmapi.dll"); if (dwm) { g_DwmpBeginTransitionRequest=(tDwmpBeginTransitionRequest)GetProcAddress(dwm,MAKEINTRESOURCEA(138)); g_DwmpTransitionWindowWithRects=(tDwmpTransitionWindowWithRects)GetProcAddress(dwm,MAKEINTRESOURCEA(141)); g_DwmpEndTransitionRequest=(tDwmpEndTransitionRequest)GetProcAddress(dwm,MAKEINTRESOURCEA(140)); if (g_DwmpBeginTransitionRequest && g_DwmpTransitionWindowWithRects && g_DwmpEndTransitionRequest) { g_DwmpBTRHook=SetIatHook(GetModuleHandle(NULL),"dwmapi.dll",MAKEINTRESOURCEA(138),DwmpBeginTransitionRequest2); g_DwmpTWWRHook=SetIatHook(GetModuleHandle(NULL),"dwmapi.dll",MAKEINTRESOURCEA(141),DwmpTransitionWindowWithRects2); g_DwmpETRHook=SetIatHook(GetModuleHandle(NULL),"dwmapi.dll",MAKEINTRESOURCEA(140),DwmpEndTransitionRequest2); if (!g_DwmpBTRHook || !g_DwmpTWWRHook || !g_DwmpETRHook) { ClearIatHook(g_DwmpBTRHook); g_DwmpBTRHook=NULL; ClearIatHook(g_DwmpTWWRHook); g_DwmpTWWRHook=NULL; ClearIatHook(g_DwmpETRHook); g_DwmpETRHook=NULL; } } } } if (GetSettingBool(L"CustomTaskbar")) { auto module=GetModuleHandle(L"taskbar.dll"); if (!module) module=GetModuleHandle(NULL); if (GetWinVersion()>=WIN_VER_WIN10) { HMODULE shlwapi=GetModuleHandle(L"shlwapi.dll"); if (shlwapi) { g_SHFillRectClr=(tSHFillRectClr)GetProcAddress(shlwapi,MAKEINTRESOURCEA(197)); if (g_SHFillRectClr) { g_SHFillRectClrHook=SetIatHook(module,"shlwapi.dll",MAKEINTRESOURCEA(197),SHFillRectClr2); if (!g_SHFillRectClrHook) g_SHFillRectClrHook=SetIatHook(module,"api-ms-win-shlwapi-winrt-storage-l1-1-1.dll",MAKEINTRESOURCEA(197),SHFillRectClr2); } } g_StretchDIBitsHook=SetIatHook(module,"gdi32.dll","StretchDIBits",StretchDIBits2); if (!g_StretchDIBitsHook) g_StretchDIBitsHook=SetIatHook(module,"ext-ms-win-gdi-draw-l1-1-0.dll","StretchDIBits",StretchDIBits2); } { HWND dlg=CreateWindow(L"#32770",L"",WS_POPUP,0,0,0,0,NULL,0,0,0); HWND toolbar=CreateWindow(TOOLBARCLASSNAME,L"",WS_CHILD|TBS_TOOLTIPS,0,0,0,0,dlg,0,0,0); DestroyWindow(dlg); } if (GetWinVersion()<=WIN_VER_WIN81) g_DrawThemeBackgroundHook=SetIatHook(module,"uxtheme.dll","DrawThemeBackground",DrawThemeBackground2); g_DrawThemeTextHook=SetIatHook(module,"uxtheme.dll","DrawThemeText",DrawThemeText2); g_DrawThemeTextExHook=SetIatHook(module,"uxtheme.dll","DrawThemeTextEx",DrawThemeTextEx2); g_DrawThemeTextCtlHook=SetIatHook(GetModuleHandle(L"comctl32.dll"),"uxtheme.dll","DrawThemeText",DrawThemeText2); if (GetWinVersion()>=WIN_VER_WIN10) g_SetWindowCompositionAttributeHook=SetIatHook(module,"user32.dll","SetWindowCompositionAttribute",SetWindowCompositionAttribute2); } g_TaskbarThreadId=GetCurrentThreadId(); g_bTrimHooks=GetWinVersion()==WIN_VER_WIN7 && (GetSettingInt(L"CompatibilityFixes")&COMPATIBILITY_TRIM_HOOKS); InitManagers(false); int level=GetSettingInt(L"CrashDump"); if (level>=1 && level<=3) { if (level==1) MiniDumpType=MiniDumpNormal; if (level==2) MiniDumpType=MiniDumpWithDataSegs; if (level==3) MiniDumpType=MiniDumpWithFullMemory; SetUnhandledExceptionFilter(TopLevelFilter); _set_invalid_parameter_handler(InvalidParameterHandler); g_bCrashDump=true; } FindTaskBar(); g_ProgWin=FindWindowEx(NULL,NULL,L"Progman",NULL); DWORD progThread=GetWindowThreadProcessId(g_ProgWin,NULL); g_ProgHook=SetWindowsHookEx(WH_GETMESSAGE,HookProgManThread,NULL,progThread); g_StartHook=SetWindowsHookEx(WH_GETMESSAGE,HookDesktopThread,NULL,GetCurrentThreadId()); if (IsWin11()) { g_StartMouseHook=SetWindowsHookEx(WH_MOUSE,HookDesktopThreadMouse,NULL,GetCurrentThreadId()); // hook ShellRegisterHotKey to prevent twinui.dll to install shell hotkeys (Win, Ctrl+Esc) // without these hotkeys there is standard WM_SYSCOMMAND+SC_TASKLIST sent when start menu is invoked by keyboard shortcut g_ShellRegisterHotKey = (ShellRegisterHotKey_t)GetProcAddress(GetModuleHandle(L"user32.dll"), MAKEINTRESOURCEA(2671)); auto twinui = GetModuleHandle(L"twinui.dll"); if (g_ShellRegisterHotKey && twinui) { g_ShellRegisterHotKeyHook = SetIatHook(twinui, "user32.dll" ,MAKEINTRESOURCEA(2671), ShellRegisterHotKeyHook); // unregister shell hotkeys as they may be registered already // this has to be done from context of thread that registered them auto hwnd = FindWindow(L"ApplicationManager_ImmersiveShellWindow", NULL); if (hwnd) { auto thread = OpenThread(THREAD_SET_CONTEXT, FALSE, GetWindowThreadProcessId(hwnd, NULL)); if (thread) { QueueUserAPC(DisableShellHotkeysFunc, thread, 0); CloseHandle(thread); } } } } HWND hwnd=FindWindow(L"OpenShellMenu.CStartHookWindow",L"StartHookWindow"); LoadLibrary(L"StartMenuDLL.dll"); // keep the DLL from unloading if (hwnd) PostMessage(hwnd,WM_CLEAR,0,0); // tell the exe to unhook this hook if (GetWinVersion()>=WIN_VER_WIN8) { SetWindowCompositionAttribute=(tSetWindowCompositionAttribute)GetProcAddress(GetModuleHandle(L"user32.dll"),"SetWindowCompositionAttribute"); } int taskbarId=g_NextTaskbar++; TaskbarInfo &taskBar=g_TaskbarInfos[taskbarId]; taskBar.taskBar=g_TaskBar; taskBar.taskbarId=taskbarId; taskBar.rebar=FindWindowEx(g_TaskBar,NULL,REBARCLASSNAME,NULL); if (taskBar.rebar) { SetWindowSubclass(taskBar.rebar,SubclassRebarProc,'CLSH',taskbarId); // TaskBand window HWND hwnd=FindWindowEx(taskBar.rebar,NULL,L"MSTaskSwWClass",NULL); if (hwnd) { taskBar.taskList=hwnd; // TaskList window // it has to be visible, otherwise it won't receive WM_PAINT that we need to intercept // in such case we will intercept parent instead hwnd=FindWindowEx(hwnd,NULL,L"MSTaskListWClass",NULL); if (hwnd&&IsWindowVisible(hwnd)) taskBar.taskList=hwnd; } if (taskBar.taskList) SetWindowSubclass(taskBar.taskList,SubclassTaskListProc,'CLSH',taskbarId); } if (GetWinVersion()>WIN_VER_WIN8) { taskBar.oldButton=FindWindowEx(taskBar.taskBar,NULL,L"Start",NULL); if (taskBar.oldButton) { if (GetWinVersion()>=WIN_VER_WIN10) { taskBar.pOriginalTarget=(IDropTarget*)GetProp(taskBar.oldButton,L"OleDropTargetInterface"); if (taskBar.pOriginalTarget) RevokeDragDrop(taskBar.oldButton); } CStartMenuTarget *pNewTarget=new CStartMenuTarget(taskBar.taskbarId); RegisterDragDrop(taskBar.oldButton,pNewTarget); pNewTarget->Release(); if (GetWinVersion()=WIN_VER_WIN10) { for (HWND button=FindWindowEx(g_TaskBar,NULL,L"TrayButton",NULL);button;button=FindWindowEx(g_TaskBar,button,L"TrayButton",NULL)) { taskBar.trayButtons.push_back(button); SetWindowSubclass(button,SubclassTrayButtonProc,'CLSH',taskBar.taskbarId); } HWND search=FindWindowEx(g_TaskBar,NULL,L"TrayDummySearchControl",NULL); if (search) { taskBar.trayButtons.push_back(search); SetWindowSubclass(search,SubclassTrayButtonProc,'CLSH',taskBar.taskbarId); } HWND tray=FindWindowEx(g_TaskBar,NULL,L"TrayNotifyWnd",NULL); if (tray) taskBar.chevron=FindWindowEx(tray,NULL,L"Button",NULL); if (taskBar.chevron) SetWindowSubclass(taskBar.chevron,SubclassTrayChevronProc,'CLSH',taskBar.taskbarId); } HandleTaskbarParts(taskBar,true); if (!g_bTrimHooks) SetWindowSubclass(taskBar.taskBar,SubclassTaskBarProc,'CLSH',taskbarId); taskBar.startButton=g_WinStartButton; #ifdef HOOK_DROPTARGET if (g_WinStartButton) { g_pOriginalTarget=(IDropTarget*)GetProp(g_WinStartButton,L"OleDropTargetInterface"); if (g_pOriginalTarget) RevokeDragDrop(g_WinStartButton); CStartMenuTarget *pNewTarget=new CStartMenuTarget(taskbarId); RegisterDragDrop(g_WinStartButton,pNewTarget); pNewTarget->Release(); } #endif if (GetWinVersion()>=WIN_VER_WIN8) { g_pAppVisibility.CoCreateInstance(CLSID_MetroMode); if (g_pAppVisibility) { CMonitorModeEvents *monitor=new CMonitorModeEvents(); g_pAppVisibility->Advise(monitor,&g_AppVisibilityMonitorCookie); monitor->Release(); } if (GetWinVersion()second; if (taskbarId>=0 && taskBar.taskbarId!=taskbarId) continue; if (taskBar.bRecreatingButton) continue; taskBar.bRecreatingButton=true; { if (taskBar.startButton && taskBar.startButton!=g_WinStartButton) { RevokeDragDrop(taskBar.startButton); DestroyStartButton(taskBar.taskbarId); } taskBar.startButton=CreateStartButton(taskBar.taskbarId,taskBar.taskBar,taskBar.rebar); CStartMenuTarget *pNewTarget=new CStartMenuTarget(taskBar.taskbarId); RegisterDragDrop(taskBar.startButton,pNewTarget); pNewTarget->Release(); } taskBar.bRecreatingButton=false; taskBar.startButtonSize=GetStartButtonSize(taskBar.taskbarId); if (taskBar.oldButton) { RECT rc; GetWindowRect(taskBar.oldButton,&rc); taskBar.oldButtonSize.cx=rc.right-rc.left; taskBar.oldButtonSize.cy=rc.bottom-rc.top; } RECT rcTask; GetWindowRect(taskBar.taskBar,&rcTask); PostMessage(taskBar.taskBar,WM_SIZE,SIZE_RESTORED,MAKELONG(rcTask.right-rcTask.left,rcTask.bottom-rcTask.top)); for (auto btn : taskBar.trayButtons) { RECT rc; GetWindowRect(btn,&rc); SetWindowPos(btn,HWND_TOP,rc.left,rc.top,0,0,SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER); } } } static DWORD WINAPI ExitThreadProc( void *param ) { Sleep(1000); // wait a second! hopefully by then the hooks will be finished and no more of our code will be executing // send WM_CLOSE to the window in StartMenu.exe to close that process if (param) PostMessage((HWND)param,WM_CLOSE,0,0); FreeLibraryAndExitThread(g_Instance,0); } static void CleanStartMenuDLL( void ) { ClearIatHook(g_DwmpBTRHook); g_DwmpBTRHook=NULL; ClearIatHook(g_DwmpTWWRHook); g_DwmpTWWRHook=NULL; ClearIatHook(g_DwmpETRHook); g_DwmpETRHook=NULL; ClearIatHook(g_SHFillRectClrHook); g_SHFillRectClrHook=NULL; ClearIatHook(g_StretchDIBitsHook); g_StretchDIBitsHook=NULL; ClearIatHook(g_DrawThemeBackgroundHook); g_DrawThemeBackgroundHook=NULL; ClearIatHook(g_DrawThemeTextHook); g_DrawThemeTextHook=NULL; ClearIatHook(g_DrawThemeTextExHook); g_DrawThemeTextExHook=NULL; ClearIatHook(g_DrawThemeTextCtlHook); g_DrawThemeTextCtlHook=NULL; ClearIatHook(g_SetWindowCompositionAttributeHook); g_SetWindowCompositionAttributeHook=NULL; ClearIatHook(g_ShellRegisterHotKeyHook); g_ShellRegisterHotKeyHook=NULL; CloseManagers(false); ClearIatHooks(); // cleanup if (g_Owner.m_hWnd) g_Owner.DestroyWindow(); CloseSettings(); CMenuContainer::CloseStartMenu(); CMenuFader::ClearAll(); UnhookDropTarget(); EnableHotkeys(HOTKEYS_CLEAR); HWND hwnd=FindWindow(L"OpenShellMenu.CStartHookWindow",L"StartHookWindow"); UnhookWindowsHookEx(g_ProgHook); UnhookWindowsHookEx(g_StartHook); if (g_StartMouseHook) UnhookWindowsHookEx(g_StartMouseHook); g_StartMouseHook=NULL; if (g_AppManagerHook) UnhookWindowsHookEx(g_AppManagerHook); g_AppManagerHook=NULL; if (g_NewWindowHook) UnhookWindowsHookEx(g_NewWindowHook); g_NewWindowHook=NULL; if (g_pAppVisibility) { g_pAppVisibility->Unadvise(g_AppVisibilityMonitorCookie); g_pAppVisibility=NULL; } ResetHotCorners(); UpdateTaskBars(TASKBAR_CLEAR); g_WinStartButton=NULL; for (id_taskbar_map::const_iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it) { if (it->second.rebar) RemoveWindowSubclass(it->second.rebar,SubclassRebarProc,'CLSH'); if (it->second.taskList) RemoveWindowSubclass(it->second.taskList,SubclassTaskListProc,'CLSH'); if (it->second.oldButton) { RemoveWindowSubclass(it->second.oldButton,SubclassWin81StartButton,'CLSH'); if (GetWinVersion()second.taskBar,NULL,NULL,NULL)==ABE_BOTTOM) SetWindowPos(it->second.oldButton,NULL,0,0,0,0,SWP_NOSIZE|SWP_NOZORDER); RevokeDragDrop(it->second.oldButton); if (it->second.pOriginalTarget) RegisterDragDrop(it->second.oldButton,it->second.pOriginalTarget); } if (!g_bTrimHooks) RemoveWindowSubclass(it->second.taskBar,SubclassTaskBarProc,'CLSH'); for (std::vector::const_iterator it2=it->second.trayButtons.begin();it2!=it->second.trayButtons.end();++it2) { RemoveWindowSubclass(*it2,SubclassTrayButtonProc,'CLSH'); } for (std::vector::const_iterator it2=it->second.taskbarParts.begin();it2!=it->second.taskbarParts.end();++it2) { RemoveWindowSubclass(*it2,SubclassTaskbarPartProc,'CLSH'); } if (it->second.chevron) RemoveWindowSubclass(it->second.chevron,SubclassTrayChevronProc,'CLSH'); if (it->second.desktop) RemoveWindowSubclass(it->second.desktop,SubclassDesktopButtonProc,'CLSH'); if (it->second.bTimer) KillTimer(it->second.startButton,'CLSM'); RECT rcTask; GetWindowRect(it->second.taskBar,&rcTask); PostMessage(it->second.taskBar,WM_SIZE,SIZE_RESTORED,MAKELONG(rcTask.right-rcTask.left,rcTask.bottom-rcTask.top)); PostMessage(it->second.taskBar,WM_THEMECHANGED,0,0); } g_TaskbarInfos.clear(); if (g_TopWin7Menu) { RemoveWindowSubclass(g_UserPic,SubclassUserPicProc,'CLSH'); RemoveWindowSubclass(g_TopWin7Menu,SubclassTopMenuProc,'CLSH'); RemoveWindowSubclass(g_AllPrograms,SubclassProgramsProc,'CLSH'); } if (g_bCrashDump) { SetUnhandledExceptionFilter(NULL); g_bCrashDump=false; } // we need to unload the DLL here. but we can't just call FreeLibrary because it will unload the code // while it is still executing. So we create a separate thread and use FreeLibraryAndExitThread CreateThread(NULL,0,ExitThreadProc,(void*)hwnd,0,NULL); } /////////////////////////////////////////////////////////////////////////////// static BOOL CALLBACK FindImmersiveWindows( HWND hwnd, LPARAM lParam ) { wchar_t name[100]; GetClassName(hwnd,name,_countof(name)); if (wcscmp(name,L"ImmersiveLauncher")==0) ((HWND*)lParam)[0]=hwnd; if (wcscmp(name,L"ImmersiveBackgroundWindow")==0) ((HWND*)lParam)[1]=hwnd; if (wcscmp(name,L"SearchPane")==0) ((HWND*)lParam)[2]=hwnd; return TRUE; } static bool WindowsMenuOpened( void ) { FindWindowsMenu(); CComPtr pImmersiveShell; if (GetWinVersion()>=WIN_VER_WIN10 && CreateImmersiveShell(pImmersiveShell)) { { CComPtr pLauncher; IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher81,(void**)&pLauncher); BOOL bIsVisible; if (pLauncher && SUCCEEDED(pLauncher->IsVisible(&bIsVisible))) return bIsVisible!=0; } { CComPtr pLauncher; IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher10RS,(void**)&pLauncher); BOOL bIsVisible; if (pLauncher && SUCCEEDED(pLauncher->IsVisible(&bIsVisible))) return bIsVisible!=0; } } if (GetWinVersion()>=WIN_VER_WIN8) { return GetMetroMode(NULL)!=METRO_NONE; } else { return g_TopWin7Menu && IsWindowVisible(g_TopWin7Menu); } } static void OpenStartScreen( HMONITOR monitor ) { CComPtr pImmersiveShell; if (CreateImmersiveShell(pImmersiveShell)) { CComPtr pMonitor; if (GetWinVersion()==WIN_VER_WIN8) { if (monitor) { CComPtr pMonitorService; IUnknown_QueryService(pImmersiveShell,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService); if (pMonitorService) { CComPtr pMonitor; pMonitorService->GetFromHandle(monitor,&pMonitor); if (pMonitor) pMonitorService->SetImmersiveMonitor(pMonitor); } } CComPtr pLauncher; IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher80,(void**)&pLauncher); if (pLauncher) pLauncher->ShowStartView(5); return; } if (monitor) { CComPtr pMonitorService; IUnknown_QueryService(pImmersiveShell,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService); if (pMonitorService) pMonitorService->GetFromHandle(monitor,&pMonitor); } { CComPtr pLauncher; IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher81,(void**)&pLauncher); if (pLauncher) { if (pMonitor) pLauncher->ConnectToMonitor(pMonitor); HRESULT hr=pLauncher->ShowStartView(GetWinVersion()>=WIN_VER_WIN10?11:5,0); return; } } { CComPtr pLauncher; IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher10RS,(void**)&pLauncher); if (pLauncher) { if (pMonitor) pLauncher->ConnectToMonitor(pMonitor); HRESULT hr=pLauncher->ShowStartView(GetWinVersion()>=WIN_VER_WIN10?11:5,0); return; } } } else if (g_AppManagerThread) PostThreadMessage(g_AppManagerThread,g_StartMenuMsg,MSG_SHIFTWIN,(LPARAM)monitor); } // WH_GETMESSAGE hook for the Progman window static LRESULT CALLBACK HookProgManThread( int code, WPARAM wParam, LPARAM lParam ) { if (code==HC_ACTION && wParam) { MSG *msg=(MSG*)lParam; if (msg->message==WM_SYSCOMMAND && (msg->wParam&0xFFF0)==SC_TASKLIST) { if (GetWinVersion()message=WM_NULL; // Win button pressed if (msg->lParam=='WSMK' || msg->lParam=='WSMM' || msg->lParam=='WSMH') { if ((g_AppManagerThread || GetWinVersion()>=WIN_VER_WIN10) && (msg->lParam=='WSMM' || msg->lParam=='WSMH' || (g_TaskbarInfos.size()>1 && GetSettingBool(L"OpenMouseMonitor")))) { if (!WindowsMenuOpened()) { HMONITOR monitor=msg->lParam=='WSMH'?g_WSMHMonitor:MonitorFromPoint(CPoint(GetMessagePos()),MONITOR_DEFAULTTONULL); OpenStartScreen(monitor); msg->message=WM_NULL; } } } else if (msg->lParam=='CSM') { msg->message=WM_NULL; PostMessage(g_TaskBar,g_StartMenuMsg,MSG_TOGGLE,0); } else { FindTaskBar(); int control=GetSettingInt(L"WinKey"); if (control==OPEN_BOTH) { if (GetWinVersion()>=WIN_VER_WIN10) control=GetWin10TabletMode()?OPEN_WINDOWS:OPEN_CLASSIC; else control=GetMetroMode(MonitorFromPoint(CPoint(GetMessagePos()),MONITOR_DEFAULTTONEAREST))?OPEN_WINDOWS:OPEN_CLASSIC; } if (control==OPEN_DESKTOP) { TMetroMode metro=GetMetroMode(MonitorFromPoint(CPoint(GetMessagePos()),MONITOR_DEFAULTTONEAREST)); if (metro==METRO_NONE) control=OPEN_CLASSIC; else if (metro==METRO_APP) control=OPEN_WINDOWS; else { msg->message=WM_NULL; SetForegroundWindow(GetDefaultTaskbarInfo()->taskBar); } } if (control==OPEN_WINDOWS) { FindWindowsMenu(); if (g_TopWin7Menu && WindowsMenuOpened()) { const TaskbarInfo *taskBar=GetDefaultTaskbarInfo(); SetForegroundWindow(taskBar->startButton?taskBar->startButton:taskBar->taskBar); msg->message=WM_NULL; } else if (GetWinVersion()>=WIN_VER_WIN8 && g_TaskbarInfos.size()>1 && GetSettingBool(L"OpenMouseMonitor") && !WindowsMenuOpened()) { HMONITOR monitor=MonitorFromPoint(CPoint(GetMessagePos()),MONITOR_DEFAULTTONULL); OpenStartScreen(monitor); msg->message=WM_NULL; } else { PostMessage(g_TaskBar,g_StartMenuMsg,MSG_NOP,0); } } else { msg->message=WM_NULL; if (control==OPEN_CLASSIC) PostMessage(g_TaskBar,g_StartMenuMsg,MSG_TOGGLE,0); else if (control==OPEN_CUSTOM) { CString commandText=GetSettingString(L"WinKeyCommand"); if (!commandText.IsEmpty()) { wchar_t expandedCommand[_MAX_PATH]{}; ::ExpandEnvironmentStrings(commandText, expandedCommand, _countof(expandedCommand)); ShellExecute(NULL,NULL,expandedCommand,NULL,NULL,SW_SHOWNORMAL); } } } } } if ((msg->message==WM_MOUSEMOVE || msg->message==WM_LBUTTONDOWN) && GetWinVersion()>=WIN_VER_WIN8 && HIWORD(msg->lParam)<10 && GetSettingInt(L"DisableHotCorner")==2) { if (msg->hwnd!=g_TopDesktopBar || !g_TopDesktopBar || !IsWindow(g_TopDesktopBar)) { wchar_t name[100]; if (!GetClassName(msg->hwnd,name,_countof(name)) || _wcsicmp(name,L"WorkerW")!=0) return CallNextHookEx(NULL,code,wParam,lParam); HWND parent=GetParent(msg->hwnd); if (parent!=g_ProgWin && !FindWindowEx(parent,NULL,L"SHELLDLL_DefView",NULL)) return CallNextHookEx(NULL,code,wParam,lParam); g_EdgeWindows.erase(g_TopDesktopBar); g_TopDesktopBar=msg->hwnd; } g_EdgeWindows.insert(g_TopDesktopBar); ShowWindow(g_TopDesktopBar,SW_HIDE); msg->message=WM_NULL; } } return CallNextHookEx(NULL,code,wParam,lParam); } // WH_MOUSE hook for taskbar thread (Win11+) static LRESULT CALLBACK HookDesktopThreadMouse(int code, WPARAM wParam, LPARAM lParam) { if (code == HC_ACTION) { // we need to steal mouse messages that are issues in start button area // so that they won't get to XAML framework that is handling original start button auto info = (const MOUSEHOOKSTRUCT*)lParam; { auto taskBar = FindTaskBarInfoButton(info->hwnd); // click on start button if (!taskBar) { taskBar = FindTaskBarInfoBar(GetAncestor(info->hwnd, GA_ROOT)); // click on taskbar if (taskBar && !PointAroundStartButton(taskBar->taskbarId)) taskBar = NULL; } if (taskBar && (info->hwnd != taskBar->startButton) && taskBar->oldButton) { // steal messages from other than our custom button window PostMessage(taskBar->oldButton, (UINT)wParam, 0, MAKELPARAM(info->pt.x, info->pt.y)); return 1; } } } return CallNextHookEx(NULL, code, wParam, lParam); } // WH_GETMESSAGE hook for the taskbar thread static LRESULT CALLBACK HookDesktopThread( int code, WPARAM wParam, LPARAM lParam ) { if (code==HC_ACTION && wParam && !g_bInMenu) { MSG *msg=(MSG*)lParam; FindTaskBar(); if (IsSettingsMessage(msg)) { msg->message=WM_NULL; return 0; } if (!g_bTrimHooks) { if (((msg->message>=WM_MOUSEFIRST && msg->message<=WM_MOUSELAST) || msg->message==WM_MOUSEHOVER || msg->message==WM_MOUSELEAVE) && GetWinVersion()<=WIN_VER_WIN7 && CMenuContainer::ProcessMouseMessage(msg->hwnd,msg->message,msg->wParam,msg->lParam)) { msg->message=WM_NULL; return 0; } } if (msg->message==g_StartMenuMsg && msg->hwnd==g_TaskBar) { msg->message=WM_NULL; static bool bProcessing; // prevent reentry if (!bProcessing) { FindWindowsMenu(); bProcessing=true; if (msg->wParam==MSG_TOGGLE || (msg->wParam==MSG_OPEN && !CMenuContainer::IsMenuOpened())) { const TaskbarInfo *taskBar=GetDefaultTaskbarInfo(); ToggleStartMenu(taskBar->taskbarId,true); } else if (msg->wParam==MSG_TOGGLENEW) { PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMK'); } else if (msg->wParam==MSG_SETTINGS) { if (GetSettingBool(L"EnableSettings")) EditSettings(false,0); } else if (msg->wParam==MSG_SHIFTWIN) { const TaskbarInfo *taskBar=GetDefaultTaskbarInfo(); int control=GetSettingInt(L"ShiftWin"); if (control==OPEN_BOTH) { if (GetWinVersion()>=WIN_VER_WIN10) control=GetWin10TabletMode()?OPEN_WINDOWS:OPEN_CLASSIC; else control=GetMetroMode(MonitorFromPoint(CPoint(GetMessagePos()),MONITOR_DEFAULTTONEAREST))?OPEN_WINDOWS:OPEN_CLASSIC; } if (control==OPEN_CLASSIC) ToggleStartMenu(taskBar->taskbarId,true); else if (control==OPEN_WINDOWS) PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMK'); else if (control==OPEN_CORTANA) OpenCortana(); else if (control==OPEN_CUSTOM) { CString commandText=GetSettingString(L"ShiftWinCommand"); if (!commandText.IsEmpty()) { wchar_t expandedCommand[_MAX_PATH]{}; ::ExpandEnvironmentStrings(commandText, expandedCommand, _countof(expandedCommand)); ShellExecute(NULL,NULL,expandedCommand,NULL,NULL,SW_SHOWNORMAL); } } } else if (msg->wParam==MSG_DRAG || msg->wParam==MSG_SHIFTDRAG) { const TaskbarInfo *taskBar=GetTaskbarInfo((int)msg->lParam); if (taskBar) { int control=GetSettingInt((msg->wParam==MSG_DRAG)?L"MouseClick":L"ShiftClick"); if (control==OPEN_BOTH && GetWinVersion()>=WIN_VER_WIN10) control=GetWin10TabletMode()?OPEN_WINDOWS:OPEN_CLASSIC; if (control==OPEN_CLASSIC || (control==OPEN_WINDOWS && GetWinVersion()>=WIN_VER_WIN8)) ToggleStartMenu(taskBar->taskbarId,true); else if (control==OPEN_WINDOWS) PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMM'); } } else if (msg->wParam==MSG_EXIT && CMenuContainer::CanShowMenu()) { LRESULT res=CallNextHookEx(NULL,code,wParam,lParam); CleanStartMenuDLL(); return res; // we should exit as quickly as possible now. the DLL is about to be unloaded } else if (msg->wParam==MSG_HOTKEYS) { EnableHotkeys((THotkeys)msg->lParam); } else if (msg->wParam==MSG_NEWTASKBAR) { HWND child=(HWND)msg->lParam; if (IsWindow(child)) { wchar_t className[100]; GetClassName(child,className,_countof(className)); if (_wcsicmp(className,L"Shell_SecondaryTrayWnd")==0) HandleSecondaryTaskbar((HWND)msg->lParam); else if (_wcsicmp(className,L"ToolbarWindow32")==0) { HWND taskbar=GetAncestor(child,GA_ROOT); TaskbarInfo *info=FindTaskBarInfoBar(taskbar); if (info && !info->HasPart(child) && GetParent(child)==info->rebar) { SetWindowSubclass(child,SubclassTaskbarPartProc,'CLSH',info->taskbarId); info->taskbarParts.push_back(child); } } else if (_wcsicmp(className,L"TrayClockWClass")==0 || _wcsicmp(className,L"ClockButton")==0) { HWND taskbar=GetAncestor(child,GA_ROOT); TaskbarInfo *info=FindTaskBarInfoBar(taskbar); if (info && !info->HasPart(child)) { SetWindowSubclass(child,SubclassTaskbarPartProc,'CLSH',info->taskbarId); info->taskbarParts.push_back(child); } } } } else if (msg->wParam==MSG_REDRAWTASKBAR) { if (msg->lParam) InvalidateRect((HWND)msg->lParam,NULL,TRUE); else RedrawTaskbars(); } else if (msg->wParam==MSG_RELOADSETTINGS) { LoadSettings(); UpdateTaskBars(TASKBAR_RECREATE_BUTTONS); UpdateTaskBars(TASKBAR_UPDATE_TEXTURE); ResetHotCorners(); RedrawTaskbars(); } bProcessing=false; } } if (!g_bTrimHooks) { if (msg->message==WM_HOTKEY && msg->hwnd==g_TaskBar) { if (msg->wParam==g_HotkeyShiftID) PostMessage(g_TaskBar,g_StartMenuMsg,MSG_SHIFTWIN,0); else if (msg->wParam==g_HotkeyCSMID) { msg->message=WM_NULL; const TaskbarInfo *taskBar=GetDefaultTaskbarInfo(); if (taskBar->startButton) SetForegroundWindow(taskBar->startButton); ToggleStartMenu(taskBar->taskbarId,true); } else if (msg->wParam==g_HotkeyWSMID) PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMK'); } if (msg->message==WM_KEYDOWN && msg->hwnd==g_TaskBar && (msg->wParam==VK_SPACE || msg->wParam==VK_RETURN)) { GUITHREADINFO info={sizeof(info)}; if (!GetGUIThreadInfo(GetCurrentThreadId(),&info) || !(info.flags&GUI_INMENUMODE)) { FindWindowsMenu(); int control=GetSettingInt(L"WinKey"); if (control==OPEN_BOTH) { if (GetWinVersion()>=WIN_VER_WIN10) control=GetWin10TabletMode()?OPEN_WINDOWS:OPEN_CLASSIC; else control=GetMetroMode(MonitorFromWindow(g_TaskBar,MONITOR_DEFAULTTONEAREST))?OPEN_WINDOWS:OPEN_CLASSIC; } if (control==OPEN_CLASSIC) { msg->message=WM_NULL; const TaskbarInfo *taskBar=FindTaskBarInfoBar(g_TaskBar); if (taskBar->startButton) SetForegroundWindow(taskBar->startButton); ToggleStartMenu(taskBar->taskbarId,true); } } } if (msg->message==WM_KEYDOWN && msg->wParam==VK_TAB && CMenuContainer::IsMenuWindow(msg->hwnd)) { // the taskbar steals the Tab key. we need to forward it to the menu instead SendMessage(msg->hwnd,msg->message,msg->wParam,msg->lParam); msg->message=WM_NULL; } if (msg->message==WM_SYSKEYDOWN && msg->wParam==VK_RETURN && CMenuContainer::IsMenuWindow(msg->hwnd)) { // the taskbar steals the Alt+Enter key. we need to forward it to the menu instead SendMessage(msg->hwnd,msg->message,msg->wParam,msg->lParam); msg->message=WM_NULL; } } bool bClick=(msg->message==WM_LBUTTONDOWN || msg->message==WM_LBUTTONDBLCLK || msg->message==WM_MBUTTONDOWN || msg->message==WM_MBUTTONDBLCLK); bool bNcClick=(msg->message==WM_NCLBUTTONDOWN || msg->message==WM_NCLBUTTONDBLCLK || msg->message==WM_NCMBUTTONDOWN || msg->message==WM_NCMBUTTONDBLCLK); bool bMiddle=(msg->message==WM_NCMBUTTONDOWN || msg->message==WM_MBUTTONDOWN || msg->message==WM_NCMBUTTONDBLCLK || msg->message==WM_MBUTTONDBLCLK); if (bClick || bNcClick) { const TaskbarInfo *taskBar=NULL; if (bClick) taskBar=FindTaskBarInfoButton(msg->hwnd); // click on start button if (!taskBar) { taskBar=FindTaskBarInfoBar(msg->hwnd); // click on taskbar if (taskBar && !PointAroundStartButton(taskBar->taskbarId)) taskBar=NULL; } if (taskBar) { if (msg->message==WM_LBUTTONDOWN && GetWinVersion()==WIN_VER_WIN7 && msg->hwnd==taskBar->startButton) { // on Win7 ignore the click if the mouse is not over the start button (clicks on the context menu are sent to the start button) CPoint pt(GetMessagePos()); if (WindowFromPoint(pt)!=msg->hwnd) { return CallNextHookEx(NULL,code,wParam,lParam); } } // left or middle click on start button FindWindowsMenu(); const wchar_t *name; const wchar_t *command; if (bMiddle) { name=L"MiddleClick"; command=L"MiddleClickCommand"; } else if (GetKeyState(VK_SHIFT)<0) { name=L"ShiftClick"; command=L"ShiftClickCommand"; } else { name=L"MouseClick"; command=L"MouseClickCommand"; } int control=GetSettingInt(name); if (control==OPEN_BOTH && GetWinVersion()>=WIN_VER_WIN10) control=GetWin10TabletMode()?OPEN_WINDOWS:OPEN_CLASSIC; if (control==OPEN_CLASSIC) { // click on the start button - toggle the menu DWORD keyboard; SystemParametersInfo(SPI_GETKEYBOARDCUES,NULL,&keyboard,0); ToggleStartMenu(taskBar->taskbarId,keyboard!=0); } else if (control==OPEN_WINDOWS) PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMM'); else if (control==OPEN_CORTANA) OpenCortana(); else if (control==OPEN_CUSTOM) { CString commandText=GetSettingString(command); if (!commandText.IsEmpty()) { wchar_t expandedCommand[_MAX_PATH]{}; ::ExpandEnvironmentStrings(commandText, expandedCommand, _countof(expandedCommand)); ShellExecute(NULL,NULL,expandedCommand,NULL,NULL,SW_SHOWNORMAL); } } msg->message=WM_NULL; } } if (msg->message==WM_LBUTTONUP) { // ignore button up on the win81 start button const TaskbarInfo *taskBar=FindTaskBarInfoButton(msg->hwnd); if (taskBar && taskBar->oldButton==msg->hwnd) msg->message=WM_NULL; } if (!g_bTrimHooks) { if (msg->message==WM_TIMER && FindTaskBarInfoBar(msg->hwnd) && CMenuContainer::IgnoreTaskbarTimers()) { // stop the taskbar timer messages. prevents the auto-hide taskbar from closing msg->message=WM_NULL; } if (msg->message==WM_MOUSEMOVE && g_ProgramsButton && msg->hwnd==g_ProgramsButton && GetSettingBool(L"CascadeAll") && !(msg->wParam&MK_SHIFT)) { DWORD pos=GetMessagePos(); if (pos!=g_LastHoverPos && !g_bAllProgramsTimer) { g_bAllProgramsTimer=true; bool bDef; DWORD time=GetSettingInt(L"AllProgramsDelay",bDef); if (bDef) SystemParametersInfo(SPI_GETMENUSHOWDELAY,NULL,&time,0); SetTimer(g_ProgramsButton,'CLSM',time,NULL); } g_LastHoverPos=pos; } if (msg->message==WM_TIMER && msg->wParam=='CLSM' && g_ProgramsButton && msg->hwnd==g_ProgramsButton) { g_bAllProgramsTimer=false; KillTimer(g_ProgramsButton,'CLSM'); DWORD pos=GetMessagePos(); if (pos==g_LastHoverPos) PostMessage(g_AllPrograms,WM_COMMAND,IDOK,(LPARAM)g_ProgramsButton); msg->message=WM_NULL; } if (msg->message==WM_MOUSELEAVE && g_ProgramsButton && msg->hwnd==g_ProgramsButton) { g_bAllProgramsTimer=false; KillTimer(g_ProgramsButton,'CLSM'); } // handle hover if (msg->message==WM_MOUSEMOVE) { TaskbarInfo *taskBar=FindTaskBarInfoButton(msg->hwnd); if (taskBar && !CMenuContainer::IsMenuOpened() && !WindowsMenuOpened()) { if (GetSettingInt(L"Hover") && !taskBar->bTimer) { taskBar->bTimer=true; int time=GetSettingInt(L"StartHoverDelay"); SetTimer(msg->hwnd,'CLSM',time,NULL); } if (msg->hwnd==taskBar->oldButton) { APPBARDATA appbar={sizeof(appbar)}; if (SHAppBarMessage(ABM_GETSTATE,&appbar)&ABS_AUTOHIDE) SendMessage(taskBar->taskBar,WM_NCHITTEST,0,GetMessagePos()); } } } if (msg->message==WM_MOUSELEAVE) { TaskbarInfo *taskBar=FindTaskBarInfoButton(msg->hwnd); if (taskBar) { taskBar->bTimer=false; KillTimer(msg->hwnd,'CLSM'); if (taskBar->oldButton==msg->hwnd) { RECT rc; GetWindowRect(taskBar->oldButton,&rc); CPoint pt(GetMessagePos()); if (PtInRect(&rc,pt)) { wchar_t className[256]={0}; GetClassName(WindowFromPoint(pt),className,_countof(className)); if (wcscmp(className,L"ImmersiveSwitchList")==0 || wcscmp(className,L"EdgeUiInputWndClass")==0) { msg->message=WM_NULL; TRACKMOUSEEVENT track={sizeof(track),TME_LEAVE,msg->hwnd,0}; TrackMouseEvent(&track); } } } } } if ((msg->message==WM_NCMOUSEMOVE || msg->message==WM_NCMOUSELEAVE) && (msg->wParam==HTCAPTION || !IsAppThemed()) && GetSettingInt(L"Hover")) // HACK: in Classic mode the start menu can show up even if wParam is not HTCAPTION (most likely a bug in Windows) { TaskbarInfo *taskBar=FindTaskBarInfoBar(msg->hwnd); if (taskBar) { if (!CMenuContainer::IsMenuOpened() && !WindowsMenuOpened() && PointAroundStartButton(taskBar->taskbarId)) { if (!taskBar->bTimer) { taskBar->bTimer=true; int time=GetSettingInt(L"StartHoverDelay"); SetTimer(taskBar->startButton,'CLSM',time,NULL); } } else { if (taskBar->bTimer) { taskBar->bTimer=false; KillTimer(taskBar->startButton,'CLSM'); } } } } if (msg->message==WM_TIMER && msg->wParam=='CLSM' && CMenuContainer::CanShowMenu()) { TaskbarInfo *taskBar=FindTaskBarInfoButton(msg->hwnd); if (taskBar) { KillTimer(msg->hwnd,'CLSM'); msg->message=WM_NULL; if (taskBar->bTimer && !CMenuContainer::IsMenuOpened() && !WindowsMenuOpened()) { CPoint pt(GetMessagePos()); if (WindowFromPoint(pt)==msg->hwnd || PointAroundStartButton(taskBar->taskbarId)) { int control=GetSettingInt(L"Hover"); if (control==OPEN_CLASSIC) { PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'CSM'); } else if (control==OPEN_WINDOWS) { FindWindowsMenu(); PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMM'); } else if (control==OPEN_CUSTOM) { CString commandText=GetSettingString(L"HoverCommand"); if (!commandText.IsEmpty()) { wchar_t expandedCommand[_MAX_PATH]{}; ::ExpandEnvironmentStrings(commandText, expandedCommand, _countof(expandedCommand)); ShellExecute(NULL,NULL,expandedCommand,NULL,NULL,SW_SHOWNORMAL); } } } } taskBar->bTimer=false; } } } // context menu if (msg->message==WM_NCRBUTTONUP || msg->message==WM_RBUTTONUP) { TaskbarInfo *taskBar=FindTaskBarInfoButton(msg->hwnd); DWORD winVer=GetWinVersion(); if (!taskBar && winVer>=WIN_VER_WIN8) { taskBar=FindTaskBarInfoBar(msg->hwnd); if (taskBar && !PointAroundStartButton(taskBar->taskbarId)) taskBar=NULL; } if (taskBar) { CPoint pt0(GetMessagePos()); if (msg->message==WM_RBUTTONUP && msg->hwnd==taskBar->startButton && msg->lParam==MAKELPARAM(-1,-1)) { RECT rc; GetWindowRect(msg->hwnd,&rc); pt0.x=(rc.left+rc.right)/2; pt0.y=(rc.top+rc.bottom)/2; } bool bShowCSMenu=false, bShowWinX=false, bShowWin7=false; if (msg->hwnd==taskBar->taskBar && taskBar->bReplaceButton) bShowWinX=true; else { bShowCSMenu=(GetSettingBool(L"ShiftRight")==(GetKeyState(VK_SHIFT)<0)); bShowWinX=winVer>=WIN_VER_WIN8 && !bShowCSMenu; } bShowWin7=!bShowCSMenu && g_WinStartButton && msg->hwnd!=g_WinStartButton; if (bShowCSMenu || bShowWinX || bShowWin7) { msg->message=WM_NULL; if (CMenuContainer::IsMenuOpened()) CMenuContainer::CloseStartMenu(); } if (bShowCSMenu) { // additional commands for the context menu enum { CMD_SETTINGS=1, CMD_HELP, CMD_EXIT, CMD_OPEN, CMD_OPEN_ALL, CMD_EXPLORER, CMD_OPEN_PINNED, }; // right-click on the start button - open the context menu (Settings, Help, Exit) HMENU menu=CreatePopupMenu(); CString titleFmt=LoadStringEx(IDS_MENU_TITLE); if (!titleFmt.IsEmpty()) { CString title; DWORD ver=GetVersionEx(g_Instance); title.Format(titleFmt,ver>>24,(ver>>16)&0xFF,ver&0xFFFF); AppendMenu(menu,MF_STRING,0,title); EnableMenuItem(menu,0,MF_BYPOSITION|MF_DISABLED); SetMenuDefaultItem(menu,0,TRUE); AppendMenu(menu,MF_SEPARATOR,0,0); } int count0=GetMenuItemCount(menu); if (GetSettingBool(L"EnableExplorer")) { if (!GetSettingString(L"ExplorerPath").IsEmpty()) AppendMenu(menu,MF_STRING,CMD_EXPLORER,FindTranslation(L"Menu.Explorer",L"Windows Explorer")); AppendMenu(menu,MF_STRING,CMD_OPEN,FindTranslation(L"Menu.Open",L"&Open")); if (!SHRestricted(REST_NOCOMMONGROUPS)) AppendMenu(menu,MF_STRING,CMD_OPEN_ALL,FindTranslation(L"Menu.OpenAll",L"O&pen All Users")); if (GetSettingInt(L"PinnedPrograms")==PINNED_PROGRAMS_PINNED) AppendMenu(menu,MF_STRING,CMD_OPEN_PINNED,FindTranslation(L"Menu.OpenPinned",L"O&pen Pinned")); AppendMenu(menu,MF_SEPARATOR,0,0); } if (GetSettingBool(L"EnableSettings")) AppendMenu(menu,MF_STRING,CMD_SETTINGS,FindTranslation(L"Menu.MenuSettings",L"Settings")); if (HasHelp()) AppendMenu(menu,MF_STRING,CMD_HELP,FindTranslation(L"Menu.MenuHelp",L"Help")); if (GetSettingBool(L"EnableExit")) { AppendMenu(menu,MF_STRING,CMD_EXIT,FindTranslation(L"Menu.MenuExit",L"Exit")); if (!CMenuContainer::CanShowMenu()) EnableMenuItem(menu,CMD_EXIT,MF_BYCOMMAND|MF_DISABLED); } if (GetMenuItemCount(menu)>count0) { MENUITEMINFO mii={sizeof(mii)}; mii.fMask=MIIM_BITMAP; mii.hbmpItem=HBMMENU_POPUP_CLOSE; SetMenuItemInfo(menu,CMD_EXIT,FALSE,&mii); MENUINFO info={sizeof(info),MIM_STYLE,MNS_CHECKORBMP}; SetMenuInfo(menu,&info); g_bInMenu=true; SetForegroundWindow(msg->hwnd); int res=TrackPopupMenu(menu,TPM_RIGHTBUTTON|TPM_RETURNCMD|(IsLanguageRTL()?TPM_LAYOUTRTL:0),pt0.x,pt0.y,0,msg->hwnd,NULL); DestroyMenu(menu); g_bInMenu=false; if (res==CMD_SETTINGS) { EditSettings(false,0); } if (res==CMD_HELP) { ShowHelp(); return TRUE; } if (res==CMD_EXIT) { LRESULT res=CallNextHookEx(NULL,code,wParam,lParam); CleanStartMenuDLL(); return res; // we should exit as quickly as possible now. the DLL is about to be unloaded } if (res==CMD_OPEN || res==CMD_OPEN_ALL) { CComString pPath; if (SUCCEEDED(ShGetKnownFolderPath((res==CMD_OPEN)?FOLDERID_StartMenu:FOLDERID_CommonStartMenu,&pPath))) ShellExecute(NULL,L"open",pPath,NULL,NULL,SW_SHOWNORMAL); } if (res==CMD_OPEN_PINNED) // open pinned folder { SHELLEXECUTEINFO execute={sizeof(execute)}; CString path=GetSettingString(L"PinnedItemsPath"); execute.lpVerb=L"open"; execute.lpFile=path; execute.nShow=SW_SHOWNORMAL; execute.fMask=SEE_MASK_DOENVSUBST; ShellExecuteEx(&execute); } if (res==CMD_EXPLORER) { CString path=GetSettingString(L"ExplorerPath"); ITEMIDLIST blank={0}; SHELLEXECUTEINFO execute={sizeof(execute)}; execute.lpVerb=L"open"; execute.lpFile=path; execute.nShow=SW_SHOWNORMAL; if (_wcsicmp(path,L"computer")==0) execute.lpFile=L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"; else if (_wcsicmp(path,L"libraries")==0) execute.lpFile=L"::{031E4825-7B94-4DC3-B131-E946B44C8DD5}"; else if (_wcsicmp(path,L"desktop")==0) { execute.fMask=SEE_MASK_IDLIST; execute.lpIDList=␣ execute.lpFile=NULL; } else { execute.fMask=SEE_MASK_DOENVSUBST; } ShellExecuteEx(&execute); } } } else if (bShowWinX) { ShowWinX(); } else if (bShowWin7) { CPoint pt(GetMessagePos()); ScreenToClient(g_WinStartButton,&pt); PostMessage(g_WinStartButton,WM_RBUTTONUP,wParam,MAKELONG(pt.x,pt.y)); } } } } return CallNextHookEx(NULL,code,wParam,lParam); } HBITMAP GetStartScreenIcon( int size ) { // for sizes >=64, use image directly // for sizes>=32, get 64x64 and scale down // for sizes<32 use the system background color StartScreenThumbInfo info={{size<64?64:size}}; info.size.cy=info.size.cx; if (size>=32 && g_AppManagerThread && GetWinVersion()==WIN_VER_WIN8) { info.event=CreateEvent(NULL,TRUE,FALSE,NULL); PostThreadMessage(g_AppManagerThread,g_StartMenuMsg,MSG_METROTHUMBNAIL,(LPARAM)&info); WaitForSingleObject(info.event,100); // if it takes more than 100ms, screw it CloseHandle(info.event); } info.size.cy=info.size.cx*3/4; BITMAPINFO bi={0}; bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth=bi.bmiHeader.biHeight=size; bi.bmiHeader.biPlanes=1; bi.bmiHeader.biBitCount=32; HDC hDst=CreateCompatibleDC(NULL); unsigned int *bits; HBITMAP bitmap=CreateDIBSection(hDst,&bi,DIB_RGB_COLORS,(void**)&bits,NULL,0); HGDIOBJ bmp0=SelectObject(hDst,bitmap); RECT rc={0,size/8,size,size*7/8}; if (info.bitmap) { HDC hSrc=CreateCompatibleDC(hDst); HGDIOBJ bmp02=SelectObject(hSrc,info.bitmap); SetStretchBltMode(hDst,HALFTONE); StretchBlt(hDst,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,hSrc,0,0,info.size.cx,info.size.cy,SRCCOPY); SelectObject(hSrc,bmp02); DeleteDC(hSrc); DeleteObject(info.bitmap); } else { typedef int (WINAPI *TGetImmersiveUserColorSetPreference)(bool bForceCheckRegistry, bool bSkipCheckOnFail); typedef DWORD (WINAPI *TGetImmersiveColorFromColorSetEx)(UINT dwImmersiveColorSet, UINT dwImmersiveColorType, bool bIgnoreHighContrast, UINT dwHighContrastCacheMode); typedef int (WINAPI *TGetImmersiveColorTypeFromName)(const wchar_t *name); COLORREF color=0; HMODULE hUxTheme=GetModuleHandle(L"uxtheme.dll"); if (hUxTheme) { TGetImmersiveUserColorSetPreference GetImmersiveUserColorSetPreference=(TGetImmersiveUserColorSetPreference)GetProcAddress(hUxTheme,MAKEINTRESOURCEA(98)); TGetImmersiveColorFromColorSetEx GetImmersiveColorFromColorSetEx=(TGetImmersiveColorFromColorSetEx)GetProcAddress(hUxTheme,MAKEINTRESOURCEA(95)); TGetImmersiveColorTypeFromName GetImmersiveColorTypeFromName=(TGetImmersiveColorTypeFromName)GetProcAddress(hUxTheme,MAKEINTRESOURCEA(96)); if (GetImmersiveUserColorSetPreference && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName) { int type=GetImmersiveColorTypeFromName(L"ImmersiveStartBackground"); int set=GetImmersiveUserColorSetPreference(false,false); color=GetImmersiveColorFromColorSetEx(set,type,false,0)&0xFFFFFF; } } SetDCBrushColor(hDst,color); FillRect(hDst,&rc,(HBRUSH)GetStockObject(DC_BRUSH)); HICON hIcon=(HICON)LoadImage(g_Instance,MAKEINTRESOURCE(GetWinVersion()>=WIN_VER_WIN10?IDI_START10:IDI_START),IMAGE_ICON,size,size,LR_DEFAULTCOLOR); DrawIconEx(hDst,0,0,hIcon,size,size,0,NULL,DI_NORMAL); DestroyIcon(hIcon); } SelectObject(hDst,bmp0); DeleteDC(hDst); int i=0; int n=size*rc.top; for (;i