Win7下RegisterClassEX失败问题
问题
在参考WebRTC(对应代码为webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
)实现基于放大镜接口(Magnification API)的屏幕画面采集时,遇到了一个仅在Win7下出现的bug。日志显示Win7 32位下调用RegisterClassEX
会失败,返回错误0x87,表示参数非法。
分析
报错函数上下文代码片段如下:
1 | WNDCLASSEXW wcex = {}; |
根据报错,我们可以猜测是wcex
结构体中的某个参数非法,进一步查看WNDCLASSEX
结构体的定义,排查了其他几个参数后都没有发现问题,最后只剩下lpfnWndProc
和hInstance
则两个参数比较可疑。参考WNDCLASSEXA文档,hInstance
表示lpfnWndProc
所在模块的句柄。这里我们使用了系统提供的DefWindowProc
,和WebRTC做法一致,因此同样的参考WebRTC,我们通过GetModuleHandleExA
来获取对应的hInstance
,即
1 | HMODULE hInstance = nullptr; |
但排查过程中找到一篇What is the HINSTANCE passed to CreateWindow and RegisterClass used for?,详细解释了hInstance的作用。hInstance实际是用来区分不同模块中可能相同名称的窗口类的,因此猜测这里应该传入当前使用的窗口类所在的模块句柄。我们这里使用的是自己创建的窗口类,因此应该传入当前模块的句柄。于是在当前模块中实现自定义的窗口过程函数,并通过其地址获取当前模块句柄,将这两个值作为参数传入,问题解决。
1 | void Init{ |
实测后发现WNDCLASSEX
结构体中的lpfnWndProc
设置为DefWindowProc
,而hInstance
设置为当前类所在模块依然可以初始化成功,进一步说明至少在Win7下,hInstance
并不表示窗口过程函数所在模块,而是窗口类所在模块。但由于Win10/11下并不存在问题,因此并不清楚是Win7下接口实现存在bug,还是官方文档有错误,最好的办法是将窗口过程函数和窗口类定义在同一模块,这样就绝对没有风险了。