Wrong vtable generated by C++ compiler (for COM object)

让人想犯罪 __ 提交于 2020-05-15 08:01:12

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!