ブロッキングコールが作成されるまで、外部変数はスレッドできません…

StackOverflow https://stackoverflow.com/questions/8362999

質問

2つのコードファイルがあります。1つは私のコードファイルが含まれています WinMain() 関数、およびメインダイアログウィンドウに関連するすべての機能。もう1つには、私のプログラムに関連するスレッドコールバックと変数関数が含まれています。私は定義しました HWND hWnd = NULL maindlg.cppのグローバル変数として定義されています extern HWND hWnd other.cpp(スレッドコールバックが含まれています)。スレッドは、のときに作成されます WM_INITDIALOG メッセージがウィンドウに送信されます。スレッドコールバックの内部、 hWnd 変数は、長い操作が実行されるまでnullです。その後、利用可能になります。

maindlg.cpp

HWND hWnd = NULL;
HANDLE hListenThread = NULL;

DWORD WINAPI ListenThread( LPVOID lpvParam );

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    /* ... */
    if( NULL == (hWnd=CreateDialog( hInstance, MAKEINTRESOURCE(IDD_MAINDLG), NULL, (DLGPROC)WndProc)) )
    {
        MessageBox( NULL, "Error creating the main dialog!", NULL, MB_OK | MB_ICONERROR );
        return -1;
    }

    MSG msg;
    while( GetMessage(&msg,NULL,0,0) && IsWindow(hWnd) )
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

BOOL CALLBACK WndProc(HWND hWndDlg, UINT Message, WPARAM wParam, LPARAM lParam)
{

    switch(Message)
    {
        case WM_INITDIALOG:
        {
            DWORD dwListenThreadId = NULL;
            /* referencing hWnd here works fine... */
            /* ... */
            hListenThread = CreateThread(
                NULL,
                0,
                ListenThread,
                hWndDlg,
                0,
                &dwListenThreadId);
            /* ... */
        } break;
    }

    return false;
}

other.cpp

extern HWND hWnd;
DWORD WINAPI ListenThread( LPVOID lpvParam )
{

    if( hWnd == NULL )
        MessageBox( NULL, "hWnd == NULL", NULL, MB_OK | MB_SYSTEMMODAL );

    if( hWnd != NULL )
        MessageBox( NULL, "hWnd != NULL", NULL, MB_OK | MB_SYSTEMMODAL );

    return 0;
}

の両方のメッセージボックス ListenThread アプリケーションの起動時にコールバックが表示されます。なぜこれが起こっているのか教えてもらえますか? これを修正するためにできることはありますか while( hWnd == NULL ); 私の始まりに ListenThread ?

役に立ちましたか?

解決

WM_INITDIALOG メッセージが発生します CreateDialog 返品と hWnd まで設定されていません CreateDialog 戻り値。したがって、createdialogが戻ってきてグローバルを設定する前に、スレッドは実行を開始します hWnd 変数。

したがって、スレッドの作成をから移動することでこれを修正できます WM_INITDIALOG の帰還直後のメッセージ CreateDialog.

しかし、あなたはグローバルを必要としないので、あなたはそれをする必要はありません hWnd 変数。スレッド開始手順のパラメーターとしてダイアログウィンドウハンドルを既に渡しています。だから、lpvparamをanにキャストしてください HWND そしてそれを使用してください。これにより、グローバル変数を取り除くことができます。これは、使用するのが悪い習慣です。

other.cpp

DWORD WINAPI ListenThread( LPVOID lpvParam )
{
    HWND hWnd= (HWND)lpvParam;

    if( hWnd == NULL )
        MessageBox( NULL, "hWnd == NULL", NULL, MB_OK | MB_SYSTEMMODAL );

    if( hWnd != NULL )
        MessageBox( NULL, "hWnd != NULL", NULL, MB_OK | MB_SYSTEMMODAL );

    return 0;
}

他のヒント

WM_INITDIALOG メッセージが発行されます WndProc() 内側から CreateDialog() それ自体ではなく DispatchMessage(). 。これは、と同じように述べられています CreateDialog() ドキュメンテーション. 。君の hWnd 変数は後まで割り当てられません CreateDialog() 出口。スレッドが以前に実行され始めた場合 CreateDialog() 出口(タスクのスケジューリングに応じて、それは保証ではありません)、あなたの最初の MessageBox() 呼び出されます。一方 MessageBox() が走っています、 CreateDialog() 変数を終了して割り当てる時間があるので、2番目の変数が MessageBox() あなたが最初のものを却下した後に呼び出されます MessageBox().

使用する必要はありません hWnd スレッドの変数。あなたはダイアログを渡しています HWNDlpParameter のパラメーター CreateThread(), 、したがって、に表示されます lpvParam のパラメーター ListenThread(), 、例:

DWORD WINAPI ListenThread( LPVOID lpvParam )  
{  
    HWND hWnd = (HWND) lpvParam;  
    ...
    return 0;  
}  
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top