在阻塞调用之前,外部变量对线程不可用

external variable is not available to thread until blocking call is made...

本文关键字:变量 线程 外部 调用      更新时间:2023-10-16

我有两个代码文件,一个包含我的WinMain()函数,以及与我的主对话框窗口相关的所有函数。另一个包含线程回调和与我的程序相关的变量函数。我在maindg .cpp中定义了HWND hWnd = NULL作为全局变量,并在Other.cpp中定义了extern HWND hWnd(其中包含线程回调)。当WM_INITDIALOG消息被发送到窗口时创建线程。在线程回调中,hWnd变量在执行long操作之前为空,之后变为可用。

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 );之外,我还可以做些什么来解决这个问题吗?

WM_INITDIALOG消息在 CreateDialog返回之前出现hWnd直到CreateDialog返回才被设置。因此,在CreateDialog返回并设置全局hWnd变量之前,线程开始运行。

因此,您可以通过将您的线程创建从WM_INITDIALOG消息移动到CreateDialog返回之后来修复此问题。

但是您不需要这样做,因为您的代码不需要全局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;
}

WM_INITDIALOG消息是从CreateDialog()内部发出给WndProc()的,而不是由DispatchMessage()发出的。这在CreateDialog()文档中有详细说明。直到CreateDialog()退出后才分配hWnd变量。如果您的线程在CreateDialog()退出之前开始运行(取决于任务调度,这并不能保证),您的第一个MessageBox()将被调用。当MessageBox()运行时,CreateDialog()有时间退出并分配变量,这就是为什么在您解散第一个MessageBox()之后调用第二个MessageBox()的原因。

你根本不需要在线程中使用hWnd变量。您将对话框HWND传递给CreateThread()lpParameter参数,因此它将出现在ListenThread()lpvParam参数中,例如:
DWORD WINAPI ListenThread( LPVOID lpvParam )  
{  
    HWND hWnd = (HWND) lpvParam;  
    ...
    return 0;  
}