问题
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 is derived from IUnknown and has a custom method Calculate:
class IRisk: public IUnknown
{
public:
virtual int __stdcall Calculate(int i,double s) = 0;
};
the class Risk implements IRisk interfaces (the implementation is omitted here).
What I want is to call the function CreateRisk in c# and obtain a reference to IRisk.
I defined a wrapper interface in c#
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IRisk
{
[PreserveSig]
int Calculate(int i,double s);
}
and I added a dll entry in C#
[DllImport("Risk.dll")]
extern static IntPtr CreateRisk();
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#?
I have tried Marshal.GetIUnknownForObjectInContext,Marshal.GetObjectForIUnknown, but to no avail.
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:
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);
}
回答1:
The following will work:
[DllImport("Risk.dll")]
extern static IRiskAssessment CreateRisk();
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);
}
Obviously you need to use the same GUID in the C# code as was used in the C++ code!
Update
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.
回答2:
If I were you I would use SWIG to generate a C# interface for your C++ code, saves you a lot of troubles. Also, I think your assembly may have to be compiled in mixed-mode, or as a managed assembly.
来源:https://stackoverflow.com/questions/13741373/how-to-use-interface-pointer-exported-by-c-dll-in-c-sharp