问一些弱智的问题(使用的是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)虽然许多书中不推荐每个窗口有自己的消息循环,但是实际应用程序中时,是否可以某个窗口有自己的消息?
现成的软件有这么做的吗?有的话介绍一个。

解决方案 »

  1.   

    1)不对,子线程中调用MessageBox只是子线程阻塞,而主线程会继续响应
    2),3)线程加入消息循还试试
    4)每个窗口都有个窗口回调函数,所以说它都有自己的消息处理程序
      

  2.   

    1)对。
    2)因为DoModal会把程序的主窗口作为其父窗口,屏蔽父窗口消息,而主窗口与其属于不同线程。
    3)把应用程序类初始化函数中m_pMainWnd=&dlg这行代码去掉,或者在创建对话框之前让m_pMainWnd=NULL。
    4)书是一种商品,其目的是满足大多数读者的需要,而多数读者都是初学者,所以书中经常不推荐某些做法以免引发问题。各种不推荐的东西,只要你都理解清楚了,就可以使用。
      

  3.   

    对于第二个,用AfxBeginThread启动没有异常,难道还是mfc对象的问题。
      

  4.   

    MFC内部是很乱的,经常会使用CWinApp和CWinThread类里面的数据和一些全局变量。估计是只有通过AfxBeginThread,MFC才知道这是另外一个线程。
    你用_beginthreadex创建线程的代码如果换成AfxMessageBox也一样会出错。
    如果要使用MFC,最好是所有能用Afx函数的地方都用Afx函数,或者能不用Afx函数的地方都不用Afx函数。
      

  5.   

    to 1楼:
    对于1)您好像没审清楚题
    对于4)我没说清楚,应该是“虽然许多书中不推荐每个窗口有自己的消息循环队列”。
    默认的是各窗口在一个消息队列中的。
    to 3楼:
    对于3)您的“应用程序类”的意思是:用AfxBeginThread启动的UI线程中的那个thread类吧?
      

  6.   

    “应用程序类”就是VC自动生成的那个CXxxApp类,Xxx是项目名称。
      

  7.   

    to LZ: 
    第一问题是我看错了,不好意思!~~ 我帮你写了一个测试程序,里面说明的很详细! 
    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;
    }
      

  8.   

    回7楼:您说的是对话框程序啊。1)更改以后,模式对话框就像非模式对话框一样了,即使主线程不响应(用一个死循环)了,模式对话框依然响应。非模式对话框,根据8楼的做法,效果一样。2)但我的是单文档程序,怎么更改?
    我将m_pMainWnd=NULL,程序就退出了。3)另外:
    _beginthreadex创建线程的代码如果换成AfxMessageBox没有出错。4)我觉得更改m_pMainWnd动静太大。可惜对话框类内部使用了这个指针,无法避免。下一步准备直接用windows api函数。
      

  9.   

    我是按对话框程序说的,单文档不能改m_pMainWnd。
    如果你要显示对话框的时候停止主窗口响应消息,就不要用多线程了,直接在主线程显示模式对话框就行了。
    如果要在线程中显示非模式对话框,你就用Create、ShowWindow,然后再加一个消息循环。
      

  10.   

    因为你的对话框类是用MFC写的,不能使用_beginthreadex来创建线程,一定要用AfxBeginThread,因为它会做一些MFC需要的额外初始化工作
      

  11.   

    另,非MFC的对话框不会有问题。
      

  12.   

    新发现:对话框程序,m_pMainWnd=NULL,_beginthreadex启动,模式对话框和非模式对话框都没有异常。
    看来异常就是m_pMainWnd引起的。
      

  13.   

    回9楼:dlg.Create(IDD_DIALOG1);  
    dlg.ShowWindow(SW_SHOW);  
       
    MSG msg;                               
    while(GetMessage (&msg, NULL, 0, 0 ))  
    {                                      
      if (dlg.GetSafeHwnd == 0  ¦ ¦ 
    !::IsDialogMessage(dlg.GetSafeHwnd(), &msg))  //加上对话框消息处理
     { 
        TranslateMessage (&msg);           
         DispatchMessage (&msg);  
     } 
    }
      

  14.   

    AFX_MANAGE_STATE(AfxGetStaticModuleState());ThreadDlg d;
    d.DoModal();
      

  15.   

    to 16楼:
    dlg.GetSafeHwnd == 0  居然正确,奇怪!to 17楼:异常依然存在,只是换了个地方
      

  16.   

    to 16楼: 
    dlg.GetSafeHwnd == 0  居然正确,奇怪!
    =======================================================================
    应该是dlg.GetSafeHwnd(),笔误,编译器不报错是不存在语法上的错误