文章类型: VC&C++
关键词: 支持x64版本的窗口内置滚动条皮肤库源码
内容摘要: 支持x64版本的窗口内置滚动条皮肤库源码

支持x64版本的窗口内置滚动条皮肤库源码,SkinSB皮肤滚动条库的使用

2016/10/9 14:55:58    来源:apple    阅读:

SkinSB皮肤滚动条库的使用
大家知道,win32窗口的内置滚动自绘是个非常棘手的问题,在写这篇文章之前首先感谢下CSDN的mynamelj,他写的那个SkinSB开源的时候我就开始使用来美化一般win32窗口的滚动条,很好用,但是最近有想把自己的应用迁移到x64平台的想法,所以必须把全部源码编译成64位的版本,以便能在win 64位下获得最佳性能,好了废话不多说,继续往下看。
改进SkinSB:
当时遇到两大难题,第一个是API钩子库detours在X64下用不了,第二个是skinsb自有源码小部分不适应64位。
对于第一个难题,当时到微软网站看了下其实detours 3.0版本有支持64位的,但是不是免费的,收费$9999一套,相当于7万RMB左右,这费用我等实在付不起,只好另找其他方法,经同事介绍mhook库,稍微看了下也是开源的,使用方法也很方便,就两个函数,一个Mhook_SetHook加载API钩子,一个Mhook_Unhook

Deom中的示例截图 


说明
     SkinSB库能为Windows标准控件或制定控件设置自定义滚动条皮肤,从而去达到美化控件的目的,如果觉得原Windows滚动条样式无法与你的程序界面搭配的话,那么SkinSB能帮你轻松的完成滚动条皮肤问题。该源代码为C语言编译通过,以标准API调用规范导出来函数,因此它可以在其它语言中使用,只需要将静态连接库改为动态链接库即可。

 

历史修订(V1.2)

2008-12-24
修正了RichEdit控件在拖动滑块时滑块没有反应的问题。

2009-05-20
修正了滚动条滑块在拖动时闪烁的问题。

2009-09-21
1.
修正了RichEidt设置皮肤滚动条后即使RichEdit中没有内容仍显示有滑块的问题。
2.
修正了无滑块时点击箭头时箭头被背景复盖的问题。
3.
修改了皮肤资源便于绘制时计算位图资源坐标。
4.
修正了水平滚动条箭头按下无法弹起的问题。
5.
修正了窗口在不活动状态时滑块显示不出来的问题。

 

使用说明

    首先你要确定的是你的控件是一个Windows控件还是一个自定义控件,如果是一个Windows控件那么就必须在程中去使用Detours库,这个库的功能就是截获指定的API函数并将这个API参数传递给你自已的函数处理,因为要绘制滚动条必须先获得滚动信息,由于Windows控件设置滚动信息是由系统完成的,所以就必须使用Detours获取滚动信息。有关Detours的技术资料请访问:http://research.microsoft.com/en-us/projects/detours/

 

下面就以MFC工程的Windows控件作为示例

 

1.首先将下列文件加入工程:

#include "detours.h"
#include "skinsb.h"
#pragma comment(lib, "detours.lib")
#pragma comment(lib, "skinsb.lib")


2.设置Detours截获系统设置的滚动信息传递给SkinSB 

申明HOOK API

DETOUR_TRAMPOLINE(int   WINAPI SetScrollInfoT(HWND, int, LPCSCROLLINFO, BOOL), SetScrollInfo)
DETOUR_TRAMPOLINE(BOOL  WINAPI GetScrollInfoT(HWND, int, LPSCROLLINFO), GetScrollInfo)
DETOUR_TRAMPOLINE(int   WINAPI SetScrollPosT(HWND, int, int, BOOL), SetScrollPos)
DETOUR_TRAMPOLINE(int   WINAPI GetScrollPosT(HWND, int), GetScrollPos)
DETOUR_TRAMPOLINE(BOOL  WINAPI GetScrollRangeT(HWND, int, LPINT, LPINT), GetScrollRange)
DETOUR_TRAMPOLINE(BOOL  WINAPI SetScrollRangeT(HWND, int, int, int, BOOL), SetScrollRange)
DETOUR_TRAMPOLINE(BOOL  WINAPI ShowScrollBarT(HWND, int, BOOL), ShowScrollBar)
DETOUR_TRAMPOLINE(BOOL  WINAPI EnableScrollBarT(HWND, UINT, UINT), EnableScrollBar)


HOOK到的函数的参数传递到SkinSB函数中

