Browse Source

SkinUI库添加,未配置完成。

Jeff 6 years ago
parent
commit
b914812e9f

+ 217 - 0
source/hook/WeChats/CDLG_Login.cpp

@@ -0,0 +1,217 @@
+// CDLG_Login.cpp: 实现文件
+//
+
+#include "stdafx.h"
+#include "WeChats.h"
+#include "CDLG_Login.h"
+#include "afxdialogex.h"
+
+
+// CDLG_Login 对话框
+
+IMPLEMENT_DYNAMIC(CDLG_Login, CDialogEx)
+
+CDLG_Login::CDLG_Login(CWnd* pParent /*=nullptr*/)
+	: CDialogEx(IDD_DLG_LOGIN, pParent)
+	, m_strAccount(_T("admin"))
+	, m_strPassword(_T("ly1234"))
+{
+
+}
+
+CDLG_Login::~CDLG_Login()
+{
+}
+
+void CDLG_Login::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+	DDX_Text(pDX, TX_ACCOUNT, m_strAccount);
+	DDX_Text(pDX, TX_PASSWROD, m_strPassword);
+	DDX_Control(pDX, ST_ACCOUNT, m_stAccount);
+	DDX_Control(pDX, ST_PASSWORD, m_stPassWord);
+	DDX_Control(pDX, IDCANCEL, m_btnCancel);
+	DDX_Control(pDX, IDOK, m_btnLogin);
+}
+
+
+BEGIN_MESSAGE_MAP(CDLG_Login, CDialogEx)
+	ON_WM_ERASEBKGND()
+	ON_WM_PAINT()
+END_MESSAGE_MAP()
+
+
+// CDLG_Login 消息处理程序
+
+
+BOOL CDLG_Login::OnInitDialog()
+{
+	CDialogEx::OnInitDialog();
+
+	// TODO:  在此添加额外的初始化
+	InitAllCtrl();
+	AdjustControl();
+	return TRUE;  // return TRUE unless you set the focus to a control
+				  // 异常: OCX 属性页应返回 FALSE
+}
+
+
+BOOL CDLG_Login::OnEraseBkgnd(CDC* pDC)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	return TRUE;
+	return CDialogEx::OnEraseBkgnd(pDC);
+}
+
+
+BOOL CDLG_Login::PreTranslateMessage(MSG* pMsg)
+{
+	// TODO: 在此添加专用代码和/或调用基类
+	// TODO: 在此添加专用代码和/或调用基类
+	if (pMsg->message == WM_LBUTTONDOWN && pMsg->hwnd == m_hWnd)
+	{
+		pMsg->message = WM_NCLBUTTONDOWN;
+		pMsg->wParam = HTCAPTION;
+	}
+
+	return CDialogEx::PreTranslateMessage(pMsg);
+}
+
+
+void CDLG_Login::OnPaint()
+{
+	CPaintDC dc(this); // device context for painting
+					   // TODO: 在此处添加消息处理程序代码
+					   // 不为绘图消息调用 CDialogEx::OnPaint()
+	//调整控件位置////////////////////////////
+	ChangeWindowRgn();
+	AdjustControl();
+
+	CRect rcClient;
+	GetClientRect(&rcClient);
+
+	//内存画图//////////////////////////
+	CDC MemDC;
+	MemDC.CreateCompatibleDC(&dc);
+
+	CBitmap btScreen;
+	btScreen.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height());
+
+	MemDC.SelectObject(&btScreen);
+	btScreen.DeleteObject();
+
+	//画背景;
+	MemDC.Rectangle(rcClient);
+	MemDC.FillSolidRect(rcClient, RGB(91, 195, 252));//draw the backGround
+	if (m_DLGBackground.m_hObject != 0)
+		m_DLGBackground.ExtendDraw(&MemDC, rcClient, 0, 0);
+
+	//重画控件/////////////////////////
+	ReDrawCrl(&MemDC);
+
+	//画到显示器上////////////////////////////
+	dc.BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &MemDC, 0, 0, SRCCOPY);
+
+	MemDC.DeleteDC();
+}
+
+
+void CDLG_Login::InitAllCtrl()
+{
+	CString strSkinpath = _T("Skin\\");
+	// 加载对话框背景图片;
+	if (PathFileExists(strSkinpath + _T("登录窗口.bmp")))
+		m_DLGBackground.LoadImage(strSkinpath + _T("登录窗口.bmp"));
+	else
+		m_DLGBackground.LoadImage(strSkinpath + _T("dlgbk.bmp"));
+
+	// 加载按钮背景图片;
+	m_btnCancel.ShowOwnerText();
+	m_btnLogin.ShowOwnerText();
+	m_btnCancel.LoadImage(strSkinpath + _T("btn.bmp"));
+	m_btnLogin.LoadImage(strSkinpath + _T("btn.bmp"));
+#if 0 // 在线版客户端不需要设置端口号与服务器地址;
+	m_btnLoginSet.LoadImage(strSkinpath + _T("loginset.bmp"));
+#endif
+
+	// 设置静态文本背景透明;
+	m_stStudioID.SetTransparent(TRUE);
+	m_stAccount.SetTransparent(TRUE);
+	m_stPassWord.SetTransparent(TRUE);
+
+}
+
+void CDLG_Login::ChangeWindowRgn() // 清除不规则窗体的其他边角;
+{
+	CRect rc;
+	GetClientRect(&rc);
+
+	CEnBitmap bmpWorkpanel;
+	if (m_DLGBackground.m_hObject != NULL)
+		m_DLGBackground.ExtendDrawImage(bmpWorkpanel, rc, 0, 0);
+
+	if (m_hrgn)
+		DeleteObject(m_hrgn);
+	m_hrgn = bmpWorkpanel.BitmapToRegion(RGB(255, 0, 255));
+	SetWindowRgn(m_hrgn, TRUE);
+
+	bmpWorkpanel.DeleteObject();
+}
+
+void CDLG_Login::AdjustControl()
+{
+	CRect rc;
+	GetClientRect(&rc);
+	int cx = rc.Width();
+	int cy = rc.Height();
+
+#if 0 // 在线版客户端不需要设置端口号与服务器地址;
+	// 登录设置按钮;
+	m_btnLoginSet.SetWindowPos(NULL, cx - m_btnLoginSet.Width() - 5, 0, 0, 0, SWP_NOSIZE);
+#endif
+	// 最小化按钮;
+	/*m_btnMin.SetWindowPos(NULL, cx - m_btnClose.Width() - m_btnMin.Width() - 5, 0, 0, 0, SWP_NOSIZE);
+	*/
+}
+
+void CDLG_Login::ReDrawCrl(CDC* pMemDC)
+{
+	CRect rcClient;
+	GetClientRect(&rcClient);
+
+	static bool firstGetClientRect = true;
+	static int preClientHeight = rcClient.Height();
+	static int preClientWidth = rcClient.Width();
+	if (firstGetClientRect)
+	{
+		firstGetClientRect = false;
+	}
+
+	if (firstGetClientRect || preClientHeight != rcClient.Height() || preClientWidth != rcClient.Width())
+	{
+		preClientHeight = rcClient.Height();
+		preClientWidth = rcClient.Width();
+
+		CEnBitmap *bmpPaint = NULL;
+		CImage *image = NULL;
+
+		CRect rcIcon;
+		CPoint ptText;
+		CString strText;
+
+		CRect rect;
+		GetClientRect(&rect);
+		int cx = rect.Width();
+		int cy = rect.Height();
+
+		bmpPaint = m_btnLogin.GetPaintBmp();
+		rect = m_btnLogin.GetRectInParent();
+		if (bmpPaint->m_hObject != 0)
+			bmpPaint->TransparentBlt(*pMemDC, rect, RGB(255, 0, 255));
+
+		bmpPaint = m_btnCancel.GetPaintBmp();
+		rect = m_btnCancel.GetRectInParent();
+		if (bmpPaint->m_hObject != 0)
+			bmpPaint->TransparentBlt(*pMemDC, rect, RGB(255, 0, 255));
+	}
+}

+ 48 - 0
source/hook/WeChats/CDLG_Login.h

@@ -0,0 +1,48 @@
+#pragma once
+
+#include "EnBitmap.h"
+#include "SkinButton.h"
+#include "SubLabel.h"
+// CDLG_Login 对话框
+
+class CDLG_Login : public CDialogEx
+{
+	DECLARE_DYNAMIC(CDLG_Login)
+
+public:
+	CDLG_Login(CWnd* pParent = nullptr);   // 标准构造函数
+	virtual ~CDLG_Login();
+
+// 对话框数据
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_DLG_LOGIN };
+#endif
+
+public:
+	INT				m_nLogInStatus;
+	CString			m_strAccount;
+	CString			m_strPassword;
+	CEnBitmap		m_DLGBackground;
+	// 不规则背景要去掉的颜色;
+	HRGN			m_hrgn;
+	CLabel			m_stStudioID;
+	CLabel			m_stAccount;
+	CLabel			m_stPassWord;
+	CSkinButton		m_btnLogin;
+	CSkinButton		m_btnCancel;
+
+	void ChangeWindowRgn();
+	void InitAllCtrl();
+	void AdjustControl();
+	void ReDrawCrl(CDC* pMemDC);
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
+
+	DECLARE_MESSAGE_MAP()
+public:
+	virtual BOOL OnInitDialog();
+	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
+	virtual BOOL PreTranslateMessage(MSG* pMsg);
+	afx_msg void OnPaint();
+};

+ 20 - 14
source/hook/WeChats/Resource.h

@@ -1,21 +1,27 @@
 //{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by WeChats.rc
+// Microsoft Visual C++ 生成的包含文件。
+// 供 WeChats.rc 使用
 //
-#define IDR_MAINFRAME					128
-#define IDM_ABOUTBOX					0x0010
-#define IDD_ABOUTBOX					100
-#define IDS_ABOUTBOX					101
-#define IDD_WECHATS_DIALOG				102
+#define IDM_ABOUTBOX                    0x0010
+#define IDD_ABOUTBOX                    100
+#define IDS_ABOUTBOX                    101
+#define IDD_WECHATS_DIALOG              102
+#define IDR_MAINFRAME                   128
+#define IDD_DLG_LOGIN                   129
+#define IDD_DLG_REGISTER                131
+#define TX_ACCOUNT                      1001
+#define IDC_EDIT3                       1002
+#define TX_PASSWROD                     1002
+#define ST_ACCOUNT                      1035
+#define ST_PASSWORD                     1036
 
-// 新对象的下一组默认值
-//
+// Next default values for new objects
+// 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
-
-#define _APS_NEXT_RESOURCE_VALUE	129
-#define _APS_NEXT_CONTROL_VALUE		1000
-#define _APS_NEXT_SYMED_VALUE		101
-#define _APS_NEXT_COMMAND_VALUE		32771
+#define _APS_NEXT_RESOURCE_VALUE        133
+#define _APS_NEXT_COMMAND_VALUE         32771
+#define _APS_NEXT_CONTROL_VALUE         1000
+#define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif

+ 7 - 0
source/hook/WeChats/WeChats.cpp

@@ -6,6 +6,7 @@
 #include "WeChats.h"
 #include "WeChatsDlg.h"
 #include "Injection.h"
+#include "CDLG_Login.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
@@ -191,6 +192,12 @@ BOOL CWeChatsApp::InitInstance()
 	// »ñÈ¡ÅäÖÃÐÅÏ¢;
 	GetIniInfo();
 	GetDebugPriv();
+
+	CDLG_Login dlg_login;
+	if ( dlg_login.DoModal() == IDCANCEL )
+	{
+		return FALSE;
+	}
 // 	HANDLE hObject = CreateMutex(NULL, FALSE, _T("CYLGLAppXiao"));
 // 	if (GetLastError() == ERROR_ALREADY_EXISTS)
 // 	{

+ 104 - 46
source/hook/WeChats/WeChats.rc

@@ -1,11 +1,11 @@
-// Microsoft Visual C++ 生成的资源脚本。
+// Microsoft Visual C++ generated resource script.
 //
 #include "resource.h"
 
 #define APSTUDIO_READONLY_SYMBOLS
 /////////////////////////////////////////////////////////////////////////////
 //
-// 从 TEXTINCLUDE 2 资源生成。
+// Generated from the TEXTINCLUDE 2 resource.
 //
 #ifndef APSTUDIO_INVOKED
 #include "targetver.h"
@@ -15,27 +15,34 @@
 /////////////////////////////////////////////////////////////////////////////
 #undef APSTUDIO_READONLY_SYMBOLS
 
+/////////////////////////////////////////////////////////////////////////////
+// 中文(简体,中国) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
+#pragma code_page(936)
+
 #ifdef APSTUDIO_INVOKED
 /////////////////////////////////////////////////////////////////////////////
 //
 // TEXTINCLUDE
 //
 
-1 TEXTINCLUDE
+1 TEXTINCLUDE 
 BEGIN
     "resource.h\0"
 END
 
-2 TEXTINCLUDE
+2 TEXTINCLUDE 
 BEGIN
-	"#ifndef APSTUDIO_INVOKED\r\n"
+    "#ifndef APSTUDIO_INVOKED\r\n"
     "#include ""targetver.h""\r\n"
     "#endif\r\n"
     "#include ""afxres.h""\r\n"
     "\0"
 END
 
-3 TEXTINCLUDE
+3 TEXTINCLUDE 
 BEGIN
     "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
     "#define _AFX_NO_OLE_RESOURCES\r\n"
@@ -46,38 +53,33 @@ BEGIN
     "LANGUAGE 4, 2\r\n"
     "#pragma code_page(936)\r\n"
     "#include ""res\\WeChats.rc2""  // 非 Microsoft Visual C++ 编辑的资源\r\n"
-    "#include ""l.CHS\\afxres.rc""  	// 标准组件\r\n"
+    "#include ""l.CHS\\afxres.rc""      // 标准组件\r\n"
     "#endif\r\n"
     "\0"
 END
 
-/////////////////////////////////////////////////////////////////////////////
 #endif    // APSTUDIO_INVOKED
 
 
 /////////////////////////////////////////////////////////////////////////////
 //
-// 图标
+// Icon
 //
 
-// ID 值最低的图标放在最前面,以确保应用程序图标
-// 在所有系统中保持一致。
-IDR_MAINFRAME           ICON         "res\\WeChats.ico"
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME           ICON                    "res\\WeChats.ico"
 
 
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
-LANGUAGE 4, 2
-#pragma code_page(936)
-
 /////////////////////////////////////////////////////////////////////////////
 //
-// 对话框
+// Dialog
 //
 
 IDD_ABOUTBOX DIALOGEX 0, 0, 170, 62
 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "关于 WeChats"
-FONT 9, "MS Shell Dlg"
+FONT 9, "MS Shell Dlg", 0, 0, 0x1
 BEGIN
     ICON            IDR_MAINFRAME,IDC_STATIC,14,14,21,20
     LTEXT           "WeChats,1.0 版",IDC_STATIC,42,14,114,8,SS_NOPREFIX
@@ -85,27 +87,47 @@ BEGIN
     DEFPUSHBUTTON   "确定",IDOK,113,41,50,14,WS_GROUP
 END
 
-IDD_WECHATS_DIALOG DIALOGEX  0, 0, 320, 200
-STYLE DS_SHELLFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION
- | DS_MODALFRAME
- | WS_SYSMENU
+IDD_WECHATS_DIALOG DIALOGEX 0, 0, 320, 200
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
 EXSTYLE WS_EX_APPWINDOW
 CAPTION "WeChats"
-FONT 9, "MS Shell Dlg"
+FONT 9, "MS Shell Dlg", 0, 0, 0x1
 BEGIN
     DEFPUSHBUTTON   "确定",IDOK,209,179,50,14
     PUSHBUTTON      "取消",IDCANCEL,263,179,50,14
-	CTEXT           "TODO: 在此放置对话框控件。",IDC_STATIC,10,96,300,8
+    CTEXT           "TODO: 在此放置对话框控件。",IDC_STATIC,10,96,300,8
+END
+
+IDD_DLG_LOGIN DIALOGEX 0, 0, 311, 180
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    DEFPUSHBUTTON   "确定",IDOK,90,113,50,14
+    PUSHBUTTON      "取消",IDCANCEL,146,113,50,14
+    EDITTEXT        TX_ACCOUNT,78,64,161,12,ES_AUTOHSCROLL
+    EDITTEXT        TX_PASSWROD,78,80,161,12,ES_PASSWORD | ES_AUTOHSCROLL
+    LTEXT           "用户:",ST_ACCOUNT,40,66,29,8
+    LTEXT           "密码:",ST_PASSWORD,40,83,28,8
+END
+
+IDD_DLG_REGISTER DIALOGEX 0, 0, 310, 177
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "注册账号"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    DEFPUSHBUTTON   "确定",IDOK,199,156,50,14
+    PUSHBUTTON      "取消",IDCANCEL,253,156,50,14
 END
 
+
 /////////////////////////////////////////////////////////////////////////////
 //
-// 版本
+// Version
 //
 
-VS_VERSION_INFO     VERSIONINFO
-  FILEVERSION       1,0,0,1
-  PRODUCTVERSION    1,0,0,1
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -116,26 +138,27 @@ VS_VERSION_INFO     VERSIONINFO
  FILETYPE 0x1L
  FILESUBTYPE 0x0L
 BEGIN
-	BLOCK "StringFileInfo"
-	BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
         BLOCK "080403a8"
-		BEGIN
+        BEGIN
             VALUE "CompanyName", "TODO: <公司名>"
             VALUE "FileDescription", "TODO: <文件说明>"
-			VALUE "FileVersion",     "1.0.0.1"
-			VALUE "InternalName",    "WeChats.exe"
+            VALUE "FileVersion", "1.0.0.1"
+            VALUE "InternalName", "WeChats.exe"
             VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。"
-			VALUE "OriginalFilename","WeChats.exe"
+            VALUE "OriginalFilename", "WeChats.exe"
             VALUE "ProductName", "TODO: <产品名>"
-			VALUE "ProductVersion",  "1.0.0.1"
-		END
-	END
-	BLOCK "VarFileInfo"
-	BEGIN
-		VALUE "Translation", 0x0804, 936
+            VALUE "ProductVersion", "1.0.0.1"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x804, 936
     END
 END
 
+
 /////////////////////////////////////////////////////////////////////////////
 //
 // DESIGNINFO
@@ -151,6 +174,7 @@ BEGIN
         TOPMARGIN, 7
         BOTTOMMARGIN, 55
     END
+
     IDD_WECHATS_DIALOG, DIALOG
     BEGIN
         LEFTMARGIN, 7
@@ -158,14 +182,45 @@ BEGIN
         TOPMARGIN, 7
         BOTTOMMARGIN, 193
     END
+
+    IDD_DLG_LOGIN, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 304
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 173
+    END
+
+    IDD_DLG_REGISTER, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 303
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 170
+    END
 END
 #endif    // APSTUDIO_INVOKED
 
 
+/////////////////////////////////////////////////////////////////////////////
+//
+// AFX_DIALOG_LAYOUT
+//
+
+IDD_DLG_LOGIN AFX_DIALOG_LAYOUT
+BEGIN
+    0
+END
+
+IDD_DLG_REGISTER AFX_DIALOG_LAYOUT
+BEGIN
+    0
+END
+
 
 /////////////////////////////////////////////////////////////////////////////
 //
-// 字符串表
+// String Table
 //
 
 STRINGTABLE
@@ -173,13 +228,15 @@ BEGIN
     IDS_ABOUTBOX            "关于 WeChats(&A)..."
 END
 
+#endif    // 中文(简体,中国) resources
+/////////////////////////////////////////////////////////////////////////////
+
 
-#endif
 
 #ifndef APSTUDIO_INVOKED
 /////////////////////////////////////////////////////////////////////////////
 //
-// 从 TEXTINCLUDE 3 资源生成。
+// Generated from the TEXTINCLUDE 3 resource.
 //
 #define _AFX_NO_SPLITTER_RESOURCES
 #define _AFX_NO_OLE_RESOURCES
@@ -189,9 +246,10 @@ END
 #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
 LANGUAGE 4, 2
 #pragma code_page(936)
-#include "res\\WeChats.rc2"  // 非 Microsoft Visual C++ 编辑的资源
-#include "l.CHS\\afxres.rc"  	// 标准组件
+#include "res\WeChats.rc2"  // 非 Microsoft Visual C++ 编辑的资源
+#include "l.CHS\afxres.rc"      // 标准组件
 #endif
+
 /////////////////////////////////////////////////////////////////////////////
-#endif    // 不是 APSTUDIO_INVOKED
+#endif    // not APSTUDIO_INVOKED
 

+ 23 - 1
source/hook/WeChats/WeChats.vcxproj

@@ -68,7 +68,7 @@
       <PrecompiledHeader>Use</PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
-      <AdditionalIncludeDirectories>..\Include</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>..\Include;..\skinui</AdditionalIncludeDirectories>
       <DisableSpecificWarnings>4018;4065;4146;4244;4251;4267;4305;4307;4309;4334;4355;4506;4800;4996</DisableSpecificWarnings>
     </ClCompile>
     <ResourceCompile>
@@ -124,6 +124,17 @@
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
     </ClCompile>
+    <ClCompile Include="..\skinui\EnBitmap.cpp" />
+    <ClCompile Include="..\skinui\GfxOutBarCtrl.cpp" />
+    <ClCompile Include="..\skinui\MyListCtrl.cpp" />
+    <ClCompile Include="..\skinui\SkinButton.cpp" />
+    <ClCompile Include="..\skinui\SkinEdit.cpp" />
+    <ClCompile Include="..\skinui\SkinStatic.cpp" />
+    <ClCompile Include="..\skinui\SkinTab.cpp" />
+    <ClCompile Include="..\skinui\SkinWin.cpp" />
+    <ClCompile Include="..\skinui\Subclass.cpp" />
+    <ClCompile Include="..\skinui\SubLabel.cpp" />
+    <ClCompile Include="CDLG_Login.cpp" />
     <ClCompile Include="Global.cpp" />
     <ClCompile Include="Injection.cpp" />
     <ClCompile Include="stdafx.cpp">
@@ -135,6 +146,17 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\pb\msg.pb.h" />
+    <ClInclude Include="..\skinui\EnBitmap.h" />
+    <ClInclude Include="..\skinui\GfxOutBarCtrl.h" />
+    <ClInclude Include="..\skinui\MyListCtrl.h" />
+    <ClInclude Include="..\skinui\SkinButton.h" />
+    <ClInclude Include="..\skinui\SkinEdit.h" />
+    <ClInclude Include="..\skinui\SkinStatic.h" />
+    <ClInclude Include="..\skinui\SkinTab.h" />
+    <ClInclude Include="..\skinui\SkinWin.h" />
+    <ClInclude Include="..\skinui\Subclass.h" />
+    <ClInclude Include="..\skinui\SubLabel.h" />
+    <ClInclude Include="CDLG_Login.h" />
     <ClInclude Include="Global.h" />
     <ClInclude Include="IClient.h" />
     <ClInclude Include="InjectInterface.h" />

+ 69 - 0
source/hook/WeChats/WeChats.vcxproj.filters

@@ -16,6 +16,9 @@
     <Filter Include="pb">
       <UniqueIdentifier>{55c59700-6c9f-4b21-b651-29cf03858ee4}</UniqueIdentifier>
     </Filter>
+    <Filter Include="skinui">
+      <UniqueIdentifier>{897b5774-040d-46dc-a590-8dbc3cd600a4}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Global.cpp">
@@ -36,6 +39,39 @@
     <ClCompile Include="..\pb\msg.pb.cc">
       <Filter>pb</Filter>
     </ClCompile>
+    <ClCompile Include="..\skinui\EnBitmap.cpp">
+      <Filter>skinui</Filter>
+    </ClCompile>
+    <ClCompile Include="..\skinui\GfxOutBarCtrl.cpp">
+      <Filter>skinui</Filter>
+    </ClCompile>
+    <ClCompile Include="..\skinui\MyListCtrl.cpp">
+      <Filter>skinui</Filter>
+    </ClCompile>
+    <ClCompile Include="..\skinui\SkinButton.cpp">
+      <Filter>skinui</Filter>
+    </ClCompile>
+    <ClCompile Include="..\skinui\SkinEdit.cpp">
+      <Filter>skinui</Filter>
+    </ClCompile>
+    <ClCompile Include="..\skinui\SkinStatic.cpp">
+      <Filter>skinui</Filter>
+    </ClCompile>
+    <ClCompile Include="..\skinui\SkinTab.cpp">
+      <Filter>skinui</Filter>
+    </ClCompile>
+    <ClCompile Include="..\skinui\SkinWin.cpp">
+      <Filter>skinui</Filter>
+    </ClCompile>
+    <ClCompile Include="..\skinui\Subclass.cpp">
+      <Filter>skinui</Filter>
+    </ClCompile>
+    <ClCompile Include="CDLG_Login.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+    <ClCompile Include="..\skinui\SubLabel.cpp">
+      <Filter>skinui</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Global.h">
@@ -68,6 +104,39 @@
     <ClInclude Include="..\pb\msg.pb.h">
       <Filter>pb</Filter>
     </ClInclude>
+    <ClInclude Include="..\skinui\EnBitmap.h">
+      <Filter>skinui</Filter>
+    </ClInclude>
+    <ClInclude Include="..\skinui\GfxOutBarCtrl.h">
+      <Filter>skinui</Filter>
+    </ClInclude>
+    <ClInclude Include="..\skinui\MyListCtrl.h">
+      <Filter>skinui</Filter>
+    </ClInclude>
+    <ClInclude Include="..\skinui\SkinButton.h">
+      <Filter>skinui</Filter>
+    </ClInclude>
+    <ClInclude Include="..\skinui\SkinEdit.h">
+      <Filter>skinui</Filter>
+    </ClInclude>
+    <ClInclude Include="..\skinui\SkinStatic.h">
+      <Filter>skinui</Filter>
+    </ClInclude>
+    <ClInclude Include="..\skinui\SkinTab.h">
+      <Filter>skinui</Filter>
+    </ClInclude>
+    <ClInclude Include="..\skinui\SkinWin.h">
+      <Filter>skinui</Filter>
+    </ClInclude>
+    <ClInclude Include="..\skinui\Subclass.h">
+      <Filter>skinui</Filter>
+    </ClInclude>
+    <ClInclude Include="CDLG_Login.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="..\skinui\SubLabel.h">
+      <Filter>skinui</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <Image Include="res\WeChats.ico">

+ 1 - 0
source/hook/WeChats/stdafx.h

@@ -39,6 +39,7 @@
 
 
 #include "Global.h"
+#include <afxcontrolbars.h>
 
 
 

+ 38 - 2
source/hook/WeChats2017.sln

@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.28407.52
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.329
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hook", "hook\hook.vcxproj", "{4E160416-52D6-454E-943D-4DD7E1150D25}"
 EndProject
@@ -13,33 +13,69 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WxAdoInterface", "WxAdoInte
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug_Super|Win32 = Debug_Super|Win32
+		Debug_Super|x64 = Debug_Super|x64
 		Debug|Win32 = Debug|Win32
 		Debug|x64 = Debug|x64
+		Release_Super|Win32 = Release_Super|Win32
+		Release_Super|x64 = Release_Super|x64
 		Release|Win32 = Release|Win32
 		Release|x64 = Release|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{4E160416-52D6-454E-943D-4DD7E1150D25}.Debug_Super|Win32.ActiveCfg = Debug|Win32
+		{4E160416-52D6-454E-943D-4DD7E1150D25}.Debug_Super|Win32.Build.0 = Debug|Win32
+		{4E160416-52D6-454E-943D-4DD7E1150D25}.Debug_Super|x64.ActiveCfg = Release|Win32
+		{4E160416-52D6-454E-943D-4DD7E1150D25}.Debug_Super|x64.Build.0 = Release|Win32
 		{4E160416-52D6-454E-943D-4DD7E1150D25}.Debug|Win32.ActiveCfg = Debug|Win32
 		{4E160416-52D6-454E-943D-4DD7E1150D25}.Debug|Win32.Build.0 = Debug|Win32
 		{4E160416-52D6-454E-943D-4DD7E1150D25}.Debug|x64.ActiveCfg = Debug|Win32
+		{4E160416-52D6-454E-943D-4DD7E1150D25}.Release_Super|Win32.ActiveCfg = Release|Win32
+		{4E160416-52D6-454E-943D-4DD7E1150D25}.Release_Super|Win32.Build.0 = Release|Win32
+		{4E160416-52D6-454E-943D-4DD7E1150D25}.Release_Super|x64.ActiveCfg = Release|Win32
+		{4E160416-52D6-454E-943D-4DD7E1150D25}.Release_Super|x64.Build.0 = Release|Win32
 		{4E160416-52D6-454E-943D-4DD7E1150D25}.Release|Win32.ActiveCfg = Release|Win32
 		{4E160416-52D6-454E-943D-4DD7E1150D25}.Release|Win32.Build.0 = Release|Win32
 		{4E160416-52D6-454E-943D-4DD7E1150D25}.Release|x64.ActiveCfg = Release|Win32
+		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Debug_Super|Win32.ActiveCfg = Debug|Win32
+		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Debug_Super|Win32.Build.0 = Debug|Win32
+		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Debug_Super|x64.ActiveCfg = Release|Win32
+		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Debug_Super|x64.Build.0 = Release|Win32
 		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Debug|Win32.ActiveCfg = Debug|Win32
 		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Debug|Win32.Build.0 = Debug|Win32
 		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Debug|x64.ActiveCfg = Debug|Win32
+		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Release_Super|Win32.ActiveCfg = Release|Win32
+		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Release_Super|Win32.Build.0 = Release|Win32
+		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Release_Super|x64.ActiveCfg = Release|Win32
+		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Release_Super|x64.Build.0 = Release|Win32
 		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Release|Win32.ActiveCfg = Release|Win32
 		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Release|Win32.Build.0 = Release|Win32
 		{7704A546-A786-41C8-B22A-04BC05AE4F82}.Release|x64.ActiveCfg = Release|Win32
+		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Debug_Super|Win32.ActiveCfg = Debug|Win32
+		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Debug_Super|Win32.Build.0 = Debug|Win32
+		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Debug_Super|x64.ActiveCfg = Release|Win32
+		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Debug_Super|x64.Build.0 = Release|Win32
 		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Debug|Win32.ActiveCfg = Debug|Win32
 		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Debug|Win32.Build.0 = Debug|Win32
 		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Debug|x64.ActiveCfg = Debug|Win32
+		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Release_Super|Win32.ActiveCfg = Release|Win32
+		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Release_Super|Win32.Build.0 = Release|Win32
+		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Release_Super|x64.ActiveCfg = Release|Win32
+		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Release_Super|x64.Build.0 = Release|Win32
 		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Release|Win32.ActiveCfg = Release|Win32
 		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Release|Win32.Build.0 = Release|Win32
 		{F6D9B47B-95FF-4A7D-BA72-F33A0506BE21}.Release|x64.ActiveCfg = Release|Win32
