Link to home
Start Free TrialLog in
Avatar of ascot
ascot

asked on

ambiguous conversions from 'class ATL::CComObject<class CTstConnect> *' to 'struct IUnknown *'

I am doing some testing with ATL Connection Points.  I have created a project that has 2 ATL Objects, ObjA and ObjB (Simple Objects created through the ATL Object Wizard) - each of these support Connection points.  IObjA has one method foo() and IObjAEvents() has one method foocb().  foo() just pops up a MessageBox and then calls Fire_foocb(). This works fine and proves that the connection point between my App and ObjA works ok.

So I want now to also get ObjB events so I thought that I could just extend my class that implements the IObjAEvents interface to also implement IObjBEvents.
TstConnect.h that contains my implemntation class CTstConnect is listed below. I thought that by adding COM_INTERFACE_ENTRY(_IObjBEvents) to the COM_MAP and adding _IObjBEvents to the list of base classes that CTstConnect derives from then I would be able to implement the IObjBEvents interface in CTstConnect.  However, when I build I get the error
error C2594: 'argument' : ambiguous conversions from 'class ATL::CComObject<class CTstConnect> *' to 'struct IUnknown *' for the line:-
    CComPtr<IUnknown> ptrEventsUnk = ptrTstConnect; in my OnButton1 event
Is this basically the wrong approach - do I need to create a new class for each event interface that I want to implement ?

void CMymfcclientDlg::OnButton1()
{
    HRESULT hRes = CoInitialize(NULL);
    _Module.Init(ObjectMap, AfxGetInstanceHandle());
    CComPtr<IObjA> ptrObjA;
    hRes = CoCreateInstance (CLSID_ObjA,NULL,CLSCTX_SERVER,IID_IObjA,(void **) &ptrObjA);
   
    CComObject<CTstConnect>* ptrTstConnect = new CComObject<CTstConnect>;
   
    CComPtr<IUnknown> ptrEventsUnk = ptrTstConnect;

    DWORD dwCookie;
    hRes = AtlAdvise(ptrObjA, ptrEventsUnk, DIID__IObjAEvents, &dwCookie);
    ptrObjA->foo();
    AtlUnadvise (ptrObjA, DIID__IObjAEvents, dwCookie);
    CoUninitialize();
}

TstConnect.h
------------
#include <atlbase.h>
CComModule _Module;
#include <atlcom.h>
#include <atlimpl.cpp>

BEGIN_OBJECT_MAP(ObjectMap)
END_OBJECT_MAP()

#include "..\callbacktest.h"
#include "..\callbacktest_i.c"

class COMModule
{
public:
    COMModule()
    {
        CoInitialize(0);
    }
    ~COMModule()
    {
        CoUninitialize();
    }
};

COMModule gModule;

class CTstConnect :
    public CComObjectRoot,
    public _IObjAEvents,
