MFC自绘皮肤编写[笔记一] .

来源:互联网 发布:三友集团网络练兵网址 编辑:程序博客网 时间:2024/05/03 08:53

用了这么长时间的MFC,感觉不错是不错,可是那个界面呀,真让人难受啊.虽然在VS2008中有了提供,但是还是不理想,所以就想找个皮肤库,现在比较好用的(个人感觉)SkinMagic,不过它不支持VS2008悲哀呀.所以打算自己写一个.

关于那些基础知识和HOOK的知识我就不详细说了,可以去

http://www.fengfly.com/plus/view-171863-1.html

这里来看下.虽然这个是用C#但还是让我收获不小

我们现在采用在要HOOK方式来给界面换肤,下面就来说一具体的步骤,

这里用到的是VS2008,不采用VC 6.0这样就可以直接要VS 2008中使用了.由于也可以让别人来使用,所以我们就用DLL的方式来换肤.

 



具体步骤:

1.新建一个Dll工程,这里我命名的是"dll",选择"带静态链接 MFC 的规则 DLL(R)",然后完成

2.打开工程的主要cpp文件,我的是dll.cpp.然后添加一个RunHook函数

[cpp] view plaincopyprint?
  1. /******************************************************************** 
  2. 函数名称:       安装钩子 
  3. ===================================================================== 
  4. 参数说明:       dwThreadID当前进程的ID,hModule默认方式0 
  5. --------------------------------------------------------------------- 
  6. 文件作者:       King.Sollyu 
  7. *********************************************************************/  
  8. HHOOK  hWndHook ;   //全局变量  
  9. HINSTANCE hMod = NULL;  
  10. BOOL __stdcall RunHook( DWORD dwThreadID, HMODULE hModule = 0)  
  11. {  
  12.     hWndHook = SetWindowsHookEx(  
  13.         WH_CALLWNDPROC, (HOOKPROC) HOOKProc, hMod , dwThreadID );  
  14.     return TRUE;  
  15. }  

 这个函数是我们的主要函数,它是我们的主入口,下面来看一下 HOOKProc 为个钩子函数

 

 

[cpp] view plaincopyprint?
  1. /******************************************************************** 
  2. 函数名称:       定义钩子函数 
  3. ===================================================================== 
  4. 参数说明:       无 
  5. --------------------------------------------------------------------- 
  6. 文件作者:       King.Sollyu 
  7. *********************************************************************/  
  8. LRESULT CALLBACK HOOKProc( int nCode, WPARAM wParam, LPARAM lParam )  
  9. {  
  10.     PCWPSTRUCT  wc = (PCWPSTRUCT) lParam;  
  11.     HWND  hWnd = wc->hwnd;  
  12.     if( hWnd )   
  13.     {  
  14.         wchar_t ClassName[MAX_PATH] =_T("");  
  15.   
  16.         GetClassName( hWnd, ClassName, MAX_PATH );  
  17.   
  18.         CWnd    *pWnd = CWnd::FromHandle( hWnd );  
  19.   
  20.         if (wcscmp( ClassName, _T("Edit") ) == 0)   //修改编辑框的窗口函数  
  21.         {  
  22.             CWnd    *pWnd = CWnd::FromHandle( hWnd );  
  23.   
  24.             pWnd->ModifyStyleEx(WS_EX_CLIENTEDGE,0,0);   //取消编辑框的边框  
  25.   
  26.             WNDPROC WndProc;  
  27.             WndProc = (WNDPROC) GetWindowLong( hWnd, GWL_WNDPROC );  
  28.   
  29.             CDrawEdit *pEdit=(CDrawEdit*)GetWindowLong(hWnd,GWL_USERDATA);  
  30.   
  31.             if (pEdit != NULL&& pEdit->m_Flag==1 )  
  32.             {  
  33.                 SetWindowLong(hWnd, GWL_USERDATA, 0);  
  34.                 SetWindowLong( hWnd, GWL_WNDPROC, (LONG)pEdit->m_OldProc);  
  35.   
  36.                 pEdit->m_OldProc = NULL;  
  37.                 delete pEdit;  
  38.             }  
  39.             else if (pEdit == NULL )   
  40.             {  
  41.                 if( WndProc !=EditWindowProc )  
  42.                 {  
  43.                     pEdit = new CDrawEdit();  
  44.                     pEdit->m_OldProc = WndProc;  
  45.                     SetWindowLong(hWnd,GWL_USERDATA,(long)pEdit);  
  46.                     WndProc =  (WNDPROC) SetWindowLong( hWnd, GWL_WNDPROC, (LONG) EditWindowProc);  
  47.                 }  
  48.             }         
  49.         }  
  50.     }  
  51.         return CallNextHookEx( hWndHook, nCode, wParam, lParam );  
  52. }  

 

 这样我们会发现CDrawEdit这个是这个错误.CDrawEdit是我们自定义的一个Edit类,它的主要功能是实现自绘Edit框.下面是CDrawEdit在代码

