变不可能为可能 - .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会抛出异常. 那 ...
随机推荐
- Codeforces 600A. Extract Numbers 模拟
A. Extract Numbers time limit per test: 2 seconds memory limit per test: 256 megabytes input: standa ...
- 人体感应模块控制LCD1602背景灯是否开启
/* Web client This sketch connects to a website (http://www.google.com) using an Arduino Wiznet Ethe ...
- python技巧31[python中使用enum][转]
以下几种方法来模拟enum:(感觉方法一简单实用) # way1 class Directions: up = 0 down = 1 left = 2 right =3 ...
- 红楼梦3d游戏
1. 红楼梦大观园2d图 2. 红楼梦3d图 潇湘馆 注册机:根据电脑名和时间生成一个id,然后根据注册机生成注册码.
- POJ2456 Aggressive cows 2017-05-11 17:54 38人阅读 评论(0) 收藏
Aggressive cows Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 13993 Accepted: 6775 ...
- MFC中和定时器使用
在MFC中和定时器相关的有三个函数: 1.设置定时器(定义一个定时器的属性): SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBAC ...
- delphi存取图片
1.存图片到数据库 var PicStream: TMemoryStream; if imgBugPic.Picture.Graphic <> nil then begin P ...
- C++ - explicit和volatile/const的内容
第一眼见到explicit和volatile可能会一愣一愣的觉得可能是c11或者c14新加的标识符. 其实不是这样,volatile和const两个关键字在C语言的第二个版本KR C的时候就被加入了C ...
- html5 app开发
如今html5技术越来越成熟,很多iPhone 及Android 上的移动APP都能用html5来开发完成.让我们一起来了解一下html5开发app. 一.HTML5框架开发的移动APP 编写开发游戏 ...
- CSharp程序员学Android开发---1.初识AndriodIDE,掌握工具使用
最近公司组织项目组成员开发一个Android项目的Demo,之前没有人有Andoid方面的开发经验,都是开发C#的. 虽说项目要求并不是很高,但是对于没有这方面经验的人来说,第一步是最困难的. 项目历 ...