2011-12-02 9 views
0

私は2つのコードファイルを持っています.1つは私のWinMain()関数と私のメインダイアログウィンドウに関連するすべての関数を含んでいます。もう一つはスレッドコールバックと私のプログラムに関連する変数関数を含んでいます。私はHWND hWnd = NULLをMainDlg.cppのグローバル変数として定義し、Other.cpp(スレッドコールバックを含む)にextern HWND hWndを定義しました。スレッドは、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コールバックで両方のメッセージボックスが表示されます。誰かがなぜこれが起こっているのか教えてもらえますか? ListenThreadの冒頭にwhile(hWnd == NULL);を実行する以外にこれを解決する方法がありますか?

答えて

3

WM_INITDIALOGメッセージはCreateDialog前に戻り、hWndCreateDialog戻るまで設定されていない場合に発生します。したがって、スレッドはCreateDialogが戻る前に実行を開始し、グローバルhWnd変数を設定します。

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

しかし、コードにグローバル変数hWndが必要ないため、これを行う必要はありません。すでにスレッド開始プロシージャのパラメータとしてダイアログウィンドウハンドルを渡しています。だから、lpvParamを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; 
} 
+0

私が仕事から家に運転していたとして、私はそれが何であったかです実現。スレッドの 'lpvParam'パラメータに' hWndDlg'を渡すことは、実際にはこの質問にあってはいけません。これは、コードの開発の初期段階から、より多くの「extern」変数が必要であり、それを「extern」に変更することを発見する前からです。私はそれを削除することを忘れてしまった。 –

1

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

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

DWORD WINAPI ListenThread(LPVOID lpvParam) 
{ 
    HWND hWnd = (HWND) lpvParam; 
    ... 
    return 0; 
} 
関連する問題