Templates. It's always the templates that get you.
Problem
You are developing a COM object that supports outgoing events (source interfaces). You get a compiler error similar to
C2440: ‘static_cast’ cannot convert from ‘CMyClass::_atl_conn_classtype *’ to ‘ATL::_ICPLocator<IID_IMyClassEvents> *'. Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast.
on a CONNECTION_POINT_ENTRY()
line:
class CMyClass
: public ATL::CComObjectRootEx<ATL::CComSingleThreadModel>
, public ATL::CComCoClass<CMyClass, &CLSID_MyClass>
, public ATL::IConnectionPointContainerImpl<CMyClass>
, public ATL::IConnectionPointImpl<CMyClass, &__uuidof(IMyClassEvents)>
, public IMyClass
{
public:
CMyClass();
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CMyClass)
COM_INTERFACE_ENTRY(IMyClass)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CMyClass)
CONNECTION_POINT_ENTRY(IID_IMyClassEvents) // <-- C2440
END_CONNECTION_POINT_MAP()
...
Analysis
The IIDs in the IConnectionPointImpl
base class and the
CONNECTION_POINT_ENTRY
are not the same symbol. The cast fails because
it attempts to convert to a base-class pointer that is not a base
class, but a separate specialization of the same template.
Solution
Use either the predefined constants (IID_IMyClassEvents
) or the MIDL
metadata based constants (__uuidof(IMyClassEvents)
) in both places;
do not mix them.