在 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++ 你想通过该接口与引用的对象进行通信。这里有一条规则要记住:CComPtr
和 CComQIPtr
的类型参数必须总是 是一个 COM 接口。该 COM 接口可以是显式定义的接口,也可以是 .NET 自动生成的 "class interface"。
说到 class 接口:如果您使用 ClassInterfaceType.AutoDual
而不是 None
,您可以使用 CComPtr<_YourClass>
(注意前导下划线 -- _YourClass
是 class 接口,而 YourClass
是 class。不过,我建议按照您已有的方式进行操作。
如标题所示,我很难从 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++ 你想通过该接口与引用的对象进行通信。这里有一条规则要记住:CComPtr
和 CComQIPtr
的类型参数必须总是 是一个 COM 接口。该 COM 接口可以是显式定义的接口,也可以是 .NET 自动生成的 "class interface"。
说到 class 接口:如果您使用 ClassInterfaceType.AutoDual
而不是 None
,您可以使用 CComPtr<_YourClass>
(注意前导下划线 -- _YourClass
是 class 接口,而 YourClass
是 class。不过,我建议按照您已有的方式进行操作。