Files
Open-Shell-Menu/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp

4354 lines
136 KiB
C++

// 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 <uxtheme.h>
#include <dwmapi.h>
#include <htmlhelp.h>
#include <dbghelp.h>
#include <set>
#include <Thumbcache.h>
#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<size_t,TaskbarInfo> 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<HWND> 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;
// ExplorerPatcher taskbar
static bool g_epTaskbar = false;
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<IUnknown> &ptr )
{
if (GetWinVersion()<WIN_VER_WIN8)
return false;
ptr.CoCreateInstance(CLSID_ImmersiveShell);
return ptr.p!=NULL;
}
///////////////////////////////////////////////////////////////////////////////
// COwnerWindow - a special window used as owner for some UI elements, like the ones created by IContextMenu::InvokeCommand.
// A menu window cannot be used because it may disappear immediately after InvokeCommand. Some UI elements, like the UAC-related
// stuff can be created long after InvokeCommand returns and the menu may be deleted by then.
class COwnerWindow: public CWindowImpl<COwnerWindow>
{
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<CMenuContainer*>::const_iterator it=CMenuContainer::s_Menus.begin();it!=CMenuContainer::s_Menus.end();++it)
if ((*it)->m_hWnd==(HWND)lParam)
return 0;
for (std::vector<CMenuContainer*>::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<HWND>::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<size_t,TaskbarInfo>::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<size_t,TaskbarInfo>::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<IDropTarget> 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)
{
if (RECT rc; GetWindowRgnBox(taskBar,&rc)!=ERROR)
{
MapWindowPoints(taskBar,NULL,(POINT*)&rc,2);
appbar.rc=rc;
}
*pRc=appbar.rc;
RECT rc;
GetWindowRect(taskBar,&rc);
if (appbar.uEdge==ABE_LEFT || appbar.uEdge==ABE_RIGHT)
{
if (pRc->top<rc.top) pRc->top=rc.top;
if (pRc->bottom>rc.bottom) pRc->bottom=rc.bottom;
}
else if (appbar.uEdge==ABE_TOP || appbar.uEdge==ABE_BOTTOM)
{
if (pRc->left<rc.left) pRc->left=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->left<info.rcWork.left)
OffsetRect(pRc,info.rcWork.left-pRc->left,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->top<info.rcWork.top)
OffsetRect(pRc,0,info.rcWork.top-pRc->top);
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.y<rc.bottom;
else if (rtl)
return pt.x>rc.left && pt.x<=rc.right;
else
return pt.x>=rc.left && pt.x<rc.right;
}
// declare few interfaces so we don't need the Win8 SDK
#ifndef __IAppVisibility_INTERFACE_DEFINED__
typedef enum MONITOR_APP_VISIBILITY
{
MAV_UNKNOWN = 0,
MAV_NO_APP_VISIBLE = 1,
MAV_APP_VISIBLE = 2
} MONITOR_APP_VISIBILITY;
MIDL_INTERFACE("6584CE6B-7D82-49C2-89C9-C6BC02BA8C38")
IAppVisibilityEvents : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE AppVisibilityOnMonitorChanged( HMONITOR hMonitor, MONITOR_APP_VISIBILITY previousMode, MONITOR_APP_VISIBILITY currentMode ) = 0;
virtual HRESULT STDMETHODCALLTYPE LauncherVisibilityChange( BOOL currentVisibleState ) = 0;
};
MIDL_INTERFACE("2246EA2D-CAEA-4444-A3C4-6DE827E44313")
IAppVisibility : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE GetAppVisibilityOnMonitor( HMONITOR hMonitor, MONITOR_APP_VISIBILITY *pMode ) = 0;
virtual HRESULT STDMETHODCALLTYPE IsLauncherVisible( BOOL *pfVisible ) = 0;
virtual HRESULT STDMETHODCALLTYPE Advise( IAppVisibilityEvents *pCallback, DWORD *pdwCookie ) = 0;
virtual HRESULT STDMETHODCALLTYPE Unadvise( DWORD dwCookie ) = 0;
};
#endif
void ResetHotCorners( void )
{
for (std::set<HWND>::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<IAppVisibility> 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()<WIN_VER_WIN10)
{
ResetHotCorners();
if (IsWin81Update1() && GetSettingBool(L"CustomTaskbar"))
PostMessage(g_TaskBar,g_StartMenuMsg,MSG_REDRAWTASKBAR,0);
}
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE LauncherVisibilityChange( BOOL currentVisibleState )
{
CComPtr<IUnknown> pImmersiveShell;
if (GetWinVersion()>=WIN_VER_WIN10 && CreateImmersiveShell(pImmersiveShell))
{
int taskbarId=-1;
if (currentVisibleState)
{
taskbarId=MAIN_TASK_BAR;
CComPtr<IImmersiveMonitor> pMonitor;
{
CComPtr<IImmersiveLauncher81> pLauncher;
IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher81,(void**)&pLauncher);
if (pLauncher)
pLauncher->GetMonitor(&pMonitor);
}
if (!pMonitor)
{
CComPtr<IImmersiveLauncher10RS> 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<IUnknown> pSite;
pObject->GetSite(IID_IUnknown,(void**)&pSite);
if (pSite)
{
if (msg->wParam==MSG_WINXMENU)
{
CPoint pt(msg->lParam);
CComPtr<ISwitchModeManager> 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<IImmersiveMonitorService> pMonitorService;
IUnknown_QueryService(pSite,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService);
if (pMonitorService)
{
HMONITOR monitor=MonitorFromPoint(pt,MONITOR_DEFAULTTONEAREST);
if (GetWinVersion()==WIN_VER_WIN8)
{
CComPtr<IUnknown> 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<IUnknown> pMonitor;
pMonitorService->GetFromHandle(monitor,&pMonitor);
if (pMonitor)
{
CComPtr<IImmersiveLauncher81> 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<IUnknown> pLauncher;
IUnknown_QueryService(pSite,SID_ImmersiveLauncher,IID_IImmersiveLauncherProvider,(void**)&pLauncher);
if (pLauncher)
{
CComPtr<IImmersiveLauncherThumbnailProvider> pProvider;
IUnknown_QueryService(pLauncher,SID_ImmersiveLauncherThumbnailProvider,IID_IImmersiveLauncherThumbnailProvider,(void**)&pProvider);
if (pProvider)
{
CComPtr<ISharedBitmap> 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<IImmersiveMonitorService> pMonitorService;
IUnknown_QueryService(pSite,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService);
if (pMonitorService)
{
CComPtr<IUnknown> pMonitor;
pMonitorService->GetFromHandle(monitor,&pMonitor);
if (pMonitor)
pMonitorService->SetImmersiveMonitor(pMonitor);
}
}
CComPtr<IImmersiveLauncher80> 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);
}
}
}
bool IsTouchTaskbar(void)
{
if (!IsWin11())
return false;
CRegKey regKey;
if (regKey.Open(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer") != ERROR_SUCCESS)
return false;
DWORD val;
return regKey.QueryDWORDValue(L"TabletPostureTaskbar", val) == ERROR_SUCCESS && val;
}
static void UpdateStartButtonPosition(const TaskbarInfo* taskBar, const WINDOWPOS* pPos)
{
if (IsStartButtonSmallIcons(taskBar->taskbarId) != IsTaskbarSmallIcons())
RecreateStartButton(taskBar->taskbarId);
RECT rcTask;
GetWindowRect(taskBar->taskBar, &rcTask);
if (IsTouchTaskbar())
{
if (RECT rc; GetWindowRgnBox(taskBar->taskBar, &rc) != ERROR)
{
MapWindowPoints(taskBar->taskBar, NULL, (POINT*)&rc, 2);
rcTask = rc;
}
}
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) && !g_epTaskbar)
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<CMenuContainer*>::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()<WIN_VER_WIN8)
{
Assert(GetCurrentThreadId()==GetWindowThreadProcessId(g_TaskBar,NULL));
EnumThreadWindows(GetCurrentThreadId(),FindWindowsMenuProc,0);
if (g_TopWin7Menu)
{
g_UserPic=FindWindow(L"Desktop User Picture",NULL);
SetWindowSubclass(g_UserPic,SubclassUserPicProc,'CLSH',0);
SetWindowSubclass(g_TopWin7Menu,SubclassTopMenuProc,'CLSH',0);
SetWindowSubclass(g_AllPrograms,SubclassProgramsProc,'CLSH',0);
}
}
}
static void PrintTaskbarBackground( HDC hdc, const RECT &rcClient, const RECT &rcPaint, UINT uEdge )
{
FillRect(hdc,&rcPaint,(HBRUSH)GetStockObject(BLACK_BRUSH));
HDC hsrc=CreateCompatibleDC(hdc);
HGDIOBJ bmp0=SelectObject(hsrc,g_TaskbarTexture);
int countH=1, countV=1;
int offsX=0, offsY=0;
if (g_TaskbarTileH==TILE_TILE)
{
countH=(rcClient.right-rcClient.left+g_TaskbarTextureSize.cx-1)/g_TaskbarTextureSize.cx;
if (uEdge==ABE_LEFT)
offsX=rcClient.right-rcClient.left-countH*g_TaskbarTextureSize.cx;
}
if (g_TaskbarTileV==TILE_TILE)
{
countV=(rcClient.bottom-rcClient.top+g_TaskbarTextureSize.cy-1)/g_TaskbarTextureSize.cy;
if (uEdge==ABE_TOP)
offsY=rcClient.bottom-rcClient.top-countV*g_TaskbarTextureSize.cy;
}
for (int y=0;y<countV;y++)
{
RECT rSrc={0,0,g_TaskbarTextureSize.cx,g_TaskbarTextureSize.cy};
RECT rDst=rcClient;
if (g_TaskbarTileV==TILE_TILE)
{
rDst.top+=g_TaskbarTextureSize.cy*y+offsY;
rDst.bottom=rDst.top+g_TaskbarTextureSize.cy;
}
if (rDst.bottom<=rcPaint.top) continue;
if (rDst.top>=rcPaint.bottom) break;
for (int x=0;x<countH;x++)
{
if (g_TaskbarTileH==TILE_TILE)
{
rDst.left=rcClient.left+g_TaskbarTextureSize.cx*x+offsX;
rDst.right=rDst.left+g_TaskbarTextureSize.cx;
}
if (rDst.right<=rcPaint.left) continue;
if (rDst.left>=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()<WIN_VER_WIN10 || look==TASKBAR_AEROGLASS || (look==TASKBAR_TRANSPARENT && g_TaskbarTexture))
{
memset(data,0,16);
}
else
{
bool bTransparent;
DWORD color0=GetMetroTaskbarColor(bTransparent);
data[0]=look+1; // 1 - opaque, 2 - transparent, 3 - glass
if (bDefLook)
data[0]=bTransparent?2:1;
data[1]=0x13;
int a=GetSettingInt(L"TaskbarOpacity")*255/100;
if ((TTaskbarLook)GetSettingInt(L"TaskbarLook")==TASKBAR_OPAQUE)
a=255;
if (a<0) a=0;
if (a>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<IUnknown> pImmersiveShell;
if (CreateImmersiveShell(pImmersiveShell))
{
CComPtr<IImmersiveMonitorService> pMonitorService;
IUnknown_QueryService(pImmersiveShell,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService);
if (pMonitorService)
{
CPoint pt(GetMessagePos());
HMONITOR monitor=MonitorFromPoint(pt,MONITOR_DEFAULTTONEAREST);
CComPtr<IUnknown> pMonitor;
pMonitorService->GetFromHandle(monitor,&pMonitor);
if (pMonitorService)
{
CComPtr<ILauncherTipContextMenu> 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()<WIN_VER_WIN10)
{
UINT uEdge=GetTaskbarPosition(hWnd,NULL,NULL,NULL);
int x=(uEdge==ABE_BOTTOM?-1:0);
SetWindowPos(taskBar->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()<WIN_VER_WIN10)
{
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
UpdateTaskBars(TASKBAR_UPDATE_TEXTURE);
return res;
}
if (uMsg==WM_PAINT && taskBar)
{
if (taskBar->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<IUnknown> pSite;
pObject->GetSite(IID_IUnknown,(void**)&pSite);
if (pSite)
{
CComPtr<IImmersiveLauncher80> 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<HWND>::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<HWND>::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<count;i++)
{
REBARBANDINFO info={sizeof(info),RBBIM_CHILD};
if (SendMessage(taskBar.rebar,RB_GETBANDINFO,i,(LPARAM)&info))
{
wchar_t name[100];
GetClassName(info.hwndChild,name,_countof(name));
if (_wcsicmp(name,L"ToolbarWindow32")==0 && !taskBar.HasPart(info.hwndChild))
{
SetWindowSubclass(info.hwndChild,SubclassTaskbarPartProc,'CLSH',taskBar.taskbarId);
taskBar.taskbarParts.push_back(info.hwndChild);
}
}
}
}
if (bPrimary)
{
HWND tray=FindWindowEx(taskBar.taskBar,NULL,L"TrayNotifyWnd",NULL);
if (tray)
{
HWND clock=FindWindowEx(tray,NULL,L"TrayClockWClass",NULL);
if (clock && !taskBar.HasPart(clock))
{
SetWindowSubclass(clock,SubclassTaskbarPartProc,'CLSH',taskBar.taskbarId);
taskBar.taskbarParts.push_back(clock);
}
if (GetWinVersion()<=WIN_VER_WIN81)
{
taskBar.desktop=FindWindowEx(tray,NULL,L"TrayShowDesktopButtonWClass",NULL);
if (taskBar.desktop)
SetWindowSubclass(taskBar.desktop,SubclassDesktopButtonProc,'CLSH',taskBar.taskbarId);
}
}
}
else if (GetWinVersion()>=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 && GetTaskbarPosition(taskBar.taskBar,NULL,NULL,NULL)==ABE_BOTTOM)
SetWindowPos(taskBar.oldButton,NULL,-1,0,0,0,SWP_NOSIZE|SWP_NOZORDER);
SetWindowSubclass(taskBar.oldButton,SubclassWin81StartButton,'CLSH',taskBar.taskbarId);
}
}
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_WIN10 && (!bDefColor || !bDefOpacity))
{
if (bDefColor && 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;i<count;i++)
bits[i]=val;
}
DeleteDC(hdc);
}
if (g_TaskbarTexture)
{
BITMAP info;
GetObject(g_TaskbarTexture,sizeof(info),&info);
int a=255;
BOOL comp=FALSE;
if (look!=TASKBAR_OPAQUE && SUCCEEDED(DwmIsCompositionEnabled(&comp)) && comp)
a=opacity*255/100;
if (a<0) a=0;
if (a<255)
{
int count=info.bmHeight*info.bmWidthBytes;
unsigned char *ptr=(unsigned char*)info.bmBits;
for (int i=0;i<count;i++,ptr++)
*ptr=*ptr*a/255;
}
g_TaskbarTextureSize.cx=info.bmWidth;
g_TaskbarTextureSize.cy=info.bmHeight;
int countH=g_TaskbarTileH==TILE_TILE?(255+info.bmWidth)/info.bmWidth:1;
int countV=g_TaskbarTileV==TILE_TILE?(255+info.bmHeight)/info.bmHeight:1;
if (countH>1 || 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;y<countV;y++)
for (int x=0;x<countH;x++)
BitBlt(hdc,x*info.bmWidth,y*info.bmHeight,info.bmWidth,info.bmHeight,hsrc,0,0,SRCCOPY);
SelectObject(hsrc,bmp02);
SelectObject(hdc,bmp01);
DeleteObject(g_TaskbarTexture);
g_TaskbarTexture=bmp;
g_TaskbarTextureSize.cx*=countH;
g_TaskbarTextureSize.cy*=countV;
}
DeleteDC(hsrc);
DeleteDC(hdc);
}
}
for (id_taskbar_map::iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
RedrawWindow(it->second.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()<WIN_VER_WIN10)
{
DWM_BLURBEHIND blur={DWM_BB_ENABLE,GetWinVersion()<WIN_VER_WIN8};
DwmEnableBlurBehindWindow(taskBar.taskBar,&blur);
if (GetWinVersion()==WIN_VER_WIN7)
{
MARGINS margins={0};
DwmExtendFrameIntoClientArea(taskBar.taskBar,&margins);
}
}
}
}
for (id_taskbar_map::iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
{
TaskbarInfo &taskBar=it->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 IatHookData* g_ExtTextOutWHook = nullptr;
// used by ExplorerPatcher's custom implementation of `SHFillRectClr`
static BOOL WINAPI ExtTextOutW2(HDC hdc, int X, int Y, UINT fuOptions, const RECT* lprc, LPCWSTR lpString, UINT cbCount, const INT* lpDx)
{
if (fuOptions != ETO_OPAQUE || lpString || cbCount || lpDx || !g_CurrentTaskList || !g_TaskbarTexture || GetCurrentThreadId() != g_TaskbarThreadId)
return ExtTextOutW(hdc, X, Y, fuOptions, lprc, lpString, cbCount, lpDx);
return FALSE;
}
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 )
{
static bool initCalled = false;
if (initCalled)
return;
initCalled = true;
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(L"ep_taskbar.5.dll");
if (!module)
module = GetModuleHandle(L"ep_taskbar.2.dll");
if (module)
g_epTaskbar = true;
}
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);
// ExplorerPatcher compatibility
if (g_epTaskbar)
g_ExtTextOutWHook = SetIatHook(module, "gdi32.dll", "ExtTextOutW", ExtTextOutW2);
}
{
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 && GetTaskbarPosition(taskBar.taskBar,NULL,NULL,NULL)==ABE_BOTTOM)
SetWindowPos(taskBar.oldButton,NULL,-1,0,0,0,SWP_NOSIZE|SWP_NOZORDER);
SetWindowSubclass(taskBar.oldButton,SubclassWin81StartButton,'CLSH',taskBar.taskbarId);
}
}
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);
taskBar.news=FindWindowEx(g_TaskBar,NULL,L"DynamicContent2",NULL);
if (taskBar.news)
SetWindowSubclass(taskBar.news,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()<WIN_VER_WIN10)
{
HWND hwndAppManager=FindWindow(L"ApplicationManager_DesktopShellWindow",NULL);
if (hwndAppManager)
{
g_AppManagerThread=GetWindowThreadProcessId(hwndAppManager,NULL);
g_AppManagerHook=SetWindowsHookEx(WH_GETMESSAGE,HookAppManager,g_Instance,g_AppManagerThread);
}
if (GetWinVersion()==WIN_VER_WIN8 && GetSettingBool(L"SkipMetro"))
{
g_SkipMetroCount=abs(GetSettingInt(L"SkipMetroCount"));
SetTimer(g_TaskBar,'CLSM',500,NULL);
PostMessage(g_TaskBar,WM_TIMER,'CLSM',0);
}
}
EnumWindows(HookAllTaskbarsEnum,0);
}
g_NewWindowHook=SetWindowsHookEx(WH_CBT,HookNewWindow,g_Instance,GetCurrentThreadId());
UpdateTaskBars(TASKBAR_RECREATE_BUTTONS);
UpdateTaskBars(TASKBAR_UPDATE_TEXTURE);
}
static void RecreateStartButton( size_t taskbarId )
{
for (id_taskbar_map::iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
{
TaskbarInfo &taskBar=it->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));
if (taskBar.taskBar==g_TaskBar)
{
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_ExtTextOutWHook);
g_ExtTextOutWHook = 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()<WIN_VER_WIN10 && GetTaskbarPosition(it->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<HWND>::const_iterator it2=it->second.trayButtons.begin();it2!=it->second.trayButtons.end();++it2)
{
RemoveWindowSubclass(*it2,SubclassTrayButtonProc,'CLSH');
}
for (std::vector<HWND>::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.news)
RemoveWindowSubclass(it->second.news,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<IUnknown> pImmersiveShell;
if (GetWinVersion()>=WIN_VER_WIN10 && CreateImmersiveShell(pImmersiveShell))
{
{
CComPtr<IImmersiveLauncher81> pLauncher;
IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher81,(void**)&pLauncher);
BOOL bIsVisible;
if (pLauncher && SUCCEEDED(pLauncher->IsVisible(&bIsVisible)))
return bIsVisible!=0;
}
{
CComPtr<IImmersiveLauncher10RS> 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<IUnknown> pImmersiveShell;
if (CreateImmersiveShell(pImmersiveShell))
{
CComPtr<IUnknown> pMonitor;
if (GetWinVersion()==WIN_VER_WIN8)
{
if (monitor)
{
CComPtr<IImmersiveMonitorService> pMonitorService;
IUnknown_QueryService(pImmersiveShell,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService);
if (pMonitorService)
{
CComPtr<IUnknown> pMonitor;
pMonitorService->GetFromHandle(monitor,&pMonitor);
if (pMonitor)
pMonitorService->SetImmersiveMonitor(pMonitor);
}
}
CComPtr<IImmersiveLauncher80> pLauncher;
IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher80,(void**)&pLauncher);
if (pLauncher)
pLauncher->ShowStartView(5);
return;
}
if (monitor)
{
CComPtr<IImmersiveMonitorService> pMonitorService;
IUnknown_QueryService(pImmersiveShell,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService);
if (pMonitorService)
pMonitorService->GetFromHandle(monitor,&pMonitor);
}
{
CComPtr<IImmersiveLauncher81> 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<IImmersiveLauncher10RS> 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()<WIN_VER_WIN8 && !CMenuContainer::CanShowMenu())
msg->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=&blank;
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<n;i++)
bits[i]=0;
n=size*rc.bottom;
for (;i<n;i++)
bits[i]|=0xFF000000;
n=size*size;
for (;i<n;i++)
bits[i]=0;
return bitmap;
}
// WH_GETMESSAGE hook for the explorer's GUI thread. The start menu exe uses this hook to inject code into the explorer process
STARTMENUAPI LRESULT CALLBACK HookInject( int code, WPARAM wParam, LPARAM lParam )
{
if (code==HC_ACTION && !g_TaskBar)
InitStartMenuDLL();
return CallNextHookEx(NULL,code,wParam,lParam);
}
STARTMENUAPI void InitManagers( bool bNohook )
{
InitializeSkinManager(bNohook);
g_ItemManager.Init(); // must be after skin manager because it uses the metro colors
g_SearchManager.Init();
}
STARTMENUAPI void CloseManagers( bool bNohook )
{
g_SearchManager.Close();
g_ItemManager.Close();
CloseSkinManager(bNohook);
}
STARTMENUAPI bool DllGetSettingBool( const wchar_t *name )
{
return GetSettingBool(name);
}
STARTMENUAPI int DllGetSettingInt( const wchar_t *name )
{
return GetSettingInt(name);
}
STARTMENUAPI void DllUpdateSettings( void )
{
CSettingsLockWrite lock;
UpdateSettings();
}
STARTMENUAPI CString DllLoadStringEx( int stringID )
{
return LoadStringEx(stringID);
}
STARTMENUAPI void DllLogToFile( const wchar_t *location, const wchar_t *message, ... )
{
va_list args;
va_start(args,message);
VLogToFile(location,message,args);
va_end(args);
}
#ifndef _WIN64
STARTMENUAPI bool DllSaveAdmx( TSettingsComponent component, const char *admxFile, const char *admlFile, const char *docFile )
{
return SaveAdmx(component,admxFile,admlFile,docFile);
}
STARTMENUAPI void DllLoadTranslationResources( HINSTANCE hLngInstance, int *pDialogs )
{
LoadTranslationResources(hLngInstance,pDialogs);
}
#endif
#ifdef TRACK_GDI_RESOURCES
STARTMENUAPI void DllDumpResourceLeaks( void )
{
DumpResourceLeaks();
}
#endif