当前位置:首页 > 文章中心 > 正文内容

C#和C++混合编程开发示例

dgx6669个月前 (03-14)文章中心65

C#使用过程中经常会遇到和C++联合开发的过程,通过C++编写动态库,封装成dll后再C#中调用,在此做个记录,并供后期查看

一、新建C#控制台项目

打开VisualStudio,新建一个C#控制台项目,项目名称HelloWorldTest

点击下一步,一个空的默认c#项目创建完成

二、创建C++库

在解决方案上右键--添加--新建项目,建一个C++动态链接库工程,输入项目名称TestDll

创建完成后如下:

这里为了方便,我们直接在HelloWorldLib.cpp里定义函数

C++库导出有两种方式

1、以C语言接口的方式导出

这种方法就是在函数前面加上 extern "C" __declspec(dllexport)

加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。

#include "stdafx.h"
#include

extern "C" __declspec(dllexport) void HelloWorld(char* name);
 
extern "C" __declspec(dllexport) void HelloWorld(char* name)
{
 std::cout << "Hello World " << name << std::endl;
}

2、以模块定义文件的方式导出

在工程上右键,选择添加-》新建项

然后选择代码-》模块定义文件

在Source.def中输入

LIBRARY

EXPORTS
HelloWorld

EXPORTS下面就是要导出的函数,这里不需要添加分号隔开,直接换行就行。

此时,我们函数的定义如下

#include "stdafx.h"
#include
 
void HelloWorld(char* name);
 
void HelloWorld(char* name)
{
 std::cout <<"Hello World "<< name << std::endl;
}

编译,生成dll。这里需要注意的是,如果生成是64位的库,C#程序也要是64位的,否则会报错

在C#项目中添加引用:同时把C#代码修改为:

using System.Runtime.InteropServices;

namespace ConsoleApplication2
{
 class Program
 {
  [DllImport("HelloWorldLib.dll")]
  public static extern void HelloWorld(string name);

  //可以通过EntryPoint特性指定函数入口,然后为函数定义别名

  [DllImport("HelloWorldLib.dll", EntryPoint = "HelloWorld")]
  public static extern void CustomName(string name);
  static void Main(string[] args)
  {
   HelloWorld("LiLi");
   //跟上面是一样的
   CustomName("QiQi");
  }
 }
}

运行程序,结果如下:

这样就成功创建了一个C#可以调用的C++库

下面我们动态调用C++库,这里委托的作用就比较明显了。把委托比喻为C++的函数指针,一点也不为过。

我们在C++库中再新增一个函数GetYear(),用来获取当前年份。

int GetYear();

int GetYear()
{
 SYSTEMTIME tm;
 GetLocalTime(&tm);
 
 return tm.wYear;
}

记得在导出文件中(Source.def)增加GetYear。编译,生成新的DLL

再新建一个C#控制台程序

using System;
using System.Runtime.InteropServices;

namespace ConsoleApplication3
{

 class Program
 {
  [DllImport("kernel32.dll")]
  public static extern IntPtr LoadLibrary(string lpFileName);

  [DllImport("kernel32.dll")]
  public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

  [DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)]
  public static extern bool FreeLibrary(IntPtr hModule);

  //声明委托,这里的签名,需要跟C++库中的对应
  delegate int GetYearDelegate();

  static void Main(string[] args)
  {
   GetYearDelegate m_fGetYear;
   IntPtr hModule = LoadLibrary("HelloWorldLib.dll");
   if(hModule != IntPtr.Zero)
   {
    IntPtr hProc = GetProcAddress(hModule, "GetYear");
    if(hProc != IntPtr.Zero)
    {
     m_fGetYear = (GetYearDelegate)Marshal.GetDelegateForFunctionPointer(hProc, typeof(GetYearDelegate));

     //在这里可以调用
     int year = m_fGetYear();
     Console.WriteLine("年份是:" + year);
    }
   }
  }
 }
}

运行结果:

好的,前面函数里面涉及的都是简单数据类型,下面来介绍一下复杂数据类型。这里指的是结构体

在C++库中定义一个GetDate()的函数,代码如下。这里也要记得在导出文件中添加(Source.def)

struct MyDate
{
 int year;
 int month;
 int day;
};

MyDate GetDate();

MyDate GetDate()
{
 SYSTEMTIME tm;
 GetLocalTime(&tm);
 
 MyDate md;
 md.day = tm.wDay;
 md.month = tm.wMonth;
 md.year = tm.wYear;
 return md;
}
建一个C#控制台程序,完整代码如下
using System;
using System.Runtime.InteropServices;
 
