透明視窗常見做法是 SetWindowRgn 配合像素掃描建立裁切區域,但支援視窗縮放時需重複掃描計算,易導致閃爍且效能不佳。本文介紹更簡單高效的 SetLayeredWindowAttributes 方法(需 Windows 2000 以上)。
BOOL SetLayeredWindowAttributes(
HWND hwnd, // 目標視窗控制代碼
COLORREF crKey, // 遮罩顏色(透明色)
BYTE bAlpha, // Alpha 值:0 全透明,255 不透明
DWORD dwFlags // 透明模式旗標
);
需在專案中動態載入 user32.dll 取得函式指標(或使用最新 SDK 直接引用)。
建立背景圖片,以特定顏色(如綠色 RGB(0,255,0))標記透明區域。

// 成員變數
CBitmap* m_oldBitmap; // 原始點陣圖指標
CDC m_DC; // 記憶體 DC
BOOL CTransWindowDlg::OnInitDialog() {
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE); SetIcon(m_hIcon, FALSE);
// 載入背景圖並調整視窗大小
CBitmap bitmap;
BITMAP bitInfo;
bitmap.LoadBitmap(IDB_BACKGROUND);
bitmap.GetBitmap(&bitInfo);
CRect rect; GetWindowRect(&rect);
rect.right = rect.left + bitInfo.bmWidth;
rect.bottom = rect.top + bitInfo.bmHeight;
MoveWindow(rect);
// 建立相容 DC 並選入圖片
m_DC.CreateCompatibleDC(GetDC());
m_oldBitmap = m_DC.SelectObject(&bitmap);
// 取得透明色(以左上角像素為準)
COLORREF maskColor = m_DC.GetPixel(0, 0);
// 動態載入 SetLayeredWindowAttributes
#define LWA_COLORKEY 0x00000001
#define WS_EX_LAYERED 0x00080000
typedef BOOL (WINAPI *LPFN_SETLAYEREDWINDOWATTRIBUTES)(HWND, COLORREF, BYTE, DWORD);
LPFN_SETLAYEREDWINDOWATTRIBUTES pSetLayeredWindowAttributes;
HMODULE hUser32 = GetModuleHandle("user32.dll");
pSetLayeredWindowAttributes = (LPFN_SETLAYEREDWINDOWATTRIBUTES)
GetProcAddress(hUser32, "SetLayeredWindowAttributes");
// 設定分層視窗樣式
SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE,
GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE) | WS_EX_LAYERED);
// 套用透明色鍵
pSetLayeredWindowAttributes(GetSafeHwnd(), maskColor, 255, LWA_COLORKEY);
FreeLibrary(hUser32);
return TRUE;
}
void CTransWindowDlg::OnPaint() {
if (IsIconic()) { /* 預設圖示繪製 */ }
else {
CDC* pDC = GetDC();
CRect rect; GetWindowRect(&rect);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &m_DC, 0, 0, SRCCOPY);
}
}
// 禁用背景擦除以消除啟動閃爍
BOOL CTransWindowDlg::OnEraseBkgnd(CDC* pDC) {
return TRUE; // 不呼叫基底類別
}
void CTransWindowDlg::OnClose() {
CBitmap* bitmap = m_DC.SelectObject(m_oldBitmap);
m_DC.DeleteDC();
bitmap->DeleteObject();
CDialog::OnClose();
}
void CTransWindowDlg::OnLButtonDblClk(UINT nFlags, CPoint point) {
PostMessage(WM_CLOSE); // 雙擊關閉
CDialog::OnLButtonDblClk(nFlags, point);
}