通过对WH_CBT进行hook对系统对话框和自建对话框进行自定义绘制

       最近老大提出要改界面了,一个一个的贴图甚是麻烦,就想有没有一种一劳永逸的办法呢?查了资料,用WM_CBT钩子,写了个demo,不仅自己写的对话框可以重绘,而且系统对话框也可以重绘.

      首先定义一个全局的钩子句柄       HHOOK g_hHook;       然后是钩子处理函数. (晕,从vc6里copy过来,代码缩进都没了)

LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
 if(nCode < 0)
 {
  return CallNextHookEx(g_hHook, nCode, wParam, lParam);
 }

 switch(nCode)
 {
 case HCBT_ACTIVATE:
  HWND hWnd = (HWND)wParam;
  char szTitle[256];
  GetWindowText(hWnd, szTitle, sizeof(szTitle));
  CHAR szClassName[255];
  GetClassName(hWnd, szClassName, sizeof(szClassName));

  LONG lWindowStyle   =   GetWindowLong(hWnd,   GWL_STYLE) ;
  TRACE("windowtext=%s, classname=%s, WindowLong = %x /n", szTitle, szClassName, lWindowStyle);
  long nStyle = WS_CAPTION | WS_DLGFRAME ;
  if((WNDPROC)GetProp(hWnd, "SkinWindowOldWndProc") == NULL &&
   (lWindowStyle & WS_CAPTION) && (lWindowStyle & WS_DLGFRAME))
  {
   WNDPROC OldWndProc=(WNDPROC)GetWindowLong(hWnd,GWL_WNDPROC);
   LONG lWindowStyle = GetWindowLong(hWnd, GWL_STYLE);
   lWindowStyle &= ~WS_SYSMENU; //去掉窗口的系统菜单
   SetWindowLong(hWnd, GWL_STYLE, lWindowStyle);
   //用SetProp函数将旧消息处理函数的地址传到新消息处理函数中,以便调用默认的处理函数以及最后恢复。
   SetProp(hWnd,"SkinWindowOldWndProc",(HANDLE)OldWndProc);
   SetWindowLong(hWnd, GWL_WNDPROC, (LONG)NewWndProc);
   return 0;
  }

 }

 // 调用下一个Hook
 return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

接着是新的消息处理函数:

