IDispatch* , COM Server(LOCAL_SERVER), event data and C#.NET -
12-17-2007
, 01:11 PM
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(OnCallE vent);
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? |