// 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 "ClassicIEDLL.h" #include "Settings.h" #include "ResourceHelper.h" #include "SettingsUIHelper.h" #include #include static _declspec(thread) SIZE g_SysButtonSize; // the size of the system buttons (close, minimize) for this thread's window static WNDPROC g_OldClassCaptionProc; static HBITMAP g_GlowBmp; static HBITMAP g_GlowBmpMax; static LONG g_bInjected; // the process is injected static int g_DPI; static UINT g_Message; // private message to detect if the caption is subclassed static ATOM g_SubclassAtom; struct CustomCaption { int leftPadding; int topPadding; int iconPadding; }; static CustomCaption g_CustomCaption[3]={ {2,3,10}, // Aero {4,2,10}, // Aero maximized {4,2,10}, // Basic }; void GetSysButtonSize( HWND hWnd ) { TITLEBARINFOEX titleInfo={sizeof(titleInfo)}; SendMessage(hWnd,WM_GETTITLEBARINFOEX,0,(LPARAM)&titleInfo); int buttonLeft=titleInfo.rgrect[2].left; if (buttonLeft>titleInfo.rgrect[5].left) buttonLeft=titleInfo.rgrect[5].left; int buttonRight=titleInfo.rgrect[2].right; if (buttonRightrc.bottom-iconSize) y=rc.bottom-iconSize; if (bIcon) { DrawIconEx(hdcPaint,rc.left,y,hIcon,iconSize,iconSize,0,NULL,DI_NORMAL|DI_NOMIRROR); rc.left+=iconSize; } rc.left+=g_CustomCaption[0].iconPadding; rc.bottom++; } else { // when the window is maximized, the caption bar is partially off-screen, so align the icon to the bottom rc.left+=g_CustomCaption[1].leftPadding; if (bIcon) { DrawIconEx(hdcPaint,rc.left,rc.bottom-iconSize-g_CustomCaption[1].topPadding,hIcon,iconSize,iconSize,0,NULL,DI_NORMAL|DI_NOMIRROR); rc.left+=iconSize; } rc.left+=g_CustomCaption[1].iconPadding; if (GetWinVersion()>=WIN_VER_WIN10) rc.bottom++; } if (GetWinVersion()rc.right-rc.left) textWidth=rc.right-rc.left; opts.dwFlags&=~DTT_CALCRECT; if (bGlow) { HDC hSrc=CreateCompatibleDC(hdcPaint); HGDIOBJ bmp0=SelectObject(hSrc,bMaximized?g_GlowBmpMax:g_GlowBmp); BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA}; AlphaBlend(hdcPaint,rc.left-11,rc.top,11,rc.bottom-rc.top,hSrc,0,0,11,24,func); AlphaBlend(hdcPaint,rc.left,rc.top,textWidth,rc.bottom-rc.top,hSrc,11,0,2,24,func); AlphaBlend(hdcPaint,rc.left+textWidth,rc.top,11,rc.bottom-rc.top,hSrc,13,0,11,24,func); SelectObject(hSrc,bmp0); DeleteDC(hSrc); } DrawThemeTextEx(theme,hdcPaint,0,0,caption,-1,DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS,&rc,&opts); SelectObject(hdcPaint,font0); EndBufferedPaint(hBufferedPaint,TRUE); } EndPaint(hWnd,&ps); } else { // Basic Theme // first draw the caption bar DefCaptionProc(hWnd,uMsg,wParam,lParam); // then draw the caption directly in the window DC HDC hdc=GetWindowDC(hWnd); // exclude the caption buttons rc.right-=g_SysButtonSize.cx+5; rc.top=rc.bottom-g_SysButtonSize.cy; rc.left+=g_CustomCaption[2].leftPadding; if (bIcon) { DrawIconEx(hdc,rc.left,rc.bottom-iconSize-g_CustomCaption[2].topPadding,hIcon,iconSize,iconSize,0,NULL,DI_NORMAL|DI_NOMIRROR); rc.left+=iconSize; } rc.left+=g_CustomCaption[2].iconPadding; HFONT font0=(HFONT)SelectObject(hdc,font); RECT rcText={0,0,0,0}; opts.dwFlags|=DTT_CALCRECT; DrawThemeTextEx(theme,hdc,0,0,caption,-1,DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE|DT_CALCRECT,&rcText,&opts); int textWidth=rcText.right-rcText.left; if (bCenter && textWidthrc.right-rc.left) textWidth=rc.right-rc.left; opts.dwFlags&=~DTT_CALCRECT; if (bGlow) { HDC hSrc=CreateCompatibleDC(hdc); HGDIOBJ bmp0=SelectObject(hSrc,bMaximized?g_GlowBmpMax:g_GlowBmp); BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA}; AlphaBlend(hdc,rc.left-11,rc.top,11,rc.bottom-rc.top,hSrc,0,0,11,24,func); AlphaBlend(hdc,rc.left,rc.top,textWidth,rc.bottom-rc.top,hSrc,11,0,2,24,func); AlphaBlend(hdc,rc.left+textWidth,rc.top,11,rc.bottom-rc.top,hSrc,13,0,11,24,func); SelectObject(hSrc,bmp0); DeleteDC(hSrc); } DrawThemeTextEx(theme,hdc,0,0,caption,-1,DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS,&rc,&opts); SelectObject(hdc,font0); ReleaseDC(hWnd,hdc); } DeleteObject(font); CloseThemeData(theme); return 0; } return DefCaptionProc(hWnd,uMsg,wParam,lParam); } // Replacement proc for the "Client Caption" class that hooks the main frame and the caption windows static LRESULT CALLBACK ClassCaptionProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if (uMsg==WM_CREATE) { WNDPROC proc=(WNDPROC)SetWindowLongPtr(hWnd,GWLP_WNDPROC,(LONG_PTR)SubclassCaptionProc); SetProp(hWnd,MAKEINTATOM(g_SubclassAtom),(HANDLE)proc); HWND frame=GetParent(hWnd); proc=(WNDPROC)SetWindowLongPtr(frame,GWLP_WNDPROC,(LONG_PTR)SubclassFrameProc); SetProp(frame,MAKEINTATOM(g_SubclassAtom),(HANDLE)proc); PostMessage(frame,g_Message,0,0); } return CallWindowProc(g_OldClassCaptionProc,hWnd,uMsg,wParam,lParam); } static BOOL CALLBACK EnumTopWindows( HWND hwnd, LPARAM lParam ) { DWORD processId; DWORD threadId=GetWindowThreadProcessId(hwnd,&processId); if (processId==GetCurrentProcessId()) { HWND caption=FindWindowEx(hwnd,NULL,L"Client Caption",NULL); if (caption) { LogToFile(CIE_LOG,L"InitClassicIE: caption=%p",caption); if (!g_OldClassCaptionProc) g_OldClassCaptionProc=(WNDPROC)SetClassLongPtr(caption,GCLP_WNDPROC,(LONG_PTR)ClassCaptionProc); WNDPROC proc=(WNDPROC)SetWindowLongPtr(caption,GWLP_WNDPROC,(LONG_PTR)SubclassCaptionProc); SetProp(caption,MAKEINTATOM(g_SubclassAtom),(HANDLE)proc); proc=(WNDPROC)SetWindowLongPtr(hwnd,GWLP_WNDPROC,(LONG_PTR)SubclassFrameProc); SetProp(hwnd,MAKEINTATOM(g_SubclassAtom),(HANDLE)proc); PostMessage(hwnd,g_Message,0,0); } } return TRUE; } void InitClassicIE( HMODULE hModule ) { CRegKey regKey; if (regKey.Open(HKEY_CURRENT_USER,GetSettingsRegPath())==ERROR_SUCCESS) { DWORD val; if (regKey.QueryDWORDValue(L"CustomAero",val)==ERROR_SUCCESS) { g_CustomCaption[0].leftPadding=(val&255); g_CustomCaption[0].topPadding=((val>>8)&255); g_CustomCaption[0].iconPadding=((val>>16)&255); } if (regKey.QueryDWORDValue(L"CustomAeroMax",val)==ERROR_SUCCESS) { g_CustomCaption[1].leftPadding=(val&255); g_CustomCaption[1].topPadding=((val>>8)&255); g_CustomCaption[1].iconPadding=((val>>16)&255); } if (regKey.QueryDWORDValue(L"CustomBasic",val)==ERROR_SUCCESS) { g_CustomCaption[2].leftPadding=(val&255); g_CustomCaption[2].topPadding=((val>>8)&255); g_CustomCaption[2].iconPadding=((val>>16)&255); } } g_Message=RegisterWindowMessage(L"ClassicIE.Injected"); g_SubclassAtom=GlobalAddAtom(L"ClassicIE.Subclass"); ChangeWindowMessageFilter(g_Message,MSGFLT_ADD); g_GlowBmp=(HBITMAP)LoadImage(g_Instance,MAKEINTRESOURCE(IDB_GLOW),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION); PremultiplyBitmap(g_GlowBmp,GetSettingInt(L"GlowColor")); g_GlowBmpMax=(HBITMAP)LoadImage(g_Instance,MAKEINTRESOURCE(IDB_GLOW),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION); PremultiplyBitmap(g_GlowBmpMax,GetSettingInt(L"MaxGlowColor")); EnumWindows(EnumTopWindows,0); }