Re: Connection point interface failing miserably
Jon Kale <[email protected]> Thu, 20 Feb 2003 15:53:05 -0000
| Newsgroups | gmane.comp.windows.devel.vbcom |
|---|---|
| Message-ID | <[email protected]> |
VB generally gets *very* unhappy if you fire an event on a thread other than the one that the initial registration was on. Why? Well, VB likes to be in an STA, which means that your interface pointer is apartment-bound: you've got to marshall the relevant interface pointer across apartments to the calling thread before calling on it. There's two ways of doing this: the complicated, NT-only way involves the GIT (the global interface table) while the simple, 9x-and-NT way involves posting messages from your event-raising thread to a hidden window. See Q206076 and Q196026 respectively for details -- Jon > -----Original Message----- > From: Magnus Werner [mailto:[email protected]]=20 > Sent: 20 February 2003 3:08 pm > To: [email protected] > Subject: [VBCOM] Connection point interface failing miserably >=20 >=20 > I've implemented a simple ActiveX COM server using ATL. It=20 > implements a connection point interface that will be used to=20 > call back to a VB client. For some reason (that I'd very much=20 > like to know) there is a catastrophic failure when firing the=20 > event. The pDispatch->Invoke causes an Access violation in=20 > VB6. Why is that? I'd be most grateful for any suggestions=20 > how to solve this. >=20 > Regards, > Magnus Werner >=20 > // IDLTest.idl : IDL source for IDLTest.dll > // >=20 > // This file will be processed by the MIDL tool to > // produce the type library (IDLTest.tlb) and marshalling code. >=20 > import "oaidl.idl"; > import "ocidl.idl"; > [ > object, > uuid(80C10722-4741-4EEC-A1C8-8DC4A97159EF), > dual, > helpstring("IExpImp Interface"), > pointer_default(unique) > ] > interface IExpImp : IDispatch > { > [id(1), helpstring("method Export")] HRESULT Export([in]=20 > short Delay); > [id(2), helpstring("method Cancel")] HRESULT Cancel(); > }; >=20 > [ > uuid(152812E3-0A28-42DB-8F22-1A5C75CF01CB), > version(1.0), > helpstring("IDLTest 1.0 Type Library") > ] > library IDLTESTLib > { > importlib("stdole32.tlb"); > importlib("stdole2.tlb"); >=20 > [ > uuid(A006CA98-3C7D-441A-865E-F64C42B4B0A6), > helpstring("IExpImpEvents Interface") > ] > dispinterface IExpImpEvents > { > properties: > methods: > [id(1), helpstring("method OnProgress")] HRESULT OnProgress=20 > ([in] long Progress); > [id(2), helpstring("method OnComplete")] HRESULT OnComplete (); > [id(3), helpstring("method OnCancel")] HRESULT OnCancel(); > }; >=20 > [ > uuid(1EE8B0E4-C43F-45C7-BD94-D50809E47BB9), > helpstring("ExpImp Class") > ] > coclass ExpImp > { > [default] interface IExpImp; > [default, source] dispinterface IExpImpEvents; > }; > }; >=20 > = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >=20 > // ExpImp.h : Declaration of the CExpImp >=20 > #ifndef __EXPIMP_H_ > #define __EXPIMP_H_ >=20 > #include "resource.h" // main symbols > #include "IDLTestCP.h" >=20 > ////////////////////////////////////////////////////////////// > ////////////// > / > // CExpImp > class ATL_NO_VTABLE CExpImp : > public CComObjectRootEx<CComSingleThreadModel>, > public CComCoClass<CExpImp, &CLSID_ExpImp>, > public ISupportErrorInfo, > public IConnectionPointContainerImpl<CExpImp>, > public IDispatchImpl<IExpImp, &IID_IExpImp,=20 > &LIBID_IDLTESTLib>, public CProxy_IExpImpEvents< CExpImp >, =20 > public IProvideClassInfo2Impl< &CLSID_ExpImp,=20 > &DIID_IExpImpEvents, &LIBID_IDLTESTLib, 1, 0 > { > public: > CExpImp() > { > } >=20 > DECLARE_REGISTRY_RESOURCEID(IDR_EXPIMP) >=20 > DECLARE_PROTECT_FINAL_CONSTRUCT() >=20 > BEGIN_COM_MAP(CExpImp) > COM_INTERFACE_ENTRY(IExpImp) > COM_INTERFACE_ENTRY(IDispatch) > COM_INTERFACE_ENTRY(ISupportErrorInfo) > COM_INTERFACE_ENTRY(IConnectionPointContainer) > COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer) > COM_INTERFACE_ENTRY(IProvideClassInfo2) > COM_INTERFACE_ENTRY(IProvideClassInfo) > END_COM_MAP() > BEGIN_CONNECTION_POINT_MAP(CExpImp) > CONNECTION_POINT_ENTRY(DIID_IExpImpEvents) > END_CONNECTION_POINT_MAP() >=20 >=20 > // ISupportsErrorInfo =20 > STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid); >=20 > // IExpImp > public: > STDMETHOD(Cancel)(); > STDMETHOD(Export)(/*[in]*/ short Delay); >=20 > void run(); >=20 > private: > short m_sDelay; > HANDLE m_hThread; > DWORD m_dwThreadId; > bool m_bCanceled; > }; >=20 > #endif //__EXPIMP_H_=20 > = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >=20 > // ExpImp.cpp : Implementation of CExpImp > #include "stdafx.h" > #include "IDLTest.h" > #include "ExpImp.h" >=20 > DWORD WINAPI ThreadProc( > LPVOID lpParameter // thread data > ) > { > CExpImp *pCExpImp =3D static_cast<CExpImp*>(lpParameter); >=20 > pCExpImp->run(); >=20 > return 0; // Thread exit code > } >=20 > ////////////////////////////////////////////////////////////// > ////////////// > / > // CExpImp >=20 > STDMETHODIMP CExpImp::InterfaceSupportsErrorInfo(REFIID riid) > { > static const IID* arr[] =3D > { > &IID_IExpImp > }; > for (int i=3D0; i < sizeof(arr) / sizeof(arr[0]); i++) > { > if (InlineIsEqualGUID(*arr[i],riid)) > return S_OK; > } > return S_FALSE; > } >=20 > STDMETHODIMP CExpImp::Export(short Delay) > { > m_bCanceled =3D false; > m_hThread =3D ::CreateThread(NULL, > // Default security descriptor > 0, > // Default stack size >=20 > &ThreadProc, // Thread start routing >=20 > static_cast<LPVOID>(this), // Arguments to start routine > 0, > // Creation flags >=20 > &m_dwThreadId); > if (m_hThread =3D=3D NULL) > return HRESULT_FROM_WIN32(GetLastError()); >=20 > return S_OK; > } >=20 > void CExpImp::run() > { > CoInitialize(0); > for (int i=3D0; i<101; i++) > { > if (m_bCanceled) > { > HRESULT hr =3D Fire_OnCancel(); > CoUninitialize(); > ::ExitThread(1); > } > HRESULT hr =3D Fire_OnProgress(i); > } >=20 > HRESULT hr =3D Fire_OnComplete(); > CoUninitialize(); > } >=20 > STDMETHODIMP CExpImp::Cancel() > { > m_bCanceled =3D true; >=20 > return S_OK; > }=20 > = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >=20 > Private WithEvents ProgressHandler As IDLTESTLib.ExpImp > Private Sub CancelButton_Click() > ProgressHandler.Cancel > End Sub >=20 > Private Sub Form_Load() > On Error GoTo error > Set ProgressHandler =3D New ExpImp > Exit Sub > error: > MsgBox Err.Description > End Sub >=20 > Private Sub OKButton_Click() > ProgressHandler.Export 2 > 'For i =3D 1 To 100 > ' ProgressBar1.Value =3D i > 'Next > End Sub >=20 > Private Sub ProgressHandler_OnCancel() > 'TBD > End Sub >=20 > Private Sub ProgressHandler_OnComplete() > 'TBD > End Sub >=20 > Private Sub ProgressHandler_OnProgress(ByVal Progress As Long) > ProgressBar1.Value =3D Progress > End Sub >=20 > You can read messages from the VBCOM archive, unsubscribe=20 > from VBCOM, or subscribe to other DevelopMentor lists at=20 > http://discuss.develop.com. >=20 You can read messages from the VBCOM archive, unsubscribe from VBCOM, or subscribe to other DevelopMentor lists at http://discuss.develop.com.