namespace ConsoleApplication3
{
 struct MyDate
 {
  public int Year;
  public int Month;
  public int Day;
 }
 
 
 class Program
 {
  [DllImport("kernel32.dll")]
  public static extern IntPtr LoadLibrary(string lpFileName);
 
  [DllImport("kernel32.dll")]
  public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
 
  [DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)]
  public static extern bool FreeLibrary(IntPtr hModule);
 
  delegate IntPtr GetDateDelegate();
 
  static void Main(string[] args)
  {
   GetDateDelegate m_fGetDate;
   IntPtr hModule = LoadLibrary("HelloWorldLib.dll");
 
   if (hModule != IntPtr.Zero)
   {
    IntPtr hProc = GetProcAddress(hModule, "GetDate");
    if (hProc != IntPtr.Zero)
    {
     m_fGetDate = (GetDateDelegate)Marshal.GetDelegateForFunctionPointer(hProc, typeof(GetDateDelegate));
     IntPtr ptr = m_fGetDate();
     if(ptr != IntPtr.Zero)
     {
      MyDate md = (MyDate)Marshal.PtrToStructure(ptr, typeof(MyDate));
      Console.WriteLine("{0}年-{1}月-{2}日",md.Year,md.Month,md.Day);
     }
    }
   }
  }
 }
}

运行结果如下:

扫描二维码推送至手机访问。

版权声明:本文由第六芝士网发布,如需转载请注明出处。

本文链接:http://www.dgx666.com/post/287.html

分享给朋友:

“C#和C++混合编程开发示例” 的相关文章

SolidWorks2014安装教程

软件介绍SolidWorks是一款专业的三维3D设计软件,功能强悍,支持分布式数据管理,支持直接处理网格数据,提供更多的数据的灵活性,使用起来高效便捷。可以帮助用户轻松进行3D CAD设计、机械设计、钣金设计、模拟设计、电气设计、PDM数据管理、CAM加工等。软件安装解压和安装前先退出360、电脑管...

非常实用!AutoCAD辅助绘图从新手到高手

【光盘内容】282个本书素材及效果文件,168个本书同步高清视频,600分钟超长播放的多媒体视听教学光盘,2本畅销书视频及素材文件超值赠送(2.11GB)。它是与图书完美结合的视听课堂,让您像看电视一样轻松、直观地进行学习。【主要内容包括】绘制二维图形使用辅助工具精确绘图编辑二维图形对象设置与管理图...

CAD运行需要什么样的电脑配置

最近发现很多小伙伴都在问一个问题,学习CAD 需要什么样的电脑配置,游戏本是不是能满足CAD的绘图需求?预算3000-4000元能不能买到能画CAD的笔记本?今天小编跟大家简单探讨一下这个问题,因为小编并不是计算机专业的,所以你对本文章有不同看法,请尽情留言,一同探讨。基本上只要提到学习CAD,用C...

网易停运两年游戏将复活,魔兽争霸官方对战平台明年却要停运了

最近游戏圈里也是出了不少让人唏嘘的反转,上个月网易和暴雪分手也是引发整个行业内外都在关注了。而今天的两个主角,却恰恰又和网易、暴雪沾上了关系——游戏经历比较久远的网友,对于对战平台等可能都不会太陌生,当年的浩方、11等对战平台也是成为一代人联机体验《魔兽争霸3:冰封王座》《DOTA》《真三国无双》等...

cad2007修剪工具使用方法技巧 #cad2007

大家好,今天给大家分享一下在 cd 当中修剪工具的使用方法。1. 这个工具用的非常多,经常会画一些线条去进行裁剪。其用法是,当这种线条有交叉了以后,如果需要去把多余的延伸出来的线条进行修剪,可以使用这个工具 tr,它的命令是缩进去以后空格一次、两次,然后点击这些线条就可以删除,这样就可以把交叉的线条...

COD19/使命召唤19 0x887A0005/0x887A0006错误代码最新解决方法

使命召唤19是无数玩家喜爱的射击游戏,这款游戏玩法丰富经典,战区由实地采景制作,得到玩家们的认可。同时,也有不少玩家遇到了使命召唤19 0x887A0005、0x887A0006错误代码的问题,玩家们不知道应该如何解决,下面小编为大家带来使命召唤190 x887A0005、0x887A0006错误代...