[cpp] view plaincopyprint?
  1. /******************************************************************** 
  2. 函数名称:       定义编辑框类 
  3. ===================================================================== 
  4. 参数说明:       无 
  5. --------------------------------------------------------------------- 
  6. 文件作者:       King.Sollyu 
  7. *********************************************************************/  
  8. class CDrawEdit  
  9. {  
  10. public:  
  11.     WNDPROC     m_OldProc;         //记录编辑框的窗口函数  
  12.     int         m_Flag;   
  13. public:  
  14.     CDrawEdit()  
  15.     {  
  16.         m_OldProc = NULL;  
  17.         m_Flag    = 0;  
  18.     }  
  19.     HBRUSH CtlColor(HWND hWnd,HDC hDC, UINT nCtlColor)  
  20.     {  
  21.         CDC* dc = CDC::FromHandle(hDC);     //获取画布对象  
  22.         CRect rect;  
  23.         ::GetClientRect(hWnd,rect);         //获取客户区域  
  24.         rect.InflateRect(1,1,1,1);          //将客户区域增大一个像素  
  25.         CPen pen(PS_SOLID,1,RGB(0,255,0));  //创建画笔  
  26.         dc->SelectObject(&pen);  
  27.         CBrush brush (RGB(0,255,0));        //创建画刷  
  28.         dc->FrameRect(rect,&brush);          //绘制边框  
  29.         return brush;  
  30.     }  
  31. };  
  32.   
  33. /******************************************************************** 
  34. 函数名称:       编辑框窗口函数 
  35. ===================================================================== 
  36. 参数说明:       无 
  37. --------------------------------------------------------------------- 
  38. 文件作者:       King.Sollyu 
  39. *********************************************************************/  
  40. LRESULT __stdcall EditWindowProc(HWND hWnd,UINT Msg,WPARAM wParam,   
  41.                                  LPARAM lParam )  
  42. {  
  43.     CPoint pt;  
  44.     CDrawEdit *pEdit=(CDrawEdit*)GetWindowLong(hWnd,GWL_USERDATA);  
  45.     switch (Msg)  
  46.     {  
  47.     case WM_PAINT:   
  48.         {  
  49.             pEdit->CtlColor(hWnd,::GetDC(hWnd),0);  
  50.             break;  
  51.         }  
  52.   
  53.     case WM_DESTROY:  
  54.         {                 
  55.             WNDPROC procOld=pEdit->m_OldProc;  
  56.             SetWindowLong(hWnd,GWL_WNDPROC,(long)procOld); //恢复原来的窗口函数  
  57.   
  58.             CWnd* pWnd = ::CWnd::FromHandle(hWnd);          //将按钮对象与句柄分离  
  59.             if (pWnd)  
  60.             {  
  61.                 pWnd->Detach();  
  62.             }  
  63.             pEdit->m_Flag = 1;  
  64.             return 1;  
  65.         }  
  66.     default :  
  67.         {  
  68.   
  69.             break;  
  70.         }  
  71.     }  
  72.     return CallWindowProc(pEdit->m_OldProc, hWnd, Msg, wParam, lParam );  
  73. }  

 

 把必要的函数在头文件中声明下,或者放在RunHook 这个函数之前.

添加卸载钩子函数

[cpp] view plaincopyprint?
  1. /******************************************************************** 
  2. 函数名称:       卸载钩子 
  3. ===================================================================== 
  4. 参数说明:       无 
  5. --------------------------------------------------------------------- 
  6. 文件作者:       King.Sollyu 
  7. *********************************************************************/  
  8. BOOL __stdcall StopHook()  
  9. {  
  10.     UnhookWindowsHookEx(hWndHook);  
  11.     return TRUE;      
  12. }  

3.导出函数

打开dll.def,在下面添加

 RunHook
 StopHook

下面是整个dll.def的内容

[cpp] view plaincopyprint?
  1. ; dll.def : 声明 DLL 的模块参数。  
  2.   
  3. LIBRARY      "dll"  
  4.   
  5. EXPORTS  
  6.     ; 此处可以是显式导出  
  7.     RunHook  
  8.     StopHook  

然后编译一下.本人测试通过

 


 

这样我们就可以实现所有的"编辑框"的换肤.现在再新建一个exe工程来测试一下我们dll是不是可以正常的使用

 

1.新建一个exe工程添加到当前的工程中.这里我选的是"基于对话框(D)"和" " .其它默认

2.在对话框中添加一个"编辑框"

3.在exeApp.cpp中包含dll.h和使用隐式连接dll.lib,

[c-sharp] view plaincopyprint?
  1. #include "../dll/dll.h"  
  2. #pragma comment(lib,"../debug/dll.lib")  

 

并在InitInstance函数中添加代码

 

[cpp] view plaincopyprint?
  1. RunHook(GetCurrentThreadId());  

编译一下,本人用win 7旗舰版+VS 2008编译通过

下面是程序的运行截图