您现在的位置是:首页 >技术杂谈 >基于C++/CLI实现C#与C++互调过程中的注意事项网站首页技术杂谈
基于C++/CLI实现C#与C++互调过程中的注意事项
目录
一、基于C++/CLI 的调用原理
C++/CLI (Common Language Infrastructure)是一种特殊的 C++ 语言,它支持在 .NET 平台上进行开发和编译。C++/CLI 可以让开发人员使用 C++ 语言来编写 .NET 应用程序,并且可以直接访问和使用 .NET 框架中的类库。其支持托管代码和非托管代码:C++/CLI 中既可以编写非托管代码,也可以编写托管代码。这使得开发人员可以利用现有的 C++ 代码库,并将其集成到 .NET 应用程序中。
托管代码是指运行在 .NET 运行时(Common Language Runtime)中的代码。托管代码是由编译器生成的,它们包含了一些元数据信息,这些信息可以被 .NET 运行时用来管理代码的执行、内存分配、垃圾回收等操作。
非托管代码是指不运行在 .NET 运行时中的代码。这些代码通常是使用 C 或 C++ 等语言编写的,并且直接访问计算机的硬件资源和操作系统 API。非托管代码不包含元数据信息,也不依赖于 .NET 运行时,因此它们无法直接与托管代码进行交互。(即待调用的C++ 应用程序)
因此我们的思路为:
1、C#调用C++:通过C++/CLI 的委托代码调用C++应用程序(非委托代码),从而生成.NET应用,实现基于C#的访问。
其中,每个环节都是利用动态链接库(.dll)交互实现。
2、C++调用C#:C++基于所支持的clr,通过调用C#生成的dll作为其引用,实现访问C#命名空间域下的功能。
二、注意事项
如何基于VS2010完成C#调用C++开发过程
1、生成C++应用程序(非托管代码)
这个就是我们需要被调用的应用程序,根据各个项目需求自行设计。需要注意,编译生成的文件需改成.dll格式而非传统的.exe控制台,如下所示:
2、基于C++/CLI生成托管代码
这一步摸索了一段时间,感觉和编译器的版本也有关系,VS2010确实有点老了,存在不便。因此,本人详细罗列了相关操作流程。
首先,我们需要新建一个CLR(Common Language Runtime)环境。这里说明下:C++/CLI 和CLR关系,前者是针对 .NET 平台而设计的一种编程语言,可以方便地将 C++ 代码与 .NET 技术集成在一起,而后者则是 .NET 平台的核心组件,提供了运行时环境和基础设施。
选中**”类库“**!!!同时注意所使用的.NET FrameWork版本。
(可能是本人操作问题,之前尝试选中的是”CLR空项目“,结果出现C#无法访问其空间域。)
完成后,为项目添加C++应用程序编译生成的dll引用
再将C++应用程序代码作为现有项添加至”源文件“,并将其路径添加至包含目录。
顺道给个代码实现demo:
// myCLR.h
#pragma once
#include "myTest.h"//C++应用程序 头文件
#include "string.h"
#include <msclr/marshal_cppstd.h>
using namespace System;
using namespace msclr::interop;
namespace myCLR {
//ref class 作为委托类,从而使得C#可对Person_CLI进行访问
public ref class Person_CLI
{
public:
void initPersonClass();
void setPersonInfo(System::String^ name,int age,double height);
private:
Person *_p;//C++应用程序 声明Person类对象
string convertToStd(System::String^ str);
};
}
// 这是主 DLL 文件。
#include "stdafx.h"
#include "myCLR.h"
void myCLR::Person_CLI::initPersonClass(){
//new
_p=new Person();
}
void myCLR::Person_CLI::setPersonInfo(System::String^ name,int age,double height){
//访问类的成员函数
string strName=convertToStd(name);
_p->init(strName,age,height);
_p->showInfo();
}
//System::String^ str 转为 string
//因为C#只有System::String^类型, 与C++应用程序函数的参数类型string 不兼容
string myCLR::Person_CLI::convertToStd(System::String^ str){
marshal_context context;
return context.marshal_as<std::string>(str);
}
3、C#调用
将添加C++/CLI生成的DLL,即可访问
using System;
using System.Runtime.InteropServices;
using myCLR;//添加命名空间域
class Program
{
static void Main(string[] args)
{
//直接访问
Person_CLI _cl = new Person_CLI();
_cl.initPersonClass();
_cl.setPersonInfo("Tom",10, 30.2);
Console.ReadKey();
}
}
正常输出结果
如何基于VS2010完成C++调用C#开发过程
1、在C++应用程序的属性中设置:公共语言运行时支持(/clr);
2、将C#生成的dll作为引用添加至C++应用程序;
首先,需要基于待调用的C#类库编译生成dll。 此外给个C#代码的Demo:
//CsharpDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CsharpDemo
{
public class Class1
{
public void showInfo(){
Console.WriteLine("showInfo()执行成功");
}
}
}
然后,再将dll作为引用添加至C++应用程序。
3、文件中添加C#的命名空间域
//cppDemo.cpp
#include "stdafx.h"
#include <iostream>
using namespace std;
using namespace CsharpDemo;//添加C#的命名空间域
int _tmain(int argc, _TCHAR* argv[])
{
//新建C#中的对象 clr中用“^”代替指针“*”,用“gcnew”代替“new”
//由于C#类会自动释放内存,因此不需要像C++手动delete释放
Class1 ^ _cl=gcnew Class1();
//调用C#类的方法
_cl->showInfo();
system("pause");
return 0;
}
三、C++/CLI与COM组件对比
C++ ATL(Active Template Library)并不能像 C++/CLI 一样实现混合使用托管和非托管代码。C++ ATL 是一种基于 COM 技术的 C++ 库,主要用于编写 COM 组件和应用程序。它不是一种语言,而是一种库,提供了一些在编写 COM 组件时经常使用的类和函数。
假如已经有一个现有的 C++ 应用程序,并且想要让 C# 调用它,那么使用 C++ ATL 可能不是最好的选择,因为这需要将现有的 C++ 应用程序重写为 COM 组件,并在 C# 中使用 COM Interop 来访问该组件,这可能会带来一些复杂性和性能开销。
相比之下,使用 C++/CLI 则更加方便和直接。通过编写 C++/CLI 包装器,可以直接将现有的 C++ 应用程序集成到 .NET 应用程序中,并且可以充分利用 .NET 平台所提供的各种优势,如自动内存管理、强类型等。同时,C++/CLI 还支持混合使用托管和非托管代码,因此可以轻松地实现与操作系统 API、硬件驱动程序、第三方库等非托管系统的交互。
不过在一些情况下,使用 ATL 可能会比使用 C++/CLI 更加高效和灵活。这是因为 ATL 提供了许多内置的 COM 基础类和模板,使得开发者可以快速创建高效的 COM 组件。此外,ATL 还提供了一套可选的 Active Template Library 对象模型(ATL OLE DB),这个对象模型提供了对 OLE DB 数据库访问的支持,使得开发者可以更方便地实现数据库相关的功能。
基于COM组件的相关操作可以回顾:
基于COM组件实现C#调用C++类对象过程中的注意事项