⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 classxp.c

📁 OA系统权限管理设计任何系统都离不开权限的管理,有一个好的权限管理模块,不仅使我们的系统操作自如,管理方便,也为系统添加亮点
💻 C
📖 第 1 页 / 共 3 页
字号:



////////////////////////////////////////////////////////////////////////////////////////////////////
// 说明: 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 + -