2012-11-13 155 views
1

在Windows 8(64位)上爲64位應用程序調用CreateWindowExA時是否存在已知問題?在Windows 8(Pro 64位)上CreateWindowExA失敗

上下文:我正在使用FOX Toolkit(FOX STABLE 1.6.46)。當編譯並運行最簡單的Hello World示例(「hello」)時,FXWindow.cpp文件中的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

+1

當處理WM_NCCREATE時,DefWindowProc()是否返回FALSE? –

+0

@RemyLebeau:是的 - 它返回'FALSE'。 –

回答

2

我發現源問題:FOX不正確地定義窗口過程的函數簽名作爲

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

(與FXID typedef定義到void*),所以在64位的Windows,wParamlParam只有32位寬,而它們應該是64位。正確的功能簽名(使用FOX類型)是:

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

那麼爲什麼它在64位Windows中工作到Windows 7呢?爲MSDN says

WM_NCCREATElParam包含一個指針,它指向包含關於所創建的窗口信息的CREATESTRUCT 結構。 CREATESTRUCT的成員與CreateWindowEx函數的參數 相同。

恰巧在Windows 7(64位)和下面,該結構總是在下面4GB存儲器分配,並且即使該指針值被截斷爲32位,但它仍然指出到正確的位置。從Windows 8開始,該結構被分配到64位內存區域的任何位置,並截斷它可能會產生不正確的指針。

有一件事我不確定:CALLBACK__stdcall,參數從右到左被推入棧中。那麼,鑑於windproc的聲明不正確,是否仍在檢索正確的iMsghwnd參數?

+1

返回類型也是錯誤的。在x64上,前4個參數通過寄存器傳遞。 –

+0

正確 - 修正了這一點。所有關於現在通過的論點都清楚了。 –

1

我有同樣的問題。然後我使用不帶「A」的CreateWindowEx(..)函數解決它。這可能會對其他使用此功能的人有所幫助

0

確認:64位Windows 8.1不調用WM_CREATE(32位,但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,而WndProc又將這個指針與hwnd關聯起來。 希望將所有窗口相關的數據和函數打包到一個類中,並使代碼更好地結構化。 這個想法看起來很健壯,但我最終拒絕了。 原因是每個WndProc調用都調用GetWindowLongPtr()的代價。 在64位版本上,它是32位和〜70的〜100條指令。 替代方法是指向動態對象的靜態指針(或者如果WndProc服務多個對象實例,則可能是哈希表)。 也許這不是很好,但它運行得更快,並且即使WM_NCCREATE也會消失,它將繼續工作。