variable externe n'est pas disponible pour fil jusqu'à ce que le blocage d'appel est fait ...

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

Question

J'ai deux fichiers de code, on contient ma fonction WinMain(), et toutes les fonctions liées à ma fenêtre principale de dialogue. L'autre contient un rappel de fil et fonctions variables liées à mon programme. J'ai défini HWND hWnd = NULL en tant que variable globale dans MainDlg.cpp et extern HWND hWnd défini dans Other.cpp (qui contient la fonction de rappel de fil). Le fil est créé lorsque le message WM_INITDIALOG est envoyé à la fenêtre. A l'intérieur du rappel de fil, la variable hWnd est nulle jusqu'à ce que se fait l'opération à long, puis après qu'il devient disponible.

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;
}

Les deux boîtes de message dans le rappel de ListenThread sont affichés lorsque l'application est lancée. Quelqu'un peut-il s'il vous plaît me dire pourquoi cela se passe? Y at-il quelque chose que je peux faire pour résoudre ce problème en plus de faire while( hWnd == NULL ); au début de mon ListenThread?

Était-ce utile?

La solution

Le message WM_INITDIALOG se produit avant retourne CreateDialog et hWnd ne sont pas réglées avant le retour de CreateDialog. Ainsi, le fil commence à courir avant le retour CreateDialog et définit la variable globale hWnd.

Vous pouvez corriger cela en déplaçant la création de votre fil à partir du message WM_INITDIALOG juste après le retour de CreateDialog.

Mais vous n'avez pas besoin de faire cela parce que vous code ne pas exigé que la variable globale hWnd. Vous êtes déjà de passer votre dialogue poignée de fenêtre comme paramètre à la procédure de démarrage du fil. Il suffit donc de jeter le lpvParam à un HWND et utiliser. Cela vous permettra de vous débarrasser de votre variable globale, ce qui est une mauvaise pratique à utiliser.

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;
}

Autres conseils

Le message WM_INITDIALOG est délivré à WndProc() à l'intérieur de CreateDialog() lui-même, et non par DispatchMessage(). Cela est indiqué aussi bien dans le CreateDialog() documentation . Votre variable hWnd n'est pas affecté jusqu'à ce que après la sortie de CreateDialog(). Si votre fil commence à courir avant de se terminer CreateDialog() (en fonction de la planification des tâches, qui ne sont pas une garantie), votre première MessageBox() est appelée. Alors que le MessageBox() est en cours d'exécution, CreateDialog() a le temps pour sortir et assigner la variable, ce qui explique pourquoi la deuxième MessageBox() est appelée après que vous rejetez la première MessageBox().

Vous n'avez pas besoin d'utiliser la variable hWnd dans votre fil du tout. Vous passez la HWND de dialogue au paramètre lpParameter de CreateThread(), il apparaîtra dans le paramètre lpvParam de ListenThread(), par exemple:

DWORD WINAPI ListenThread( LPVOID lpvParam )  
{  
    HWND hWnd = (HWND) lpvParam;  
    ...
    return 0;  
}  
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top