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

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

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

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指针乱跑,引出的一系列问题,下面举例来操作普通变量的指针,如下:

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#便可以调用带指针的普通变量了。

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

在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接口参数包含结构体指针

nt 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#

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

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

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

如下的结构体

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#把结构体封装好了,就可以直接调用了,无论是结构体还是结构体指针按照前面的方法就可以使用了。

到此这篇关于C#调用带结构体指针的Dll的方法的文章就介绍到这了,更多相关C# 结构体针Dll内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C#之set与get方法的用法案例

    需求:学生输入姓名和语文.数学.英语,编程求出总分和平均分,并在屏幕上显示XX的总分和平均分 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; //学生输入姓名和语文.数学.英语,编程求出总分和平均分,并在屏幕上显示XX的总分和平均分 namespace Student_management_system { cla

  • C# DirectShow预览摄像头并截图

    C# DirectShow预览摄像头并截图,供大家参考,具体内容如下 本事例通过Windows DirectX Filtergraph 一些列管道将电脑所接入视频采集设备的视频流播放到制定区域,通过ISampleGrabberCB接口的BufferCB回调函数截取图片. 用此方法预览图像cpu占用率极低,比其其他事件绑定并逐帧显示图像性能更佳. UI布局: 代码如下: using System; using System.Drawing; using System.Windows.Forms;

  • C# windows语音识别与朗读实例

    C# windows语音识别与朗读示例,供大家参考,具体内容如下 本示例通过windows语音识别功能进行语音识别和文本朗读. 打开windows麦克风,点击start按键,大声朗读 "中国"."美国"."英国",识别成功将发出"嘟"的提示音并朗读对应结果. 用到的语音识别模块包括: using System.Speech.Recognition; using System.Speech.Synthesis; 动态连接库文件在

  • C#实现滑动开关效果

    C#重绘checkbox生成滑动开关,供大家参考,具体内容如下 通过调用checkbox控件的paint事件,在重绘事件里判断checked属性,如果选中绘制选中图形,如果未选中绘制未选中图形. 效果图: 绘制圆角矩形方法: /// <summary> /// 填充圆角矩形 /// </summary> /// <param name="g"></param> /// <param name="brush">

  • C#实现电脑麦克风录音

    本实例通过Naudio库完成麦克风录音并把PCM脉冲信号保存成wav音频文件.关于音频的采样率.比特率.声道等问题请查阅相关资料,本示例不做解释.Naudio库 请从NuGet搜索并下载. 录音接口类: public interface ISpeechRecorder { void SetFileName(string fileName); void StartRec(); void StopRec(); } 录音实现类: using System; using NAudio.Wave; nam

  • C# WebApi+Webrtc局域网音视频通话实例

    C# WebApi+Webrtc 局域网音视频通话示例,供大家参考,具体内容如下 本示例通过IIS部署webapi,利用websocket进行webrtc消息交换,通过Chrome浏览器访问,可实现局域网内webrtc 音视频通话. 通过Chrome浏览器打开localhost/live.html本地网址,打开两个本地网,点击任意页面连接按钮即联通. 本示例未实现NAT穿透处理,互联网无法联通,如需NAT穿透请自行查阅相关资料. 关于webrtc.webapi相关技术说明请自行查阅相关资料,本文

  • C#实现截图工具小项目

    本文实例为大家分享了C#实现截图工具小项目的具体代码,供大家参考,具体内容如下 1.起因 一直用的截图是qq的截图,所以想要实现一个简单点的截图,为了方便. 2.思路 讲一下实现流程. 1.主窗体,上有截图按钮,点击进入截图窗体 2.在截图窗体中,背景设置为全屏幕的截图图片,无边框,窗体最大化,这时你看到的就是一张屏幕图,其实是一个窗体,然后我们将在这个窗体中截取图片,其实主要就是画板Graphics的使用,截取完之后图片将保存到剪切板. 3.代码 热键注册类   HotKey.cs using

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

    在C#中调用C(C++)类的DLL的时候,有时候C的接口函数包含很多参数,而且有的时候这些参数有可能是个结构体,而且有可能是结构体指针,那么在C#到底该如何安全的调用这样的DLL接口函数呢?本文将详细介绍如何调用各种参数的方法. 一.调用接口仅含普通变量 int fnAdd(int num1,int num2); 那么在C#调用这种函数最简单了,直接用函数原型即可,如下: [DllImport("你的dll名称", EntryPoint = "fnAdd", Cal

  • 使用python来调用CAN通讯的DLL实现方法

    由于工作上的需要,经常要与USBCAN打交道,但厂家一般不会提供PYTHON的例子,于是自己摸索地写一个例子出来,以便在工作上随时可以使用PYTHON来测试CAN的功能.这里的例子是使用珠海创芯科技有限公司的USBCAN接口卡,他们提供一个ControlCAN.dll,也提供了一个.h文件,如下: #ifndef CONTROLCAN_H #define CONTROLCAN_H ////文件版本:v2.00 20150920 //#include <cvidef.h> //使用CVI平台开发

  • PHP调用C#开发的dll类库方法

    有的时候,我们需要在php中利用到其他语言编写的dll类库,如C#编写的dll,方法就是利用PHP new COM方法来调用,在调用之前先要把dll库注册并把程序集放入到全局缓存中. 1. 创建一个 C# Class Library ,命名为:HelloWorld 2. 打开项目的属性,在点选左边的 "Application"(就是第一个tab) , 然后点击Assembly Information 按钮 ,在弹出的Dialog中, 必须在底部勾上: Make assembly COM

  • java使用jna调用c#中dll的方法详解

    前言 JNA(Java Native Access )提供一组Java工具类用于在运行期动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JNI代码.开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射. 优点 JNA可以让你像调用一般java方法一样直接调用本地方法.就和直接执行本地方法差不多,而且调用本地方法还不用额外的其他处理或者配置什么的,

  • 易语言编写调用dll文件方法总结

    易语言编写dll文件,在新建中选择 编写动态链接库 然后我们看到的就是这样的 这里要注意的是,可以直接在启动子程序下些命令,勾选公开,一样可以调用.但是程序会运行两遍. 方法,忽略上面默认代码,直接新建子程序,子程序名自定,需要返回值的填写返回值类型,一定要勾选公开 可以提供参数和变量. 然后静态编译 OK.这样就编写了一个dll. 调用dll,假设我们编写的dll名字为123.dll 调用的时候,插入一个新的dll,"DLL命令名"自定义,无所谓什么."库文件名"

  • Windows系统Python直接调用C++ DLL的方法

    环境:Window 10,VS 2019, Python 2.7.12, 64bit 1,打开 VS 2019,新建C++ Windows 动态链接库工程 Example,加入下列文件,如果Python是64位的则在VS中 Solution platforms 选择 x64 编译成64位的 DLL: Example.h #pragma once #ifndef CPP_EXPORTS #define CPP_EXPORTS #endif #ifdef CPP_EXPORTS #define CP

  • 易语言调用模块和DLL的方法教学

    易语言是一门中文编程语言,虽然其功能已经非常完善,但是很多时候为了方便甚至有时候是必须调用一些模块和DLL文件,能够极大的提高编程效率.作为一个易语言新手不建议频繁的调用模块,这样不利于学习,但如何调用时必须得学会. 1.打开易语言,新建一个Windows桌面程序.本例以改变进度条颜色为例,在主窗口拖放一个"进度条"和"按钮"控件,如下图,"进度条"显示方式设置成成"连续"且位置改为50:"按钮"标题改为&

  • java调用相互依赖的dll的处理方法

    目录 一.问题描述 二.处理办法 2.1 类定义 2.2 调用 三.结语 一.问题描述 最近在做一个功能时遇到java需要调用dll,并且dll有依赖关系,之前都是单独调用一个,其实调用dll的都是模板代码,本身没有太高的难度,主要是相互依赖的还是第一次碰见,特此记录一下并分享给需要的朋友参考. 二.处理办法 其中A是dll方法的入口,A依赖B,C,D,E,F,G五个dll,先定义接口继承StdCallLibrary ,编写加载各个dll的模板代码,需要依赖的都全部加载进来,我这儿是A依赖了B,

  • C#使用DLLImport调用外部DLL的方法

    C#.Net调用基本格式: DllImport 属性提供非托管 DLL 函数的调用信息. [DLLImport(“DLL文件路径”)]修饰符 extern 返回值类型 方法名称(参数列表) 如: using System.Runtime.InteropServices; [DllImport( "KERNEL32.DLL", EntryPoint="MoveFileW", SetLastError=true, CharSet=CharSet.Unicode, Exa

  • 分享如何在VB中调用VC编写的DLL

    一般来说,VB和VC共同编程有3种方式:一种是VC生成DLL,在VB中调用DLL:一种是VC生成ActiveX控件(.ocx),在VB中插入:还有一种是在VC中生成ActiveX Automation服务器,在VB中调用.相对而言,第一种方法对VC编程者的要求最低,但要求你的伙伴进行配合,我推荐这种方法. 先说说VC++的编程.首先在VC++中生成Win32 DLL工程.在这个工程中添加几个函数供VB用户调用.一个DLL中的函数要想被VB调用,必须满足两个条件:一是调用方式为stdcall,另一

随机推荐