+		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Debug_Super|Win32.ActiveCfg = Debug|Win32
+		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Debug_Super|Win32.Build.0 = Debug|Win32
+		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Debug_Super|x64.ActiveCfg = Release|Win32
+		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Debug_Super|x64.Build.0 = Release|Win32
 		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Debug|Win32.ActiveCfg = Debug|Win32
 		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Debug|Win32.Build.0 = Debug|Win32
 		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Debug|x64.ActiveCfg = Debug|Win32
+		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Release_Super|Win32.ActiveCfg = Release|Win32
+		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Release_Super|Win32.Build.0 = Release|Win32
+		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Release_Super|x64.ActiveCfg = Release|Win32
+		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Release_Super|x64.Build.0 = Release|Win32
 		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Release|Win32.ActiveCfg = Release|Win32
 		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Release|Win32.Build.0 = Release|Win32
 		{3DA33328-6F2A-4673-9A30-BB8791A88171}.Release|x64.ActiveCfg = Release|Win32

+ 43 - 41
source/hook/WxService/MainProcess.cpp

@@ -92,47 +92,47 @@ En_HP_HandleResult __stdcall CMainProcess::OnReceive( HP_CONNID dwConnID, const
 	switch (thepackage.nCmd)
 	{
 		// 客户端请求登录;
-	case C2CCMD_REQ_LOGIN:
-	{
-		Req_Login(dwConnID, pData, iLength, msg_login(), pSendData, dwSendLen);
-	}
-	break;
-	// 客户端请求登出;
-	case C2CCMD_REQ_LOGOUT:
-	{
-		Req_LogOut(dwConnID, pData, iLength, thepackage, pSendData, dwSendLen);
-	}
-	break;
-	// 客户端请求添加部门;
-	case C2CCMD_NEW_DEPARTMENT:
-	{
-		New_Department(dwConnID, pData, iLength, thepackage, pSendData, dwSendLen);
-	}
-	break;
-	// 客户端请求删除部门;
-	case C2CCMD_DEL_DEPARTMENT:
-	{
-		Del_Department(dwConnID, pData, iLength, thepackage, pSendData, dwSendLen);
-	}
-	break;
-	// 客户端请求修改部门;
-	case C2CCMD_MOD_DEPARTMENT:
-	{
-		// 暂未使用;
-		Mod_Department(dwConnID, pData, iLength, thepackage, pSendData, dwSendLen);
-	}
-	break;
-	// 客户端请求查询部门;
-	case C2CCMD_QRY_DEPARTMENT:
-	{
-		nResult = Ask_Department(dwConnID, pData, iLength, thepackage, pSendData, dwSendLen);
-		if (nResult != HR_IGNORE)
-			return nResult;
-	}
-	break;
-	//////////////////////////////////////////////////////////////////////////
-	default:
+		case C2CCMD_REQ_LOGIN:
+		{
+			Req_Login(dwConnID, pData, iLength, thepackage, pSendData, dwSendLen);
+		}
+		break;
+		// 客户端请求登出;
+		case C2CCMD_REQ_LOGOUT:
+		{
+			Req_LogOut(dwConnID, pData, iLength, thepackage, pSendData, dwSendLen);
+		}
+		break;
+		// 客户端请求添加部门;
+		case C2CCMD_NEW_DEPARTMENT:
+		{
+			New_Department(dwConnID, pData, iLength, thepackage, pSendData, dwSendLen);
+		}
+		break;
+		// 客户端请求删除部门;
+		case C2CCMD_DEL_DEPARTMENT:
+		{
+			Del_Department(dwConnID, pData, iLength, thepackage, pSendData, dwSendLen);
+		}
+		break;
+		// 客户端请求修改部门;
+		case C2CCMD_MOD_DEPARTMENT:
+		{
+			// 暂未使用;
+			Mod_Department(dwConnID, pData, iLength, thepackage, pSendData, dwSendLen);
+		}
+		break;
+		// 客户端请求查询部门;
+		case C2CCMD_QRY_DEPARTMENT:
+		{
+			nResult = Ask_Department(dwConnID, pData, iLength, thepackage, pSendData, dwSendLen);
+			if (nResult != HR_IGNORE)
+				return nResult;
+		}
 		break;
+		//////////////////////////////////////////////////////////////////////////
+		default:
+			break;
 	}
 
 	BOOL bSendResult = ::HP_Server_Send(m_spThis->m_pServer, dwConnID, pSendData, dwSendLen);
@@ -318,8 +318,10 @@ BOOL CMainProcess::Disconnect(IN const DWORD & dwConnId)
 
 
 //////////////////////////////////////////////////////////////////////////
-void CMainProcess::Req_Login(IN HP_CONNID dwConnID, IN const BYTE* pReceiveData, IN INT nReceiveLength, IN msg_login &msg, OUT BYTE*& pSendData, OUT DWORD &dwSendLen)
+void CMainProcess::Req_Login(IN HP_CONNID dwConnID, IN const BYTE* pReceiveData, IN INT nReceiveLength, IN TheProPackage &thepackage, OUT BYTE*& pSendData, OUT DWORD &dwSendLen)
 {
+	msg_login msg;
+	msg.ParseFromArray(thepackage.byBody, thepackage.nDataLen);
 	if (COnlineUser::GetInstance()->IsAccountExist(msg.phone().c_str()) == -1)
 	{// 用户没在线;
 		// 查询数据库是否存在用户;

+ 1 - 1
source/hook/WxService/MainProcess.h

@@ -86,7 +86,7 @@ public:
 	static BOOL Stop();
 	static BOOL Disconnect(IN const DWORD& dwConnId);
 	// µÇ¼µÇ³ö;
-	static void Req_Login(IN HP_CONNID dwConnID, IN const BYTE* pReceiveData, IN INT nReceiveLength, IN msg_login &msg, OUT BYTE*& pSendData, OUT DWORD &dwSendLen);
+	static void Req_Login(IN HP_CONNID dwConnID, IN const BYTE* pReceiveData, IN INT nReceiveLength, IN TheProPackage &thepackage, OUT BYTE*& pSendData, OUT DWORD &dwSendLen);
 	static void Req_LogOut(IN HP_CONNID dwConnID, IN const BYTE* pReceiveData, IN INT nReceiveLength, IN TheProPackage &thepackage, OUT BYTE*& pSendData, OUT DWORD &dwSendLen);
 	// ²¿ÃÅ;
 	static void New_Department(IN HP_CONNID dwConnID, IN const BYTE* pReceiveData, IN INT nReceiveLength, IN TheProPackage &thepackage, OUT BYTE*& pSendData, OUT DWORD &dwSendLen);

+ 0 - 2
source/hook/WxService/OnlineUser.h

@@ -27,13 +27,11 @@ typedef struct __OnlineUser__
 {
 	DWORD	m_dwConnID;				// 客户端连接ID;
 	TCHAR	m_szAccount[17];		// 账号(手机号码);
-	//TCHAR	m_szPassword[17];		// 密码;
 
 	__OnlineUser__()
 	{
 		m_dwConnID = -1;
 		memset(m_szAccount, 0, sizeof(TCHAR)*17);
-		//memset(m_szPassword, 0, sizeof(TCHAR)*17);
 	}
 }OnlineUser, *pOnlineUser;
 

+ 1 - 1
source/hook/WxService/WxService.cpp

@@ -64,7 +64,7 @@ int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
 	msg.set_vcode(_T("5678"));
 	msg.set_name(_T("dfdfdfdf"));
 	//msg.set_len(msg.ByteSizeLong());
-	msg.set_len(msg.ByteSizeLong()+ msg.len());
+	//msg.set_len(msg.ByteSizeLong()+ msg.len());
 
 
 	long size = msg.ByteSizeLong();

+ 5 - 121
source/hook/hp-src/helper.h

@@ -71,119 +71,10 @@ enum ProtocolCmd
 	C2CCMD_REQ_DOG_DATA					= 2002,     // 读软件狗数据;
 	C2CCMD_AUTO_UPDATA					= 2003,		// 服务端向所有客户发送自动数据更新命令;
 	C2CCMD_REQ_SERVER_VAR				= 2004,		// 请求服务端的版本号;
-	C2CCMD_GET_DBINFO					= 2005,		// 利亚方舟服务端获取用户终端电脑数据库信息;
-	C2CCMD_ORD_PHOTO_BAK				= 2006,		// 客户端端向备份程序发送订单相片重新备份命令(导片与备份存在写备份无法锁定现象,need to Notify);
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_ORDERINFO				= 2007,		// 开单;
-	C2CCMD_DEL_ORDERINFO				= 2008,		// 删除订单;
-	C2CCMD_MOD_ORDERINFO				= 2009,		// 修改订单;
-	C2CCMD_MOD_ORDERINFO2				= 2089,		// 修改订单;
-	C2CCMD_QRY_ORDERINFO				= 2010,		// 查询订单;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_PRODUCT					= 2012,		// 添加商品;
-	C2CCMD_MOD_PRODUCT					= 2013,		// 修改商品;
-	C2CCMD_DEL_PRODUCT					= 2014,		// 删除商品;
-	C2CCMD_QRY_PRODUCT					= 2015,		// 查询商品;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_CUSTOMERFROM				= 2016,		// 添加顾客来源;
-	C2CCMD_DEL_CUSTOMERFROM				= 2017,		// 删除顾客来源;
-	C2CCMD_MOD_CUSTOMERFROM				= 2018,		// 修改顾客来源;
-	C2CCMD_QRY_CUSTOMERFROM				= 2019,		// 查询顾客来源;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_CUSTOMERINFO				= 2020,		// 添加新顾客信息;
-	C2CCMD_DEL_CUSTOMERINFO				= 2021,		// 删除顾客信息;
-	C2CCMD_MOD_CUSTOMERINFO				= 2022,		// 修改顾客信息;
-	C2CCMD_QRY_CUSTOMERINFO				= 2023,		// 查询顾客信息;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_DEPARTMENT				= 2024,		// 新增部门信息;
-	C2CCMD_DEL_DEPARTMENT				= 2025,		// 删除部门信息;
-	C2CCMD_MOD_DEPARTMENT				= 2026,		// 修改部门信息;
-	C2CCMD_QRY_DEPARTMENT				= 2027,		// 查询部门信息;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_STAFFINFO				= 2028,		// 新增员工信息;
-	C2CCMD_DEL_STAFFINFO				= 2029,		// 删除员工信息;
-	C2CCMD_MOD_STAFFINFO				= 2030,		// 修改员工信息;
-	C2CCMD_QRY_STAFFINFO				= 2031,		// 查询员工信息;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_USERINFO					= 2032,		// 新增用户信息;
-	C2CCMD_DEL_USERINFO					= 2033,		// 删除用户信息;
-	C2CCMD_MOD_USERINFO					= 2034,		// 修改用户信息;
-	C2CCMD_QRY_USERINFO					= 2035,		// 查询用户信息;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_SCENERY					= 2036,		// 新增景点信息;
-	C2CCMD_DEL_SCENERY					= 2037,		// 删除景点信息;
-	C2CCMD_MOD_SCENERY					= 2038,		// 修改景点信息;
-	C2CCMD_QRY_SCENERY					= 2039,		// 查询景点信息;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_ORDERTYPE				= 2040,		// 新增订单类型信息;
-	C2CCMD_DEL_ORDERTYPE				= 2041,		// 删除订单类型信息;
-	C2CCMD_MOD_ORDERTYPE				= 2042,		// 修改订单类型信息;
-	C2CCMD_QRY_ORDERTYPE				= 2043,		// 查询订单类型信息;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_PRODUCTTYPE				= 2044,		// 添加商品类型;
-	C2CCMD_MOD_PRODUCTTYPE				= 2045,		// 修改商品类型;
-	C2CCMD_DEL_PRODUCTTYPE				= 2046,		// 删除商品类型;
-	C2CCMD_QRY_PRODUCTTYPE				= 2047,		// 查询商品类型;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_PACKAGETYPE				= 2048,		// 添加套系类型;
-	C2CCMD_DEL_PACKAGETYPE				= 2049,		// 修改套系类型;
-	C2CCMD_MOD_PACKAGETYPE				= 2050,		// 删除套系类型;
-	C2CCMD_QRY_PACKAGETYPE				= 2051,		// 查询套系类型;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_PACKAGEINFO				= 2052,		// 添加套系信息;
-	C2CCMD_DEL_PACKAGEINFO				= 2053,		// 删除套系信息;
-	C2CCMD_MOD_PACKAGEINFO				= 2054,		// 修改套系信息;
-	C2CCMD_QRY_PACKAGEINFO				= 2055,		// 查询套系信息;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_PACKAGEITEM				= 2056,		// 添加套系项目;
-	C2CCMD_DEL_PACKAGEITEM				= 2057,		// 修改套系项目;
-	C2CCMD_MOD_PACKAGEITEM				= 2058,		// 删除套系项目;
-	C2CCMD_QRY_PACKAGEITEM				= 2059,		// 查询套系项目;
-	C2CCMD_QRY_PACKAGEITEM_DETAIL		= 2072,		// 查询套系项目详情;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_ORDERPACKAGEITEM			= 2060,		// 添加套系项目;
-	C2CCMD_NEW_ORDERPACKAGEITEM2		= 2087,		// 添加订单套餐项目(删除以前的);
-	C2CCMD_DEL_ORDERPACKAGEITEM			= 2061,		// 修改套系项目;
-	C2CCMD_MOD_ORDERPACKAGEITEM			= 2062,		// 删除套系项目;
-	C2CCMD_QRY_ORDERPACKAGEITEM			= 2063,		// 查询套系项目;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_SYSCONFING				= 2064,		// 添加影楼配置信息;
-	C2CCMD_DEL_SYSCONFING				= 2065,		// 删除影楼配置信息;
-	C2CCMD_MOD_SYSCONFING				= 2066,		// 修改影楼配置信息;
-	C2CCMD_QRY_SYSCONFING				= 2067,		// 查询影楼配置信息;
-	//////////////////////////////////////////////////////////////////////////
-	C2CCMD_NEW_STUDIOINFO				= 2068,		// 添加影楼信息;
-	C2CCMD_DEL_STUDIOINFO				= 2069,		// 删除影楼信息;
-	C2CCMD_MOD_STUDIOINFO				= 2070,		// 修改影楼信息;
-	C2CCMD_QRY_STUDIOINFO				= 2071,		// 查询影楼信息;
-	// .预留,若SQL数据库引擎未启用TCP/IP作为远程连接方式,需定义读写表的具体命令;(Jeff.100%的不建议使用这种方式获取数据,占用太多带宽和资源)
-	// .若要使用SQL,则只允许SQL的updata、insert、delete、drop……等命令,不允许使用select来返回查询到数据;
-
-	//C2CCMD_QRY_PACKAGEITEM_DETAIL		= 2072,		// 查询套系项详情;
-	C2CCMD_QRY_PACKAGEITEM_VIEW			= 2073,		// 查询套系项详情;
-	C2CCMD_NEW_PACKAGEITEM_MUTI			= 2074,		// 多个项同时插入到套系中;	
-	C2CCMD_NEW_PACKAGEITEM2				= 2075,		// 添加套系项目;
-
-	// 订单景点信息;
-	C2CCMD_NEW_ORDERSCENERY				= 2076,		// 添加订单景点信息;
-	C2CCMD_NEW_ORDERSCENERY2			= 2088,		// 添加订单景点信息(删除以前的);
-	C2CCMD_DEL_ORDERSCENERY				= 2077,		// 删除订单景点信息,使用autoid;
-	C2CCMD_MOD_ORDERSCENERY				= 2078,		// 修改订单景点信息;
-	C2CCMD_QRY_ORDERSCENERY				= 2079,		// 查询订单景点信息;
-	C2CCMD_DEL_ORDERSCENERY2			= 2080,		// 删除订单景点信息,使用订单号+景点名;
-
-	// 订单商品信息;
-	C2CCMD_NEW_ORDERPRODUCT				= 2081,		// 添加订单商品信息;
-	C2CCMD_DEL_ORDERPRODUCT				= 2082,		// 删除订单商品信息;
-	C2CCMD_MOD_ORDERPRODUCT				= 2083,		// 修改订单商品信息;
-	C2CCMD_QRY_ORDERPRODUCT				= 2084,		// 查询订单商品信息;
-
-	// 获取订单序号;
-	C2CCMD_GET_ORDER_SERIALNUMBER		= 2085,		// 获取订单序号;
-	// 获取打印序号;
-	C2CCMD_GET_PRINT_SERIALNUMBER		= 2086,		// 获取打印序号;
-
-	C2CCMD_OTHER_INFO					= 2999,     // 读其它信息;
+	C2CCMD_NEW_DEPARTMENT = 2005,		// 利亚方舟服务端获取用户终端电脑数据库信息;
+	C2CCMD_DEL_DEPARTMENT = 2006,		// 客户端端向备份程序发送订单相片重新备份命令(导片与备份存在写备份无法锁定现象,need to Notify);
+	C2CCMD_MOD_DEPARTMENT = 2007,
+	C2CCMD_QRY_DEPARTMENT = 2008
 };
 
 enum PackageFlag
@@ -214,14 +105,10 @@ typedef struct __THEPROPACKAGE__
 {
 	byte				flag;				// 协议包类型标识;
 	short				nCmd;				// 协议携带的命令标识;
-	//unsigned int		nUnCompressLen;
 	unsigned int		nDataLen;			// 数据长度,除了头之外的数据;
 	unsigned int		nSubDataLen;		// 分包大小;
-	DWORD				dwReserve;			// 预留填0;
-	TCHAR				szStudioId[MAX_STUDIOID_LENGTH];		// 影楼Guid;
 	TCHAR				szAccount[MAX_ACCOUNT_LENGTH];			// 账号;
-	TCHAR				szPassword[MAX_PASSWORD_LENGTH];		// 密码;
-	//BYTE				byProp[5];
+	DWORD				dwReserve;
 	BYTE				byBody[2];			// 包数据;
 
 	__THEPROPACKAGE__(){
@@ -231,10 +118,7 @@ typedef struct __THEPROPACKAGE__
 		nSubDataLen = 0;
 		dwReserve = 0;
 		memset(byBody, 0, 2);
-		//memset(byProp, 0, 5);
-		memset(szStudioId, 0, sizeof(TCHAR)*MAX_STUDIOID_LENGTH);
 		memset(szAccount, 0, sizeof(TCHAR)*MAX_ACCOUNT_LENGTH);
-		memset(szPassword, 0, sizeof(TCHAR)*MAX_PASSWORD_LENGTH);
 	}
 }TheProPackage,*pTheProPackage;
 

+ 1239 - 0
source/hook/skinui/EnBitmap.cpp

@@ -0,0 +1,1239 @@
+#include "stdafx.h"
+#include "EnBitmap.h"
+#include <AFXPRIV.H>
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#define new DEBUG_NEW
+#endif
+
+const int HIMETRIC_INCH = 2540;
+
+enum
+{
+	FT_BMP,
+	FT_ICO,
+	FT_JPG,
+	FT_GIF,
+
+	FT_UNKNOWN
+};
+
+CEnBitmap::CEnBitmap()
+{
+
+}
+
+CEnBitmap::~CEnBitmap()
+{
+
+}
+
+BOOL CEnBitmap::LoadImage(UINT uIDRes, LPCTSTR szResourceType, HMODULE hInst, COLORREF crBack)
+{
+	ASSERT(m_hObject == NULL);      // only attach once, detach on destroy
+
+	if (m_hObject != NULL)
+		return FALSE;
+
+	return Attach(LoadImageResource(uIDRes, szResourceType, hInst, crBack));
+}
+
+BOOL CEnBitmap::LoadImage(LPCTSTR szImagePath, COLORREF crBack)
+{
+	//如果原先存在就去除
+	if (m_hObject != NULL)
+	{
+		DeleteObject();
+		Detach();
+	}
+
+	return Attach(LoadImageFile(szImagePath, crBack));
+}
+
+HBITMAP CEnBitmap::LoadImageFile(LPCTSTR szImagePath, COLORREF crBack)
+{
+	int nType = GetFileType(szImagePath);
+
+	switch (nType)
+	{
+		// the reason for this is that i suspect it is more efficient to load
+		// bmps this way since it avoids creating device contexts etc that the 
+		// IPicture methods requires. that method however is still valuable
+		// since it handles other image types and transparency
+	case FT_BMP:
+		return (HBITMAP)::LoadImage(NULL, szImagePath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
+
+	case FT_UNKNOWN:
+		return NULL;
+
+	default: // all the rest
+	{
+		USES_CONVERSION;
+		IPicture* pPicture = NULL;
+
+		HBITMAP hbm = NULL;
+		HRESULT hr = OleLoadPicturePath(LPOLESTR(szImagePath), NULL, 0, crBack, IID_IPicture, (LPVOID *)&pPicture);
+
+		if (pPicture)
+		{
+			hbm = ExtractBitmap(pPicture, crBack);
+			pPicture->Release();
+		}
+
+		return hbm;
+	}
+	}
+
+	return NULL; // can't get here
+}
+
+HBITMAP CEnBitmap::LoadImageResource(UINT uIDRes, LPCTSTR szResourceType, HMODULE hInst, COLORREF crBack)
+{
+	BYTE* pBuff = NULL;
+	int nSize = 0;
+	HBITMAP hbm = NULL;
+
+	// first call is to get buffer size
+	if (GetResource(MAKEINTRESOURCE(uIDRes), szResourceType, hInst, 0, nSize))
+	{
+		if (nSize > 0)
+		{
+			pBuff = new BYTE[nSize];
+
+			// this loads it
+			if (GetResource(MAKEINTRESOURCE(uIDRes), szResourceType, hInst, pBuff, nSize))
+			{
+				IPicture* pPicture = LoadFromBuffer(pBuff, nSize);
+
+				if (pPicture)
+				{
+					hbm = ExtractBitmap(pPicture, crBack);
+					pPicture->Release();
+				}
+			}
+
+			delete[] pBuff;
+		}
+	}
+
+	return hbm;
+}
+
+IPicture* CEnBitmap::LoadFromBuffer(BYTE* pBuff, int nSize)
+{
+	bool bResult = false;
+
+	HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, nSize);
+	void* pData = GlobalLock(hGlobal);
+	memcpy(pData, pBuff, nSize);
+	GlobalUnlock(hGlobal);
+
+	IStream* pStream = NULL;
+	IPicture* pPicture = NULL;
+
+	if (CreateStreamOnHGlobal(hGlobal, TRUE, &pStream) == S_OK)
+	{
+		HRESULT hr = OleLoadPicture(pStream, nSize, FALSE, IID_IPicture, (LPVOID *)&pPicture);
+		pStream->Release();
+	}
+
+	return pPicture; // caller releases
+}
+
+BOOL CEnBitmap::GetResource(LPCTSTR lpName, LPCTSTR lpType, HMODULE hInst, void* pResource, int& nBufSize)
+{
+	HRSRC		hResInfo;
+	HANDLE		hRes;
+	LPSTR		lpRes = NULL;
+	int			nLen = 0;
+	bool		bResult = FALSE;
+
+	// Find the resource
+	hResInfo = FindResource(hInst, lpName, lpType);
+
+	if (hResInfo == NULL)
+		return false;
+
+	// Load the resource
+	hRes = LoadResource(hInst, hResInfo);
+
+	if (hRes == NULL)
+		return false;
+
+	// Lock the resource
+	lpRes = (char*)LockResource(hRes);
+
+	if (lpRes != NULL)
+	{
+		if (pResource == NULL)
+		{
+			nBufSize = SizeofResource(hInst, hResInfo);
+			bResult = true;
+		}
+		else
+		{
+			if (nBufSize >= (int)SizeofResource(hInst, hResInfo))
+			{
+				memcpy(pResource, lpRes, nBufSize);
+				bResult = true;
+			}
+		}
+
+		UnlockResource(hRes);
+	}
+
+	// Free the resource
+	FreeResource(hRes);
+
+	return bResult;
+}
+
+HBITMAP CEnBitmap::ExtractBitmap(IPicture* pPicture, COLORREF crBack)
+{
+	ASSERT(pPicture);
+
+	if (!pPicture)
+		return NULL;
+
+	CBitmap bmMem;
+	CDC dcMem;
+	CDC* pDC = CWnd::GetDesktopWindow()->GetDC();
+
+	if (dcMem.CreateCompatibleDC(pDC))
+	{
+		long hmWidth;
+		long hmHeight;
+
+		pPicture->get_Width(&hmWidth);
+		pPicture->get_Height(&hmHeight);
+
+		int nWidth = MulDiv(hmWidth, pDC->GetDeviceCaps(LOGPIXELSX), HIMETRIC_INCH);
+		int nHeight = MulDiv(hmHeight, pDC->GetDeviceCaps(LOGPIXELSY), HIMETRIC_INCH);
+
+		if (bmMem.CreateCompatibleBitmap(pDC, nWidth, nHeight))
+		{
+			CBitmap* pOldBM = dcMem.SelectObject(&bmMem);
+
+			if (crBack != -1)
+				dcMem.FillSolidRect(0, 0, nWidth, nHeight, crBack);
+
+			HRESULT hr = pPicture->Render(dcMem, 0, 0, nWidth, nHeight, 0, hmHeight, hmWidth, -hmHeight, NULL);
+			dcMem.SelectObject(pOldBM);
+		}
+	}
+
+	CWnd::GetDesktopWindow()->ReleaseDC(pDC);
+
+	return (HBITMAP)bmMem.Detach();
+}
+
+int CEnBitmap::GetFileType(LPCTSTR szImagePath)
+{
+	CString sPath(szImagePath);
+	sPath.MakeUpper();
+
+	if (sPath.Find(_T(".BMP")) > 0)
+		return FT_BMP;
+
+	else if (sPath.Find(_T(".ICO")) > 0)
+		return FT_ICO;
+
+	else if (sPath.Find(_T(".JPG")) > 0 || sPath.Find(_T(".JPEG")) > 0)
+		return FT_JPG;
+
+	else if (sPath.Find(_T(".GIF")) > 0)
+		return FT_GIF;
+
+	// else
+	return FT_UNKNOWN;
+}
+
+/////////////////////////////////////////////////////////////////////
+// Converts a bitmap to a region
+//
+//	BitmapToRegion :	Create a region from the "non-transparent" pixels of a bitmap
+//	Author :			Jean-Edouard Lachand-Robert (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998.
+//
+//	hBmp :				Source bitmap
+//	cTransparentColor :	Color base for the "transparent" pixels (default is black)
+//	cTolerance :		Color tolerance for the "transparent" pixels.
+//
+//	A pixel is assumed to be transparent if the value of each of its 3 components (blue, green and red) is 
+//	greater or equal to the corresponding value in cTransparentColor and is lower or equal to the 
+//	corresponding value in cTransparentColor + cTolerance.
+//
+HRGN CEnBitmap::BitmapToRegion(COLORREF cTransparentColor, COLORREF cTolerance)
+{
+	HBITMAP hBmp = (HBITMAP)GetSafeHandle();
+	HRGN hRgn = NULL;
+
+	if (hBmp)
+	{
+		// Create a memory DC inside which we will scan the bitmap content
+		HDC hMemDC = CreateCompatibleDC(NULL);
+		if (hMemDC)
+		{
+			// Get bitmap size
+			BITMAP bm;
+			::GetObject(hBmp, sizeof(bm), &bm);
+
+			// Create a 32 bits depth bitmap and select it into the memory DC 
+			BITMAPINFOHEADER RGB32BITSBITMAPINFO = {
+				sizeof(BITMAPINFOHEADER),	// biSize 
+				bm.bmWidth,					// biWidth; 
+				bm.bmHeight,				// biHeight; 
+				1,							// biPlanes; 
+				32,							// biBitCount 
+				BI_RGB,						// biCompression; 
+				0,							// biSizeImage; 
+				0,							// biXPelsPerMeter; 
+				0,							// biYPelsPerMeter; 
+				0,							// biClrUsed; 
+				0							// biClrImportant; 
+			};
+			VOID * pbits32;
+			HBITMAP hbm32 = CreateDIBSection(hMemDC, (BITMAPINFO *)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS, &pbits32, NULL, 0);
+			if (hbm32)
+			{
+				HBITMAP holdBmp = (HBITMAP)SelectObject(hMemDC, hbm32);
+
+				// Create a DC just to copy the bitmap into the memory DC
+				HDC hDC = CreateCompatibleDC(hMemDC);
+				if (hDC)
+				{
+					// Get how many bytes per row we have for the bitmap bits (rounded up to 32 bits)
+					BITMAP bm32;
+					::GetObject(hbm32, sizeof(bm32), &bm32);
+					while (bm32.bmWidthBytes % 4)
+						bm32.bmWidthBytes++;
+
+					// Copy the bitmap into the memory DC
+					HBITMAP holdBmp = (HBITMAP)SelectObject(hDC, hBmp);
+					BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY);
+
+					// For better performances, we will use the ExtCreateRegion() function to create the
+					// region. This function take a RGNDATA structure on entry. We will add rectangles by
+					// amount of ALLOC_UNIT number in this structure.
+#define ALLOC_UNIT	100
+					DWORD maxRects = ALLOC_UNIT;
+					HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects));
+					RGNDATA *pData = (RGNDATA *)GlobalLock(hData);
+					pData->rdh.dwSize = sizeof(RGNDATAHEADER);
+					pData->rdh.iType = RDH_RECTANGLES;
+					pData->rdh.nCount = pData->rdh.nRgnSize = 0;
+					SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
+
+					// Keep on hand highest and lowest values for the "transparent" pixels
+					BYTE lr = GetRValue(cTransparentColor);
+					BYTE lg = GetGValue(cTransparentColor);
+					BYTE lb = GetBValue(cTransparentColor);
+					BYTE hr = min(0xff, lr + GetRValue(cTolerance));
+					BYTE hg = min(0xff, lg + GetGValue(cTolerance));
+					BYTE hb = min(0xff, lb + GetBValue(cTolerance));
+
+					// Scan each bitmap row from bottom to top (the bitmap is inverted vertically)
+					BYTE *p32 = (BYTE *)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes;
+					for (int y = 0; y < bm.bmHeight; y++)
+					{
+						// Scan each bitmap pixel from left to right
+						for (int x = 0; x < bm.bmWidth; x++)
+						{
+							// Search for a continuous range of "non transparent pixels"
+							int x0 = x;
+							LONG *p = (LONG *)p32 + x;
+							while (x < bm.bmWidth)
+							{
+								BYTE b = GetRValue(*p);
+								if (b >= lr && b <= hr)
+								{
+									b = GetGValue(*p);
+									if (b >= lg && b <= hg)
+									{
+										b = GetBValue(*p);
+										if (b >= lb && b <= hb)
+											// This pixel is "transparent"
+											break;
+									}
+								}
+								p++;
+								x++;
+							}
+
+							if (x > x0)
+							{
+								// Add the pixels (x0, y) to (x, y+1) as a new rectangle in the region
+								if (pData->rdh.nCount >= maxRects)
+								{
+									GlobalUnlock(hData);
+									maxRects += ALLOC_UNIT;
+									hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), GMEM_MOVEABLE);
+									pData = (RGNDATA *)GlobalLock(hData);
+								}
+								RECT *pr = (RECT *)&pData->Buffer;
+								SetRect(&pr[pData->rdh.nCount], x0, y, x, y + 1);
+								if (x0 < pData->rdh.rcBound.left)
+									pData->rdh.rcBound.left = x0;
+								if (y < pData->rdh.rcBound.top)
+									pData->rdh.rcBound.top = y;
+								if (x > pData->rdh.rcBound.right)
+									pData->rdh.rcBound.right = x;
+								if (y + 1 > pData->rdh.rcBound.bottom)
+									pData->rdh.rcBound.bottom = y + 1;
+								pData->rdh.nCount++;
+
+								// On Windows98, ExtCreateRegion() may fail if the number of rectangles is too
+								// large (ie: > 4000). Therefore, we have to create the region by multiple steps.
+								if (pData->rdh.nCount == 2000)
+								{
+									HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
+									if (hRgn)
+									{
+										CombineRgn(hRgn, hRgn, h, RGN_OR);
+										::DeleteObject(h);
+									}
+									else
+										hRgn = h;
+									pData->rdh.nCount = 0;
+									SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
+								}
+							}
+						}
+
+						// Go to next row (remember, the bitmap is inverted vertically)
+						p32 -= bm32.bmWidthBytes;
+					}
+
+					// Create or extend the region with the remaining rectangles
+					HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
+					if (hRgn)
+					{
+						CombineRgn(hRgn, hRgn, h, RGN_OR);
+						::DeleteObject(h);
+					}
+					else
+						hRgn = h;
+
+					// Clean up
+					GlobalFree(hData);
+					SelectObject(hDC, holdBmp);
+					DeleteDC(hDC);
+				}
+
+				::DeleteObject(SelectObject(hMemDC, holdBmp));
+			}
+
+			DeleteDC(hMemDC);
+		}
+	}
+
+	return hRgn;
+}
+
+BOOL CEnBitmap::Draw(CDC *pDC, LPRECT r)
+{
+	CDC dc;
+	dc.CreateCompatibleDC(pDC);
+	CBitmap * bmp = dc.SelectObject(this);
+	pDC->BitBlt(r->left, r->top, r->right - r->left, r->bottom - r->top, &dc, 0, 0, SRCCOPY);
+
+	dc.SelectObject(bmp);
+	return TRUE;
+}
+
+// TransparentBlt	- Copies a bitmap transparently onto the destination DC
+// hdcDest		- Handle to destination device context 
+// nXDest		- x-coordinate of destination rectangle's upper-left corner 
+// nYDest		- y-coordinate of destination rectangle's upper-left corner 
+// nWidth		- Width of destination rectangle 
+// nHeight		- height of destination rectangle 
+// hBitmap		- Handle of the source bitmap
+// nXSrc		- x-coordinate of source rectangle's upper-left corner 
+// nYSrc		- y-coordinate of source rectangle's upper-left corner 
+// colorTransparent	- The transparent color
+// hPal			- Logical palette to be used with bitmap. Can be NULL
+
+/************************************************************************/
+/*  函数:TransparentBlt[8/23/2016 IT];
+/*  描述:将透明位图拷贝到目标;
+/*  参数:;
+/*  	[IN] :;
+/*  	[OUT] :;
+/*  	[IN/OUT] :;
+/*  返回:void;
+/*  注意:;
+/*  示例:;
+/*
+/*  修改:;
+/*  日期:;
+/*  内容:;
+/************************************************************************/
+void CEnBitmap::TransparentBlt(IN CDC &dc, IN CRect rc, IN UINT colorTransparent)
+{
+	CDC pDC;
+	pDC.CreateCompatibleDC(&dc);
+	HBITMAP hOldBmp = (HBITMAP) ::SelectObject(pDC.m_hDC, m_hObject);
+
+	::TransparentBlt(dc.GetSafeHdc(), rc.left, rc.top, rc.Width(), rc.Height(), pDC.GetSafeHdc(), 0, 0, GetWidth(), GetHeight(), colorTransparent);
+	::SelectObject(pDC.m_hDC, hOldBmp);
+	pDC.DeleteDC();
+}
+
+// DrawGreyScale    - Draws a bitmap in Grey scale
+// pDC              - Pointer to target device context
+// hDIB             - Handle of device-independent bitmap
+//
+void CEnBitmap::DrawGreyScale(CDC *pDC)
+{
+	CPalette pal;
+	CPalette *pOldPalette = 0;
+
+	HBITMAP hBmp = (HBITMAP)this->GetSafeHandle();
+
+	// allocate memory for extended image information
+	BITMAPINFO &bmInfo = *(LPBITMAPINFO) new BYTE[sizeof(BITMAPINFO) + 8];
+	memset(&bmInfo, 0, sizeof(BITMAPINFO) + 8);
+	bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+
+	// get extended information about image (length, compression, length of color table if exist, ...)
+	DWORD res = GetDIBits(pDC->GetSafeHdc(), hBmp, 0, GetHeight(), 0, &bmInfo, DIB_RGB_COLORS);
+	// allocate memory for image data (colors)
+	LPBYTE pBits = new BYTE[bmInfo.bmiHeader.biSizeImage + 4];
+
+	res = GetDIBits(pDC->GetSafeHdc(), hBmp, 0, bmInfo.bmiHeader.biHeight, pBits, &bmInfo, DIB_RGB_COLORS);
+
+	int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed :
+		1 << bmInfo.bmiHeader.biBitCount;
+
+	int nWidth = bmInfo.bmiHeader.biWidth;
+	int nHeight = bmInfo.bmiHeader.biHeight;
+
+	// Compute the address of the bitmap bits
+	LPVOID lpDIBBits;
+	if (bmInfo.bmiHeader.biBitCount > 8)
+		lpDIBBits = (LPVOID)((LPDWORD)(pBits +
+		bmInfo.bmiHeader.biClrUsed) +
+		((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
+	else
+		lpDIBBits = (LPVOID)(pBits + nColors);
+
+	// Create the palette if needed
+	if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE && nColors <= 256)
+	{
+		// The device supports a palette and bitmap has color table
+
+		// Allocate memory for a palette
+		UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
+		LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
+
+		pLP->palVersion = 0x300;
+		pLP->palNumEntries = nColors;
+
+		for (int i = 0; i < nColors; i++)
+		{
+			int nGrey = Grey(bmInfo.bmiColors[i].rgbRed, bmInfo.bmiColors[i].rgbGreen,
+				bmInfo.bmiColors[i].rgbBlue);
+			pLP->palPalEntry[i].peRed = nGrey;
+			pLP->palPalEntry[i].peGreen = nGrey;
+			pLP->palPalEntry[i].peBlue = nGrey;
+			pLP->palPalEntry[i].peFlags = 0;
+		}
+
+		pal.CreatePalette(pLP);
+
+		delete[] pLP;
+
+		// Select the palette
+		pOldPalette = pDC->SelectPalette(&pal, FALSE);
+		pDC->RealizePalette();
+	}
+	else
+	{
+		// Modify the bitmaps pixels directly
+		// Note : This ends up changing the DIB. If that is not acceptable then
+		// copy the DIB and then change the copy rather than the original
+		if (bmInfo.bmiHeader.biBitCount == 24 || bmInfo.bmiHeader.biBitCount == 32)
+		{
+			BYTE *dst = (BYTE*)lpDIBBits;
+			int Size = nWidth*nHeight;
+
+			while (Size--)
+			{
+				int nGrey = Grey(dst[2], dst[1], dst[0]);
+
+				dst[0] = (BYTE)nGrey;
+				dst[1] = (BYTE)nGrey;
+				dst[2] = (BYTE)nGrey;
+				dst += 4;
+			}
+		}
+		else if (bmInfo.bmiHeader.biBitCount == 16)
+		{
+			WORD *dst = (WORD*)lpDIBBits;
+			int Size = nWidth*nHeight;
+
+			while (Size--)
+			{
+				BYTE b = (BYTE)((*dst)&(0x1F));
+				BYTE g = (BYTE)(((*dst) >> 5)&(0x1F));
+				BYTE r = (BYTE)(((*dst) >> 10)&(0x1F));
+
+				int nGrey = Grey(r, g, b);
+
+				*dst++ = ((WORD)(((BYTE)(nGrey) | ((WORD)((BYTE)(nGrey)) << 5)) | (((DWORD)(BYTE)(nGrey)) << 10)));
+			}
+		}
+	}
+
+	// Draw the image 
+	::SetDIBitsToDevice(pDC->m_hDC,    // hDC
+		0,                             // XDest
+		0,                             // YDest
+		nWidth,                        // nDestWidth
+		nHeight,                       // nDestHeight
+		0,                             // XSrc
+		0,                             // YSrc
+		0,                             // nStartScan
+		nHeight,                       // nNumScans
+		lpDIBBits,                     // lpBits
+		&bmInfo,            // lpBitsInfo
+		DIB_RGB_COLORS);               // wUsage
+
+
+	if (pOldPalette)
+		pDC->SelectPalette(pOldPalette, FALSE);
+}
+
+//
+//      DitherBlt :     Draw a bitmap dithered (3D grayed effect like disabled buttons in toolbars) into a destination DC
+//      Author :        Jean-Edouard Lachand-Robert (iamwired@geocities.com), June 1997.
+//
+//      hdcDest :       destination DC
+//      nXDest :        x coordinate of the upper left corner of the destination rectangle into the DC
+//      nYDest :        y coordinate of the upper left corner of the destination rectangle into the DC
+//      nWidth :        width of the destination rectangle into the DC
+//      nHeight :       height of the destination rectangle into the DC
+//      hbm :           the bitmap to draw (as a part or as a whole)
+//      nXSrc :         x coordinates of the upper left corner of the source rectangle into the bitmap
+//      nYSrc :         y coordinates of the upper left corner of the source rectangle into the bitmap
+//
+void CEnBitmap::DitherBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth,
+	int nHeight, HBITMAP hbm, int nXSrc, int nYSrc)
+{
+	ASSERT(hdcDest && hbm);
+	ASSERT(nWidth > 0 && nHeight > 0);
+
+	// Create a generic DC for all BitBlts
+	HDC hDC = CreateCompatibleDC(hdcDest);
+	ASSERT(hDC);
+
+	if (hDC)
+	{
+		// Create a DC for the monochrome DIB section
+		HDC bwDC = CreateCompatibleDC(hDC);
+		ASSERT(bwDC);
+
+		if (bwDC)
+		{
+			// Create the monochrome DIB section with a black and white palette
+			struct {
+				BITMAPINFOHEADER bmiHeader;
+				RGBQUAD 		 bmiColors[2];
+			} RGBBWBITMAPINFO = {
+
+				{		// a BITMAPINFOHEADER
+					sizeof(BITMAPINFOHEADER),	// biSize 
+					nWidth, 				// biWidth; 
+					nHeight,				// biHeight; 
+					1,						// biPlanes; 
+					1,						// biBitCount 
+					BI_RGB, 				// biCompression; 
+					0,						// biSizeImage; 
+					0,						// biXPelsPerMeter; 
+					0,						// biYPelsPerMeter; 
+					0,						// biClrUsed; 
+					0						// biClrImportant; 
+				},
+
+				{
+					{ 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 }
+				}
+			};
+			VOID *pbitsBW;
+			HBITMAP hbmBW = CreateDIBSection(bwDC,
+				(LPBITMAPINFO)&RGBBWBITMAPINFO, DIB_RGB_COLORS, &pbitsBW, NULL, 0);
+			ASSERT(hbmBW);
+
+			if (hbmBW)
+			{
+				// Attach the monochrome DIB section and the bitmap to the DCs
+				SelectObject(bwDC, hbmBW);
+				SelectObject(hDC, hbm);
+
+				// BitBlt the bitmap into the monochrome DIB section
+				BitBlt(bwDC, 0, 0, nWidth, nHeight, hDC, nXSrc, nYSrc, SRCCOPY);
+
+				// Paint the destination rectangle in gray
+				FillRect(hdcDest, CRect(nXDest, nYDest, nXDest + nWidth, nYDest +
+					nHeight), GetSysColorBrush(COLOR_3DFACE));
+
+				// BitBlt the black bits in the monochrome bitmap into COLOR_3DHILIGHT bits in the destination DC
+				// The magic ROP comes from the Charles Petzold's book
+				HBRUSH hb = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
+				HBRUSH oldBrush = (HBRUSH)SelectObject(hdcDest, hb);
+				BitBlt(hdcDest, nXDest + 1, nYDest + 1, nWidth, nHeight, bwDC, 0, 0, 0xB8074A);
+
+				// BitBlt the black bits in the monochrome bitmap into COLOR_3DSHADOW bits in the destination DC
+				hb = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
+				::DeleteObject(SelectObject(hdcDest, hb));
+				BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, bwDC, 0, 0, 0xB8074A);
+				::DeleteObject(SelectObject(hdcDest, oldBrush));
+			}
+
+			VERIFY(DeleteDC(bwDC));
+		}
+
+		VERIFY(DeleteDC(hDC));
+	}
+}
+
+// CreateReservedPalette	- Create a palette using the PC_RESERVED flag
+//				  Limit the colors to 236 colors
+// Returns			- Handle to a palette object
+// hDIB				- Handle to a device-independent bitmap
+//
+HPALETTE CEnBitmap::CreateReservedPalette(CDC *pDC)
+{
+	HPALETTE hPal = NULL;    // handle to a palette
+
+	HBITMAP hBmp = (HBITMAP)this->GetSafeHandle();
+	// get image properties
+	//BITMAP bmp = { 0 };
+	//::GetObject( hBmp, sizeof(BITMAP), &bmp );
+	// allocate memory for extended image information
+	BITMAPINFO &bmInfo = *(LPBITMAPINFO) new BYTE[sizeof(BITMAPINFO) + 8];
+	memset(&bmInfo, 0, sizeof(BITMAPINFO) + 8);
+	bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+
+	// get extended information about image (length, compression, length of color table if exist, ...)
+	DWORD res = GetDIBits(pDC->GetSafeHdc(), hBmp, 0, GetHeight(), 0, &bmInfo, DIB_RGB_COLORS);
+	// allocate memory for image data (colors)
+	LPBYTE pBits = new BYTE[bmInfo.bmiHeader.biSizeImage + 4];
+
+	res = GetDIBits(pDC->GetSafeHdc(), hBmp, 0, bmInfo.bmiHeader.biHeight, pBits, &bmInfo, DIB_RGB_COLORS);
+
+
+	int nWidth = bmInfo.bmiHeader.biWidth;
+	int nHeight = bmInfo.bmiHeader.biHeight;
+
+	int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed :
+		1 << bmInfo.bmiHeader.biBitCount;
+
+	if (nColors > 256)
+		return NULL;		// No Palette   
+
+
+	//allocate memory block for logical palette
+	UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
+	LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
+
+	// Initialize the palette version
+	pLP->palVersion = 0x300;
+
+	// If it is a 256 color DIB, then let's find the most used 236 colors 
+	// and make a palette out of those colors
+	if (nColors > 236)
+	{
+		typedef struct _tagBESTCOLORS
+		{
+			DWORD dwColorCnt;	//Count of how many times a color is used
+			BOOL  bDontUse;	//Should we use this color?
+		} BESTCOLORS;
+
+		BESTCOLORS bc[256];
+		BYTE dwLeastUsed[20];		// Least used color indices
+		LPSTR lpBits;			// pointer to D.I. bits of a DIB
+		int   nWidth, nHeight, nBytesPerLine, cx, cy;
+
+		::ZeroMemory(bc, 256 * sizeof(BESTCOLORS));
+
+		lpBits = (LPSTR)(pBits + nColors);
+		nWidth = bmInfo.bmiHeader.biWidth;
+		nHeight = bmInfo.bmiHeader.biHeight;
+		nBytesPerLine = ((((bmInfo.bmiHeader.biWidth *
+			bmInfo.bmiHeader.biBitCount) + 31) & ~31) / 8);
+
+		// Traverse through all of the bits in the bitmap and place the 
+		// color count of each color in the BESTCOLORS array
+		for (cy = 0; cy < nHeight; cy++)
+			for (cx = 0; cx < nWidth; cx++)
+				bc[*(LPBYTE)(lpBits + cy*nBytesPerLine + cx)].dwColorCnt++;
+
+		// Let's arbitrarily place the first few colors in the "Least Used" list.
+		int nReject = nColors - 236;
+		for (cx = 0; cx < nReject; cx++)
+		{
+			bc[cx].bDontUse = TRUE;
+			dwLeastUsed[cx] = cx;
+		}
+
+		// Now, let's traverse through all of the colors and 
+		// sort out the least used
+		for (cx = 0; cx < nColors; cx++)
+		{
+			cy = 0;
+			while ((!(bc[cx].bDontUse)) && cy < nReject)
+			{
+				if (bc[cx].dwColorCnt < bc[dwLeastUsed[cy]].dwColorCnt)
+				{
+					bc[dwLeastUsed[cy]].bDontUse = FALSE;
+					dwLeastUsed[cy] = cx;
+					bc[cx].bDontUse = TRUE;
+				}
+				cy++;
+			}
+		}
+
+		// We want only 236 colors, so that the 20 system colors 
+		// are left untouched
+		pLP->palNumEntries = 236;
+
+		cx = 0;
+		for (int i = 0; i < nColors; i++)
+		{
+			// Should we use this color?
+			if (!((bc[i].bDontUse)))
+			{
+				pLP->palPalEntry[cx].peRed = bmInfo.bmiColors[i].rgbRed;
+				pLP->palPalEntry[cx].peGreen =
+					bmInfo.bmiColors[i].rgbGreen;
+				pLP->palPalEntry[cx].peBlue = bmInfo.bmiColors[i].rgbBlue;
+				pLP->palPalEntry[cx].peFlags = PC_RESERVED;
+				cx++;
+			}
+		}
+
+	}
+	else if (nColors)
+	{
+		// We have enough room for all the colors
+
+		pLP->palNumEntries = nColors;
+
+		// Copy the colors
+		for (int i = 0; i < nColors; i++)
+		{
+			pLP->palPalEntry[i].peRed = bmInfo.bmiColors[i].rgbRed;
+			pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen;
+			pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue;
+			pLP->palPalEntry[i].peFlags = PC_RESERVED;
+		}
+	}
+
+
+	hPal = CreatePalette(pLP);
+	delete[] pLP;
+
+	// return handle to DIB's palette 
+	return hPal;
+}
+
+// FadeColorToGrayScale	- Draws a bitmap in color slowly turns it to grayscale
+// pDC				- Pointer to target device context
+// hDIB				- Handle of device-independent bitmap
+// xDest			- x-coordinate of upper-left corner of dest. rect. 
+// yDest			- y-coordinate of upper-left corner of dest. rect. 
+// nLoops			- How many loops to fade the image into color
+// nDelay			- Delay in milli-seconds between each loop
+//
+void CEnBitmap::FadeColorToGrayScale(CDC *pDC, int xDest, int yDest, int nLoops,
+	int nDelay)
+{
+	CPalette pal;
+	CPalette *pOldPalette;
+	PALETTEENTRY peAnimate[256];
+	PALETTEENTRY peGray[256];
+	PALETTEENTRY peOriginal[256];
+
+	HBITMAP hBmp = (HBITMAP)this->GetSafeHandle();
+	// get image properties
+	//BITMAP bmp = { 0 };
+	//::GetObject( hBmp, sizeof(BITMAP), &bmp );
+	// allocate memory for extended image information
+	BITMAPINFO &bmInfo = *(LPBITMAPINFO) new BYTE[sizeof(BITMAPINFO) + 8];
+	memset(&bmInfo, 0, sizeof(BITMAPINFO) + 8);
+	bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+
+	// get extended information about image (length, compression, length of color table if exist, ...)
+	DWORD res = GetDIBits(pDC->GetSafeHdc(), hBmp, 0, GetHeight(), 0, &bmInfo, DIB_RGB_COLORS);
+	// allocate memory for image data (colors)
+	LPBYTE pBits = new BYTE[bmInfo.bmiHeader.biSizeImage + 4];
+
+	res = GetDIBits(pDC->GetSafeHdc(), hBmp, 0, bmInfo.bmiHeader.biHeight, pBits, &bmInfo, DIB_RGB_COLORS);
+
+	int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed :
+		1 << bmInfo.bmiHeader.biBitCount;
+
+	int nWidth = bmInfo.bmiHeader.biWidth;
+	int nHeight = bmInfo.bmiHeader.biHeight;
+
+	// Compute the address of the bitmap bits
+	LPVOID lpDIBBits;
+	if (bmInfo.bmiHeader.biBitCount > 8)
+		lpDIBBits = (LPVOID)((LPDWORD)(pBits +
+		bmInfo.bmiHeader.biClrUsed) +
+		((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
+	else
+		lpDIBBits = (LPVOID)(pBits + nColors);
+
+	int nReservedColors = nColors > 236 ? 236 : nColors;
+
+
+	// Create the palette if needed
+	if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE && nColors <= 256)
+	{
+		// The device supports a palette and bitmap has color table
+
+		HPALETTE hPal = CreateReservedPalette(pDC);
+		pal.Attach(hPal);
+
+		// Now save the original colors and get the grayscale colors
+		int i = 0;
+		pal.GetPaletteEntries(0, nReservedColors, (LPPALETTEENTRY)&peOriginal);
+		for (i = 0; i < nReservedColors; i++)
+		{
+			int nGray = Grey(peOriginal[i].peRed, peOriginal[i].peGreen, peOriginal[i].peBlue);
+
+			peGray[i].peRed = nGray;
+			peGray[i].peGreen = nGray;
+			peGray[i].peBlue = nGray;
+		}
+
+
+
+		// Select the palette
+		pOldPalette = pDC->SelectPalette(&pal, FALSE);
+		pDC->RealizePalette();
+
+		::SetDIBitsToDevice(pDC->m_hDC, xDest, yDest, nWidth, nHeight, 0, 0, 0,
+			nHeight, lpDIBBits, (LPBITMAPINFO)&bmInfo, DIB_RGB_COLORS);
+
+		// Now animate palette to set the image to grayscale
+		for (i = 1; i <= nLoops; i++)
+		{
+			for (int j = 0; j < nColors; j++)
+			{
+				peAnimate[j].peRed = peOriginal[j].peRed -
+					((peOriginal[j].peRed - peGray[j].peRed)*i) / nLoops;
+				peAnimate[j].peGreen = peOriginal[j].peGreen -
+					((peOriginal[j].peGreen - peGray[j].peGreen)*i)
+					/ nLoops;
+				peAnimate[j].peBlue = peOriginal[j].peBlue -
+					((peOriginal[j].peBlue - peGray[j].peBlue)*i) / nLoops;
+
+				peAnimate[j].peFlags = peOriginal[j].peFlags;
+			}
+
+			pal.AnimatePalette(0, nColors, (LPPALETTEENTRY)&peAnimate);
+
+			// Delay...
+			Sleep(nDelay);
+		}
+
+		// Select the old palette back
+		pDC->SelectPalette(pOldPalette, FALSE);
+	}
+	else if ((pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) == 0 && nColors <= 256)
+	{
+		// Now change the image to grayscale
+		for (int i = 1; i <= nLoops; i++)
+		{
+
+			BYTE *dst = (BYTE*)lpDIBBits;
+			int Size = nWidth*nHeight;
+
+			while (Size--)
+			{
+				int nGrey = Grey(dst[2], dst[1], dst[0]);
+
+				dst[2] = (BYTE)dst[2] - ((dst[2] - nGrey)*i) / nLoops;
+				dst[1] = (BYTE)dst[1] - ((dst[1] - nGrey)*i) / nLoops;
+				dst[0] = (BYTE)dst[0] - ((dst[0] - nGrey)*i) / nLoops;
+				dst += 4;
+			}
+
+			// Draw the image again
+			::SetDIBitsToDevice(pDC->m_hDC, xDest, yDest, nWidth, nHeight, 0,
+				0, 0, nHeight, lpDIBBits, (LPBITMAPINFO)&bmInfo,
+				DIB_RGB_COLORS);
+
+			// Delay...
+			Sleep(nDelay);
+		}
+	}
+	else
+	{
+		::SetDIBitsToDevice(pDC->m_hDC, xDest, yDest, nWidth, nHeight, 0, 0, 0,
+			nHeight, lpDIBBits, (LPBITMAPINFO)&bmInfo, DIB_RGB_COLORS);
+	}
+}
+
+void CEnBitmap::AlphaDisplay(CDC  *pDC, BYTE bAlpha)
+{
+	CDC dc;
+	dc.CreateCompatibleDC(pDC);
+	CBitmap * bmp = dc.SelectObject(this);
+
+	BLENDFUNCTION rBlendProps;
+	rBlendProps.BlendOp = AC_SRC_OVER;
+	rBlendProps.BlendFlags = 0;
+	rBlendProps.AlphaFormat = 0;
+	rBlendProps.SourceConstantAlpha = bAlpha;
+	BITMAP bmInfo;
+	::GetObject(m_hObject, sizeof(BITMAP), &bmInfo);
+	INT nWidth, nHeigh;
+	nWidth = bmInfo.bmWidth;
+	nHeigh = bmInfo.bmHeight;
+
+	AlphaBlend(pDC->m_hDC, 0, 0, nWidth, nHeigh, dc.m_hDC, 0, 0,
+		nWidth, nHeigh, rBlendProps);
+	dc.SelectObject(bmp);
+}
+
+/* ExtCreateRegion replacement */
+HRGN CEnBitmap::CreateRegionExt(DWORD nCount, CONST RGNDATA *pRgnData)
+{
+	HRGN hRgn = CreateRectRgn(0, 0, 0, 0);
+	const DWORD RDHDR = sizeof(RGNDATAHEADER);
+	ASSERT(hRgn != NULL);
+	LPRECT pRects = (LPRECT)((LPBYTE)pRgnData + RDHDR);
+	for (int i = 0; i < (int)nCount; i++)
+	{
+		HRGN hr = CreateRectRgn(pRects[i].left, pRects[i].top, pRects[i].right, pRects[i].bottom);
+		VERIFY(CombineRgn(hRgn, hRgn, hr, RGN_OR) != ERROR);
+		if (hr)
+			::DeleteObject(hr);
+	}
+	ASSERT(hRgn != NULL);
+	return hRgn;
+}
+
+///////////////////////////////////////////////////////////////////
+// InflateRegion - Inflates a region by the x and y values
+// specified in nXInflate and nYInflate
+// Creates a new region that represents the inflated region
+// (retains the contents of the old region)
+// Returns NULL if unsuccessfull
+HRGN CEnBitmap::InflateRegion(HRGN hRgn, int nXInflate, int nYInflate)
+{
+	// Local Variables
+	LPRGNDATA lpData;	// The RGNDATA structure
+	LPRECT lpRect;		// Pointer to the array of RECT structures
+	DWORD BufSize;		// The amount of memory required
+	DWORD i;			// General index variable
+	HRGN hRgnNew;		// The newly created region
+
+	// Get the number of rectangles in the region
+	BufSize = GetRegionData(hRgn, 0, NULL);
+	if (BufSize == 0)
+		return NULL;
+	// Allocate memory for the RGNDATA structure
+	lpData = (LPRGNDATA)malloc(BufSize);
+	// Set the location of the RECT structures
+	lpRect = (LPRECT)(lpData->Buffer);
+	// Get the region data
+	if (!GetRegionData(hRgn, BufSize, lpData))
+	{
+		free(lpData);
+		return NULL;
+	}
+	// Expand (or contract) all the rectangles in the data
+	for (i = 0; i < lpData->rdh.nCount; i++)
+		InflateRect(&lpRect[i], nXInflate, nYInflate);
+	// Create the new region
+	hRgnNew = CreateRegionExt(lpData->rdh.nCount, lpData);
+	free((void*)lpData);
+	return hRgnNew;
+}
+
+BOOL CEnBitmap::StretchDraw(CDC *pDC, LPRECT r, LPRECT sr)
+{
+	if (!r)
+		return FALSE;
+	CDC dc;
+	dc.CreateCompatibleDC(pDC);
+	CBitmap * bmp = dc.SelectObject(this);
+	//pDC->SetStretchBltMode(COLORONCOLOR);
+	pDC->SetStretchBltMode(STRETCH_HALFTONE);	// 使界面拉伸后不模糊;
+
+	if (!sr)
+		pDC->StretchBlt(r->left, r->top, r->right, r->bottom, &dc, 0, 0, GetWidth(), GetHeight(), SRCCOPY);
+	else
+		pDC->StretchBlt(r->left, r->top, r->right - r->left, r->bottom - r->top,
+		&dc, sr->left, sr->top, sr->right - sr->left, sr->bottom - sr->top, SRCCOPY);
+
+	dc.SelectObject(bmp);
+	return TRUE;
+
+}
+
+BOOL CEnBitmap::DrawImage(CEnBitmap &bmp, int nX, int nY, int nCol, int nRow)
+{
+	nX -= 1;
+	nY -= 1;
+	//单个图片的长和宽;
+	int w = GetWidth() / nCol;
+	int h = GetHeight() / nRow;
+
+	CBitmap *OldBmp;
+	CDC memDC;
+	CClientDC dc(0);
+
+	memDC.CreateCompatibleDC(&dc);
+	bmp.CreateCompatibleBitmap(&dc, w, h);
+	OldBmp = memDC.SelectObject(&bmp);
+
+	StretchDraw(&memDC, CRect(0, 0, w, h), CRect(GetWidth()*nX / nCol, GetHeight()*nY / nRow, GetWidth()*nX / nCol + w, GetHeight()*nY / nRow + h));
+
+	memDC.SelectObject(OldBmp);
+	return TRUE;
+}
+
+//BOLL GetBmp()
+
+CRect CEnBitmap::GetRect()
+{
+	return CRect(0, 0, GetWidth(), GetHeight());
+}
+
+HBITMAP CEnBitmap::SetBitmap(HBITMAP hBitmap)
+{
+	CEnBitmap *pBmp = (CEnBitmap *)CEnBitmap::FromHandle(hBitmap);
+	HBITMAP hBmp = (HBITMAP)this->Detach();
+	this->DeleteObject();
+	pBmp->DrawImage(*this, 1, 1, 1, 1);
+	return hBmp;
+}
+
+/************************************************************************/
+/*  函数:[8/23/2016 IT];
+/*  描述:;
+/*  参数:;
+/*  	[IN] :;
+/*  	[OUT] :;
+/*  	[IN/OUT] :;
+/*  返回:void;
+/*  注意:;
+/*  示例:;
+/*
+/*  修改:;
+/*  日期:;
+/*  内容:;
+/************************************************************************/
+BOOL CEnBitmap::ExtendDraw(IN CDC *pDC, IN CRect rc, IN int nX, IN int nY, IN BOOL bTran, IN UINT colorTransparent)
+{
+	CEnBitmap bmp;
+	if (ExtendDrawImage(bmp, rc, nX, nY))
+	{
+		if (bTran)
+			bmp.TransparentBlt(*pDC, &rc, colorTransparent);
+		else
+			bmp.Draw(pDC, &rc);
+		// 
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/************************************************************************/
+/*  函数:ExtendDrawImage[8/23/2016 IT];
+/*  描述:;
+/*  参数:;
+/*  	[OUT] bmp:返回图片对象;
+/*  	[IN] rc:画图的目标区域;
+/*  	[IN] nX:分割点x坐标(原图坐标);
+/*  	[IN] nY:分割点y坐标(原图坐标);
+/*  返回:BOOL;
+/*  注意:;
+/*  示例:;
+/*  (0,0)-------|----------|
+/*   |	        |	       |
+/*   | 左上     | 右上     |
+/*   |          |          |
+/*   ----------(x,y)-------|----x,y分割点坐标;
+/*   |          |          |
+/*   | 左下     | 右下     |
+/*   |          |          |
+/*   -----------|---------(r,b)-
+/*
+/*  修改:;
+/*  日期:;
+/*  内容:;
+/************************************************************************/
+BOOL CEnBitmap::ExtendDrawImage(OUT CEnBitmap &bmp, IN CRect rc, IN int nX, IN int nY)
+{
+	CBitmap *OldBmp;
+	CDC memDC;
+	CClientDC cdc(0);
+
+	memDC.CreateCompatibleDC(&cdc);
+	bmp.CreateCompatibleBitmap(&cdc, rc.Width(), rc.Height());
+	OldBmp = memDC.SelectObject(&bmp);
+
+	if (nX == 0 && nY == 0)
+	{
+		StretchDraw(&memDC, &rc, GetRect());
+		return TRUE;
+	}
+
+	CDC dc;
+	dc.CreateCompatibleDC(&memDC);
+	CBitmap * Bmp = dc.SelectObject(this);
+	//dc.SetStretchBltMode(COLORONCOLOR);
+	if (nX > 0 && nY == 0)
+	{// 左右对半;
+		// 左边;
+		memDC.BitBlt(0, 0, nX, rc.Height(), &dc, 0, 0, SRCCOPY);
+		memDC.StretchBlt(nX, 0, rc.Width() - GetWidth(), rc.Height(), &dc, nX, 0, 1, GetHeight(), SRCCOPY);
+		// 右边;
+		memDC.BitBlt(rc.right - (GetWidth() - nX), 0, GetWidth() - nX, rc.Height(), &dc, nX, 0, SRCCOPY);
+	}
+	else if (nX == 0 && nY > 0)
+	{// 上下对半;
+		// 上边;
+		memDC.BitBlt(0, 0, rc.Width(), nY, &dc, 0, 0, SRCCOPY);
+		memDC.StretchBlt(0, nY, GetWidth(), rc.Height() - GetHeight(), &dc, 0, nY, GetWidth(), 1, SRCCOPY);
+		// 下边;
+		memDC.BitBlt(0, rc.bottom - (GetHeight() - nY), GetWidth(), GetHeight() - nY, &dc, 0, nY, SRCCOPY);
+	}
+	else if (nX > 0 && nY > 0)
+	{
+		//左上角;
+		memDC.StretchBlt(0, 0, nX, nY, &dc, 0, 0, nX, nY, SRCCOPY);
+		//上中;
+		memDC.StretchBlt(nX, 0, rc.Width() - GetWidth(), nY, &dc, nX, 0, 1, nY, SRCCOPY);
+
+		//右上角;
+		memDC.StretchBlt(rc.Width() - (GetWidth() - nX), 0, GetWidth() - nX, nY, &dc, nX, 0, GetWidth() - nX, nY, SRCCOPY);
+		//左中;
+		memDC.StretchBlt(0, nY, nX, rc.Height() - GetHeight(), &dc, 0, nY, nX, 1, SRCCOPY);
+
+		//正中;
+		memDC.StretchBlt(nX, nY, rc.Width() - GetWidth(), rc.Height() - GetHeight(), &dc, nX, nY, 1, 1, SRCCOPY);
+		//右中;
+		memDC.StretchBlt(rc.Width() - (GetWidth() - nX), nY, GetWidth() - nX, rc.Height() - GetHeight(), &dc, nX, nY, GetWidth() - nX, 1, SRCCOPY);
+
+		//左下角;
+		memDC.StretchBlt(0, rc.Height() - (GetHeight() - nY), nX, GetHeight() - nY, &dc, 0, nY, nX, GetHeight() - nY, SRCCOPY);
+		//下中;
+		memDC.StretchBlt(nX, rc.Height() - (GetHeight() - nY), rc.Width() - GetWidth(), GetHeight() - nY, &dc, nX, nY, 1, GetHeight() - nY, SRCCOPY);
+		//右下角;
+		memDC.StretchBlt(rc.Width() - (GetWidth() - nX), rc.Height() - (GetHeight() - nY), GetWidth() - nX, GetHeight() - nY, &dc, nX, nY, GetWidth() - nX, GetHeight() - nY, SRCCOPY);
+	}
+
+	dc.SelectObject(Bmp);
+	memDC.SelectObject(OldBmp);
+
+	return TRUE;
+}

+ 93 - 0
source/hook/skinui/EnBitmap.h

@@ -0,0 +1,93 @@
+/************************************************************************/
+/*  Copyright (C), 2016-2020, [IT], 保留所有权利;
+/*  模 块 名:;
+/*  描    述:;
+/*
+/*  版    本:[V];
+/*  作    者:[IT];
+/*  日    期:[8/19/2016];
+/*
+/*
+/*  注    意:;
+/*
+/*  修改记录:[IT];
+/*  修改日期:;
+/*  修改版本:;
+/*  修改内容:;
+/************************************************************************/
+
+#ifndef __ENBITMAP_20160823__
+#define __ENBITMAP_20160823__
+
+#pragma once
+
+class CEnBitmap : public CBitmap
+{
+public:
+	HBITMAP SetBitmap(HBITMAP hBitmap);
+	CRect GetRect();
+	void AlphaDisplay(CDC  *pDC, BYTE bAlpha);
+	CEnBitmap();
+	virtual ~CEnBitmap();
+	BOOL ExtendDraw(IN CDC *pDC, IN CRect rc, IN int nX, IN int nY, IN BOOL bTran = FALSE, IN UINT colorTransparent = RGB(255, 0, 255));
+	BOOL ExtendDrawImage(OUT CEnBitmap &bmp, IN CRect rc, IN int nX, IN int nY);
+
+	BOOL LoadImage(LPCTSTR szImagePath, COLORREF crBack = 0);
+	BOOL LoadImage(UINT uIDRes, LPCTSTR szResourceType, HMODULE hInst = NULL, COLORREF crBack = 0);
+
+	// helpers
+	static HBITMAP LoadImageFile(LPCTSTR szImagePath, COLORREF crBack = 0);
+	static HBITMAP LoadImageResource(UINT uIDRes, LPCTSTR szResourceType, HMODULE hInst = NULL, COLORREF crBack = 0);
+	static BOOL GetResource(LPCTSTR lpName, LPCTSTR lpType, HMODULE hInst, void* pResource, int& nBufSize);
+	static IPicture* LoadFromBuffer(BYTE* pBuff, int nSize);
+	HRGN BitmapToRegion(COLORREF cTransparentColor = 0, COLORREF cTolerance = 0x101010);
+	BOOL Draw(CDC *pDC, LPRECT r);
+	BOOL DrawImage(CEnBitmap &bmp, int nX, int nY, int nCol, int nRow);
+	void TransparentBlt(IN CDC &dc, IN CRect rc, IN UINT colorTransparent);
+
+	int	 Width()
+	{
+		return GetWidth();
+	}
+
+	int	 GetWidth()
+	{
+		BITMAP bm;
+		memset(&bm, 0, sizeof(bm));
+		GetBitmap(&bm);
+		return bm.bmWidth;
+	}
+
+	int	 Height()
+	{
+		return GetHeight();
+	}
+
+	int	 GetHeight()
+	{
+		BITMAP bm;
+		memset(&bm, 0, sizeof(bm));
+		GetBitmap(&bm);
+		return bm.bmHeight;
+	}
+
+	int CEnBitmap::Grey(int r, int g, int b)
+	{
+		return (((b * 11) + (g * 59) + (r * 30)) / 100);
+	}
+	void DrawGreyScale(CDC *pDC);
+	void DitherBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth,
+		int nHeight, HBITMAP hbm, int nXSrc, int nYSrc);
+	HPALETTE CreateReservedPalette(CDC *pDC);
+	void FadeColorToGrayScale(CDC *pDC, int xDest, int yDest, int nLoops,
+		int nDelay);
+	HRGN InflateRegion(HRGN hRgn, int nXInflate, int nYInflate);
+	HRGN CreateRegionExt(DWORD nCount, CONST RGNDATA *pRgnData);
+	BOOL StretchDraw(CDC *pDC, LPRECT r, LPRECT sr);
+protected:
+	static HBITMAP ExtractBitmap(IPicture* pPicture, COLORREF crBack);
+	static int GetFileType(LPCTSTR szImagePath);
+
+};
+
+#endif // __ENBITMAP_20160823__

+ 570 - 0
source/hook/skinui/GfxOutBarCtrl.cpp

@@ -0,0 +1,570 @@
+
+#include "stdafx.h"
+#include "GfxOutBarCtrl.h"
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+#define IDC_CURSOR_HAND                 132
+/////////////////////////////////////////////////////////////////////////////
+// CGfxOutBarCtrl
+
+IMPLEMENT_DYNCREATE(CGfxOutBarCtrl, CWnd)
+
+CGfxOutBarCtrl::CGfxOutBarCtrl()
+{
+	//背景色
+	m_crBackground = RGB(255,255,255);
+	//字体颜色
+	m_crText = RGB(27,79,116);
+	//字体
+	m_pFont = NULL;
+	//目录高度
+	m_nFolderHeight = 20;
+
+	//当前选中目录索引
+	m_nCurSelFolder = 1;
+	//最后高亮的目录索引
+	iLastFolderHighlighted = -1;
+	//当前鼠标滑过的目录
+	iHoverFolder = -1;
+
+	hHandCursor = AfxGetApp()->LoadCursor(IDC_CURSOR_HAND);
+
+	iSelcon = NULL;
+}
+
+CGfxOutBarCtrl::~CGfxOutBarCtrl()
+{
+	for (int t = 0; t < m_arFolder.GetSize(); t++)
+	{
+		if (m_arFolder.GetAt(t)) delete (CBm_arFolder*) m_arFolder.GetAt(t);
+	}
+
+	m_arFolder.RemoveAll();
+}
+
+
+BEGIN_MESSAGE_MAP(CGfxOutBarCtrl, CWnd)
+	//{{AFX_MSG_MAP(CGfxOutBarCtrl)
+	ON_WM_CREATE()
+	ON_WM_PAINT()
+	ON_WM_ERASEBKGND()
+	ON_WM_LBUTTONDOWN()
+	ON_WM_SETCURSOR()
+	ON_WM_SIZE()
+	//}}AFX_MSG_MAP
+	ON_WM_MOUSEMOVE()
+	ON_WM_TIMER()
+	ON_WM_MOUSEWHEEL()
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CGfxOutBarCtrl message handlers
+
+void CGfxOutBarCtrl::SetFolderImage(LPCTSTR lpszPath)
+{
+	CEnBitmap bmpTemp;
+	bmpTemp.LoadImage(lpszPath);
+	bmpTemp.DrawImage(m_bmpNormalFolder,1,1,1,2);
+	bmpTemp.DrawImage(m_bmpHoverFolder,1,2,1,2);
+	bmpTemp.DeleteObject();
+
+};
+
+void CGfxOutBarCtrl::SetSelIcon(LPCTSTR lpszIconPath)
+{
+	iSelcon=(HICON)::LoadImage(AfxGetApp()->m_hInstance,lpszIconPath,IMAGE_ICON,16,16,LR_LOADFROMFILE);
+}
+
+void CGfxOutBarCtrl::SetFolderText(const int index, const TCHAR * text)
+{
+	ASSERT(index >= 0 && index < GetFolderCount());
+	CBm_arFolder * pbf = (CBm_arFolder *) m_arFolder.GetAt(index);
+	if (pbf->cName) 
+	{
+		delete [] pbf->cName;
+		pbf->cName = NULL;
+	}
+	pbf->cName = new TCHAR [lstrlen(text)+1];
+	lstrcpy(pbf->cName, text);
+}
+
+BOOL CGfxOutBarCtrl::Create(DWORD dwStyle, const RECT & rect, CWnd * pParentWnd, UINT nID)
+{
+	return CWnd::CreateEx(0, NULL, NULL, dwStyle|WS_CHILD, rect, pParentWnd, nID);
+}
+
+int CGfxOutBarCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
+{
+	if (CWnd::OnCreate(lpCreateStruct) == -1)
+		return -1;
+	// TODO: Add your specialized creation code here
+	return 0;
+}
+
+void CGfxOutBarCtrl::OnPaint() 
+{
+	CRect rc;
+	GetClientRect(&rc);
+	CPaintDC dc(this);
+	CDC memDC;
+	memDC.CreateCompatibleDC(&dc);
+	CBitmap bmp;
+	bmp.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
+
+	CBitmap * oldbmp = memDC.SelectObject(&bmp);;
+	memDC.FillSolidRect(rc,m_crBackground);
+	int nFolders=m_arFolder.GetSize();
+
+	for(int i=0;i<nFolders;i++)
+	{
+		CRect rcFolder;
+		GetFolderRect(i,rcFolder);
+		DrawFolder(&memDC,i,&rcFolder);
+	}
+
+	dc.BitBlt(rc.left,rc.top,rc.Width(),rc.Height(),&memDC,0,0,SRCCOPY);//Copy
+	memDC.DeleteDC();
+}
+
+BOOL CGfxOutBarCtrl::OnEraseBkgnd(CDC* pDC) 
+{
+	return true;
+}
+
+bool CGfxOutBarCtrl::GetFolderRect(const int iIndex, CRect & rect) const
+{
+	int max = m_arFolder.GetSize();
+	ASSERT(iIndex >= 0 && iIndex < max);
+
+	if (iIndex >= 0 && iIndex < max)
+	{
+		CRect rc;
+		GetClientRect(rc);
+		if (iIndex > m_nCurSelFolder)
+			rect.SetRect(rc.left, rc.bottom - ((max - iIndex)) * m_nFolderHeight, rc.right, 
+			rc.bottom - (max - iIndex - 1) * m_nFolderHeight);
+		else 
+			rect.SetRect(rc.left, rc.top + iIndex * m_nFolderHeight, rc.right, 
+			rc.top + (1 + iIndex) * m_nFolderHeight);
+		return true;
+	}
+	return false;
+}
+
+bool CGfxOutBarCtrl::PtInFolderHeadRect(CPoint pt) const
+{
+	int max = m_arFolder.GetSize();
+	ASSERT(m_nCurSelFolder >= 0 && m_nCurSelFolder < max);
+
+	CRect rcClient;
+	GetClientRect(rcClient);
+
+	CRect rcTop, rcBottom;
+	rcTop.SetRect(rcClient.left, rcClient.top, rcClient.right, rcClient.top + (m_nCurSelFolder + 1) * m_nFolderHeight);
+	rcBottom.SetRect(rcClient.left, rcClient.bottom - ( max - m_nCurSelFolder) * m_nFolderHeight, rcClient.right, rcClient.bottom );
+	if ( rcTop.PtInRect(pt) || rcBottom.PtInRect(pt) )
+		return true;
+	
+	return false;
+}
+
+int CGfxOutBarCtrl::AddFolder(const TCHAR * cFolderName, const DWORD exData)
+{
+	CBm_arFolder * pbf = new CBm_arFolder(cFolderName, exData);
+	ASSERT(pbf);
+	m_arFolder.Add((void *)pbf);
+
+	return m_arFolder.GetSize() - 1;
+}
+
+int CGfxOutBarCtrl::AddFolderBar(const TCHAR * pFolder, CWnd * pSon, const DWORD exData)
+{
+	CBm_arFolder * pbf = new CBm_arFolder(pFolder, exData);
+	ASSERT(pbf);
+	pbf->pChild = pSon;
+
+	m_arFolder.Add((void *)pbf);
+
+	return m_arFolder.GetSize() - 1;
+}
+
+CGfxOutBarCtrl::CBm_arFolder::CBm_arFolder(const TCHAR * name, DWORD exData)
+{
+	cName = NULL;
+	dwData = exData;
+
+	if (name)
+	{
+		cName = new TCHAR[lstrlen(name)+1];
+		ASSERT(cName);
+		lstrcpy(cName, name);
+	}
+	pChild = NULL;
+}
+
+CGfxOutBarCtrl::CBm_arFolder::~CBm_arFolder()
+{
+	if (cName) delete [] cName;
+}
+
+void CGfxOutBarCtrl::GetInsideRect(CRect & rect) const
+{
+	GetClientRect(rect);
+	if (m_arFolder.GetSize() > 0)
+	{
+		int max = m_arFolder.GetSize();
+		rect.top += m_nFolderHeight * (m_nCurSelFolder + 1);//+ 2;
+		rect.bottom -= (max - m_nCurSelFolder - 1)*m_nFolderHeight +1;
+		return;
+	}
+}
+
+int CGfxOutBarCtrl::HitTestEx(const CPoint & point, int &index)
+{
+	int max = m_arFolder.GetSize(), t;
+
+	CRect rc;
+	for (t = 0; t < max; t++)
+	{
+		GetFolderRect(t, rc);
+		if (rc.PtInRect(point)) 
+		{
+			index = t;
+			return htFolder;
+		}
+	}
+	index = -1;
+	return htNothing;
+}
+
+void CGfxOutBarCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
+{
+	if (GetFocus() != this) SetFocus();
+
+	int index, ht = HitTestEx(point, index);
+
+	if (ht == htFolder)
+	{
+		bool bHigh = true;
+
+		if (::GetCapture() == NULL)
+		{
+			SetCapture();
+			ASSERT(this == GetCapture());
+			AfxLockTempMaps();
+			while (TRUE)
+			{
+				MSG msg;
+				VERIFY(::GetMessage(&msg, NULL, 0, 0));
+
+				if (CWnd::GetCapture() != this) break;
+
+				switch (msg.message)
+				{
+				case WM_LBUTTONUP:
+					{
+						CPoint pt(msg.lParam);
+						int idx, ht1 = HitTestEx(pt, idx);
+						if (ht1 == htFolder && idx != m_nCurSelFolder)
+						{
+							//idx = (idx == m_nCurSelFolder)?(idx+1):idx;
+							if(idx <GetFolderCount())
+								SetSelFolder(idx);
+						}
+					}
+					goto ExitLoop;
+				default:
+					DispatchMessage(&msg);
+					break;
+				}
+			}
+ExitLoop:
+			ReleaseCapture();
+			AfxUnlockTempMaps(FALSE);
+		}
+	}
+	CWnd::OnLButtonDown(nFlags, point);
+}
+
+void CGfxOutBarCtrl::SetSelFolder(const int index)
+{
+	ASSERT(index >= 0 && index < GetFolderCount());
+	if (index == m_nCurSelFolder) return;
+
+	CWnd * pc = GetFolderChild();
+	if (pc) pc->ShowWindow(SW_HIDE);
+
+	m_nCurSelFolder = index;
+
+	pc = GetFolderChild();
+	if (pc)
+	{
+		CRect rc;
+		GetInsideRect(rc);
+		pc->MoveWindow(rc);
+		pc->ShowWindow(SW_SHOW);
+	}	
+
+	Invalidate();
+}
+
+int CGfxOutBarCtrl::GetFolderCount() const
+{
+	return m_arFolder.GetSize();
+}
+
+int CGfxOutBarCtrl::GetSelFolder() const
+{
+	return m_nCurSelFolder;
+}
+
+void CGfxOutBarCtrl::RemoveFolder(const int index)
+{
+	ASSERT(index >= 0 && index < GetFolderCount());
+	CBm_arFolder * pbf = (CBm_arFolder *) m_arFolder.GetAt(index);
+	delete pbf;
+	m_arFolder.RemoveAt(index);
+	if (m_nCurSelFolder >= index) m_nCurSelFolder = index - 1;
+	if (m_nCurSelFolder < 0 && GetFolderCount() > 0) m_nCurSelFolder = 0;
+	Invalidate();
+}
+
+BOOL CGfxOutBarCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
+{
+	CPoint pt(GetMessagePos());
+	ScreenToClient(&pt);
+	int index, ht = HitTestEx(pt, index);
+	if (ht == htFolder)
+	{
+		SetCursor(hHandCursor);
+		return true;
+	}
+	return CWnd::OnSetCursor(pWnd, nHitTest, message);
+}
+
+void CGfxOutBarCtrl::OnSize(UINT nType, int cx, int cy) 
+{
+	CWnd::OnSize(nType, cx, cy);
+
+	int t, max = GetFolderCount();
+	CRect rc;
+	GetInsideRect(rc);
+
+	for (t = 0; t < max; t++)
+	{
+		CBm_arFolder * pbf = (CBm_arFolder *) m_arFolder.GetAt(t);
+		CWnd * pc = GetFolderChild(t);
+		if (pc) pc->SetWindowPos(0, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOZORDER);
+	}
+}
+
+CWnd * CGfxOutBarCtrl::GetFolderChild(int iFolder)
+{
+	if (GetFolderCount())
+	{
+		if (iFolder < 0) iFolder = m_nCurSelFolder;
+
+		CBm_arFolder * pbf = (CBm_arFolder *) m_arFolder.GetAt(iFolder);
+		return pbf->pChild;
+	}
+	return NULL;
+}
+
+
+void CGfxOutBarCtrl::SetAutoFolder(IN const DWORD& dwTime)
+{
+	SetTimer(2, dwTime, NULL);
+}
+
+DWORD CGfxOutBarCtrl::GetFolderData(int iFolder)
+{
+	if (iFolder < 0) iFolder = m_nCurSelFolder;
+	CBm_arFolder * pbf = (CBm_arFolder *) m_arFolder.GetAt(iFolder);
+	return pbf->dwData;
+}
+
+void CGfxOutBarCtrl::OnMouseMove(UINT nFlags, CPoint point)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	if (GetFocus() != this && PtInFolderHeadRect(point))
+		SetFocus();
+
+	int ht = HitTestEx(point, iHoverFolder);
+
+	if (ht == htFolder)
+	{
+		HighlightFolder(iHoverFolder);
+		SetTimer(1,100,NULL);
+	}
+
+	m_curpoint = point;
+	CWnd::OnMouseMove(nFlags, point);
+}
+
+void CGfxOutBarCtrl::DrawFolder(CDC * pDC, const int iIdx, CRect rect)
+{
+	if(iIdx < 0)	return;
+
+	CBm_arFolder *pBf=(CBm_arFolder*)m_arFolder.GetAt(iIdx);
+
+	if (iHoverFolder == iIdx)
+	{
+		if(m_bmpHoverFolder.m_hObject != NULL)
+			m_bmpHoverFolder.ExtendDraw(pDC,rect,20,5);
+	}
+	else
+	{
+		if(m_bmpNormalFolder.m_hObject != NULL)
+			m_bmpNormalFolder.ExtendDraw(pDC,rect,20,5);
+	}
+
+	if(m_nCurSelFolder == iIdx && iSelcon != NULL)
+	{
+		::DrawIconEx(*pDC,rect.left+2,rect.top +(m_nFolderHeight-16)/2,iSelcon,16,16,0,NULL,DI_NORMAL);
+	}
+
+	//Draw Folder Name In Folder
+	if(m_pFont == NULL)
+		m_pFont = CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT));
+
+	pDC->SelectObject(m_pFont);
+	pDC->SetTextColor(m_crText);
+	pDC->SetBkMode(TRANSPARENT);
+	pDC->DrawText(pBf->cName,rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
+}
+
+void CGfxOutBarCtrl::HighlightFolder(const int index)
+{
+	if (iLastFolderHighlighted == index) return;
+
+	CClientDC dc(this);
+	if (iLastFolderHighlighted >= 0)
+	{
+		CRect rc;
+		if (GetFolderRect(iLastFolderHighlighted, rc))
+		{
+			DrawFolder(&dc,iLastFolderHighlighted,rc);
+		}
+	}
+	if (index >= 0)
+	{
+		CRect rc;
+		if (GetFolderRect(index, rc))
+		{
+			DrawFolder(&dc,index,rc);
+		}
+	}
+	iLastFolderHighlighted = index;
+}
+
+void CGfxOutBarCtrl::OnTimer(UINT_PTR nIDEvent)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	if (nIDEvent == 1)
+	{
+		CPoint pt(GetMessagePos()); 
+		ScreenToClient(&pt);
+		CRect rc; GetClientRect(&rc);
+
+		int ht = HitTestEx(pt, iHoverFolder);
+
+		if (ht != htFolder || !(rc.PtInRect(pt)))
+		{
+			HighlightFolder(-1);
+			KillTimer(1);
+		}
+	}
+
+	if ( nIDEvent == 2 )
+	{// 鼠标在folderheader上x毫秒自动打开;
+		if (GetFocus() != this && PtInFolderHeadRect(m_curpoint)) SetFocus();
+
+		int index, ht = HitTestEx(m_curpoint, index);
+
+		if (ht == htFolder)
+		{
+			bool bHigh = true;
+
+			if (::GetCapture() == NULL)
+			{
+				SetCapture();
+				ASSERT(this == GetCapture());
+				AfxLockTempMaps();
+				if(index <GetFolderCount())
+					SetSelFolder(index);
+				ReleaseCapture();
+				AfxUnlockTempMaps(FALSE);
+			}
+		}
+	}
+	CWnd::OnTimer(nIDEvent);
+}
+
+BOOL CGfxOutBarCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
+{
+	if (GetFocus() != this)
+		SetFocus();
+
+	if ( m_nCurSelFolder <= 0 && m_nCurSelFolder >= m_arFolder.GetSize() )
+		return FALSE;
+
+	ScreenToClient(&pt);
+	if ( !PtInFolderHeadRect(pt) )
+	{
+		return FALSE;
+	}
+
+	INT nIndex = m_nCurSelFolder;
+	if (::GetCapture() == NULL)
+	{
+		SetCapture();
+		AfxLockTempMaps();
+		CBm_arFolder *pChild = NULL;
+		if ( zDelta > 0 )
+		{// 向上滚动;
+			if ( m_nCurSelFolder == 0 )
+			{
+				ReleaseCapture();
+				AfxUnlockTempMaps(FALSE);
+				return TRUE;
+			}
+
+			nIndex--;
+			pChild = (CBm_arFolder *)m_arFolder.GetAt(nIndex);
+			if ( pChild )
+			{
+				SetSelFolder(nIndex);
+			}
+		}
+		else
+		{// 向下滚动;
+			if ( m_nCurSelFolder == GetFolderCount() - 1)
+			{
+				ReleaseCapture();
+				AfxUnlockTempMaps(FALSE);
+				return TRUE;
+			}
+
+			nIndex++;
+			pChild = (CBm_arFolder *)m_arFolder.GetAt(nIndex);
+			if ( pChild )
+			{
+				SetSelFolder(nIndex);
+			}
+		}
+
+		ReleaseCapture();
+		AfxUnlockTempMaps(FALSE);
+	}
+
+	Invalidate();
+
+	return CWnd::OnMouseWheel(nFlags, zDelta, pt);
+}