LRESULT CALLBACK NewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
 static  WNDPROC  OldWndProc=NULL;
 OldWndProc=(WNDPROC)GetProp(hwnd,"SkinWindowOldWndProc");
 ASSERT(OldWndProc != NULL);
 CHAR szClassName[255];
 GetClassName(hwnd, szClassName, sizeof(szClassName));
 if(uMsg == WM_NCPAINT || uMsg == WM_NCACTIVATE)
 {

  char szTitle[256];
  ZeroMemory(szTitle, sizeof(szTitle));
  GetWindowText(hwnd, szTitle, sizeof(szTitle));
  LRESULT lResult = CallWindowProc(OldWndProc,hwnd,uMsg,wParam,lParam);
  CRect rtWnd, rtTitle, rtButtons;
  GetWindowRect(hwnd, &rtWnd);
  rtTitle.left = GetSystemMetrics(SM_CXFRAME);
  rtTitle.top = GetSystemMetrics(SM_CYFRAME);
  rtTitle.right = rtWnd.right - rtWnd.left - GetSystemMetrics(SM_CXFRAME);
  rtTitle.bottom = rtTitle.top + GetSystemMetrics(SM_CYSIZE);
  HDC hDC = GetWindowDC(hwnd);
  SetStretchBltMode(hDC, COLORONCOLOR);
  CBitmap bitmap;
  BITMAP bm;
  HDC hdcMem = CreateCompatibleDC(hDC);
  CPoint point;
  //CBrush Brush(0xad7931);
  //HGDIOBJ oldBrush = SelectObject(hDC, Brush);
  //填充顶部框架
  point.x = rtWnd.Width();
  point.y = GetSystemMetrics(SM_CYSIZE) + GetSystemMetrics(SM_CYFRAME)+ 1;
  // PatBlt(hDC, 0, 0, point.x, point.y, PATCOPY);
  //填充左侧框架
  point.x = GetSystemMetrics(SM_CXFRAME) + 0;
  point.y = rtWnd.Height();
  bitmap.LoadBitmap(IDB_LEFT);
  bitmap.GetBitmap(&bm);
  SelectObject(hdcMem, bitmap);
  StretchBlt(hDC, 0, 0, point.x, point.y, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
  bitmap.DeleteObject();
  //PatBlt(hDC, 0, 0, point.x, point.y, PATCOPY);
  //填充右侧框架
  point.x = GetSystemMetrics(SM_CXFRAME) + 0;
  point.y = rtWnd.Height();
  bitmap.LoadBitmap(IDB_RIGHT);
  bitmap.GetBitmap(&bm);
  SelectObject(hdcMem, bitmap);
  StretchBlt(hDC,  rtWnd.Width()-point.x, 0, point.x, point.y, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
  bitmap.DeleteObject();
  //PatBlt(hDC, rtWnd.Width()-point.x, 0, point.x, point.y, PATCOPY);
  //SelectObject(hDC, oldBrush);
  //填充底部框架
  point.x = rtWnd.Width();
  point.y = GetSystemMetrics(SM_CYFRAME) + 0;
  bitmap.LoadBitmap(IDB_BOTTOM);
  bitmap.GetBitmap(&bm);
  SelectObject(hdcMem, bitmap);
  StretchBlt(hDC, 0, rtWnd.Height()-point.y, point.x, point.y,hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
  bitmap.DeleteObject();
  //PatBlt(hDC, 0, rtWnd.Height()-point.y, point.x, point.y, PATCOPY);

  bitmap.LoadBitmap(IDB_TITLE);
  bitmap.GetBitmap(&bm);
  SelectObject(hdcMem, bitmap);
  StretchBlt(hDC,  -5, 0,
   rtTitle.right - rtTitle.left + 15, rtTitle.bottom - rtTitle.top + 5,
   hdcMem, 0, 1, bm.bmWidth, bm.bmHeight, SRCCOPY);
  SetTextColor(hDC, RGB(255, 255, 255));
  SetBkMode(hDC, TRANSPARENT);
  DrawText(hDC, szTitle, strlen(szTitle), rtTitle, DT_LEFT);
  bitmap.DeleteObject();
  DeleteDC(hdcMem);
  ReleaseDC(hwnd, hDC);

  return lResult;
 }

 //窗体销毁时,把原来的消息处理函数还原
 if(WM_NCDESTROY == uMsg )
 {
  SetWindowLong(hwnd,GWL_WNDPROC,(LONG)OldWndProc);
  RemoveProp(hwnd,"SkinWindowOldWndProc");

  return CallWindowProc(OldWndProc,hwnd,uMsg,wParam,lParam);

 }
 return CallWindowProc(OldWndProc,hwnd,uMsg,wParam,lParam);
}

 

//接下来的两个消息处理为屏蔽通用对话框上的"?"按钮和"X"按钮  //其实这种屏蔽方法还不是很完全  //如果见到WM_NCLBUTTONDOWN函数就返回TRUE的话,对话框就不能移动了。  //如果要完全屏蔽的话,需要重写WM_NCLBUTTONDOWN处理函数,即自己写窗口移动的函数。  if(WM_NCLBUTTONDOWN == uMsg)  {   if(strcmp(szClassName, "#32770") == 0)   {    CallWindowProc(OldWndProc,hwnd,uMsg,wParam,lParam);    SendMessage(hwnd, WM_NCPAINT, wParam, lParam);   }   CallWindowProc(OldWndProc,hwnd,uMsg,wParam,lParam);   return TRUE;     }

 if(WM_NCMOUSEMOVE == uMsg )  {   if(strcmp(szClassName, "#32770") == 0)   {    return TRUE;   }   CallWindowProc(OldWndProc,hwnd,uMsg,wParam,lParam);  }

 //窗体销毁时,把原来的消息处理函数还原  if(WM_DESTROY == uMsg )  {   SetWindowLong(hwnd,GWL_WNDPROC,(LONG)OldWndProc);   RemoveProp(hwnd,"SkinWindowOldWndProc");      return CallWindowProc(OldWndProc,hwnd,uMsg,wParam,lParam);

 }  return CallWindowProc(OldWndProc,hwnd,uMsg,wParam,lParam); } 最后在app的InitInstance函数里加入:  g_hHook = SetWindowsHookEx(WH_CBT, CBTProc, NULL, GetCurrentThreadId());

在ExitInstance函数里加入: UnhookWindowsHookEx(g_hHook); 

效果图如下:

通过对WH_CBT进行hook对系统对话框和自建对话框进行自定义绘制_第1张图片

通过对WH_CBT进行hook对系统对话框和自建对话框进行自定义绘制_第2张图片

通过对WH_CBT进行hook对系统对话框和自建对话框进行自定义绘制_第3张图片

 

你可能感兴趣的:(技术话题)