远程视频会议解决方案:用独立线程解决弹出模态对话框后执行自定义函数问题 - VC/MFC - 提供最全面实用的J...

来源:百度文库 编辑:九乡新闻网 时间:2024/05/05 05:15:10
用独立线程解决弹出模态对话框后执行自定义函数问题 - VC/MFC - 提供最全面实用的Java面试题,JAVA自测题,Java代码,Java项目,Java学习资料,Java论坛,Java教程,Java下载 - JAVA世纪网

用独立线程解决弹出模态对话框后执行自定义函数问题


模态对话框在执行DoModal()时,当前线程处于阻塞状态。
因此,只有当退出该对话框时,当前线程才能继续执行。

你的要求很另类,既要模态对话框,又要执行另一个函数,可以用新建线程的方法来解决
单独创建一个线程,在该线程中创建模态对话框,当对话框创建完成时置位主线程的某事件句柄,使得阻塞的线程可以继续执行某函数。

例程:
设CDlgModal为模态对话框类,设CViewMain为创建CDlgModal的主线程对象(此时要求CViewMain类的必须是CWnd类的子孙类)
在CViewMain的头文件ViewMain.h 中加入自定义消息的定义

1. 在CViewMain类的声明中加入一个线程指针,并在CViewMain类构造函数中为其赋值NULL
CWinThread* pThrdModalDlg; // 模态对话框线程指针(此线程为工作者线程就足够了,生成方法见下文)

2. 在ViewMain.h 中加入全局回调函数声明及友元声明
2.1 在ViewMain.h末尾(CViewMain类的声明的体外)加入回调函数声明
UINT AFX_CDECL CallbackModalDlg(LPVOID pParam); // 接收并解析报文线程用的回调函数
2.2 在CViewMain类的声明的体内加入事件句柄变量,加入对回调函数、CDlgModal类的友元声明(视情况可忽略)
friend UINT AFX_CDECL CallbackModalDlg(LPVOID pParam); // 声明回调函数为友元函数,在该线程内部任意访问CViewMain对象的各个成员变量或函数;假如你不需要访问的话,可以忽略此句。
friend class CDlgModal; //  声明CDlgModal为友元类,这样模块对话框对象可任意访问CViewMain对象的各个成员变量或函数;假如你不需要访问的话,可以忽略此句。
public:
HANDLE m_hEventModelDlgCreated; // 事件句柄,标识模态对话框是否创建。此变量最好设为公有类型,否则如果没有上句的友元声明的话,CDlgModal对象将无法置位此事件句柄


3. 在ViewMain.cpp中实现回调函数体
/************************************************************************/
/* 创建模态对话框用专用的线程pThrdModalDlg用的回调函数                      */
/************************************************************************/
UINT AFX_CDECL CallbackModalDlg(LPVOID pParam)
{
CViewMain* pViewMain=NULL;
pViewMain=(CViewMain*)pParam; // 通过线程构造时的LPVOID pParam变量来传递指向CViewMain的指针。如果前面声明了此回调函数为CViewMain类的友元的话,以后可以通过这个指针来任意调用CViewMain对象的成员变量和函数
CDlgModal dlg(pViewMain); // 创建模态对话框,将CViewMain对象指针作为参数传递给CDlgModal
dlg.DoModal(); // 执行CDlgModal对话框

// 对话框退出时,本线程退出
pViewMain->pThrdModalDlg=NULL; // 将CViewMain对象的pThrdModalDlg置空,这样下次可以再次产生本线程来创建模态对话框
pViewMain=NULL;
::AfxEndThread(0);
return 0;
}

4. 在ViewMain.cpp中实现线程创建与句柄关闭
4.1 CViewMain类的合适位置(某函数内,某按钮处理函数,自己任意指定)加入创建模态对话框线程的代码
if (pThrdModalDlg==NULL) // 判断线程是否已经创建,没创建时新建一个,如果已创建线程(模态对话框未关闭),就忽略
{
pThrdModalDlg=::AfxBeginThread(::CallbackModalDlg,this,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL); // 创建线程,并处于休眠状态
ASSERT(pThrdModalDlg);
m_hEventModelDlgCreated=CreateEvent(NULL,TRUE,FALSE,_T("ModalDlgCreated")); // 此事件初始状态为FALSE,必须手动复位
::ResetEvent(m_hEventModelDlgCreated); // 复位此标识
pThrdModalDlg->ResumeThread(); // 唤醒该线程
if (WAIT_OBJECT_0==WaitForSingleObject(m_hEventModelDlgCreated, 2000)) // 阻塞当前线程,等待m_hEventModelDlgCreated标识在CDlgModal::OnInitDialog()中被置位,超时为2000毫秒(视情况而定,机器负荷不重的时候2秒足够了)。WaitForSingleObject函数返回WAIT_OBJECT_0表示在规定时间(2000毫秒)内该标识被置位。其它返回值请参阅MSDN
{
DoSomething(); // 模态对话框已创建,执行自定义的函数
}
}
4.2 在CViewMain类析构函数中关闭事件句柄
CViewMain::~CViewMain()
{
CloseHandle(m_hEventModelDlgCreated);
}

5. 在CDlgModal类的头文件中加入对ViewMain.h 文件的包含,并添加一个指向CViewMain的指针成员变量
#include "ViewMain.h"
在CDlgModal类声明中加入:
CViewMain* m_pViewMain;

6. 修改CDlgModal类的构造函数和OnInitDialog()
CDlgModal:CDlgModal(CWnd* pParent /*=NULL*/)
: CDialog(CDlgModal::IDD, pParent)
, m_pViewMain(NULL)
{
m_pViewMain=(CViewMain*)pParent; // m_pViewMain是指向CViewMain的指针
}


BOOL CDlgModal::OnInitDialog()
{
CDialog::OnInitDialog();

// TODO:  在此添加额外的初始化
// 执行你自定义的另一个函数,此函数执行起来后模态对话框就显示了

::SetEvent(m_hEventModelDlgCreated); // 指示标识模态对话框已经创建,此时在CViewMain中用WaitForSingleObject阻塞的线程可以继续执行自定义函数
return TRUE;  // return TRUE unless you set the focus to a control
// 异常: OCX 属性页应返回 FALSE
}

小结:
此方法的本质就是先创建一个工作者线程,在该线程中创建模态对话框。当模态对话框创建完成后,通过置位主线程的事件句柄来通知主线程继续执行自定义的函数。
此方法的缺点是主线程的退出和模态对话框的退出产生异步,此时需要自己保证程序的可靠性。否则主线程关闭了,模态对话框还活着可能会产生错误。
使用者可以依本文思想,另外加一个事件标识来在主线程退出时通知模态对话框提前关闭,篇幅关系,在此不再赘述。