return lpDispatch->Invoke(dispidMember, riid, lcid, \\
wFlags, pdispparams, pvarResult, \\ pexcepinfo, puArgErr); \\ } \\
/////////////////////////////////////////////////////////////////////
// TRY_DUAL and CATCH_ALL_DUAL are used to provide exception handling // for your dual interface methods. CATCH_ALL_DUAL takes care of // returning the appropriate error code. #define TRY_DUAL(iidSource) \\ HRESULT _hr = S_OK; \\
REFIID _riidSource = iidSource; \\ TRY \\
#define CATCH_ALL_DUAL \\ CATCH(COleException, e) \\ { \\
_hr = e->m_sc; \\ } \\
AND_CATCH_ALL(e) \\ { \\
AFX_MANAGE_STATE(pThis->m_pModuleState); \\ _hr = DualHandleException(_riidSource, e); \\ } \\
END_CATCH_ALL \\ return _hr; \\
///////////////////////////////////////////////////////////////////// // DualHandleException is a helper function used to set the system's // error object, so that container applications that call through // VTBLs can retrieve rich error information
HRESULT DualHandleException(REFIID riidSource, const CException* pAnyException); /////////////////////////////////////////////////////////////////////
// DECLARE_DUAL_ERRORINFO expands to declare the ISupportErrorInfo // support class. It works together with DUAL_ERRORINFO_PART and // IMPLEMENT_DUAL_ERRORINFO defined below. #define DECLARE_DUAL_ERRORINFO() \\
BEGIN_INTERFACE_PART(SupportErrorInfo, ISupportErrorInfo) \\ STDMETHOD(InterfaceSupportsErrorInfo)(THIS_ REFIID riid); \\ END_INTERFACE_PART(SupportErrorInfo) \\
/////////////////////////////////////////////////////////////////////
// DUAL_ERRORINFO_PART adds the appropriate entry to the interface map // for ISupportErrorInfo, if you used DECLARE_DUAL_ERRORINFO. #define DUAL_ERRORINFO_PART(objectClass) \\
INTERFACE_PART(objectClass, IID_ISupportErrorInfo, SupportErrorInfo) \\ /////////////////////////////////////////////////////////////////////
// IMPLEMENT_DUAL_ERRORINFO expands to an implementation of // ISupportErrorInfo which matches the declaration in // DECLARE_DUAL_ERRORINFO.
#define IMPLEMENT_DUAL_ERRORINFO(objectClass, riidSource) \\
STDMETHODIMP_(ULONG) objectClass::XSupportErrorInfo::AddRef() \\ { \\
METHOD_PROLOGUE(objectClass, SupportErrorInfo) \\ return pThis->ExternalAddRef(); \\ } \\
STDMETHODIMP_(ULONG) objectClass::XSupportErrorInfo::Release() \\ { \\
METHOD_PROLOGUE(objectClass, SupportErrorInfo) \\ return pThis->ExternalRelease(); \\ } \\
STDMETHODIMP objectClass::XSupportErrorInfo::QueryInterface( \\ REFIID iid, LPVOID* ppvObj) \\ { \\
METHOD_PROLOGUE(objectClass, SupportErrorInfo) \\ return pThis->ExternalQueryInterface(&iid, ppvObj); \\ } \\
STDMETHODIMP objectClass::XSupportErrorInfo::InterfaceSupportsErrorInfo( \\ REFIID iid) \\ { \\
METHOD_PROLOGUE(objectClass, SupportErrorInfo) \\ return (iid == riidSource) ? S_OK : S_FALSE; \\ }
ÏÂÃæÊÇjiangsheng(½¯êÉ.MSMVP2004Jan)ÀÏ´óµÄ¾«²Ê»ØÌù£º
Knowledge Base Article Q157437: \ Fires Events from a Second Thread\
http://support.microsoft.com/support/kb/articles/q157/4/37.asp
Knowledge Base Article Q196026: \ Firing Event in Second Thread Causes IPF or GPF\
http://support.microsoft.com/support/kb/articles/q196/0/26.asp
Michael Lindig's ATL: Firing events from worker threads article on CodeGuru.com
http://www.codeguru.com/atl/ThreadEvents.shtml
Knowledge Base Article Q280512: \ ATLCPImplMT Encapsulates ATL Event Firing Across COM Apartments\
http://support.microsoft.com/support/kb/articles/q280/5/12.asp
COM FAQ 11: HOWTO: Post messages to a hidden window for raising events from an Apartment-threaded object employing worker threads http://www.mvps.org/vcfaq/com/11.htm
ÕâÊÇ´ÓcsdnÉÏÕªÀ´µÄÒ»¶Î£¨ÍüÁËÔÌùλÖÃÁË£¬ºÜÊDZ§Ç¸£©£¬Ö÷ÒªÊǽâ¾öActiveX¿Ø¼þÈçºÎ´Ó¹¤×÷Ïß³ÌÖд¥·¢Ê¼þµÄ£¬ÒòΪ×Ô¼ºÒÔǰҲÓöµ½¹ýÕâ¸öÎÊÌ⣬ËùÒÔ½ñÌìÓÖ¸ø·À´³öÀ´¡£
ÉÏÃæÌáµ½µÄ½â¾ö·½·¨ÓÐÐí¶à¶¼ÊÇÕë¶ÔATL¿Ø¼þµÄ£¬ËäÈ»MFCÏÂÒ²Ó¦¸Ã¿ÉÒÔÓ㬲»¹ýËÆºõÌ«¹ýÀÍʦ¶¯ÖÚÁË£¬ËùÒÔÕâÀïÑ¡ÔñÁËmicrosoftµÄFireev.exeÀý³ÌÖеķ½·¨À´ÖØÀúÒ»»ØÊ¹ÓÃÒþ²Ø´°¿ÚÀ´´¥·¢Ê¼þµÄ·½·¨£¬¿ÉÒԲο¼Fireev.exeÀý³Ì
1.н¨Ò»ÎÞ´°¿Ú(windowless activation)¿Ø¼þTFire£¬Ìí¼ÓÈý·½·¨void Start()£¬void End()ºÍvoid Trigger(LPCTSTR strParam)ºÍһʼþvoid FireThreadEvent(LPCTSTR strEvent)¡£ÕâÀïStartÓÃÀ´¿ªÊ¼¹¤×÷Ị̈߳¬EndÓÃÀ´½áÊø¹¤×÷Ị̈߳¬TriggerÓÃÀ´Ê¹¹¤×÷Ï̲߳úÉúʼþ£¬ThreadEvent¾ÍÊÇËù²úÉúµÄʼþÃû¡£ Õû¸ö˼·ÈçÏ£º
ÔÚCTFireCtrlµÄStart·½·¨ÖУ¬´´½¨Ïß³ÌMyThread£¬´´½¨Òþ²Ø´°¿ÚCMyWindow£¬ÔÚ Trigger·½·¨ÖУ¬Í¨¹ýSetEvent ֪ͨÏß³ÌPostMessage¸øÒþ²Ø´°¿Ú£¬ÔÙÓÉCMyWindowµ÷ÓÃCTFireCtrlµÄFireTheadEvent´¥·¢Ê¼þ£¬µ±µ÷Óà CTFireCtrµÄEnd·½·¨Ê±£¬¾Í½áÊøMyTheadỊ̈߳¬Ïú»ÙÒþ²Ø´°¿Ú
2.ÏÈ´ÓCWndÅÉÉúÒ»CMyWindowÀ࣬ÓÃ×÷Òþ²Ø´°¿Ú£¬
a.Ìí¼ÓÒ»³ÉÔ±±äÁ¿CTFireCtrl* m_pCtrl£¬ÓÃÀ´Êµ¼Êµ÷ÓÃCTFireCtrlµÄFireThreadEventÀ´²úÉúʼþ¡£
b.¶¨Òå×Ô¶¨ÒåÏûÏ¢define WM_THREADEVENT WM_USER+101¡£
c.Ìí¼Ó×Ô¶¨ÒåÏûÏ¢´¦Àíº¯Êý LRESULT OnFireThreadEvent(WPARAM wParam, LPARAM lParam);²¢¼ÓÈëµ½ÏûÏ¢Ó³ÉäºêÖУ¬ÈçÏ£º
BEGIN_MESSAGE_MAP(CMyWindow, CWnd) //{{AFX_MSG_MAP(CMyWindow)
// NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP
ON_MESSAGE(WM_THREADEVENT, OnFireThreadEvent) END_MESSAGE_MAP()
OnFireThreadEventº¯Êý¶¨ÒåÈçÏ£¬ÕâÀïµÃÊ×ÏȽ«CTFireCtrlµÄFireThreadEvent´Óprotected¸ÄΪpublic£¬µ±È»Ò²¿ÉÒÔÔÚCTFireCtrlÖÐн¨Ò»º¯Êý£¬Ôڸú¯ÊýÖÐFire£¬²»¹ý¶àÕÛÌÚÁËÒ»·¬£¬ÕâÀïÓúÍFireevÀý³ÌÖÐÏàͬµÄ·½·¨£º
LRESULT CMyWindow::OnFireThreadEvent(WPARAM wParam, LPARAM lParam) {
m_pCtrl->FireThreadEvent((LPCTSTR)lParam); return 0; }
d.Ìí¼ÓHWND Create()³ÉÔ±º¯Êý£¬ÒÔ´´½¨´°¿Ú£¬²¢·µ»Ø´°¿Ú¾ä±ú¹©Ïß³ÌPostMessageʹÓ᣺¯Êý¶¨ÒåÈçÏ£º
HWND CMyWindow::Create() {
//Register a window class LPCTSTR classname = 0;
classname = AfxRegisterWndClass(0);
//Create the window and return it's handle
CWnd::CreateEx(NULL,classname,NULL,NULL,1,1,1,1,NULL,NULL); ASSERT(m_hWnd!=NULL); return m_hWnd; }
e.ÖØÐ´PostNcDestroyÐéÄ⺯Êý£¬ÒÔÔÚ´°¿ÚÏú»Ùʱɾ³ýCMyWindowÀà¶ÔÏó void CMyWindow::PostNcDestroy() {
// TODO: Add your specialized code here and/or call the base class CWnd::PostNcDestroy(); delete this; }
3.¶¨ÒåÏ̺߳¯Êý
DWORD MyThread(LPVOID pParam) {
CTFireCtrl* pctrl = (CTFireCtrl*)pParam; while(!pctrl->m_bEnd){
DWORD dwRes = WaitForSingleObject(pctrl->m_hEvent, 100); if(dwRes == WAIT_OBJECT_0){
PostMessage(pctrl->m_hMyWnd, WM_THREADEVENT, 0, (LPARAM)LPCTSTR(pctrl->m_strParam)); } }
return 0; }
4.¿ÉÒÔ¿´µ½Ï̺߳¯ÊýÖÐÐèÒªÓõ½ºÜ¶à±äÁ¿£¬Òò´ËÔÚCTFireCtrlÖж¨Òå³ÉÔ±±äÁ¿ÈçÏ£º BOOL m_bEnd;//¿ØÖÆÏß³ÌÊÇ·ñ½áÊø
HANDLE m_hEvent;//ʼþ¾ä±ú£¬ÓÃ;¾Í²»¶à˵ÁË
HWND m_hMyWnd;//CMyWindowµÄ´°¿Ú¾ä±ú£¬ÓÉËüµÄCreateº¯Êý·µ»Ø»ñµÃ¡£
CString m_strParam;//ÓÃÀ´´«µÝ¸øÊ¼þ²ÎÊýµÄ×Ö·û´®£¬½ö×÷²Î¿¼Óã¬ÓÉTrigger·½·¨¸³Öµ»ñµÃ
5.¶¨ÒåStartº¯Êý void CTFireCtrl::Start() {
// TODO: Add your dispatch handler code here //³õʼ»¯´«µÝ¸øÏ̵߳ĸ÷¸ö±äÁ¿ m_bEnd = FALSE;
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); //½¨Á¢´«µÝʼþÓõÄÒþ²Ø´°¿Ú
CMyWindow* pwnd = new CMyWindow; pwnd->m_pCtrl = this;