你的位置:首页 > ASP.net教程

[ASP.net教程]变不可能为可能


  发布《 .NET Windows Form 改变窗体类名(Class Name)有多难?》转眼大半年过去了,要不是在前几天有园友对这篇文章进行评论,基本上已经很少关注它了,毕竟那只是一个解惑的研究,在开发中没什么实际的用处。但是由于Squares园友的评论,结合最近自己相关的工作,灵感一现,却真的找到了解决之法,不得不感慨一下,“问题总是会有解决办法的,只是自己能力不够或一时没想到而已”。好了,前奏写完,进入正题。

最近相关工作

  最近一段时间,重新拾起以前比较熟悉的界面UI开发,由于需要,了解了一些 HOOK API 的知识。HOOK API C++ 已经有比较好的开源资源,MHook 和 MinHook。而 HOOK API 就是解决 “Windows Form 改变窗体类名(Class Name)”的关键。

灵感及思路

  还记得上一篇文章里提到为什么不能改变Windows Form窗体类名的原因吗?就是微软的代码里只认系统注册的 ClassName,只要我们在 CreateParams 属性里设置的 ClassName 不是认系统注册的 ClassName,就会报错。所以,设置自己喜欢的 ClassName,只能按照窗口创建的过程,自己实现一个窗口。而实现一个窗口的过程也很简单:

  1. 使用 API 函数 RegisterClass 注册窗口;
  2. 使用 API 函数 CreateWindowEx 创建窗口;
  3. 使用 API 函数 ShowWindow 显示窗口;
  4. 最后退出时使用 API 函数 DestroyWindow 销毁窗口。

  过程非常简单,Winform 的窗口也脱离不了这个过程。那这样, HOOK API 不就有机可乘了吗?只要我们 HOOK RegisterClass 和 CreateWindowEx,在 Winform 注册窗口时,把它使用的类名改为我们需要的类名;创建窗口的时候,也同样。当然,在实际处理过程中,UnregisterClassGetClassInfo 也是需要 HOOK 进行处理的。

最终实现

  不多说,非常简单,一切以代码说话。  

 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 }

最终效果

最后的最后

  源码是要上的,下载项目源代码。