1

私は OpenGL の移植性レイヤーに取り組んでいます (Linux と Windows の glX と wgl のものを抽象化します)...とにかく、ウィンドウを作成する方法があります...親を渡さない場合は、フレーム付きの実際のウィンドウ...親を渡すと、ボーダーレス、フレームレスのウィンドウが得られます...

1 つのスレッドですべてを実行する限り、これは正常に機能します...別のスレッドが子ウィンドウを作成しようとするとすぐに、アプリは win32 呼び出し「CreateWindow()」でデッドロックします。何か案は?

4

5 に答える 5

5

これは本当の答えではありませんが、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 を終了します (または単にコンソール ウィンドウを閉じます)。

于 2009-11-19T16:06:32.943 に答える
2

子ウィンドウが作成されると、 を介して親ウィンドウと対話できますSendMessage。ただし、SendMessageとは異なり、スレッド境界を越えるとスレッドがブロックされることに注意してくださいPostMessage。親ウィンドウのスレッドが子スレッドを待っていて、子スレッドが親がそのスレッドにあるウィンドウを作成しようとしている場合、それはデッドロックです。

一般的に、スレッド間で親子関係を作るのは得策ではないと思います。非常に簡単にデッドロックを起こすことができます。

于 2009-11-18T21:38:28.487 に答える
1

ここには、子ウィンドウと親ウィンドウを異なるスレッドに配置しようとしてはならず、機能しないことを強調して、多くの回答があります。

もしそうなら、Windowsはいくつかの安全策を講じ、CreateWindowを呼び出そうとしたときに単に失敗します。さて、大きな問題を引き起こす可能性のあるスレッド結合の問題は間違いなくありますが、これらの制約があるとすれば、これはサポートされているシナリオです。

于 2009-11-19T15:33:18.423 に答える
0

これは興味深い質問です。昔ながらの win32 関係者の多くが、これはできないと言っていました。これを調査しているときに、このフォーラムを見つけました: SendMessage()。私の現在の理論では、CreateWindowEx() は (SendMessage() を介してブロックするため) メッセージを親ウィンドウに送信して、存在する許可を求める (または少なくともその存在を通知する) 必要があるというものです...とにかく、限りその親スレッドはこれらのメッセージを自由に処理できます。すべて機能します...

于 2009-11-19T14:58:20.757 に答える
-1

ウィンドウは、それを作成したスレッド (より具体的には、そのスレッドのメッセージ キュー) に関連付けられています。親ウィンドウは、その子ウィンドウとは異なるスレッドに存在できません。

于 2009-11-18T21:33:24.053 に答える