我正在为 OpenGL 开发一个可移植层(为 Linux 和 Windows 抽象了 glX 和 wgl 的东西)......无论如何,它有一种创建窗口的方法......如果你不传入父级,你会得到一个带框架的真实窗口......如果你传入一个父窗口,你会得到一个无边框、无框架的窗口......
这工作正常,只要我在 1 个线程上完成这一切......只要另一个线程尝试创建子窗口,应用程序就会在 win32 调用“CreateWindow()”中死锁。有任何想法吗?
我正在为 OpenGL 开发一个可移植层(为 Linux 和 Windows 抽象了 glX 和 wgl 的东西)......无论如何,它有一种创建窗口的方法......如果你不传入父级,你会得到一个带框架的真实窗口......如果你传入一个父窗口,你会得到一个无边框、无框架的窗口......
这工作正常,只要我在 1 个线程上完成这一切......只要另一个线程尝试创建子窗口,应用程序就会在 win32 调用“CreateWindow()”中死锁。有任何想法吗?
这不是一个真正的答案,但由于很多人似乎认为 Win32 禁止在父线程之外的其他线程中创建子线程,我觉得有必要发布一个相反的演示。
下面的代码演示了在属于不同进程的父级上创建子窗口。它接受一个窗口句柄值作为命令行参数,并在该父窗口上创建一个子窗口。
// t.cpp
#include <windows.h>
#include <stdio.h>
#define CLASS_NAME L"fykshfksdafhafgsakr452"
static LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch ( msg )
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int main( int argc, char* argv[] )
{
HWND parent = (argc >= 2) ? (HWND)strtoul(argv[1], 0, 0) : (HWND)0;
printf("parent: 0x%x\n", parent);
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
wc.lpszClassName = CLASS_NAME;
wc.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION + 1);
if ( !RegisterClass(&wc) )
{
printf("%d: error %d\n", __LINE__, GetLastError());
return 0;
}
const DWORD style = WS_CHILD | WS_VISIBLE;
HWND hwnd = CreateWindow(CLASS_NAME, L"Test", style, 50, 50, 100, 100,
parent, 0, wc.hInstance, 0);
if ( !hwnd )
{
printf("%d: error %d\n", __LINE__, GetLastError());
return 0;
}
MSG msg;
while ( GetMessage(&msg, 0, 0, 0) )
DispatchMessage(&msg);
return 0;
}
使用以下命令编译它(使用 MSVC 命令行环境):
cl /EHsc /DUNICODE /D_UNICODE t.cpp user32.lib
然后使用 Spy++ 或其他工具获取任何窗口的句柄值——例如记事本或您正在查看此站点的浏览器。假设它是 0x00001234。然后使用t.exe 0x1234
. 使用 Ctrl-C 终止 t.exe(或关闭控制台窗口)。
创建子窗口后,它可以通过SendMessage
. 但是,请注意,SendMessage
跨线程边界阻塞线程不像PostMessage
. 如果父窗口的线程正在等待子线程,而子线程试图创建一个父窗口在该线程中的窗口,那么它就是死锁。
一般来说,我认为跨线程建立父子关系不是一个好主意。它很容易造成死锁。
这里有很多回复说你不能尝试在不同的线程上拥有子窗口和父窗口,而是强调它不会工作。
如果是这样,当您尝试调用 CreateWindow 时,Windows 会设置一些保护措施并简单地失败。现在,肯定存在可能导致重大问题的线程耦合问题,但是,鉴于这些限制,这是受支持的方案。
这是一个有趣的问题:很多老派的 win32 人告诉我你不能这样做。在研究这个时,我发现了这个论坛:SendMessage()。我目前的理论是 CreateWindowEx() 必须向父窗口发送一条消息(通过 SendMessage(),因此它会阻塞)以请求存在的权限(或至少通知它的存在)......无论如何,只要父线程可以自由处理这些消息,一切正常......
窗口与创建它的线程相关联(更具体地说,与该线程的消息队列相关联)。父窗口不能驻留在与其子窗口不同的线程中。