0

2 つのコード ファイルがあり、1 つにはWinMain()関数が含まれており、すべての関数はメイン ダイアログ ウィンドウに関連しています。もう 1 つは、プログラムに関連するスレッド コールバックと変数関数を含みます。HWND hWnd = NULLMainDlg.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;
}

その他.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

4

2 に答える 2

3

WM_INITDIALOGメッセージは戻る前に発生し、戻るまで 設定されません。そのため、CreateDialog が返されてグローバル変数が設定される前に、スレッドの実行が開始されます。CreateDialoghWndCreateDialoghWnd

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

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

その他.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;
}
于 2011-12-02T22:04:54.003 に答える
1

メッセージは、によってではなく、それ自体の内部から にWM_INITDIALOG発行されます。これはドキュメントにも記載されています。変数は、終了するまで割り当てられません。スレッドが終了する前に実行を開始した場合 (タスクのスケジューリングによって異なりますが、これは保証されません)、最初に呼び出されます。の実行中は、終了して変数を割り当てる時間があります。これが、最初の を閉じた後に 2 番目が呼び出される理由です。WndProc()CreateDialog()DispatchMessage()CreateDialog() hWndCreateDialog()CreateDialog()MessageBox()MessageBox()CreateDialog()MessageBox()MessageBox()

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

DWORD WINAPI ListenThread( LPVOID lpvParam )  
{  
    HWND hWnd = (HWND) lpvParam;  
    ...
    return 0;  
}  
于 2011-12-02T22:05:47.027 に答える