变不可能为可能 - .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会抛出异常. 那 ...
随机推荐
- RNA-seq要做几次生物学重复?找出来的100%都是真正的应答基因
尹师妹:“哈师兄,做验证实验好辛苦,老板让我提高筛选差异基因的条件,尽量降低假阳性,我该怎么筛?” 小哈打开Evernote,给尹师妹看张表: “瞧见那个100%了吗?30 million mappe ...
- AJAX 请求中多出了一次 OPTIONS 请求 导致 Laravel 中间件无法对 Header 传入的 Token 无法获取
背景知识: 我们会发现,在很多post,put,delete等请求之前,会有一次options请求.本文主要是来讨论一下这是什么原因引起的. 根本原因就是,W3C规范这样要求了!在跨域请求中,分为简单 ...
- 前端之JavaScript笔记1
一 JavaScript的引入方式 <!DOCTYPE html> <html lang="en"> <head> <meta chars ...
- 日历时间选择控件---3(支持ie、火狐)
效果展示: 源代码: <script language=javascript ><!--/* 调用方法:不能用onfocus,要用onclick <input onclic ...
- 多网卡下对ServerSocket以TCP协议绑定IP和端口的测试
一.引言:之前开发TCP协议的程序(C#里是Socket为主)都是基于主机上只有一个IP的,后来项目里涉及到了主机需要同时连接内外和外网的情况,在该主机上部署着一套WCS系统和一套WMS系统:WCS系 ...
- LdA笔记
LDA算法最初的论文使用的是变分EM方法训练(Variational Inference).该方法较为复杂,而且最后训练出的topic主题非全局最优分布,而是局部最优分布.后期发明了Collapsed ...
- 小强 ROS 机器人教程
首先请您自行依据线标提示将小强接线连接好,完整结构如下两图所示: 小强是属于Turtlebot机器人.它由底盘.主机.Kinect相机(通过USB连接主机)组成,没有显示屏.如果要通过显示器查看主机的 ...
- noip第11课作业
1. 数字比较 定义一个函数check(n,d),让它返回一个布尔值,如果数字d在正整数n的某位中出现则返回true,否则返回false. 例如:check(325719,3)==true:ch ...
- C++ 引用 指针 使用举例
1. 请看下程序 inline void CScanLineFill::removeOldNodeAET(AET* &aetList, const float yCurrent) { AET* ...
- hdu 1348 凸包模板
http://acm.hdu.edu.cn/showproblem.php?pid=1348 造城墙问题,求出凸包加上一圈圆的周长即可 凸包模板题 #include <cstdio> #i ...