话不多说,先验货:
(原始状态)
(最大化状态)
(对比图)
为自己鼓掌!!!
哈哈,捣鼓2天终于把这个搞出来了!虽然代码一团糟,但是不难理解!
要实现这个功能需要几个组件:DWM,GDI+
在实现这个代码中我认为最困难的就是chrome边框的阴影部分~
(这里的2个像素的阴影)
和本身客户区边框的1个黑色像素,这1个像素IE11没有处理,而CHROME却没有这个黑边:
最开始使用GDI,但是GDI不带有Alpha通道,导致在画阴影时画出来的是实线,所以换成GDI+,下面是实现效果(没有采用圆角矩形,因为GDI+没有直接绘制圆角矩形的接口):
好了,上代码:
1 # include <windows.h> 2 #include <windowsx.h> 3 # include <stdio.h> 4 # include <stdlib.h> 5 #include "dwmapi.h" 6 #include "resource.h" 7 #include <gdiplus.h> 8 using namespace Gdiplus; 9 10 11 const int TOPEXTENDWIDTH = 44; 12 const int TOPEXTENDWIDTHMAX = 34; 13 const int BOTTOMEXTENDWIDTH = 8; 14 const int LEFTEXTENDWIDTH = 8; 15 const int RIGHTEXTENDWIDTH = 8; 16 17 18 LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); 19 LRESULT AppWinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); 20 LRESULT CustomCaptionProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool* pfCallDWP); 21 22 bool formstateMax=false; 23 24 LRESULT HitTestNCA(HWND hWnd, WPARAM wParam, LPARAM lParam) 25 { 26 27 POINT ptMouse = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; 28 29 RECT rcWindow; 30 GetWindowRect(hWnd, &rcWindow); 31 32 33 RECT rcFrame = { 0 }; 34 AdjustWindowRectEx(&rcFrame, WS_OVERLAPPEDWINDOW & ~WS_CAPTION, FALSE, NULL); 35 36 37 USHORT uRow = 1; 38 USHORT uCol = 1; 39 bool fOnResizeBorder = false; 40 41 42 if (ptMouse.y >= rcWindow.top && ptMouse.y < rcWindow.top + (formstateMax?TOPEXTENDWIDTHMAX:TOPEXTENDWIDTH) ) 43 { 44 fOnResizeBorder = (ptMouse.y < (rcWindow.top - rcFrame.top)); 45 uRow = 0; 46 } 47 else if (ptMouse.y < rcWindow.bottom && ptMouse.y >= rcWindow.bottom - BOTTOMEXTENDWIDTH) 48 { 49 uRow = 2; 50 } 51 52 if (ptMouse.x >= rcWindow.left && ptMouse.x < rcWindow.left + LEFTEXTENDWIDTH) 53 { 54 uCol = 0; 55 } 56 else if (ptMouse.x < rcWindow.right && ptMouse.x >= rcWindow.right - RIGHTEXTENDWIDTH) 57 { 58 uCol = 2; 59 } 60 61 // Hit test (HTTOPLEFT, ... HTBOTTOMRIGHT) 62 LRESULT hitTests[3][3] = 63 { 64 { HTTOPLEFT, fOnResizeBorder ? HTTOP : HTCAPTION, HTTOPRIGHT }, 65 { HTLEFT, HTNOWHERE, HTRIGHT }, 66 { HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT }, 67 }; 68 69 70 return hitTests[uRow][uCol]; 71 } 72 73 int RECTWIDTH(RECT trec) 74 { 75 int rWidth = 0; 76 rWidth = trec.right - trec.left; 77 return rWidth; 78 } 79 80 int RECTHEIGHT(RECT trec) 81 { 82 int rHeight = 0; 83 rHeight = trec.bottom - trec.top; 84 return rHeight; 85 } 86 87 void ReDrawExtendFrame(HWND hWnd) 88 { 89 MARGINS margins; 90 91 margins.cxLeftWidth = LEFTEXTENDWIDTH; 92 margins.cxRightWidth = RIGHTEXTENDWIDTH; 93 margins.cyBottomHeight = BOTTOMEXTENDWIDTH; 94 if (formstateMax) 95 margins.cyTopHeight = TOPEXTENDWIDTHMAX; 96 else 97 margins.cyTopHeight = TOPEXTENDWIDTH; 98 99 int hr = DwmExtendFrameIntoClientArea(hWnd, &margins); 100 101 if (!SUCCEEDED(hr)) 102 { 103 104 } 105 } 106 107 int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow) 108 { 109 static TCHAR szAppName [] = TEXT("Pavkoo SChrome"); 110 int address = (int)hInstance; 111 HWND hwnd; 112 MSG msg; 113 WNDCLASS wndclass; 114 GdiplusStartupInput gdiplusStartupInput; 115 ULONG_PTR gdiplusToken; 116 GdiplusStartup(&gdiplusToken,&gdiplusStartupInput,NULL); 117 wndclass.style = CS_HREDRAW|CS_VREDRAW; 118 wndclass.lpfnWndProc = WndProc; 119 wndclass.cbClsExtra = 0 ; 120 wndclass.cbWndExtra = 0 ; 121 wndclass.hInstance = hInstance; 122 wndclass.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1)); 123 wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); 124 wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); 125 wndclass.lpszMenuName=NULL; 126 wndclass.lpszClassName=szAppName; 127 if(!RegisterClass(&wndclass)) 128 { 129 MessageBox(NULL,TEXT("This program requires Windows NT!"),szAppName,MB_ICONERROR); 130 return 0; 131 } 132 hwnd=CreateWindow(szAppName,TEXT("Schrome"),WS_OVERLAPPEDWINDOW, 133 CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, 134 NULL,NULL,hInstance,NULL); 135 ShowWindow(hwnd,iCmdShow); 136 UpdateWindow(hwnd); 137 138 while(GetMessage(&msg,NULL,0,0)) 139 { 140 TranslateMessage(&msg); 141 DispatchMessage(&msg); 142 } 143 GdiplusShutdown(gdiplusToken); 144 return msg.wParam; 145 } 146 147 148 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 149 { 150 bool fCallDWP = true; //是否需要将消息传递给默认的窗口处理程序,如果是重绘窗体框架就不用传递消息了! 151 BOOL fDwmEnabled = FALSE; 152 LRESULT lRet = 0; 153 HRESULT hr = S_OK; 154 155 // 判断Aero Glass是否开启 156 hr = DwmIsCompositionEnabled(&fDwmEnabled); 157 if (SUCCEEDED(hr)) 158 { 159 lRet = CustomCaptionProc(hWnd, message, wParam, lParam, &fCallDWP); 160 } 161 162 // 处理其他默认的消息 163 if (fCallDWP) 164 { 165 lRet = AppWinProc(hWnd, message, wParam, lParam); 166 } 167 return lRet; 168 } 169 170 // 171 // 绘制自定义窗体框架的处理程序 172 // 173 LRESULT CustomCaptionProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool* pfCallDWP) 174 { 175 LRESULT lRet = 0; 176 HRESULT hr = S_OK; 177 bool fCallDWP = true; // 传递给DefWindowProc 178 179 //是否需要DWM绘制非客户区 180 fCallDWP = !DwmDefWindowProc(hWnd, message, wParam, lParam, &lRet); 181 182 if (message == WM_CREATE) 183 { 184 RECT rcClient; 185 GetWindowRect(hWnd, &rcClient); 186 187 SetWindowPos(hWnd, 188 NULL, 189 rcClient.left, rcClient.top, 190 RECTWIDTH(rcClient), RECTHEIGHT(rcClient), 191 SWP_FRAMECHANGED);//触发一条WM_NCCALCSIZE消息,通吃应用程序框架大小发生改变 192 193 fCallDWP = true; 194 lRet = 0; 195 } 196 197 // 窗口激活 198 if (message == WM_ACTIVATE) 199 { 200 ReDrawExtendFrame(hWnd); 201 fCallDWP = true; 202 lRet = 0; 203 } 204 205 if (message == WM_PAINT) 206 { 207 HDC hdc; 208 PAINTSTRUCT ps; 209 { 210 hdc = BeginPaint(hWnd, &ps); 211 212 //使用gdi+绘制 213 Graphics graphicsInstance(hdc); 214 Rect rect = Rect(ps.rcPaint.left + LEFTEXTENDWIDTH, 215 ps.rcPaint.top + (formstateMax?TOPEXTENDWIDTHMAX:TOPEXTENDWIDTH), 216 ps.rcPaint.right - ps.rcPaint.left - RIGHTEXTENDWIDTH-LEFTEXTENDWIDTH , 217 ps.rcPaint.bottom -ps.rcPaint.top -BOTTOMEXTENDWIDTH-(formstateMax?TOPEXTENDWIDTHMAX:TOPEXTENDWIDTH)); 218 SolidBrush solidBrush(Color(255,255,255,255)); 219 rect.Inflate(1,1); 220 graphicsInstance.FillRectangle(&solidBrush,rect); 221 Pen pen(Color(200,100,100,100)); 222 graphicsInstance.DrawRectangle(&pen,rect); 223 rect.Inflate(1,1); 224 pen.SetColor(Color(60,100,100,100)); 225 graphicsInstance.DrawRectangle(&pen,rect); 226 rect.Inflate(1,1); 227 pen.SetColor(Color(20,100,100,100)); 228 graphicsInstance.DrawRectangle(&pen,rect); 229 230 231 //画标签 232 Rect rectTab= Rect(20,rect.Y-TOPEXTENDWIDTHMAX+3+7,190,TOPEXTENDWIDTHMAX-7); 233 solidBrush.SetColor(Color(255,255,255,255)); 234 graphicsInstance.FillRectangle(&solidBrush,rectTab); 235 pen.SetColor(Color(200,100,100,100)); 236 graphicsInstance.DrawRectangle(&pen,rectTab); 237 pen.SetColor(Color(255,255,255,255)); 238 graphicsInstance.DrawLine(&pen,rectTab.X,rectTab.Y+rectTab.Height,rectTab.X+rectTab.Width,rectTab.Y+rectTab.Height); 239 240 Rect * add = rectTab.Clone(); 241 add->Offset(add->Width +6,0); 242 add->Width = 30; 243 add->Height = 18; 244 add->Y = add->Y +4; 245 solidBrush.SetColor(Color(100,255,255,255)); 246 graphicsInstance.FillRectangle(&solidBrush,*add); 247 pen.SetColor(Color(80,100,100,100)); 248 graphicsInstance.DrawRectangle(&pen,*add); 249 250 SolidBrush brush(Color(255, 0, 0, 0)); 251 FontFamily fontFamily(L"微软雅黑"); 252 Font font(&fontFamily, 12, FontStyleRegular, UnitPixel); 253 PointF pointF(rectTab.X +10,rectTab.Y+6); 254 255 graphicsInstance.DrawString(L"打开新的标签页", -1, &font, pointF, &brush); 256 FontFamily fontFamily2(L"Gautami"); 257 Font font2(&fontFamily2,12, FontStyleBold, UnitPixel); 258 PointF pointF2(rectTab.X + rectTab.Width - 10- 10 ,rectTab.Y+4); 259 brush.SetColor(Color(255, 60, 60, 60)); 260 graphicsInstance.DrawString(L"x", -1, &font2, pointF2, &brush); 261 262 263 Rect rectAddress = Rect(rect.X+3,rectTab.Y+rectTab.Height,rect.Width-6,TOPEXTENDWIDTHMAX); 264 LinearGradientBrush linGrBrush( 265 Point(rectAddress.X,rectAddress.Y), 266 Point(rectAddress.X, rectAddress.Y+rectAddress.Height-2), //不包含边框 267 Color(255, 255,255, 255), 268 Color(255, 220, 220, 220) 269 ); 270 graphicsInstance.FillRectangle(&linGrBrush,rectAddress); 271 pen.SetColor(Color(255,160,160,160)); 272 graphicsInstance.DrawLine(&pen,rectAddress.X,rectAddress.Y+rectAddress.Height-2,rectAddress.X +rectAddress.Width,rectAddress.Y+rectAddress.Height-2); 273 274 275 Rect * left= rectAddress.Clone(); 276 left->X = left->X +10; 277 left->Y = left->Y + 8; 278 left ->Width = 18; 279 left->Height = 14; 280 Image imageLeft(L"D:\\Code\\WINAPI\\chrome\\alpha\\Windowstyle\\RES\\left.png"); 281 graphicsInstance.DrawImage(&imageLeft,left->X,left->Y,left->Width,left->Height); 282 283 Image imageRight(L"D:\\Code\\WINAPI\\chrome\\alpha\\Windowstyle\\RES\\right.png"); 284 graphicsInstance.DrawImage(&imageRight,left->X+left->Width+15,left->Y,left->Width,left->Height); 285 286 Image imageRefresh(L"D:\\Code\\WINAPI\\chrome\\alpha\\Windowstyle\\RES\\refresh.png"); 287 graphicsInstance.DrawImage(&imageRefresh,left->X+left->Width+15+left->X+left->Width,left->Y,left->Width,left->Height); 288 int leftSparate = left->X+left->Width+15+left->X+left->Width+15 + left->Width; 289 Rect rectSearch = Rect(leftSparate,rectAddress.Y +5,rectAddress.Width-leftSparate,rectAddress.Height -12); 290 solidBrush.SetColor(Color(255,255,255,255)); 291 graphicsInstance.FillRectangle(&solidBrush,rectSearch.X,rectSearch.Y,rectSearch.Width,rectSearch.Height); 292 rectSearch.Inflate(1,1); 293 pen.SetColor(Color(200,200,200,200)); 294 graphicsInstance.DrawRectangle(&pen,rectSearch); 295 rectSearch.Inflate(-1,-1); 296 pen.SetColor(Color(10,100,100,100)); 297 graphicsInstance.DrawRectangle(&pen,rectSearch); 298 299 Image image(L"D:\\Code\\WINAPI\\chrome\\alpha\\Windowstyle\\RES\\center.png"); 300 PointF point3(((ps.rcPaint.right-ps.rcPaint.left) - image.GetWidth()) / 2,((ps.rcPaint.bottom-ps.rcPaint.top) - image.GetHeight()) / 2); 301 graphicsInstance.DrawImage(&image,point3.X,point3.Y,image.GetWidth(),image.GetHeight()); 302 303 EndPaint(hWnd, &ps); 304 } 305 306 fCallDWP = true; 307 lRet = 0; 308 } 309 310 // 接受非客户区大小发生改变 311 if ((message == WM_NCCALCSIZE) && (wParam == TRUE)) 312 { 313 // 计算新的NCCALCSIZE_PARAMS大小 314 NCCALCSIZE_PARAMS *pncsp = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam); 315 316 pncsp->rgrc[0].left = pncsp->rgrc[0].left + 0; 317 pncsp->rgrc[0].top = pncsp->rgrc[0].top + 0; 318 pncsp->rgrc[0].right = pncsp->rgrc[0].right - 0; 319 pncsp->rgrc[0].bottom = pncsp->rgrc[0].bottom - 0; 320 321 lRet = 0; 322 323 // 这个消息没有必要传递给Defwindowproc 324 fCallDWP = false; 325 } 326 327 // 处理DwmDefWindowProc没有处理到的hit testing消息 328 if ((message == WM_NCHITTEST) && (lRet == 0)) 329 { 330 lRet = HitTestNCA(hWnd, wParam, lParam); 331 332 if ((lRet != HTNOWHERE) ) 333 { 334 fCallDWP = false; 335 } 336 } 337 *pfCallDWP = fCallDWP; 338 339 return lRet; 340 } 341 342 LRESULT AppWinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 343 { 344 int wmId, wmEvent; 345 PAINTSTRUCT ps; 346 HDC hdc; 347 HRESULT hr; 348 LRESULT result = 0; 349 350 switch (message) 351 { 352 case WM_CREATE: 353 {} 354 break; 355 case WM_COMMAND: 356 wmId = LOWORD(wParam); 357 wmEvent = HIWORD(wParam); 358 switch (wmId) 359 { 360 default: 361 return DefWindowProc(hWnd, message, wParam, lParam); 362 } 363 break; 364 case WM_PAINT: 365 { 366 hdc = BeginPaint(hWnd, &ps); 367 EndPaint(hWnd, &ps); 368 } 369 break; 370 case WM_SIZE: 371 { 372 if (wParam==SIZE_MAXIMIZED) 373 { 374 formstateMax = true; 375 } 376 else 377 { 378 formstateMax = false; 379 } 380 ReDrawExtendFrame(hWnd); 381 } 382 break; 383 case WM_DESTROY: 384 PostQuitMessage(0); 385 break; 386 default: 387 return DefWindowProc(hWnd, message, wParam, lParam); 388 } 389 return 0; 390 }
参考链接:
http://msdn.microsoft.com/en-us/library/bb688195(VS.85).aspx#appendixc
http://msdn.microsoft.com/en-us/library/ms632606(VS.85).aspx
http://blog.csdn.net/oldmtn/article/details/7258003
http://www.cnblogs.com/kekec/archive/2010/10/08/1845645.html