变不可能为可能 - .NET Windows Form 改变窗体类名(Class Name)有多难?续篇
发布《.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,只能按照窗口创建的过程,自己实现一个窗口。而实现一个窗口的过程也很简单:
- 使用 API 函数 RegisterClass 注册窗口;
- 使用 API 函数 CreateWindowEx 创建窗口;
- 使用 API 函数 ShowWindow 显示窗口;
- 最后退出时使用 API 函数 DestroyWindow 销毁窗口。
过程非常简单,Winform 的窗口也脱离不了这个过程。那这样, HOOK API 不就有机可乘了吗?只要我们 HOOK RegisterClass 和 CreateWindowEx,在 Winform 注册窗口时,把它使用的类名改为我们需要的类名;创建窗口的时候,也同样。当然,在实际处理过程中,UnregisterClass,GetClassInfo 也是需要 HOOK 进行处理的。
最终实现
不多说,非常简单,一切以代码说话。
#include "ClassNameManager.h"
#include <Windows.h>
#include <tchar.h>
#include <assert.h>
#include "../MinHook/include/MinHook.h" #ifdef _M_X64
#pragma comment(lib, "../lib/MinHook/MinHook.x64.lib")
#else
#pragma comment(lib,"../lib/MinHook/MinHook.x86.lib")
#endif namespace Starts2000 {
namespace Window {
namespace Forms { #define FORM_CLASS_NAME L"WindowsForms10.Window.8.app"
#define FORM_CUSTOM_CLASS_NAME L"Starts2000.Window" typedef ATOM (WINAPI * TrueRegisterClassW)(_In_ CONST WNDCLASSW *);
typedef BOOL (WINAPI * TrueUnregisterClassW)(_In_ LPCWSTR, _In_opt_ HINSTANCE);
typedef BOOL (WINAPI * TrueGetClassInfoW)(
_In_opt_ HINSTANCE,
_In_ LPCWSTR,
_Out_ LPWNDCLASSW);
typedef HWND (WINAPI * TrueCreateWindowExW)(
_In_ DWORD,
_In_opt_ LPCWSTR,
_In_opt_ LPCWSTR,
_In_ DWORD,
_In_ int,
_In_ int,
_In_ int,
_In_ int,
_In_opt_ HWND,
_In_opt_ HMENU,
_In_opt_ HINSTANCE,
_In_opt_ LPVOID); TrueRegisterClassW _registerClassW = NULL;
TrueUnregisterClassW _unregisterClassW = NULL;
TrueGetClassInfoW _getClassInfoW = NULL;
TrueCreateWindowExW _createWindowExW = NULL; ATOM WINAPI RegisterClassWD(_In_ CONST WNDCLASSW *lpWndClass) {
if (_tcsstr(lpWndClass->lpszClassName, FORM_CLASS_NAME)) {
WNDCLASSW wndClass;
memcpy(&wndClass, lpWndClass, sizeof(WNDCLASSW));
wndClass.lpszClassName = FORM_CUSTOM_CLASS_NAME;
auto ret = _registerClassW(&wndClass);
return ret;
} return _registerClassW(lpWndClass);
} BOOL WINAPI UnregisterClassWD(_In_ LPCWSTR lpClassName, _In_opt_ HINSTANCE hInstance) {
if (_tcsstr(lpClassName, FORM_CLASS_NAME)) {
return _unregisterClassW(FORM_CUSTOM_CLASS_NAME, hInstance);
} return _unregisterClassW(lpClassName, hInstance);
} BOOL WINAPI GetClassInfoWD(_In_opt_ HINSTANCE hInstance,
_In_ LPCWSTR lpClassName,
_Out_ LPWNDCLASSW lpWndClass) {
if (_tcsstr(lpClassName, FORM_CLASS_NAME)) {
return _getClassInfoW(hInstance, FORM_CUSTOM_CLASS_NAME, lpWndClass);
} return _getClassInfoW(hInstance, lpClassName, lpWndClass);
} HWND WINAPI CreateWindowExWD(
_In_ DWORD dwExStyle,
_In_opt_ LPCWSTR lpClassName,
_In_opt_ LPCWSTR lpWindowName,
_In_ DWORD dwStyle,
_In_ int X,
_In_ int Y,
_In_ int nWidth,
_In_ int nHeight,
_In_opt_ HWND hWndParent,
_In_opt_ HMENU hMenu,
_In_opt_ HINSTANCE hInstance,
_In_opt_ LPVOID lpParam) {
if (_tcsstr(lpClassName, FORM_CLASS_NAME)) {
auto hwnd = _createWindowExW(dwExStyle, FORM_CUSTOM_CLASS_NAME, lpWindowName, dwStyle,
X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
assert(hwnd);
return hwnd;
} return _createWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle,
X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
} ClassNameManager::ClassNameManager() {
auto ret = MH_Initialize();
assert(ret == MH_STATUS::MH_OK); ret = MH_CreateHookApi(L"User32.dll",
"RegisterClassW", &RegisterClassWD, reinterpret_cast<LPVOID*>(&_registerClassW));
assert(ret == MH_STATUS::MH_OK); ret = MH_CreateHookApi(L"User32.dll",
"UnregisterClassW", &UnregisterClassWD, reinterpret_cast<LPVOID*>(&_unregisterClassW));
assert(ret == MH_STATUS::MH_OK); ret = MH_CreateHookApi(L"User32.dll",
"GetClassInfoW", &GetClassInfoWD, reinterpret_cast<LPVOID*>(&_getClassInfoW));
assert(ret == MH_STATUS::MH_OK); ret = MH_CreateHookApi(L"User32.dll",
"CreateWindowExW", &CreateWindowExWD, reinterpret_cast<LPVOID*>(&_createWindowExW));
assert(ret == MH_STATUS::MH_OK); ret = MH_EnableHook(MH_ALL_HOOKS);
assert(ret == MH_STATUS::MH_OK);
} ClassNameManager::~ClassNameManager() {
} ClassNameManager::!ClassNameManager() {
auto ret = MH_Uninitialize();
assert(ret == MH_STATUS::MH_OK);
}
}
}
}
最终效果

