Does COM support multiple dual interfaces?

1

I have made a COM object with multiple dual interfaces. It worked in an earlier version of compiler, but not in the current version.

My question: Does the COM spec say this should work (and therefore I should report a compiler bug), or is not meant to work? This page suggests that perhaps it is not meant to work.

The RIDL file:

[
  uuid(0A6CC6CE-623E-4455-8B9B-65178FB7585A),
  version(1.0),
  helpstring("Library to illustrate failure of Dispatch interface")
]
library DaxFail
{

  importlib("stdole2.tlb");

  interface IFoo;
  coclass DaxFailClass;
  interface IBar;


  [
    uuid(2CD15FFC-0C09-4A29-BD57-99BBC53AE01F),
    helpstring("Dispatch interface for DaxFailClass Object"),
    dual,
    oleautomation
  ]
  interface IFoo: IDispatch
  {
    [id(0x000000C9)]
    HRESULT _stdcall foo_method(void);
  };

  [
    uuid(AECB5DF3-EDE3-441A-93E6-220CB271AD43),
    dual,
    oleautomation
  ]
  interface IBar: IDispatch
  {
    [id(0x000000C9)]
    HRESULT _stdcall bar_method(void);
  };

  [
    uuid(9DCD1024-6E1A-435E-82F9-FD4FE863D710),
    helpstring("DaxFailClass Object")
  ]
  coclass DaxFailClass
  {
    [default] interface IFoo;
    interface IBar;
  };

};

The code to access it (this is pseudocode, I have extra statements in "real" code to display the HRESULTs):

const GUID CLSID_DaxFailClass = {0x9DCD1024, 0x6E1A, 0x435E,{ 0x82, 0xF9, 0xFD,0x4F, 0xE8, 0x63,0xD7, 0x10} };
const GUID IID_IFoo = {0x2CD15FFC, 0x0C09, 0x4A29,{ 0xBD, 0x57, 0x99,0xBB, 0xC5, 0x3A,0xE0,     0x1F} };
const GUID IID_IBar = {0xAECB5DF3, 0xEDE3, 0x441A,{ 0x93, 0xE6, 0x22,0x0C, 0xB2, 0x71,0xAD, 0x43} };

int _tmain()
{
    IDispatch *intf, *ibar;
    HRESULT hr;
    DISPID disp_id;
    wchar_t *name;

    CoInitialize(NULL);

    hr = CoCreateInstance(CLSID_DaxFailClass, 0, CLSCTX_ALL, IID_IDispatch, (void **)&intf);

// This returns 0 , and doing Invoke with disp_id executes foo_method
    name = L"foo_method";
    intf->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &disp_id );

// returns 0
    hr = intf->QueryInterface(IID_IBar, (void **)&ibar);

// this returns 0x80020006
    name = L"bar_method";
    hr = ibar->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &disp_id );

// This returns 0 , and doing Invoke with disp_id executes foo_method
    name = L"foo_method";
    hr = ibar->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &disp_id );

    CoUninitialize();
    getchar();
}

So, the trouble is that ibar behaves exactly like intf. ibar can have foo_method called on it, but does not seem to know what bar_method is.

I was expecting the second GetIDsOfNames call to give 0 and then Invoke to be able to call bar_method, and the third GetIDsOfNames should give 0x80020006.

Extra info about compilers (although, to be clear, my question is whether the COM spec says it should work or not): Works in BDS 2006 and does not work in C++Builder XE5. I trawled through the code in XE5 which implements COM, and the ojbect factory fills an ITypeInfo * using GetTypeInfoOfGUID(CLSID_....) when the object is first created, but then the implementation of QueryInterface just uses the same ITypeInfo for all results, it does not call GetTypeInfoOfGUID again with the new IID. That ITypeInfo is passed to DispGetIDsOfNames in the implementation of IDispatch::GetIDsOfNames.

com
c++builder
idispatch
asked on Stack Overflow May 6, 2014 by M.M

1 Answer

2

The specs don't have to say something to that.

  1. You have to different interfaces on one class. This is allowed.
  2. Both derive from IDispatch. This is allowed too.
  3. Both have to do their own implementation and this implementation should do its job.

If something is wrong with your dual interface "usally" the IDL compiler will tell it to you.

Here with your code: I can say nothing without seeing the class implementation for the interfaces. And yes: It works and you find a sample for ATL here at CodeProject

It is exactly what you are doing and far more.

answered on Stack Overflow May 6, 2014 by xMRi

User contributions licensed under CC BY-SA 3.0