+ 111 - 0
source/hook/skinui/GfxOutBarCtrl.h

@@ -0,0 +1,111 @@
+/************************************************************************/
+/*  Copyright (C), 2016-2020, [IT], 保留所有权利;
+/*  模 块 名:;
+/*  描    述:;
+/*
+/*  版    本:[V];	
+/*  作    者:[IT];
+/*  日    期:[8/19/2016];
+/*
+/*
+/*  注    意:;
+/*
+/*  修改记录:[IT];
+/*  修改日期:;
+/*  修改版本:;
+/*  修改内容:;
+/************************************************************************/
+#ifndef __GFX_OUTBARCTRL_20160823__
+#define __GFX_OUTBARCTRL_20160823__
+
+#pragma once
+
+#include <afxcoll.h>
+#include "EnBitmap.h"
+
+class CGfxOutBarCtrl : public CWnd
+{
+	// Construction
+	DECLARE_DYNCREATE(CGfxOutBarCtrl)
+public:
+	CGfxOutBarCtrl();
+
+public:
+	CEnBitmap	m_bmpNormalFolder;
+	CEnBitmap	m_bmpHoverFolder;
+
+	COLORREF	m_crBackground;
+	// 图片高度;
+	UINT		m_nFolderHeight;
+	// 鼠标位置;
+	CPoint		m_curpoint;
+
+	COLORREF	m_crText;
+	CFont		*m_pFont;
+
+	HCURSOR		hHandCursor;
+
+	int			iLastFolderHighlighted;
+	int			iHoverFolder;
+	// 当前选中的项;
+	int			m_nCurSelFolder;
+
+	HICON		iSelcon;
+
+	CPtrArray	m_arFolder;
+	class CBm_arFolder
+	{
+	public:
+		CBm_arFolder(const TCHAR * name, DWORD exData);
+		virtual  ~CBm_arFolder();
+		TCHAR *			cName;
+		DWORD			dwData;
+		CWnd *			pChild;
+	};
+
+public:
+	enum { htNothing = -1, htFolder,htFind};
+
+public:
+	void SetAutoFolder(IN const DWORD& dwTime);
+	DWORD GetFolderData(int iFolder = -1);
+	CWnd * GetFolderChild(int iFolder = -1);
+	int AddFolderBar(const TCHAR * pFolder, CWnd * pSon, const DWORD exData = 0);
+
+	void HighlightFolder(const int index);
+	void SetFolderText(const int index, const TCHAR * text);
+	void SetFolderImage(LPCTSTR lpszPath);
+	void SetSelIcon(LPCTSTR lpszIconPath);
+	void RemoveFolder(const int index);
+	int GetSelFolder() const;
+	int GetFolderCount() const;
+	void SetSelFolder(const int index);
+	int HitTestEx(const CPoint &point, int &index);
+	void GetInsideRect(CRect &rect) const;
+	int AddFolder(const TCHAR * cFolderName, const DWORD exData);
+	bool GetFolderRect(const int nIndex, CRect &rect) const;
+	bool PtInFolderHeadRect(CPoint pt) const;
+	BOOL Create(DWORD dwStyle, const RECT& rect, CWnd * pParentWnd, UINT nID);
+	void SetFolderHeight(UINT nHeight){m_nFolderHeight = nHeight;};
+	virtual ~CGfxOutBarCtrl();
+
+	// Generated message map functions
+protected:
+	void DrawFolder(CDC * pDC, const int iIdx, CRect rect);
+	//{{AFX_MSG(CGfxOutBarCtrl)
+	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
+	afx_msg void OnPaint();
+	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
+	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
+	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+	afx_msg void OnTimer(UINT_PTR nIDEvent);
+	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+	afx_msg void OnSize(UINT nType, int cx, int cy);
+	//}}AFX_MSG
+	DECLARE_MESSAGE_MAP()
+public:
+	afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
+};
+
+
+#endif // __GFX_OUTBARCTRL_20160823__

