變不可能爲可能 - .NET Windows Form 改變窗體類名(Class Name)有多難?續篇

  發佈《 .NET Windows Form 改變窗體類名(Class Name)有多難?》轉眼大半年過去了,要不是在前幾天有園友對這篇文章進行評論,基本上已經不多關注它了,畢竟那只是一個解惑的研究,在開發中沒什麼實際的用處。可是因爲Squares園友的評論,結合最近本身相關的工做,靈感一現,卻真的找到了解決之法,不得不感慨一下,「問題老是會有解決辦法的,只是本身能力不夠或一時沒想到而已」。好了,前奏寫完,進入正題。css

最近相關工做

  最近一段時間,從新拾起之前比較熟悉的界面UI開發,因爲須要,瞭解了一些 HOOK API 的知識。HOOK API C++ 已經有比較好的開源資源,MHook MinHook。而 HOOK API 就是解決 「Windows Form 改變窗體類名(Class Name)」的關鍵。html

靈感及思路

  還記得上一篇文章裏提到爲何不能改變Windows Form窗體類名的緣由嗎?就是微軟的代碼裏只認系統註冊的 ClassName,只要咱們在 CreateParams 屬性裏設置的 ClassName 不是系統註冊的 ClassName,就會報錯。因此,設置本身喜歡的 ClassName,只能按照窗口建立的過程,本身實現一個窗口。而實現一個窗口的過程也很簡單:git

  1. 使用 API 函數 RegisterClass 註冊窗口;
  2. 使用 API 函數 CreateWindowEx 建立窗口;
  3. 使用 API 函數 ShowWindow 顯示窗口;
  4. 最後退出時使用 API 函數 DestroyWindow 銷燬窗口。

  過程很是簡單,Winform 的窗口也脫離不了這個過程。那這樣, HOOK API 不就有隙可乘了嗎?只要咱們 HOOK RegisterClass 和 CreateWindowEx,在 Winform 註冊窗口時,把它使用的類名改成咱們須要的類名;建立窗口的時候,也一樣。固然,在實際處理過程當中,UnregisterClassGetClassInfo 也是須要 HOOK 進行處理的。github

