据我所知,C#只能与COM接口进行交互。幸运的是,它不需要成为一个完整的带有注册表的COM对象,可以是任何实现IUnknown接口的普通C++类。
因此,在C++中可以这样做:
#include <Windows.h>
static const GUID IID_MyInterface =
{ 0xefbf7d84, 0x3efe, 0x41e0, { 0x95, 0x2e, 0x68, 0xa4, 0x4a, 0x3e, 0x72, 0xca } };
struct MyInterface: public IUnknown
{
STDMETHOD_(double, GetValue)() = 0;
STDMETHOD(ThrowError)() = 0;
};
class MyClass: public MyInterface
{
volatile long refcount_;
public:
MyClass(): refcount_(1) { }
STDMETHODIMP QueryInterface(REFIID guid, void **pObj) {
if(pObj == NULL) {
return E_POINTER;
} else if(guid == IID_IUnknown) {
*pObj = this;
AddRef();
return S_OK;
} else if(guid == IID_MyInterface) {
*pObj = this;
AddRef();
return S_OK;
} else {
*pObj = NULL;
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG) AddRef() {
return InterlockedIncrement(&refcount_);
}
STDMETHODIMP_(ULONG) Release() {
ULONG result = InterlockedDecrement(&refcount_);
if(result == 0) delete this;
return result;
}
STDMETHODIMP_(DOUBLE) GetValue() {
return 42.0;
}
STDMETHODIMP ThrowError() {
return E_FAIL;
}
};
extern "C" __declspec(dllexport) LPUNKNOWN WINAPI CreateInstance()
{
return new MyClass();
}
在C#端,您可以这样做:
[ComImport]
[Guid("EFBF7D84-3EFE-41E0-952E-68A44A3E72CA")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface MyInterface
{
[PreserveSig] double GetValue();
void ThrowError();
}
class Program
{
[DllImport("mylib.dll")]
static extern MyInterface CreateInstance();
static void Main(string[] args)
{
MyInterface iface = CreateInstance();
Console.WriteLine(iface.GetValue());
try { iface.ThrowError(); }
catch(Exception ex) { Console.WriteLine(ex); }
Console.ReadKey(true);
}
}
只要C++和C#之间的通信通过虚拟接口进行,你就可以以任何想要的方式进行操作。