+ 499 - 0
source/hook/skinui/MyListCtrl.cpp

@@ -0,0 +1,499 @@
+/************************************************************************ 
+* 程序名:    精仿QQ主界面 
+* 制作人:    李克平, 2011年04月11日
+* 版本号:    1.0 
+************************************************************************/ 
+// MyListCtrl.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "MyListCtrl.h"
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CMyListCtrl
+
+CMyListCtrl::CMyListCtrl()
+{
+	m_crHighlight = RGB(254,242,205);
+	m_crHighlightBorder = RGB(233,175,0);
+	m_crHover = RGB(7,162,254);
+	nHoverItem = -1;
+	nLastHoverItem = -1;
+	m_bmpItemSelected.LoadImage(_T("Skin\\ItemSelected.bmp"));
+	m_bmpFaceBG.LoadImage(_T("Skin\\FaceBG.bmp"));
+	
+	m_hTailIconCamera =(HICON)::LoadImage(AfxGetApp()->m_hInstance, _T("Skin\\icon\\CameraProp.ico"), IMAGE_ICON,14,14,LR_LOADFROMFILE);
+	m_hTailIconEmail=(HICON)::LoadImage(AfxGetApp()->m_hInstance, _T("Skin\\icon\\EmailProp.ico"), IMAGE_ICON,14,14,LR_LOADFROMFILE);
+	m_hTailIconMobile=(HICON)::LoadImage(AfxGetApp()->m_hInstance, _T("Skin\\icon\\MobileProp.ico"), IMAGE_ICON,14,14,LR_LOADFROMFILE);
+}
+
+CMyListCtrl::~CMyListCtrl()
+{
+	if(m_hTailIconCamera)
+		::DestroyIcon(m_hTailIconCamera);
+	if(m_hTailIconEmail)
+		::DestroyIcon(m_hTailIconEmail);
+	if(m_hTailIconMobile)
+		::DestroyIcon(m_hTailIconMobile);
+}
+
+
+BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
+	//{{AFX_MSG_MAP(CMyListCtrl)
+	ON_WM_NCCALCSIZE()
+	ON_WM_MOUSEMOVE()
+	ON_WM_MEASUREITEM_REFLECT()
+	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdraw)
+	ON_WM_LBUTTONDOWN()
+	//}}AFX_MSG_MAP
+	ON_WM_SIZE()
+	ON_WM_ERASEBKGND()
+	ON_WM_PAINT()
+	ON_WM_TIMER()
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CMyListCtrl message handlers
+
+void CMyListCtrl::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp) 
+{
+	// TODO: Add your message handler code here and/or call default
+	ShowScrollBar(SB_HORZ,FALSE);
+	CListCtrl::OnNcCalcSize(bCalcValidRects, lpncsp);
+}
+
+
+void CMyListCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
+{
+	LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
+
+	LPNMLVCUSTOMDRAW lpLVCustomDraw = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);
+
+	lpLVCustomDraw->clrText = RGB(58,25,255); // white text
+    //lpLVCustomDraw->clrTextBk = RGB(222,0,0); 
+
+	/*
+	 
+    if(lpLVCustomDraw->nmcd.dwDrawStage==CDDS_PREPAINT)   
+        *pResult=CDRF_NOTIFYITEMDRAW;   
+    if(lpLVCustomDraw->nmcd.dwDrawStage==CDDS_ITEMPREPAINT)   
+    {   
+        for(int i=0;i<10;i++)   
+        {   
+            if(lpLVCustomDraw->nmcd.dwItemSpec==(unsigned)i)   
+            {   
+                lpLVCustomDraw->clrText=RGB(255,0,0);   
+                lpLVCustomDraw->clrTextBk=RGB(255,255,0);   
+            }   
+        }   
+    }   
+	*/
+	
+
+	// TODO: 在此添加控件通知处理程序代码
+	*pResult = 0;
+	*pResult |= CDRF_NOTIFYPOSTPAINT;
+	*pResult |= CDRF_NOTIFYITEMDRAW;
+	*pResult |= CDRF_NOTIFYSUBITEMDRAW;
+}
+
+int CMyListCtrl::InsertItem(int nItem, LPCTSTR szItemText, int nImageIndex, LUSERITEM* UserInfo)
+{
+	DEQUELVITEM* pDeqListItem = &m_DequeList;
+	if(UserInfo)
+		pDeqListItem ->push_back(*UserInfo);
+	nItem = CListCtrl::InsertItem(nItem,szItemText,nImageIndex);
+	return nItem;
+}
+
+void CMyListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
+{
+	CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
+	//CRect rcItem(lpDrawItemStruct->rcItem);
+	int nItem = lpDrawItemStruct->itemID;
+	CImageList* pImageList;
+
+	// Save dc state
+	int nSavedDC = pDC->SaveDC();
+
+	// Get item image and state info
+	LV_ITEM lvi;
+	lvi.mask = LVIF_IMAGE | LVIF_STATE;
+	lvi.iItem = nItem;
+	lvi.iSubItem = 0;
+	lvi.stateMask = 0xFFFF;		// get all state flags
+	GetItem(&lvi);
+
+	// Should the item be highlighted
+	BOOL bHighlight = ((lvi.state & LVIS_DROPHILITED) || ( (lvi.state & LVIS_SELECTED) && ((GetFocus() == this) || (GetStyle() & LVS_SHOWSELALWAYS))));
+				
+	// Get rectangles for drawing
+	CRect rcClient;
+	GetClientRect(&rcClient);
+
+	CRect rcBounds, rcLabel, rcIcon;
+	GetItemRect(nItem, rcBounds, LVIR_BOUNDS);
+	GetItemRect(nItem, rcLabel, LVIR_LABEL);
+	GetItemRect(nItem, rcIcon, LVIR_ICON);
+	CRect rcCol( rcBounds );
+
+	POINT pt;
+	GetCursorPos(&pt);
+	ScreenToClient(&pt);
+
+	CString sLabel = GetItemText( nItem, 0 );
+
+	// Labels are offset by a certain amount  
+	// This offset is related to the width of a space character
+	int offset = pDC->GetTextExtent(_T(" "), 1 ).cx*2;
+
+	CRect rcHighlight;
+
+	int nExt;
+	switch( m_nHighlight )
+	{
+	case 0:
+		nExt = pDC->GetOutputTextExtent(sLabel).cx + offset;
+		rcHighlight = rcLabel;
+		if( rcLabel.left + nExt < rcLabel.right )
+			rcHighlight.right = rcLabel.left + nExt;
+		break;
+	case 1:
+		rcHighlight = rcBounds;
+		rcHighlight.left = rcLabel.left;
+		break;
+	default:
+		rcHighlight = rcBounds;
+		rcHighlight.left = rcBounds.left+1;
+		rcHighlight.right = rcClient.right-2;
+		break;
+	}
+
+	// 画背景
+	CRect rcIconBG(rcIcon);
+	rcIconBG.right += 12;
+
+	CEnBitmap bmpFaceBG;
+	if( bHighlight )
+	{
+		//nItem是当前高亮的项
+		if(m_bmpItemSelected.m_hObject != NULL)
+			m_bmpItemSelected.ExtendDraw(pDC,rcLabel/*rcHighlight*/,20,10,TRUE);
+
+		//画图标背景
+		if(m_bmpFaceBG.m_hObject != NULL)
+		{
+			m_bmpFaceBG.DrawImage(bmpFaceBG,1,1,2,1);
+			bmpFaceBG.ExtendDraw(pDC,rcIconBG,20,10);
+		}
+	}
+	else
+	{
+		//if(nHoverItem == nItem)
+		//	pDC->FillRect(rcHighlight, &CBrush(m_crHover));
+		//else
+			pDC->FillRect(rcHighlight, &CBrush(RGB(255,255,255)));
+
+		//画图标背景
+		if(m_bmpFaceBG.m_hObject != NULL)
+		{
+			m_bmpFaceBG.DrawImage(bmpFaceBG,2,1,2,1);
+			bmpFaceBG.ExtendDraw(pDC,rcIconBG,20,10);
+		}
+	}
+	// Draw normal and overlay icon
+	pImageList = GetImageList(LVSIL_SMALL);
+	if (pImageList)
+	{
+		UINT nOvlImageMask=lvi.state & LVIS_OVERLAYMASK;
+
+		pImageList->Draw(pDC, lvi.iImage,
+			CPoint(rcIcon.left+6, rcIcon.top+6),ILD_TRANSPARENT | nOvlImageMask );
+	}
+
+ 
+	// Draw item label - Column 0
+	rcLabel.top += 5;
+	rcLabel.left += offset/2 + 7;
+	rcLabel.right -= offset;
+
+	pDC->DrawText(sLabel,-1,rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP
+				 | DT_END_ELLIPSIS);
+
+
+	LUSERITEM userInfo;
+	GetUserItemInfo(sLabel,&userInfo);
+	CSize size = pDC->GetTextExtent(sLabel);
+	if(userInfo.szUserID !="")
+	{
+		sLabel = userInfo.szNoticeMsg;
+
+		rcLabel.top = rcLabel.top + size.cy + 3;
+		rcLabel.right = rcClient.right;
+		//if(rcLabel.PtInRect(pt))
+		//{
+		//	pDC->SetTextColor(RGB(10,255,10));
+		//}
+		//else
+		//{
+		pDC->SetTextColor(GetSysColor(COLOR_BTNSHADOW));
+		//}
+		pDC->DrawText(sLabel,rcLabel,DT_SINGLELINE|DT_LEFT|DT_END_ELLIPSIS);
+	}
+
+	//Draw TailIcon
+	DWORD nStyle = GetItemData(nItem);
+	CRect rcCamera = GetTailIconRect(nItem,TVS_CAMERA);
+	if ( (nStyle & TVS_CAMERA) && (m_hTailIconCamera !=NULL) )
+	{
+		if( rcCamera.PtInRect(pt) )
+		{
+			pDC->FillSolidRect(rcCamera,m_crHighlight);
+			pDC->Draw3dRect(rcCamera,m_crHighlightBorder,m_crHighlightBorder);
+		}
+		::DrawIconEx(*pDC,rcCamera.left+2,rcCamera.top+2,m_hTailIconCamera,14,14,0,NULL,DI_NORMAL);
+	}
+	
+	CRect rcEmail = GetTailIconRect(nItem,TVS_EMAIL);
+	if ( (nStyle & TVS_EMAIL) && (m_hTailIconEmail !=NULL) )
+	{
+		if( rcEmail.PtInRect(pt) )
+		{
+			pDC->FillSolidRect(rcEmail,m_crHighlight);
+			pDC->Draw3dRect(rcEmail,m_crHighlightBorder,m_crHighlightBorder);
+		}
+		::DrawIconEx(*pDC,rcEmail.left+2,rcEmail.top+2,m_hTailIconEmail,14,14,0,NULL,DI_NORMAL);
+	}
+
+	CRect rcMobile = GetTailIconRect(nItem,TVS_MOBILE);
+	if ( (nStyle & TVS_MOBILE) && (m_hTailIconMobile !=NULL) )
+	{
+		if( rcMobile.PtInRect(pt) )
+		{
+			pDC->FillSolidRect(rcMobile,m_crHighlight);
+			pDC->Draw3dRect(rcMobile,m_crHighlightBorder,m_crHighlightBorder);
+		}
+		::DrawIconEx(*pDC,rcMobile.left+2,rcMobile.top+2,m_hTailIconMobile,14,14,0,NULL,DI_NORMAL);
+	}
+
+	// Draw labels for remaining columns
+	LV_COLUMN lvc;
+	lvc.mask = LVCF_FMT | LVCF_WIDTH;
+
+	if( m_nHighlight == 0 )		// Highlight only first column
+	{
+		pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
+		pDC->SetBkColor(::GetSysColor(COLOR_WINDOW));
+	}
+
+	rcBounds.right = rcHighlight.right > rcBounds.right ? rcHighlight.right+10 :
+							rcBounds.right + 10;
+
+	for(int nColumn = 1; GetColumn(nColumn, &lvc); nColumn++)
+	{
+		rcCol.left = rcCol.right;
+		rcCol.right += lvc.cx;
+
+		 //Draw the background if needed
+		//if( m_nHighlight == HIGHLIGHT_NORMAL )
+		//	pDC->FillRect(rcCol, &CBrush(::GetSysColor(COLOR_WINDOW)));
+
+		sLabel = GetItemText(nItem, nColumn);
+		if (sLabel.GetLength() == 0)
+			continue;
+
+		// Get the text justification
+		UINT nJustify = DT_LEFT;
+		switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
+		{
+		case LVCFMT_RIGHT:
+			nJustify = DT_RIGHT;
+			break;
+		case LVCFMT_CENTER:
+			nJustify = DT_CENTER;
+			break;
+		default:
+			break;
+		}
+
+		rcLabel = rcCol;
+		rcLabel.left += offset;
+		rcLabel.right -= offset;
+
+		pDC->DrawText(sLabel, -1, rcLabel, nJustify | DT_SINGLELINE |
+					DT_NOPREFIX | DT_VCENTER | DT_END_ELLIPSIS);
+	}
+
+	// Restore dc
+	pDC->RestoreDC( nSavedDC );
+}
+
+CRect CMyListCtrl::GetTailIconRect(int nItem,DWORD dwServeFlag)
+{
+	CRect rcIcon,rcClient;
+	GetItemRect(nItem,rcIcon,LVIR_ICON);
+	GetClientRect(&rcClient);
+
+	DWORD nStyle = GetItemData(nItem);
+	switch(nStyle & dwServeFlag)
+	{
+	case TVS_CAMERA:
+		{
+			rcIcon.left = rcClient.right - 22;
+			rcIcon.right = rcIcon.left +18;
+			rcIcon.bottom = rcIcon.top +18;
+		}
+		break;
+	case TVS_EMAIL:
+		{
+			rcIcon.left = rcIcon.right + 10;
+			rcIcon.right = rcIcon.left +18;
+			rcIcon.top = rcIcon.bottom - 20;
+			rcIcon.bottom  = rcIcon.top + 18;
+		}
+		break;
+	case TVS_MOBILE:
+		{
+			rcIcon.left = rcIcon.right + 10;
+			if (nStyle & TVS_EMAIL)
+				rcIcon.left += 18;
+			rcIcon.right = rcIcon.left +18;
+			rcIcon.top = rcIcon.bottom - 20;
+			rcIcon.bottom  = rcIcon.top + 18;
+		}
+		break;
+	default:
+		rcIcon.SetRectEmpty();
+		break;
+	}
+	return rcIcon;
+}
+
+BOOL CMyListCtrl::GetUserItemInfo(LPCTSTR szItemText,LUSERITEM* userInfo)
+{
+	ASSERT(userInfo !=NULL);
+
+	BOOL bRet = FALSE;
+	DEQUELVITEM* pDeqListItem = &m_DequeList;
+
+	DEQUELVITEM::iterator it,itbegin = pDeqListItem->begin(),itend = pDeqListItem->end();
+	for ( it = itbegin; it != itend; it++ )
+	{
+		if( it->szUserID == szItemText)
+		{
+			*userInfo = (LUSERITEM)*it;	//复制结构数据到userInof;
+			bRet = TRUE;
+			break;
+		}
+	}
+	return bRet;
+}
+
+void CMyListCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
+{
+	int nItem = HitTest(point);
+	if(nItem != -1)
+	{
+		CString strTip;
+		CRect rcServe;
+		for(DWORD dwFlag = TVS_CAMERA;dwFlag < TVS_ONLINEUSER;dwFlag++)
+		{
+			rcServe = GetTailIconRect(nItem,dwFlag);
+			if(rcServe.PtInRect(point))
+			{
+				strTip.Format(_T("位置:nItem=%d,dwServeFlag=%#0.8x"),nItem,dwFlag);
+				break;
+			}
+		}
+		if(!strTip.IsEmpty())
+			MessageBox(strTip);
+	}
+	CListCtrl::OnLButtonDown(nFlags, point);
+}
+
+//调整行高
+void CMyListCtrl::MeasureItem( LPMEASUREITEMSTRUCT lpMis )
+{
+	lpMis->itemHeight = 52;
+}
+
+void CMyListCtrl::OnSize(UINT nType, int cx, int cy)
+{
+	CListCtrl::OnSize(nType, cx, cy);
+	SetColumnWidth(0 ,cx);
+	RedrawWindow();
+	// TODO: 在此处添加消息处理程序代码
+}
+
+BOOL CMyListCtrl::OnEraseBkgnd(CDC* pDC)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	return TRUE;
+	//return CListCtrl::OnEraseBkgnd(pDC);
+}
+
+void CMyListCtrl::OnPaint()
+{
+	CPaintDC dc(this); // device context for painting
+
+	CRect rcClient;
+	GetClientRect(&rcClient);
+
+	CDC memdc;
+	memdc.CreateCompatibleDC(&dc);	
+	CBitmap bitmap;
+	bitmap.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height());
+	memdc.SelectObject( &bitmap );
+
+	memdc.FillSolidRect(rcClient,RGB(255,255,255));
+	CWnd::DefWindowProc(WM_PAINT, (WPARAM)memdc.m_hDC , 0);
+
+	dc.BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &memdc, 
+		0, 0,SRCCOPY);
+}
+
+void CMyListCtrl::OnMouseMove(UINT nFlags, CPoint point) 
+{
+	// TODO: Add your message handler code here and/or call default
+	nHoverItem = HitTest(point);
+	if(nLastHoverItem >= 0 )
+	{
+		CRect rcItem;
+		GetItemRect(nLastHoverItem,rcItem,LVIR_BOUNDS);
+		InvalidateRect(rcItem);
+	}
+	nLastHoverItem = nHoverItem;
+	if (nHoverItem >= 0)
+	{
+		CRect rcItem;
+		GetItemRect(nHoverItem,rcItem,LVIR_BOUNDS);
+		InvalidateRect(rcItem);
+		//SetTimer(1,100,NULL);
+	}
+	CListCtrl::OnMouseMove(nFlags, point);
+}
+
+void CMyListCtrl::OnTimer(UINT_PTR nIDEvent)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	if (nIDEvent == 1)
+	{
+		CPoint pt(GetMessagePos()); ScreenToClient(&pt);
+		CRect rc; GetClientRect(&rc);
+		if (!rc.PtInRect(pt))
+		{
+			nHoverItem = -1;
+			CRect rcItem;
+			GetItemRect(nLastHoverItem,rcItem,LVIR_BOUNDS);
+			InvalidateRect(rcItem);
+			KillTimer(1);
+		}
+	}
+	
+	CListCtrl::OnTimer(nIDEvent);
+}

