我有一个用C ++实现的类,它负责程序的算术运算,以及一个使用WPF的接口。我使用C#处理输入但是我如何使用我的C ++类?
我已经看到一些关于使托管C ++包装类与它交互的注释,但我不知道从哪里开始。我也不知道如何将其与所有其他代码一起编译。我无法真正找到这方面的教程,并且在托管C ++上显示谷歌的东西看起来并没有什么帮助。
有什么东西可以帮助我吗?这对我来说似乎并不合理。
编辑尝试了m3rLinEz解决方案,但它给了我一个BadImageFormatException,我认为这是因为没有生成DLL。我按照所说的做了一切,不知道发生了什么。有什么想法吗?
答案 0 :(得分:56)
你看过C ++ / CLI吗?
让我举一个很短的例子。这是Visual C ++中的源文件 - > CLR - >类库项目。它基本上获得Windows用户名并返回它。
请注意,为了进行编译,您必须进入项目设置并将“Additional Dependencies”标记为“从父级继承”,因为我们正在使用这些Windows库(kernel32.lib,user32.lib ,. 。)
// CSCPP.h
#pragma once
#include "windows.h"
using namespace System;
namespace CSCPP {
public ref class Class1
{
// TODO: Add your methods for this class here.
public:
String^ GetText(){
WCHAR acUserName[100];
DWORD nUserName = sizeof(acUserName);
if (GetUserName(acUserName, &nUserName)) {
String^ name = gcnew String(acUserName);
return String::Format("Hello {0} !", name);
}else{
return gcnew String("Error!");
}
}
};
}
现在创建了一个新的C#项目并添加对我们的第一个C ++ / CLI类库项目的引用。然后调用实例方法。
namespace CSTester
{
class Program
{
static void Main(string[] args)
{
CSCPP.Class1 instance = new CSCPP.Class1();
Console.WriteLine(instance.GetText());
}
}
}
这在我的机器上给出了以下结果:
你好m3rlinez!
C ++ / CLI基本上是基于C ++标准的托管扩展。它允许您在C ++ / CLI项目中使用CLR类和数据类型,并将其公开给托管语言。您可以使用此方法为旧C ++库创建托管包装器。有一些奇怪的语法,例如String^
来定义CLR String的引用类型。我发现"Quick C++/CLI - Learn C++/CLI in less than 10 minutes"在这里很有用。
答案 1 :(得分:9)
在同一进程中至少有三种方法可以从托管中调用非托管代码:
在工作中我们使用C ++ / CLI,它似乎有效。
答案 2 :(得分:4)
我将创建一个标准(非COM /托管)动态链接库作为described here,然后使用c#代码中的DllImport attribute(平台调用)来访问导出的函数。
该文章的关键点:
注意__declspec(dllexport) 方法声明中的修饰符 这段代码。这些修饰符使得 这样由DLL导出的方法 它可以被其他人使用 应用。欲获得更多信息, 见dllexport,dllimport。
这是实际COM互操作包装器的轻量级替代方案,可避免注册等问题(DLL可以简单地放在应用程序目录中)
另一种选择是It Just Works(IJW)。如果您有托管的C ++代码并且需要从其他.NET语言访问它,那么这可能是更好的选择。但是,如果您能够/很乐意将非托管C ++转换为托管C ++,那么这只是一个选项。
答案 3 :(得分:3)
我会远离P / Invoke,因为它与IJW(It Just Works)相比相当慢。后者允许您无缝地交织托管和非托管c ++。您所要做的就是创建一个托管c ++程序集,编写一个可从c#中看到的托管类,并从中调用非托管代码。
嗯......好的。我的印象是P / Invoke调用速度较慢,而它们本身并不是。但是,通过明确控制编组,您可以使C ++ / CLI版本在许多情况下表现更好。以下是Microsoft关于这两种机制的文章:
http://msdn.microsoft.com/en-us/library/ms235282.aspx
IJW的优势
- 无需为此编写DLLImport属性声明 程序使用的非托管API。只是 包括头文件和链接 导入库。
- IJW机制稍快(例如,IJW存根不会 需要检查是否需要销或 复制数据项,因为这样做 由开发商明确表示。
- 它清楚地说明了性能问题。在这种情况下,事实是 您正在从Unicode进行翻译 字符串到ANSI字符串,你 有一个伴随的内存分配 和解除分配。在这种情况下,一个 开发人员使用IJW编写代码 会意识到调用_putws和 使用PtrToStringChars会更好 表现。
- 如果使用相同的数据调用许多非托管API,请对其进行封送处理 曾经和通过编组的副本是 比重新编组更有效率 每一次。
还有美学上的优势:
您不必定义DLLImport
属性,您不必定义任何数据结构(也包含p / invoke特定属性),如下所示:
[StructLayout(LayoutKind.Sequential,CharSet = CharSet.Ansi)] public struct DevMode { [MarshalAs(UnmanagedType.ByValTStr,SizeConst = 32)] public string dmDeviceName; }
Marshal.PtrToString(ptr)
的字符串编组。恕我直言,如果你在Windows SDK中调用一个奇怪的函数,请使用P / Invoke。如果要将一个中等复杂的C ++ API暴露给托管世界,那肯定是C ++ / CLI。