Get Events from an COM Server
-
Hi All, now I get connected in my main.cpp file to the server. I hope this will be correct. But how can I get now an event from the server? The server sends some events. I can see that because an Message Dialog will be opened from the server. Now my questions are the following: a) Is the code until now correct? Is it possible to make a test if I get the correct connection or anything else? b) How can I get in the main.cpp an event (OnShowMessageDlg) or any message from the server? Do I need to add something to the sink class? c) Must I add something in the Sink class to get the an event in the invoke function? Or how should this work? Let me know If you need any more information. Once more, thanks for any help. Juergen main.cpp File
CComPtr<ICWOLE2> tCWOLE;
HRESULT hr;
hr = CoInitialize(0);hr = CoCreateInstance(CLSID_CWOLEv2, 0, CLSCTX_LOCAL_SERVER, IID_ICWOLE2, (void**)&tCWOLE);
IConnectionPointContainer * pConnPtContainer;
hr = tCWOLE->QueryInterface(IID_IConnectionPointContainer,(void**)&pConnPtContainer);
if(FAILED(hr)){
CoUninitialize();
return false;
}
CComPtr<IConnectionPoint> ICPoint;
hr = pConnPtContainer->FindConnectionPoint(DIID_ICWOLEEvents,&m_pConnectionPoint);
if(FAILED(hr)){
CoUninitialize();
return false;
}m_sink = new CSink;
LPUNKNOWN pUnk = NULL;
m_sink->QueryInterface(IID_IUnknown,(void**)&pUnk);
hr = m_pConnectionPoint->Advise(pUnk,&m_sink->cookie);
if(FAILED(hr)){
CoUninitialize();
return false;
}
pConnPtContainer->Release();
.
.
.
// Here I must get the event from the COM Server, but how can this be done???
// How can I test if I get the information from the correct class??
.
.
.m_pConnectionPoint->Unadvise(m_sink->cookie);
m_pConnectionPoint->Release();
m_sink->Release();CSink.h
class CSink : public ICWOLEEvents
{
public:CSink::CSink() {m\_refCount = 1, cookie = 0;} CSink::~CSink() {} STDMETHODIMP QueryInterface(REFIID riid, void \*\* ppvObj); //HRESULT \_stdcall STDMETHODIMP\_(ULONG) AddRef(); // Note the underscore STDMETHODIMP\_(ULONG) Release(); STDMETHODIMP GetTypeInfoCount(UINT \*iTInfo); STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo \*\*ppTInfo); STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR \*\*rgszNames, UINT cNames, LCID lcid, DISPID \*rgDispId); STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS
-
Hi All, now I get connected in my main.cpp file to the server. I hope this will be correct. But how can I get now an event from the server? The server sends some events. I can see that because an Message Dialog will be opened from the server. Now my questions are the following: a) Is the code until now correct? Is it possible to make a test if I get the correct connection or anything else? b) How can I get in the main.cpp an event (OnShowMessageDlg) or any message from the server? Do I need to add something to the sink class? c) Must I add something in the Sink class to get the an event in the invoke function? Or how should this work? Let me know If you need any more information. Once more, thanks for any help. Juergen main.cpp File
CComPtr<ICWOLE2> tCWOLE;
HRESULT hr;
hr = CoInitialize(0);hr = CoCreateInstance(CLSID_CWOLEv2, 0, CLSCTX_LOCAL_SERVER, IID_ICWOLE2, (void**)&tCWOLE);
IConnectionPointContainer * pConnPtContainer;
hr = tCWOLE->QueryInterface(IID_IConnectionPointContainer,(void**)&pConnPtContainer);
if(FAILED(hr)){
CoUninitialize();
return false;
}
CComPtr<IConnectionPoint> ICPoint;
hr = pConnPtContainer->FindConnectionPoint(DIID_ICWOLEEvents,&m_pConnectionPoint);
if(FAILED(hr)){
CoUninitialize();
return false;
}m_sink = new CSink;
LPUNKNOWN pUnk = NULL;
m_sink->QueryInterface(IID_IUnknown,(void**)&pUnk);
hr = m_pConnectionPoint->Advise(pUnk,&m_sink->cookie);
if(FAILED(hr)){
CoUninitialize();
return false;
}
pConnPtContainer->Release();
.
.
.
// Here I must get the event from the COM Server, but how can this be done???
// How can I test if I get the information from the correct class??
.
.
.m_pConnectionPoint->Unadvise(m_sink->cookie);
m_pConnectionPoint->Release();
m_sink->Release();CSink.h
class CSink : public ICWOLEEvents
{
public:CSink::CSink() {m\_refCount = 1, cookie = 0;} CSink::~CSink() {} STDMETHODIMP QueryInterface(REFIID riid, void \*\* ppvObj); //HRESULT \_stdcall STDMETHODIMP\_(ULONG) AddRef(); // Note the underscore STDMETHODIMP\_(ULONG) Release(); STDMETHODIMP GetTypeInfoCount(UINT \*iTInfo); STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo \*\*ppTInfo); STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR \*\*rgszNames, UINT cNames, LCID lcid, DISPID \*rgDispId); STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS
Yes, you need to add code into the Invoke methods that looks at the dispid that's passed and maps that to the method you need to call. In addition, you need to unpack the parameter values from the struct pointed at by pDispParams. Also, that thread needs to be in a window message dispatch loop - my understanding is that COM method calls are passed from other threads and processes into your thread using windows messages. I know you can't/don't want to use ATL and I can totally understand that...but ATL does make this sort of thing REALLY easy :-)
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
Yes, you need to add code into the Invoke methods that looks at the dispid that's passed and maps that to the method you need to call. In addition, you need to unpack the parameter values from the struct pointed at by pDispParams. Also, that thread needs to be in a window message dispatch loop - my understanding is that COM method calls are passed from other threads and processes into your thread using windows messages. I know you can't/don't want to use ATL and I can totally understand that...but ATL does make this sort of thing REALLY easy :-)
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
Hi Stuart, thanks a lot for your reply. Do you know if there will be an example about the invoke theme? I didn't know how this function will/must be called and how my functions then will be called / how I can get a message from the COM server above this invoke functions. I know and I heared also from other people :) that it will be easier to work with ATL. But in this project I can't use ATL.
-
Hi Stuart, thanks a lot for your reply. Do you know if there will be an example about the invoke theme? I didn't know how this function will/must be called and how my functions then will be called / how I can get a message from the COM server above this invoke functions. I know and I heared also from other people :) that it will be easier to work with ATL. But in this project I can't use ATL.
OK - the Invoke method is called when an event is raised by the server. It will tell you which method it's calling using the dispidMember parameter. The parameters to the call will be in the structure pointed at by pdispparams. You can pass back a result in pvarResult. So, you could implement your Invoke using a switch statement and parameter transformation like this:
STDMETHODIMP CSink::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS* pDispParams,
VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
UINT* puArgErr)
{if ((riid != IID_NULL))
return E_INVALIDARG;HRESULT hr = S_OK; // Initialize
switch (dispIdMember)
{
case 1: // OnConfigurationApply
// Here we need to verify that the parameters passed are what we expect (a VARIANT_BOOL*)
// then call the OnConfigurationApply with these passed parameters
if (pDispParams->cArgs != 1) return E_INVALIDARG;
if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL|VT_BYREF) return E_INVALIDARG;
OnConfigurationApply(V_BOOLREF(&pDispParams->rgvarg[0]));
break;
case 2: // OnShowMessageDlg
// Do as for OnConfigurationApply
break;
}return hr;
}HTH!
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
OK - the Invoke method is called when an event is raised by the server. It will tell you which method it's calling using the dispidMember parameter. The parameters to the call will be in the structure pointed at by pdispparams. You can pass back a result in pvarResult. So, you could implement your Invoke using a switch statement and parameter transformation like this:
STDMETHODIMP CSink::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS* pDispParams,
VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
UINT* puArgErr)
{if ((riid != IID_NULL))
return E_INVALIDARG;HRESULT hr = S_OK; // Initialize
switch (dispIdMember)
{
case 1: // OnConfigurationApply
// Here we need to verify that the parameters passed are what we expect (a VARIANT_BOOL*)
// then call the OnConfigurationApply with these passed parameters
if (pDispParams->cArgs != 1) return E_INVALIDARG;
if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL|VT_BYREF) return E_INVALIDARG;
OnConfigurationApply(V_BOOLREF(&pDispParams->rgvarg[0]));
break;
case 2: // OnShowMessageDlg
// Do as for OnConfigurationApply
break;
}return hr;
}HTH!
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
The problem I have before is that the Invoke Function will not be called. What must I do that this function will be called from the Server when an event is raised? I can see that an event is raised from the server because an dialog will be opended. But the invoke function will not be called.
-
The problem I have before is that the Invoke Function will not be called. What must I do that this function will be called from the Server when an event is raised? I can see that an event is raised from the server because an dialog will be opended. But the invoke function will not be called.
Your code all looks reasonable - I presume you've set a breakpoint in your Invoke method to see if it gets called? I'd also set breakpoints on your AddRef, QueryInterface methods and see if they get called when you call the connection point's Advise method - that's how you tell the server about your event handler.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
Your code all looks reasonable - I presume you've set a breakpoint in your Invoke method to see if it gets called? I'd also set breakpoints on your AddRef, QueryInterface methods and see if they get called when you call the connection point's Advise method - that's how you tell the server about your event handler.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
I set now also some breakpoints in the AddRef and QueryInterface Methods. These methods will be called. Only the Invoke function will not be called. Do you know what I can do to test if I did something wrong or if the COM server works correct?
-
I set now also some breakpoints in the AddRef and QueryInterface Methods. These methods will be called. Only the Invoke function will not be called. Do you know what I can do to test if I did something wrong or if the COM server works correct?
Suddenly realised what your problem could well be. The server could be asking for your event handler's dispinterface methods by name - in which case you would need to implement GetIDsOfNames. Or it could be asking for your class's type-information, in order to determine what methods and associated parameters are available. I think you need to investigate (with breakpoints) whether the othe r IDispatch methods are called. If they are, then as you don't implement them, the server will (as a result) decide not to call your IDispatch::Invoke method. All these details, and the pain of implementation, are why I use ATL - I fully accept that you can't use ATL - I sympathize with your predicament!
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
Suddenly realised what your problem could well be. The server could be asking for your event handler's dispinterface methods by name - in which case you would need to implement GetIDsOfNames. Or it could be asking for your class's type-information, in order to determine what methods and associated parameters are available. I think you need to investigate (with breakpoints) whether the othe r IDispatch methods are called. If they are, then as you don't implement them, the server will (as a result) decide not to call your IDispatch::Invoke method. All these details, and the pain of implementation, are why I use ATL - I fully accept that you can't use ATL - I sympathize with your predicament!
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
I tried it now with the breakpoints. The functions QueryInterface / AddRef and Release (IUnknown) will be called. But all the four IDispatch methods (GetTypeInfoCount / GetTypeInfo / GetIDsOfNames / Invoke) will not be called. So now if I understood you correct, I must implement (call the method) GetIDsOfNames by myself? I tried the implementation of the method GetIDsOfNames a little bit but my application crashed down anytime. Please give me a note if I understood you correctly that the solution must be to implement this function. If so, I must search for some better examples about that and try it again. :-D Thanks for your help.
-
I tried it now with the breakpoints. The functions QueryInterface / AddRef and Release (IUnknown) will be called. But all the four IDispatch methods (GetTypeInfoCount / GetTypeInfo / GetIDsOfNames / Invoke) will not be called. So now if I understood you correct, I must implement (call the method) GetIDsOfNames by myself? I tried the implementation of the method GetIDsOfNames a little bit but my application crashed down anytime. Please give me a note if I understood you correctly that the solution must be to implement this function. If so, I must search for some better examples about that and try it again. :-D Thanks for your help.
Have a look more closely at what interfaces are being asked for in QueryInterface. The fact that your IDispatch methods aren't being called means that implementing GetIDsOfNames isn't going to help - you need to work out what the server's actually trying to access on your event handler object.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
Hi All, now I get connected in my main.cpp file to the server. I hope this will be correct. But how can I get now an event from the server? The server sends some events. I can see that because an Message Dialog will be opened from the server. Now my questions are the following: a) Is the code until now correct? Is it possible to make a test if I get the correct connection or anything else? b) How can I get in the main.cpp an event (OnShowMessageDlg) or any message from the server? Do I need to add something to the sink class? c) Must I add something in the Sink class to get the an event in the invoke function? Or how should this work? Let me know If you need any more information. Once more, thanks for any help. Juergen main.cpp File
CComPtr<ICWOLE2> tCWOLE;
HRESULT hr;
hr = CoInitialize(0);hr = CoCreateInstance(CLSID_CWOLEv2, 0, CLSCTX_LOCAL_SERVER, IID_ICWOLE2, (void**)&tCWOLE);
IConnectionPointContainer * pConnPtContainer;
hr = tCWOLE->QueryInterface(IID_IConnectionPointContainer,(void**)&pConnPtContainer);
if(FAILED(hr)){
CoUninitialize();
return false;
}
CComPtr<IConnectionPoint> ICPoint;
hr = pConnPtContainer->FindConnectionPoint(DIID_ICWOLEEvents,&m_pConnectionPoint);
if(FAILED(hr)){
CoUninitialize();
return false;
}m_sink = new CSink;
LPUNKNOWN pUnk = NULL;
m_sink->QueryInterface(IID_IUnknown,(void**)&pUnk);
hr = m_pConnectionPoint->Advise(pUnk,&m_sink->cookie);
if(FAILED(hr)){
CoUninitialize();
return false;
}
pConnPtContainer->Release();
.
.
.
// Here I must get the event from the COM Server, but how can this be done???
// How can I test if I get the information from the correct class??
.
.
.m_pConnectionPoint->Unadvise(m_sink->cookie);
m_pConnectionPoint->Release();
m_sink->Release();CSink.h
class CSink : public ICWOLEEvents
{
public:CSink::CSink() {m\_refCount = 1, cookie = 0;} CSink::~CSink() {} STDMETHODIMP QueryInterface(REFIID riid, void \*\* ppvObj); //HRESULT \_stdcall STDMETHODIMP\_(ULONG) AddRef(); // Note the underscore STDMETHODIMP\_(ULONG) Release(); STDMETHODIMP GetTypeInfoCount(UINT \*iTInfo); STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo \*\*ppTInfo); STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR \*\*rgszNames, UINT cNames, LCID lcid, DISPID \*rgDispId); STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS
Stuart, thanks for your help. Now it seems to work. The problem was that the Connection (Advise) must be done before I open the programm. If I do this Advise after the program start I didn't get any events.