+ 97 - 0
source/hook/skinui/MyListCtrl.h

@@ -0,0 +1,97 @@
+/************************************************************************ 
+* 程序名:    精仿QQ主界面 
+* 制作人:    李克平, 2011年04月11日
+* 版本号:    1.0 
+************************************************************************/
+#if !defined(AFX_MYLISTCTRL_H__AEB7A796_0079_40F7_892E_32954E3D1604__INCLUDED_)
+#define AFX_MYLISTCTRL_H__AEB7A796_0079_40F7_892E_32954E3D1604__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+// MyListCtrl.h : header file
+//
+#include	<deque>
+#include <atlimage.h> 
+#include "EnBitmap.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// CMyListCtrl window
+struct LUSERITEM
+{
+	CString		szUserID;
+	CString		szUserName;
+	CString		szIPAddress;
+	CString		szServerAddress;
+	CString		szNoticeMsg;
+	BOOL		bOnline;
+	int			nHeadImageIndex;
+};
+
+typedef std::deque<LUSERITEM>	DEQUELVITEM;
+/////////////////////////////////////////////////////////////////////////////
+// CMyListCtrl window
+
+class CMyListCtrl : public CListCtrl
+{
+// Construction
+public:
+	CMyListCtrl();
+
+	enum {  TVS_CAMERA = 1 << 0, TVS_EMAIL = 1 << 1, TVS_MOBILE = 1 << 2,TVS_ONLINEUSER = 1 << 3};
+// Attributes
+public:
+	COLORREF	m_crHighlight;
+	COLORREF	m_crHighlightBorder;
+	COLORREF	m_crHover;
+	CEnBitmap	m_bitmap;
+// Operations
+public:
+
+	void SetBackBitmap(LPCTSTR lpszImage){};
+	int InsertItem(int nItem, LPCTSTR szItemText, int nImageIndex, LUSERITEM* UserInfo = NULL);
+	BOOL GetUserItemInfo(LPCTSTR szItemText,LUSERITEM* userInfo);
+	CRect GetTailIconRect(int nItem,DWORD dwServeFlag);
+// Overrides
+	// ClassWizard generated virtual function overrides
+	//{{AFX_VIRTUAL(CMyListCtrl)
+	//}}AFX_VIRTUAL
+
+// Implementation
+public:
+	virtual ~CMyListCtrl();	
+	int m_nHighlight;
+
+	virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
+	// Generated message map functions
+protected:
+	//{{AFX_MSG(CMyListCtrl)
+	afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp);
+	afx_msg void OnMouseMove(UINT nFlags, CPoint point) ;
+	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
+	afx_msg void MeasureItem( LPMEASUREITEMSTRUCT lpMeasureItemStruct);
+	//}}AFX_MSG
+    afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult);
+	afx_msg void OnSize(UINT nType, int cx, int cy);
+	DECLARE_MESSAGE_MAP()
+private:
+	DEQUELVITEM m_DequeList;
+	HICON m_hTailIconCamera;
+	HICON m_hTailIconEmail;
+	HICON m_hTailIconMobile;
+	CEnBitmap m_bmpItemSelected;
+	CEnBitmap m_bmpFaceBG;
+	int nHoverItem;
+	int nLastHoverItem;
+public:
+	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
+	afx_msg void OnPaint();
+	afx_msg void OnTimer(UINT_PTR nIDEvent);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_MYLISTCTRL_H__AEB7A796_0079_40F7_892E_32954E3D1604__INCLUDED_)

+ 448 - 0
source/hook/skinui/SkinButton.cpp

