【问题标题】:Using C# code in C++ (COM) Dll import not working quite right在 C++ (COM) Dll 导入中使用 C# 代码不能正常工作
【发布时间】:2018-02-07 10:49:55
【问题描述】:

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

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

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

regasm MyFirstDll.dll /codebase /tlb

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

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

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

类“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) 显示为红色,类“ATL::_NoAddRefReleaseOnCComPtr”没有成员“Add”

【问题讨论】:

  • 尝试使用CComPtr&lt;MyFirstDll::Easy_Math&gt; 而不是CComPtr&lt;MyFirstDll::AddClass&gt;
  • @HansPassant 很高兴知道!不幸的是,在将 C# AddClass.Add 代码更新为 int Add(int i, int j) 后,仍然出现相同的错误。 :(
  • @MichaelGunter 如果我对接口使用 CComPtr 而不是类,它怎么知道调用我的类的方法实现?
  • 因为你 CoCreateInstance 的 UUID 为 AddClass,但对于 COM,你总是通过其实现的接口之一调用类的方法。
  • 好的,太好了!知道为什么尝试在 C++ 对象的实例上调用 Add 时会出现空指针异常吗? NateMath nm = NateMath();长 x = nm.Add(1,2);引发读取访问冲突,“nm.adder.p was nullptr.”

标签: c# c++ dll com


【解决方案1】:

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

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

要解决此问题,请使用CComPtr&lt;YourInterface&gt;。这告诉 C++ 你想通过那个接口与被引用的对象通信。这里有一条要记住的规则:CComPtrCComQIPtr 的类型参数必须始终是 COM 接口。该 COM 接口可以是显式定义的接口,也可以是 .NET 自动生成的“类接口”。

说到类接口:如果你使用ClassInterfaceType.AutoDual而不是None,你可以使用CComPtr&lt;_YourClass&gt;(注意前导下划线——_YourClass是类接口,而YourClass是课程。不过,我建议您按照您已有的方式进行。

【讨论】:

  • 这不正确,他通过明确声明接口做到了。他只是忘了使用它。好的建议可能应该包括使用 #import 自动生成的智能指针类型的建议,在这种情况下应该命名为 Easy_MathPtr
  • @HansPassant 啊,谢谢。我忘了类接口是_YourClass,而不是YourClass。至于使用CComPtr_com_ptr,这完全取决于消费开发者。如果他们在现有的 ATL 项目中使用它,则没有理由更喜欢生成的 _com_ptr 而不是 CComPtr。事实上,这样做意味着您需要处理一个额外的异常类型 (_com_error)。
猜你喜欢
  • 1970-01-01
  • 2017-04-09
  • 1970-01-01
  • 1970-01-01
  • 2013-10-28
  • 1970-01-01
  • 2012-03-03
  • 1970-01-01
  • 2012-01-05
相关资源
最近更新 更多