IDispatch* , COM Server(LOCAL_SERVER), event data and C#.NET

Tech-Archive recommends: Fix windows errors by optimizing your registry



I wrote and maintain a high-performance COM server written in MFC (ATL guys
excuse me), to provide a COM layer on top of an existing SIP protocol stack
written in pure C. I have one main inbound interface called

_ISipPhone and corresponding outbound event interface called
_ISipEventCallback. Both are dispinterfaces. Event and APIs are working fine
up untill now when I intended to pass some structured data (event args)
accross. My intention is to use something like,



[ uuid(FA1A568E-EC16-4af4-8C7F-BD448057622F) ]

dispinterface _ISipEventCallback

{

properties:

// NOTE - ClassWizard will maintain property information here.

// Use extreme caution when editing this section.

//{{AFX_ODL_PROP(CSipEventCallback)

//}}AFX_ODL_PROP


methods:

// NOTE - ClassWizard will maintain method information here.

// Use extreme caution when editing this section.

//{{AFX_ODL_METHOD(CSipEventCallback)

//}}AFX_ODL_METHOD


[

id(1),

helpstring("method OnCallEvent")

]

HRESULT OnCallEvent(ccc_call_id iCallId,

ccc_line hLine,

sip_callstate_event event,

sip_callstate_cause cause,

BSTR bstrRemoteParty,

IDispatch* info);

//SAFEARRAY(VARIANT)* info);//IDispatch* Info);



};



Now first question is



1. what should ideally be passed as event args accross the proces? My client
is C#.



If IDispatch is the answer, I already did the following,



[ uuid(BC494DC1-B538-47ac-AC0F-BCC1BA3B63F7)]

interface _ICallInfo : IDispatch

{

[

propget,

id(1),

helpstring("Call ID")

]

HRESULT CallId([out, retval] LONG *pVal);


};



And the CoClass



[ uuid(AEC6F3D2-C579-49e5-82B9-E4934D708A0A)]

coclass CallInfo

{

[default] dispinterface _ICallInfo;

};



I tried passing IDispatch pointer for this interface impl. as the 6th
parameter of above event -



HRESULT OnCallEvent(ccc_call_id iCallId,

ccc_line hLine,

sip_callstate_event event,

sip_callstate_cause cause,

BSTR bstrRemoteParty,

IDispatch* info);



I did code following C++ wrapper class for the _ICallInfo impl.



class CCallInfo : public CCmdTarget

{

DECLARE_DYNCREATE(CCallInfo)

CCallInfo(); // protected constructor used by dynamic creation

// Attributes

public:

LONG CallId;



// Implementation

protected:

virtual ~CCallInfo();

// Generated message map functions

//{{AFX_MSG(CCallInfo)

// NOTE - the ClassWizard will add and remove member functions here.

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

DECLARE_OLECREATE(CCallInfo)

// Generated OLE dispatch map functions

//{{AFX_DISPATCH(CCallInfo)

//}}AFX_DISPATCH

DECLARE_DISPATCH_MAP()

DECLARE_INTERFACE_MAP()


enum

{

dispidCallId = 1L

};

};



The code for the source file is as below:



IMPLEMENT_DYNCREATE(CCallInfo, CCmdTarget)



CCallInfo::CCallInfo() {

EnableAutomation();


// To keep the application running as long as an OLE automation

// object is active, the constructor calls AfxOleLockApp.


AfxOleLockApp();

}



CCallInfo::~CCallInfo() {

// To terminate the application when all objects created with

// with OLE automation, the destructor calls AfxOleUnlockApp.


AfxOleUnlockApp();

}



void CCallInfo::OnFinalRelease() {

// When the last reference for an automation object is released

// OnFinalRelease is called. The base class will automatically

// deletes the object. Add additional cleanup required for your

// object before calling the base class.

CCmdTarget::OnFinalRelease();

}



BEGIN_MESSAGE_MAP(CCallInfo, CCmdTarget)

//{{AFX_MSG_MAP(CCallInfo)

// NOTE - the ClassWizard will add and remove mapping macros here.

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

BEGIN_DISPATCH_MAP(CCallInfo, CCmdTarget)

//{{AFX_DISPATCH_MAP(CCallInfo)

//}}AFX_DISPATCH_MAP

DISP_PROPERTY_ID(CCallInfo, "CallId", dispidCallId, CallId, VT_I4)

END_DISPATCH_MAP()

//

// Note:

// we add support for IID_ICallInfo to support typesafe binding

// from VBA. This IID must match the GUID that is attached to the

// dispinterface in the .ODL file.



//

// _ICallInfo GUID {BC494DC1-B538-47ac-AC0F-BCC1BA3B63F7}

