winapi – 如何子类化win32控件并保持与旧版本的comctl32.dll的
通用控件的6.0版(comctl32.dll)实现了一种新方法,用于子类化旧版
Windows上不可用的控件.实现子类化的最佳方法是什么,以便它可以在支持任一版本的公共控件库的系统上运行?
解决方法
首先,有一个
article on MSDN讨论了在您应该熟悉的版本6.0和之前的子类控件中发生的更改.
保持向后兼容性的最佳方法是为子类控件创建包装函数.这将要求您动态加载comctl32.dll版本6上的子类控件所需的函数.这是一个如何完成的粗略示例. typedef BOOL (WINAPI *LPFN_SETWINDOWSUBCLASS)(HWND,SUBCLASSPROC,UINT_PTR,DWORD_PTR); typedef LRESULT (WINAPI *LPFN_DEFSUBCLASSPROC)(HWND,UINT,WPARAM,LPARAM); typedef BOOL (WINAPI *LPFN_REMOVEWINDOWSUBCLASS)(HWND,UINT_PTR); typedef BOOL (WINAPI *LPFN_INITCOMMONCONTROLSEX)(LPINITCOMMONCONTROLSEX); typedef struct SubclassStruct { WNDPROC Proc; } SubclassStruct; LPFN_SETWINDOWSUBCLASS SetWindowSubclassPtr = NULL; LPFN_REMOVEWINDOWSUBCLASS RemoveWindowSubclassPtr = NULL; LPFN_DEFSUBCLASSPROC DefSubclassProcPtr = NULL; LPFN_INITCOMMONCONTROLSEX InitCommonControlsExPtr = NULL; HMODULE ComCtlModule = NULL; int Subclasser_Init(void) { INITCOMMONCONTROLSEX CommonCtrlEx = {0}; ComCtlModule = LoadLibrary("comctl32.dll"); if (ComCtlModule == NULL) return FALSE; SetWindowSubclassPtr = (LPFN_SETWINDOWSUBCLASS)GetProcAddress(ComCtlModule,"SetWindowSubclass"); RemoveWindowSubclassPtr = (LPFN_REMOVEWINDOWSUBCLASS)GetProcAddress(ComCtlModule,"RemoveWindowSubclass"); DefSubclassProcPtr = (LPFN_DEFSUBCLASSPROC)GetProcAddress(ComCtlModule,"DefSubclassProc"); InitCommonControlsExPtr = (LPFN_INITCOMMONCONTROLSEX)GetProcAddress(ComCtlModule,"InitCommonControlsEx"); if (InitCommonControlsExPtr != NULL) { CommonCtrlEx.dwSize = sizeof(CommonCtrlEx); InitCommonControlsExPtr(&CommonCtrlEx); } return TRUE; } int Subclasser_Uninit(void) { if (ComCtlModule != NULL) FreeLibrary(ComCtlModule); return TRUE; } LRESULT CALLBACK Subclasser_SharedSubclassProc(HWND hWnd,UINT Message,WPARAM wParam,LPARAM lParam,UINT_PTR SubclassId,DWORD_PTR RefData) { SubclassStruct *Subclass = (SubclassStruct *)SubclassId; return CallWindowProc(Subclass->Proc,hWnd,Message,wParam,lParam); } int Subclasser_SetProc(HWND hWnd,WNDPROC Proc,WNDPROC *OriginalProc,void *Param) { SubclassStruct *Subclass = NULL; int Result = TRUE; SetLastError(0); if (SetWindowLongPtr(hWnd,GWLP_USERDATA,(__int3264)(UINT_PTR)Param) == 0) { if (GetLastError() > 0) return FALSE; } if (SetWindowSubclassPtr!= NULL) { Subclass = (SubclassStruct*)malloc(sizeof(SubclassStruct)); Subclass->Proc = Proc; *OriginalProc = (WNDPROC)Subclass; Result = SetWindowSubclassPtr(hWnd,Subclasser_SharedSubclassProc,(UINT_PTR)Subclass,NULL); } else { *OriginalProc = (WNDPROC)(void *)GetWindowLongPtr(hWnd,GWLP_WNDPROC); SetLastError(0); if (SetWindowLongPtr(hWnd,GWLP_WNDPROC,(__int3264)(intptr)Proc) == 0) { if (GetLastError() > 0) Result = FALSE; } } if (Result == FALSE) return FALSE; return TRUE; } int Subclasser_UnsetProc(HWND hWnd,WNDPROC *OriginalProc) { SubclassStruct *Subclass = NULL; int Result = TRUE; if (RemoveWindowSubclassPtr != NULL) { if (*OriginalProc != NULL) { Subclass = (SubclassStruct *)*OriginalProc; Proc = Subclass->Proc; } Result = RemoveWindowSubclassPtr(hWnd,(UINT_PTR)Subclass); free(Subclass); } else { SetLastError(0); if (SetWindowLongPtr(hWnd,(__int3264)(UINT_PTR)*OriginalProc) == 0) { if (GetLastError() > 0) Result = FALSE; } } SetLastError(0); if (SetWindowLongPtr(hWnd,0) == 0) { if (GetLastError() > 0) Result = FALSE; } *OriginalProc = NULL; if (Result == FALSE) return FALSE; return TRUE; } LRESULT Subclasser_DefProc(WNDPROC OriginalProc,HWND hWnd,LPARAM lParam) { if (OriginalProc == NULL) return DefWindowProc(hWnd,lParam); if (DefSubclassProcPtr != NULL) return DefSubclassProcPtr(hWnd,lParam); return CallWindowProc(OriginalProc,lParam); } 唯一的另一个例子可以在OpenJDK中找到.它的一个缺点是它使用WindowProc作为子类ID,如果你在具有相同WindowProc函数的对话框上继承多个控件,它将崩溃.在上面的示例中,我们分配一个名为SubclassStruct的新内存结构,并将其地址作为子类ID传递,以保证子类控件的每个实例都具有唯一的子类ID. 如果您在多个应用程序中使用子类化函数,则有些使用comctl32.dll< 6和一些使用comctl32.dll> = 6,你可以通过获取comctl32.dll的文件版本信息来检测加载了哪个版本的公共控件库.这可以通过使用GetModuleFileName和GetFileVersionInfo来完成. 另外,如果你在comctl32.dll 6.0的子类回调中使用SetWindowWord / GetWindowWord,例如在下面的Dobbs博士文章中 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- windows-services – 使用pscp.exe时跳过主机检查
- 在没有安装JRE的Windows中将java程序作为exe运行
- Windows防火墙,Tinywall和GIT
- 为什么将`uint8_t`赋值给`uint8_t`会给出转换警告?
- windows-server-2008 – 适用于Windows Server 2008的远程桌
- windows-services – Play 2.0 – 在服务器重启后作为Windo
- windows – 重新安装操作系统时软件raid是否中断?
- .net core 3.0 WPF中使用FolderBrowserDialog
- windows-update – Windows Server 2016中的“延迟功能更新
- 在Windows上的80端口上运行node.js webbapp
- windows-server-2008 – 跨海访问文件共享(通过V
- windows-server-2008 – Windows Server 2008和S
- 如何设置Squeak和Pharo的主窗口标题?
- windows – 批处理脚本使其他批处理文件访问setl
- Windows Phone 7手动启动 – WP7手动启动
- Microsoft SQL Server 不同系统版本支持和下载说
- 在DOS / FAT中缩小或部分截断文件
- windows – 如何识别哪个bitlocker保护器处于活动
- windows-server-2003 – 从死Windows域控制器中获
- 在windows server 2012 R2上安装sql server 2017