When dealing with interprocess COM
objects, is it safe to cast a IDispatch*
into an IUnknown*
, without using QueryInterface
?
Here our IDispatch
object comes from an other process OtherProcess.exe
.
And a colleague of mine says that I should call QueryInterface
on the IDispatch
so as to get an IUnknown
.
Currently I'm doing:
void CComThrowDispatch::CheckCOMAvailabilty() const
{
IUnknown * pIUnknown = m_spDispatchDriver.p;
// is this line above a problem ?
// m_spDispatchDriver is an ATL CComDispatchDriver
// it handles an object instanciated in another process.
// m_spDispatchDriver.p is of type IDispatch*
if (pIUnknown == nullptr) return;
bool bComObjectReachable = ::CoIsHandlerConnected(pIUnknown) == TRUE;
if (bComObjectReachable == false)
{
throw MyException;
}
}
My problem with his suggestion: I am dealing with cases (access violations) when the OtherProcess.exe has crashed or has been killed. It seems calling any functions like Invoke
on the IDispatch
that encapsulates any objects from this no longer exisiting OtherProcess.exe provokes these access violations (EDIT: comments and answers reveals that this latest assumption was completely false!).
That's why I'm trying to protect the application testing ::CoIsHandlerConnected(pIUnknown);
which takes an IUnknown
as parameter.
But by calling QueryInterface
on the IDispatch
, like my colleague advises me to do, I am afraid to fall back in the same problem I am trying to solve: This IDispatch
handles an object that no longer exists, and QueryInterface
to an IUnknown
would just be Undefined Behaviour all the same (EDIT again, this assumption is also false).
Am I really wrong when I just do the cast ?
What is the common way to deal with dead interprocess COM
objects ?
This is the begining of the definition of IDispatch
in OAIdl.h, which is declared as deriving from IUnknown
.
MIDL_INTERFACE("00020400-0000-0000-C000-000000000046")
IDispatch : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(
/* [out] */ __RPC__out UINT *pctinfo) = 0;
Casting
IDispatch
toIUnknown
in C++ (likestatic_cast<IUnknown*>(pDispatch)
) yields exactly the same pointer value, becauseIDispatch
derives fromIUnknown
. OTOH, doingQueryInterface
forIID_IUnknown
onpDispatch
may return a different pointer, but it's still a legit operation. In fact, this is how to get the identity of a COM object, say, to check if two interfaces are implemented by the same COM object (a hard COM rule which always work inside the same COM apartment).That said, the proxy COM object implemented by the COM marshaller may be caching interfaces, so the call to
IDispatch::QueryInterface
may returnS_OK
and a validIUnknown
identity of the proxy, despite the remote server already went down. That is, such operation might not be causing an instant IPC call.In your case, to test if the COM server is still alive and well, I'd simply call
IDispatch::GetTypeInfoCount
on the proxy object you already have. That would actually cause an IPC call (or a round-trip over the wire, if the server runs on a different host).In case the remote server has crashed or is unavailable, you'd likely receive a
CO_E_OBJNOTCONNECTED
error (could perhaps be a different error code, but certainly notS_OK
).Note though, doing an extra IPC call just to check if the server is available might be a costly operation, depending on your scenario.