首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

VC++ 實現視窗透明/半透明效果:SetLayeredWindowAttributes 動態載入技巧 (免 SDK 升級)

     編輯:VC 教學

背景與挑戰

Windows 2000+ 引入分層視窗 (WS_EX_LAYERED) 支援半透明、透明色鍵、Alpha 混合。核心 API SetLayeredWindowAttributes 定義於 Winuser.h,需最新 Platform SDK。舊版 VC6 預設 SDK 無此定義,升級 SDK 體積龐大 (200MB+)。本文展示動態載入 User32.dll 取得函式指標技巧,免升級 SDK 即可使用新 API。

核心 API 簽名與常數


// Winuser.h 定義 (手動補充)
#define WS_EX_LAYERED           0x00080000
#define LWA_COLORKEY            0x00000001 // 使用透明色鍵
#define LWA_ALPHA               0x00000002 // 使用 Alpha 混合

BOOL WINAPI SetLayeredWindowAttributes(
    HWND hwnd,           // 分層視窗句柄
    COLORREF crKey,      // 透明色鍵 (LWA_COLORKEY 時使用)
    BYTE bAlpha,         // Alpha 值 0-255 (LWA_ALPHA 時使用),0=全透明, 255=不透明
    DWORD dwFlags        // LWA_COLORKEY | LWA_ALPHA
);

動態載入實作步驟

1. 定義函式指標類型


typedef BOOL (WINAPI *PFN_SetLayeredWindowAttributes)(
    HWND, COLORREF, BYTE, DWORD
);

2. OnInitDialog 中啟用分層屬性並動態呼叫


BOOL CTransparentDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // 步驟 1:加上 WS_EX_LAYERED 擴充風格
    // 使用 XOR 切換位元,避免覆蓋現有擴充風格
    DWORD exStyle = GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);
    SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, exStyle ^ WS_EX_LAYERED);

    // 步驟 2:動態載入 User32.dll 並取得函式指標
    HMODULE hUser32 = LoadLibrary(_T("User32.dll"));
    if (hUser32)
    {
        PFN_SetLayeredWindowAttributes pfn = 
            (PFN_SetLayeredWindowAttributes)GetProcAddress(hUser32, "SetLayeredWindowAttributes");

        if (pfn)
        {
            // 範例:設定 50% 半透明 (Alpha = 128)
            // dwFlags = LWA_ALPHA (0x2),crKey 忽略 (設 0)
            pfn(GetSafeHwnd(), 0, 128, LWA_ALPHA);

            // 替代方案:設定透明色鍵 (如將白色背景變透明)
            // pfn(GetSafeHwnd(), RGB(255,255,255), 0, LWA_COLORKEY);
        }
        FreeLibrary(hUser32);
    }

    return TRUE;
}

進階應用:淡入淡出動畫


// 成員變數
BYTE m_bCurrentAlpha = 0;
bool m_bFadingIn = true;
CButton m_btnToggle;

// OnInitDialog 追加
SetTimer(TIMER_FADE, 50, NULL); // 50ms 更新一次

// OnTimer
void CTransparentDlg::OnTimer(UINT_PTR nIDEvent)
{
    if (nIDEvent == TIMER_FADE)
    {
        HMODULE hUser32 = LoadLibrary(_T("User32.dll"));
        if (hUser32)
        {
            auto pfn = (PFN_SetLayeredWindowAttributes)GetProcAddress(hUser32, "SetLayeredWindowAttributes");
            if (pfn)
            {
                if (m_bFadingIn)
                {
                    m_bCurrentAlpha += 10;
                    if (m_bCurrentAlpha >= 255) { m_bCurrentAlpha = 255; m_bFadingIn = false; KillTimer(TIMER_FADE); }
                }
                else
                {
                    if (m_bCurrentAlpha >= 10) m_bCurrentAlpha -= 10;
                    else { m_bCurrentAlpha = 0; m_bFadingIn = true; KillTimer(TIMER_FADE); }
                }
                pfn(GetSafeHwnd(), 0, m_bCurrentAlpha, LWA_ALPHA);
            }
            FreeLibrary(hUser32);
        }
    }
    CDialog::OnTimer(nIDEvent);
}

關鍵注意事項與避坑指南

問題原因解決
視窗完全消失 (找不到)Alpha 設為 0 (全透明) 且無色鍵Alpha 最小設 10-20,或保留標題列/邊框 (WS_CAPTION) 可見
子控制項 (按鈕、編輯框) 也變透明分層視窗預設整個視窗 (含子控制項) 混合無法分離。需求「僅背景透明、控制項不透明」請改用 UpdateLayeredWindow + 手繪背景,或使用 DWM (Vista+) DwmExtendFrameIntoClientArea
GDI 繪圖異常 (文字模糊、位圖錯位)分層視窗使用預乘 Alpha,標準 GDI 不支援使用 UpdateLayeredWindow 配合 32-bit 位圖 (含 Alpha 通道) 繪製
Windows 9x/Me 不支援分層視窗需 Win2000+執行檢查:if (GetVersion() & 0x80000000) { /* 9x 系列,降級處理 */ }
動態載入 GetProcAddress 失敗系統版本過舊 (Win2000 前) 或 User32.dll 未載入LoadLibrary 確保載入,檢查回傳值,優雅降級 (不啟用透明)

現代替代方案:DWM 玻璃效果 (Vista/Win7+)


#include 
#pragma comment(lib, "dwmapi.lib")

// 擴展客戶區至整個視窗 (玻璃邊框)
MARGINS margins = {-1}; // -1 表示整個客戶區
DwmExtendFrameIntoClientArea(GetSafeHwnd(), &margins);

// 客戶區繪製時背景透明 (需 WS_EX_LAYERED 配合)

優點:原生支援 Aero 玻璃、標題列整合、子控制項正常不透明。缺點:需 Vista+、主題開啟、相容性測試較複雜。

結語

動態載入 SetLayeredWindowAttributes 是 VC6 時代免升級 SDK 使用新 API 的經典技巧,核心思想:**LoadLibrary + GetProcAddress + 函式指標呼叫**。雖然現代開發環境 (VS2017+/Windows SDK 10) 已內建完整標頭庫,但此技巧對插件開發、舊專案維護、跨版本相容性測試仍具參考價值。理解分層視窗限制 (子控制項同步透明、GDI 繪圖問題),在需求複雜時果斷遷移至 UpdateLayeredWindow 或 DWM API。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved