在 C++ (COM) Dll 导入中使用 C# 代码不太正确

Using C# code in C++ (COM) Dll import not working quite right

如标​​题所示,我很难从 C++ 调用 C# 代码。一些上下文:在 C# 中有一个 API 调用(在 API 的 C++ 版本中不存在),我需要将它集成到一个更大的 C++ 项目中。

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

我的 C# dll 编译*。将生成的 dll 和 tlb 文件复制到相应的 C++ 项目目录后,我在同一 C++ 项目目录中打开一个管理命令提示符,然后 运行:

regasm MyFirstDll.dll /codebase /tlb

(*我将其编译为 Class 库,程序集名称:MyFirstDll,默认命名空间:MyMethods,程序集信息... -> 选中 Make assembly Com-Visible,Build->Register for COM还检查了互操作性。)

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

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

class "ATL::_NoAddRefReleaseOnCComPtr" 没有会员 "Add"
这是我的代码:

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

问题是 "return adder->Add(a,b)" (NateMath.cpp) Add(a,b) 显示为红色 class "ATL::_NoAddRefReleaseOnCComPtr" 没有成员 "Add"

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

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

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

说到 class 接口:如果您使用 ClassInterfaceType.AutoDual 而不是 None,您可以使用 CComPtr<_YourClass>(注意前导下划线 -- _YourClass 是 class 接口,而 YourClass 是 class。不过,我建议按照您已有的方式进行操作。