多线程
CWinThread* m_pFindFile;
static UINT FileThread(LPVOID lparam);
m_pFindFile = AfxBeginThread((AFX_THREADPROC)FileThread,this,THREAD_PRIORITY_NORMAL,0,0);
UINT CFTP2DataBaseDlg::FileThread(LPVOID lparam)
{
CInternetSession sess("区局.10文件服务器"); CFtpConnection* pConnect = NULL; CInternetFile* pFile = NULL;
pConnect = sess.GetFtpConnection(_T("x.x.x.x"),_T("USER"),_T("PASSWD"));
pConnect->GetCurrentDirectory(InitDirName); pConnect->SetCurrentDirectory(NowDirName);
CFtpFileFind finder(pConnect);
if(finder.FindFile(FileName))
{ pFile = pConnect->OpenFile(FileName); char* BUFF = new char[500]; pFile->Read(BUFF,430);
CString str; str.Format(_T("%s"), BUFF); pFile->Close(); } return 1;
}
二、线程调用主窗口资源
时常为所开的线程传入个窗口参数 (cwnd),这里里面有个很大的隐患就是当做CWnd::AssertValid()检查,就会遇到断言失败。具体原因在于MFC管理窗口的机制。MFC有个窗口句柄和窗口类对象的映射表,就是Windows对象(句柄)和C++对象的一个映射,它是在窗口调用CWnd::Create(),CWnd::CreateEx()时,就添加到映射表里的。映射表的一个重要的特征,它只存于一个线程当中。当你在B线程使用A线程的窗口对象指针pWnd,B线程对此对象指针做AssertValid时,会因为以下几种原因导致断言失败:
1.CHandleMap*
pMap =
afxMapHWND(); ASSERT(pMap != NULL)失败;该线程没有映射表。原因这个线程只是工作线程(没有主窗口),并不是用户界面线程(利用界面线程可以在一个进程的地址空间开启几个并行运行的窗口)。在工作线程里调用AfxGetMainWnd()->m_hWnd出错,也会发生发生内存访问冲突。(AfxGetMainWnd得到的是当前线程的主窗口)。
2.ASSERT((p =
pMap->LookupPermanent(m_hWnd)) != NULL ||(p =
pMap->LookupTemporary(m_hWnd)) != NULL)失败;从线程的句柄映射表没有句柄pWnd->m_hWnd所对应的对象。
3.ASSERT((CWnd*)p == this);句柄pWnd->m_hWnd所对应 的对象并不是自身。
每个界面线程都有自身的映射表,TLS(线程局部存储)。映射表有两类:永久的,临时的。.普通窗口,如程序主窗口的映射关系在永久映射表中。并不是所有的句柄都有个Cwnd对象对其进行封装,所以如果无法在永久映射中找到HWND对应的CWnd对象,就会创建一个临时CWnd对象包装此HWND,并将它们记入临时映射表中.当程序空闲时(OnIdle()),会删除所创的临时窗口对象.此后对该CWnd的引用都将引发上述的断言出错(状况2,3). 也是因这个原因,GetDlgItem()等常用函数返回的都是临时对象,不能在程序中保存以在以后使用,而应该随用随取.注意MSDN中的说明:The returned pointer
may be temporary and
should not be stored for
later use.
有人说在线程间传递大多数MFC类的指针,是一个常识性的错误。确实是个错误,但可以回避它。只要调用者明白传递这窗口指针的意义,如有时我们传递一个继承的MFC类指针,只是为了得到我们在其中所加入的结构或进行一些与窗口无关的操作(进行窗口操作就会出现上述问题了,因为afxMapHWND得到的是线程本身的句柄表)。如果非要在线程里做一些非本线程窗口的操作,只有创建线程的时候将窗口句柄作为参数传递进去了。其实这是不必要的,我们可以通过发送消息完成线程间窗口的交互。

浙公网安备 33010602011771号