2017-08-29 60 views
0

正如标题所暗示的,我很难从C++调用C#代码。一点上下文:在C#中有一个API调用(在C++版本的API中不存在),我需要将它集成到一个更大的C++项目中。在C++(COM)中使用C#代码Dll导入不能正常工作

我一直在阅读this SO post,并且用COM方法取得了最大进展。

我的C#的DLL编译*。所产生的DLL和TLB文件复制到相应的C++项目目录后,我打开管理员CMD在同一个C++项目目录提示符,然后运行:

regasm MyFirstDll.dll /codebase /tlb 

(*我编译它作为一个类库,大会名称: MyFirstDll,默认命名空间:MyMethods,程序集信息... - >使汇编Com-Visible被选中,Build-> Register for COM interop也被选中。)

使用对象浏览器,我能够看到类我定义了一个具有适当的参数和签名的方法。 Screenshot of it showing up in Object Browser

我遇到的问题是方法调用(而不是类)。即使该方法在对象浏览器中可见,但在我的代码中,它不会被识别为对象的方法。

类 “ATL :: _ NoAddRefReleaseOnCComPtr” 没有成员 “添加”
这里是我的代码:

MyFirstDll C#项目:

using System; 
using System.Runtime.InteropServices; 
// 

namespace MyMethods 
{ 
    // Interface declaration. 
    [Guid("8a0f4457-b08f-4124-bc49-18fe11cb108e")] 
    [ComVisible(true)] 
    [InterfaceType(ComInterfaceType.InterfaceIsDual)] 
    public interface Easy_Math 
    { 
     [DispId(1)] 
     long Add(long i, long j); 
    }; 
} 
namespace MyMethods 
{ 
    [Guid("0cb5e240-0df8-4a13-87dc-50823a395ec1")] 
    [ComVisible(true)] 
    [ClassInterface(ClassInterfaceType.None)] 
    [ProgId("MyMethods.AddClass")] 
    public class AddClass: Easy_Math 
    { 
     public AddClass() { } 
     [ComVisible(true)] 

     public long Add(long i, long j) 
     { 
      return (i + j); 
     } 
    } 
} 

NateMath.h:

#include <atlcomcli.h> 
#import "MyFirstDll.tlb" 

class NateMath 
{ 
public: 
    NateMath(void); 
    ~NateMath(void); 
    long Add(long a, long b); 

private: 
    CComPtr<MyFirstDll::AddClass> adder; 
}; 

NateMath.cpp:

#include "stdafx.h" 
#include <atlcomcli.h> 
#import "MyFirstDll.tlb" 
#include "NateMath.h" 

NateMath::NateMath(void) 
{ 
    CoInitialize(NULL); 
    adder.CoCreateInstance(__uuidof(MyFirstDll::AddClass)); 
} 

NateMath::~NateMath(void) 
{ 
    CoUninitialize(); 
} 
long NateMath::Add(long a, long b) { 
    return adder->Add(a,b); 
} 

问题是在“返回加法器 - >添加(a,b)”(NateMath.cpp)添加(a,b)显示红色与类“ATL :: _否AddRefReleaseOnCComPtr”没有成员“添加”

+1

尝试使用'CComPtr '而不是'CComPtr '。 –

+0

@HansPassant这很好知道!不幸的是,在更新C#AddClass将代码添加到int Add(int i,int j)中,仍然出现同样的错误。:( –

+0

@MichaelGunter如果我使用CComPtr而不是类,它将如何知道调用我的类的实现方法? –

回答

0

这是因为您正尝试在CComPtr而不是界面中使用您的班级名称。使用COM,所有方法都是在接口上定义的,而不是在实现接口的类上定义的。

您可以CoCreateInstance(__uuidof(YourClass)),因为意图是创建一个YourClass(由__uuidof(YourClass)表示的GUID标识)的实例。但是,C++中的YourClass是仅存在的虚拟结构,因此您可以读取uuid - 从#import生成的C++中的YourClass的定义为空,并且始终为空。

要解决此问题,请使用CComPtr<YourInterface>。这告诉C++你想通过该接口与被引用的对象进行通信。这里有一条规则要记住:CComPtrCComQIPtr的类型参数必须是总是是一个COM接口。该COM接口可以是一个明确定义的接口,也可以是由.NET自动生成的“类接口”。

的类接口说到:如果您用过ClassInterfaceType.AutoDual代替None,你可以使用一个CComPtr<_YourClass>(注意前导下划线 - _YourClass是类接口,而YourClass将是一流的,我会建议做的。然而,你已经有了这种方法

+0

这是不正确的,他通过明确声明接口来做到了这一点。他忘了使用它。好的建议可能应该包括建议使用#import自动生成的智能指针类型,在这种情况下应该命名为'Easy_MathPtr'。 –

+0

@HansPassant啊,谢谢。我忘记了类接口是'_YourClass',而不是'YourClass'。至于使用'CComPtr'和'_com_ptr',这完全取决于消费开发者。如果他们在现有的ATL项目中使用它,没有理由选择生成'_com_ptr'而不是'CComPtr'。事实上,这样做意味着你有一个额外的异常类型来处理('_com_error')。 –