变不可能为可能 - .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会抛出异常. 那 ...
随机推荐
- 实验 Attacks on TCP/IP Protocols
------- 转载请注明出处,博客园-lasgalen-http://www.cnblogs.com/lasgalen/p/4555648.html ------- 1 实验目的 进行这个实验的目的 ...
- c++ 博客资源
/************************************************************** 技术博客 http://www.cnblogs.com/itdef/ ...
- hibernate4 , spring3 使用 org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean 报错 Implementing class
错误代码如下 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with ...
- Angular 通过注入 $location 获取与修改当前页面URL
//1.获取当前完整的url路径 var absurl = $location.absUrl(); //http://172.16.0.88:8100/#/homePage?id=10&a=1 ...
- CentOS里vim基本操作
1.关于退出 :wq! ----强制保存退出 :wq ---- 保存退出 :x ----- 作用和:wq 一样 ZZ ---- 作用和:wq一样,(注意Z是大写的,并且不是在命令模式) :q ...
- DB2 runstats、reorgchk、reorg 命令【转载】
1.runstats runsats可以搜集表的信息,也可以搜集索引信息.作为runstats本身没有优化的功能,但是它更新了统计信息以后,可以让DB2优化器使用最新的统计信息来进行优化,这样优化的效 ...
- Spring 集成 MemCache
1)xml <bean class="com.danga.MemCached.SockIOPool" factory-method="getInstance&quo ...
- Ubuntu16.04安装PostgreSQL并使用pgadmin3管理数据库_图文详解
版权声明:本文地址http://blog.csdn.net/caib1109/article/details/51582663 欢迎非商业目的的转载, 作者保留一切权利 apt安装postgresql ...
- ESP32应用程序的内存布局
应用程序内存布局 ESP32芯片具有灵活的内存映射功能.本节介绍ESP-IDF在默认情况下如何使用这些功能. ESP-IDF中的应用程序代码可以放置在以下内存区域之一中. IRAM(指令RAM) ES ...
- spring boot搭建Hello Word
一.安装与配置jdk 二.安装与配置maven 安装好maven,必须配置环境变量 通过cmd命令查询maven是否安装成功,以下是安装成功的界面 修改setting.xml的配置,制定本地仓库的路径 ...