?? classxp.c
字號:
////////////////////////////////////////////////////////////////////////////////////////////////////
// 說明: ClassXP.c 文件
// 更新: 2003-3-10
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// 編譯預處理
#if _WIN32_WINNT < 0x0400
#define _WIN32_WINNT 0x0400
#endif
#include <Windows.h>
#include "ClassXP.h"
#pragma warning(disable: 4311)
#pragma warning(disable: 4312)
#pragma comment(lib, "Msimg32.lib")
// 導出函數
#ifdef CXP_DLLMODE
#pragma comment(linker, "/EXPORT:ClassXP=_ClassXP@8")
#endif // CXP_DLLMODE
// 強制使用 C 語言方式編譯
#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// 宏定義
// 窗口類型
#define CXPT_UNKNOWN -1 // 不能處理的類型
#define CXPT_PUSHBUTTON 0 // 按鈕
#define CXPT_CHECKBOX 1 // 復選框
#define CXPT_RADIOBOX 2 // 單選框
#define CXPT_EDITBOX 3 // 編輯框
#define CXPT_COMBOBOX 4 // 組合框
// 窗口狀態
#define CXPS_DISABLED 0x00000001L // 禁用狀態
#define CXPS_PRESSED 0x00000002L // 按下狀態
#define CXPS_HOTLIGHT 0x00000004L // 高亮狀態 (鼠標在該窗口上)
#define CXPS_FOCUS 0x00000008L // 具有鍵盤輸入焦點
#define CXPS_DEFAULT 0x00000010L // 默認狀態 (用于按鈕)
#define CXPS_CHECKED 0x00000020L // 選中狀態 (用于復選框)
#define CXPS_INDETERMINATE 0x00000040L // 未確定狀態 (用于復選框)
#define CXPS_READONLY 0x00000080L // 只讀狀態 (用于編輯框)
// 設置窗口狀態
#define CXPM_SETSTATE(Data, Mask, IsSet) ((IsSet) ? (Data |= Mask) : (Data &= ~Mask))
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// CLASSXP 結構,所有的代碼都是圍繞這個結構而編寫的
typedef struct tagCLASSXP
{
HWND hWnd; // 窗口句柄
DWORD dwType; // 窗口的類型
DWORD dwState; // 窗口的狀態
WNDPROC wpPrev; // 子類化之前的窗口回調函數地址
struct tagCLASSXP * pNext; // 指向下一個 CLASSXP 結構,這里采用單向鏈表結構
}
CLASSXP, * PCLASSXP;
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// MEMDCXP 結構,為了方便使用內存兼容設備場景而設計
typedef struct tagMEMDCXP
{
HWND hWnd; // 窗口句柄,輸入參數
HDC hDC; // 窗口設備場景,輸出參數
HDC hMemDC; // 窗口內存兼容設備場景,輸出參數
BOOL bTransfer; // 是否要用在 hDC 和 hMemDC 間傳送數據,輸入參數
HBITMAP hBitmap; // 位圖句柄,輸入和輸出參數
}
MEMDCXP, * LPMEMDCXP;
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// 函數聲明
PCLASSXP WINAPI CreateClassXP(HWND hWnd);
PCLASSXP WINAPI DeleteClassXP(HWND hWnd);
PCLASSXP WINAPI GetClassXP(HWND hWnd);
DWORD WINAPI GetWindowTypeXP(HWND hWnd);
HDC WINAPI GetMemDCXP(LPMEMDCXP pMdcxp);
VOID WINAPI ReleaseMemDCXP(LPMEMDCXP pMdcxp);
VOID WINAPI GradientRectXP(HDC hDC, LPRECT pRect,COLORREF crColor[4]);
VOID WINAPI DrawDropGripXP(HDC hDC, LPRECT pRect);
BOOL CALLBACK EnumWndProcXP(HWND hWnd, LPARAM lParam);
LRESULT CALLBACK HookProcXP(int iCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK WindowProcXP(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
VOID WINAPI DrawPushButtonXP(PCLASSXP pCxp);
VOID WINAPI DrawCheckBoxXP(PCLASSXP pCxp);
VOID WINAPI DrawRadioBoxXP(PCLASSXP pCxp);
VOID WINAPI DrawEditBoxXP(PCLASSXP pCxp);
VOID WINAPI DrawComboBoxXP(PCLASSXP pCxp);
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// 全局變量
HHOOK g_hPrevHookXP = NULL; // 窗口消息 HOOK 句柄
PCLASSXP g_pClassXP = NULL; // 窗口的 CLASSXP 結構指針
#ifdef CXP_DLLMODE
HINSTANCE g_hModuleXP = NULL; // 動態連接庫模塊句柄
#endif // CXP_DLLMODE
////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef CXP_DLLMODE
////////////////////////////////////////////////////////////////////////////////////////////////////
// 動態連接庫主函數
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID pvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
g_hModuleXP = hModule;
DisableThreadLibraryCalls(hModule);
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
#endif // CXP_DLLMODE
////////////////////////////////////////////////////////////////////////////////////////////////////
// 設置或取消窗口的 ClassXP 風格
BOOL WINAPI ClassXP(HWND hWnd, BOOL bEnable)
{
BOOL bReturn;
bReturn = FALSE;
// 如果是影響當前進程中的所有窗口
if (hWnd == NULL)
{
// 如果是取消當前進程中的所有窗口
if ((bEnable == FALSE) && (g_hPrevHookXP != NULL))
{
// 枚舉當前線程的窗口并取消 ClassXP 風格
EnumThreadWindows(GetCurrentThreadId(), EnumWndProcXP, FALSE);
// 取消窗口消息 HOOK
bReturn = UnhookWindowsHookEx(g_hPrevHookXP);
g_hPrevHookXP = NULL;
}
// 如果是設置當前進程中的所有窗口
else if ((bEnable == TRUE) && (g_hPrevHookXP == NULL))
{
// 枚舉當前線程中已存在的窗口并設置為 ClassXP 風格
EnumThreadWindows(GetCurrentThreadId(), EnumWndProcXP, TRUE);
// 安裝窗口消息 HOOK
g_hPrevHookXP = SetWindowsHookEx(WH_CALLWNDPROC, HookProcXP, 0, GetCurrentThreadId());
bReturn = (BOOL) g_hPrevHookXP;
}
}
else
{
// 如果是取消指定窗口的 ClassXP 風格
if (bEnable == FALSE)
bReturn = (BOOL) DeleteClassXP(hWnd);
// 如果是設置指定窗口的 ClassXP 風格
else
bReturn = (BOOL) CreateClassXP(hWnd);
}
return bReturn;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// 創建并初始化 CLASSXP 數據結構;子類化窗口
// 如果返回 NULL,表示沒有創建;否則返回新創建節點的指針,同時 g_pClassXP 指向新創建的節點
PCLASSXP WINAPI CreateClassXP(HWND hWnd)
{
LONG lStyle;
DWORD dwType;
PCLASSXP pCxp;
// 是否已經是 ClassXP 風格
if (GetClassXP(hWnd) == NULL)
{
// 獲取窗口類型,如果并判斷是否能設置為 ClassXP 風格
dwType = GetWindowTypeXP(hWnd);
if ((dwType >= CXPT_PUSHBUTTON) && (dwType <= CXPT_COMBOBOX))
{
lStyle = GetWindowLong(hWnd, GWL_STYLE);
// 分配存儲空間,增加一個節點
pCxp = (PCLASSXP) HeapAlloc(GetProcessHeap(), 0, sizeof(CLASSXP));
pCxp->pNext = g_pClassXP;
g_pClassXP = pCxp;
// 子類化窗口并初始化 CLASSXP 數據結構
pCxp->hWnd = hWnd;
pCxp->dwType = dwType;
pCxp->dwState = (lStyle & WS_DISABLED) ? CXPS_DISABLED : 0;
if (hWnd == GetFocus())
pCxp->dwState |= CXPS_FOCUS;
pCxp->wpPrev = (WNDPROC) SetWindowLong(hWnd, GWL_WNDPROC, (LONG) WindowProcXP);
// 按窗口類型分別 CLASSXP 數據結構
switch (dwType)
{
case CXPT_PUSHBUTTON:
case CXPT_CHECKBOX:
case CXPT_RADIOBOX:
if ((lStyle & SS_TYPEMASK) == BS_DEFPUSHBUTTON)
pCxp->dwState |= CXPS_DEFAULT;
lStyle = (LONG) SendMessage(hWnd, BM_GETCHECK, 0, 0);
if (lStyle == BST_CHECKED)
pCxp->dwState |= CXPS_CHECKED;
else if (lStyle == BST_INDETERMINATE)
pCxp->dwState |= CXPS_INDETERMINATE;
break;
case CXPT_EDITBOX:
if (lStyle & ES_READONLY)
pCxp->dwState |= CXPS_READONLY;
break;
}
// 重畫窗口
RedrawWindow(hWnd, NULL, NULL,
RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ERASENOW | RDW_UPDATENOW);
return pCxp;
}
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// 取消窗口子類化;銷毀窗口的 CLASSXP 數據結構
// 如果返回值不為 NULL 表示成功刪除,返回值為指向上一個節點指針;
// 如果返回 NULL 且 g_pClassXP 為 NULL,表全部節點被刪除;
// 否則表示沒有找到該節點。
// 致謝: 感謝 dREAMtHEATER 改進此函數!
PCLASSXP WINAPI DeleteClassXP(HWND hWnd)
{
PCLASSXP pDel;
PCLASSXP pCxp;
// 獲取待刪除的節點指針
pDel = GetClassXP(hWnd);
if (pDel != NULL)
{
// 如果待刪除的節點就是 g_pClassXP 節點
if (pDel == g_pClassXP)
pCxp = g_pClassXP = pDel->pNext;
else
{
// 循環查找待刪除節點的上一個節點
for (pCxp = g_pClassXP; pCxp != NULL; pCxp = pCxp->pNext)
{
// 如果找到
if (pCxp->pNext == pDel)
{
// 使鏈表跳過待刪除的節點
pCxp->pNext = pDel->pNext;
break;
}
}
}
// 取消窗口子類化并重畫窗口
SetWindowLong(hWnd, GWL_WNDPROC, (LONG) pDel->wpPrev);
// 刪除堆內存
HeapFree(GetProcessHeap(), 0, pDel);
// 重畫窗口
RedrawWindow(hWnd, NULL, NULL,
RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ERASENOW | RDW_UPDATENOW);
return pCxp;
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// 獲取窗口的 CLASSXP 數據結構
// 如果返回 NULL,表示沒有找到;否則返回節點的指針
PCLASSXP WINAPI GetClassXP(HWND hWnd)
{
PCLASSXP pCxp;
for (pCxp = g_pClassXP; pCxp != NULL; pCxp = pCxp->pNext)
{
if (pCxp->hWnd == hWnd)
return pCxp;
}
return FALSE;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// 獲取窗口類型
DWORD WINAPI GetWindowTypeXP(HWND hWnd)
{
DWORD lReturn;
char szTemp[MAX_PATH];
static char s_szClass[][32] =
{
"Button", // 按鈕類
"Edit", // 編輯框類
"ComboBox", // 組合框類
#ifdef CXP_DLLMODE
"TButton", // VCL TButton 類
"ThunderCommandButton", // Visual Basic Command Button 類
"ThunderRT6CommandButton", // Visual Basic Command Button 類
"TCheckBox",
"ThunderCheckBox",
"ThunderRT6CheckBox",
"TEdit",
"TNumberEdit",
"ThunderTextBox",
"ThunderRT6TextBox",
"TComboBox",
"ThunderComboBox",
"ThunderRT6ComboBox"
#endif // CXP_DLLMODE
};
// 查找判斷匹配的類名稱
GetClassName(hWnd, szTemp, sizeof(szTemp));
for (lReturn = 0; lReturn < (sizeof(s_szClass) / sizeof(s_szClass[0])); lReturn++)
if (lstrcmpi(szTemp, s_szClass[lReturn]) == 0)
break;
switch (lReturn)
{
case 0:
lReturn = GetWindowLong(hWnd, GWL_STYLE);
switch (lReturn & SS_TYPEMASK)
{
case BS_DEFPUSHBUTTON: // 默認按鈕
case BS_PUSHBUTTON: // 普通按鈕
lReturn = CXPT_PUSHBUTTON;
break;
case BS_CHECKBOX: // 復選框
case BS_AUTOCHECKBOX: // 自動復選框
case BS_3STATE: // 三狀態復選框
case BS_AUTO3STATE: // 自動三狀態復選框
if (lReturn & BS_PUSHLIKE)
lReturn = CXPT_PUSHBUTTON;
else
lReturn = CXPT_CHECKBOX;
break;
case BS_RADIOBUTTON: // 單選框
case BS_AUTORADIOBUTTON: // 自動單選框
if (lReturn & BS_PUSHLIKE)
lReturn = CXPT_PUSHBUTTON;
else
lReturn = CXPT_RADIOBOX;
break;
default: // 未知類型
lReturn = CXPT_UNKNOWN;
}
break;
case 1: // 編輯框
lReturn = CXPT_EDITBOX;
break;
case 2: // 組合框
if ((GetWindowLong(hWnd, GWL_STYLE) & 0x00000003) == CBS_SIMPLE)
lReturn = CXPT_UNKNOWN;
else
lReturn = CXPT_COMBOBOX;
break;
#ifdef CXP_DLLMODE
// VB 和 VCL 的控件,只有在動態連接庫方式下才有可能出現這種情況
case 3:
case 4:
case 5:
lReturn = CXPT_PUSHBUTTON;
break;
case 6:
case 7:
case 8:
lReturn = CXPT_CHECKBOX;
break;
case 9:
case 10:
case 11:
case 12:
lReturn = CXPT_EDITBOX;
break;
case 13:
case 14:
case 15:
lReturn = CXPT_COMBOBOX;
break;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -