C#调用C类型dll入参为struct的问题详解

 更新时间:2021年03月22日 09:50:06   作者:Hancel  
这篇文章主要给大家介绍了关于C#调用C类型dll入参为struct问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

C# 可以通过 DllImport 的方式引用 C 类型的 dll。但很多 dll 的参数不会是简单的基础类型,而是结构体 struct 。因此就需要在 C# 端定义同样的结构体类型,才能实现调用 C 类型 dll。这里例举几种不同的结构体情况,以及其对应的解决方案。

基础调用方式

对于一个结构体类型:

typedef struct DATA
{
 int nNumber;
 float fDecimal;
};

在 C# 端就需要定义为

[StructLayout(LayoutKind.Sequential)]
public struct DATA
{
 public int nNumber;
 public float fDecimal;
}

包含字符数组

对于一个包含字符数组的结构体类型:

typedef struct DATA
{
 int nNumber;
 float fDecimal;
 char szString[256];
};

在 C# 端就需要使用 Marshal 设置数据空间大小,同时最好定义一个初始化函数与 get 的定义

[StructLayout(LayoutKind.Sequential)]
public struct DATA
{
 void alloc() {
  szString = new char[256];
 }

 string sString {
  get {
   int nLength = 256;
   string sData = "";
   for (int i = 0; i < nLength; i++)
   {
    if (szData[i] == '\0') break;
    sData += szData[i];
   }
   return sData;
  }
 }

 public int nNumber;
 public float fDecimal;
 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
 char[] szString;
}

包含字符二维数组

对于一个包含字符二维数组的结构体类型:

typedef struct DATA
{
 int nNumber;
 float fDecimal;
 char szString[6][256];
};

在 C# 端同样需要使用 Marshal 设置数据空间大小,需要将两个 Size 相乘,并定义一个初始化函数。同时在做一个 get 的定义。

[StructLayout(LayoutKind.Sequential)]
public struct DATA
{
 void alloc() {
  szString = new char[256 * 6];
 }

 public string[] sStrings
 {
  get {
   int nSize = 6, nLength = 256;
   string[] sDatas = new string[nSize];
   for (int i = 0; i < nSize; i++)
   {
    for (int j = 0; j < nLength; j++)
    {
     if (szData[i * nLength + j] == '\0') break;
     sData += szData[i * nLength + i];
    }
    sDatas[i] = sData;
   }
   return sDatas;
  }
 }

 public int nNumber;
 public float fDecimal;
 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256 * 6)]
 char[] szStrings;
}

dll 入参为结构体数组

若有一个这样的 C dll 函数定义:

void FnCall(DATA* datas);

// 调用方式
DATA datas[10];
fnCall(datas);

那么,在 C# 中要实现等价调用:

// 首先 Import 函数
[DllImport("Module.dll")]
public static extern void FnCall(IntPtr pInfo); // 注意入参要定义为指针

// 再定义定义结构体数组
int nCount = 10;
DATA datas = new DATA[nCount];

// 再分配内存空间
int nSize = Marshal.SizeOf(typeof(DEVICE_INFO));
IntPtr Dataptr = Marshal.AllocHGlobal(nSize * nCount);

// 调用函数
FnCall(Dataptr);

// 复制数据到结构体中
for (int i = 0; i < nCount; i++)
{
 IntPtr ptr = (IntPtr)((UInt32)Dataptr + i * size);
 datas[i] = (DEVICE_INFO)Marshal.PtrToStructure(ptr, typeof(DEVICE_INFO));
}

// 释放内存空间
Marshal.FreeHGlobal(Dataptr);

另外,如果你要调用的 dll 是非 C 类型 dll,而是 C++ Class。那么我们就可以将其再包装一层,转换为 C 类型 dll。

例如:

class Example {
public:
 int MethodCall();
};

那么就可以编写 C 类型的 dll。

extern "C" {
 Example* Example_New() { 
  return new Example(); 
 }
 int Example_MethodCall(Example* p) { 
  return p->MethodCall(); 
 }
 void Example_Delete(Example* p) { 
  delete p; 
 }
}

C# 那边就这样导入

[DllImport("Module.dll")]
public static extern IntPtr Example_Create();

[DllImport("Module.dll")]
public static extern int Example_MethodCall(IntPtr value);

[DllImport("Module.dll")]
public static extern void Example_Delete(IntPtr value);

// 调用方式
IntPtr p = Example_Create();
Example_MethodCall(p);
Example_Delete(p);

至于 C 类型 dll 中其他类型变量在 C# 的对应,则可以参考 Microsoft 的 文档

总结

到此这篇关于C#调用C类型dll入参为struct问题的文章就介绍到这了,更多相关C#调用C类型dll入参内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解C#把DataTable中数据一次插入数据库的方法

    详解C#把DataTable中数据一次插入数据库的方法

    本篇文章主要介绍了详解C#把DataTable中数据一次插入数据库的方法,具有一定的参考价值,有兴趣的可以了解一下。
    2017-01-01
  • UnityShader使用Plane实现翻书效果

    UnityShader使用Plane实现翻书效果

    这篇文章主要为大家详细介绍了UnityShader使用Plane实现翻书效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • C#命令行参数解析库System.CommandLine使用

    C#命令行参数解析库System.CommandLine使用

    System.CommandLine是一个基于.Net Standard 2.0的命令行参数解析库,该项目还是属于beta状态,期待以后的正式版本,文章通过示例代码给大家介绍了System.CommandLine使用讲解,感兴趣的朋友一起看看吧
    2021-06-06
  • Unity AssetBundle打包工具示例详解

    Unity AssetBundle打包工具示例详解

    这篇文章主要介绍了Unity AssetBundle打包工具,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-10-10
  • Unity使用LineRender实现绘画功能

    Unity使用LineRender实现绘画功能

    这篇文章主要为大家详细介绍了Unity使用LineRender实现绘画功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • C# 拼图魔方小游戏

    C# 拼图魔方小游戏

    这篇文章主要介绍了C# 拼图魔方小游戏,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • C# 设计模式系列教程-适配器模式

    C# 设计模式系列教程-适配器模式

    通过适配器,客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单、更直接、更紧凑。
    2016-06-06
  • C#绝对路径拼接相对路径的实例代码

    C#绝对路径拼接相对路径的实例代码

    C#绝对路径拼接相对路径的实例代码,需要的朋友可以参考一下
    2013-03-03
  • C#使用SqlDataAdapter对象获取数据的方法

    C#使用SqlDataAdapter对象获取数据的方法

    这篇文章主要介绍了C#使用SqlDataAdapter对象获取数据的方法,结合实例形式较为详细的分析了SqlDataAdapter对象获取数据具体步骤与相关使用技巧,需要的朋友可以参考下
    2016-02-02
  • c#实现网页图片提取工具代码分享

    c#实现网页图片提取工具代码分享

    c#实现网页图片提取工具代码分享,大家参考使用吧
    2013-12-12

最新评论