如何在C#中使用C ++ DLL导出的接口指针 [英] How to use interface pointer exported by C++ DLL in C#
问题描述
我有一个用C ++编写的DLL,它可以导出函数CreateRisk.该函数返回一个接口指针,如下所示:
I have a DLL written in C++, which exports a function CreateRisk. The function returns an interface pointer, as follows:
extern "C"
{
__declspec(dllexport) IRisk* __stdcall CreateRisk()
{
return new Risk();
}
}
IRisk源自IUnknown,并具有自定义方法Calculate:
IRisk is derived from IUnknown and has a custom method Calculate:
class IRisk: public IUnknown
{
public:
virtual int __stdcall Calculate(int i,double s) = 0;
};
Risk类实现IRisk接口(此处省略了实现).
the class Risk implements IRisk interfaces (the implementation is omitted here).
我想要的是在c#中调用函数CreateRisk并获取对IRisk的引用.
What I want is to call the function CreateRisk in c# and obtain a reference to IRisk.
我在c#中定义了包装器接口
I defined a wrapper interface in c#
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IRisk
{
[PreserveSig]
int Calculate(int i,double s);
}
然后我在C#中添加了一个dll条目
and I added a dll entry in C#
[DllImport("Risk.dll")]
extern static IntPtr CreateRisk();
我可以在C#中调用CreateRisk并获取IntPtr的值类型.有什么方法可以将IntPtr编组到c#IRisk接口,以便我可以在C#中调用Calculate方法?
I can call CreateRisk in C# and obtain a value type of IntPtr. Is there any way to marshal the IntPtr to the c# IRisk interface so that I can call the Calculate method in C#?
我已经尝试过Marshal.GetIUnknownForObjectInContext,Marshal.GetObjectForIUnknown,但无济于事.
I have tried Marshal.GetIUnknownForObjectInContext,Marshal.GetObjectForIUnknown, but to no avail.
我知道创建一个COM组件可以做到这一点.但是,COM组件需要在系统中注册.我想避免这些麻烦,并让C#直接使用C ++ dll导出的接口.
I know creating a COM component can do it. However, COM component needs to be registered with the system. I want to avoid those troubles and let C# use the interface exported by the C++ dll directly.
PS:
以下是我的Risk类实现:
The following is my Risk class implementation:
class IRisk : public IUnknown
{
public:
virtual int __stdcall Calculate(int i,double y ) = 0;
};
class Risk:public IRisk
{
int count;
public:
Risk();
virtual int __stdcall Calculate( int i ,double y);
virtual ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(const IID& riid,void **ppvObject);
};
Risk::Risk(){
count=0;
}
ULONG __stdcall Risk::AddRef()
{
return ++count;
}
ULONG __stdcall Risk::Release()
{
return --count;
}
HRESULT __stdcall Risk::QueryInterface(const IID& riid,void **ppvObject) {
*ppvObject=this;
AddRef();
return S_OK;
}
int __stdcall Risk::Calculate(int i ,double y) {
return (int)(i+y);
}
推荐答案
以下方法将起作用:
[DllImport("Risk.dll")]
extern static IRiskAssessment CreateRisk();
您将需要在界面中添加GUID:
You will need to add a GUID to the interface:
[Guid("your GUID goes here")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IRiskAssessment
{
[PreserveSig]
int Calculate(int i,double s);
}
显然,您需要在C#代码中使用与C ++代码中相同的GUID!
Obviously you need to use the same GUID in the C# code as was used in the C++ code!
更新
看您的C ++ COM对象实现,明显的错误是在QueryInterface
中.您不能为所有GUID返回S_OK
.仅为您实现的接口返回S_OK
.返回其他的E_NOINTERFACE
.
Looking at your C++ COM object implementation, the obvious fault is in QueryInterface
. You must not return S_OK
for all GUIDs. Only return S_OK
for the interfaces you implement. Return E_NOINTERFACE
for the others.
这篇关于如何在C#中使用C ++ DLL导出的接口指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!