最終實現

  很少說,很是簡單,一切以代碼說話。  app

  1 #include "ClassNameManager.h"
  2 #include <Windows.h>
  3 #include <tchar.h>
  4 #include <assert.h>
  5 #include "../MinHook/include/MinHook.h"
  6 
  7 #ifdef _M_X64
  8 #pragma comment(lib, "../lib/MinHook/MinHook.x64.lib")
  9 #else
 10 #pragma comment(lib,"../lib/MinHook/MinHook.x86.lib")
 11 #endif
 12 
 13 namespace Starts2000 {
 14     namespace Window {
 15         namespace Forms {
 16 
 17             #define FORM_CLASS_NAME L"WindowsForms10.Window.8.app"
 18             #define FORM_CUSTOM_CLASS_NAME L"Starts2000.Window"
 19 
 20             typedef ATOM (WINAPI * TrueRegisterClassW)(_In_ CONST WNDCLASSW *);
 21             typedef BOOL (WINAPI * TrueUnregisterClassW)(_In_ LPCWSTR, _In_opt_ HINSTANCE);
 22             typedef BOOL (WINAPI * TrueGetClassInfoW)(
 23                 _In_opt_ HINSTANCE,
 24                 _In_ LPCWSTR,
 25                 _Out_ LPWNDCLASSW);
 26             typedef HWND (WINAPI * TrueCreateWindowExW)(
 27                 _In_ DWORD,
 28                 _In_opt_ LPCWSTR,
 29                 _In_opt_ LPCWSTR,
 30                 _In_ DWORD,
 31                 _In_ int,
 32                 _In_ int,
 33                 _In_ int,
 34                 _In_ int,
 35                 _In_opt_ HWND,
 36                 _In_opt_ HMENU,
 37                 _In_opt_ HINSTANCE,
 38                 _In_opt_ LPVOID);
 39 
 40             TrueRegisterClassW _registerClassW = NULL;
 41             TrueUnregisterClassW _unregisterClassW = NULL;
 42             TrueGetClassInfoW _getClassInfoW = NULL;
 43             TrueCreateWindowExW _createWindowExW = NULL;
 44 
 45             ATOM WINAPI RegisterClassWD(_In_ CONST WNDCLASSW *lpWndClass) {
 46                 if (_tcsstr(lpWndClass->lpszClassName, FORM_CLASS_NAME)) {
 47                     WNDCLASSW wndClass;
 48                     memcpy(&wndClass, lpWndClass, sizeof(WNDCLASSW));
 49                     wndClass.lpszClassName = FORM_CUSTOM_CLASS_NAME;
 50                     auto ret = _registerClassW(&wndClass);
 51                     return ret;
 52                 }
 53 
 54                 return _registerClassW(lpWndClass);
 55             }
 56 
 57             BOOL WINAPI UnregisterClassWD(_In_ LPCWSTR lpClassName, _In_opt_ HINSTANCE hInstance) {
 58                 if (_tcsstr(lpClassName, FORM_CLASS_NAME)) {
 59                     return _unregisterClassW(FORM_CUSTOM_CLASS_NAME, hInstance);
 60                 }
 61 
 62                 return _unregisterClassW(lpClassName, hInstance);
 63             }
 64 
 65             BOOL WINAPI GetClassInfoWD(_In_opt_ HINSTANCE hInstance,
 66                 _In_ LPCWSTR lpClassName,
 67                 _Out_ LPWNDCLASSW lpWndClass) {
 68                 if (_tcsstr(lpClassName, FORM_CLASS_NAME)) {
 69                     return _getClassInfoW(hInstance, FORM_CUSTOM_CLASS_NAME, lpWndClass);
 70                 }
 71 
 72                 return _getClassInfoW(hInstance, lpClassName, lpWndClass);
 73             }
 74 
 75             HWND WINAPI CreateWindowExWD(
 76                 _In_ DWORD dwExStyle,
 77                 _In_opt_ LPCWSTR lpClassName,
 78                 _In_opt_ LPCWSTR lpWindowName,
 79                 _In_ DWORD dwStyle,
 80                 _In_ int X,
 81                 _In_ int Y,
 82                 _In_ int nWidth,
 83                 _In_ int nHeight,
 84                 _In_opt_ HWND hWndParent,
 85                 _In_opt_ HMENU hMenu,
 86                 _In_opt_ HINSTANCE hInstance,
 87                 _In_opt_ LPVOID lpParam) {
 88                 if (_tcsstr(lpClassName, FORM_CLASS_NAME)) {
 89                     auto hwnd = _createWindowExW(dwExStyle, FORM_CUSTOM_CLASS_NAME, lpWindowName, dwStyle,
 90                         X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
 91                     assert(hwnd);
 92                     return hwnd;
 93                 }
 94 
 95                 return _createWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle,
 96                     X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
 97             }
 98 
 99             ClassNameManager::ClassNameManager() {
100                 auto ret = MH_Initialize();
101                 assert(ret == MH_STATUS::MH_OK);
102 
103                 ret = MH_CreateHookApi(L"User32.dll", 
104                     "RegisterClassW", &RegisterClassWD, reinterpret_cast<LPVOID*>(&_registerClassW));
105                 assert(ret == MH_STATUS::MH_OK);
106 
107                 ret = MH_CreateHookApi(L"User32.dll",
108                     "UnregisterClassW", &UnregisterClassWD, reinterpret_cast<LPVOID*>(&_unregisterClassW));
109                 assert(ret == MH_STATUS::MH_OK);
110 
111                 ret = MH_CreateHookApi(L"User32.dll",
112                     "GetClassInfoW", &GetClassInfoWD, reinterpret_cast<LPVOID*>(&_getClassInfoW));
113                 assert(ret == MH_STATUS::MH_OK);
114 
115                 ret = MH_CreateHookApi(L"User32.dll",
116                     "CreateWindowExW", &CreateWindowExWD, reinterpret_cast<LPVOID*>(&_createWindowExW));
117                 assert(ret == MH_STATUS::MH_OK);
118 
119                 ret = MH_EnableHook(MH_ALL_HOOKS);
120                 assert(ret == MH_STATUS::MH_OK);
121             }
122 
123             ClassNameManager::~ClassNameManager() {
124             }
125 
126             ClassNameManager::!ClassNameManager() {
127                 auto ret = MH_Uninitialize();
128                 assert(ret == MH_STATUS::MH_OK);
129             }
130         }
131     }
132 }

最終效果

最後的最後

  源碼是要上的,下載項目源代碼函數

相關文章
相關標籤/搜索