C#调用带结构体指针的C Dll的方法

原文:C#调用带结构体指针的C Dll的方法

在C#中调用C(C++)类的DLL的时候,有时候C的接口函数包含很多参数,而且有的时候这些参数有可能是个结构体,而且有可能是结构体指针,那么在C#到底该如何安全的调用这样的DLL接口函数呢?本文将详细介绍如何调用各种参数的方法。

一、调用接口仅含普通变量

eg:int fnAdd(int num1,int num2);

那么在C#调用这种函数最简单了,直接用函数原型即可,如下:

[DllImport("你的dll名称", EntryPoint = "fnAdd", CallingConvention = CallingConvention.Cdecl)]
public static extern int fnAdd(int num1, int num2);

这样在C#的方法内可以放心的使用这个dll函数了。

二、调用接口含普通变量的指针

大家都知道C#为了安全起见,隐形的避开了指针(其实在C#完全可以使用指针的,只是为了安全),采用了引用的方式来取代指针,引用的好处就是可以和指针一样操作参数原地址内的数据,并且这些数据在调用函数返回时还存活,但是引用不可以想指针那样++或者--到此PC指针乱跑,引出的一系列问题,下面举例来操作普通变量的指针,如下:

eg:int fnAdd(int *p_n1,int *p_n2);

上文已经说了C#采用引用来代替指针,那么好了调用接口可以这么写了:

[DllImport("你的dll名称", EntryPoint = "fnAdd", CallingConvention = CallingConvention.Cdecl)]
public static extern int fnAdd(ref int num1,ref int num2);

对,就这样的简单,这样C#便可以调用带指针的普通变量了。

三、来电稍微难度点的,调用接口含结构体

eg:在C的头文件内包含这样一个简单的结构体

struct mybuf
{
	int num1;
	int num2;
}

接口函数如下:

int fnAdd(struct mybuf mydata);

那么这样在C#该如何调用这样的接口函数呢?

首先在C#我们要声明一个结构体,在C#结构体并没有被抛弃,只不过在使用结构体时需要注意一些细节,比如要调用C的DLL那么最好在C#内定义的结构体前加上一些修饰符,如下:

[StructLayout(LayoutKind.Sequential)]
public struct MyBuf
{
	public int num1;
	public int num2;
	public MyBuf(int n1,int n2)
	{
		num1 = n1;
		num2 = n2;
	}
}
[DllImport("你的dll名称", EntryPoint = "fnAdd", CallingConvention = CallingConvention.Cdecl)]
public static extern int fnAdd(MyBuf mydata);

大家可能会发现怎么这个结构体这么像个类啊,是的啊在C#中结构体确实是个特殊的类,也有构造函数,如上例子中的public MyBuf(int n1,int n2)这样的构造函数;

大家也可能看到定义结构体前我们使用StructLayout这样的结构体布局修饰符,这个其实是很有用的,我们使用了LayoutKind.Sequential这个属性,这在dll的参数是指针的时候特别有用,因为你的C中的结构体内存是顺序布局的,因此我们在C#内也要采用顺序布局,这样传递指针的时候在C dll内就不会出错了(也不一定)。

另外大家看到结构体的成员变量我们都用来public修饰符,当没有public只有int num1这样的语句的时候,C#默认成员变量是保护的,那么你在C#中其他方法内定义这个结构体就不能随便的访问修改其成员变量了(只能通过构造函数new的时候进行初始化),因此需要使用public来修饰一下成员变量。

四、继续来点难度,其实也没什么难度,就是dll接口参数包含结构体指针

eg:int fnAdd(struct mybuf *p_mydata),或者写成int fnAdd(void *p_mydata)

上面两个函数其实是一样的,因为C规定void类型的指针可以指向任何数据类型,只不过在c函数实体内强制为你的数据类型即可,比如:

struct mybuf*p = (structmybuf*)p_mydata;

那么在C#内该如何调用该函数接口呢?很简单举一反三ref嘛……

好了,代码如下:

[StructLayout(LayoutKind.Sequential)]
public struct MyBuf
{
	public int num1;
	public int num2;
	public MyBuf(int n1,int n2)
	{
		num1 = n1;
		num2 = n2;
	}
}
[DllImport("你的dll名称", EntryPoint = "fnAdd", CallingConvention = CallingConvention.Cdecl)]
public static extern int fnAdd(ref MyBuf mydata);

对这样就OK了。

五、其实这样调用还有更复杂的,比如结构体内嵌套结构体,嵌套结构体指针,结构体内包含数组,这些都需要在C#

内声明结构体的时候需要特别处理,暂时就不增加这样的难度了。

<over>

<补>

为了继续增加点难度,下面继续补充几种情况,来涨点姿势……

六、dll接口参数内的结构体包含一个整形,一个字符数组

eg:如下的结构体

struct mybuf
{
	int a;
	int b;
	bool bl;
	int arr[200];
	char ch[100];
};

dll内接口原型为int fnAdd(struct mybuf mydata),那么这种情况在C#下该如何调用呢?

在C#中数据的布局和C(C++)中的数据布局有很大的不同,因此当用户需要在C#和C代码间进行数据传递时,必须手动

的告诉C#的老大.NET,这批数据该怎么传递给C的DLL来使用;因此这就涉及了C#的历史遗留问题(数据封送)。好

不多说先上代码,在C#该怎么声明这样一个结构体呢,如下:

