La variabile esterna non è disponibile per il thread fino a quando non viene effettuata la chiamata di blocco ...
-
27-10-2019 - |
Domanda
Ho due file di codice, uno contiene il mio WinMain()
funzione e tutte le funzioni relative alla mia finestra di dialogo principale. L'altro contiene un callback thread e funzioni variabili relative al mio programma. Ho definito HWND hWnd = NULL
come variabile globale in maindlg.cpp e definita extern HWND hWnd
in altri.cpp (che contiene il callback del thread). Il thread viene creato quando il WM_INITDIALOG
Il messaggio viene inviato alla finestra. All'interno del callback del thread, il hWnd
La variabile è null fino a quando non viene eseguita una lunga operazione, quindi dopo che diventa disponibile.
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;
}
Altro.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;
}
Entrambe le caselle di messaggi nel file ListenThread
Il callback viene visualizzato al momento dell'avvio dell'applicazione. Qualcuno può dirmi perché sta accadendo? C'è qualcosa che posso fare per risolvere questo problema oltre a farlo while( hWnd == NULL );
All'inizio del mio ListenThread
?
Soluzione
Il WM_INITDIALOG
si verifica il messaggio prima CreateDialog
ritorna e hWnd
non è impostato fino a quando CreateDialog
ritorna. Quindi il thread inizia in esecuzione prima che CreateAlog ritorni e imposta il globale hWnd
variabile.
Quindi potresti risolverlo spostando la creazione del tuo thread da WM_INITDIALOG
messaggio a subito dopo il ritorno di CreateDialog
.
Ma non è necessario farlo perché il codice non richiede il globale hWnd
variabile. Stai già passando la maniglia della finestra di dialogo come parametro nella procedura di avvio del thread. Quindi basta lanciare LPVParam su un HWND
e usalo. Ciò ti permetterà di sbarazzarti della tua variabile globale, che è una cattiva pratica da usare.
Altro.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;
}
Altri suggerimenti
Il WM_INITDIALOG
il messaggio viene emesso WndProc()
dall'interno di CreateDialog()
se stesso, non da DispatchMessage()
. Questo è indicato tanto in CreateDialog()
documentazione. Tuo hWnd
La variabile non è assegnata fino a dopo CreateDialog()
uscite. Se il thread inizia a funzionare prima CreateDialog()
Esci (a seconda della pianificazione delle attività, non è una garanzia), il tuo primo MessageBox()
viene chiamato. Mentre il MessageBox()
è in esecuzione, CreateDialog()
ha il tempo di uscire e assegnare la variabile, motivo per cui il secondo MessageBox()
Viene chiamato dopo aver respinto il primo MessageBox()
.
Non è necessario usare il hWnd
variabile nel tuo thread. Stai passando la finestra di dialogo HWND
al lpParameter
parametro di CreateThread()
, quindi apparirà in lpvParam
parametro di ListenThread()
, per esempio:
DWORD WINAPI ListenThread( LPVOID lpvParam )
{
HWND hWnd = (HWND) lpvParam;
...
return 0;
}