关于在窗口消息处理函数中使用MessageBox造成消息重入的问题的研究及解决

原文地址:http://sns.ruanko.com/space.php?uid=15384&do=blog&id=97415

这两天慢慢把这次实训的成果总结出来,这是第一篇日志。

最早碰到的一个报错问题,在窗口消息处理函数中使用MessageBox(包括A和W版),由于MessageBox特性,程序会被阻塞,此时由于窗口处理函数未返回,消息分发会继续分发这个“未处理”的消息,从而导致消息重入。

下面进行分析:

MessageBox是模态对话框,Msdn中对于Dialog的解释为:

The DialogBox macro uses the CreateWindowEx function to create the dialog box. DialogBox then sends a WM_INITDIALOG message (and a WM_SETFONT message if the template specifies the DS_SETFONT style) to the dialog box procedure. The function displays the dialog box (regardless of whether the template specifies the WS_VISIBLE style), disables the owner window, and starts its own message loop to retrieve and dispatch messages for the dialog box.

原因如下:

所有的输入型消息都被MessageBox先处理,有一些在处理完后直接被丢弃,并不会传递给所有者窗体以及其他兄弟窗体;而非输入型消息在此期间MessageBox并未做处理,而是根据消息信息直接传递给所有者窗体或其他兄弟窗体,此时虽然未点击MessageBox上的任何按钮关闭MessageBox,但是同样的消息处理函数有可能重入。

我自己的解决方法是写一个多线程的对话框函数:

DWORD WINAPI _MTMessageBox(LPVOID argv)
{
 DWORD dwBtn;
 TCHAR* szText;
 TCHAR* szCaption;

 TCHAR* szMsg = (TCHAR*)argv;
 int iMsgLen = _tcslen(szMsg);
 TCHAR* szBuff = new TCHAR[iMsgLen + 1];
 _tcscpy(szBuff,szMsg);

 for (int i=0;i<iMsgLen;i++)
 { 
  if (szBuff[i]==0x02)
   szBuff[i]=0;
 }

 szText = new TCHAR[_tcslen(szBuff) + 1];
 _stscanf(szBuff,_T("%s"),szText);
 szBuff+=(_tcslen(szBuff)+1);

 szCaption = new TCHAR[_tcslen(szBuff) + 1];
 _stscanf(szBuff,_T("%s"),szCaption);
 szBuff+=(_tcslen(szBuff)+1);

 _stscanf(szBuff,_T("%d"),&dwBtn);

 MessageBox(NULL,szText,szCaption,dwBtn);
 delete szBuff;
 delete szText;
 delete szCaption;
 delete argv;
 return 0;
}


DWORD MultiThreadMessageBox(LPCTSTR szText,LPCTSTR szCaption,DWORD btn)
{
 HANDLE hThread;
 DWORD  ThreadID;
 TCHAR* buff = new TCHAR[MAX_PATH*4];

 _stprintf(buff,_T("%s\x02%s\x02%d\x02"),szText,szCaption,btn);
 hThread = CreateThread(0,0,_MTMessageBox,(PVOID)buff,0,&ThreadID);
 return 1;
}

使用MultiThreadMessageBox就行了,同时支持ANSI和Unicode。

备注:原作者写的MultiThreadMessageBox存在一些问题。比如“delete szBuff;”需要修改为“delete [] szBuff;”,否则会泄露内存。

下面是我重新实现了一下:

typedef struct
{
    TCHAR text[MAX_PATH];
    TCHAR caption[MAX_PATH];
    UINT type;
}MessageBoxData;

DWORD WINAPI MessageBoxThread(LPVOID parameter)
{
    MessageBoxData * message_box_data = static_cast<MessageBoxData *>(parameter);
    MessageBox(NULL, message_box_data->text, message_box_data->caption, message_box_data->type);
    delete message_box_data;
    message_box_data = NULL;

    return 0;
}

void MultiThreadMessageBox(LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
    MessageBoxData * message_box_data = new MessageBoxData;
    _tcscpy(message_box_data->text ,lpText);
    _tcscpy(message_box_data->caption, lpCaption);
    message_box_data->type = uType;

    HANDLE handle_thread = CreateThread(0, 0, MessageBoxThread, (LPVOID)message_box_data, 0, NULL);
    if (NULL != handle_thread)
        CloseHandle(handle_thread);
}

 

你可能感兴趣的:(message)