One item on my C++ wishlist is a syntax for inlining typedefs into the
base class list on a class declaration:
class CMyClass
: public ATL::CComObjectRootEx<ATL::CComSingleThreadModel>
, public ATL::CComCoClass<CMyClass, &__uuidof(MyClass)>
, public ATL::IConnectionPointContainerImpl<CMyClass>
, public ATL::IConnectionPointImpl<CMyClass,
&__uuidof(IMyClassEvents)>
, public ATL::IConnectionPointImpl<CMyClass,
&__uuidof(IMyClassOtherEvents)>
, public IMyClass
The two connection points result in a duplicated name, m_vec
. To get
the list of listeners to deliver any given event to, contortions like
ATL::IConnectionPointImpl<CMyClass, &__uuidof(IMyClassOtherEvents)>::m_vec
are necessary. These usually
become typedefs:
private:
typedef ATL::IConnectionPointImpl<CMyClass, &__uuidof(IMyClassEvents)> events_cp;
typedef ATL::IConnectionPointImpl<CMyClass, &__uuidof(IMyClassOtherEvents)> otherevents_cp;
Then a relatively simple otherevents_cp::m_vec
leads to the right
container, but it requires regurgitating the entire base class type in
the typedef.
Something like this would be really nice to have instead:
class CMyClass
: public ATL::CComObjectRootEx<ATL::CComSingleThreadModel>
, public ATL::CComCoClass<CMyClass, &__uuidof(MyClass)>
, public ATL::IConnectionPointContainerImpl<CMyClass>
, public ATL::IConnectionPointImpl<CMyClass,
&__uuidof(IMyClassEvents)> [private: events_cp]
, public ATL::IConnectionPointImpl<CMyClass,
&__uuidof(IMyClassOtherEvents)> [private: otherevents_cp]
, public IMyClass
Wouldn’t it?
I know it’s because the class is from waaay back when the SBCS APIs
were still actually being used, but …
// Extract a const wchar_t*
//
inline _bstr_t::operator const wchar_t*() const throw()
{
return (m_Data != NULL) ? m_Data->GetWString() : NULL;
}
// Extract a const char_t*
//
inline _bstr_t::operator const char*() const
{
return (m_Data != NULL) ? m_Data->GetString() : NULL;
}
BSTR is a Unicode string, and the second extractor above converts it
to ANSI. This, unfortunately, results in ambiguous-overload errors
whenever a _bstr_t
is passed to anything that can accept both
forms.
There should really be a way to, say, #define _BSTR_T_NO_ANSI_SUPPORT
.
Huh? I thought type libraries could only represent the
Automation compatible types?
Good to know. #import is much easier than writing all the wrappers
myself, particularly because I’ve been rather generous with the
property attributes this time.
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.