研讀《Windows 程式設計》時便使用 SkinMagic 進行換膚,但其 SDK 範例僅支援以檔案方式載入皮膚,使用不便且存在 Bug。後來參考 VCKBASE 網站線上雜誌中「用 SkinMagic 工具包建立換膚程式」一文,終於掌握將皮膚加入靜態資源為 SDK 程式換膚的方法。原文作者使用 MFC 實現,本文提供 SDK 版本。主要解決標題列出現 "[Powered by SkinMagic]" 的問題,改用 SkinMagic SDK 1.0 Library,支援更多皮膚格式。
SkinMagicLib.h、SkinMagicLib.lib、DETOURS.lib 從範例專案 ./res 目錄透過 Project → Add To Project → Files 加入專案。stdafx.h 中加入 #include "SkinMagicLib.h"WinMain 開頭加入初始化程式碼:
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// 載入 SkinMagicLib.lib、DETOURS.lib
InitSkinMagicLib(hInstance, "LINJIN", NULL, NULL);
// LoadSkinFile("corona.smf"); // 檔案方式載入
// 載入靜態自訂皮膚資源
LoadSkinFromResource(GetModuleHandle(NULL), "XPBLUE", "SKINMAGIC");
// 為程式對話方塊換膚
SetDialogSkin("Dialog");
......
// WinMain 結束時釋放 SkinMagic 資源
ExitSkinMagicLib();
}
InitInstance 中設定主視窗皮膚:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
......
// 若程式使用選單,必須在 SetWindowSkin 之前呼叫,否則 hMenu 為 NULL
hMenu = GetMenu(hWnd);
// 將皮膚套用至程式框架
SetWindowSkin(hWnd, "MainFrame");
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
WndProc 中建立選單與皮膚資源對應:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
......
static char* idColor[7] = { "XPBLUE", "CORONA", "KROMO",
"XPGREAN", "XPLUS", "XPSTEEL", "DEVIOR" };
......
switch (wmId)
{
case IDM_XP:
case IDM_CORONA:
case IDM_KROMO:
case IDM_XPGREAN:
case IDM_XPLUS:
case IDM_XPSTEEL:
case IDM_DEVIOR:
// 選單選擇處理
CheckMenuItem(hMenu, iSelection, MF_UNCHECKED);
iSelection = wmId;
CheckMenuItem(hMenu, iSelection, MF_CHECKED);
LoadSkinFromResource(GetModuleHandle(NULL),
idColor[LOWORD(wParam) - IDM_XP], "SKINMAGIC");
InvalidateRect(hWnd, NULL, TRUE);
return 0;
......
}
}
其他細節請參考原始碼,範例專案無需修改即可直接編譯。./res 目錄包含經處理不會顯示 "[Powered by SkinMagic]" 的 SkinMagicLib.lib、DETOURS.lib 及多款皮膚檔案。
目前 SkinMagic 仍有一個未解決的 Bug:子選單回傳值為 0,無法使用。期待作者與各位高手有好的解決方案。
下圖為範例程式執行截圖: