Windows Vista 引入的桌面窗口管理器(DWM)帶來了標誌性的 Aero 毛玻璃視覺效果。本文演示如何在基於 WTL 的 C++ 原生程序中集成毛玻璃界面,涵蓋框架窗口與對話框兩種場景,並處理繪製文本、圖標及動態狀態變更。
需定義 Vista 版本宏(0x0600)並包含 DWM API:
#define WINVER 0x0600
#define _WIN32_WINNT 0x0600
#define _WIN32_IE 0x0700
#define _WTL_NO_WTYPES
#include <atlbase.h>
#include <atltypes.h>
#include <atlapp.h>
extern CAppModule _Module;
#include <atlwin.h>
#include <atlframe.h>
#include <atlmisc.h>
#include <atlcrack.h>
#include <atltheme.h> // XP/Vista 主題支持
#include <dwmapi.h> // DWM API
注意:Windows SDK 中 atltheme.h 的 GetThemeTextMetrics 轉換代碼與 Platform SDK 不兼容,需刪除該轉換行以編譯通過。
將非客戶區的毛玻璃效果擴展到客戶區:
MARGINS mar = {0};
mar.cyBottomHeight = 100; // 底部擴展 100 像素
DwmExtendFrameIntoClientArea(m_hWnd, &mar);
MARGINS 結構控制四邊擴展距離(cxLeftWidth、cxRightWidth、cyTopHeight、cyBottomHeight)。
毛玻璃區域像素 Alpha 必須為 0 才能顯示效果。最簡單方法是在 OnEraseBkgnd 中用黑刷填充:
BOOL OnEraseBkgnd(HDC hdc) {
CDCHandle dc = hdc;
CRect rcClient;
GetClientRect(rcClient);
dc.FillSolidRect(rcClient, RGB(0,0,0)); // RGBA 全 0
return TRUE;
}
GDI 函數不支持 Alpha 通道,必須使用主題 API DrawThemeTextEx 配合雙緩衝:
biHeight 設為負值,頂-down 格式)。DTTOPTS 啟用 DTT_COMPOSITED(合成繪製)與 DTT_GLOWSIZE(發光)。DrawThemeTextEx 繪製到內存位圖。BitBlt (SRCCOPY) 複製到屏幕 DC。if (IsCompositionEnabled()) {
CDC dcMem; CBitmap bmp; BITMAPINFO dib = {0};
dcMem.CreateCompatibleDC(dc);
dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
dib.bmiHeader.biWidth = rcText.Width();
dib.bmiHeader.biHeight = -rcText.Height(); // 負值:top-down
dib.bmiHeader.biPlanes = 1;
dib.bmiHeader.biBitCount = 32;
dib.bmiHeader.biCompression = BI_RGB;
bmp.CreateDIBSection(dc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);
dcMem.SelectBitmap(bmp);
dcMem.SelectFont(m_font);
DTTOPTS dto = { sizeof(DTTOPTS) };
dto.dwFlags = DTT_COMPOSITED | DTT_GLOWSIZE;
dto.iGlowSize = 10; // 發光半徑
CRect rcText2 = rcText; rcText2 -= rcText2.TopLeft(); // 歸零座標
DrawThemeTextEx(m_hTheme, dcMem, 0, 0, CT2CW(szTime), -1,
DT_SINGLELINE|DT_CENTER|DT_VCENTER|DT_NOPREFIX,
rcText2, &dto);
BitBlt(dc, rcText.left, rcText.top, rcText.Width(), rcText.Height(),
dcMem, 0, 0, SRCCOPY);
}
系統廣播 WM_DWMCOMPOSITIONCHANGED 通知,需重新應用邊距:
LRESULT OnCompositionChanged(...) {
if (IsCompositionEnabled()) {
MARGINS mar = {0};
mar.cyBottomHeight = 100;
DwmExtendFrameIntoClientArea(m_hWnd, &mar);
}
return 0;
}
流程類似,但需注意:
OnInitDialog 中調用 OpenThemeData()(對話框無 WM_CREATE)。SS_OWNERDRAW 風格,在 OnDrawItem 中繪製。OnPaint 而非 OnEraseBkgnd(對話框默認處理背景)。EnableThemeDialogTexture(ETDT_ENABLE) 使對話框背景跟隨主題。毛玻璃區域繪製圖片需用 GDI+ Image 類保留 Alpha 通道:
// OnDrawItem 中
Graphics g(dcMem);
Image img(L"mylogo.png");
g.DrawImage(&img, x, y); // 自動處理透明度
設置 MARGINS mar = {-1}; 可使整個窗口毛玻璃化,但子控件(按鈕等)會顯示異常(不透明矩形框、文字顏色錯誤)。解決方案:子控件區域繪製不透明背景,參考「Windows Mobility Center」風格。
DwmIsCompositionEnabled。DrawThemeTextEx + 32位 DIB 雙緩衝。WM_DWMCOMPOSITIONCHANGED 保證狀態切換正確。本文代碼基於 WTL 7.5 + VC++ 2003/2005,可直接移植到 MFC 或純 Win32 專案。