In my project, I wrote a component which will be called in a service(COM server). There is another process will get this component's interface and register a callback interface through connection point. So the service could use the callback interface to do some feedback.
But I found that when I use the IConnectionPoint::Advise to register my callback interface cause a crash.
I implement the connection point manually. Here are part of my code:
class ATL_NO_VTABLE CUploadManager :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CUploadManager, &CLSID_UploadManager>,
public IUploadManager,
public IConnectionPointContainer,
public IConnectionPoint
...
// IConnectionPointContainer Functions
STDMETHODIMP EnumConnectionPoints(IEnumConnectionPoints **ppEnum);
STDMETHODIMP FindConnectionPoint(REFIID riid, IConnectionPoint **ppCP);
// IConnectionPoint Functions
STDMETHODIMP GetConnectionInterface(IID *pIID);
STDMETHODIMP GetConnectionPointContainer(IConnectionPointContainer **ppCPC);
STDMETHODIMP Advise(IUnknown *pUnkSink, DWORD *pdwCookie);
STDMETHODIMP Unadvise(DWORD dwCookie);
STDMETHODIMP EnumConnections(IEnumConnections **ppEnum);
In the client, I have get the component interface already, then I get the connection point and try to call function Advise:
...
CComPtr<IConnectionPointContainer> pCPC;
hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (LPVOID *)&pCPC);
if (FAILED(hr))
{
return ;
}
CComPtr<IConnectionPoint> pConnectionPoint;
hr = pCPC->FindConnectionPoint(__uuidof(_IEvents), &pConnectionPoint);
if (SUCCEEDED(hr))
{
DWORD dwCookie = 0;
CDataCallback* pCallback = new CDataCallback();
IUnknown* pUnknown = NULL;
pCallback->QueryInterface(IID_IUnknown, (void**)&pUnknown);
hr = pConnectionPoint->Advise(pUnknown, &dwCookie);
...
All interface pointers could be got successfully, but when I call Advise, the crash occurs. The strange thing is the crash is not happened in the Advise implementation, it seems occurs in the RPC call process, the call stack is like this:
003d0070() <----crash here
combase.dll!76eea3ab()
[Frames below may be incorrect and/or missing, no symbols loaded for combase.dll]
combase.dll!76ee9d00()
rpcrt4.dll!7612a53d()
mfc90ud.dll!CDialog::OnCmdMsg
...
But if the first parameter of Advise is NULL, the function Advise could be executed.
Here is the Sink code implemented in client:
class CDataCallback : public _IEvents
{
public:
CDataCallback() {}
~CDataCallback() {}
HRESULT __stdcall QueryInterface(REFIID iid, LPVOID* ppInterface)
{
*ppInterface = this;
return S_OK;
}
ULONG STDMETHODCALLTYPE AddRef()
{
return 1;
}
ULONG STDMETHODCALLTYPE Release()
{
return 0;
}
HRESULT __stdcall TestFunc()
{
...
return S_OK;
}
};
The interface _IEvents is generated in the component which will be used as a callback in the connection point. I just use this class to test the connection point, so the implementation is very simple.
I have no idea about how this crash occurs. Thanks for all your help!
The problem is likely to be in your
CDataCallback
class. It'sQueryInterface
implementation is unsafe and returns interface pointer incorrectly.You have to check
iid
and returnE_NOINTERFACE
in case requested interface is not_IEvents
. Basically you can set a breakpoint there and see if you have a call there prior to crash and check the arguments.Your sink might be queried for other interfaces (
IMarhsal
etc) and you have to properly indicate that you are not implementing them, instead of returning unmatching pointer, use of which leads to undefined behavior.