📄 coolsblib.c
字号:
/*
Cool Scrollbar Library Version 1.2
Module: coolsblib.c
Copyright (c) J Brown 2001
This code is freeware, however, you may not publish
this code elsewhere or charge any money for it. This code
is supplied as-is. I make no guarantees about the suitability
of this code - use at your own risk.
It would be nice if you credited me, in the event
that you use this code in a product.
VERSION HISTORY:
V1.2: TreeView problem fixed by Diego Tartara
Small problem in thumbsize calculation also fixed (thanks Diego!)
V1.1: Added support for Right-left windows
Changed calling convention of APIs to WINAPI (__stdcall)
Completely standalone (no need for c-runtime)
V1.0: Apr 2001: Initial Version
*/
#define STRICT
#include <windows.h>
#include <commctrl.h>
#include <tchar.h>
#include "coolscroll.h"
#include "userdefs.h"
#include "coolsb_internal.h"
static TCHAR szPropStr[] = _T("CoolSBSubclassPtr");
LRESULT CALLBACK CoolSBWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
SCROLLWND *GetScrollWndFromHwnd(HWND hwnd)
{
return (SCROLLWND *)GetProp(hwnd, szPropStr);
}
SCROLLBAR *GetScrollBarFromHwnd(HWND hwnd, UINT nBar)
{
SCROLLWND *sw = GetScrollWndFromHwnd(hwnd);
if(!sw) return 0;
if(nBar == SB_HORZ)
return &sw->sbarHorz;
else if(nBar == SB_VERT)
return &sw->sbarVert;
else
return 0;
}
BOOL WINAPI CoolSB_IsCoolScrollEnabled(HWND hwnd)
{
if(GetScrollWndFromHwnd(hwnd))
return TRUE;
else
return FALSE;
}
BOOL GetScrollRect(SCROLLWND *sw, UINT nBar, HWND hwnd, RECT *rect);
//
// Special support for USER32.DLL patching (using Detours library)
// The only place we call a real scrollbar API is in InitializeCoolSB,
// where we call EnableScrollbar.
//
// We HAVE to call the origial EnableScrollbar function,
// so we need to be able to set a pointer to this func when using
// using Detours (or any other LIB??)
//
static BOOL (WINAPI * pEnableScrollBar) (HWND, UINT, UINT) = 0;
void WINAPI CoolSB_SetESBProc(void *proc)
{
pEnableScrollBar = proc;
}
//
//
static void RedrawNonClient(HWND hwnd, BOOL fFrameChanged)
{
if(fFrameChanged == FALSE)
{
/*
RECT rect;
HRGN hrgn1, hrgn2;
SCROLLWND *sw = GetScrollWndFromHwnd(hwnd);
GetScrollRect(sw, SB_HORZ, hwnd, &rect);
hrgn1 = CreateRectRgnIndirect(&rect);
GetScrollRect(sw, SB_VERT, hwnd, &rect);
hrgn2 = CreateRectRgnIndirect(&rect);
CombineRgn(hrgn1, hrgn2, hrgn1, RGN_OR);
SendMessage(hwnd, WM_NCPAINT, (WPARAM)hrgn1, 0);
DeleteObject(hrgn1);
DeleteObject(hrgn2);*/
SendMessage(hwnd, WM_NCPAINT, (WPARAM)1, 0);
}
else
{
SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE
| SWP_FRAMECHANGED | SWP_DRAWFRAME);
}
}
//
// return the default minimum size of a scrollbar thumb
//
int WINAPI CoolSB_GetDefaultMinThumbSize(void)
{
DWORD dwVersion = GetVersion();
// set the minimum thumb size for a scrollbar. This
// differs between NT4 and 2000, so need to check to see
// which platform we are running under
if(dwVersion < 0x80000000) // Windows NT/2000
{
if(LOBYTE(LOWORD(dwVersion)) >= 5)
return MINTHUMBSIZE_2000;
else
return MINTHUMBSIZE_NT4;
}
else
{
return MINTHUMBSIZE_NT4;
}
}
static SCROLLINFO *GetScrollInfoFromHwnd(HWND hwnd, int fnBar)
{
SCROLLBAR *sb = GetScrollBarFromHwnd(hwnd, fnBar);
if(sb == 0)
return FALSE;
if(fnBar == SB_HORZ)
{
return &sb->scrollInfo;
}
else if(fnBar == SB_VERT)
{
return &sb->scrollInfo;
}
else
return NULL;
}
//
// Initialize the cool scrollbars for a window by subclassing it
// and using the coolsb window procedure instead
//
BOOL WINAPI InitializeCoolSB(HWND hwnd)
{
SCROLLWND *sw;
SCROLLINFO *si;
INITCOMMONCONTROLSEX ice;
TOOLINFO ti;
RECT rect;
DWORD dwCurStyle;
//BOOL fDisabled;
if(pEnableScrollBar == 0)
pEnableScrollBar = EnableScrollBar;
GetClientRect(hwnd, &rect);
//if we have already initialized Cool Scrollbars for this window,
//then stop the user from doing it again
if(GetScrollWndFromHwnd(hwnd) != 0)
{
return FALSE;
}
//allocate a private scrollbar structure which we
//will use to keep track of the scrollbar data
sw = (SCROLLWND *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SCROLLWND));
si = &sw->sbarHorz.scrollInfo;
si->cbSize = sizeof(SCROLLINFO);
si->fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_HORZ, si);
si = &sw->sbarVert.scrollInfo;
si->cbSize = sizeof(SCROLLINFO);
si->fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_VERT, si);
//check to see if the window has left-aligned scrollbars
if(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LEFTSCROLLBAR)
sw->fLeftScrollbar = TRUE;
else
sw->fLeftScrollbar = FALSE;
dwCurStyle = GetWindowLong(hwnd, GWL_STYLE);
SetProp(hwnd, szPropStr, (HANDLE)sw);
//try to enable the scrollbar arrows - if the return value is
//non-zero, then the scrollbars were previously disabled
//fDisabled = pEnableScrollBar(hwnd, SB_HORZ, ESB_ENABLE_BOTH);
//scrollbars will automatically get enabled, even if
//they aren't to start with....sorry, but there isn't an
//easy alternative.
if(dwCurStyle & WS_HSCROLL)
sw->sbarHorz.fScrollFlags = CSBS_VISIBLE;
if(dwCurStyle & WS_VSCROLL)
sw->sbarVert.fScrollFlags = CSBS_VISIBLE;
//need to be able to distinguish between horizontal and vertical
//scrollbars in some instances
sw->sbarHorz.nBarType = SB_HORZ;
sw->sbarVert.nBarType = SB_VERT;
sw->sbarHorz.fFlatScrollbar = CSBS_NORMAL;
sw->sbarVert.fFlatScrollbar = CSBS_NORMAL;
//set the default arrow sizes for the scrollbars
sw->sbarHorz.nArrowLength = SYSTEM_METRIC;
sw->sbarHorz.nArrowWidth = SYSTEM_METRIC;
sw->sbarVert.nArrowLength = SYSTEM_METRIC;
sw->sbarVert.nArrowWidth = SYSTEM_METRIC;
sw->bPreventStyleChange = FALSE;
sw->oldproc = (WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC, (LONG)CoolSBWndProc);
CoolSB_SetMinThumbSize(hwnd, SB_BOTH, CoolSB_GetDefaultMinThumbSize());
#ifdef COOLSB_TOOLTIPS
ice.dwSize = sizeof(ice);
ice.dwICC = ICC_BAR_CLASSES;
InitCommonControlsEx(&ice);
sw->hwndToolTip = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW, TOOLTIPS_CLASS, _T(""),
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hwnd, NULL, GetModuleHandle(0),
NULL);
ti.cbSize = sizeof(TOOLINFO);
ti.uFlags = TTF_IDISHWND;
ti.hwnd = hwnd;
ti.uId = (UINT)hwnd;
ti.lpszText = LPSTR_TEXTCALLBACK;
ti.hinst = GetModuleHandle(0);
SendMessage(sw->hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
#else
UNREFERENCED_PARAMETER(ice);
UNREFERENCED_PARAMETER(ti);
sw->hwndToolTip = 0;
#endif
//send the window a frame changed message to update the scrollbars
RedrawNonClient(hwnd, TRUE);
return TRUE;
}
BOOL WINAPI CoolSB_EnableScrollBar (HWND hwnd, int wSBflags, UINT wArrows)
{
SCROLLBAR *sbar;
UINT oldstate;
BOOL bFailed = FALSE;
if(!CoolSB_IsCoolScrollEnabled(hwnd))
return EnableScrollBar(hwnd, wSBflags, wArrows);
if((wSBflags == SB_HORZ || wSBflags == SB_BOTH) &&
(sbar = GetScrollBarFromHwnd(hwnd, SB_HORZ)))
{
oldstate = sbar->fScrollFlags;
//clear any existing state, and OR in the disabled flags
sbar->fScrollFlags = (sbar->fScrollFlags & ~ESB_DISABLE_BOTH) | wArrows;
if(oldstate == sbar->fScrollFlags)
bFailed = TRUE;
}
if((wSBflags == SB_VERT || wSBflags == SB_BOTH) &&
(sbar = GetScrollBarFromHwnd(hwnd, SB_VERT)))
{
oldstate = sbar->fScrollFlags;
//clear any existing state, and OR in the disabled flags
sbar->fScrollFlags = (sbar->fScrollFlags & ~ESB_DISABLE_BOTH) | wArrows;
if(oldstate == sbar->fScrollFlags)
bFailed = TRUE;
}
return !bFailed;
}
BOOL WINAPI CoolSB_GetScrollBarInfo(HWND hwnd)
{
// SCROLLBARINFO sbi; not defined in winuser.h
return FALSE;
}
BOOL WINAPI CoolSB_GetScrollInfo (HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
{
SCROLLINFO *mysi;
BOOL copied = FALSE;
if(!lpsi)
return FALSE;
if(!(mysi = GetScrollInfoFromHwnd(hwnd, fnBar)))
{
return GetScrollInfo(hwnd, fnBar, lpsi);
}
if(lpsi->fMask & SIF_PAGE)
{
lpsi->nPage = mysi->nPage;
copied = TRUE;
}
if(lpsi->fMask & SIF_POS)
{
lpsi->nPos = mysi->nPos;
copied = TRUE;
}
if(lpsi->fMask & SIF_TRACKPOS)
{
lpsi->nTrackPos = mysi->nTrackPos;
copied = TRUE;
}
if(lpsi->fMask & SIF_RANGE)
{
lpsi->nMin = mysi->nMin;
lpsi->nMax = mysi->nMax;
copied = TRUE;
}
return copied;
}
int WINAPI CoolSB_GetScrollPos (HWND hwnd, int nBar)
{
SCROLLINFO *mysi;
if(!(mysi = GetScrollInfoFromHwnd(hwnd, nBar)))
return GetScrollPos(hwnd, nBar);
return mysi->nPos;
}
BOOL WINAPI CoolSB_GetScrollRange (HWND hwnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos)
{
SCROLLINFO *mysi;
if(!lpMinPos || !lpMaxPos)
return FALSE;
if(!(mysi = GetScrollInfoFromHwnd(hwnd, nBar)))
return GetScrollRange(hwnd, nBar, lpMinPos, lpMaxPos);
*lpMinPos = mysi->nMin;
*lpMaxPos = mysi->nMax;
return TRUE;
}
int WINAPI CoolSB_SetScrollInfo (HWND hwnd, int fnBar, LPSCROLLINFO lpsi, BOOL fRedraw)
{
SCROLLINFO *mysi;
SCROLLBAR *sbar;
BOOL fRecalcFrame = FALSE;
if(!lpsi)
return FALSE;
if(!(mysi = GetScrollInfoFromHwnd(hwnd, fnBar)))
return SetScrollInfo(hwnd, fnBar, lpsi, fRedraw);
//if(CoolSB_IsThumbTracking(hwnd))
// return mysi->nPos;
if(lpsi->fMask & SIF_RANGE)
{
mysi->nMin = lpsi->nMin;
mysi->nMax = lpsi->nMax;
}
//The nPage member must specify a value from 0 to nMax - nMin +1.
if(lpsi->fMask & SIF_PAGE)
{
UINT t = (UINT)(mysi->nMax - mysi->nMin + 1);
mysi->nPage = min(max(0, lpsi->nPage), t);
}
//The nPos member must specify a value between nMin and nMax - max(nPage - 1, 0).
if(lpsi->fMask & SIF_POS)
{
mysi->nPos = max(lpsi->nPos, mysi->nMin);
mysi->nPos = min((UINT)mysi->nPos, mysi->nMax - max(mysi->nPage - 1, 0));
}
sbar = GetScrollBarFromHwnd(hwnd, fnBar);
if((lpsi->fMask & SIF_DISABLENOSCROLL) || (sbar->fScrollFlags & CSBS_THUMBALWAYS))
{
if(!sbar->fScrollVisible)
{
CoolSB_ShowScrollBar(hwnd, fnBar, TRUE);
fRecalcFrame = TRUE;
}
}
else
{
if( mysi->nPage > (UINT)mysi->nMax
|| mysi->nPage == (UINT)mysi->nMax && mysi->nMax == 0
|| mysi->nMax <= mysi->nMin)
{
if(sbar->fScrollVisible)
{
CoolSB_ShowScrollBar(hwnd, fnBar, FALSE);
fRecalcFrame = TRUE;
}
}
else
{
if(!sbar->fScrollVisible)
{
CoolSB_ShowScrollBar(hwnd, fnBar, TRUE);
fRecalcFrame = TRUE;
}
}
}
if(fRedraw && !CoolSB_IsThumbTracking(hwnd))
RedrawNonClient(hwnd, fRecalcFrame);
return mysi->nPos;
}
int WINAPI CoolSB_SetScrollPos(HWND hwnd, int nBar, int nPos, BOOL fRedraw)
{
SCROLLINFO *mysi;
int oldpos;
if(!(mysi = GetScrollInfoFromHwnd(hwnd, nBar)))
{
return SetScrollPos(hwnd, nBar, nPos, fRedraw);
}
//this is what should happen, but real scrollbars don't work like this..
//if(CoolSB_IsThumbTracking(hwnd))
// return mysi->nPos;
//validate and set the scollbar position
oldpos = mysi->nPos;
mysi->nPos = max(nPos, mysi->nMin);
mysi->nPos = min((UINT)mysi->nPos, mysi->nMax - max(mysi->nPage - 1, 0));
if(fRedraw && !CoolSB_IsThumbTracking(hwnd))
RedrawNonClient(hwnd, FALSE);
return oldpos;
}
int WINAPI CoolSB_SetScrollRange (HWND hwnd, int nBar, int nMinPos, int nMaxPos, BOOL fRedraw)
{
SCROLLINFO *mysi;
if(!(mysi = GetScrollInfoFromHwnd(hwnd, nBar)))
return SetScrollRange(hwnd, nBar, nMinPos, nMaxPos, fRedraw);
if(CoolSB_IsThumbTracking(hwnd))
return mysi->nPos;
//hide the scrollbar if nMin == nMax
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -