win32的安全子类化

win32消息映射13-子类和超类 12 子类和超类 回顾SDK窗口创建的过程。首先注册一个类,这里重要的是类名和窗口的回调函数,然后调用CreateWindowEx创建窗口,创建时必须指定类名,实际上也是指定了窗口的回调函数。 windows操作系统内置了一些标准控件,供程序员使用。这些标准控件控件,不需要注册类名,系统已经帮你注册好,直接拿过来用就是了。比如按钮的类名是“BUTTON”,编辑框的类名是“EDIT”……,C... 阅读详情
原文标题:Safe Subclassing in Win32
作者:Kyle Marsh
MSDN技术组

点击此处查看原文

摘要

本文描述了Win32环境下的子类化,描述了它是如何工作的以及实现安全的子类化必须要遵循的规则。本文涵盖了实例子类化和全局子类化。而超类化则作为一个全局子类化的可选替代方案被介绍。
Win16Win32,子类化并没有发生特别显著的变化,但是,在Win32中,一个应用程序还是要遵守几个新的子类化规则。其中最重要(也是最明显的)就是一个应用程序不能子类化属于另一个进程的窗口或者类,除非有工作区提供给应用程序使用,否则这条规则不能被打破。

子类化的定义

子 类化是这样一种技术,它允许一个应用程序截获发往另一个窗口的消息。一个应用程序通过截获属于另一个窗口的消息,从而实现增加、监视或者修改那个窗口的缺 省行为。子类化是用来改变或者扩展一个已存在的窗口的行为、而不用重新开发的有效途径。想要获得那些预定义控件窗口类(按钮控件、编辑控件、列表控件、下 拉列表控件、静态控件和滚动条控件)的功能而又要修改它们的某些行为的一个便利的方法就是对它们进行子类化。例如,对于一个在对话框中的多行编辑框来说, 当用户按下Enter键时,对话框会关闭。通过对编辑控件子类化,一个应用程序就能拥有一个可以往文本中插入回车和换行,而同时又不会关闭对话框的编辑控件,应用程序不用为这个特殊的需要而去专门开发一个编辑控件。

子类化基础

创建一个窗口的第一步是填充一个WNDCLASS 结构,并调用RegisterClass 函数来注册一个窗口类。WNDCLASS 结构的其中一个成员是这个窗口类的窗口过程地址,当一个窗口被建立,32位版本的Microsoft Windows操作系统会取出WNDCLASS 结构中的窗口过程地址,并把它复制到一个新的窗口信息结构中。当一条消息被发往这个窗口时,Windows通过窗口信息结构中的这个地址调用这个窗口的窗口过程。为了子类化一个窗口,你要用一个新的窗口过程地址取代原窗口过程地址,从而使新的窗口过程可以接收发往原窗口过程的所有消息。
当一个应用程序子类化一个窗口时,它可对消息采取三种操作: (1) 把消息传递给原窗口过程; (2) 修改消息然后再传递给原窗口过程; (3) 不再往下传递消息。
应用程序子类化一个窗口时,可以决定什么情况下对所接收的消息做出反应,应用程序可以在将消息传递给原窗口过程之前或(和)之后处理这条消息。

子类化的类型

有两种子类化的类型,它们是实例子类化全局子类化.

实例子类化是子类化一个独立的窗口信息结构,在实例子类化后,只有属于一个特定的窗口实例的消息会被发送到新窗口过程。
全局子类化是替换一个窗口类的WNDCLASS 结 构中的窗口过程地址,所有在这之后使用该窗口类建立起来的窗口都具有这个被替换的窗口过程地址。全局子类化只对那些在子类化生效之后创建的窗口有效,在进 行子类化之前,如果已经存在任何用这个被全局子类化的窗口类创建的窗口,这些已经存在的窗口不会被子类化。如果应用程序想要使子类化对这些已经存在的窗口 生效,应用程序必须子类化每一个已经存在的该窗口类的实例。

Win32子类化规则

有两条规则应用到Win32下的实例子类化和全局子类化。

子类化仅被允许用在进程内,一个应用程序不能子类化属于另一个进程的窗口或窗口类。

这条规则的起因很简单:Win32进程具有独立的进程地址空间。在一个特定的进程里,一个窗口过程有一个地址,而在另一个不同的进程里,这个地址值并未指向这个窗口过程,结果就是,在一个进程中,使用从另一个进程获得的地址替换后的地址并不能获得期望的结果,因此32位的Windows不允许这种地址替换发生。SetWindowLong 和SetClassLong 函数中防止了这种类型的子类化发生。你不能子类化属于另一个进程的窗口或窗口类,你能做的就到此为止。

不过,也还是有些途径能让你把子类化的功能用到每一个进程上。只要能得到位于某个进程地址空间里的某个函数,你就能该进程里的任何东西进行子类化。有几个方法可以达到这个目的,其中最容易(也是最不讲理的)的一个方法就是在下面这个注册表键中添加一个动态链接库名称:
HKEY_LOCAL_MACHINE/Software/Microsoft/Windows NT/CurrentVersion/Windows/APPINIT_DLLS

这个键导致Windows把你的DLL附加到系统里的每一个进程上。你的DLL需要一些能在它要子类化的事件发生时被唤醒的方法,通常一个WH_CBT钩子可以实现。这个DLL可以监视HCBT_CREATEWND 事件,然后子类化它想子类化的窗口。例子程序CTL3D就使用了WH_CBT钩子去实现它的子类化,尽管它没有使用注册表键为每个进程实现子类化,想要得到CTL3D功能的应用程序可以把他链接到进程里。

另一个把你的子类化代码附加到每个进程的方法是使用一个系统钩子。当一个系统钩子在另一个进程的上下文中被调用时,系统就把包含这个钩子的DLL加载到这个进程空间中。样例CTL3D 的代码按照使用当前线程中本地WH_CBT 钩子的方式使用系统WH_CBT 钩子。

第三个把子类化代码附加到另一个进程方法更复杂:它使用OpenProcess, WriteProcessMemory和 CreateRemoteThread 函数将代码注入其它进程。我并不推荐这个方法,并且不打算更详细地介绍怎么实现这个方法。如果有人坚持要使用这个方法, Jeffrey Richter 曾说过他计划在Microsoft Systems Journal 中他的一个即将开辟的Win32 Q&A专栏中描述这项技术。

现在很多Windows 3.1的应用程序子类化其它进程来扩展操作和增加一些很酷的功能。当Windows转向一个面向对象的系统时,对象链接和嵌入技术(OLE)提供了更好的办法去实现这些功能。在Windows的未来版本中,子类化其它进程可能会变得更加困难,而使用OLE也许会更容易。我推荐的是,只要可能,你应该让你的应用程序转向OLE,而不要子类化其它进程。

子类化操作不要直接使用原窗口过程地址。

在Win16中,一个应用程序会去使用从SetWindowLong 或 SetClassLong函数返回的窗口过程地址来直接调用窗口过程,毕竟返回值只是一个简单的指向函数的指针,为什么不使用它呢?在Win32中,这种做法却是个禁忌。SetWindowLong 或 SetClassLong函数的返回值可能根本不是原窗口过程的指针。Win32可能会返回指向一个数据结构的指针,该数据结构能被用来调用当前的窗口过程。这种情况发生在Windows NT中,当一个应用程序用一个非Unicode的窗口过程子类化一个Unicode窗口时,或者用一个Unicode的窗口过程子类化一个非Unicode窗口时。在这两种情况下, 操作系统必须为窗口收到的消息执行一个Unicode和ANSI之间的转换。如果应用程序直接使用指向这个结构的指针调用窗口过程,应用程序会立即导致一个异常。使用SetWindowLong 或 SetClassLong函数返回的窗口地址的唯一做法是将返回值作为参数调用CallWindowProc 函数。

实例子类化

SetWindowLong函数用来子类化一个窗口的一个实例。应用程序必须知道子类化函数的地址,子类化函数是这样一个函数:它用来接收从Windows发来的消息,并把消息传递给原窗口过程。子类化函数必须在应用程序中或DLL的模块定义文件中导出。

应用程序子类化窗口时,使用将要被子类化的窗口的句柄、GWL_WNDPROC标志(WINDOWS.H中定义)以及新的子类化函数地址作为参数调用函数 SetWindowLong 函数SetWindowLong返回一个DWORD类型的值,它是窗口的原窗口过程地址,应用程序应该保存该地址以用于将截获的消息传递给原窗口过程,以及将来为窗口移除子类化之用。应用程序使用原窗口过程的地址以及Windows消息所使用的hWnd, Message, wParamlParam 参数调用函数CallWindowProc 向原窗口过程传递消息。通常应用程序只是简单地把它从Windows接收来的数据传递给函数CallWindowProc

应用程序同时需要原窗口过程地址来为窗口移除子类化。应用程序通过再次调用函数SetWindowLong 来为窗口移除子类化,应用程序向函数传递原窗口过程地址、GWL_WNDPROC 标志以及已经被子类化的窗口的句柄。

下面的代码演示子类化一个编辑框控件以及为它移除子类化:

LONG FAR PASCAL SubClassFunc(HWND hWnd,UINT Message,WPARAM wParam,LONG lParam);

FARPROC lpfnOldWndProc;
HWND hEditWnd;

//
// Create an edit control and subclass it.
// The details of this particular edit control are not important.
//

hEditWnd = CreateWindow("EDIT", "EDIT Test",
   WS_CHILD | WS_VISIBLE | WS_BORDER ,
   0, 0, 50, 50,
   hWndMain,NULL,hInst,NULL);

//
// Now subclass the window that was just Created.
//

lpfnOldWndProc = (FARPROC)SetWindowLong(hEditWnd,GWL_WNDPROC, (DWORD) SubClassFunc);

.
.
.

//
// Remove the subclass for the edit control.
//

SetWindowLong(hEditWnd, GWL_WNDPROC, (DWORD) lpfnOldWndProc);

//
// Here is a sample subclass function.
//

LONG FAR PASCAL SubClassFunc(HWND hWnd,
   UINT Message,WPARAM wParam,LONG lParam)
{
   //
   // When the focus is in an edit control   inside a dialog box, the
   //  default ENTER key action will not occur.
   //
   if ( Message == WM_GETDLGCODE )
       return DLGC_WANTALLKEYS;

   return CallWindowProc(lpfnOldWndProc, hWnd, Message, wParam,lParam);
}


潜在的缺陷

只要留意下面的保障规则,实例子类化通常是安全的。

当子类化一个窗口时,你必须了解谁在对窗口的行为负责,例如,Windows负 责它所提供的所有控件的行为,而应用程序则对它自己定义的所有窗口负责。子类化可以作用在同一进程中的任何一个窗口上,但是,当一个应用程序子类化一个不 属于它自己负责的窗口时,应用程序必须确保子类化函数不会破坏那个窗口原有的行为。由于应用程序并未控制那个窗口,它不应该依赖任何在未来很有可能会被窗 口的拥有者改变的窗口信息。除非确切地知道窗口附加字节或窗口类附加字节的含义以及原窗口过程如何使用它们,否则一个子类化函数不应该使用 它们。退一步说,即使应用程序了解关于窗口附加字节或窗口类附加字节的每一件事,除非应用程序负责这个窗口,否则也不要使用它们。如果一个应用程序使用了 由另一个组件负责的窗口的窗口附加字节,当那个组件决定更新窗口并且改变附加字节的结构时,子类化过程很有可能会失败。正是因为这个原因,Microsoft 建议你不要子类化控件类,因为Windows负责着这些它所提供的控件,而且下一个版本的Windows可能会改变这些控件的外观。如果你的应用程序必须子类化一个Windows提供的控件,在新版本的Windows发布后,代码很可能也需要更新。

由于实例子类化发生在一个窗口被创建之后,应用程序子类化窗口无法向窗口添加任何附加字节,应用程序也许需要将被子类化的窗口的实例所需的所有数据保存在窗口的属性列表中。

SetProp函数可以把属性附加到一个窗口。应用程序使用窗口的句柄、一个标示属性的字符串和属性数据的句柄作为参数调用SetProp函数。数据的句柄通常从调用LocalAlloc GlobalAlloc 函数获得。当应用程序要使用一个窗口的属性列表中的这些数据时,可以使用窗口的句柄和标示属性的字符串作参数调用GetProp函数,它返回用SetProp函数设置的数据的句柄。当应用程序不再需要这些数据或者当窗口将要被销毁时,应用程序必须使用窗口的句柄和标示属性的字符串作参数调用RemoveProp函数从属性列表中移除这些属性数据,该函数返回数据的句柄,然后应用程序使用该句柄调用函数LocalFree 或函数GlobalFree 关于函数SetProp, GetPropRemoveProp的更多信息,参见平台SDK文档。

当一个应用程序子类化一个已经被子类化过的窗口时,所有的子类化会被按照们被设置时的相反顺序移除。

全局子类化

全局子类化类似于实例子类化。应用程序通过调用函数SetClassLong对一个窗口类进行全局子类化,就象在实例子类化中一样,应用程序同样需要子类化函数的地址,并且这个子类化函数必须在应用程序中或DLL的模块定义文件中导出。

要全局子类化一个窗口类,应用程序必须拥有一个该类的窗口实例。想要获得该类的窗口实例,大多数应用程序采 取建立一个属于将要被全局子类化的窗口类的窗口的方法,当应用程序要移除子类化,也必须有一个窗口句柄,该句柄应该是属于应用程序要子类化的窗口类的,因 此,为此而专门创建并保存一个窗口是个不错的办法。如果应用程序需要创建它所要子类化的窗口类的窗口实例,这个窗口实例通常应该是不可见的。在拥有了一个 正确类型的窗口句柄之后,应用程序可以使用该窗口句柄、GCL_WNDPROC 标志(在WINDOWS.H 中有定义)和新子类化函数的地址作为参数调用函数SetClassLong ,该函数返回一个DWORD 值,该值是该窗口类的原窗口过程地址。原窗口过程地址在全局子类化中的用处和在实例子类化中一样,窗口消息也象在实例子类化中一样通过调用函数CallWindowProc传递给原窗口过程。应用程序可以通过再次调用SetClassLong函数来从窗口类移除子类化,这时需通过传递参数是原窗口过程地址、GCL_WNDPROC 标志和被子类化的窗口类的窗口实例句柄。全局子类化一个控件的应用程序必须在应用程序结束时移除所做的子类化。

下面的代码演示了全局子类化一个编辑框控件以及为它移除子类化:

LONG FAR PASCAL SubClassFunc(HWND hWnd,UINT,Message,WORD wParam,LONG lParam);
FARPROC lpfnOldClassWndProc;
HWND hEditWnd;

//
// Create an edit control and subclass it.
// Notice that the edit control is not visible.
// Other details of this particular edit control are not important.
//
hEditWnd = CreateWindow("EDIT", "EDIT Test",
                        WS_CHILD,
                        0, 0, 50, 50,
                        hWndMain,
                        NULL,
                        hInst,
                        NULL);

lpfnOldClassWndProc = (FARPROC)SetClassLong(hEditWnd, GCL_WNDPROC, (DWORD)SubClassFunc);
.
.
.
//
// To remove the subclass:
//
SetClassLong(hEditWnd, GWL_WNDPROC, (DWORD) lpfnOldClassWndProc);
DestroyWindow(hEditWnd);

潜在的缺陷

全局子类化具有和实例子类化一样的限制,除非明确知道原窗口过程如何使用窗口类和窗口实例的附加字节,否则应用程序不应尝试去使用它们。如果数据必须和一个窗口相关联,可以象实例子类化中介绍的一样,使用窗口属性列表。

在Win32中, 全局子类化不会对任何其它进程中的窗口类或从这些类创建的窗口实例生效,这对于Win16环境是个重大的变化。在系统中,Windows分别为每个Win32进程单独保存窗口类的信息,可以参见MSDN中的技术文章Window Classes in Win32来了解Windows在这方面的细节。目前全局子类化不能对其它进程生效,这对开发人员来讲,是个有用的技术。在Win16中, 全局子类化对被子类化的窗口类的每一个窗口实例都生效:不仅仅是属于执行了子类化操作的应用程序,还包括了属于整个系统的,这点让人感到失望。通常这是应 用程序不想达到的效果,所以应用程序不得不使用更不方便,不好用的方法来改变从系统窗口类创建的窗口实例行为。而现在,在Win32中,使用全局子类化却是非常容易的。

超类化

子类化一个窗口类,导致原本属于窗口过程的消息被发送至子类化函数,然后该子类化函数再把消息传递给原窗口 过程,而超类化(也被称作窗口类克隆)是创建一个新的窗口类。这个新窗口类使用一个已经存在的窗口类的窗口过程,来为它自己添加和已经存在的窗口类一样的 功能,超类化是基于其它窗口类的――也被称为基类。基类常常是Windows预定义的控件类,但它也可以是任何其它窗口类。

注意   不要超类化滚动条控件类,因为Windows 使用该类名来为滚动条提供标准的行为。

超类化拥有它自己的窗口过程――超类化过程,它能起和子类化函数一样的作用。超类化过程可以对消息实施三种动作: (1)直接将消息传递给原窗口过程 。(2)在传递给原窗口过程前修改消息。 (3)不在往下传递消息。超类化可以在把消息传递给原窗口过程之前、之后或两者都有的情况下对消息进行操作。

和子类化函数不一样的是,一个超类化过程也可以从Windows接收创建消息(例如WM_NCCREATE, WM_CREATE 之类的),超类化可以处理这些消息,但它必须把这些消息传递给原基类窗口过程,这样基类窗口过程才能进行初始化操作

应用程序调用函数GetClassInfo 来使一个超类化基于一个基类。函数GetClassInfo 使用从基类的WNDCLASS 结构得来的值填充一个新WNDCLASS结构。然后超类化基类的应用程序把新WNDCLASS结构的hInstance域的值设置成应用程序自己的实例句柄,同时也必须把lpszClassName域的值设置成它要给该超类化的新名称。如果基类拥有一个菜单,超类化该基类的应用程序必须提供一个新菜单,该新菜单必须和基类的菜单拥有相同的菜单标识。如果该超类化打算处理WM_COMMAND消息的,并且不再把该消息传递给基类的窗口过程, 那么菜单的标识可以不必和基类的一样。函数GetClassInfo 不会返回WNDCLASS结构中域 lpszMenuName, lpszClassName, hInstance 的值。

最后一个必须在超类化的WNDCLASS 结构中设置的是域lpfnWndProc,函数GetClassInfo 用原窗口过程的地址填充它。应用程序必须保存这个地址,以便能用函数CallWindowProc把消息传递给基类的窗口过程。应用程序要在WNDCLASS 结构中把该地址值设置成它的超类化过程的地址。这个地址并不是个过程实例地址,因为函数RegisterClass 才能得到过程实例地址。应用程序可以修改WNDCLASS 结构中其它域的值,以便符合应用程序的需要。

应用程序可以往窗口类附加字节和窗口实例附加字节后添加内容,这是因为它注册了一个新窗口类。当应用程序做这件事时,必须遵从两个规则: (1) 原类附加字节和窗口实例附加字节不能被子类化覆盖,这和在实例子类化与全局子类化中的原因一样。(2) 如果应用程序因自身需要为窗口类或窗口实例添加了附加字节,它在引用这些附加字节时,必须保持是相对于基类所使用的附加字节数来引用的。而且因为某个版本的基类所使用的附加字节数可能会与下一个版本不同,所以超类化自己的附加字节的起始偏移也因基类版本不同而不同。

当填充完WNDCLASS 结构后,应用程序应该调用函数RegisterClass 来注册新的窗口类,现在,就可以创建并使用属于该新窗口类的窗口实例了。

应用程序通常是在Win16环境下使用超类化,因为在Win16环境下全局子类化是令人沮丧的。现在在Win32下, 全局子类化不再令人失望,所以超类化就不再那么具有吸引力了。但在你的应用程序要改变一些窗口的行为,而这些窗口又只是从一个系统窗口类所创建的所有窗口 中的一部分时,你仍然可以发现使用超类化是很有用的,相反,对从一个系统窗口类所创建的所有窗口都有效,那是全局子类化的功能。

总结

子类化是个强大的技术,而且在Win32中的使用也没有发生什么特别重大的改变,唯一的比较主要的变化是你不能再属于另一个进程的窗口或窗口类,虽然有方法可以绕过这个限制,如果你确实需要这种能力,我还是建议你把你的应用程序移植到OLE,这比仍然依赖子类化更好。

好了,至此整篇文章都翻译完了(终于赶在放假前弄完了),在Win32中安全的子类化(1)中,提供了本文的英语原文的链接,由于本人时间、水平有限,所以欢迎大家指正文中的错误和疏漏之处,谢谢!



 
Win32 SDK Gui编程系列之--Win32API 控件的子类 WM_KEYDOWN消息中的VK_RETURN用包装器的EditWindowProc函数处理,默认的EDIT控件的WindowProc函数没有传递消息。将设置为全局变量的默认WindowProc函数的地址作为第1个参数,之后和DefWindowProc函数一样,排列参数,调用CallWindowProc函数。代替这个默认的WindowProc函数,可以自己准备WindowProc函数来处理给控件的信息。但是,大部分的消息处理都交给默认的WindowProc函数,所以自己的WindowProc函数是包装器。 阅读详情

相关推荐

Win32子窗口控件:从消息机制到实战调试的底层GUI编程指南

在桌面应用开发中,GUI编程的核心在于理解窗口与消息机制。Win32 API作为Windows系统的底层图形接口,其核心哲学是“一切皆窗口”,每个控件(如按钮、编辑框)本质上都是一个拥有独立句柄(HWND)和窗口过程(WndProc)的窗口对象。通过消息循环,系统在用户操作(如点击、输入)与控件行为间建立桥梁,实现交互。掌握这一原理,不仅能深入理解Windows GUI的工作机制,更能为高性能、高定制专业工具开发及复杂UI问题排查提供底层支持。在实际工程中,诸如按钮点击无响应、滚动条异常等常见问题,往往源

weixin_28828243的博客 277

Duilib中的子类