@@ -0,0 +1,448 @@
+#include "stdafx.h"
+#include "SkinButton.h"
+
+// CSkinButton
+#define IDC_CURSOR_HAND                 132
+
+IMPLEMENT_DYNAMIC(CSkinButton, CButton)
+
+CSkinButton::CSkinButton()
+{
+	m_state = NORMAL;
+	m_pFont = new CFont();
+	m_pFont->CreatePointFont(90, _T("Arial"));
+	m_fg = RGB(0, 0, 0);
+	m_bg = RGB(255, 255, 255);
+	m_crBack = RGB(255, 0, 255);
+	m_bMouseOver = false;
+	m_bEnabled = true;
+	m_bDCStored = false;
+	m_bShowOwnerText = FALSE;
+	m_textPos = CPoint(0, 0);
+	m_iconRect = CRect(0, 0, 16, 16);
+	m_bmpIconButton.LoadImage(_T("Skin\\IconButton.bmp"));
+}
+
+CSkinButton::~CSkinButton()
+{
+	delete m_pFont;
+	m_memDC.DeleteDC();
+}
+
+BEGIN_MESSAGE_MAP(CSkinButton, CButton)
+	ON_WM_MOUSEMOVE()
+	ON_WM_TIMER()
+	ON_WM_ERASEBKGND()
+	ON_WM_SETCURSOR()
+	ON_WM_ENABLE()
+	ON_WM_LBUTTONUP()
+END_MESSAGE_MAP()
+
+void CSkinButton::DrawItem(LPDRAWITEMSTRUCT lpDIS)
+{
+	//CDC* pDC = CDC::FromHandle(lpDIS->hDC);
+	UINT state = lpDIS->itemState;
+	//CRect rect;
+	//rect.CopyRect(&lpDIS->rcItem); 
+
+	m_state = NORMAL;
+
+	if (state & ODS_FOCUS)
+	{
+		if (state & ODS_SELECTED)
+		{
+			m_state = DOWN;
+		}
+		else
+		{
+			if (m_bMouseOver)
+				m_state = HOVER;
+		}
+	}
+	else
+	{
+		m_state = NORMAL;
+	}
+	if (state & ODS_DISABLED)
+	{
+		m_state = DISABLE;
+		m_bEnabled = false;
+	}
+
+	DrawButton();
+}
+
+void CSkinButton::DrawButton()
+{
+	CClientDC  dc(this);
+
+	CRect	rect;
+	GetClientRect(&rect);
+
+	CDC memDC;
+	memDC.CreateCompatibleDC(&dc);
+
+	CBitmap Screen;
+	Screen.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
+	memDC.SelectObject(&Screen);
+	Screen.DeleteObject();
+
+	//画背景;
+	memDC.BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &m_memDC, 0, 0, SRCCOPY);
+
+	CString strText;
+	GetWindowText(strText);
+
+	memDC.SetBkMode(TRANSPARENT);
+	memDC.SelectObject(m_pFont);
+	switch (m_state)
+	{
+	case NORMAL:
+	{
+		//memDC.TextOutW(m_textPos.x,m_textPos.y,str);
+		if (m_bmpNormal.m_hObject != 0)
+			m_bmpNormal.TransparentBlt(memDC, rect, m_crBack);
+		if (!m_hMouseOutIcon.IsNull())
+		{
+			m_hMouseOutIcon.TransparentBlt(memDC, m_iconRect.left + 2, m_iconRect.top + 2,
+				m_iconRect.Width(), m_iconRect.Height(), RGB(0, 0, 0));
+			memDC.SetTextColor(GetFGColor());
+			memDC.TextOut(m_textPos.x + 2, m_textPos.y + 2, strText);
+			_tprintf(_T("Normal-Icon:%d,%d\n"), m_textPos.x + 2, m_textPos.y + 2);
+		}
+		else if (m_bShowOwnerText)
+		{
+			DrawButtonText(&memDC, rect, strText, GetFGColor());
+			_tprintf(_T("Normal-UnIcon:%d,%d,%d,%d\n"), rect.left, rect.top, rect.right, rect.bottom);
+		}
+	}
+	break;
+	case HOVER:
+	{	
+		//DrawFilledRect(&memDC, rect, RGB(255,255,0));
+		if (m_bmpHover.m_hObject != 0)
+			m_bmpHover.TransparentBlt(memDC, rect, m_crBack);
+		if (!m_hMouseInIcon.IsNull())
+		{
+			if (m_bmpIconButton.m_hObject != 0)
+			{
+				CEnBitmap bmpHover;
+				m_bmpIconButton.DrawImage(bmpHover, 1, 1, 2, 1);
+				bmpHover.ExtendDraw(&memDC, rect, 10, 10, TRUE);
+			}
+
+			m_hMouseInIcon.TransparentBlt(memDC, m_iconRect.left + 2, m_iconRect.top + 2,
+				m_iconRect.Width(), m_iconRect.Height(), RGB(0, 0, 0));
+			memDC.SetTextColor(GetBGColor());
+			memDC.TextOut(m_textPos.x + 2, m_textPos.y + 2, strText);
+			_tprintf(_T("Hover-Icon:%d,%d\n"), m_textPos.x + 2, m_textPos.y + 2);
+		}
+		else if (m_bShowOwnerText)
+		{
+			rect.OffsetRect(-1, -1);
+			DrawButtonText(&memDC, rect, strText, GetFGColor());
+			_tprintf(_T("Hover-UnIcon:%d,%d,%d,%d\n"), rect.left, rect.top, rect.right, rect.bottom);
+			rect.OffsetRect(1, 1);
+		}
+	}
+	break;
+	case DOWN:
+	{	
+		//DrawFilledRect(&memDC, rect, RGB(0,0,255)); 
+		if (m_bmpDown.m_hObject != 0)
+			m_bmpDown.TransparentBlt(memDC, rect, m_crBack);
+		if (!m_hMouseOutIcon.IsNull())
+		{
+			if (m_bmpIconButton.m_hObject != 0)
+			{
+				CEnBitmap bmpDown;
+				m_bmpIconButton.DrawImage(bmpDown, 2, 1, 2, 1);
+				bmpDown.ExtendDraw(&memDC, rect, 10, 10, TRUE);
+			}
+
+			m_hMouseOutIcon.TransparentBlt(memDC, m_iconRect.left + 3, m_iconRect.top + 3,
+				m_iconRect.Width(), m_iconRect.Height(), RGB(0, 0, 0));
+			memDC.SetTextColor(GetBGColor());
+			memDC.TextOut(m_textPos.x + 3, m_textPos.y + 3, strText);
+			_tprintf(_T("Down-Icon:%d,%d\n"), m_textPos.x + 2, m_textPos.y + 2);
+		}
+		else if (m_bShowOwnerText)
+		{
+			rect.OffsetRect(1, 1);
+			DrawButtonText(&memDC, rect, strText, GetFGColor());
+			_tprintf(_T("Down-UnIcon:%d,%d,%d,%d\n"), rect.left, rect.top, rect.right, rect.bottom);
+			rect.OffsetRect(-1, -1);
+		}
+	}
+	break;
+	case DISABLE:
+	{
+		if (m_bmpDisable.m_hObject != 0)
+			m_bmpDisable.TransparentBlt(memDC, rect, m_crBack);
+		if (!m_hMouseOutIcon.IsNull())
+		{
+			m_hMouseOutIcon.TransparentBlt(memDC, m_iconRect.left + 2, m_iconRect.top + 2,
+				m_iconRect.Width(), m_iconRect.Height(), RGB(0, 0, 0));
+			memDC.SetTextColor(GetFGColor());
+			memDC.TextOut(m_textPos.x + 2, m_textPos.y + 2, strText);
+		}
+		else if (m_bShowOwnerText)
+			DrawButtonText(&memDC, rect, strText, RGB(128, 128, 128));
+	}
+	break;
+	default:
+		break;
+	}
+
+	dc.BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);
+
+	::DeleteDC(memDC);
+}
+
+void CSkinButton::DrawFilledRect(CDC *DC, CRect R, COLORREF color)
+{
+	CBrush B;
+	B.CreateSolidBrush(color);
+	DC->FillRect(R, &B);
+}
+
+void CSkinButton::DrawButtonText(CDC *DC, CRect R, CString str, COLORREF TextColor)
+{
+	COLORREF prevColor = DC->SetTextColor(TextColor);
+	DC->SetBkMode(TRANSPARENT);
+	DC->SelectObject(m_pFont);
+	if (m_hMouseOutIcon.IsNull() && m_hMouseInIcon.IsNull())
+	{
+		//int iconwidth=::GetSystemMetrics(SM_CXICON);
+		R.right = R.right - m_textPos.x;
+		_tprintf(_T("DrawText:%d\n"), m_textPos.x);
+		DC->DrawText(str, str.GetLength(), R, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+	}
+	else
+	{
+		DC->DrawText(str, str.GetLength(), R, DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
+	}
+
+	DC->SetTextColor(prevColor);
+}
+
+void CSkinButton::OnMouseMove(UINT nFlags, CPoint point)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	//if (nFlags & MK_LBUTTON && m_bMouseOver == FALSE) 
+	//	return;
+	if (!m_bMouseOver&&m_bEnabled)
+	{
+		m_bMouseOver = true;
+		m_state = HOVER;
+
+		CPoint	point;
+		CRect	rect;
+		GetWindowRect(&rect);
+		GetCursorPos(&point);
+		if (!rect.PtInRect(point) && m_bMouseOver&&m_bEnabled)
+		{
+			SetTimer(1, 10, NULL);
+			return;
+		}
+		DrawButton();
+		SetTimer(1, 10, NULL);
+	}
+	CButton::OnMouseMove(nFlags, point);
+}
+
+void CSkinButton::OnTimer(UINT_PTR nIDEvent)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	CPoint	point;
+	CRect	rect;
+	GetWindowRect(&rect);
+	GetCursorPos(&point);
+
+	if (!rect.PtInRect(point) && m_bMouseOver&&m_bEnabled)
+	{
+		KillTimer(1);
+		m_bMouseOver = false;
+		m_state = NORMAL;
+		DrawButton();
+	}
+
+	CButton::OnTimer(nIDEvent);
+}
+
+void CSkinButton::PreSubclassWindow()
+{
+	// TODO: 在此添加专用代码和/或调用基类
+	SetOwnerDraw(true);
+
+	CButton::PreSubclassWindow();
+}
+
+void CSkinButton::SetOwnerDraw(bool IsDraw)
+{
+	if (IsDraw)
+	{
+		ModifyStyle(NULL, BS_OWNERDRAW);
+		Invalidate();
+	}
+	else
+	{
+		ModifyStyle(BS_OWNERDRAW, NULL);
+		Invalidate();
+	}
+}
+
+
+void CSkinButton::SetStatusBmp()
+{
+	if (m_bmpButton.m_hObject != 0)
+	{
+		if (m_bmpNormal.m_hObject != NULL) m_bmpNormal.DeleteObject();
+		if (m_bmpHover.m_hObject != NULL) m_bmpHover.DeleteObject();
+		if (m_bmpDown.m_hObject != NULL) m_bmpDown.DeleteObject();
+		if (m_bmpDisable.m_hObject != NULL) m_bmpDisable.DeleteObject();
+
+		m_bmpButton.DrawImage(m_bmpNormal, 1, 1, 4, 1);
+		m_bmpButton.DrawImage(m_bmpHover, 2, 1, 4, 1);
+		m_bmpButton.DrawImage(m_bmpDown, 3, 1, 4, 1);
+		m_bmpButton.DrawImage(m_bmpDisable, 4, 1, 4, 1);
+
+		m_bmpButton.DeleteObject();
+	}
+}
+
+//设置区域和大小
+void CSkinButton::ResetButtonSize(BOOL bResetSize)
+{
+	SetWindowRgn(m_bmpNormal.BitmapToRegion(m_crBack), TRUE);
+	SetWindowPos(NULL, 0, 0, m_bmpNormal.Width(), m_bmpNormal.Height(), SWP_NOMOVE);
+}
+
+
+void CSkinButton::LoadImage(LPCTSTR szImagePath, COLORREF crBack, BOOL bResetSize)
+{
+	if (!PathFileExists(szImagePath))
+		return;
+	if (m_bmpButton.m_hObject != NULL)
+		m_bmpButton.DeleteObject();
+
+	m_bmpButton.LoadImage(szImagePath, RGB(255, 0, 255));
+	m_crBack = crBack;
+	SetStatusBmp();
+	ResetButtonSize(bResetSize);
+}
+
+void CSkinButton::loadHoverBGBmp(LPCTSTR szImagePath)
+{
+	m_bmpIconButton.LoadImage(szImagePath, RGB(255, 0, 255));
+}
+
+BOOL CSkinButton::LoadBitmap(UINT uIDRes, COLORREF crBack, BOOL bResetSize)
+{
+	if (m_bmpButton.LoadBitmap(uIDRes))
+	{
+		m_bmpButton.DrawImage(m_bmpNormal, 1, 1, 4, 1);
+		m_crBack = crBack;
+		SetStatusBmp();
+		ResetButtonSize(bResetSize);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+void CSkinButton::SetImage(CString strNormal, CString strHover, CString strDown, CString strDisable)
+{
+	m_bmpNormal.LoadImage(strNormal);
+	m_bmpHover.LoadImage(strHover);
+	m_bmpDown.LoadImage(strDown);
+	m_bmpDisable.LoadImage(strDisable);
+}
+
+void CSkinButton::SetImage(UINT nNormalID, UINT nHoverID, UINT nDownID, UINT nDisableID)
+{
+	m_bmpNormal.LoadBitmap(nNormalID);
+	m_bmpHover.LoadBitmap(nHoverID);
+	m_bmpDown.LoadBitmap(nDownID);
+	m_bmpDisable.LoadBitmap(nDisableID);
+}
+
+BOOL CSkinButton::OnEraseBkgnd(CDC* pDC)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	//保存按钮背景
+	if (!m_bDCStored)
+	{
+		CRect  rect;
+		GetClientRect(&rect);
+
+		m_memDC.CreateCompatibleDC(pDC);
+		CBitmap	btScreen;
+		btScreen.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
+		m_memDC.SelectObject(&btScreen);
+
+		m_memDC.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
+
+		m_bDCStored = true;
+
+		CRgn rgn;
+		rgn.CreateRectRgn(0, 0, rect.Width(), rect.Height());
+		SetWindowRgn(rgn, TRUE);
+
+		btScreen.DeleteObject();
+	}
+	return TRUE;// CButton::OnEraseBkgnd(pDC);//
+}
+
+BOOL CSkinButton::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	::SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR_HAND));
+	return TRUE;
+	//return CButton::OnSetCursor(pWnd, nHitTest, message);
+}
+
+void CSkinButton::SetIcon(CString strMouseOut, CString strMouseIn)
+{
+	m_hMouseOutIcon.Load(strMouseOut);
+	m_hMouseInIcon.Load(strMouseIn);
+	SetWindowPos(NULL, 0, 0, 20, 20, SWP_NOMOVE);
+}
+
+void CSkinButton::SetColor(COLORREF fgcolor, COLORREF bgcolor)
+{
+	m_fg = fgcolor;
+	m_bg = bgcolor;
+	DrawButton();
+}
+
+void CSkinButton::SetTextPos(CPoint point)
+{
+	m_textPos = point;
+	DrawButton();
+}
+
+CRect CSkinButton::GetRectInParent()
+{
+	CRect rcWindowParent;
+	GetParent()->GetWindowRect(rcWindowParent);//client
+	CRect rcWindow;
+	GetWindowRect(&rcWindow);
+	CRect rect;
+	rect.left = rcWindow.left - rcWindowParent.left;
+	rect.top = rcWindow.top - rcWindowParent.top;
+	rect.right = rcWindow.right - rcWindowParent.left;
+	rect.bottom = rcWindow.bottom - rcWindowParent.top;
+
+	return rect;
+}
+
+void CSkinButton::OnEnable(BOOL bEnable)
+{
+	CButton::OnEnable(bEnable);
+
+	// TODO: 在此处添加消息处理程序代码
+	if (bEnable)
+		m_bEnabled = true;
+	else
+		m_bEnabled = false;
+}

+ 110 - 0
source/hook/skinui/SkinButton.h

@@ -0,0 +1,110 @@
+/************************************************************************/
+/*  Copyright (C), 2016-2020, [IT], 保留所有权利;
+/*  模 块 名:;
+/*  描    述:;
+/*
+/*  版    本:[V];	
+/*  作    者:[IT];
+/*  日    期:[8/19/2016];
+/*
+/*
+/*  注    意:;
+/*
+/*  修改记录:[IT];
+/*  修改日期:;
+/*  修改版本:;
+/*  修改内容:;
+/************************************************************************/ 
+#pragma once
+#include <atlimage.h>       
+#include "EnBitmap.h"
+
+// CSkinButton
+
+class CSkinButton : public CButton
+{
+	DECLARE_DYNAMIC(CSkinButton)
+
+public:
+	CSkinButton();
+	virtual ~CSkinButton();
+
+	typedef enum state
+	{
+		NORMAL,
+		HOVER,
+		DOWN,
+		DISABLE
+	}state;
+
+protected:
+	DECLARE_MESSAGE_MAP()
+
+	CEnBitmap m_bmpButton;
+	CEnBitmap m_bmpNormal;
+	CEnBitmap m_bmpHover;
+	CEnBitmap m_bmpDown;
+	CEnBitmap m_bmpDisable;
+	CEnBitmap m_bmpIconButton;
+
+
+private:
+	// 是否显示按钮本身文本;
+	BOOL		m_bShowOwnerText;
+	state		m_state;
+	COLORREF	m_fg, m_bg;
+	COLORREF	m_crBack;
+	bool		m_bMouseOver;
+	BOOL		m_bDown;
+	bool		m_bEnabled;
+	CFont		*m_pFont;
+
+	bool m_bDCStored;//是否已经保存背景图
+
+	CImage m_hMouseInIcon;
+	CImage m_hMouseOutIcon;
+	CPoint m_textPos;
+	CRect m_iconRect;
+
+	CDC m_memDC;
+
+public:
+	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+	afx_msg void OnTimer(UINT_PTR nIDEvent);
+	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
+	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+protected:
+	virtual void PreSubclassWindow();
+	virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);
+protected:	
+	//在按钮中填充颜色
+	void DrawFilledRect(CDC *DC, CRect R, COLORREF color);
+	//设置按钮上的字体颜色
+	void DrawButtonText(CDC *DC, CRect R, CString str, COLORREF TextColor);
+	void DrawButton();
+public:
+	void ShowOwnerText(IN BOOL bShowOwnerText = TRUE) { m_bShowOwnerText = bShowOwnerText; };
+	void SetOwnerDraw(bool IsDraw);
+	void SetImage(UINT nNormalID, UINT nHoverID, UINT nDownID, UINT nDisableID);
+	void SetImage(CString strNormal, CString strHover, CString strDown, CString strDisable);
+	void loadHoverBGBmp(LPCTSTR szImagePath);
+	void LoadImage(LPCTSTR szImagePath,COLORREF crBack = RGB(255,0,255),BOOL bResetSize =TRUE);
+	BOOL LoadBitmap(UINT uIDRes,COLORREF crBack,BOOL bResetSize = TRUE);
+	void SetIcon(CString  strMouseOut,CString strMouseIn);
+	void SetColor(COLORREF fgcolor,COLORREF bgcolor);
+	void SetTextPos(CPoint point);
+	CEnBitmap* GetPaintBmp(){return &m_bmpNormal;}
+	CImage* GetPaintIcon(){return &m_hMouseOutIcon;}
+	CPoint GetTextPos(){return m_textPos;}
+	COLORREF GetFGColor() { return m_fg; }	
+	COLORREF GetBGColor() { return m_bg; }
+	CRect GetRectInParent();
+	void SetStatusBmp();
+	CRect GetIconRect(){return m_iconRect;}
+	int Width(){return m_bmpNormal.Width();}
+	int Heighth(){return m_bmpNormal.Height();}
+	void ResetButtonSize(BOOL bResetSize);
+public:
+	afx_msg void OnEnable(BOOL bEnable);
+};
+

+ 202 - 0
source/hook/skinui/SkinEdit.cpp

@@ -0,0 +1,202 @@
+/************************************************************************ 
+* 程序名:    精仿QQ主界面 
+* 制作人:    李克平, 2011年04月11日
+* 版本号:    1.0 
+************************************************************************/ 
+// SkinEdit.cpp : 实现文件
+//
+
+#include "stdafx.h"
+#include "SkinEdit.h"
+
+
+// CSkinEdit
+
+IMPLEMENT_DYNAMIC(CSkinEdit, CEdit)
+
+CSkinEdit::CSkinEdit()
+{
+
+}
+
+CSkinEdit::~CSkinEdit()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CSkinEdit, CEdit)
+	ON_WM_PAINT()
+	ON_WM_NCCALCSIZE()
+	ON_WM_NCLBUTTONDOWN()
+	ON_WM_MOUSEMOVE()
+	ON_WM_SETFOCUS()
+	ON_WM_KILLFOCUS()
+	ON_WM_NCHITTEST()
+END_MESSAGE_MAP()
+
+
+void CSkinEdit::OnPaint()
+{
+	CPaintDC dc(this); // device context for painting
+	CRect rcClient;
+	GetClientRect(&rcClient);
+	rcClient.left -= 15;
+	rcClient.right += 33;
+	rcClient.top -= 5;
+	rcClient.bottom += 5;
+
+	if (m_bmpEdit.m_hObject !=0)
+		m_bmpEdit.ExtendDraw(&dc,rcClient,m_nX,m_nY); 
+
+	CRect rc=rcClient;
+	rc.left = 0;
+	CString strText;
+	GetWindowText(strText);
+	DrawText(&dc,rc,strText);
+}
+
+
+// CSkinEdit 消息处理程序
+void CSkinEdit::LoadBitmap(LPCTSTR szImagePath)
+{
+	m_bmpEdit.LoadImage(szImagePath); 
+}
+
+void CSkinEdit::SetText(CString strText, int nStart,COLORREF cr)
+{
+	m_strText=strText;
+	m_nTextStart=nStart;
+	m_crText=cr;
+	SetWindowText(strText);
+}
+
+
+BOOL CSkinEdit::DrawText(CDC *pDC,CRect rc ,CString strText)
+{
+	CRect r;
+	CString str;
+	CRect rcButton;
+	if (strText.GetLength() )
+	{
+		CFont *ofont;
+		ofont = pDC->SelectObject( GetParent()->GetFont() );
+
+		pDC->SetTextColor(m_crText);
+		pDC->SetBkMode(TRANSPARENT);
+		pDC->DrawText( strText, rc, DT_SINGLELINE | DT_VCENTER );
+		pDC->SelectObject(ofont);
+	}
+
+	return TRUE;
+}
+
+CRect CSkinEdit::GetRectInParent()
+{
+	CRect rcWindowParent;
+	GetParent()->GetWindowRect(rcWindowParent);//client
+	CRect rcWindow;
+	GetWindowRect(&rcWindow);
+	CRect rect;
+	rect.left = rcWindow.left-rcWindowParent.left;
+	rect.top = rcWindow.top-rcWindowParent.top;
+	rect.right = rcWindow.right-rcWindowParent.left;
+	rect.bottom = rcWindow.bottom-rcWindowParent.top;
+
+	return rect;
+}
+
+void CSkinEdit::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	lpncsp->rgrc->left += 15;
+	lpncsp->rgrc->right -= 33;
+	lpncsp->rgrc->top += 5;
+	lpncsp->rgrc->bottom -= 5;
+
+	CEdit::OnNcCalcSize(bCalcValidRects, lpncsp);
+}
+
+void CSkinEdit::OnNcLButtonDown(UINT nHitTest, CPoint point)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+
+	//POINT pt = {point.x,param.mousept.y};
+	SetWindowText(_T(""));
+	RECT rc;
+	GetWindowRect(&rc);
+
+	//rc.left = rc.right - 14;
+	//rc.right = rc.left + 8;
+
+	//if(PtInRect(&rc,point))
+	//{
+	//	if(m_rm)
+	//		m_rm->Popup(m_hWnd);
+	//}
+
+	CEdit::OnNcLButtonDown(nHitTest, point);
+}
+
+void CSkinEdit::OnMouseMove(UINT nFlags, CPoint point)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+
+	//CRect	rect;
+	//GetWindowRect(&rect);	
+	//if (!rect.PtInRect(point))
+	//{
+	//	ReleaseCapture();
+	//}
+	CEdit::OnMouseMove(nFlags, point);
+}
+
+void CSkinEdit::OnSetFocus(CWnd* pOldWnd)
+{
+	CEdit::OnSetFocus(pOldWnd);
+	CString str;
+	GetWindowText(str);
+	if(str == m_strText)
+	{
+		SetWindowText(_T(""));
+		//SetTextColor(RGB(0,0,0));
+	}
+	// TODO: 在此处添加消息处理程序代码
+}
+
+void CSkinEdit::OnKillFocus(CWnd* pNewWnd)
+{
+	CEdit::OnKillFocus(pNewWnd);
+	CString str;
+	GetWindowText(str);
+
+	if(str.IsEmpty())
+	{
+		SetWindowText(m_strText);
+	}
+	// TODO: 在此处添加消息处理程序代码
+}
+
+LRESULT CSkinEdit::OnNcHitTest(CPoint point)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	//LRESULT res = 0;
+	//if(res != HTCLIENT)
+	//	res = HTCAPTION;
+	//return res;
+	return CEdit::OnNcHitTest(point);
+}
+
+BOOL CSkinEdit::PreTranslateMessage(MSG* pMsg)
+{
+	// TODO: 在此添加专用代码和/或调用基类
+	if(pMsg->wParam == WM_LBUTTONDOWN && pMsg->hwnd != m_hWnd)
+	{
+		pMsg->wParam = HTCAPTION;
+	}
+	//if (pMsg->message == WM_LBUTTONDOWN && pMsg->hwnd == m_hWnd)
+	//{
+	//	pMsg->message = WM_NCLBUTTONDOWN;
+	//	pMsg->wParam = HTCAPTION;
+	//}
+	return CEdit::PreTranslateMessage(pMsg);
+}

+ 59 - 0
source/hook/skinui/SkinEdit.h

@@ -0,0 +1,59 @@
+/************************************************************************/
+/*  Copyright (C), 2016-2020, [IT], 保留所有权利;
+/*  模 块 名:;
+/*  描    述:;
+/*
+/*  版    本:[V];	
+/*  作    者:[IT];
+/*  日    期:[8/19/2016];
+/*
+/*
+/*  注    意:;
+/*
+/*  修改记录:[IT];
+/*  修改日期:;
+/*  修改版本:;
+/*  修改内容:;
+/************************************************************************/
+#pragma once
+
+
+// CSkinEdit
+#include "EnBitmap.h"
+class CSkinEdit : public CEdit
+{
+	DECLARE_DYNAMIC(CSkinEdit)
+
+public:
+	CSkinEdit();
+	virtual ~CSkinEdit();
+
+	CEnBitmap m_bmpEdit;
+	CString m_strText,m_strSearchTip;
+	int m_nTextStart;
+	COLORREF m_crText;
+
+	void SetText(CString strText,int nStart,COLORREF cr);
+	void SetExtendPoint(int nX,int nY){m_nX=nX;m_nY=nY;}
+	BOOL DrawText(CDC *pDC,CRect rc ,CString strText);
+
+	void LoadBitmap(LPCTSTR szImagePath);
+	int	 Width(){return m_bmpEdit.GetWidth();}
+	int	 Height(){return m_bmpEdit.GetHeight();}
+	CRect GetRectInParent();
+
+protected:
+	int m_nX,m_nY;
+	DECLARE_MESSAGE_MAP()
+public:
+	afx_msg void OnPaint();
+	afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp);
+	afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point);
+	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+	afx_msg void OnSetFocus(CWnd* pOldWnd);
+	afx_msg void OnKillFocus(CWnd* pNewWnd);
+	afx_msg LRESULT OnNcHitTest(CPoint point);
+	virtual BOOL PreTranslateMessage(MSG* pMsg);
+};
+
+

+ 124 - 0
source/hook/skinui/SkinStatic.cpp

@@ -0,0 +1,124 @@
+
+#include "stdafx.h"
+#include "SkinStatic.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CSkinStatic
+
+CSkinStatic::CSkinStatic()
+{
+	m_nX=0;
+	m_nY=0;
+	m_strText="";
+	m_pFont = NULL;
+	//m_pFont.CreateFont(
+	//	15,                        // nHeight
+	//	0,                         // nWidth
+	//	0,                         // nEscapement
+	//	0,                         // nOrientation
+	//	FW_BOLD,                 // nWeight
+	//	FALSE,                     // bItalic
+	//	FALSE,                     // bUnderline
+	//	0,                         // cStrikeOut
+	//	ANSI_CHARSET,              // nCharSet
+	//	OUT_DEFAULT_PRECIS,        // nOutPrecision
+	//	CLIP_DEFAULT_PRECIS,       // nClipPrecision
+	//	DEFAULT_QUALITY,           // nQuality
+	//	DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
+	//	_T("Arial"));                 // lpszFacename
+}
+
+CSkinStatic::~CSkinStatic()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CSkinStatic, CStatic)
+	//{{AFX_MSG_MAP(CSkinStatic)
+	ON_WM_PAINT()
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CSkinStatic message handlers
+void CSkinStatic::LoadBitmap(LPCTSTR szImagePath)
+{
+	m_bmpStatic.LoadImage(szImagePath); 
+}
+
+void CSkinStatic::OnPaint() 
+{
+	CPaintDC dc(this); // device context for painting
+	CRect rcClient;
+	GetClientRect(&rcClient);
+	if (m_bmpStatic.m_hObject !=0)
+		m_bmpStatic.ExtendDraw(&dc,rcClient,m_nX,m_nY); 
+
+	CRect rc = rcClient;
+	rc.left = m_nTextStart;
+	DrawText(&dc, rc, m_strText);
+}
+
+BOOL CSkinStatic::OnCommand(WPARAM wParam, LPARAM lParam) 
+{
+	GetParent()->SendMessage(WM_COMMAND,wParam,lParam); 	
+	return CStatic::OnCommand(wParam, lParam);
+}
+
+void CSkinStatic::SetText(CString strText, int nStart, COLORREF cr)
+{
+	m_strText = strText;
+	m_nTextStart = nStart;
+	m_crText = cr;
+	Invalidate();
+}
+
+BOOL CSkinStatic::DrawText(CDC *pDC,CRect rc ,CString strText)
+{
+	CRect r;
+	CString str;
+	CRect rcButton;
+	if (strText.GetLength() )
+	{
+		if(m_pFont == NULL)
+			m_pFont = GetParent()->GetFont();
+
+		pDC->SelectObject(m_pFont);
+		pDC->SetTextColor(m_crText);
+		pDC->SetBkMode(TRANSPARENT);
+		pDC->DrawText( strText, rc, DT_SINGLELINE | DT_VCENTER );
+	}
+
+	return TRUE;
+}
+
+void CSkinStatic::Redraw(CDC *pDC)
+{
+	CRect rc = GetRectInParent();
+	if (m_bmpStatic.m_hObject !=0)
+		m_bmpStatic.ExtendDraw(pDC,rc,m_nX,m_nY); 
+	CRect rcText = rc;
+	rcText.left += m_nTextStart;
+	DrawText(pDC,rcText,m_strText);
+}
+
+CRect CSkinStatic::GetRectInParent()
+{
+	CRect rcWindowParent;
+	GetParent()->GetWindowRect(rcWindowParent);//client
+	CRect rcWindow;
+	GetWindowRect(&rcWindow);
+	CRect rect;
+	rect.left = rcWindow.left-rcWindowParent.left;
+	rect.top = rcWindow.top-rcWindowParent.top;
+	rect.right = rcWindow.right-rcWindowParent.left;
+	rect.bottom = rcWindow.bottom-rcWindowParent.top;
+
+	return rect;
+}

+ 69 - 0
source/hook/skinui/SkinStatic.h

@@ -0,0 +1,69 @@
+/************************************************************************/
+/*  Copyright (C), 2016-2020, [IT], 保留所有权利;
+/*  模 块 名:;
+/*  描    述:;
+/*
+/*  版    本:[V];	
+/*  作    者:[IT];
+/*  日    期:[8/19/2016];
+/*
+/*
+/*  注    意:;
+/*
+/*  修改记录:[IT];
+/*  修改日期:;
+/*  修改版本:;
+/*  修改内容:;
+/************************************************************************/
+#ifndef __SKIN_STATIC_20160824__
+#define __SKIN_STATIC_20160824__
+
+#include "EnBitmap.h"	// Added by ClassView
+#pragma once
+
+class CSkinStatic : public CStatic
+{
+public:
+	CSkinStatic();
+	virtual ~CSkinStatic();
+protected:
+	virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
+
+public:
+	void	SetText(CString strText,int nStart = 0,COLORREF cr = RGB(0,0,0));
+	void	SetExtendPoint(int nX,int nY)
+	{
+		m_nX=nX;
+		m_nY=nY;
+	}
+
+	void	SetFont(CFont *pFont){m_pFont = pFont;}
+	BOOL	DrawText(CDC *pDC,CRect rc ,CString strText);
+	void	Redraw(CDC *pDC);
+	
+	void	LoadBitmap(LPCTSTR szImagePath);
+	int		Width()
+	{
+		return m_bmpStatic.GetWidth();
+	}
+
+	int		Height()
+	{
+		return m_bmpStatic.GetHeight();
+	}
+	CRect	GetRectInParent();
+
+	CEnBitmap	m_bmpStatic;
+	CString		m_strText;
+	CFont		*m_pFont;
+	int			m_nTextStart;
+	COLORREF	m_crText;
+
+protected:
+	int			m_nX;
+	int			m_nY;
+	afx_msg void OnPaint();
+	DECLARE_MESSAGE_MAP()
+};
+
+#endif // __SKIN_STATIC_20160824__

+ 330 - 0
source/hook/skinui/SkinTab.cpp

