使用microsoft提供的ATL Com Appwizard模板生成控件很方便,用户的灵活性也比较大,可如果想从一个工作线程中fire事件却总是出问题,有一些是在fire时出现内存错,有一些是事件是fire出去了,可却收不到。
查了很多资料才知道,vc现有的事件分发存在一定的缺陷,在线程发送事件时可能存在问题,(但奇怪的是,同一个控件,如果使用ms自带的Active X Control Test Container测试不管是从线程中发出的事件还是别的都能收到,而使用javascript写的脚本却收不到线程发出的时间,具体原因还不太清楚。)
为解决从线程中发送的事件不能被javascript等脚本语言接收的问题,好多人都提供了解决方法,经笔者测试发现下面解决方案为最佳,描述如下:
(1)从microsoft下载ATLCPImplMT.h文件(http://support.microsoft.com/kb/280512/zh-cn)
(2)改写工作线程函数
由原来的
void MyThreadProc( LPVOID pParam )
{
CThreadEvent * m_pThreadEvent = (CThreadEvent *)pParam;
m_pThreadEvent->Fire_SomeEvent();
return ;
}
改成
void MyThreadProc( LPVOID pParam )
{
HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
CThreadEvent * m_pThreadEvent = (CThreadEvent *)pParam;
m_pThreadEvent->Fire_SomeEvent();
::CoUninitialize ();
return ;
}
(3)改变系统生成的XXXCP.h
先包含头文件#include "ATLCPImplMT.h"
将以前的template
class CProxy_IThreadEventEvents : public IConnectionPointImpl
改成
template
class CProxy_IThreadEventEvents : public IConnectionPointImplMT
(4)逐个改变系统生成的fire事件代码
将
pT->Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
更换成
CComPtr<IUnknown> sp;
sp.Attach (GetInterfaceAt(nConnectionIndex));
重新编译,从线程中发送事件应该可以使用了
注意:笔者使用的开发环境如下,winxp + sp2,
vc6.0 + sp6
另外,如果新添加了一些事件从新编译后会发现以前在fire部分做的更改全部消失,要重新更改代码,所以建议全部事件添加完成后再做代码更换工作,以免重复劳动