[转]版权属于原作者!<br><br>unit SkinSB;<br><br>interface<br><br>uses<br> SysUtils, Classes, Windows, Messages, Graphics;<br><br>const<br> SKINSB_PROP = '{8BC6661E-5880-4353-878D-C3B3784CFC5F}';<br><br>type<br><br> TBarPosCode = ( bpcNone,<br> bpcHArrowL, bpcHArrowR, bpcHPageL, bpcHPageR, bpcHThumb,<br> bpcVArrowU, bpcVArrowD, bpcVPageU, bpcVPageD, bpcVThumb,<br> bpcCross 
;<br><br> TWindowProc = function (hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;<br><br> PSkinSBInfo = ^TSkinSBInfo;<br> TSkinSBInfo = packed record<br> OldWndProc: TWindowProc;<br> Prevent: Boolean; // prevent style change message<br> Scrolling: Boolean;<br> Style: Cardinal; // real style<br> ThumbTrack: Boolean;<br> ThumbPos: Integer;<br> Tracking: Boolean; // tracking: click arrow or track thumb<br> end;<br><br> TSkinSB = class<br> protected<br> FBitmap: TBitmap;<br> constructor CreateInstance;<br> public<br> constructor Create;<br> destructor Destroy; override;<br> procedure InitSkinSB(H: HWND);<br> procedure UnInitSkinSB(H: HWND);<br> procedure DrawElem(H: HWND; Code: TBarPosCode; R: TRect; Down: Boolean);<br> end;<br><br>function GetSkinSB: TSkinSB;<br><br>function SkinSBWndProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;<br>function GetSkinSBInfo(hWnd: HWND): PSkinSBInfo;<br><br>implementation<br><br>uses<br> CommCtrl;<br><br>{$R *.res} <br><br>var<br> l_SkinSB: TSkinSB;<br> l_SkinSB_Prop: TATOM;<br><br>type<br> PImageImportDescriptor = ^TImageImportDescriptor;<br> TImageImportDescriptor = packed record<br> originalFirstThunk: DWORD; // or Characteristics: DWORD<br> TimeDateStamp: DWORD;<br> ForwarderChain: DWORD;<br> Name: DWORD;<br> FirstThunk: DWORD;<br> end;<br> PImageChunkData = ^TImageChunkData;<br> TImageChunkData = packed record<br> case Integer of<br> 0: ( ForwarderString: DWORD 
;<br> 1: ( Func: DWORD 
;<br> 2: ( ordinal: DWORD 
;<br> 3: ( AddressOfData: DWORD 
;<br> end;<br> PImageImportByName = ^TImageImportByName;<br> TImageImportByName = packed record<br> Hint: Word;<br> Name: array[0..0] of Byte;<br> end;<br><br>type<br> PHookRec = ^THookRec;<br> THookRec = packed record<br> OldFunc: Pointer;<br> NewFunc: Pointer;<br> end;<br><br>var<br> _HookGetScrollInfo: THookRec; <br><br>procedure HookApiInMod(ImageBase: Cardinal; ApiName: PChar; PHook: PHookRec);<br>var<br> pidh: PImageDosHeader;<br> pinh: PImageNtHeaders;<br> pSymbolTable: PIMAGEDATADIRECTORY;<br> piid: PIMAGEIMPORTDESCRIPTOR;<br> pitd_org, pitd_1st: PImageChunkData;<br> piibn: PImageImportByName;<br> pAPIFunction: Pointer;<br> written, oldAccess: DWORD;<br>begin<br> if ImageBase = 0 then Exit;<br> pidh := PImageDosHeader(ImageBase);<br> pinh := PImageNtHeaders(DWORD(ImageBase) + Cardinal(pidh^._lfanew));<br> pSymbolTable := @pinh^.OptionalHeader.DataDirectory[1];<br> piid := PImageImportDescriptor(DWORD(ImageBase) + pSymbolTable^.VirtualAddress);<br> repeat<br> pitd_org := PImageChunkData(DWORD(ImageBase) + piid^.OriginalFirstThunk);<br> pitd_1st := PImageChunkData(DWORD(ImageBase) + piid^.FirstThunk);<br> repeat<br> piibn := PImageImportByName(DWORD(ImageBase) + LPDWORD(pitd_org)^);<br> pAPIFunction := Pointer(pitd_1st^.Func);<br> if StrComp(ApiName, @piibn^.Name) = 0 then<br> begin<br> PHook^.OldFunc := pAPIFunction;<br> VirtualProtect(@(pitd_1st^.Func), SizeOf(DWORD), PAGE_WRITECOPY, oldAccess);<br> WriteProcessMemory(GetCurrentProcess(), @(pitd_1st^.Func), @PHook^.NewFunc, SizeOf(DWORD), written);<br> VirtualProtect(@(pitd_1st^.Func), SizeOf(DWORD), oldAccess, oldAccess);<br> end;<br> Inc(pitd_org);<br> Inc(pitd_1st);<br> until pitd_1st^.Func = 0;<br> Inc(piid);<br> until piid^.FirstThunk + piid^.OriginalFirstThunk + piid^.ForwarderChain + piid^.Name = 0;<br>end;<br><br>function GetSkinSBInfo(hWnd: HWND): PSkinSBInfo;<br>begin<br> Result := PSkinSBInfo( GetProp(hWnd, MAKEINTATOM(l_SkinSB_Prop)) 
;<br>end;<br><br>function GetSkinSB: TSkinSB;<br>begin<br> if l_SkinSB = nil then l_SkinSB := TSkinSB.CreateInstance;<br> Result := l_SkinSB;<br>end;<br><br>function CalcScrollBarRect(H: HWND; nBarCode: Cardinal): TRect;<br>var<br> Style, ExStyle: Cardinal;<br>begin<br> SetRect(Result, 0, 0, 0, 0);<br> Style := GetWindowLong(H, GWL_STYLE);<br> ExStyle := GetWindowLong(H, GWL_EXSTYLE);<br> if (nBarCode = SB_HORZ) and ((Style and WS_HSCROLL) = 0) then Exit;<br> if (nBarCode = SB_VERT) and ((Style and WS_VSCROLL) = 0) then Exit;<br> GetWindowRect(H, Result);<br> OffsetRect(Result, -Result.Left, -Result.Top);<br> if ((ExStyle and WS_EX_DLGMODALFRAME) <> 0)<br> or ((ExStyle and WS_EX_CLIENTEDGE) <> 0) then<br> begin<br> InflateRect(Result, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));<br> end;<br> // special: returns the cross<br> if nBarCode = SB_BOTH then<br> begin<br> if ((Style and WS_HSCROLL) = 0) or ((Style and WS_VSCROLL) = 0) then<br> begin<br> SetRect(Result, 0, 0, 0, 0);<br> Exit;<br> end; <br> Result.Top := Result.Bottom - GetSystemMetrics(SM_CYVSCROLL);<br> if (ExStyle and WS_EX_LEFTSCROLLBAR) <> 0 then Result.Right := Result.Left + GetSystemMetrics(SM_CXHSCROLL)<br> else Result.Left := Result.Right - GetSystemMetrics(SM_CXHSCROLL);<br> Exit;<br> end;<br> if nBarCode = SB_HORZ then<br> begin<br> // if (ExStyle and WS_EX_TOPSCROLLBAR) <> 0 then Result.Bottom := Result.Top + GetSystemMetrics(SM_CYVSCROLL)<br> Result.Top := Result.Bottom - GetSystemMetrics(SM_CYVSCROLL);<br> if ((Style and WS_VSCROLL) <> 0) then Dec(Result.Right, GetSystemMetrics(SM_CYVSCROLL));<br> end;<br> if nBarCode = SB_VERT then<br> begin<br> if (ExStyle and WS_EX_LEFTSCROLLBAR) <> 0 then Result.Right := Result.Left + GetSystemMetrics(SM_CXHSCROLL)<br> else Result.Left := Result.Right - GetSystemMetrics(SM_CXHSCROLL);<br> if ((Style and WS_HSCROLL) <> 0) then Dec(Result.Bottom, GetSystemMetrics(SM_CXHSCROLL));<br> end;<br>end;<br><br>type<br> TBarElem = (beArrow1, beBG, beThumb, beArrow2);<br> TBarElemRects = array[TBarElem] of TRect;<br><br>function CalcBarElemRects(hWnd: HWND; nBarCode: Integer): TBarElemRects;<br>var<br> R: TRect;<br> SI: TScrollInfo;<br> ThumbSize: Integer;<br> X, L, H, BlockH, BlockV: Integer;<br>begin<br> R := CalcScrollBarRect(hWnd, nBarCode);<br> SI.cbSize := SizeOf(SI);<br> SI.fMask := SIF_ALL;<br> GetScrollInfo(hWnd, nBarCode, SI);<br> Result[beArrow1] := R;<br> Result[beArrow2] := R;<br> Result[beBG] := R;<br> Result[beThumb] := R;<br> if nBarCode = SB_VERT then<br> begin<br> BlockV := GetSystemMetrics(SM_CYVSCROLL);<br> L := Result[beArrow1].Top + BlockV;<br> H := Result[beArrow2].Bottom - BlockV;<br> Result[beArrow1].Bottom := L;<br> Result[beArrow2].Top := H;<br>// Inc(L);<br>// Dec(H);<br> Result[beBG].Top := L;<br> Result[beBG].Bottom := H;<br> end<br> else<br> begin<br> BlockH := GetSystemMetrics(SM_CXHSCROLL);<br> L := Result[beArrow1].Left + BlockH;<br> H := Result[beArrow2].Right - BlockH;<br> Result[beArrow1].Right := L;<br> Result[beArrow2].Left := H;<br>// Inc(L);<br>// Dec(H);<br> Result[beBG].Left := L;<br> Result[beBG].Right := H;<br> end;<br> if SI.nMax - SI.nMin - Integer(SI.nPage) + 1 <= 0 then<br> begin<br> // max thumb, no thumb<br> if nBarCode = SB_VERT then<br> begin<br> Result[beThumb].Top := L;<br> Result[beThumb].Bottom := H;<br> end<br> else<br> begin<br> Result[beThumb].Left := L;<br> Result[beThumb].Right := H;<br> end;<br> Exit;<br> end;<br> ThumbSize := MulDiv(H - L, SI.nPage, SI.nMax - SI.nMin + 1);<br> X := L + MulDiv(SI.nTrackPos, H - ThumbSize - L, SI.nMax - Integer(SI.nPage) - SI.nMin + 1);<br> if nBarCode = SB_VERT then<br> begin<br> Result[beThumb].Top := X;<br> Result[beThumb].Bottom := X + ThumbSize;<br> end<br> else<br> begin<br> Result[beThumb].Left := X;<br> Result[beThumb].Right := X + ThumbSize;<br> end;<br>end;<br><br>function GetPtBarPos(H: HWND; Pt: TPoint): TBarPosCode;<br>var<br> R: TRect;<br> BR: TBarElemRects;<br>begin<br> Result := bpcNone;<br> R := CalcScrollBarRect(H, SB_HORZ);<br> InflateRect(R, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));<br> if PtInRect(R, Pt) then<br> begin<br> BR := CalcBarElemRects(H, SB_HORZ);<br> if PtInRect(BR[beArrow1], Pt) then Result := bpcHArrowL<br> else if PtInRect(BR[beThumb], Pt) then Result := bpcHThumb<br> else if PtInRect(BR[beArrow2], Pt) then Result := bpcHArrowR<br> else if Pt.X < BR[beThumb].Left then Result := bpcHPageL<br> else Result := bpcHPageR;<br> Exit;<br> end;<br> R := CalcScrollBarRect(H, SB_VERT);<br> InflateRect(R, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)); <br> if PtInRect(R, Pt) then<br> begin<br> BR := CalcBarElemRects(H, SB_VERT);<br> if PtInRect(BR[beArrow1], Pt) then Result := bpcVArrowU<br> else if PtInRect(BR[beThumb], Pt) then Result := bpcVThumb<br> else if PtInRect(BR[beArrow2], Pt) then Result := bpcVArrowD<br> else if Pt.Y < BR[beThumb].Top then Result := bpcVPageU<br> else Result := bpcVPageD;<br> Exit;<br> end;<br>end;<br><br>type<br> TGetScrollInfoFunc = function (H: HWND; Code: Integer; var SI: TScrollInfo): Boolean; stdcall;<br><br>function _SkinSB_GetScrollInfo(H: HWND; Code: Integer; var SI: TScrollInfo): Boolean; stdcall;<br>var<br> P: PSkinSBInfo;<br>begin<br> Result := TGetScrollInfoFunc(_HookGetScrollInf
ldFunc)(H, Code, SI);<br> P := GetSkinSBInfo(H);<br> if (P <> nil) and P^.ThumbTrack and ((SI.fMask and SIF_TRACKPOS) <> 0) then<br> begin<br> SI.nTrackPos := P^.ThumbPos;<br> end;<br>end;<br><br>{ TSkinSB }<br><br>constructor TSkinSB.Create;<br>begin<br> raise Exception.Create('use GetSkinSB.');<br>end;<br><br>constructor TSkinSB.CreateInstance;<br>begin<br> inherited;<br> _HookGetScrollInf
ldFunc := nil;<br> _HookGetScrollInfo.NewFunc := @_SkinSB_GetScrollInfo;<br> HookApiInMod( GetModuleHandle('comctl32.dll'), 'GetScrollInfo', @_HookGetScrollInfo 
;<br> FBitmap := TBitmap.Create;<br> FBitmap.LoadFromResourceName(hInstance, 'scrollbar');<br>end;<br><br>destructor TSkinSB.Destroy;<br>begin<br> FreeAndNil(FBitmap);<br> inherited;<br>end;<br><br>procedure TSkinSB.DrawElem(H: HWND; Code: TBarPosCode; R: TRect;<br> Down: Boolean);<br>var<br> Canvas: TCanvas;<br>begin<br> Canvas := TCanvas.Create;<br> try<br> Canvas.Handle := GetWindowDC(H);<br> try<br> case Code of<br> bpcHArrowL:<br> begin<br> if Down then BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16, FBitmap.Canvas.Handle, 64, 0, SRCCOPY)<br> else BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16, FBitmap.Canvas.Handle, 0, 0, SRCCOPY);<br> Exit;<br> end;<br> bpcHArrowR:<br> begin<br> if Down then BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16, FBitmap.Canvas.Handle, 80, 0, SRCCOPY)<br> else BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16, FBitmap.Canvas.Handle, 16, 0, SRCCOPY);<br> Exit;<br> end;<br> bpcHThumb:<br> begin<br> BitBlt(Canvas.Handle, R.Left, R.Top, 2, 16, FBitmap.Canvas.Handle, 128, 0, SRCCOPY);<br> BitBlt(Canvas.Handle, R.Right - 2, R.Top, 2, 16, FBitmap.Canvas.Handle, 142, 0, SRCCOPY);<br> StretchBlt(Canvas.Handle, R.Left + 2, R.Top, R.Right - R.Left - 4, 16, FBitmap.Canvas.Handle,<br> 130, 0, 12, 16, SRCCOPY);<br> Exit;<br> end;<br> bpcHPageL, bpcHPageR:<br> begin<br> if R.Right - R.Left < 4 then<br> begin<br> StretchBlt(Canvas.Handle, R.Left, R.Top, R.Right - R.Left, 16, FBitmap.Canvas.Handle,<br> 160, 0, 16, 16, SRCCOPY);<br> end<br> else<br> begin<br> BitBlt(Canvas.Handle, R.Left, R.Top, 2, 16, FBitmap.Canvas.Handle, 160, 0, SRCCOPY);<br> BitBlt(Canvas.Handle, R.Right - 2, R.Top, 2, 16, FBitmap.Canvas.Handle, 174, 0, SRCCOPY);<br> StretchBlt(Canvas.Handle, R.Left + 2, R.Top, R.Right - R.Left - 4, 16, FBitmap.Canvas.Handle,<br> 162, 0, 12, 16, SRCCOPY);<br> end;<br> Exit;<br> end;<br> bpcVArrowU:<br> begin<br> if Down then BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16, FBitmap.Canvas.Handle, 96, 0, SRCCOPY)<br> else BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16, FBitmap.Canvas.Handle, 32, 0, SRCCOPY);<br> Exit;<br> end;<br> bpcVArrowD:<br> begin<br> if Down then BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16, FBitmap.Canvas.Handle, 112, 0, SRCCOPY)<br> else BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16, FBitmap.Canvas.Handle, 48, 0, SRCCOPY);<br> Exit;<br> end;<br> bpcVThumb:<br> begin<br> BitBlt(Canvas.Handle, R.Left, R.Top, 16, 2, FBitmap.Canvas.Handle, 144, 0, SRCCOPY);<br> BitBlt(Canvas.Handle, R.Left, R.Bottom - 2, 16, 2, FBitmap.Canvas.Handle, 144, 14, SRCCOPY);<br> StretchBlt(Canvas.Handle, R.Left, R.Top + 2, 16, R.Bottom - R.Top - 4, FBitmap.Canvas.Handle,<br> 144, 2, 16, 12, SRCCOPY);<br> Exit;<br> end;<br> bpcVPageU, bpcVPageD:<br> begin<br> if R.Bottom - R.Top < 4 then<br> begin<br> StretchBlt(Canvas.Handle, R.Left, R.Top, 16, R.Bottom - R.Top, FBitmap.Canvas.Handle,<br> 176, 0, 16, 16, SRCCOPY);<br> end<br> else<br> begin<br> BitBlt(Canvas.Handle, R.Left, R.Top, 16, 2, FBitmap.Canvas.Handle, 176, 0, SRCCOPY);<br> BitBlt(Canvas.Handle, R.Left, R.Bottom - 2, 16, 2, FBitmap.Canvas.Handle, 176, 14, SRCCOPY);<br> StretchBlt(Canvas.Handle, R.Left, R.Top + 2, 16, R.Bottom - R.Top - 4, FBitmap.Canvas.Handle,<br> 176, 2, 16, 12, SRCCOPY);<br> end;<br> Exit;<br> end;<br> end;<br> Canvas.Pen.Color := clBlack;<br> Canvas.Brush.Color := clWhite;<br> Canvas.Rectangle(R);<br> finally<br> ReleaseDC(H, Canvas.Handle);<br> end;<br> finally<br> Canvas.Handle := 0;<br> FreeAndNil(Canvas);<br> end;<br>end;<br><br>procedure TSkinSB.InitSkinSB(H: HWND);<br>var<br> PInfo: PSkinSBInfo;<br>begin<br> PInfo := GetSkinSBInfo(H);<br> if PInfo <> nil then Exit; // already inited<br> New(PInfo);<br> PInfo^.OldWndProc := TWindowProc(GetWindowLong(H, GWL_WNDPROC));<br> PInfo^.Style := GetWindowLong(H, GWL_STYLE);<br> PInfo^.Prevent := False;<br> PInfo^.Scrolling := False;<br> PInfo^.ThumbTrack := False;<br> SetWindowLong(H, GWL_WNDPROC, Cardinal(@SkinSBWndProc));<br> SetProp(H, MAKEINTATOM(l_SkinSB_Prop), Cardinal(PInfo));<br>end;<br><br>procedure TSkinSB.UnInitSkinSB(H: HWND);<br>var<br> PInfo: PSkinSBInfo;<br>begin<br> PInfo := GetSkinSBInfo(H);<br> if PInfo = nil then Exit; // not inited<br> RemoveProp(H, MAKEINTATOM(l_SkinSB_Prop));<br> SetWindowLong(H, GWL_WNDPROC, Cardinal(@PInfo^.OldWndProc));<br> Dispose(PInfo);<br>end;<br><br>const<br> WM_REPEAT_CLICK = WM_USER + $6478;<br><br>procedure OnRepeatClickTimer(hWnd: HWND; uMsg: UINT; idEvent: UINT; dwTime: DWORD); stdcall;<br>begin<br> KillTimer(0, idEvent);<br> PostThreadMessage(MainThreadID, WM_REPEAT_CLICK, 0, 0);<br>end;<br><br>procedure RedrawScrollBars(hWnd: HWND);<br>var<br> RHBar, RVBar, RCross: TRect;<br> BR: TBarElemRects;<br>begin<br> RHBar := CalcScrollBarRect(hWnd, SB_HORZ);<br> if not IsRectEmpty(RHBar) then<br> begin<br> BR := CalcBarElemRects(hWnd, SB_HORZ);<br> GetSkinSB.DrawElem(hWnd, bpcHPageL, Rect(BR[beBG].Left, BR[beBG].Top, BR[beThumb].Left, BR[beBG].Bottom), False);<br> GetSkinSB.DrawElem(hWnd, bpcHPageR, Rect(BR[beThumb].Right, BR[beBG].Top, BR[beBG].Right, BR[beBG].Bottom), False);<br> GetSkinSB.DrawElem(hWnd, bpcHThumb, BR[beThumb], False);<br> GetSkinSB.DrawElem(hWnd, bpcHArrowL, BR[beArrow1], False);<br> GetSkinSB.DrawElem(hWnd, bpcHArrowR, BR[beArrow2], False);<br> end;<br> RVBar := CalcScrollBarRect(hWnd, SB_VERT);<br> if not IsRectEmpty(RVBar) then<br> begin<br> BR := CalcBarElemRects(hWnd, SB_VERT);<br> GetSkinSB.DrawElem(hWnd, bpcVPageU, Rect(BR[beBG].Left, BR[beBG].Top, BR[beBG].Right, BR[beThumb].Top), False);<br> GetSkinSB.DrawElem(hWnd, bpcVPageD, Rect(BR[beBG].Left, BR[beThumb].Bottom, BR[beBG].Right, BR[beBG].Bottom), False);<br> GetSkinSB.DrawElem(hWnd, bpcVThumb, BR[beThumb], False);<br> GetSkinSB.DrawElem(hWnd, bpcVArrowU, BR[beArrow1], False);<br> GetSkinSB.DrawElem(hWnd, bpcVArrowD, BR[beArrow2], False);<br> end;<br> RCross := CalcScrollBarRect(hWnd, SB_BOTH);<br> if not IsRectEmpty(RCross) then<br> begin<br> GetSkinSB.DrawElem(hWnd, bpcCross, RCross, False);<br> end;<br>end;<br><br>procedure TrackBar(hWnd: HWND; nBarCode: Integer; PosCode: TBarPosCode; BarElem: TBarElem; MsgCode: Integer);<br>var<br> BR: TBarElemRects;<br> Msg: tagMSG;<br> Pt: TPoint;<br> R: TRect;<br> ScrollMsg: Cardinal;<br> RepeatClick: Boolean;<br> idEvent: UINT;<br> SI: TScrollInfo;<br><br> procedure RefreshRect;<br> begin<br> BR := CalcBarElemRects(hWnd, nBarCode);<br> R := BR[BarElem];<br> end;<br><br>begin<br> RepeatClick := False;<br> BR := CalcBarElemRects(hWnd, nBarCode);<br> R := BR[BarElem];<br> GetScrollInfo(hWnd, nBarCode, SI);<br> if nBarCode = SB_HORZ then ScrollMsg := WM_HSCROLL<br> else ScrollMsg := WM_VSCROLL;<br> if BarElem = beBG then<br> begin<br> if PosCode = bpcHPageL then R.Right := BR[beThumb].Left<br> else if PosCode = bpcHPageR then R.Left := BR[beThumb].Right<br> else if PosCode = bpcVPageU then R.Bottom := BR[beThumb].Top<br> else if PosCode = bpcVPageD then R.Top := BR[beThumb].Bottom;<br> end;<br> GetSkinSB.DrawElem(hWnd, PosCode, R, True);<br> GetSkinSBInfo(hWnd)^.Tracking := True;<br> idEvent := 0;<br> try<br> SetCapture(hWnd);<br> idEvent := SetTimer(0, 0, 1000, @OnRepeatClickTimer);<br> while GetCapture = hWnd do<br> begin<br> if not GetMessage(Msg, 0, 0, 0) then Break;<br> if (Msg.hwnd = 0) and (Msg.message = WM_REPEAT_CLICK) then<br> begin<br> GetCursorPos(Pt);<br> ScreenToClient(hWnd, Pt);<br> if PtInRect(R, Pt) then<br> begin<br> RepeatClick := True;<br> SendMessage(hWnd, ScrollMsg, MsgCode, 0);<br> SendMessage(hWnd, ScrollMsg, SB_ENDSCROLL, 0);<br> RefreshRect;<br> GetSkinSB.DrawElem(hWnd, PosCode, R, True);<br>// if MsgCode = SB_LINEDOWN then SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) + 1, False);<br> if MsgCode = SB_PAGEDOWN then SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) + Integer(SI.nPage), False);<br>// if MsgCode = SB_LINEUP then SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) - 1, False);<br> if MsgCode = SB_PAGEUP then SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) - Integer(SI.nPage), False);<br> RedrawScrollBars(hWnd);<br> SetTimer(0, 0, 80, @OnRepeatClickTimer);<br> end;<br> end<br> else if Msg.hwnd = hWnd then<br> begin<br> case Msg.message of<br> WM_LBUTTONUP:<br> begin<br> if RepeatClick then Break;<br> GetCursorPos(Pt);<br> ScreenToClient(hWnd, Pt);<br> if PtInRect(R, Pt) then<br> begin<br> SendMessage(hWnd, ScrollMsg, MsgCode, 0);<br> SendMessage(hWnd, ScrollMsg, SB_ENDSCROLL, 0);<br> RefreshRect;<br>// if MsgCode = SB_LINEDOWN then SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) + 1, False);<br> if MsgCode = SB_PAGEDOWN then SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) + Integer(SI.nPage), False);<br>// if MsgCode = SB_LINEUP then SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) - 1, False);<br> if MsgCode = SB_PAGEUP then SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) - Integer(SI.nPage), False);<br> end;<br> Break;<br> end;<br> end;<br> end;<br> DispatchMessage(Msg);<br> end;<br> finally<br> if idEvent <> 0 then KillTimer(0, idEvent);<br> if IsWindow(hWnd) then<br> begin<br> if GetCapture = hWnd then ReleaseCapture;<br> GetSkinSB.DrawElem(hWnd, PosCode, R, False);<br> GetSkinSBInfo(hWnd)^.Tracking := False;<br> end;<br> end;<br>end;<br><br>procedure TrackThumb(hWnd: HWND; nBarCode: Integer; PosCode: TBarPosCode; BarElem: TBarElem);<br>var<br> BR: TBarElemRects;<br> Msg: tagMSG;<br> Pt: TPoint;<br> DragX: Integer;<br> R: TRect;<br> ScrollMsg: Cardinal;<br> SI, SI2: TScrollInfo;<br> Pos: Integer;<br> H, L, ThumbSize, X: Integer;<br> Pushed: Boolean;<br><br> function ValidDragArea(ARect: TRect; APt: TPoint): Boolean;<br> begin<br> if nBarCode = SB_HORZ then Result := Abs((ARect.Bottom + ARect.Top) div 2 - APt.Y) < 150<br> else Result := Abs((ARect.Left + ARect.Right) div 2 - APt.X) < 150;<br> end;<br><br> function CalcPos(ARect: TRect; APt: TPoint; ADragX: Integer): Integer;<br> var<br> NewX: Integer;<br> begin<br> if nBarCode = SB_HORZ then NewX := APt.X - ADragX<br> else NewX := APt.Y - ADragX;<br> Result := SI.nMin + MulDiv(NewX - L, SI.nMax - Integer(SI.nPage) - SI.nMin + 1, H - L - ThumbSize);<br> if Result < SI.nMin then Result := SI.nMin;<br> if Result > SI.nMax - Integer(SI.nPage) + 1 then<br> Result := SI.nMax - Integer(SI.nPage) + 1;<br> end;<br><br> procedure UpdateDragBar(ADown: Boolean; APos: Integer = -10000);<br> var<br> W: Integer;<br> begin<br> BR := CalcBarElemRects(hWnd, nBarCode);<br> R := BR[BarElem];<br> if nBarCode = SB_HORZ then<br> begin<br> if APos <> -10000 then<br> begin<br> W := R.Right - R.Left;<br> if APos < BR[beArrow1].Right then APos := BR[beArrow1].Right;<br> if APos + W > BR[beArrow2].Left then APos := BR[beArrow2].Left - W;<br> R.Left := APos;<br> R.Right := APos + W;<br> end;<br> GetSkinSB.DrawElem(hWnd, bpcHPageL, Rect(BR[beBG].Left, BR[beBG].Top, R.Left, BR[beBG].Bottom), False);<br> GetSkinSB.DrawElem(hWnd, bpcHPageR, Rect(R.Right, BR[beBG].Top, BR[beBG].Right, BR[beBG].Bottom), False);<br> end<br> else<br> begin<br> if APos <> -10000 then<br> begin<br> W := R.Bottom - R.Top;<br> if APos < BR[beArrow1].Bottom then APos := BR[beArrow1].Bottom;<br> if APos + W >= BR[beArrow2].Top then APos := BR[beArrow2].Top - W - 1;<br> R.Top := APos;<br> R.Bottom := APos + W;<br> end;<br> GetSkinSB.DrawElem(hWnd, bpcVPageU, Rect(BR[beBG].Left, BR[beBG].Top, BR[beBG].Right, R.Top), False);<br> GetSkinSB.DrawElem(hWnd, bpcVPageD, Rect(BR[beBG].Left, R.Bottom, BR[beBG].Right, BR[beBG].Bottom), False);<br> end;<br> GetSkinSB.DrawElem(hWnd, PosCode, R, ADown);<br> OutputDebugString(PChar(Format('R=(%d,%d,%d,%d)', [R.Left, R.Top, R.Right, R.Bottom])));<br> end;<br><br>begin<br> BR := CalcBarElemRects(hWnd, nBarCode);<br> R := BR[BarElem];<br> if nBarCode = SB_HORZ then ScrollMsg := WM_HSCROLL<br> else ScrollMsg := WM_VSCROLL;<br> SI.cbSize := SizeOf(SI);<br> SI.fMask := SIF_ALL;<br> GetScrollInfo(hWnd, nBarCode, SI);<br> GetCursorPos(Pt);<br> ScreenToClient(hWnd, Pt);<br> if nBarCode = SB_HORZ then<br> begin<br> DragX := Pt.X - BR[beThumb].Left;<br> ThumbSize := BR[beThumb].Right - BR[beThumb].Left;<br> L := BR[beArrow1].Right;<br> H := BR[beArrow2].Left;<br> end<br> else<br> begin<br> DragX := Pt.Y - BR[beThumb].Top;<br> ThumbSize := BR[beThumb].Bottom - BR[beThumb].Top;<br> L := BR[beArrow1].Bottom;<br> H := BR[beArrow2].Top;<br> end;<br>{ if nBarCode = SB_HORZ then SendMessage(hWnd, WM_SYSCOMMAND, SC_HSCROLL, MAKELPARAM(Pt.X, Pt.Y))<br> else SendMessage(hWnd, WM_SYSCOMMAND, SC_VSCROLL, MAKELPARAM(Pt.X, Pt.Y)); }<br> GetSkinSBInfo(hWnd)^.Tracking := True;<br> UpdateDragBar(True);<br> try<br> SetCapture(hWnd);<br> while GetCapture = hWnd do<br> begin<br> if not GetMessage(Msg, 0, 0, 0) then Break;<br> if Msg.hwnd = hWnd then<br> begin<br> case Msg.message of<br> WM_MOUSEMOVE:<br> begin<br> Pushed := ValidDragArea(R, Pt);<br> GetCursorPos(Pt);<br> ScreenToClient(hWnd, Pt);<br> if ValidDragArea(R, Pt) then<br> begin<br> Pos := CalcPos(R, Pt, DragX);<br> if nBarCode = SB_HORZ then X := Pt.X - DragX<br> else X := Pt.Y - DragX;<br> end<br> else<br> begin<br> Pos := SI.nPos;<br> X := DragX;<br> end;<br> GetSkinSBInfo(hWnd)^.ThumbPos := Pos;<br> GetSkinSBInfo(hWnd)^.ThumbTrack := True;<br> SendMessage(hWnd, ScrollMsg, MAKEWPARAM(SB_THUMBTRACK, Pos), 0);<br> GetSkinSBInfo(hWnd)^.ThumbTrack := False;<br> UpdateDragBar(Pushed, X);<br> end;<br> WM_LBUTTONUP:<br> begin<br> GetCursorPos(Pt);<br> ScreenToClient(hWnd, Pt);<br> if ValidDragArea(R, Pt) then<br> begin<br> Pos := CalcPos(R, Pt, DragX);<br> SI2.cbSize := SizeOf(SI2);<br> SI2.fMask := SIF_ALL;<br> GetScrollInfo(hWnd, nBarCode, SI2);<br> SI2.nPos := Pos;<br> SI2.nTrackPos := Pos;<br> SetScrollInfo(hWnd, nBarCode, SI2, False);<br> SI2.nTrackPos := 0;<br> SI2.nPos := 0;<br> GetScrollInfo(hWnd, nBarCode, SI2);<br> SendMessage(hWnd, ScrollMsg, MAKEWPARAM(SB_THUMBPOSITION, Pos), 0);<br> SendMessage(hWnd, ScrollMsg, SB_ENDSCROLL, 0);<br> end;<br> Break;<br> end;<br> end;<br> end;<br> DispatchMessage(Msg);<br> end;<br> finally<br> if IsWindow(hWnd) then<br> begin<br> if GetCapture = hWnd then ReleaseCapture;<br> GetSkinSBInfo(hWnd)^.Tracking := False;<br> end;<br> UpdateDragBar(False);<br> end;<br>end;<br><br>function SkinSBWndProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;<br>var<br> PInfo: PSkinSBInfo;<br> Style, ExStyle: Cardinal;<br> R, RHBar, RVBar, RCross: TRect;<br> Pt: TPoint;<br> Rgn, Rgn2: HRGN;<br> PR: PRect;<br> BR: TBarElemRects;<br> XBar, YBar: Integer;<br>begin<br> PInfo := GetSkinSBInfo(hWnd);<br> if PInfo = nil then Result := DefWindowProc(hWnd, uMsg, wParam, lParam) //// error!!!<br> else<br> begin<br> case uMsg of<br> WM_NCHITTEST:<br> begin<br> GetCursorPos(Pt);<br> ScreenToClient(hWnd, Pt);<br> case GetPtBarPos(hWnd, Pt) of<br> bpcHArrowL:<br> begin<br> if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then<br> begin<br> if GetCapture <> hWnd then<br> TrackBar(hWnd, SB_HORZ, bpcHArrowL, beArrow1, SB_LINELEFT);<br> end;<br> Result := HTNOWhere;<br> Exit;<br> end;<br> bpcHArrowR:<br> begin<br> if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then<br> begin<br> if GetCapture <> hWnd then<br> TrackBar(hWnd, SB_HORZ, bpcHArrowR, beArrow2, SB_LINERIGHT);<br> end;<br> Result := HTNOWhere;<br> Exit;<br> end;<br> bpcHPageL:<br> begin<br> if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then<br> begin<br> if GetCapture <> hWnd then<br> begin<br> TrackBar(hWnd, SB_HORZ, bpcHPageL, beBG, SB_PAGELEFT);<br> RedrawScrollBars(hWnd);<br> end;<br> end;<br> Result := HTNOWhere;<br> Exit;<br> end;<br> bpcHPageR:<br> begin<br> if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then<br> begin<br> if GetCapture <> hWnd then<br> begin<br> TrackBar(hWnd, SB_HORZ, bpcHPageR, beBG, SB_PAGERIGHT);<br> RedrawScrollBars(hWnd);<br> end;<br> end;<br> Result := HTNOWhere;<br> Exit;<br> end;<br> bpcHThumb:<br> begin<br> if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then<br> begin<br> if GetCapture <> hWnd then<br> TrackThumb(hWnd, SB_HORZ, bpcHThumb, beThumb);<br> end;<br> Result := HTNOWhere;<br> Exit;<br> end;<br><br> bpcVArrowU:<br> begin<br> if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then<br> begin<br> if GetCapture <> hWnd then<br> TrackBar(hWnd, SB_VERT, bpcVArrowU, beArrow1, SB_LINELEFT);<br> end;<br> Result := HTNOWhere;<br> Exit;<br> end;<br> bpcVArrowD:<br> begin<br> if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then<br> begin<br> if GetCapture <> hWnd then<br> TrackBar(hWnd, SB_VERT, bpcVArrowD, beArrow2, SB_LINERIGHT);<br> end;<br> Result := HTNOWhere;<br> Exit;<br> end;<br> bpcVPageU:<br> begin<br> if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then<br> begin<br> if GetCapture <> hWnd then<br> begin<br> TrackBar(hWnd, SB_VERT, bpcVPageU, beBG, SB_PAGELEFT);<br> RedrawScrollBars(hWnd);<br> end;<br> end;<br> Result := HTNOWhere;<br> Exit;<br> end;<br> bpcVPageD:<br> begin<br> if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then<br> begin<br> if GetCapture <> hWnd then<br> begin<br> TrackBar(hWnd, SB_VERT, bpcVPageD, beBG, SB_PAGERIGHT);<br> RedrawScrollBars(hWnd);<br> end;<br> end;<br> Result := HTNOWhere;<br> Exit;<br> end;<br> bpcVThumb:<br> begin<br> if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then<br> begin<br> if GetCapture <> hWnd then<br> TrackThumb(hWnd, SB_VERT, bpcVThumb, beThumb);<br> end;<br> Result := HTNOWhere;<br> Exit;<br> end;<br> end;<br> end;<br> WM_HSCROLL:<br> begin<br> PInfo^.Scrolling := True;<br> Style := GetWindowLong(hWnd, GWL_STYLE);<br> PInfo^.Style := Style;<br> PInfo^.Prevent := True;<br> try<br> SetWindowLong(hWnd, GWL_STYLE, Style and (not (WS_VSCROLL or WS_HSCROLL)));<br> finally<br> PInfo^.Prevent := False;<br> end;<br> Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg, wParam, lParam);<br> RedrawScrollBars(hWnd);<br> PInfo^.Prevent := True;<br> try<br> SetWindowLong(hWnd, GWL_STYLE, Style);<br> finally<br> PInfo^.Prevent := False;<br> end;<br> PInfo^.Scrolling := False;<br> Exit;<br> end;<br><br> WM_VSCROLL:<br> begin<br> PInfo^.Scrolling := True;<br> Style := GetWindowLong(hWnd, GWL_STYLE);<br> PInfo^.Style := Style;<br> PInfo^.Prevent := True;<br> try<br> SetWindowLong(hWnd, GWL_STYLE, Style and (not (WS_VSCROLL or WS_HSCROLL)));<br> finally<br> PInfo^.Prevent := False;<br> end;<br> Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg, wParam, lParam);<br> PInfo^.Prevent := True;<br> try<br> SetWindowLong(hWnd, GWL_STYLE, Style);<br> finally<br> PInfo^.Prevent := False;<br> end;<br> PInfo^.Scrolling := False;<br> Exit;<br> end;<br> WM_STYLECHANGED:<br> begin<br> if wParam = GWL_STYLE then<br> begin<br> if PInfo^.Prevent then<br> begin<br> Result := 0;<br> Exit;<br> end<br> else<br> begin<br> PInfo^.Style := GetWindowLong(hWnd, GWL_STYLE);<br> end;<br> end;<br> end;<br> WM_NCCALCSIZE:<br> begin<br> Style := GetWindowLong(hWnd, GWL_STYLE);<br> ExStyle := GetWindowLong(hWnd, GWL_EXSTYLE);<br> XBar := GetSystemMetrics(SM_CXVSCROLL);<br> YBar := GetSystemMetrics(SM_CYHSCROLL);<br> if PInfo^.Scrolling then<br> begin<br> PInfo^.Prevent := True;<br> try<br> SetWindowLong(hWnd, GWL_STYLE, Style and (not (WS_HSCROLL or WS_VSCROLL))); // real style<br> finally<br> PInfo^.Prevent := False;<br> end;<br> end;<br> Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg, wParam, lParam);<br> if PInfo^.Scrolling then<br> begin<br> PR := PRect(lParam);<br> if (PInfo^.Style and WS_VSCROLL) <> 0 then<br> begin<br> if (ExStyle and WS_EX_LEFTSCROLLBAR) <> 0 then Inc(PR^.Left, XBar)<br> else Dec(PR^.Right, XBar);<br> end;<br> if (PInfo^.Style and WS_HSCROLL) <> 0 then<br> begin<br> Dec(PR^.Bottom, YBar);<br> end;<br> end;<br> if PInfo^.Scrolling then<br> begin<br> PInfo^.Prevent := True;<br> try<br> SetWindowLong(hWnd, GWL_STYLE, Style); // old style<br> finally<br> PInfo^.Prevent := False;<br> end;<br> end;<br> Exit;<br> end;<br> WM_NCPAINT:<br> begin<br> GetWindowRect(hWnd, R);<br> Pt := R.TopLeft;<br> if wParam = 1 then<br> begin<br> Rgn := CreateRectRgn(Pt.X, Pt.Y, Pt.X + R.Right, Pt.Y + R.Bottom);<br> end else Rgn := wParam;<br> RHBar := CalcScrollBarRect(hWnd, SB_HORZ);<br> OffsetRect(RHBar, Pt.X, PT.Y);<br> if not IsRectEmpty(RHBar) then<br> begin<br> BR := CalcBarElemRects(hWnd, SB_HORZ);<br> GetSkinSB.DrawElem(hWnd, bpcHPageL, Rect(BR[beBG].Left, BR[beBG].Top, BR[beThumb].Left, BR[beBG].Bottom), False);<br> GetSkinSB.DrawElem(hWnd, bpcHPageR, Rect(BR[beThumb].Right, BR[beBG].Top, BR[beBG].Right, BR[beBG].Bottom), False);<br> GetSkinSB.DrawElem(hWnd, bpcHThumb, BR[beThumb], False);<br> GetSkinSB.DrawElem(hWnd, bpcHArrowL, BR[beArrow1], False);<br> GetSkinSB.DrawElem(hWnd, bpcHArrowR, BR[beArrow2], False);<br> end;<br> Rgn2 := CreateRectRgn(RHBar.Left, RHBar.Top, RHBar.Right, RHBar.Bottom);<br> CombineRgn(Rgn, Rgn, Rgn2, RGN_DIFF);<br> DeleteObject(Rgn2);<br> RVBar := CalcScrollBarRect(hWnd, SB_VERT);<br> if not IsRectEmpty(RVBar) then<br> begin<br> BR := CalcBarElemRects(hWnd, SB_VERT);<br> GetSkinSB.DrawElem(hWnd, bpcVPageU, Rect(BR[beBG].Left, BR[beBG].Top, BR[beBG].Right, BR[beThumb].Top), False);<br> GetSkinSB.DrawElem(hWnd, bpcVPageD, Rect(BR[beBG].Left, BR[beThumb].Bottom, BR[beBG].Right, BR[beBG].Bottom), False);<br> GetSkinSB.DrawElem(hWnd, bpcVThumb, BR[beThumb], False);<br> GetSkinSB.DrawElem(hWnd, bpcVArrowU, BR[beArrow1], False);<br> GetSkinSB.DrawElem(hWnd, bpcVArrowD, BR[beArrow2], False);<br> end;<br> OffsetRect(RVBar, Pt.X, PT.Y);<br> Rgn2 := CreateRectRgn(RVBar.Left, RVBar.Top, RVBar.Right, RVBar.Bottom);<br> CombineRgn(Rgn, Rgn, Rgn2, RGN_DIFF);<br> DeleteObject(Rgn2);<br> RCross := CalcScrollBarRect(hWnd, SB_BOTH);<br> if not IsRectEmpty(RCross) then<br> begin<br> GetSkinSB.DrawElem(hWnd, bpcCross, RCross, False);<br> end;<br> OffsetRect(RCross, Pt.X, PT.Y);<br> Rgn2 := CreateRectRgn(RCross.Left, RCross.Top, RCross.Right, RCross.Bottom);<br> CombineRgn(Rgn, Rgn, Rgn2, RGN_DIFF);<br> DeleteObject(Rgn2);<br> Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg, Rgn, lParam);<br> if wParam = 1 then DeleteObject(Rgn);<br> Exit;<br> end;<br> WM_ERASEBKGND:<br> begin<br> Style := GetWindowLong(hWnd, GWL_STYLE);<br> PInfo^.Prevent := True;<br> try<br> SetWindowLong(hWnd, GWL_STYLE, Style and (not (WS_VSCROLL or WS_HSCROLL)));<br> finally<br> PInfo^.Prevent := False;<br> end;<br><br> Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg, wParam, lParam);<br> PInfo^.Prevent := True;<br> try<br> SetWindowLong(hWnd, GWL_STYLE, Style); // old style<br> finally<br> PInfo^.Prevent := False;<br> end;<br> Exit;<br> end;<br> WM_MOUSEWHEEL, WM_MOUSEMOVE:<br> begin<br> Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg, wParam, lParam);<br> if PInfo^.Tracking then Exit;<br> if (uMsg = WM_MOUSEMOVE) and ((wParam and MK_LBUTTON) = 0) then Exit;<br> RedrawScrollBars(hWnd);<br> Exit;<br> end;<br> end;<br> Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg, wParam, lParam);<br> end;<br>end;<br><br>initialization<br><br> l_SkinSB := nil;<br> l_SkinSB_Prop := GlobalAddAtom(SKINSB_PROP);<br><br>finalization<br><br> if Assigned(l_SkinSB) then FreeAndNil(l_SkinSB);<br><br>end.