VS2010 C#调用C++ DLL文件 【转】
http://www.soaspx.com/dotnet/csharp/csharp_20110406_7469.html
背景
在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使用一些第三方通讯组件的时候,通过C#来开发应用软件时,就需要利用DllImport特性进行方法调用。本篇文章将引导你快速理解这个调用的过程。
步骤
1. 创建一个CSharpInvokeCPP的解决方案:

2. 创建一个C++的动态库项目:

3. 在应用程序设置中,选择“DLL”,其他按照默认选项:

最后点击完成,得到如图所示项目:

我们可以看到这里有一些文件,其中dllmain.cpp作为定义DLL应用程序的入口点,它的作用跟exe文件有个main或者WinMain入口函数 是一样的,它就是作为DLL的一个入口函数,实际上它是个可选的文件。它是在静态链接时或动态链接时调用LoadLibrary和FreeLibrary 时都会被调用。详细内容可以参考(http://blog.csdn.net/benkaoya/archive/2008/06/02/2504781.aspx)。
4. 现在我们打开CSharpInvokeCPP.CPPDemo.cpp文件:
现在我们加入以下内容:
1 // CSharpInvokeCPP.CPPDemo.cpp : 定义 DLL 应用程序的导出函数。
2 //
3
4 #include "stdafx.h"
5
6 extern "C" __declspec(dllexport) int Add(int x, int y)
7 {
8 return x + y;
9 }
10 extern "C" __declspec(dllexport) int Sub(int x, int y)
11 {
12 return x - y;
13 }
14 extern "C" __declspec(dllexport) int Multiply(int x, int y)
15 {
16 return x * y;
17 }
18 extern "C" __declspec(dllexport) int Divide(int x, int y)
19 {
20 return x / y;
21 }
extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。而被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。
__declspec(dllexport)的目的是为了将对应的函数放入到DLL动态库中。
extern "C" __declspec(dllexport)加起来的目的是为了使用DllImport调用非托管C++的DLL文件。因为使用DllImport只能调用由C语言函数做成的DLL。
5. 编译项目程序,最后在Debug目录生成CSharpInvokeCPP.CPPDemo.dll和CSharpInvokeCPP.CPPDemo.lib

我们用反编译工具PE Explorer查看下该DLL里面的方法:

可以发现对外的公共函数上包含这四种“加减乘除”方法。
6. 现在来演示下如何利用C#项目来调用非托管C++的DLL,首先创建C#控制台应用程序:

7. 在CSharpInvokeCSharp.CSharpDemo项目上新建一个CPPDLL类,编写以下代码:
1 public class CPPDLL
2 {
3 [DllImport("CSharpInvokeCPP.CPPDemo.dll")]
4 public static extern int Add(int x, int y);
5
6 [DllImport("CSharpInvokeCPP.CPPDemo.dll")]
7 public static extern int Sub(int x, int y);
8
9 [DllImport("CSharpInvokeCPP.CPPDemo.dll")]
10 public static extern int Multiply(int x, int y);
11
12 [DllImport("CSharpInvokeCPP.CPPDemo.dll")]
13 public static extern int Divide(int x, int y);
14 }
DllImport作为C#中对C++的DLL类的导入入口特征,并通过static extern对extern “C”进行对应。
8. 另外,记得把CPPDemo中生成的DLL文件拷贝到CSharpDemo的bin目录下,你也可以通过设置【项目属性】->【配置属性】->【常规】中的输出目录:

这样编译项目后,生成的文件就自动输出到CSharpDemo中了。
9. 然后在Main入口编写测试代码:
1 static void Main(string[] args)
2 {
3 int result = CPPDLL.Add(10, 20);
4 Console.WriteLine("10 + 20 = {0}", result);
5
6 result = CPPDLL.Sub(30, 12);
7 Console.WriteLine("30 - 12 = {0}", result);
8
9 result = CPPDLL.Multiply(5, 4);
10 Console.WriteLine("5 * 4 = {0}", result);
11
12 result = CPPDLL.Divide(30, 5);
13 Console.WriteLine("30 / 5 = {0}", result);
14
15 Console.ReadLine();
16 }
运行结果:

方法得到调用。
10. 以上的方法只能通过静态方法对于C++中的函数进行调用。那么怎样通过静态方法去调用C++中一个类对象中的方法呢?现在我在CPPDemo项目中添加一个头文件userinfo.h:
1 class UserInfo {
2 private:
3 char* m_Name;
4 int m_Age;
5 public:
6 UserInfo(char* name, int age)
7 {
8 m_Name = name;
9 m_Age = age;
10 }
11 virtual ~UserInfo(){ }
12 int GetAge() { return m_Age; }
13 char* GetName() { return m_Name; }
14 };
在CSharpInvokeCPP.CPPDemo.cpp中,添加一些代码:
1#include "malloc.h"
2#include "userinfo.h"
3
4typedef struct {
5 char name[32];
6 int age;
7} User;
8
9UserInfo* userInfo;
10
11extern "C" __declspec(dllexport) User* Create(char* name, int age)
12{
13 User* user = (User*)malloc(sizeof(User));
14
15 userInfo = new UserInfo(name, age);
16 strcpy(user->name, userInfo->GetName());
17 user->age = userInfo->GetAge();
18
19 return user;
20}
这里声明一个结构,包括name和age,这个结构是用于和C#方面的结构作个映射。
注意:代码中的User*是个指针,返回也是一个对象指针,这样做为了防止方法作用域结束后的局部变量的释放。
strcpy是个复制char数组的函数。
11. 在CSharpDemo项目中CPPDLL类中补充代码:
1 [DllImport("CSharpInvokeCPP.CPPDemo.dll")]
2 public static extern IntPtr Create(string name, int age);
3
4 [StructLayout(LayoutKind.Sequential)]
5 public struct User
6 {
7 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
8 public string Name;
9
10 public int Age;
11 }
其中这里的结构User就和C++中的User对应。
12. 在Program.cs中补充代码:
1 IntPtr ptr = CPPDLL.Create("李平", 27);
2 <strong><font color="#ff0000">CPPDLL.User user = (CPPDLL.User)Marshal.PtrToStructure(ptr, typeof(CPPDLL.User));</font></strong>
3 Console.WriteLine("Name: {0}, Age: {1}", user.Name, user.Age);
注意:红色字体部分,这里结构指针首先转换成IntPtr句柄,然后通过Marshal.PtrToStructrue转换成你所需要的结构。
运行结果:

最后附上我的源代码:CSharpInvokeCPP.rar,希望对大家有所帮助:)
VS2010 C#调用C++ DLL文件 【转】的更多相关文章
- VS2010 C#调用C++ DLL文件
http://www.soaspx.com/dotnet/csharp/csharp_20110406_7469.html http://www.cnblogs.com/warensoft/archi ...
- Java调用第三方dll文件的使用方法 System.load()或System.loadLibrary()
Java调用第三方dll文件的使用方法 public class OtherAdapter { static { //System.loadLibrary("Connector") ...
- VS2010 项目引用了DLL文件,也写了Using,但是编译时提示:未能找到类型或命名空间名称 <转>
昨天写了一个很小的winform程序,其中引用了自己写的两个dll文件. 本来认为轻松搞定,结果一编译居然提示:未能找到类型或命名空间名称..... 于是删掉两个dll重新引用,再编译结果依旧!很是郁 ...
- C#调用C++ DLL 文件
说来惭愧,都注册一年多了,却没有发表过一篇正式的博文,中间很多学习的过程也没有记录下来.如今到了一个新的环境,也有了学习的机会,一定要把每天的收获记录一下. 要做的东西需要引用C++编写的DLL,刚开 ...
- 对C#调用C++ dll文件进行总结
在实际项目工作中,经常用到C#调用C++ 或者C编写的dll文件. dll支持一般函数声明和类的定义声明,但是一般为了简化,都是 采用函数声明的方式.这里主要并不是写 dll的编写. 先在vs中创建一 ...
- java调用c#dll文件配置
1 在强大的c#语言和java语言之间,二者难免会因为某些特殊的要求会相互调用. 下面就以java调用c#的dll为例做详细介绍 1 在vs中的环境设置如下图,图片中程序仅作为讲解程序,在项目编译成 ...
- 用vc生成可被python调用的dll文件
前提已经有.c 和.i文件 用swid编译了.i文件生成了wrap.c文件和.py文件 vc创建dll工程 将.h加入到头文件中.c文件和wrap.c文件添加到源文件中 将.i文件添加到工程目录下To ...
- 制作和unity调用动态链接库dll文件
首先用vc建立一个dll工程 然后在里面建立一个testunity.h文件.内容如下 1 extern "C" int _declspec(dllexport)testunity( ...
- unity调用C++ dll文件
首先建立Plugins文件夹,把dll文件放在里面 一一对应,我踩的坑是文件名加了后缀.dll,虽然不知道网上为什么都加了我这加了就报找不到dll文件错误,反正解决啦
随机推荐
- Python+Selenium练习篇之6-利用class name定位元素
有时候,我们在用firepath(不会的请点这里)查看元素的XPath信息,发现没有可以用来定位的id信息,这个时候我们就需要考虑用其他的可用的来定位元素.本文介绍如何通过元素节点中class nam ...
- c#之线程同步--轻量级同步 Interlocked
轻量级同步 Interlock 为什么说它是轻量级呢?因为它仅对整形数据(即int类型,long也行)进行同步. 如果你学过操作系统里面的PV操作(即信号量),那么你对它已经了解了一般.它实现的正是如 ...
- [oldboy-django][3作业汇总]登录,注册最终版
# 作业(登录,注册)最终版 - 保留上次输入的值 - 用户数据格式的验证
- leetcode NO.171 Excel表列序号 (python实现)
来源 https://leetcode-cn.com/problems/excel-sheet-column-number/description/ 题目描述 给定一个Excel表格中的列名称,返回其 ...
- 重做LVM文件系统之减小PV
命令 缩小PV空间到120G,即PV上的vg00已将缩小到120G pvresize --setphysicalvolumesize 120g /dev/sda2 背景 机器上有一块900G本地的本地 ...
- Java.io.File中的delete()方法和deleteOnExit()方法的区别
1.delete()方法: 当调用delete()方法时,直接删除文件,不管该文件是否存在,一经调用立即执行: 2.deleteOnExit()方法: 当 ...
- mybatis 从数据库查询的信息不完整解决办法
List<Product> products = productService.getProductListWithPage(productQuery); 今天碰到一个很奇怪的现象,上面的 ...
- python实现贪吃蛇
贪吃蛇的算法还是比较简单的,蛇的移动我是通过不停添加一个head方块,然后判断应该加到蛇头的哪个方向,加完后删掉蛇尾就行了,如果吃到食物就不删蛇尾. 只是一个贪吃蛇只需要70行代码左右就可以了,后来又 ...
- [bzoj 3048] [Usaco2013 Jan]Cow Lineup
[bzoj 3048] [Usaco2013 Jan]Cow Lineup Description 给你一个长度为n(1<=n<=100,000)的自然数数列,其中每一个数都小于等于10亿 ...
- 【HDOJ5956】The Elder(树形DP,斜率优化)
题意:有一棵n个点的有根树,每条边上有一个边权.给定P,从i跳到它的祖先j的费用是距离的平方+P,问所有点中到根节点1的总花费最大值 n<=1e5,p<=1e6,w<=1e2 思路: ...