最后的最后
源码是要上的,下载项目源代码。
变不可能为可能 - .NET Windows Form 改变窗体类名(Class Name)有多难?续篇的更多相关文章
- .NET Windows Form 改变窗体类名(Class Name)有多难?
研究WinForm的东西,是我的一个个人兴趣和爱好,以前做的项目,多与WinForm相关,然而这几年,项目都与WinForm没什么关系了,都转为ASP.NET MVC与WPF了.关于今天讨论的这个问题 ...
- Ninject之旅之十二:Ninject在Windows Form程序上的应用(附程序下载)
摘要: 下面的几篇文章介绍如何使用Ninject创建不同类型的应用系统.包括: Windows Form应用系统 ASP.NET MVC应用系统 ASP.NET Web Form应用系统 尽管对于不同 ...
- 如何用Web技术开发Windows Form应用
现在H5很热,很多互联网公司的产品都采用混合编程,其中各个平台客户端的“壳”为原生控件,但是内容很多都是Web网页,因此可以做出很多炫酷的效果.随着Node.js和Ionic等框架的出现,现在感觉Ja ...
- Windows Form 中快捷键设置
在Windows Form程序中使用带下划线的快捷键只需要进行设置: 就能够工作.
- VS2008 Windows Form项目安装包生成详解
2008 Windows Form项目的发布对有经验的程序员来说,可能不值一提,但对很多新手来说却不知道如何操作,因为在很多关于Visual Studio的书籍中也没有相关介绍,权威如<C# 2 ...
- VISUAL STUDIO 2008 WINDOWS FORM项目发布生成安装包详解(转)
转自:http://www.cnblogs.com/killerofyang/archive/2012/05/31/2529193.html Visual Studio 2008 Windows Fo ...
- C# Adding Hyperlink to Windows Form z
When creating a Windows form in C#, we would like to create a hyperlink so that when the user click ...
- windows form (窗体) 之间传值小结
windows form (窗体) 之间传值小结 windows form (窗体) 之间传值小结 在windows form之间传值,我总结了有四个方法:全局变量.属性.窗体构造函数和deleg ...
- Windows Form线程同步
.Net多线程开发中,经常需要启动工作线程Worker thread处理某些事情,而工作线程中又需要更新主线程UI thread的界面状态.我们只能在主线程中操作界面控件,否则.Net会抛出异常. 那 ...
随机推荐
- apache的80端口被占用
1.netstart -ano | findstr "80":查看80端口是否被占用,并找出对应的pid 2.关掉pid对应的进程
- CreateThread
CreateThread(NULL,0,ReportResultThread,this,0,&g_dwThreadId) 2. 参数说明: 第一个参数 lpThreadAttributes 表 ...
- pkg_config找不到库
解决方法 假设libavutil默认安装时libavutil.pc安装到了 /usr/lib64/lib/pkgconfig/ 中,而 echo $PKG_CONFIG_PATH 结果中没有这个路径, ...
- 7.11 cookie 失效后 ,重新登陆 页面 可能跳出 框架 ,只剩主题 部分 ,
判断地址 不在 框架里 (项目 地址栏一般 都是 首页地址 ) function url(){ var page=getpage(); if(window==top&&(page ...
- 2、C++
2.2定义变量 2.2.1命名规则 赋予变量的名称叫做标识符,或者更方便地称之为变量名.变量名可用字母(包括大小写),数字,以及下划线,其他字符不允许.以下划线或者字母开头.在Visual C++20 ...
- 2018.10.16 uoj#340. 【清华集训2017】小 Y 和恐怖的奴隶主(矩阵快速幂优化dp)
传送门 一道不错的矩阵快速幂优化dpdpdp. 设f[i][j][k][l]f[i][j][k][l]f[i][j][k][l]表示前iii轮第iii轮还有jjj个一滴血的,kkk个两滴血的,lll个 ...
- 字典树Java实现
Trie树的原理 Trie树也称字典树,因为其效率很高,所以在在字符串查找.前缀匹配等中应用很广泛,其高效率是以空间为代价的. 利用串构建一个字典树,这个字典树保存了串的公共前缀信息,因此可以降低查询 ...
- Java 增强 for 循环
Java 增强 for 循环 Java5 引入了一种主要用于数组的增强型 for 循环. Java 增强 for 循环语法格式如下: for(声明语句 : 表达式) { //代码句子 } 声明语句:声 ...
- mysql操作说明,插入时外键约束,快速删除
快速删除: CMD命令 SET FOREIGN_KEY_CHECKS=0;去除外键约束 truncate table 表名;
- Delphi for iOS开发指南(3):创建一个FireMonkey iOS应用程序
http://cache.baiducontent.com/c?m=9d78d513d9d431a94f9d92697d60c015134381132ba1d0020fa48449e3732b4b50 ...