У меня есть этот код C ++, который определяет IMyInterface
COM-интерфейс. Единственная тонкость в том, что он определяет два метода с разными параметрами, но с одинаковым именем:
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;
};
Вот простая реализация:
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;
}
};
Вот два экспорта DLL, чтобы иметь возможность использовать его в 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;
}
}
И теперь у меня есть эта C# программа, которая использует приведенный выше код:
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);
}
}
Вывод такой (???):
int value called
float value called
float value called
int value called
Даже если я изменю имя первого метода C# IMyInterface, результат будет тем же.
У меня такое ощущение, что из-за методов с одинаковым именем C / C ++ Компилятор создал vtable, который не соответствует ожидаемому макету. Это ошибка? Ожидается ли такое поведение? это может быть предопределено? Я использую Visual Studio 2019.