具体到DirectUI,我们要想使用我们自定义的窗口过程,同样需要子类: HWND CWindowWnd::Subclass(HWND hWnd) {     ASSERT(::IsWindow(hWnd));   //判断给定的句柄是否是一个已经存在的窗口     ASSERT(m_hWnd==NULL);     m_OldWndProc = SubclassWindow(

Marcelxx的专栏 1366

Win32窗口API核心解析:从消息驱动到实战优

Windows桌面开发领域,消息驱动模型是图形用户界面(GUI)程序的核心架构。其基本原理是系统通过消息队列(Message Queue)与应用程序通信,窗口过程(Window Procedure)作为消息处理中枢,决定了程序的响应逻辑与行为。深入理解这一机制,对于实现高性能、高稳定性的客户端软件具有关键价值,尤其在处理复杂界面交互、定制控件以及性能优等场景下不可或缺。本文聚焦于**窗口生命周期管理**与**消息循环优**,通过剖析CreateWindow、消息分派等核心API,并结合双缓冲、子类

weixin_42116058的博客 304

MFC-- 子类控件

首先讲讲什么是子类,其实子类很好理解,和以前一样,仍然从win32 sdk方法开始,在这里也可以补充一下,我在一些群里的见到有些人关于MFC的说法,说直接就学MFC就可以了,没必要学win32,有的人把MFC说的很简单似的,其实不然,由于MFC对底层的隐藏和其复杂的框架,其实很多时候,我们学起来是很吃力的,而且,很多人照着一些编程书说的照着做,改来改去,最后做出来了,但是不知道其中的原理,当需

xinzhiyounizhiyouni的专栏 2706

Win32安全子类

关于子类的话题虽然有些旧,但它至今仍然不失为一种开发Windows的强有力技术,在MFC的内核、甚至.NET的内核中都离不开它,希望本连载能对Windows开发的爱好者有所帮助。 原文标题:Safe Subclassing in Win32 作者:Kyle Marsh MSDN技术组 点击此处查看原文 摘要 本文描述了Win32环境下的子类,描述了它是如何工作的以及

huasonl room 2776

Safe Subclassing in Win32(Win32中的安全子类)

Safe Subclassing in Win32(Win32中的安全子类)Kyle MarshMicrosoft Developer Network Technology GroupCreated: January 25, 1994译者:BBE&BFE大意    这篇文章描述了Win32®环境下的子类(subclassing)技术,它怎样实现,以及为了使子类安全而必须遵循的规则(rul

Y___Y的专栏 1734

深入解析Win32窗口子类技术与代码实例

窗口子类涉及定义一个新的窗口类,并将其实例附加到现有的窗口上。新窗口类通常继承自已存在的窗口类,但我们可以修改其窗口过程函数以改变其行为。以下是如何定义一个新窗口类的示例代码:// 定义新的窗口类名// 步骤1: 注册新的窗口类// 用自定义窗口过程替换默认窗口过程// 自定义窗口过程函数示例// 处理消息...在上述代码中,WndProc将作为新的窗口过程函数,用于处理窗口消息。默认窗口过程通过函数被调用,以便处理未被自定义处理的消息。

weixin_35949153的博客 1169

Unity编辑器全局深色模式实现:Win32窗口子类DLL注入实战

Windows桌面应用开发中,Win32 API提供了对窗口行为的底层控制能力,其中窗口子类是一项关键技术,允许开发者拦截并自定义窗口消息处理流程。这项技术的核心价值在于能够在不修改原始程序源码的情况下,动态改变其界面行为,为软件界面定制提供了强大支持。在游戏开发领域,Unity编辑器作为广泛使用的开发环境,其Windows版本仍沿用传统的Win32窗口框架,导致系统标题栏与编辑器内部深色主题不协调。通过DLL注入技术结合窗口子类原理,可以精准定位Unity主窗口类名UnityContainerWn

weixin_30887919的博客 337

Flutter 三方库 win32_gui 的鸿蒙适配指南 - 掌握桌面端底层窗口控制、助力鸿蒙跨研发生态构建高效的桌面辅助工具与预览增强系统

在 OpenHarmony 鸿蒙跨平台应用(如基于 Flutter 的鸿蒙工程)的研发全生命周期中,“桌面端工具”的作用不可忽视。无论是在 Windows 宿主机上运行的鸿蒙 API 预览器增强组件,还是需要从鸿蒙端远程控制桌面窗口的特定业务,对原生 Win32 GUI 的深度操控都是硬核需求。win32_gui作为一个对 Windows 底层窗口 API 进行现代 Dart 封装的利器,旨在提供比原始 FFI 调用更安全、更具声明式特征的窗口治理框架。

Leo 2087

Win32 Tips and Tricks

Continuing on from the last part, here are more Win32 Tips and Tricks for you to browse.XP ThemesCommon-control manifests (which enable the XP themes) can be added to an executable in one of two w

vrix的专栏 1609

Win32对话框状态自动保存:基于窗口属性与反射机制的C++库实现

在桌面应用开发中,状态持久是提升用户体验的关键技术,它确保用户界面设置能在会话间得以保留。其核心原理通常基于序列与反序列机制,将控件状态转为可存储的数据格式。这项技术的核心价值在于减少用户重复操作,提升软件的专业性和易用性,广泛应用于配置工具、设计软件等需要复杂交互的场景。本文聚焦于一个高效的C++解决方案,通过窗口属性(Window Property)和反射机制,实现了对复选框、编辑框、列表框等控件的自动状态管理。该方案特别适用于Win32/MFC项目,能显著降低开发维护成本,其非侵入式设计允许

weixin_33724570的博客 616

Win32子类与超类

大家都知道,MS提供了很多丰富的控件(也叫窗体),但有些控件在实际的应用中可能还是不能满足要求,比如说,我想让BUTTON点击时变成另一种外观,我们怎么做呢?要改变外观就只能重新进行绘制,肯定就需要在HWND的WM_PAINT消息里面处理,问题是我们怎么才能得到这个HWND的消息呢?每一个窗体都是通过CreateWindow来创建的,在创建之前,都会注册一个类,这个类就相当于是模板,当然有些是系统

永远即等待的专栏 2741

解说Win32的窗口子类

也许你需要一个特殊的Edit来限制浮点数的输入,但是现有的Edit却并不能完成这项工作——因为它只能够单纯的限制大小写或者纯数字。当你在论坛上求救的时候,某个网友告诉你:“用子类。”你也许会在看到一线曙光的同时多出了一连串的问题:何为子类子类的原理是什么?如何实现子类?下面就让我从一个简单的C++程序开始,一步步解开你的疑团吧。  首先,我为你列出以下这个C++程序:#include

清清湖水 1125

窗口子类实现自绘按钮如此简单

有没有发现利用createwindow创建按钮感觉太单调,msdn上说的owndraw 按钮太复杂,其实子类按钮,可以很方便的实现自绘按钮,只需要会点贴图知识就行了。 下面采用gdi+贴图:(关于gdi+环境的搭建我在前面的章节里已经介绍了)   第一步: WNDPROC Button1Proc;  LRESULT CALLBACK ButtonProc1(HWND hwnd,UINT

在梦中享一刻静谧,等待梦中的你 4351

WIN32汇编: 20.窗口子类

第二十课 窗口子类在这一讲,我们将学习什么是窗口子类和怎样按你所想要的方式方便地使用它。理论:如果你曾经在 Windows 环境下编过程序,有时候就会发现:有一个现成的窗口,几乎有你所需要的全部功能,但还不完全一样(否则就没有必要讲这一节了)。你曾遇到过这样的处境吗,如果你需要一个具有过滤特殊字符功能的 Edit 控件。当然最直接的方法就是自己用代码来实现,但这的确是一个费

GodDragon的专栏 2257

Win32汇编教程七 控件的子类

--------------------------------------------------------------------------------有关控件子类说到类,大家可能马上就想到C++,的确,类首先是在C中提出的,但是,这个概念在 Win32Asm 中仍然适用,因为在类的思路是这样的:先假设某个对象有不同的属性,当一个新的对象的某个属性和上面所说的对象有些不同,而别的属性一模

蝈蝈俊.net 4892

WIN32窗口子类----自定义Edit控件的右键菜单

前言 Win32应用程序中,子控件的消息都是分发到其父窗口的消息处理函数中去了,这对于我们需要自定义子控件的某些特性时时十分不方便的,还好,Windows为我们提供了控件子类的相关接口API。核心的思想是:通过获取子控件的消息处理函数地址,设置子控件的消息处理函数到自己定义的函数里,也就是Get/SetWindowLong API的使用。 测试代码 这里是一个

https://github.com/JelinYao 5248
上一篇: Ubuntu全程安装配置手册
下一篇: 如何在DC上创建一个半透明的矩形
AlfredLu
博客等级 码龄20年 14粉丝 19原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值