变不可能为可能 - .NET Windows Form 改变窗体类名(Class Name)有多难?续篇

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

最近相关工作

  最近一段时间,重新拾起以前比较熟悉的界面UI开发,由于需要,了解了一些 HOOK API 的知识。HOOK API C++ 已经有比较好的开源资源,MHookMinHook。而 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 }

最终效果

最后的最后

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

时间: 2024-10-13 11:15:22

变不可能为可能 - .NET Windows Form 改变窗体类名(Class Name)有多难?续篇的相关文章

.NET Windows Form 改变窗体类名(Class Name)有多难?

研究WinForm的东西,是我的一个个人兴趣和爱好,以前做的项目,多与WinForm相关,然而这几年,项目都与WinForm没什么关系了,都转为ASP.NET MVC与WPF了.关于今天讨论的这个问题,以前也曾深入研究过,只是最近有朋友问到这个问题,就再挖挖这个坟(坑). 一.类名是啥? 打开神器SPY++,VS2013 在[工具]菜单里: VS2013之前的VS版本,在[开始菜单]里: 打开SPY++,点击标注的按钮, 在打开的窗口上,把雷达按钮拖到你想查看的窗口,就可以看到它的类名了,下面就

C#通讯录——Windows Form Contact List

C#通讯录 Windows Form Contact List 主窗口 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Syste

windows form中将服务器端的文件保存到客户端

开发中常常遇到这样的问题:需要将服务器端的文件下载到客户端.这种情况分为两种,一种是windows环境,一种是web环境.前两天在winform开发中就遇到过这样一个问题,上网搜索后没有发现现成的demo,所以自己花费了一点时间,做了一个简单的文件保存的demo,分享如下: 首先需要写一个下载的方法,将其抽象为一个静态类,以方便调用,如下: public static class FileHelper { /// <summary> /// 下载服务器文件至客户端,Create By Wang

c#学习笔记之WPF Application和Windows Form Applications

一.WPF Application WPF使用XAML(extensible application markup language)可扩展应用程序标记语言,来进行页面的操纵,非常简便易懂. 下面一段代码,就是使用xaml语言对页面进行布局 <Window x:Class="WpfApplication1.Window1"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

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 on the link it would open up a web browser and display the desire website. In order to do so you will need to use the control LabelLink. 1. First drag

Liam的C# 学习历程(七):WPF(Windows Presentation Foundation)、Windows Form Applications

在今天的课堂中,老师向我们讲述了关于一些WPF(Windows Presentation Foundation)和Windows Form Applications的内容,接下来就让我们一起来复习一下: (一).WPF(Windows Presentation Foundation): WPF是一个重要运用于desktop手机开发方面.它使用到了一种XML的变形语言——XAML的语言(eXtensible Application Markup Language). 使用XAML开发人员可以对WP

C#之Windows Form Application与attribute

1. WPF是什么: Windows Presentation Foundation, 它提供了统一的编程模型.语言和框架,真正做到了分离界面设计人员与开发人员的工作, WPF由XAML( eXtensible Application Markup Language )语言编写. 2. Windows Form Project是由几个文件构成的:它们有不同的功能划分 3. 对于一个应用,最重要的就是对用户的各种events做出反应,那么监听器的实现就非常重要,而VS将监听器的设计界面化,我们只需

windows Form的使用

Form常用属性: BackgroundImage:设置背景图片 BackgroundImageLayout:用于组件背景图像布局 BackColor:获取或设置控件的背景色 Form常用事件的使用: private void Form1_Load(object sender, EventArgs e)//Form加载事件 { //result获得对话框的返回值 DialogResult result = MessageBox.Show("是否打开窗体", "提示"

如何用Web技术开发Windows Form应用

现在H5很热,很多互联网公司的产品都采用混合编程,其中各个平台客户端的“壳”为原生控件,但是内容很多都是Web网页,因此可以做出很多炫酷的效果.随着Node.js和Ionic等框架的出现,现在感觉JavaScript有一统Web.Mobile.PC三大平台应用开发的能力.在Windows Form 上,利用开源浏览器内核Chromium Embedded Framework (CEF),CEF可以实现C#调用JS,JS调用C#,可以很好的与Web进行应用交互.下面用一个简单的例子来说明. 1 新