int WINAPI SetScrollInfoD(HWND hwnd, int fnBar, LPCSCROLLINFO lpsi, BOOL bRedraw)
{
 if( SkinSB_IsValid(hwnd) )
  return SkinSB_SetScrollInfo(hwnd, fnBar, lpsi, bRedraw);
 else
  return SetScrollInfoT(hwnd, fnBar, lpsi, bRedraw);
}

BOOL WINAPI GetScrollInfoD(HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
{
 if( SkinSB_IsValid(hwnd) )
  return SkinSB_GetScrollInfo(hwnd, fnBar, lpsi);
 else
  return GetScrollInfoT(hwnd, fnBar, lpsi);
}

int WINAPI SetScrollPosD(HWND hwnd, int nBar, int nPos, BOOL bRedraw)
{
 if( SkinSB_IsValid(hwnd) )
  return SkinSB_SetScrollPos(hwnd, nBar, nPos, bRedraw);
 else
  return SetScrollPosT(hwnd, nBar, nPos, bRedraw);
}

int WINAPI GetScrollPosD(HWND hwnd, int nBar)
{
 if( SkinSB_IsValid(hwnd) )
  return SkinSB_GetScrollPos(hwnd, nBar);
 else
  return GetScrollPosT(hwnd, nBar);
}

BOOL WINAPI SetScrollRangeD(HWND hwnd, int nBar, int nMinPos, int nMaxPos, BOOL bRedraw)
{
 if( SkinSB_IsValid(hwnd) )
  return SkinSB_SetScrollRange(hwnd, nBar, nMinPos, nMaxPos, bRedraw);
 else
  return SetScrollRangeT(hwnd, nBar, nMinPos, nMaxPos, bRedraw);
}

BOOL WINAPI GetScrollRangeD(HWND hwnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos)
{
 if( SkinSB_IsValid(hwnd) )
  return SkinSB_GetScrollRange(hwnd, nBar, lpMinPos, lpMaxPos);
 else
  return GetScrollRangeT(hwnd, nBar, lpMinPos, lpMaxPos);
}

BOOL WINAPI ShowScrollBarD(HWND hwnd, int nBar, BOOL bShow)
{
 if( SkinSB_IsValid(hwnd) )
  return SkinSB_ShowScrollBar(hwnd, nBar, bShow);
 else
  return ShowScrollBarT(hwnd, nBar, bShow);
}

BOOL WINAPI EnableScrollBarD(HWND hwnd, UINT wSBflags, UINT wArrows)
{
 if( SkinSB_IsValid(hwnd) )
  return SkinSB_EnableScrollBar(hwnd, wSBflags, wArrows);
 else
  return EnableScrollBarT(hwnd, wSBflags, wArrows);
}


加载API HOOK的代码,最好写在CXXXApp::InitInstance()函数中

DetourFunctionWithTrampoline((PBYTE)SetScrollInfoT, (PBYTE)SetScrollInfoD);
DetourFunctionWithTrampoline((PBYTE)GetScrollInfoT, (PBYTE)GetScrollInfoD);
DetourFunctionWithTrampoline((PBYTE)SetScrollPosT, (PBYTE)SetScrollPosD);
DetourFunctionWithTrampoline((PBYTE)GetScrollPosT, (PBYTE)GetScrollPosD);
DetourFunctionWithTrampoline((PBYTE)SetScrollRangeT, (PBYTE)SetScrollRangeD);
DetourFunctionWithTrampoline((PBYTE)GetScrollRangeT, (PBYTE)GetScrollRangeD);
DetourFunctionWithTrampoline((PBYTE)ShowScrollBarT, (PBYTE)ShowScrollBarD);
DetourFunctionWithTrampoline((PBYTE)EnableScrollBarT, (PBYTE)EnableScrollBarD);


卸载API HOOK,最好写在CXXXApp::ExitInstance()函数中

DetourRemove((PBYTE)SetScrollInfoT, (PBYTE)SetScrollInfoD);
DetourRemove((PBYTE)SetScrollPosT, (PBYTE)SetScrollPosD);
DetourRemove((PBYTE)GetScrollInfoT, (PBYTE)GetScrollInfoD);
DetourRemove((PBYTE)GetScrollPosT, (PBYTE)GetScrollPosD);
DetourRemove((PBYTE)SetScrollRangeT, (PBYTE)SetScrollRangeD);
DetourRemove((PBYTE)GetScrollRangeT, (PBYTE)GetScrollRangeD);
DetourRemove((PBYTE)ShowScrollBarT, (PBYTE)ShowScrollBarD);
DetourRemove((PBYTE)EnableScrollBarT, (PBYTE)EnableScrollBarD);


 3.在窗口初始化时为控件设置滚动条皮肤

BOOL CSkinSBDemoDlg::OnInitDialog()
{
   CDialog::OnInitDialog();

   //装入位图
    m_bmScroll.LoadBitmap(IDB_SCROLL);

   //为控件设置滚动条皮肤
    SkinSB_Init(GetDlgItem(IDC_LIST1)->GetSafeHwnd(), m_bmScroll);
    SkinSB_Init(GetDlgItem(IDC_EDIT1)->GetSafeHwnd(), m_bmScroll);

    return TRUE;
}


      以上代码就完成了针对Windows控件设置滚动条皮肤的工作,是不是很简单?那么怎样为自定义控件设置滚动条皮肤呢,其实你也可以用以上的方法为你的自定义控件设置滚动条皮肤,好处就是方便,坏处也是有的那就是要在工程中使用Detours库,虽然Detours体积不算大但是考虑到程序的效率和代码的简洁性宁原不使以Detours库。那么如何为自定义控件设置滚动条皮肤呢?SkinSB里导出了滚动条API函数,它的函数原型与Windows Scrollbar API是一样的,只不过每个函数前都有个SkinSB_XXX原因是不和Windows命名的API发生冲突,下面来看下这些函数的说明:

//------------------------------------------------------------------------------
// 函数名称:
//     SkinSB_Init
// 参数:
//     - HWND hwnd      指定一个需要加载皮肤滚动条的窗口句柄
//     - HBITMAP hBmp   指定一个位图句柄,滚动条皮肤位图
// 反回:
//     BOOL             如果函数成功反回一个非零值,否则反回为零
// 说明:
//                      初始化并给指定的控件加载滚动条皮肤
//------------------------------------------------------------------------------
BOOL WINAPI SkinSB_Init(HWND hwnd,HBITMAP hBmp);


//------------------------------------------------------------------------------
// 函数名称:
//     SkinSB_Uninit
// 参数:
//     - HWND hwnd      指定一个需要移除滚动条皮肤的窗口句柄
// 反回:
//     BOOL             如果函数成功反回一个非零值,否则反回为零
// 说明:
//                      移除窗口的滚动条皮肤,还原系统样式的滚动条
//------------------------------------------------------------------------------
BOOL WINAPI SkinSB_Uninit(HWND hwnd);


//------------------------------------------------------------------------------
// 函数名称:
//     SkinSB_IsValid
// 参数:
//     - HWND hwnd      指定一个窗口句柄
// 反回:
//     BOOL             如果函数成功反回一个非零值,否则反回为零
// 说明:
//                      确定一个窗口是否加载了皮肤滚动条
//------------------------------------------------------------------------------
BOOL WINAPI SkinSB_IsValid(HWND hwnd);

//------------------------------------------------------------------------------
// 函数名称:
//     SkinSB_GetScrollInfo
// 参数:
//     - HWND hwnd         指定一个窗口句柄
//     - int fnBar         指示是一个水平还是垂直的滚动条
//     - LPSCROLLINFO lpsi 指向滚动条滚动信息结构体指针
// 反回:
//     BOOL                如果函数成功反回一个非零值,否则反回为零
// 说明:
//                         获得滚动条的滚动信息参数
//------------------------------------------------------------------------------
BOOL WINAPI SkinSB_GetScrollInfo(HWND hwnd, int fnBar, LPSCROLLINFO lpsi);

//------------------------------------------------------------------------------
// 函数名称:
//     SkinSB_SetScrollInfo
// 参数:
//     - HWND hwnd         指定一个窗口句柄
//     - int fnBar         指示是一个水平还是垂直的滚动条
//     - LPSCROLLINFO lpsi 指向滚动条滚动信息结构体指针
//     - BOOL fRedraw      是否重绘滚动条,如果为真则重绘滚动条
// 反回:
//     int                 如果函数成功则反回滚动条滑块当前位置
// 说明:
//                         设置滚动条的滚动信息参数
//------------------------------------------------------------------------------
int  WINAPI SkinSB_SetScrollInfo(HWND hwnd, int fnBar, LPCSCROLLINFO psi, BOOL fRedraw);


//------------------------------------------------------------------------------
// 函数名称:
//     SkinSB_GetScrollPos
// 参数:
//     - HWND hwnd      指定一个窗口句柄
//     - int fnBar      指示是一个水平还是垂直的滚动条
// 反回:
//     int              如果函数成功则反回滚动条滑块当前位置
// 说明:
//                      获得滚动滑块当前位置
//------------------------------------------------------------------------------
int  WINAPI SkinSB_GetScrollPos(HWND hwnd, int fnBar);

//------------------------------------------------------------------------------
// 函数名称:
//     SkinSB_SetScrollPos
// 参数:
//     - HWND hwnd      指定一个窗口句柄
//     - int fnBar      指示是一个水平还是垂直的滚动条
//     - int nPos       指定一个期望的滚动条滑块位置
//     - BOOL fRedraw   是否重绘滚动条,如果为真则重绘滚动条
// 反回:
//     int              如果函数成功则反回期望的滚动条滑块位置
// 说明:
//                      设置滚动条滑块期望的位置
//------------------------------------------------------------------------------
int  WINAPI SkinSB_SetScrollPos(HWND hwnd, int nBar, int nPos, BOOL fRedraw);

//------------------------------------------------------------------------------
// 函数名称:
//     SkinSB_GetScrollRange
// 参数:
//     - HWND hwnd      指定一个窗口句柄
//     - int fnBar      指示是一个水平还是垂直的滚动条
//     - LPINT lpMinPos 指向一个int变量的指针,反回滚动条最小范围值
//     - LPINT lpMaxPos 指向一个int变量的指针,反回滚动条最大范围值
// 反回:
//     BOOL             如果函数成功反回一个非零值,否则反回为零
// 说明:
//                      获得滚动条滚动范围值
//------------------------------------------------------------------------------
BOOL WINAPI SkinSB_GetScrollRange(HWND hwnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos);

//------------------------------------------------------------------------------
// 函数名称:
//     SkinSB_SetScrollRange
// 参数:
//     - HWND hwnd      指定一个窗口句柄
//     - int fnBar      指示是一个水平还是垂直的滚动条
//     - int nMinPos    指定一个最小范围值
//     - int nMaxPos    指定一个最大范围值
//     - BOOL fRedraw   指示是否立即进行重绘,TRUE立即重绘FALSE不立即重会
// 反回:
//     BOOL             如果函数成功反回一个非零值,否则反回为零
// 说明:
//                      设置滚动条滚动范围值
//------------------------------------------------------------------------------
BOOL WINAPI SkinSB_SetScrollRange(HWND hwnd, int nBar, int nMinPos, int nMaxPos, BOOL fRedraw);

//------------------------------------------------------------------------------
// 函数名称:
//     SkinSB_ShowScrollBar
// 参数:
//     - HWND hwnd      指定一个窗口句柄
//     - int fnBar      指示是一个水平还是垂直的滚动条
//     - BOOL fShow     指示是否显示或隐藏滚动条,TRUE则显示滚动条FALSE则隐藏滚动条
// 反回:
//     BOOL             如果函数成功反回一个非零值,否则反回为零
// 说明:
//                      显示或隐藏滚动条
//------------------------------------------------------------------------------
BOOL WINAPI SkinSB_ShowScrollBar(HWND hwnd, int wBar, BOOL fShow);

//------------------------------------------------------------------------------
// 函数名称:
//     SkinSB_EnableScrollBar
// 参数:
//     - HWND hwnd      指定一个窗口句柄
//     - UINT wSBflags  指示是一个水平还是垂直的滚动条或两个同时
//     - UINT wArrows   指示禁止或启用哪些箭头按钮
// 反回:
//     BOOL             如果函数成功反回一个非零值,否则反回为零
// 说明:
//                      禁用或启用滚动条箭头按钮
//------------------------------------------------------------------------------
BOOL WINAPI SkinSB_EnableScrollBar(HWND hwnd, UINT wSBflags, UINT wArrows);

      以上这些API用法跟Windows Scrollbar API用法是一样的,只不过多了前面三个函数。有了以上这些函数你就可以为自定义控件设置滚动信息,别忘了用SkinSB_Init来加载皮肤位图,要注意的是要加载的皮肤位图规格必须与Demo中的相同,否则画出来的将是一团糟。最后一点要说明的是这个SkinSB库不能够为ScrollBar控件本身设置皮肤,如果有这样需要可以拿源代码自已改即可。

 

好了我就不多说了,如果文章和代码有不当之处不请P正,有什么建议或者问题请联系我!


附上源码:https://yunpan.cn/cvmWnaj4Ck5CT (提取码:ffc3)

↑ 上一篇文章:VC++/MFC精讲多练#004:DIY一个漂亮的滚动条控件 关键词:VC++/MFC精讲多练#004:DIY一个漂亮的滚动条控件 发布日期:2016/10/9 14:40:57
↓ 下一篇文章:全面解析VC中的MFC应用程序框架 关键词:全面解析VC中的MFC应用程序框架 发布日期:2016/10/10 11:19:33
相关目录:.NETVC&C++软件开发
我要评论
正在加载评论信息......