我们都会发现,如过给主窗口过多的任务,或者让主窗口过多地Sleep,那么主窗口很难响应用户的任何操作,
甚至在此种情况下想要移动一下主窗口都会造成窗口标题栏显示“没有响应”,如此一来,大多用户都会启动任
务管理器来结束这个假死的窗口。
如何避免这种情况呢?
一种办法就是使用多线程,也就是把那些耗时耗力的工作交给主窗口的子线程,如此以来,假死的就不是主窗口而是用户看不见的子线程了,而此时窗口仍然可以正常地响应用户的一些操作。
具体方法是:
在即将启动子线程的窗口类的类体外(注意一定是类体外!)定义出子线程要执行的函数,该函数的格式必须是(注意必须!):
UINT FunctionName(LPVOID pParam)
{return ***}// ***处写返回值,一般说来这个返回值没什么用处,只是为了跳出函数
函数定义完了,于是该启动一个子线程来执行这个函数了,启动的方法是:
CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
千万不要被这个函数复杂的参数所下到,因为通常情况只用到前两个参数,后几个默认即可,比如我们可以这样写:
AfxBeginThread(FunctionName,GetSafeHwnd());//别问我第二个参数为什么是这样,通常都这样写,它用于和启动子线程的窗口通信。
到这里,一个最简单的“多线程”就算出炉了,在程序运行到AfxBeginThread(FunctionName,GetSafeHwnd());时,子线程就会被启动来完成一定的操作。
实际上的多线程并不这样简单,子线程并非总应在AfxBeginThread(FunctionName,GetSafeHwnd());之后被启动,而且也不应总运行一遍函数体就结束。实际上我们还经常用CEvent类对象来触发一个已经启动的子线程开始运行,相应地,子线程也必须等待收到指定的CEvent对象时才真正运行。一个比较完善的子线程:
UINT FunctionName(LPVOID pParam)
{
::WaitForSingleObject(refresh,INFINITE);
。。。。。
::PostMessage((HWND)pParam,WM_REFRESH,0,0);
}
这个例子中::WaitForSingleObject(refresh,INFINITE);一句的refreshe是一个CEvent类对象,INFINITE指定无限时地等待refresh的到来,只有收到refresh后才继续往下运行,refresg的发送方法是:refresh.Setevent;::PostMessage((HWND)pParam,WM_REFRESH,0,0);一句就是与pParam窗口(通常是启动它的窗口)通信,WM_REFRESH是自定义消息,当然,pParam窗口中还必须有能接受并相应这个消息的函数例如可以是:afx_msg LRESULT OnRefresh(WPARAM wParam,LPARAM lParam);
为什么一定要用这种方法来和主窗口通信呢?很简单,因为子线程所执行的函数被定义在了类体外。
最后一点,当主窗口被关闭后,子线程就自动终止了,如果要在运行期间结束,就调用void AfxEndThread( UINT nExitCode );这个函数很简单,看一下MSDN即可,在此不做赘述。