@@ -0,0 +1,330 @@
+// BmpTab.cpp : implementation file
+
+#include "stdafx.h"
+#include "SkinTab.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+#define IDC_CURSOR_HAND                 132
+
+/////////////////////////////////////////////////////////////////////////////
+// CSkinTab
+
+CSkinTab::CSkinTab()
+{
+	m_bIsCDC=FALSE;
+	m_dwState=HTNORMAL;
+	m_hIconHand=AfxGetApp()->LoadCursor(IDC_CURSOR_HAND);
+	m_iCurrentSelect=1;
+	m_iCurrentFouce=-1;
+}
+
+CSkinTab::~CSkinTab()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CSkinTab, CStatic)
+	//{{AFX_MSG_MAP(CSkinTab)
+	ON_WM_PAINT()
+	ON_WM_LBUTTONDOWN()
+	ON_WM_ERASEBKGND()
+	ON_WM_MOUSEMOVE()
+	ON_WM_TIMER()
+	ON_WM_SETCURSOR()
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CSkinTab message handlers
+
+void CSkinTab::PreSubclassWindow() 
+{
+	// TODO: Add your specialized code here and/or call the base class
+	ModifyStyle(0,SS_NOTIFY);
+	CStatic::PreSubclassWindow();
+}
+
+void CSkinTab::OnPaint()
+{
+	CPaintDC dc(this);
+	CRect rc;GetClientRect(&rc);
+
+	CDC memDC;memDC.CreateCompatibleDC(&dc);
+	CBitmap bmpBack;bmpBack.CreateCompatibleBitmap(&dc,rc.Width(),rc.Height());
+	CBitmap *bmpOld=memDC.SelectObject(&bmpBack);
+
+	memDC.BitBlt(0,0,rc.Width(),rc.Height(),&m_memDC,0,0,SRCCOPY);
+	if(m_bmpBG.m_hObject != NULL)
+		m_bmpBG.ExtendDraw(&memDC,rc,10,50);
+
+	CRect rcItem;
+	TABITEM* tabItem;
+	for(int i=0;i<m_aryItem.GetSize();i++)
+	{
+		CDC tmpDC;tmpDC.CreateCompatibleDC(&dc);
+		
+		tabItem=(TABITEM*)m_aryItem.GetAt(i);
+// 		if(tabItem->pVoid)
+// 			((CWnd*)(tabItem->pVoid))->ShowWindow(SW_HIDE);
+
+		GetTabItemRect(i,&rcItem);
+
+		bmpOld=tmpDC.SelectObject(&m_bmpNormal);
+
+		if(m_iCurrentFouce==i)
+		{
+			bmpOld=tmpDC.SelectObject(&m_bmpHover);
+		}
+		if(m_iCurrentSelect==i)
+		{
+			bmpOld=tmpDC.SelectObject(&m_bmpHdown);
+// 			if(tabItem->pVoid)
+// 			((CWnd*)(tabItem->pVoid))->ShowWindow(SW_NORMAL);
+		}
+
+		memDC.BitBlt(rcItem.left+1,rcItem.top,rcItem.Width(),rcItem.Height(),&tmpDC,0,0,SRCCOPY);
+
+		tmpDC.SelectObject(bmpOld);
+		ReleaseDC(&tmpDC);
+		tmpDC.DeleteDC();
+
+		::DrawIconEx(memDC,rcItem.left+8,rcItem.top+3,tabItem->icon,24,24,0,NULL,DI_NORMAL);
+	}
+
+	dc.BitBlt(0,0,rc.Width(),rc.Height(),&memDC,0,0,SRCCOPY);
+	memDC.DeleteDC();
+
+//	CStatic::OnPaint();
+}
+
+void CSkinTab::OnLButtonDown(UINT nFlags, CPoint point) 
+{
+	// TODO: Add your message handler code here and/or call default
+//	AfxMessageBox("dd");
+	//m_dwState=HTHDOWN;
+	CRect rcItem;
+	for(int i=0;i<m_aryItem.GetSize();i++)
+	{
+		CWnd *tabItemView;
+		tabItemView=(CWnd*)((TABITEM*)m_aryItem.GetAt(i))->pVoid;
+		CRect recTab(0,0,Width(),Heighth());
+		if(tabItemView && recTab.PtInRect(point))
+			tabItemView->ShowWindow(SW_HIDE);
+
+		GetTabItemRect(i,&rcItem);
+		if(rcItem.PtInRect(point))
+		{
+			m_iCurrentSelect=i;
+			if((m_aryItem.GetAt(i))!=NULL)
+			{
+				if(tabItemView)
+					tabItemView->ShowWindow(SW_NORMAL);
+			}
+		}
+		
+	}
+	Invalidate();
+	CStatic::OnLButtonDown(nFlags, point);
+}
+
+BOOL CSkinTab::OnEraseBkgnd(CDC* pDC) 
+{
+	// TODO: Add your message handler code here and/or call default
+	if(!m_bIsCDC)
+	{
+		m_memDC.CreateCompatibleDC(pDC);
+		CRect rc;GetClientRect(&rc);
+		CBitmap bmpBack;bmpBack.CreateCompatibleBitmap(pDC,rc.Width(),rc.Height());
+		m_memDC.SelectObject(&bmpBack);
+		
+		m_memDC.BitBlt(0,0,rc.Width(),rc.Height(),pDC,0,0,SRCCOPY);
+		//	m_memDC.SelectObject(bmpOld);
+		//	bmpOld->DeleteObject();
+		m_bIsCDC=TRUE;
+		bmpBack.DeleteObject();
+	
+	}
+	return TRUE;
+	//return CStatic::OnEraseBkgnd(pDC);
+}
+
+void CSkinTab::SetIcon(int nIndex,UINT nIcon,void *pVoid)
+{
+	TABITEM* tabItem=new TABITEM;
+	tabItem->nIndex=nIndex;
+	tabItem->icon=AfxGetApp()->LoadIcon(nIcon);
+	tabItem->pVoid=pVoid;
+
+	m_aryItem.Add(tabItem);
+}
+
+void CSkinTab::SetIcon(int nIndex,LPCTSTR szIcon,void *pVoid)
+{
+	TABITEM* tabItem=new TABITEM;
+	tabItem->nIndex=nIndex;
+	tabItem->icon=(HICON)::LoadImage(AfxGetApp()->m_hInstance,szIcon,IMAGE_ICON,24,24,LR_LOADFROMFILE);
+	tabItem->pVoid=pVoid;
+
+	m_aryItem.Add(tabItem);
+}
+
+void CSkinTab::SetBmp(UINT nBmpNormal, UINT nBmpHover, UINT nBmpHdown)
+{
+	m_bmpNormal.LoadBitmap(nBmpNormal);
+	m_bmpHover.LoadBitmap(nBmpHover);
+	m_bmpHdown.LoadBitmap(nBmpHdown);
+}
+
+void CSkinTab::SetSkin(CString strNormal, CString strHover, CString strDown)
+{
+	m_bmpNormal.LoadImage(strNormal);
+	m_bmpHover.LoadImage(strHover);
+	m_bmpHdown.LoadImage(strDown);
+}
+
+void CSkinTab::SetSkin(CString strBmpTab)
+{
+	CEnBitmap bmp;
+	bmp.LoadImage(strBmpTab);
+
+	if(bmp.m_hObject != NULL)
+	{
+		bmp.DrawImage(m_bmpNormal,1,1,3,1);
+		bmp.DrawImage(m_bmpHover,2,1,3,1);
+		bmp.DrawImage(m_bmpHdown,3,1,3,1);
+	}
+	if(bmp.m_hObject != NULL) bmp.DeleteObject();
+}
+
+void CSkinTab::SetSkinBG(CString strBmpBG)
+{
+	m_bmpBG.LoadImage(strBmpBG);
+}
+
+void CSkinTab::AddTabItem(TABITEM &item)
+{
+	//m_aryItem.Add(&item);
+}
+
+void CSkinTab::AddTabItem(UINT nBmpNormal, UINT nBmpHover, UINT nBmpHdown, UINT nIcon, void *pVoid)
+{
+	//if(m_aryItem.GetSize()==0)
+// 	CBitmap bmpNormal,bmpHover,bmpHdown;
+// 	HICON icon;
+// // 	bmpNormal.LoadBitmap(nBmpNormal);
+// // 	bmpHover.LoadBitmap(nBmpHover);
+// // 	bmpHdown.LoadBitmap(nBmpHdown);
+// 	icon=AfxGetApp()->LoadIcon(nIcon);
+// 
+// 	TABITEM* tabitm=new TABITEM;
+// //	tabitm.rcItem=rc;
+// 	tabitm->bmpNormal.LoadBitmap(nBmpNormal);
+// 	tabitm->bmpHover.LoadBitmap(nBmpHover);
+// 	tabitm->bmpHdown.LoadBitmap(nBmpHdown);
+// 	tabitm->icon=icon;
+// 	tabitm->pVoid=NULL;
+// 	
+// 	m_aryItem.Add((void*)tabitm);
+}
+
+void CSkinTab::OnMouseMove(UINT nFlags, CPoint point) 
+{
+	// TODO: Add your message handler code here and/or call default
+	//AfxMessageBox("dd");
+//	m_dwState=HTHOVER;
+// 	CRect rc;
+// 	BOOL IsTrue=FALSE;
+// 	for(int i=0;i<m_aryItem.GetSize();i++)
+// 	{
+// 		GetTabItemRect(i,&rc);
+// 		if(rc.PtInRect(point))
+// 		{
+// 			m_iCurrentFouce=i;
+// 			IsTrue=TRUE;
+// 		}
+// 	}
+// 	if(!IsTrue)
+// 		m_iCurrentFouce=-1;
+	CRect rcItem(0,0,Width(),Heighth());
+	if(rcItem.PtInRect(point))
+	{
+		SetTimer(1,10,NULL);
+		Invalidate();
+	}
+	CStatic::OnMouseMove(nFlags, point);
+}
+
+void CSkinTab::OnTimer(UINT nIDEvent) 
+{
+	// TODO: Add your message handler code here and/or call default
+	CPoint pt(GetMessagePos());
+	ScreenToClient(&pt);
+	CRect rc;
+	
+	BOOL bIsOK=FALSE;
+
+	for (int i=0;i<m_aryItem.GetSize();i++)
+	{
+		GetTabItemRect(i,&rc);
+		if(rc.PtInRect(pt))
+		{
+			m_iCurrentFouce=i;
+			bIsOK=TRUE;
+		}
+	}
+	
+	if (!bIsOK)
+	{
+		m_iCurrentFouce=-1;
+			KillTimer(1);
+	}
+
+	Invalidate();
+// 	if(rc.PtInRect(pt))
+// 	{
+// 		m_dwState=HTHOVER;
+// 	}
+// 	else
+// 	{
+// 		m_dwState=HTNORMAL;
+// 	
+// 		
+// 	}
+// 	
+	CStatic::OnTimer(nIDEvent);
+}
+
+BOOL CSkinTab::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
+{
+	// TODO: Add your message handler code here and/or call default
+ 	CPoint pt(GetMessagePos());
+	ScreenToClient(&pt);
+
+	CRect rcItem(0,0,Width(),Heighth());
+ 	if(rcItem.PtInRect(pt))
+ 	{
+		::SetCursor(m_hIconHand);
+		return TRUE;
+	}
+	return CStatic::OnSetCursor(pWnd, nHitTest, message);
+}
+
+void CSkinTab::GetTabItemRect(int nIndex, CRect *rc)
+{
+// 	if(m_bmpNormal.GetSafeHandle())
+// 	{
+		BITMAP bm;
+		m_bmpNormal.GetBitmap(&bm);
+		
+		rc->SetRect(0,nIndex*bm.bmHeight,bm.bmWidth,nIndex*bm.bmHeight+bm.bmHeight);
+// 	}
+// 	else
+// 	{
+// 		rc->SetRect(0,0,0,0);
+// 	}
+}

+ 107 - 0
source/hook/skinui/SkinTab.h

@@ -0,0 +1,107 @@
+/************************************************************************/
+/*  Copyright (C), 2016-2020, [IT], 保留所有权利;
+/*  模 块 名:;
+/*  描    述:;
+/*
+/*  版    本:[V];	
+/*  作    者:[IT];
+/*  日    期:[8/19/2016];
+/*
+/*
+/*  注    意:;
+/*
+/*  修改记录:[IT];
+/*  修改日期:;
+/*  修改版本:;
+/*  修改内容:;
+/************************************************************************/
+#if !defined(AFX_BMPTAB_H__7DCB7FED_B1D0_46B0_852D_9E7B6F93D59B__INCLUDED_)
+#define AFX_BMPTAB_H__7DCB7FED_B1D0_46B0_852D_9E7B6F93D59B__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+// BmpTab.h : header file
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// CSkinTab window
+#include <afxtempl.h>
+#include <afxcoll.h>
+#include "EnBitmap.h"
+class CSkinTab : public CStatic
+{
+// Construction
+public:
+	CSkinTab();
+public:
+typedef	struct  tabitem
+	{
+		int		nIndex;
+		HICON	icon;
+		void	*pVoid;
+	}TABITEM,*PTABITEM;
+// Attributes
+public:
+
+// Operations
+public:
+		CDC	m_memDC;
+		CPtrArray	m_aryItem;
+		HICON	m_hIconHand;
+		BOOL	m_bIsCDC;
+		DWORD	m_dwState;
+		CEnBitmap m_bmpBG;
+		CEnBitmap m_bmpNormal;
+		CEnBitmap m_bmpHover;
+		CEnBitmap m_bmpHdown;
+
+		int		m_iCurrentSelect;
+		int		m_iCurrentFouce;
+		enum{
+			HTNORMAL	=0x0001,
+			HTHOVER		=0x0002,
+			HTHDOWN		=0x0003
+		};
+// Overrides
+	// ClassWizard generated virtual function overrides
+	//{{AFX_VIRTUAL(CSkinTab)
+	public:
+	protected:
+	virtual void PreSubclassWindow();
+	//}}AFX_VIRTUAL
+
+// Implementation
+public:
+	void GetTabItemRect(int nIndex,CRect *rc);
+	void AddTabItem(TABITEM &item);
+	void SetBmp(UINT nBmpNormal, UINT nBmpHover, UINT nBmpHdown);
+	void SetSkin(CString strNormal, CString strHover, CString strDown);
+	void SetSkin(CString strBmp);
+	void SetSkinBG(CString strBmpBG);
+	void SetIcon(int nIndex,UINT nIcon,void *pVoid);
+	void SetIcon(int nIndex,LPCTSTR szIcon,void *pVoid);
+	void AddTabItem(UINT nBmpNormal, UINT nBmpHover, UINT nBmpHdown, UINT nIcon, void *pVoid);
+	virtual ~CSkinTab();
+	int Width(){return 35;}
+	int Heighth(){return m_aryItem.GetSize()*35;}
+	// Generated message map functions
+protected:
+	//{{AFX_MSG(CSkinTab)
+	afx_msg void OnPaint();
+	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
+	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
+	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+	afx_msg void OnTimer(UINT nIDEvent);
+	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+	//}}AFX_MSG
+
+	DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_BMPTAB_H__7DCB7FED_B1D0_46B0_852D_9E7B6F93D59B__INCLUDED_)

+ 103 - 0
source/hook/skinui/SkinWin.cpp

@@ -0,0 +1,103 @@
+/************************************************************************ 
+* 程序名:    精仿QQ主界面 
+* 制作人:    李克平, 2011年04月11日
+* 版本号:    1.0 
+************************************************************************/ 
+
+#include "stdafx.h"
+
+#include "SkinWin.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[]=__FILE__;
+#define new DEBUG_NEW
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CSkinWin::CSkinWin()
+{
+}
+
+CSkinWin::~CSkinWin()
+{
+
+}
+
+BOOL CSkinWin::InstallSkin(CWnd *wnd)
+{
+	if ( !wnd ) return FALSE;
+	HookWindow( (HWND)NULL);
+	int r = HookWindow( wnd );
+
+	DWORD style = GetWindowLong( m_hWnd, GWL_STYLE );
+	style &= ~(WS_MINIMIZEBOX);
+	style &= ~WS_MAXIMIZEBOX;
+	style &= ~WS_SYSMENU;
+	SetWindowLong( m_hWnd, GWL_STYLE, style );
+	return r;
+}
+
+LRESULT CSkinWin::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
+{
+	if ( !IsWindow(m_hWnd) )
+		return 0;
+
+	switch ( msg )
+	{
+	case WM_NCHITTEST:
+		{
+			Default();
+			return OnNcHitTest(CPoint(LOWORD(lp), HIWORD(lp)));
+		}
+	default:
+		return Default();
+	}
+}
+
+UINT CSkinWin::OnNcHitTest(CPoint point)
+{
+	static int m_TitleHeight = 5;
+	static int m_BorderLeftWidth = 5;
+	static int m_BorderRightWidth=5;
+	static int m_BorderBottomHeight = 5;
+	CWnd *pWnd = CWnd::FromHandle(m_hWnd);
+	CRect wr;
+	pWnd->GetWindowRect(wr);
+
+	point.x -= wr.left;
+	point.y -= wr.top;
+
+	CRect rc;
+	int cx = GetSystemMetrics(SM_CXSMICON);
+	int cy = GetSystemMetrics(SM_CYSMICON);
+
+	rc = CRect( 0, 0, m_BorderLeftWidth, m_TitleHeight );
+	if ( PtInRect( rc, point ))  //!IsZoomed(m_hWnd) )
+		return HTTOPLEFT;
+	rc = CRect( wr.Width() - m_BorderLeftWidth, 0,  wr.Width(), m_TitleHeight  );
+	if ( PtInRect( rc, point ) )  //!IsZoomed(m_hWnd) )
+		return HTTOPRIGHT;
+	rc = CRect( 0, wr.Height() - m_BorderBottomHeight, m_BorderLeftWidth, wr.Height() );
+	if ( PtInRect( rc, point ) )  //!IsZoomed(m_hWnd) )
+		return HTBOTTOMLEFT;
+	rc = CRect( wr.Width()-m_BorderRightWidth, wr.Height() - m_BorderBottomHeight,  wr.Width(), wr.Height() );
+	if ( PtInRect( rc, point ))  //!IsZoomed(m_hWnd) )
+		return HTBOTTOMRIGHT;
+	rc = CRect( 0, m_TitleHeight,  m_BorderLeftWidth, wr.Height() - m_BorderBottomHeight  );
+	if ( PtInRect( rc, point ))  //!IsZoomed(m_hWnd) )
+		return HTLEFT;
+	rc = CRect( wr.Width()-m_BorderRightWidth, m_TitleHeight,  wr.Width(), wr.Height() - m_BorderBottomHeight  );
+	if ( PtInRect( rc, point ) )  //!IsZoomed(m_hWnd) )
+		return HTRIGHT;
+	rc = CRect( m_BorderLeftWidth, wr.Height() - m_BorderBottomHeight,  wr.Width()-m_BorderRightWidth, wr.Height() );
+	if ( PtInRect( rc, point ) )  //!IsZoomed(m_hWnd) )
+		return HTBOTTOM;
+	rc = CRect( m_BorderLeftWidth, 0,  wr.Width()-m_BorderRightWidth, m_BorderBottomHeight );
+	if ( PtInRect( rc, point ))  //!IsZoomed(m_hWnd) )
+		return HTTOP;	
+	return HTCLIENT;
+}

+ 49 - 0
source/hook/skinui/SkinWin.h

@@ -0,0 +1,49 @@
+/************************************************************************/
+/*  Copyright (C), 2016-2020, [IT], 保留所有权利;
+/*  模 块 名:;
+/*  描    述:;
+/*
+/*  版    本:[V];	
+/*  作    者:[IT];
+/*  日    期:[8/19/2016];
+/*
+/*
+/*  注    意:;
+/*
+/*  修改记录:[IT];
+/*  修改日期:;
+/*  修改版本:;
+/*  修改内容:;
+/************************************************************************/
+
+#if !defined(AFX_SKINWIN_H__F010D322_E34F_4F9E_87E8_E76E9611942D__INCLUDED_)
+#define AFX_SKINWIN_H__F010D322_E34F_4F9E_87E8_E76E9611942D__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "Subclass.h"
+class CSkinWin  : public CSubclassWnd
+{
+	//public:
+	//	int			m_TitleHeight;
+	//	int			m_BorderLeftWidth;
+	//	int			m_BorderRightWidth;
+	//	int			m_BorderBottomHeight;
+public:
+	BOOL InstallSkin( CWnd * wnd );
+	CSkinWin();
+	CSkinWin( const char * skinfile )
+	{
+		CSkinWin();			
+	}
+	virtual ~CSkinWin();
+
+	//skinfile:	full path name to skin inifile
+	//vitrual functions
+	virtual LRESULT WindowProc(UINT msg, WPARAM wp, LPARAM lp);
+	UINT OnNcHitTest(CPoint point);
+};
+
+#endif // !defined(AFX_SKINWIN_H__F010D322_E34F_4F9E_87E8_E76E9611942D__INCLUDED_)

+ 1364 - 0
source/hook/skinui/SubLabel.cpp

