对于64位应用程序,在Windows 8(64位)上调用CreateWindowExA是否存在已知问题?
背景:我正在使用FOX Toolkit(FOX STABLE 1.6.46)。在编译并运行最简单的 Hello World 示例(“hello”)时,文件FXWindow.cpp:1345中对CreateWindowExA
的调用将返回零HWND句柄(但是GetLastError()
不报告错误)。这只发生在一个特定的配置中:
OS | OS Platform | App compiled for | CreateWindowExA succeeds? |
Windows 7 | 32-bit | 32-bit | YES |
Windows 7 | 64-bit | 32-bit | YES |
Windows 7 | 64-bit | 64-bit | YES |
Windows 8 | 64-bit | 32-bit | YES |
Windows 8 | 64-bit | 64-bit | NO! (returns NULL) |
最后一次配置与CreateWindowExA
有什么不同吗?请注意,窗口过程在所有情况下都是相同的,并且它接收的消息如下:
WM_GETMINMAXINFO
(已转发至DefWindowProc
)WM_NCCREATE
(已转发至DefWindowProc
)在上一个配置中,它继续WM_NCDESTROY
,然后CreateWindowExA
返回NULL。
在所有其他配置中,WM_NCCALCSIZE
已发送,最后WM_CREATE
。
答案 0 :(得分:2)
我发现源问题:FOX错误地将窗口过程的函数签名定义为
long CALLBACK wndproc(FXID hwnd,unsigned iMsg,unsigned int wParam,long lParam);
(FXID
typedef为void*
),因此在64位Windows上,wParam
和lParam
只有32位宽,而它们应该是64位。正确的函数签名(使用FOX类型)是:
FXival CALLBACK wndproc(FXID hwnd,unsigned int iMsg,FXuval wParam,FXival lParam);
那么为什么它可以在64位Windows中运行到Windows 7?正如MSDN says:
lParam
的{{1}}包含指向CREATESTRUCT的指针 包含有关正在创建的窗口的信息的结构。 CREATESTRUCT的成员与the的参数相同 CreateWindowEx函数。
在Windows 7(64位)及以下版本中,该结构总是在4GB以下的内存中分配,即使指针值被截断为32位,它仍指向正确的位置。从Windows 8开始,该结构被分配在64位内存范围内的任何位置,截断它可能会产生不正确的指针。
我只有一点不确定:WM_NCCREATE
是CALLBACK
,参数从右到左被压入堆栈。因此,鉴于__stdcall
的声明不正确,它是否仍在检索正确的windproc
和iMsg
参数?
答案 1 :(得分:1)
我有同样的问题。然后我使用没有“A”的CreateWindowEx(..)函数解决了它。这可能对应该使用此功能的其他人有益
答案 2 :(得分:0)
确认:64位Windows 8.1不会调用WM_CREATE(32位,而是一位,如同32位和64位Windows 7)。 当消息循环不相关时,在CreateWindows *()下会发生这些麻烦。
32位地址的注释是公平的。 在以下代码中 SetWindowLongPtr(m_hWnd,GWLP_USERDATA,(LONG_PTR)this) LONG_PTR可能被错误地替换为Windows 7原谅的LONG,但Windows 8却没有。
幸运的是,WM_NCCREATE仍然被发送。
拦截WM_CREATE / WM_NCCREATE后,必须"返回DefWindowProc()",而不是"返回0"。
我使用这个机制将一个指针(CreateWindow()的最后一个参数)传递给我的WndProc,后者又将这个指针与hwnd相关联。 希望将所有与窗口相关的数据和函数打包到一个类中,并使代码更好地构造。 这个想法看起来很健壮,但最终我拒绝了。 原因是GetWindowLongPtr()的成本在每次WndProc调用时都会被调用。 它是32位上的约100条指令和64位版本上的~70条。 另一种方法是指向动态对象的静态指针(如果WndProc服务于多个对象实例,则可能是哈希表)。 可能不是很好,但它的工作速度更快,即使WM_NCCREATE也会消失,它也会继续工作。