1

在 Windows 8(64 位)上为 64 位应用程序调用 CreateWindowExA 是否存在已知问题?

背景:我正在使用FOX 工具包(FOX STABLE 1.6.46)。在编译和运行最简单的Hello World示例(“hello”)时,对CreateWindowExA文件 FXWindow.cpp:1345 中的调用返回零 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

4

3 回答 3

2

我找到了根源问题:FOX 错误地将窗口过程的函数签名定义为

long CALLBACK wndproc(FXID hwnd,unsigned iMsg,unsigned int wParam,long lParam);

FXIDtypedef'd to void*),所以在 64 位 Windows 上,wParam只有lParam32 位宽,而它们应该是 64 位。正确的函数签名(使用 FOX 类型)是:

FXival CALLBACK wndproc(FXID hwnd,unsigned int iMsg,FXuval wParam,FXival lParam); 

那么为什么它可以在 64 位 Windows 到 Windows 7 中工作呢?正如MSDN 所说

lParamof包含一个指向 CREATESTRUCT 结构的WM_NCCREATE指针,该结构包含有关正在创建的窗口的信息。CREATESTRUCT 的成员与 CreateWindowEx 函数的参数相同。

碰巧在 Windows 7(64 位)及更​​低版本上,该结构始终分配在 4GB 以下的内存中,即使指针值被截断为 32 位,它仍然指向正确的位置。从 Windows 8 开始,该结构被分配在 64 位内存范围内的任何位置,截断它可能会产生不正确的指针。

只有一件事我不确定:CALLBACK作为__stdcall,参数从右到左被推入堆栈。那么,鉴于 的 声明不正确windproc,它是否仍在检索正确的iMsghwnd参数?

于 2012-11-14T09:19:40.590 回答
1

我有同样的问题。然后我使用没有“A”的 CreateWindowEx(..) 函数解决了它。这可能对应该使用此功能的其他人有益

于 2015-09-17T14:54:53.063 回答
0

确认:64 位 Windows 8.1 不调用 WM_CREATE(而 32 则调用 WM_CREATE,就像 32 位和 64 位 Windows 7 一样)。当消息循环还无关紧要时,问题发生在 CreateWindows*() 下。

32 位地址的注释是公平的。在以下代码中,SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG_PTR)this) LONG_PTR 可能被错误地替换为 Windows 7 允许但 Windows 8 不允许的 LONG。

幸运的是,仍然发送了 WM_NCCREATE。

拦截 WM_CREATE/WM_NCCREATE 后,必须“返回 DefWindowProc()”,而不是“返回 0”。

我使用这种机制将一个指针(CreateWindow() 的最后一个参数)传递给我的 WndProc,而 WndProc 又将这个指针与 hwnd 相关联。希望将所有与窗口相关的数据和函数打包到一个类中,并使代码结构更好。这个想法看起来很强大,但我最终拒绝了。原因是每次 WndProc 调用都会调用 GetWindowLongPtr() 的成本。在 32 位版本上大约有 100 条指令,在 64 位版本上大约有 70 条指令。另一种方法是指向动态对象的静态指针(或者如果 WndProc 服务于多个对象实例,则可能是哈希表)。也许不是那么好,但它工作得更快,即使 WM_NCCREATE 也会消失,它也会继续工作。

于 2018-02-12T01:04:57.430 回答