variable externe n'est pas disponible pour fil jusqu'à ce que le blocage d'appel est fait ...
-
27-10-2019 - |
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
?
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;
}