问题
I have this C++ code that defines a IMyInterface
COM interface. The only subtlety is it defines two methods with different parameters but same name:
struct __declspec(uuid("bd8a0cfc-312e-4871-8f82-07adab05c6d0")) __declspec(novtable) IMyInterface : public IUnknown
{
virtual HRESULT __stdcall SetValue(float value) = 0;
virtual HRESULT __stdcall SetValue(int value) = 0;
};
Here is a simple implementation:
class MyClass : public IMyInterface
{
public:
// poor man's COM object impl
HRESULT MyClass::QueryInterface(REFIID riid, void** ppvObject)
{
if (riid == __uuidof(IUnknown))
{
*ppvObject = (IUnknown*)this;
return S_OK;
}
if (riid == __uuidof(IMyInterface))
{
*ppvObject = (IMyInterface*)this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG MyClass::AddRef() { return 1; }
ULONG MyClass::Release() { return 1; }
HRESULT MyClass::SetValue(float value)
{
printf("float value called\n");
return S_OK;
}
HRESULT MyClass::SetValue(int value)
{
printf("int value called\n");
return S_OK;
}
};
Here is two DLL exports to be able to use it in C#:
static MyClass myc;
extern "C" {
__declspec(dllexport) HRESULT __stdcall GetMyInterface(REFIID riid, void** pvInstance)
{
return myc.QueryInterface(riid, pvInstance);
}
}
extern "C" {
__declspec(dllexport) HRESULT __stdcall DoItInCPP()
{
IMyInterface* my;
GetMyInterface(__uuidof(IMyInterface), (void**)&my);
my->SetValue(.0f);
my->SetValue(0);
return S_OK;
}
}
And now, I have this C# program that uses the code above:
public class Program
{
static void Main()
{
var hr = GetMyInterface(typeof(IMyInterface).GUID, out var obj);
var my = (IMyInterface)obj;
my.SetValue(.0f);
my.SetValue(0);
DoItInCPP();
}
[DllImport("MyComProject.dll")]
private static extern int GetMyInterface([MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv);
[DllImport("MyComProject.dll")]
private static extern int DoItInCPP();
[Guid("bd8a0cfc-312e-4871-8f82-07adab05c6d0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IMyInterface
{
[PreserveSig]
int SetValue(float value);
[PreserveSig]
int SetValue(int value);
}
}
The output is this (???):
int value called
float value called
float value called
int value called
Even if I change the C# IMyInterface's first method name, the result is the same.
I have the feeling that due to the methods with same name, the C/C++ compiler has built a vtable that doesn't correspond to the expected layout. Is it a bug? Is this behavior expected? can it be predected? I'm using Visual Studio 2019.
来源:https://stackoverflow.com/questions/61527633/wrong-vtable-generated-by-c-compiler-for-com-object