//  public _IObjBEvents
{      
public:
    CTstConnect(){ }
    ~CTstConnect(){ }

    BEGIN_COM_MAP(CTstConnect)
        COM_INTERFACE_ENTRY(_IObjAEvents)
//      COM_INTERFACE_ENTRY(_IObjBEvents)
    END_COM_MAP()

public:
    STDMETHODIMP GetTypeInfoCount(UINT*)
    {
        return E_NOTIMPL;
    }

    STDMETHODIMP GetTypeInfo( UINT iTinfo, LCID lcid, ITypeInfo **ppTInfo)
    {
        return E_NOTIMPL;
    }

    STDMETHODIMP GetIDsOfNames( REFIID riid, LPOLESTR *rgszNames, UINT cNAMES,      LCID lcid, DISPID *rgDispId)
    {
        return E_NOTIMPL;
    }

    STDMETHODIMP Invoke ( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
                          VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
    {
        switch (dispIdMember)
        {
            case 0x1:
                if (pDispParams->cArgs != 0)
                    return DISP_E_BADPARAMCOUNT;
                if (pDispParams->cNamedArgs)
                    return DISP_E_NONAMEDARGS;

                foocb();
                break;

            default:
                MessageBox( 0, "Error", "Test", MB_OK);
                break;
      }
      return S_OK;
    }

    STDMETHODIMP foocb()
    {
        MessageBox(  0,  "foocb",  "Test",  MB_OK  );
        return S_OK;
    }
};
Avatar of jkr
jkr
Flag of Germany image

Use

    CComPtr<IUnknown> ptrEventsUnk = static_cast<IUnknown*>(ptrTstConnect);

or

    CComPtr<IUnknown> ptrEventsUnk = (IUnknown*) ptrTstConnect;

to resolve the abiguity.
Avatar of ascot
ascot

ASKER

tried both
CComPtr<IUnknown> ptrEventsUnk = static_cast<IUnknown*>(ptrTstConnect);
and
CComPtr<IUnknown> ptrEventsUnk = (IUnknown*) ptrTstConnect;

snd get the same error.

it is the addition of the commented out lines in my CTstConnect  class that causes the error.  I'm guessing that there is some sort of ambiguity because _IObjAEvents and _IObjBEvents  derive from the same base classes i.e.
ObjA.h =
class ATL_NO_VTABLE CObjA :
      public CComObjectRootEx<CComSingleThreadModel>,
      public CComCoClass<CObjA, &CLSID_ObjA>,
      public IConnectionPointContainerImpl<CObjA>,
      public IDispatchImpl<IObjA, &IID_IObjA, &LIBID_CALLBACKTEST5Lib>,
      public CProxy_IObjAEvents< CObjA >
{

ObjB.h=
class ATL_NO_VTABLE CObjB :
      public CComObjectRootEx<CComSingleThreadModel>,
      public CComCoClass<CObjB, &CLSID_ObjB>,
      public IConnectionPointContainerImpl<CObjB>,
      public IDispatchImpl<IObjB, &IID_IObjB, &LIBID_CALLBACKTEST5Lib>,
      public CProxy_IObjBEvents< CObjB >
{

I could be barking up the wrong tree.
Avatar of ascot

ASKER

Aaaghh - I've somehow managed to put this in the wrong topic area.  I will move it when I work out how.
Avatar of ascot

ASKER

ignore my last comment - it's been a long day !!!!!
Ah, I see - the problem is that your object inherits 'IUnknown' through more than one interface - you can fix this by using the COM_INTERFACE_ENTRY2 macro to select one of the inheritance branches:

   BEGIN_COM_MAP(CTstConnect)
      COM_INTERFACE_ENTRY(_IObjAEvents)
      COM_INTERFACE_ENTRY2(_IObjBEvents) // <------- different macro
   END_COM_MAP()
>>>>    CComObject<CTstConnect>* ptrTstConnect = new CComObject<CTstConnect>;
>>>>    CComPtr<IUnknown> ptrEventsUnk = ptrTstConnect;

Did you see that code somewhere? No?

I'll try to anyalyze it cause I don't know much about COM (though some about C++).:

A CComObject is a template class that was derived by its template argument class. So we have

    class CComObject : public CTstObject
    {
            ...
    };


A CComPtr is a smart pointer (pointer class) that holds and manages a pointer of it's template argument, here 'IUnknown'.

'ptrTstConnect' is a (normal) pointer of CComObject and cause of the dreivation also a pointer to a CTstObject.


>>>> CComPtr<IUnknown> ptrEventsUnk = ptrTstConnect;

Here CComPtr::operator=() function  needs to assign a CTstObject pointer to a IUnknown pointer what is valid only if IUnknown is a baseclass of CTstObject. That seems to be the case cause the error message is not "Don't know how to convert CTstObject* to IUnknown*" but an 'ambiguity' error. That means there are more than one way to make that conversion. These kind of errors typically would arise if we would have multi-inheritance that isn't 'virtual'. In that case we have more than one IUnknown instance that is base of CTstObject what causes the error. Unfortunately there could be some other valid explanations if any of the baseclasses has one or more *cast* operators that would be involved by the assignment operation. In that case, 'ambiguity' might come by these and not by multi-inheritance.

Don't know if the excursus helped you. Maybe, you should consider why you need that kind of assignment.

Regards, Alex
Avatar of ascot

ASKER

COM_INTERFACE_ENTRY2 needs 2 arguments so I changed my COM MAP as follows to disambiguate the two branches of inheritance tIDispatch.  However I still get the same error - I guess this is because there are also dual branches of inheritance to IConnectionPointContainer.  I shall experiment with entries in my COM MAP to see if I can get rid of this ambiguous conversion problem - any help appreciated.

BEGIN_COM_MAP(CTstConnect)
    COM_INTERFACE_ENTRY(_IObjAEvents)
    COM_INTERFACE_ENTRY2(IDispatch,_IObjBEvents)
END_COM_MAP()

ObjA COM MAP is as follows:-

BEGIN_COM_MAP(CObjA)
      COM_INTERFACE_ENTRY(IObjA)
      COM_INTERFACE_ENTRY(IDispatch)
      COM_INTERFACE_ENTRY(IConnectionPointContainer)
      COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
END_COM_MAP()

ObjB COM MAP is as follows:-
BEGIN_COM_MAP(CObjB)
      COM_INTERFACE_ENTRY(IObjB)
      COM_INTERFACE_ENTRY(IDispatch)
      COM_INTERFACE_ENTRY(IConnectionPointContainer)
      COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
END_COM_MAP()
Avatar of ascot

ASKER

Also tried

      BEGIN_COM_MAP(CTstConnect)
            COM_INTERFACE_ENTRY(_IObjAEvents)
            COM_INTERFACE_ENTRY2(IDispatch,_IObjBEvents)
            COM_INTERFACE_ENTRY2(IConnectionPointContainer,_IObjBEvents)
      END_COM_MAP()

but still get
error C2594: 'type cast' : ambiguous conversions from 'class ATL::CComObject<class CTstConnect> *' to 'struct IUnknown *'

for line       CComPtr<IUnknown> ptrEventsUnk = (IUnknown*) ptrTstConnect;
Avatar of ascot

ASKER

Have tried
BEGIN_COM_MAP(CTstConnect)
    COM_INTERFACE_ENTRY(_IObjAEvents)
    COM_INTERFACE_ENTRY(_IObjBEvents)
    COM_INTERFACE_ENTRY2(IDispatch, _IObjBEvents)
    COM_INTERFACE_ENTRY2(IConnectionPointContainer, _IObjBEvents)
END_COM_MAP()

and even

BEGIN_COM_MAP(CTstConnect)
    COM_INTERFACE_ENTRY(_IObjAEvents)
    COM_INTERFACE_ENTRY(_IObjBEvents)
    COM_INTERFACE_ENTRY2(IUnknown, _IObjBEvents)
    COM_INTERFACE_ENTRY2(IDispatch, _IObjBEvents)
    COM_INTERFACE_ENTRY2(IConnectionPointContainer, _IObjBEvents)
END_COM_MAP()
 but get the same error
Avatar of ascot

ASKER

Well I've played around with this and the fix appears to be to change the offending line to

    CComPtr<IUnknown> ptrEventsUnk = ptrTstConnect->GetUnknown();

I messed with the COM MAP but it all works ok as follows:
      BEGIN_COM_MAP(CTstConnect)
      COM_INTERFACE_ENTRY(_IObjAEvents)
      COM_INTERFACE_ENTRY(_IObjBEvents)
      END_COM_MAP()

If somebody can give a clear explanation of what the problem was and why this fix works, I will award the points to them.
As you have found the solution yourself you could get points refund.

>>>> If somebody can give a clear explanation of what the problem was

GetUnknown() returns the IUnknown pointer the CTstConnect object was associated with. As the left side of the assignment requires a pointer to IUnknown, the statement now compiles.

Before, it didn't work cause the compiler couldn't find a non-ambiguous way to convert a CTstConnect pointer to an IUnknown pointer. Note, the compiler couldn't find the GetUnknown method cause it is not a standard (C++) method like a cast operator function or a constructor. If IUnknown is a baseclass of CTstConnect - what is my assumption but couldn't be verified as I have no class definition - , the assignment could fail because of multi-inheritance as I explained above.

Note, the mappings in COM_MAP array mean that cour class has been derived from both these interface classes. If both classes were derived from IUnknown - what is most likely - the ambiguousness came from that.

Regards, Alex


 

Avatar of ascot

ASKER

but as jkr pointed out - the following should have got rid of that ambiguity - that's what I don't understand

BEGIN_COM_MAP(CTstConnect)
    COM_INTERFACE_ENTRY(_IObjAEvents)
    COM_INTERFACE_ENTRY(_IObjBEvents)
    COM_INTERFACE_ENTRY2(IUnknown, _IObjBEvents)
    COM_INTERFACE_ENTRY2(IDispatch, _IObjBEvents)
    COM_INTERFACE_ENTRY2(IConnectionPointContainer, _IObjBEvents)
END_COM_MAP()
ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of ascot

ASKER

Have awarded the points to itsmeandnobodyelse for extra explanation of why my fix worked