我有一个在 C++ 中定义的接口,现在需要在 C# 中实现。解决此问题的最佳方法是什么?我根本不想在我的接口定义中使用 COM。我现在解决这个问题的方法是有两个接口定义,一个在 C++ 中,一个在 C# 中。然后我将 C# 接口公开为 COM 服务器。这是我用 C++ 编写的应用程序,可以调用 C#。无论如何我可以避免在 C++ 和 C# 中定义我的实现吗?
6 回答
如果您愿意为托管代码使用 C++/CLI 而不是 C#,那么您可以直接通过头文件使用本机 C++ 接口定义。这将是多么容易将取决于您的界面中的确切内容 - 最简单的情况是您可以从 C 中使用的东西。
查看 Marcus Heege 的Expert C++/CLI: .NET for Visual C++ Programmers,了解有关在 .NET 中混合本机和托管 C++ 的许多有用信息。
Swig是一个很好的工具,可以用其他语言(如 C#)包装 C++ 类。
你为什么不想使用COM?
这本来是我的建议。COM 互操作对我来说非常有效,我在 C# 中使用了 COM 对象和接口(只需引用 COM 对象,运行时可调用包装器就会自动创建)。同样,将 C# 类标记为“注册 COM 互操作”也有相反的效果。
用 C++ 编写接口并使用宏使其看起来像 UNIX 上的标准 cpp 头文件和 Windows 上的 IDL 文件(如果这不起作用,您可以随时编写 python/ruby 脚本从C++ 头文件)。
编译 IDL 以生成类型库。使用 TypeLib Importer 为 C# 生成接口定义并在那里实现接口。
另一种方法是使用“平面”的 C 风格 API。你不妨用它extern "C"
来防止意外超载。使用 DEF 文件显式命名导出的函数,因此绝对不会以任何方式修饰它们(C++ 函数使用导出表中参数类型的编码进行“修饰”)。
在 x86 上,请注意调用约定。可能是明确声明使用__stdcall
or __cdecl
。因为 P/Invoke 主要用于调用 Windows API,所以它默认为 StdCall,但 C 和 C++ 默认为 cdecl,因为它支持可变参数。
我最近将 COM 接口包装IRapiStream
在一个平面 C 接口中,因为 .NET 似乎试图将 IStream 转换为存储,但由于错误而失败STG_E_UNIMPLEMENTEDFUNCTION
。
您没有提及您使用的是哪个版本的 .NET,但在使用 Visual Studio .NET 2003 时对我有用的是为真正的 C++ 类的 pimpled 实现提供一个薄 C# 包装器:
public __gc class MyClass_Net {
public:
MyClass_Net()
:native_ptr_(new MyClass())
{
}
~MyClass_Net()
{
delete native_ptr_;
}
private:
MyClass __nogc *native_ptr_;
};
显然,人们更愿意在那里使用 Boost shared_ptr,但我永远无法让它们与 V.NET 2003 很好地配合使用......
方法只是通过指针转发到底层 C++ 方法。可能必须转换方法参数。例如,要调用采用字符串的 C++ 方法,C# 方法可能应该采用 System.String(托管 C++ 中的 System::String)。你必须使用 System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi() 来做到这一点。
这种方法的一个好处是因为托管 C++ 是一种 .NET 语言,您可以将访问器公开为属性 (__property)。您甚至可以像在 C# 中一样公开属性。