问一些弱智的问题(使用的是vc6.0 MFC单文档程序)
/////////////////////////////////////////////////////////////////////////////////
用_beginthreadex创建一个副线程,在线程回调函数中:
::MessageBox(NULL,"Thread4","Thread4",MB_OK);
弹出一个对话框,即使主线程不响应了,此对话框仍然响应,
可见副线程拥有这个窗口,而且有独立的消息循环。
1)我这种说法对否?/////////////////////////////////////////////////////////////////////////////////
但是当将MessageBox换成如下代码:
ThreadDlg d;//ThreadDlg是个对话框类,没有父窗口
d.DoModal();//异常出现在这。
//d.Create(IDD_DIALOG2);
//d.ShowWindow(SW_SHOW);
Sleep(200000);就不行了。无论是有模式的还是无模式的。(在主线程中调用没有问题)
出现了异常,位置在wincore.cpp文件中的CWnd::AssertValid()中,具体异常位置如下:ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL || (p = pMap->LookupTemporary(m_hWnd)) != NULL);
ASSERT((CWnd*)p == this); // must be us
看样子是窗口无效的原因。调试的时候其实窗口还是出现过的。2)这是什么原因呢?为什么::MessageBox可以呢?
/////////////////////////////////////////////////////////////////////////////////
3)如何在线程中弹出自己定义的对话框?
/////////////////////////////////////////////////////////////////////////////////
4)虽然许多书中不推荐每个窗口有自己的消息循环,但是实际应用程序中时,是否可以某个窗口有自己的消息?
现成的软件有这么做的吗?有的话介绍一个。
/////////////////////////////////////////////////////////////////////////////////
用_beginthreadex创建一个副线程,在线程回调函数中:
::MessageBox(NULL,"Thread4","Thread4",MB_OK);
弹出一个对话框,即使主线程不响应了,此对话框仍然响应,
可见副线程拥有这个窗口,而且有独立的消息循环。
1)我这种说法对否?/////////////////////////////////////////////////////////////////////////////////
但是当将MessageBox换成如下代码:
ThreadDlg d;//ThreadDlg是个对话框类,没有父窗口
d.DoModal();//异常出现在这。
//d.Create(IDD_DIALOG2);
//d.ShowWindow(SW_SHOW);
Sleep(200000);就不行了。无论是有模式的还是无模式的。(在主线程中调用没有问题)
出现了异常,位置在wincore.cpp文件中的CWnd::AssertValid()中,具体异常位置如下:ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL || (p = pMap->LookupTemporary(m_hWnd)) != NULL);
ASSERT((CWnd*)p == this); // must be us
看样子是窗口无效的原因。调试的时候其实窗口还是出现过的。2)这是什么原因呢?为什么::MessageBox可以呢?
/////////////////////////////////////////////////////////////////////////////////
3)如何在线程中弹出自己定义的对话框?
/////////////////////////////////////////////////////////////////////////////////
4)虽然许多书中不推荐每个窗口有自己的消息循环,但是实际应用程序中时,是否可以某个窗口有自己的消息?
现成的软件有这么做的吗?有的话介绍一个。
2),3)线程加入消息循还试试
4)每个窗口都有个窗口回调函数,所以说它都有自己的消息处理程序
2)因为DoModal会把程序的主窗口作为其父窗口,屏蔽父窗口消息,而主窗口与其属于不同线程。
3)把应用程序类初始化函数中m_pMainWnd=&dlg这行代码去掉,或者在创建对话框之前让m_pMainWnd=NULL。
4)书是一种商品,其目的是满足大多数读者的需要,而多数读者都是初学者,所以书中经常不推荐某些做法以免引发问题。各种不推荐的东西,只要你都理解清楚了,就可以使用。
你用_beginthreadex创建线程的代码如果换成AfxMessageBox也一样会出错。
如果要使用MFC,最好是所有能用Afx函数的地方都用Afx函数,或者能不用Afx函数的地方都不用Afx函数。
对于1)您好像没审清楚题
对于4)我没说清楚,应该是“虽然许多书中不推荐每个窗口有自己的消息循环队列”。
默认的是各窗口在一个消息队列中的。
to 3楼:
对于3)您的“应用程序类”的意思是:用AfxBeginThread启动的UI线程中的那个thread类吧?
第一问题是我看错了,不好意思!~~ 我帮你写了一个测试程序,里面说明的很详细!
http://txk.12mf.cn/demo.rar部分代码如下: #include <process.h>///////////////////////////// chBEGINTHREADEX Macro ///////////////////////////
// This macro function calls the C runtime's _beginthreadex function.
// The C runtime library doesn't want to have any reliance on Windows' data
// types such as HANDLE. This means that a Windows programmer needs to cast
// values when using _beginthreadex. Since this is terribly inconvenient,
// I created this macro to perform the casting.
typedef unsigned (__stdcall *PTHREAD_START) (void *);#define chBEGINTHREADEX(psa, cbStack, pfnStartAddr, \
pvParam, fdwCreate, pdwThreadId) \
((HANDLE)_beginthreadex( \
(void *) (psa), \
(unsigned) (cbStack), \
(PTHREAD_START) (pfnStartAddr), \
(void *) (pvParam), \
(unsigned) (fdwCreate), \
(unsigned *) (pdwThreadId)))void CDemoDlg::OnButton1()
{
// TODO: Add your control notification handler code here
AfxBeginThread(ThreadFun, NULL); //这里要用AfxBeginThread,不能用下面的_beginthreadex
//具体原因下面会说明// DWORD dwThreadId;
// chBEGINTHREADEX (NULL, 0, ThreadFun, (PVOID)NULL,
// NULL, &dwThreadId);
}UINT CDemoDlg::ThreadFun(LPVOID pParam)
{
AfxMessageBox("test"); //在这里无论上面用的是AfxBeginThread还是_beginthreadex都可以
//因为AfxMessageBox没有关系到MFC环境初始化 CDlg1 dlg;///////////////////////////////////////////////////////////////////////////////////////
//modal dialog
//dlg.DoModal(); //这里和下面的一定要用AfxBeginThread不然的话就出现你所说的情况,
//AfxMessageBox内部初始化MFC环境然后它会调用_beginthreadex//////////////////////////////////////////////////////////////////////////////////////
//non-modal dialog dlg.Create(IDD_DIALOG1);
dlg.ShowWindow(SW_SHOW);
MSG msg; //如果是非模态对话框一定要加入这个消息循环
while(GetMessage (&msg, NULL, 0, 0 )) //模态对话就不要了,因为DoModal内部执行了这
{ //个工作
TranslateMessage (&msg); //只要是子线程中要创建窗口都要有一个消息循环
DispatchMessage (&msg);
}
return 0;
}
我将m_pMainWnd=NULL,程序就退出了。3)另外:
_beginthreadex创建线程的代码如果换成AfxMessageBox没有出错。4)我觉得更改m_pMainWnd动静太大。可惜对话框类内部使用了这个指针,无法避免。下一步准备直接用windows api函数。
如果你要显示对话框的时候停止主窗口响应消息,就不要用多线程了,直接在主线程显示模式对话框就行了。
如果要在线程中显示非模式对话框,你就用Create、ShowWindow,然后再加一个消息循环。
看来异常就是m_pMainWnd引起的。
dlg.ShowWindow(SW_SHOW);
MSG msg;
while(GetMessage (&msg, NULL, 0, 0 ))
{
if (dlg.GetSafeHwnd == 0 ¦ ¦
!::IsDialogMessage(dlg.GetSafeHwnd(), &msg)) //加上对话框消息处理
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
d.DoModal();
dlg.GetSafeHwnd == 0 居然正确,奇怪!to 17楼:异常依然存在,只是换了个地方
dlg.GetSafeHwnd == 0 居然正确,奇怪!
=======================================================================
应该是dlg.GetSafeHwnd(),笔误,编译器不报错是不存在语法上的错误