皮肤引擎设计
http://blog.sina.com.cn/s/blog_5eb1ba9e0100c72r.html
皮肤引擎设计思路:
其实也就是Hook掉默认的窗口绘制,然后根据窗口类别,用自己的窗口渲染代替了windows默认的窗口渲染。这个过程非常繁琐,特别考验耐心和体力。
花了一个上午,总算把Button做好了, 下一步是把这个Button应用到公司的客户端上,效果不错。
Button的Demo图:
设计思路:
1. 首先加载一个钩子函数
SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)WndProc, g_hHookDll, GetCurrentThreadId());
钩子实际上是一个处理消息的程序段,通过SetWindowsHookEx系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
简单的说,钩子程序在消息到达目的窗口前, 可以先处理(过滤, 丢弃...)该消息。
2. 在窗口初始化时替换掉窗口处理函数(消息到达目的窗口前), 同时保存原窗口处理函数
map<HWND, WNDPROC> g_mapWindow; //每个窗口对应的原窗口函数
LRESULT CALLBACK WndProc(int iCode, WPARAM wParam, LPARAM lParam)
{
static RECT rect ;
char szClassName[512];
if (iCode < 0)
return CallNextHookEx(g_Hook,iCode,wParam,lParam);
CWPSTRUCT *pCWP = (CWPSTRUCT *)lParam;
HWND hWnd = pCWP->hwnd;
int nLen = GetClassName(hWnd, szClassName, 512);
if (strcmp(szClassName, "Button") == 0)
{
if (pCWP->message == WM_CREATE)
{
//保存原窗口处理函数
WNDPROC pButtonOldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)HookButtonWndProc);
g_mapWindow[hWnd] = pButtonOldWndProc;
//return 0;
}
return 0;
}
.......
}
3. 实现自己的button消息处理函数HookButtonWndProc,这里要处理大堆的windows消息(十分消耗体力和耐心)
LRESULT CALLBACK HookButtonWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch ( msg )
{
case WM_PAINT:
{
PaintButton(hWnd); //自己绘制button
}
return 0;
....
}
4. 自己不处理的消息可以Call下原窗口函数处理一下。
int CallPreWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
int Result = 0;
WNDPROC hWndProc = g_mapWindow[hWnd]; //hWndProc 就是原来的窗口处理函数
if (hWndProc)
{
Result = ::CallWindowProc(hWndProc, hWnd, msg, wp, lp);
}
return Result;
}
总的来说,没有必要在界面上花费太多时间, 有时候稍微调整一下界面也会好很多。 如果您确实需要一个华丽的界面,可以使用如今已泛滥成灾的皮肤库。