static const IID IID_ICallInfo =

{ 0xbc494dc1, 0xb538, 0x47ac, { 0xac, 0x0f, 0xbc, 0xc1, 0xba, 0x3b, 0x63,
0xf7 } };

BEGIN_INTERFACE_MAP(CCallInfo, CCmdTarget)

INTERFACE_PART(CCallInfo, IID_ICallInfo, Dispatch)

END_INTERFACE_MAP()

//

// CallInfo CoClass GUID {AEC6F3D2-C579-49e5-82B9-E4934D708A0A}

IMPLEMENT_OLECREATE(CCallInfo, "SipServer.CallInfo", 0xaec6f3d2, 0xc579,
0x49e5, 0x82, 0xb9, 0xe4, 0x93, 0x4d, 0x70, 0x8a, 0x0a)



The calling code is shown below:


static BYTE paramInfo[] = VTS_UI4 VTS_UI4 VTS_I4 VTS_I4 VTS_BSTR
VTS_DISPATCH;//VTS_VARIANT; //VTS_DISPATCH;


CCallInfo* callIno = new CCallInfo();

callIno->CallId = 45;

LPDISPATCH lpdispCallInfo = callIno->GetIDispatch(FALSE);

if ((callIno == NULL) || (lpdispCallInfo == NULL))

{

AfxMessageBox(CString("CallInfo NULL"));

}



// Retrieve the array of connected interfaces from the connection point

const CPtrArray* pConnections = m_xSipServerEvents.GetConnections();

ASSERT(pConnections != NULL);


// Iterate through array, calling the event on each interface

int cConnections = pConnections->GetSize();

COleDispatchDriver sipxEvent;

for (int i = 0; i < cConnections; i++)

{

if((IDispatch*)pConnections->GetAt(i))

{

sipxEvent.AttachDispatch((IDispatch*)pConnections->GetAt(i), false);


try

{

//OnCallEvent()

sipxEvent.InvokeHelper(0x1,

DISPATCH_METHOD,

VT_EMPTY,

NULL,

paramInfo, //param info types: VTS_...

hCall,

hLine,
event,

cause,

_ConvertStringToBSTR (pszRemoteParty),

lpdispCallInfo);

//vaPacket);

}

catch(COleException* ex)

{

#ifdef _DEBUG

AfxMessageBox(CString("Error :" + ex->ReportError()));

#endif

}


catch(...)

{

}


sipxEvent.DetachDispatch();

}

}



At the C# side my event handler (which was working earlier ) looks like



m_sipPhone.OnCallEvent += new
_ISipEventCallback_OnCallEventEventHandler(OnCallEvent);



void OnCallEvent(int hCall,

int hLine,

sip_callstate_event cevent,

sip_callstate_cause cause,

string strRemoteParty,

object callInfo)

//ref object[] callInfo)

{

//...


}



My intention is to access the properties of _ICallInfo interface like



// int call_id = callInfo.CallId; //(int) pVarResult[0];



At first event was not firing at all just after I put IDispatch* in
OnCallEvent's 6th parameter. Now though event is firing but the object I got
in my handler is of type generic COM object or System.__ComObject.



Am I doing it correctly?

.



Relevant Pages

  • Re: Is it possible to know within a function which object called it
    ... that there is an error in the design. ... my system that I would want to prevent them from calling this function. ... // execute if okay ... interface ICanBeProcessed ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Problems with IDispatchImpl
    ... you have your own dual interface defined in another type library. ... You have to check if this IApplication is indeed a dual interface. ... IDispatch by hand (based on your previous post, ... > The IDispatch methods are indeed implemented by IDispatchImpl, ...
    (microsoft.public.vc.atl)
  • Re: Problems with IDispatchImpl
    ... you have your own dual interface defined in another type library. ... You have to check if this IApplication is indeed a dual interface. ... IDispatch by hand (based on your previous post, ... > The IDispatch methods are indeed implemented by IDispatchImpl, ...
    (microsoft.public.vc.atl)
  • Re: Problems with IDispatchImpl
    ... > you have your own dual interface defined in another type library. ... > You have to check if this IApplication is indeed a dual interface. ... > IDispatch by hand (based on your previous post, ... >> perfnurt at hotmail dot com ...
    (microsoft.public.vc.atl)
  • Re: Creating object inside an ISAPI DLL - does registry settings required?
    ... interface needs hand-coding in ATL. ... > ActiveX implementation so the same DLL can server both purposes (that will ... > the ISAPI Dll does not utilize any sytem resources such as registry). ... > ATL IDispatch implementation is based on type library, ...
    (microsoft.public.vc.atl)