@@ -0,0 +1,1364 @@
+// Label.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "SubLabel.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+BEGIN_MESSAGE_MAP(CLabel, CStatic)
+	//{{AFX_MSG_MAP(CLabel)
+	ON_WM_TIMER()
+	ON_WM_LBUTTONDOWN()
+	ON_WM_SETCURSOR()
+	ON_WM_SYSCOLORCHANGE()
+	ON_WM_PAINT()
+	ON_WM_ERASEBKGND()
+	//}}AFX_MSG_MAP
+	ON_WM_CTLCOLOR_REFLECT()
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CLabel Version 1.2
+//
+// From now on I'll try to keep a log of fixes and enhancements...
+// 
+// The new feature were added due to the response of people.
+// All I ask is to all you programmers out there, is if you add, fix or
+// enhance this code, sent me a copy and I'll send the copy on to www.codeproject.com
+//
+// Happy Software Engineer :)
+// 
+// New features include:
+//
+// A. Support for 3D Fonts
+// B. Support for background transparency
+// C. More comments provided
+// D. If alignment is 'centered' and the window text is seperated by '\r\n'
+//	  the will be centered accordingly - requested by someone @ nasa ;)
+// E. Support for font rotation.
+// F. Respond to System Color Change
+// G. OnPaint improved performance - using Double Buffering Technique
+//
+// Thanks to:
+// Mark McDowell	- For suggestion on 'Increasing the flexibility of "hypertext" setting...'
+// Erich Ruth		- For suggestion on 'Font Rotation'
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// CLabel Version 1.3
+//
+// A. Added SS_LEFTNOWORDWRAP to include wordwrap
+// B. Fix repainting problem 
+// C. Fix SetBkColor
+// D. Added SS_CENTER
+
+// Thanks to:
+// Marius						- Added styling problem.
+// Azing Vondeling & Broker		- Spotting painting Problem.
+// Mel Stober					- Back Color & SS_CENTER
+// 
+/////////////////////////////////////////////////////////////////////////////
+// CLabel Version 1.4
+//
+// A. Fix to transparency mode
+// B. Added new SetText3DHiliteColor to change the 3D Font face color - default is white.
+// 
+// Thanks to:
+// michael.groeger				- Spotting Transparency with other controls bug.
+//
+//
+/////////////////////////////////////////////////////////////////////////////
+// CLabel Version 1.5
+//
+// A. Sanity handle check
+// B. Support Interface Charset
+// C. Check compilition with _UNICODE
+// D. Fix hyperlink feature
+// E. Support default Dialog Font
+// F. Inclusion of SS_OWNERDRAW via control creation and subclassing
+// G. Modification to Text aligmnent code
+// H. New background gradient fill function
+// 
+// Thanks to:
+// Steve Kowald				- Using null handles 
+// Alan Chan				- Supporting International Windows
+// Dieter Fauth				- Request for default Dialog font
+// Herb Illfelder			- Text Alignment code
+// 
+/////////////////////////////////////////////////////////////////////////////
+// CLabel Version 1.6
+// Jeroen Roosendaal		- SetFont suggestion
+// Laurent					- Spotting SelectObject bugs
+// Bernie					- Fix PreCreateWindow bug
+// Jignesh I. Patel			- Added expanded tabs feature
+// Jim Farmelant 			- Fix SetText crash
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::CLabel
+//
+// Description:		Default contructor
+//
+// INPUTS:          
+// 
+// RETURNS:         
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel::CLabel()
+{
+	m_crText = GetSysColor(COLOR_WINDOWTEXT);
+
+	// 1.1
+	m_hBackBrush = NULL;
+
+
+	m_crHiColor =		0;
+	m_crLoColor	=		0;
+
+	m_bTimer =			FALSE;
+	m_bState =			FALSE;
+	m_bTransparent =	FALSE;
+	m_Link =			LinkNone;
+	m_hCursor =			NULL;
+	m_Type =			None;
+	m_bFont3d =			FALSE;
+	m_bNotifyParent =	FALSE;
+	m_bToolTips =		FALSE;
+	m_bRotation =		FALSE;
+	m_fillmode =		Normal;
+	m_cr3DHiliteColor =	RGB(255,255,255);
+	m_strText =			_T("");
+	m_hwndBrush = ::CreateSolidBrush(GetSysColor(COLOR_3DFACE));
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::~CLabel
+//
+// Description:		
+//
+// INPUTS:          
+// 
+// RETURNS:         
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+// NT ALMOND				15092000	1.5		Handle Check
+//////////////////////////////////////////////////////////////////////////
+CLabel::~CLabel()
+{
+	// Clean up
+	m_font.DeleteObject();
+	::DeleteObject(m_hwndBrush);
+
+	// Stop Checking complaining
+	if (m_hBackBrush)
+		::DeleteObject(m_hBackBrush);
+
+}
+
+void CLabel::UpdateSurface()
+{
+	CRect (rc);
+	GetWindowRect(rc);
+	RedrawWindow();
+
+	GetParent()->ScreenToClient(rc);
+	GetParent()->InvalidateRect(rc,TRUE);
+	GetParent()->UpdateWindow();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::ReconstructFont
+//
+// Description:		Helper function to build font after it was changed
+//
+// INPUTS:          
+// 
+// RETURNS:         
+//
+// NOTES:			PROTECTED
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+void CLabel::ReconstructFont()
+{
+	m_font.DeleteObject();
+	BOOL bCreated = m_font.CreateFontIndirect(&m_lf);
+
+	ASSERT(bCreated);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::OnPaint
+//
+// Description:		Handles all the drawing code for the label
+//
+// INPUTS:          
+// 
+// RETURNS:         
+//
+// NOTES:			Called by Windows... not by USER
+//					Probably needs tiding up a some point.
+//					Different states will require this code to be reworked.
+//
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				22/10/98    1.0     Origin
+// NT ALMOND				15092000	1.5		Handle Check
+// NT ALMOND				15092000	1.5		Alignment mods
+// NT ALMOND				15092000	1.5		Gradient Fill Mode
+// NT ALMOND				02072002	1.6		Fill SelectObject bugs
+// NT ALMOND				02072002	1.6		Added to expand tabs
+//////////////////////////////////////////////////////////////////////////
+
+void CLabel::OnPaint() 
+{
+	CPaintDC dc(this); // device context for painting
+
+	DWORD dwFlags = 0;
+
+	CRect rc;
+	GetClientRect(rc);
+	if (m_strText.IsEmpty())
+		GetWindowText(m_strText);
+	CBitmap bmp;
+
+
+	///////////////////////////////////////////////////////
+	//
+	// Set up for double buffering...
+	//
+	CDC* pDCMem;
+	CBitmap*	pOldBitmap = NULL;
+
+	if (!m_bTransparent)
+	{
+		pDCMem = new CDC;
+		pDCMem->CreateCompatibleDC(&dc);
+		bmp.CreateCompatibleBitmap(&dc,rc.Width(),rc.Height());
+		pOldBitmap = pDCMem->SelectObject(&bmp);
+	}
+	else
+	{
+		pDCMem = &dc;
+	}
+
+	UINT nMode = pDCMem->SetBkMode(TRANSPARENT);
+
+
+	COLORREF crText = pDCMem->SetTextColor(m_crText);
+	CFont *pOldFont = pDCMem->SelectObject(&m_font);
+
+
+	// Fill in backgound if not transparent
+	if (!m_bTransparent)
+	{
+		if (m_fillmode == Normal)
+		{
+			CBrush br;
+
+			if (m_hBackBrush != NULL)
+				br.Attach(m_hBackBrush);
+			else
+				br.Attach(m_hwndBrush);
+
+			pDCMem->FillRect(rc,&br);
+
+			br.Detach();
+		}
+		else // Gradient Fill
+		{
+			DrawGradientFill(pDCMem, &rc, m_crLoColor, m_crHiColor, 100);
+		}
+
+	}
+
+
+	// If the text is flashing turn the text color on
+	// then to the color of the window background.
+
+	LOGBRUSH lb;
+	ZeroMemory(&lb,sizeof(lb));
+
+	// Stop Checking complaining
+	if (m_hBackBrush)
+		::GetObject(m_hBackBrush,sizeof(lb),&lb);
+
+
+	// Something to do with flashing
+	if (!m_bState && m_Type == Text)
+	{
+		//ZeroMemory(&lb,sizeof(lb));
+		lb.lbColor = RGB(255,0,255);
+		pDCMem->SetTextColor(lb.lbColor);
+	}
+
+	DWORD style = GetStyle();
+
+	switch (style & SS_TYPEMASK)
+	{
+	case SS_RIGHT: 
+		dwFlags = DT_RIGHT | DT_WORDBREAK; 
+		break; 
+
+	case SS_CENTER: 
+		dwFlags = SS_CENTER | DT_WORDBREAK;
+		break;
+
+	case SS_LEFTNOWORDWRAP: 
+		dwFlags = DT_LEFT; 
+		break;
+
+	default: // treat other types as left
+	case SS_LEFT: 
+		dwFlags = DT_LEFT | DT_WORDBREAK; 
+		break;
+	}	
+
+
+	// Added to expand tabs...
+	if(m_strText.Find(_T('\t')) != -1)
+		dwFlags |= DT_EXPANDTABS;
+
+	// If the text centered make an assumtion that
+	// the will want to center verticly as well
+	if (style & SS_CENTERIMAGE)
+	{
+		dwFlags = DT_CENTER;
+
+		// Apply 
+		if (m_strText.Find(_T("\r\n")) == -1)
+		{
+			dwFlags |= DT_VCENTER;
+
+			// And because DT_VCENTER only works with single lines
+			dwFlags |= DT_SINGLELINE; 
+		}
+
+	}
+
+	//
+	// 3333   DDDDD
+	//     3  D    D
+	//   33   D     D    E F X 
+	//     3  D    D
+	// 3333   DDDDD
+	//
+	//
+	if (m_bRotation)
+	{
+		int nAlign = pDCMem->SetTextAlign (TA_BASELINE);
+
+		CPoint pt;
+		GetViewportOrgEx (pDCMem->m_hDC,&pt) ;
+		SetViewportOrgEx (pDCMem->m_hDC,rc.Width() / 2, rc.Height() / 2, NULL) ;
+		pDCMem->TextOut(0, 0, m_strText);
+		SetViewportOrgEx (pDCMem->m_hDC,pt.x / 2, pt.y / 2, NULL) ;
+		pDCMem->SetTextAlign (nAlign);
+	}
+	else
+	{
+		pDCMem->DrawText(m_strText, rc, dwFlags);
+		if (m_bFont3d)
+		{
+			pDCMem->SetTextColor(m_cr3DHiliteColor);
+
+			if (m_3dType == Raised)
+				rc.OffsetRect(-1,-1);
+			else
+				rc.OffsetRect(1,1);
+
+			pDCMem->DrawText(m_strText, rc, dwFlags);
+			m_3dType;
+
+		}
+	}
+
+	// Restore DC's State
+	pDCMem->SetBkMode(nMode);
+	pDCMem->SelectObject(pOldFont);
+	pDCMem->SetTextColor(crText);
+
+	if (!m_bTransparent)
+	{
+		dc.BitBlt(0, 0, rc.Width(), rc.Height(), pDCMem, 0, 0, SRCCOPY);
+		// continue DC restore 
+		pDCMem->SelectObject ( pOldBitmap ) ;
+		delete pDCMem;
+	}
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::OnTimer
+//
+// Description:		Used in conjunction with 'FLASH' functions
+//
+// INPUTS:          Windows API
+// 
+// RETURNS:         Windows API
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+void CLabel::OnTimer(UINT nIDEvent) 
+{
+
+	m_bState = !m_bState;
+
+	UpdateSurface();
+
+	CStatic::OnTimer(nIDEvent);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::OnSetCursor
+//
+// Description:		Used in conjunction with 'LINK' function
+//
+// INPUTS:          Windows API
+// 
+// RETURNS:         Windows API
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+BOOL CLabel::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
+{
+
+	if (m_hCursor)
+	{
+		::SetCursor(m_hCursor);
+		return TRUE;
+	}
+
+	return CStatic::OnSetCursor(pWnd, nHitTest, message);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::OnLButtonDown
+//
+// Description:		Called when a link is click on
+//
+// INPUTS:          Windows API
+// 
+// RETURNS:         Windows API
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+// NT ALMOND				02072002    1.6     Added Mail support
+//////////////////////////////////////////////////////////////////////////
+void CLabel::OnLButtonDown(UINT nFlags, CPoint point) 
+{
+
+	if (!m_bNotifyParent) // Fix
+	{
+		CString strLink;
+
+		GetWindowText(strLink);
+		if (m_Link == HyperLink)
+		{
+			ShellExecute(NULL,_T("open"),m_sLink.IsEmpty() ? strLink : m_sLink,NULL,NULL,SW_SHOWNORMAL);
+		}
+		if (m_Link == MailLink)
+		{
+			strLink = _T("mailto:") + strLink;
+			ShellExecute( NULL, NULL,  strLink,  NULL, NULL, SW_SHOWNORMAL );
+		}
+	}
+	else
+	{
+		// To use notification in parent window
+		// Respond to a OnNotify in parent and disassemble the message
+		//
+		NMHDR nm;
+
+		nm.hwndFrom = GetSafeHwnd();
+		nm.idFrom  = GetDlgCtrlID();
+		nm.code = NM_LINKCLICK;
+		GetParent()->SendMessage(WM_NOTIFY,nm.idFrom,(LPARAM) &nm);
+	}
+
+	CStatic::OnLButtonDown(nFlags, point);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+// THE FUNCTIONS START HERE :----
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetText
+//
+// Description:		Short cut to set window text - caption - label
+//
+// INPUTS:          Text to use
+// 
+// RETURNS:         Reference to this
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26081998    1.0     Origin
+// NT ALMOND				02072002    1.6     Crash Fix
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetText(const CString& strText)
+{
+	if(IsWindow(this->GetSafeHwnd())) 
+	{
+		//SetWindowText(strText);
+		m_strText = strText;
+		UpdateSurface();
+	}
+
+	return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetTextColor
+//
+// Description:		Sets the text color 
+//
+// INPUTS:          True or false
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				22/10/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetTextColor(COLORREF crText)
+{
+
+	m_crText = crText;
+
+	UpdateSurface();
+	return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetFontBold
+//
+// Description:		Sets the font ot bold 
+//
+// INPUTS:          True or false
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				22/10/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetFontBold(BOOL bBold)
+{	
+
+	m_lf.lfWeight = bBold ? FW_BOLD : FW_NORMAL;
+	ReconstructFont();
+	UpdateSurface();
+	return *this;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetFontUnderline
+//
+// Description:		Sets font underline attribue
+//
+// INPUTS:          True of false
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetFontUnderline(BOOL bSet)
+{	
+	m_lf.lfUnderline = bSet;
+	ReconstructFont();
+	UpdateSurface();
+
+	return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetFontItalic
+//
+// Description:		Sets font italic attribute
+//
+// INPUTS:          True of false
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetFontItalic(BOOL bSet)
+{
+
+	m_lf.lfItalic = bSet;
+	ReconstructFont();
+	UpdateSurface();
+
+	return *this;	
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetSunken
+//
+// Description:		Sets sunken effect on border
+//
+// INPUTS:          True of false
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetSunken(BOOL bSet)
+{
+
+	if (!bSet)
+		ModifyStyleEx(WS_EX_STATICEDGE,0,SWP_DRAWFRAME);
+	else
+		ModifyStyleEx(0,WS_EX_STATICEDGE,SWP_DRAWFRAME);
+
+	return *this;	
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetBorder
+//
+// Description:		Toggles the border on/off
+//
+// INPUTS:          True of false
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetBorder(BOOL bSet)
+{
+
+	if (!bSet)
+		ModifyStyle(WS_BORDER,0,SWP_DRAWFRAME);
+	else
+		ModifyStyle(0,WS_BORDER,SWP_DRAWFRAME);
+
+	return *this;	
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetFontSize
+//
+// Description:		Sets the font size
+//
+// INPUTS:          True of false
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetFontSize(int nSize)
+{
+
+	CFont cf;
+	LOGFONT lf;
+
+	cf.CreatePointFont(nSize * 10, m_lf.lfFaceName);
+	cf.GetLogFont(&lf);
+
+	m_lf.lfHeight = lf.lfHeight;
+	m_lf.lfWidth  = lf.lfWidth;
+
+	//	nSize*=-1;
+	//	m_lf.lfHeight = nSize;
+	ReconstructFont();
+	UpdateSurface();
+
+	return *this;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetBkColor
+//
+// Description:		Sets background color
+//
+// INPUTS:          Colorref of background color
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetBkColor(COLORREF crBkgnd, COLORREF crBkgndHigh , BackFillMode mode)
+{
+
+	m_crLoColor = crBkgnd;
+	m_crHiColor = crBkgndHigh;
+
+	m_fillmode = mode;
+
+	if (m_hBackBrush)
+		::DeleteObject(m_hBackBrush);
+
+
+	if (m_fillmode == Normal)
+		m_hBackBrush = ::CreateSolidBrush(crBkgnd);
+
+	UpdateSurface();
+
+	return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetFontName
+//
+// Description:		Sets the fonts face name
+//
+// INPUTS:          String containing font name
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+// NT ALMOND				15092000	1.5		Support internation windows
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetFontName(const CString& strFont, BYTE byCharSet /* Default = ANSI_CHARSET */)
+{	
+
+	m_lf.lfCharSet = byCharSet;
+
+	_tcscpy(m_lf.lfFaceName,strFont);
+	ReconstructFont();
+	UpdateSurface();
+
+	return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::FlashText
+//
+// Description:		As the function states
+//
+// INPUTS:          True or false
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::FlashText(BOOL bActivate)
+{
+
+	if (m_bTimer)
+		KillTimer(1);
+
+	if (bActivate)
+	{
+		m_bState = FALSE;
+
+		m_bTimer = TRUE;
+
+		SetTimer(1,500,NULL);
+
+		m_Type = Text;
+	}
+	else
+		m_Type = None; // Fix
+
+	return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::FlashBackground
+//
+// Description:		As the function states
+//
+// INPUTS:          True or false
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::FlashBackground(BOOL bActivate)
+{
+
+	if (m_bTimer)
+		KillTimer(1);
+
+	if (bActivate)
+	{
+		m_bState = FALSE;
+
+		m_bTimer = TRUE;
+		SetTimer(1,500,NULL);
+
+		m_Type = Background;
+	}
+
+	return *this;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetLink
+//
+// Description:		Indicates the string is a link
+//
+// INPUTS:          True or false
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+// NT ALMOND				26/08/99	1.2		Added flexbility of
+//												Sending Click meessage to parent
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetLink(BOOL bLink,BOOL bNotifyParent)
+{
+
+	if (bLink)
+		m_Link = HyperLink;
+	else
+		m_Link = LinkNone;
+
+	m_bNotifyParent = bNotifyParent;
+
+	if (m_Link != LinkNone)
+		ModifyStyle(0,SS_NOTIFY);
+	else
+		ModifyStyle(SS_NOTIFY,0);
+
+
+
+	return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetLinkCursor
+//
+// Description:		Sets the internet browers link
+//
+// INPUTS:          Handle of cursor
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				26/08/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetLinkCursor(HCURSOR hCursor)
+{
+
+	m_hCursor = hCursor;
+	return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetTransparent
+//
+// Description:		Sets the Label window to be transpaent
+//
+// INPUTS:          True or false
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				22/10/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetTransparent(BOOL bSet)
+{
+
+	m_bTransparent = bSet;
+	ModifyStyleEx(0,WS_EX_TRANSPARENT); // Fix for transparency
+	UpdateSurface();
+
+	return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetFont3D
+//
+// Description:		Sets the 3D attribute of the font.
+//
+// INPUTS:          True or false, Raised or Sunken
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				22/10/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetFont3D(BOOL bSet,Type3D type)
+{
+
+	m_bFont3d = bSet;
+	m_3dType = type;
+	UpdateSurface();
+
+
+	return *this;
+}
+
+void CLabel::OnSysColorChange() 
+{
+
+	if (m_hwndBrush)
+		::DeleteObject(m_hwndBrush);
+
+	m_hwndBrush = ::CreateSolidBrush(GetSysColor(COLOR_3DFACE));
+
+	UpdateSurface();
+
+
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetRotationAngle
+//
+// Description:		Sets the rotation angle for the current font.
+//
+// INPUTS:          Angle in Degress
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				22/10/98    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetRotationAngle(UINT nAngle,BOOL bRotation)
+{
+	// Arrrrh...
+	// Your looking in here why the font is rotating, aren't you?
+	// Well try setting the font name to 'Arial' or 'Times New Roman'
+	// Make the Angle 180 and set bRotation to true.
+	//
+	// Font rotation _ONLY_ works with TrueType fonts...
+	//
+	// 
+	m_lf.lfEscapement = m_lf.lfOrientation = (nAngle * 10);
+	m_bRotation = bRotation;
+
+	ReconstructFont();
+
+	UpdateSurface();
+
+
+	return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetText3DHiliteColor
+//
+// Description:		Sets the 3D font hilite color
+//
+// INPUTS:          Color 
+// 
+// RETURNS:         Reference to 'this' object
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				17/07/00    1.0     Origin
+//
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetText3DHiliteColor(COLORREF cr3DHiliteColor)
+{
+	m_cr3DHiliteColor = cr3DHiliteColor;
+	UpdateSurface();
+
+
+	return *this;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::PreSubclassWindow
+//
+// Description:		Assigns default dialog font
+//
+// INPUTS:          
+// 
+// RETURNS:         
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				15092000    1.5     Origin
+// NT ALMOND				02072002    1.6     Fix crash when GetFont returns NULL
+//////////////////////////////////////////////////////////////////////////
+void CLabel::PreSubclassWindow() 
+{
+
+	CStatic::PreSubclassWindow();
+
+	CFont* cf = GetFont();
+	if(cf !=NULL)
+	{
+		cf->GetObject(sizeof(m_lf),&m_lf);
+	}
+	else
+	{
+		GetObject(GetStockObject(SYSTEM_FONT),sizeof(m_lf),&m_lf);
+	}
+
+	ReconstructFont();
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::PreCreateWindow
+//
+// Description:		
+//
+// INPUTS:          
+// 
+// RETURNS:         
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				15092000    1.5     Origin
+//////////////////////////////////////////////////////////////////////////
+BOOL CLabel::PreCreateWindow(CREATESTRUCT& cs) 
+{	
+	return CStatic::PreCreateWindow(cs);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::DrawGradientFill
+//
+// Description:		Internal help function to gradient fill background
+//
+// INPUTS:          
+// 
+// RETURNS:         
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				15092000    1.5     Origin
+//////////////////////////////////////////////////////////////////////////
+void CLabel::DrawGradientFill(CDC* pDC, CRect* pRect, COLORREF crStart, COLORREF crEnd, int nSegments)
+{
+	// Get the starting RGB values and calculate the incremental
+	// changes to be applied.
+
+	COLORREF cr;
+	int nR = GetRValue(crStart);
+	int nG = GetGValue(crStart);
+	int nB = GetBValue(crStart);
+
+	int neB = GetBValue(crEnd);
+	int neG = GetGValue(crEnd);
+	int neR = GetRValue(crEnd);
+
+	if(nSegments > pRect->Width())
+		nSegments = pRect->Width();
+
+	int nDiffR = (neR - nR);
+	int nDiffG = (neG - nG);
+	int nDiffB = (neB - nB);
+
+	int ndR = 256 * (nDiffR) / (max(nSegments,1));
+	int ndG = 256 * (nDiffG) / (max(nSegments,1));
+	int ndB = 256 * (nDiffB) / (max(nSegments,1));
+
+	nR *= 256;
+	nG *= 256;
+	nB *= 256;
+
+	neR *= 256;
+	neG *= 256;
+	neB *= 256;
+
+	int nCX = pRect->Width() / max(nSegments,1), nLeft = pRect->left, nRight;
+	pDC->SelectStockObject(NULL_PEN);
+
+	for (int i = 0; i < nSegments; i++, nR += ndR, nG += ndG, nB += ndB)
+	{
+		// Use special code for the last segment to avoid any problems
+		// with integer division.
+
+		if (i == (nSegments - 1))
+			nRight = pRect->right;
+		else
+			nRight = nLeft + nCX;
+
+		cr = RGB(nR / 256, nG / 256, nB / 256);
+
+		{
+			CBrush br(cr);
+			CBrush* pbrOld = pDC->SelectObject(&br);
+			pDC->Rectangle(nLeft, pRect->top, nRight + 1, pRect->bottom);
+			pDC->SelectObject(pbrOld);
+		}
+
+		// Reset the left side of the drawing rectangle.
+
+		nLeft = nRight;
+	}
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetFont
+//
+// Description:		Sets font with LOGFONT structure
+//
+// INPUTS:          
+// 
+// RETURNS:         
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				02072002    1.6     Origin
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetFont(LOGFONT lf)
+{
+	CopyMemory(&m_lf, &lf, sizeof(m_lf));
+	ReconstructFont();
+	UpdateSurface();
+	return *this;
+
+}
+
+BOOL CLabel::OnEraseBkgnd(CDC* pDC) 
+{
+	// TODO: Add your message handler code here and/or call default
+
+	return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetMailLink
+//
+// Description:		Sets the label so it becomes Mail enabled
+//
+// INPUTS:          
+// 
+// RETURNS:         
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				02072002    1.6     Origin
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetMailLink(BOOL bEnable, BOOL bNotifyParent)
+{
+	if (bEnable)
+		m_Link = MailLink;
+	else
+		m_Link = LinkNone;
+
+
+	m_bNotifyParent = bNotifyParent;
+
+	if (m_Link != LinkNone)
+		ModifyStyle(0,SS_NOTIFY);
+	else
+		ModifyStyle(SS_NOTIFY,0);
+
+	return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Function:		CLabel::SetHyperLink
+//
+// Description:		Sets the label so it becomes hyperlink enabled
+//
+// INPUTS:          
+// 
+// RETURNS:         
+//
+// NOTES:			
+// 
+// MODIFICATIONS:
+//
+// Name                     Date        Version Comments
+// NT ALMOND				02072002    1.6     Origin
+//////////////////////////////////////////////////////////////////////////
+CLabel& CLabel::SetHyperLink(const CString& sLink)
+{
+	m_sLink = sLink;
+
+	return *this;
+}
+
+/*************************************************************
+*add at  : 2014-08-11  by唐太闲
+*describe: 设置背景透明,返回空画刷                  
+*************************************************************/
+HBRUSH CLabel::CtlColor(CDC* pDC, UINT /*nCtlColor*/)
+{
+	// TODO:  在此更改 DC 的任何属性
+
+	// TODO:  如果不应调用父级的处理程序,则返回非 null 画笔
+	//return NULL;
+	pDC->SetBkMode(TRANSPARENT);  
+	return (HBRUSH)GetStockObject(NULL_BRUSH);
+}

+ 117 - 0
source/hook/skinui/SubLabel.h

@@ -0,0 +1,117 @@
+#if !defined(AFX_LABEL_H__A4EABEC5_2E8C_11D1_B79F_00805F9ECE10__INCLUDED_)
+#define AFX_LABEL_H__A4EABEC5_2E8C_11D1_B79F_00805F9ECE10__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+// Label.h : header file
+//
+
+#define	NM_LINKCLICK	WM_APP + 0x200
+
+/////////////////////////////////////////////////////////////////////////////
+// CLabel window
+
+class CLabel : public CStatic
+{
+	// Construction
+public:
+
+
+	static enum LinkStyle { LinkNone, HyperLink, MailLink };
+	static enum FlashType {None, Text, Background };
+	static enum Type3D { Raised, Sunken};
+	static enum BackFillMode { Normal, Gradient };
+
+	CLabel();
+	virtual CLabel& SetBkColor(COLORREF crBkgnd, COLORREF crBkgndHigh = 0, BackFillMode mode = Normal);
+	virtual CLabel& SetTextColor(COLORREF crText);
+	virtual CLabel& SetText(const CString& strText);
+	virtual CLabel& SetFontBold(BOOL bBold = TRUE);
+	virtual CLabel& SetFontName(const CString& strFont, BYTE byCharSet = ANSI_CHARSET);
+	virtual CLabel& SetFontUnderline(BOOL bSet = TRUE);
+	virtual CLabel& SetFontItalic(BOOL bSet = TRUE);
+	virtual CLabel& SetFontSize(int nSize);
+	virtual CLabel& SetSunken(BOOL bSet );
+	virtual CLabel& SetBorder(BOOL bSet);
+	virtual CLabel& SetTransparent(BOOL bSet);
+	virtual CLabel& FlashText(BOOL bActivate);
+	virtual CLabel& FlashBackground(BOOL bActivate);
+	virtual CLabel& SetLink(BOOL bLink,BOOL bNotifyParent);
+	virtual CLabel& SetLinkCursor(HCURSOR hCursor);
+	virtual CLabel& SetFont3D(BOOL bSet,Type3D type=Raised);
+	virtual CLabel& SetRotationAngle(UINT nAngle,BOOL bRotation);
+	virtual CLabel& SetText3DHiliteColor(COLORREF cr3DHiliteColor);
+	virtual CLabel& SetFont(LOGFONT lf);
+	virtual CLabel& SetMailLink(BOOL bEnable, BOOL bNotifyParent);
+	virtual CLabel& SetHyperLink(const CString& sLink);
+
+	// Attributes
+public:
+protected:
+	void UpdateSurface();
+	void ReconstructFont();
+	void DrawGradientFill(CDC* pDC, CRect* pRect, COLORREF crStart, COLORREF crEnd, int nSegments);
+	COLORREF		m_crText;
+	COLORREF		m_cr3DHiliteColor;
+	HBRUSH			m_hwndBrush;
+	HBRUSH			m_hBackBrush;
+	LOGFONT			m_lf;
+	CFont			m_font;
+	BOOL			m_bState;
+	BOOL			m_bTimer;
+	LinkStyle		m_Link;
+	BOOL			m_bTransparent;
+	BOOL			m_bFont3d;
+	BOOL			m_bToolTips;
+	BOOL			m_bNotifyParent;
+	BOOL			m_bRotation;
+	FlashType		m_Type;
+	HCURSOR			m_hCursor;
+	Type3D			m_3dType;
+	BackFillMode	m_fillmode;
+	COLORREF		m_crHiColor;
+	COLORREF		m_crLoColor;
+	CString			m_sLink;
+	CString			m_strText;
+	CDC* m_pMemDC;
+	//CDC* pDCMem;
+
+	// Operations
+public:
+
+	// Overrides
+	// ClassWizard generated virtual function overrides
+	//{{AFX_VIRTUAL(CLabel)
+protected:
+	virtual void PreSubclassWindow();
+	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
+	//}}AFX_VIRTUAL
+
+	// Implementation
+public:
+	virtual ~CLabel();
+
+	// Generated message map functions
+protected:
+	//{{AFX_MSG(CLabel)
+	afx_msg void OnTimer(UINT nIDEvent);
+	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
+	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+	afx_msg void OnSysColorChange();
+	afx_msg void OnPaint();
+	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
+	//}}AFX_MSG
+
+	DECLARE_MESSAGE_MAP()
+public:
+	//tc:这就是新添加的ON_WM_CTLCOLOR_REFLECT()消息的响应函数
+	afx_msg HBRUSH CtlColor(CDC* /*pDC*/, UINT /*nCtlColor*/);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_LABEL_H__A4EABEC5_2E8C_11D1_B79F_00805F9ECE10__INCLUDED_)

+ 269 - 0
source/hook/skinui/Subclass.cpp

@@ -0,0 +1,269 @@
+/************************************************************************ 
+* 程序名:    精仿QQ主界面 
+* 制作人:    李克平, 2011年04月11日
+* 版本号:    1.0 
+************************************************************************/ 
+#include "StdAfx.h"
+#include "Subclass.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+//////////////////
+// The message hook map is derived from CMapPtrToPtr, which associates
+// a pointer with another pointer. It maps an HWND to a CSubclassWnd, like
+// the way MFC's internal maps map HWND's to CWnd's. The first CSubclassWnd
+// attached to a window is stored in the map; all other CSubclassWnd's for that
+// window are then chained via CSubclassWnd::m_pNext.
+//
+class CSubclassWndMap : private CMapPtrToPtr {
+public:
+	CSubclassWndMap();
+	~CSubclassWndMap();
+	static CSubclassWndMap& GetHookMap();
+	void Add(HWND hwnd, CSubclassWnd* pSubclassWnd);
+	void Remove(CSubclassWnd* pSubclassWnd);
+	void RemoveAll(HWND hwnd);
+	CSubclassWnd* Lookup(HWND hwnd);
+};
+
+// This trick is used so the hook map isn't
+// instantiated until someone actually requests it.
+//
+#define	theHookMap	(CSubclassWndMap::GetHookMap())
+
+IMPLEMENT_DYNAMIC(CSubclassWnd, CWnd);
+
+CSubclassWnd::CSubclassWnd()
+{
+	m_pNext = NULL;
+	m_pOldWndProc = NULL;	
+	m_hWnd  = NULL;
+}
+
+CSubclassWnd::~CSubclassWnd()
+{
+	if (m_hWnd) 
+		HookWindow((HWND)NULL);		// unhook window
+}
+
+//////////////////
+// Hook a window.
+// This installs a new window proc that directs messages to the CSubclassWnd.
+// pWnd=NULL to remove.
+//
+BOOL CSubclassWnd::HookWindow(HWND hwnd)
+{
+	ASSERT_VALID(this);
+	if (hwnd) {
+		// Hook the window
+		ASSERT(m_hWnd==NULL);
+		ASSERT(::IsWindow(hwnd));
+		theHookMap.Add(hwnd, this);			// Add to map of hooks
+
+	} else if (m_hWnd) {
+		// Unhook the window
+		theHookMap.Remove(this);				// Remove from map
+		m_pOldWndProc = NULL;
+	}
+	m_hWnd = hwnd;
+	return TRUE;
+}
+
+//////////////////
+// Window proc-like virtual function which specific CSubclassWnds will
+// override to do stuff. Default passes the message to the next hook; 
+// the last hook passes the message to the original window.
+// You MUST call this at the end of your WindowProc if you want the real
+// window to get the message. This is just like CWnd::WindowProc, except that
+// a CSubclassWnd is not a window.
+//
+LRESULT CSubclassWnd::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
+{
+	//	ASSERT_VALID(this);  // removed for speed
+	ASSERT(m_pOldWndProc);
+	return m_pNext ? m_pNext->WindowProc(msg, wp, lp) :	
+		::CallWindowProc(m_pOldWndProc, m_hWnd, msg, wp, lp);
+}
+
+//////////////////
+// Like calling base class WindowProc, but with no args, so individual
+// message handlers can do the default thing. Like CWnd::Default
+//
+LRESULT CSubclassWnd::Default()
+{
+	// MFC stores current MSG in thread state
+	MSG& curMsg = AfxGetThreadState()->m_lastSentMsg;
+	// Note: must explicitly call CSubclassWnd::WindowProc to avoid infinte
+	// recursion on virtual function
+	return CSubclassWnd::WindowProc(curMsg.message, curMsg.wParam, curMsg.lParam);
+}
+
+#ifdef _DEBUG
+void CSubclassWnd::AssertValid() const
+{
+	CObject::AssertValid();
+	ASSERT(m_hWnd==NULL || ::IsWindow(m_hWnd));
+	CSubclassWnd* p = NULL;
+	if (m_hWnd) {
+		for (p = theHookMap.Lookup(m_hWnd); p; p=p->m_pNext) {
+			if (p==this)
+				break;
+		}
+		ASSERT(p); // should have found it!
+	}
+}
+
+void CSubclassWnd::Dump(CDumpContext& dc) const
+{
+	CObject::Dump(dc);
+}
+
+#endif
+
+//////////////////
+// Subclassed window proc for message hooks. Replaces AfxWndProc (or whatever
+// else was there before.)
+//
+LRESULT CALLBACK
+HookWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+#ifdef _USRDLL
+	// If this is a DLL, need to set up MFC state
+	AFX_MANAGE_STATE(AfxGetStaticModuleState());
+#endif
+
+	// Set up MFC message state just in case anyone wants it
+	// This is just like AfxCallWindowProc, but we can't use that because
+	// a CSubclassWnd is not a CWnd.
+	//
+	MSG& curMsg = AfxGetThreadState()->m_lastSentMsg;
+	MSG  oldMsg = curMsg;   // save for nesting
+	curMsg.hwnd		= hwnd;
+	curMsg.message = msg;
+	curMsg.wParam  = wp;
+	curMsg.lParam  = lp;
+
+	// Get hook object for this window. Get from hook map
+	CSubclassWnd* pSubclassWnd = theHookMap.Lookup(hwnd);
+	ASSERT(pSubclassWnd);
+
+	LRESULT lr;
+	if (msg==WM_NCDESTROY) {
+		// Window is being destroyed: unhook all hooks (for this window)
+		// and pass msg to orginal window proc
+		//
+		WNDPROC wndproc = pSubclassWnd->m_pOldWndProc;
+		theHookMap.RemoveAll(hwnd);
+		lr = ::CallWindowProc(wndproc, hwnd, msg, wp, lp);
+
+	} else {
+		// pass to msg hook
+		lr = pSubclassWnd->WindowProc(msg, wp, lp);
+	}
+	curMsg = oldMsg;			// pop state
+	return lr;
+}
+
+////////////////////////////////////////////////////////////////
+// CSubclassWndMap implementation
+//
+CSubclassWndMap::CSubclassWndMap()
+{
+}
+
+CSubclassWndMap::~CSubclassWndMap()
+{
+	// This assert bombs when posting WM_QUIT, so I've deleted it.
+	//	ASSERT(IsEmpty());	// all hooks should be removed!	
+}
+
+//////////////////
+// Get the one and only global hook map
+// 
+CSubclassWndMap& CSubclassWndMap::GetHookMap()
+{
+	// By creating theMap here, C++ doesn't instantiate it until/unless
+	// it's ever used! This is a good trick to use in C++, to
+	// instantiate/initialize a static object the first time it's used.
+	//
+	static CSubclassWndMap theMap;
+	return theMap;
+}
+
+/////////////////
+// Add hook to map; i.e., associate hook with window
+//
+void CSubclassWndMap::Add(HWND hwnd, CSubclassWnd* pSubclassWnd)
+{
+	ASSERT(hwnd && ::IsWindow(hwnd));
+
+	// Add to front of list
+	pSubclassWnd->m_pNext = Lookup(hwnd);
+	SetAt(hwnd, pSubclassWnd);
+
+	if (pSubclassWnd->m_pNext==NULL) {
+		// If this is the first hook added, subclass the window
+		pSubclassWnd->m_pOldWndProc = 
+			(WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC, (DWORD)HookWndProc);
+
+	} else {
+		// just copy wndproc from next hook
+		pSubclassWnd->m_pOldWndProc = pSubclassWnd->m_pNext->m_pOldWndProc;
+	}
+	ASSERT(pSubclassWnd->m_pOldWndProc);
+}
+
+//////////////////
+// Remove hook from map
+//
+void CSubclassWndMap::Remove(CSubclassWnd* pUnHook)
+{
+	HWND hwnd = pUnHook->m_hWnd;
+	ASSERT(hwnd && ::IsWindow(hwnd));
+
+	CSubclassWnd* pHook = Lookup(hwnd);
+	ASSERT(pHook);
+	if (pHook==pUnHook) {
+		// hook to remove is the one in the hash table: replace w/next
+		if (pHook->m_pNext)
+			SetAt(hwnd, pHook->m_pNext);
+		else {
+			// This is the last hook for this window: restore wnd proc
+			RemoveKey(hwnd);
+			SetWindowLong(hwnd, GWL_WNDPROC, (DWORD)pHook->m_pOldWndProc);
+		}
+	} else {
+		// Hook to remove is in the middle: just remove from linked list
+		while (pHook->m_pNext!=pUnHook)
+			pHook = pHook->m_pNext;
+		ASSERT(pHook && pHook->m_pNext==pUnHook);
+		pHook->m_pNext = pUnHook->m_pNext;
+	}
+}
+
+//////////////////
+// Remove all the hooks for a window
+//
+void CSubclassWndMap::RemoveAll(HWND hwnd)
+{
+	CSubclassWnd* pSubclassWnd;
+	while ((pSubclassWnd = Lookup(hwnd))!=NULL)
+		pSubclassWnd->HookWindow((HWND)NULL);	// (unhook)
+}
+
+/////////////////
+// Find first hook associate with window
+//
+CSubclassWnd* CSubclassWndMap::Lookup(HWND hwnd)
+{
+	CSubclassWnd* pFound = NULL;
+	if (!CMapPtrToPtr::Lookup(hwnd, (void*&)pFound))
+		return NULL;
+	ASSERT_KINDOF(CSubclassWnd, pFound);
+	return pFound;
+}
+

+ 101 - 0
source/hook/skinui/Subclass.h

@@ -0,0 +1,101 @@
+/************************************************************************/
+/*  Copyright (C), 2016-2020, [IT], 保留所有权利;
+/*  模 块 名:;
+/*  描    述:;
+/*
+/*  版    本:[V];	
+/*  作    者:[IT];
+/*  日    期:[8/19/2016];
+/*
+/*
+/*  注    意:;
+/*
+/*  修改记录:[IT];
+/*  修改日期:;
+/*  修改版本:;
+/*  修改内容:;
+/************************************************************************/
+
+#ifndef _SUBCLASSW_H
+#define _SUBCLASSW_H
+
+////////////////////////////////////////////////////////////////
+// Copyright 1998 Paul DiLascia
+// If this code works, it was written by Paul DiLascia.
+// If not, I don't know who wrote it.
+//
+/////////////////////////////////////////////////////////////////////////////
+/****************************************************************************
+*
+* $Date: 10/26/99 10:50p $
+* $Revision: 4 $
+* $Archive: /CodeJock/Include/Subclass.h $
+*
+* $History: Subclass.h $
+* 
+* *****************  Version 4  *****************
+* User: Kirk Stowell Date: 10/26/99   Time: 10:50p
+* Updated in $/CodeJock/Include
+* Made class methods virtual for inheritance purposes.
+* 
+* *****************  Version 3  *****************
+* User: Kirk Stowell Date: 10/14/99   Time: 12:41p
+* Updated in $/CodeJock/Include
+* Added source control history to file header.
+*
+***************************************************************************/
+/////////////////////////////////////////////////////////////////////////////
+
+//////////////////
+// Generic class to hook messages on behalf of a CWnd.
+// Once hooked, all messages go to CSubclassWnd::WindowProc before going
+// to the window. Specific subclasses can trap messages and do something.
+//
+// To use:
+//
+// * Derive a class from CSubclassWnd.
+//
+// * Override CSubclassWnd::WindowProc to handle messages. Make sure you call
+//   CSubclassWnd::WindowProc if you don't handle the message, or your
+//   window will never get messages. If you write seperate message handlers,
+//   you can call Default() to pass the message to the window.
+//
+// * Instantiate your derived class somewhere and call HookWindow(pWnd)
+//   to hook your window, AFTER it has been created.
+//	  To unhook, call HookWindow(NULL).
+//
+// This is a very important class, crucial to many of the widgets Window
+// widgets implemented in PixieLib. To see how it works, look at the HOOK
+// sample program.
+//
+class  CSubclassWnd : public CObject {
+public:
+	DECLARE_DYNAMIC(CSubclassWnd);
+	CSubclassWnd();
+	~CSubclassWnd();
+
+	// Subclass a window. Hook(NULL) to unhook (automatic on WM_NCDESTROY)
+	virtual BOOL	HookWindow(HWND  hwnd);
+	virtual BOOL	HookWindow(CWnd* pWnd)	{ return HookWindow(pWnd->GetSafeHwnd()); }
+	virtual BOOL	IsHooked()					{ return m_hWnd!=NULL; }
+
+	friend LRESULT CALLBACK HookWndProc(HWND, UINT, WPARAM, LPARAM);
+	friend class CSubclassWndMap;
+
+#ifdef _DEBUG
+	virtual void AssertValid() const;
+	virtual void Dump(CDumpContext& dc) const;
+#endif
+
+protected:
+	HWND				m_hWnd;				// the window hooked
+	WNDPROC			m_pOldWndProc;		// ..and original window proc
+	CSubclassWnd*	m_pNext;				// next in chain of hooks for this window
+
+	// Override this to handle messages in specific handlers
+	virtual LRESULT WindowProc(UINT msg, WPARAM wp, LPARAM lp);
+	virtual LRESULT Default();				// call this at the end of handler fns
+};
+
+#endif // _SUBCLASSW_H
+