Connection point interface failing miserably

Magnus Werner <[email protected]> Thu, 20 Feb 2003 07:08:28 -0800
Newsgroups gmane.comp.windows.devel.vbcom
Message-ID <VBCOM%[email protected]>
I've implemented a simple ActiveX COM server using ATL. It implements a
connection point interface that will be used to call back to a VB client.
For some reason (that I'd very much like to know) there is a catastrophic
failure when firing the event. The pDispatch->Invoke causes an Access
violation in VB6. Why is that? I'd be most grateful for any suggestions how
to solve this.

Regards,
Magnus Werner

// IDLTest.idl : IDL source for IDLTest.dll
//

// This file will be processed by the MIDL tool to
// produce the type library (IDLTest.tlb) and marshalling code.

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]
short Delay);
  [id(2), helpstring("method Cancel")] HRESULT Cancel();
 };

[
 uuid(152812E3-0A28-42DB-8F22-1A5C75CF01CB),
 version(1.0),
 helpstring("IDLTest 1.0 Type Library")
]
library IDLTESTLib
{
 importlib("stdole32.tlb");
 importlib("stdole2.tlb");

 [
  uuid(A006CA98-3C7D-441A-865E-F64C42B4B0A6),
  helpstring("IExpImpEvents Interface")
 ]
 dispinterface IExpImpEvents
 {
  properties:
  methods:
  [id(1), helpstring("method OnProgress")] HRESULT OnProgress
([in] long Progress);
  [id(2), helpstring("method OnComplete")] HRESULT OnComplete
();
  [id(3), helpstring("method OnCancel")] HRESULT OnCancel();
 };

 [
  uuid(1EE8B0E4-C43F-45C7-BD94-D50809E47BB9),
  helpstring("ExpImp Class")
 ]
 coclass ExpImp
 {
  [default] interface IExpImp;
  [default, source] dispinterface IExpImpEvents;
 };
};

============================================================================

// ExpImp.h : Declaration of the CExpImp

#ifndef __EXPIMP_H_
#define __EXPIMP_H_

#include "resource.h"       // main symbols
#include "IDLTestCP.h"

////////////////////////////////////////////////////////////////////////////
/
// CExpImp
class ATL_NO_VTABLE CExpImp :
 public CComObjectRootEx<CComSingleThreadModel>,
 public CComCoClass<CExpImp, &CLSID_ExpImp>,
 public ISupportErrorInfo,
 public IConnectionPointContainerImpl<CExpImp>,
 public IDispatchImpl<IExpImp, &IID_IExpImp, &LIBID_IDLTESTLib>,
 public CProxy_IExpImpEvents< CExpImp >,
 public IProvideClassInfo2Impl< &CLSID_ExpImp, &DIID_IExpImpEvents,
&LIBID_IDLTESTLib, 1, 0 >
{
public:
 CExpImp()
 {
 }

DECLARE_REGISTRY_RESOURCEID(IDR_EXPIMP)

DECLARE_PROTECT_FINAL_CONSTRUCT()

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()


// ISupportsErrorInfo
 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);

// IExpImp
public:
 STDMETHOD(Cancel)();
 STDMETHOD(Export)(/*[in]*/ short Delay);

 void run();

private:
 short m_sDelay;
 HANDLE m_hThread;
 DWORD m_dwThreadId;
 bool m_bCanceled;
};

#endif //__EXPIMP_H_
============================================================================

// ExpImp.cpp : Implementation of CExpImp
#include "stdafx.h"
#include "IDLTest.h"
#include "ExpImp.h"

DWORD WINAPI ThreadProc(
  LPVOID lpParameter   // thread data
)
{
 CExpImp *pCExpImp = static_cast<CExpImp*>(lpParameter);

 pCExpImp->run();

 return 0; // Thread exit code
}

////////////////////////////////////////////////////////////////////////////
/
// CExpImp

STDMETHODIMP CExpImp::InterfaceSupportsErrorInfo(REFIID riid)
{
 static const IID* arr[] =
 {
  &IID_IExpImp
 };
 for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
 {
  if (InlineIsEqualGUID(*arr[i],riid))
   return S_OK;
 }
 return S_FALSE;
}

STDMETHODIMP CExpImp::Export(short Delay)
{
 m_bCanceled = false;
 m_hThread = ::CreateThread(NULL,
  // Default security descriptor
         0,
      // Default stack size

&ThreadProc,    // Thread start routing

static_cast<LPVOID>(this), // Arguments to start routine
         0,
      // Creation flags

&m_dwThreadId);
 if (m_hThread == NULL)
  return HRESULT_FROM_WIN32(GetLastError());

 return S_OK;
}

void CExpImp::run()
{
 CoInitialize(0);
 for (int i=0; i<101; i++)
 {
  if (m_bCanceled)
  {
   HRESULT hr = Fire_OnCancel();
   CoUninitialize();
   ::ExitThread(1);
  }
  HRESULT hr = Fire_OnProgress(i);
 }

 HRESULT hr = Fire_OnComplete();
 CoUninitialize();
}

STDMETHODIMP CExpImp::Cancel()
{
 m_bCanceled = true;

 return S_OK;
}
============================================================================

Private WithEvents ProgressHandler As IDLTESTLib.ExpImp
Private Sub CancelButton_Click()
    ProgressHandler.Cancel
End Sub

Private Sub Form_Load()
    On Error GoTo error
    Set ProgressHandler = New ExpImp
    Exit Sub
error:
    MsgBox Err.Description
End Sub

Private Sub OKButton_Click()
   ProgressHandler.Export 2
   'For i = 1 To 100
   '     ProgressBar1.Value = i
   'Next
End Sub

Private Sub ProgressHandler_OnCancel()
    'TBD
End Sub

Private Sub ProgressHandler_OnComplete()
    'TBD
End Sub

Private Sub ProgressHandler_OnProgress(ByVal Progress As Long)
    ProgressBar1.Value = Progress
End Sub

You can read messages from the VBCOM archive, unsubscribe from VBCOM, or
subscribe to other DevelopMentor lists at http://discuss.develop.com.