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 HRESULT
s):
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
.
The specs don't have to say something to that.
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.
User contributions licensed under CC BY-SA 3.0