[StructLayout(LayoutKind.Sequential)]
public struct MyBuf
{
    public int num1;
    public int num2;
    public bool flg;
    // 整形数组
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 200)]
    public int[] buf;
    // 字符数组
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
    public char[] ch;
    public MyBuf(int n1, int n2, bool bl)
    {
        num1 = n1;
        num2 = n2;
        flg = bl;
        buf = new int[200];
        ch = new char[100];
    }
};

是的,你可能奇怪的发现每个数值的声明前,增加了一个[MarshalAsxxxx]字段,这是干嘛用的呢?这就是前面红色字体标注的数据封送格式,简单介绍一下,MarshalAs的属性告诉了.NET如何将下面的数据进行封送到dll接口中,当UnmanagedType的值为ByValArray时,就是告诉下面的数据是一个数组,并且使用这个ByValArray值后面必须跟上SizeConst来告诉.NET这个数组的大小,如上;其实VS2010内写代码的时候当输入UnmanagedType之后按【.】之后VS会自动弹出框里面会列举很多数据封送格式,每个格式都有中文的tooltip来说明,自己看看就会明白的;前段时间看到字符数组和整形数据数据封送格式不一样,整形用ByValArray,而字符使用ByValTStr,但是实际我测下来当字符使用ByValTStr时调试的时候回报错,说非法的封送格式,把字符封送也改为ByValArray后就OK了,不晓得啥问题?还要继续研究。那么继续,在C#把结构体封装好了,就可以直接调用了,无论是结构体还是结构体指针按照前面的方法就可以使用了。

原文地址:https://www.cnblogs.com/lonelyxmas/p/9388797.html

时间: 2024-11-05 15:58:45

C#调用带结构体指针的C Dll的方法的相关文章

python 传递结构体指针到 c++ dll

CMakeLists.txt # project(工程名) project(xxx) # add_library(链接库名称 SHARED 链接库代码) add_library(xxx SHARED xxx.cpp) xxx.cpp #include <iostream> using namespace std; // c++ 结构体定义 struct struck_ { // 股票名,字符串 char * stock_code_; // 开盘价 double stock_open_; };

ctypes 操作 python 与 c++ dll 互传结构体指针

CMakeLists.txt # project(工程名) project(blog-3123958139-1) # add_library(链接库名称 SHARED 链接库代码) add_library(dll_ SHARED dll_.cpp) dll_.cpp #include <iostream> using namespace std; // c++ 结构体定义 struct cpp_struck_ { // 股票代码,字符串 char *stock_name_; // 日期,字符串

C#调用C++方法(结构体指针)

一:开发者文档 1.方法所需的结构体指针: 2.C++版本的SDK所提供的方法: 二:开始动手 1.定义结构体 2.准备好方法与SDK对应 3.项目使用,调用上面的方法 原文地址:https://www.cnblogs.com/HansZimmer/p/9766380.html

在VS2010上使用C#调用非托管C++生成的DLL文件

背景 在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使用一些第三方通讯组件的时候,通过C#来开发应用软件时,就需要利用DllImport特性进行方法调用.本篇文章将引导你快速理解这个调用的过程. 步骤 1. 创建一个CSharpInvokeCPP的解决方案: 2. 创建一个C++的动态库项目: 3. 在应用程序设置中,选择“DLL”,其他按照默认选项: 最后点击完成,得到如图所示项目: 我们可以看到这里有一些文件,其中dllmain.cpp作为定义DLL应用程序的入口点,它的作用跟

C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com

原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 本文由 arthinking 发表于315 天前 ⁄ itzhai.com原创文章 ⁄ C语言 ⁄ 评论数 3 ⁄ 被围观 1,775 views+ 指针数组: 在一个数组中,如果它的元素全部都是指针类

在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解)

背景 在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使用一些第三方通讯组件的时候,通过C#来开发应用软件时,就需要利用DllImport特性进行方法调用.本篇文章将引导你快速理解这个调用的过程. 步骤 1. 创建一个CSharpInvokeCPP的解决方案: 2. 创建一个C++的动态库项目: 3. 在应用程序设置中,选择“DLL”,其他按照默认选项: 最后点击完成,得到如图所示项目: 我们可以看到这里有一些文件,其中dllmain.cpp作为定义DLL应用程序的入口点,它的作用跟

[转]C语言指针 之 结构体指针

在C语言中几乎可以创建指向任何类型的指针,包括用户自定义的类型.创建结构体指针是极常见的.下面是一个例子: 1 typedef struct 2 { 3 char name[21]; 4 char city[21]; 5 char state[3]; 6 } Rec; 7 typedef Rec *RecPointer; 8 9 RecPointer r; 10 r=(RecPointer)malloc(sizeof(Rec)); r是一个指向结构体的指针.请注意,因为r是一个指针,所以像其他指

vlc的应用之三:动态调用vlc-0.9.4的libvlc.dll【转】

 vlc的应用之三:动态调用vlc-0.9.4的libvlc.dll 2008-12-03 17:38:46 标签:WinForm C# libvlc.dll 休闲 vlc 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://jeremiah.blog.51cto.com/539865/116981 vlc-0.9.4提供的libvlc.dll是可以动态调用的,Jeremiah这一篇博客就介绍下如何用C#和WinForm框架调用l

在VS2017上使用C#调用非托管C++生成的DLL文件(图文讲解)

原文:在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解) 背景 在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使用一些第三方通讯组件的时候,通过C#来开发应用软件时,就需要利用DllImport特性进行方法调用.本篇文章将引导你快速理解这个调用的过程. 步骤 1. 创建一个CSharpInvokeCPP的解决方案: 2. 创建一个C++的动态库项目 CSharpInvokeCPP.CPPDemo: 3. 在Windows桌面项目中,选择“动态链接库DLL”,其他按