6

我有一个用 C++ 编写的 DLL,它导出一个函数 CreateRisk。该函数返回一个接口指针,如下所示:

extern "C"
{
    __declspec(dllexport) IRisk* __stdcall CreateRisk()
    {
        return new  Risk();


    }
}

IRisk 派生自 IUnknown,并有一个自定义方法 Calculate:

class IRisk: public IUnknown                               
{
public:
    virtual int __stdcall Calculate(int i,double s) = 0;  
};

Risk 类实现了 IRisk 接口(这里省略了实现)。

我想要的是在 c# 中调用函数 CreateRisk 并获得对 IRisk 的引用。

我在 C# 中定义了一个包装器接口

    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]        
    public interface IRisk
    {
        [PreserveSig]                                            
        int Calculate(int i,double s);
    }

我在 C# 中添加了一个 dll 条目

    [DllImport("Risk.dll")]
    extern static IntPtr CreateRisk();

我可以在 C# 中调用 CreateRisk 并获取 IntPtr 的值类型。有没有办法将 IntPtr 编组到 c# IRisk 接口,以便我可以在 C# 中调用 Calculate 方法?

我试过 Marshal.GetIUnknownForObjectInContext,Marshal.GetObjectForIUnknown,但无济于事。

我知道创建一个 COM 组件可以做到这一点。但是,COM 组件需要向系统注册。我想避免这些麻烦,让C#直接使用C++ dll导出的接口。

PS:

以下是我的风险类实现:

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);
}
4

2 回答 2

2

以下将起作用:

[DllImport("Risk.dll")]
extern static IRiskAssessment CreateRisk();

您需要在界面中添加一个 GUID:

[Guid("your GUID goes here")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]        
public interface IRiskAssessment
{
    [PreserveSig]                                            
    int Calculate(int i,double s);
}

显然,您需要在 C# 代码中使用与 C++ 代码中相同的 GUID!

更新

查看您的 C++ COM 对象实现,明显的错误在QueryInterface. 您不得返回S_OK所有 GUID。仅返回S_OK您实现的接口。为其他人返回E_NOINTERFACE

于 2012-12-06T11:09:25.843 回答
1

如果我是你,我会使用SWIG为你的 C++ 代码生成 C# 接口,为你省去很多麻烦。另外,我认为您的程序集可能必须以混合模式编译,或者作为托管程序集。

于 2012-12-06T10:56:48.627 回答