• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

卢晓春的博客

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

C#调用c语言dll,并且传入byte数组或字符串,简单实例

前言

在C#中调用dll,可能会出现程序一开始可以运行,但过一会儿后出现内存错误——尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
这是由于C#的托管内存机制,而C语言中是非托管内存。如果参数传入dll后,C#提前回收了内存或者移动了数据,将会出现错误。
解决方法是,在C#传入dll参数之前,将托管内存中的数据移动到非托管内存中,然后传入非托管内存的地址。(同理我们需要在dll中函数执行完后,手动释放非托管内存)、

静态路径调用dll

使用DllImport即可

const string zlg1939Dllpath = "C:\\projects\\自动测试\\zlgcanj1939\\Debug\\zlgcanj1939.dll";
[DllImport(zlg1939Dllpath, CallingConvention = CallingConvention.Cdecl)]
public static extern uint zlgcanInit(IntPtr dllDirectory, uint baurdrate);

[DllImport(zlg1939Dllpath, CallingConvention = CallingConvention.Cdecl)]
public static extern int zlgcanSendOneMessage(uint id, IntPtr data, byte datanum);

参数传入

核心思想是,使用Marshal类,开辟非托管的内存空间,然后向dll传入指针。
下面例举的C语言函数原型为:

int zlgcanInit(char* dllDirectory, uint32_t baurdrate, uint32_t device_index, uint32_t can_index);
int zlgcanSendOneMessage(uint32_t id, uint8_t* data, uint8_t datanum);

字符串

// 参数声明使用 IntPtr dllDirectory
// public static extern uint zlgcanInit(IntPtr dllDirectory, uint baurdrate);
// 参数传入使用 Marshal.StringToHGlobalAnsi(zlgwrapDllpath)
zlgcanInit(Marshal.StringToHGlobalAnsi(zlgwrapDllpath), 250000);

简单类型数组(例如byte数组)

// 参数声明使用 IntPtr data
// public static extern int zlgcanSendOneMessage(uint id, IntPtr data, byte datanum);
// 指向非托管内存的指针
IntPtr dataptr = Marshal.AllocHGlobal(8 * sizeof(byte));
// 托管内存中的数组
byte[] data = { 0, 0, 0, 4, 5, 0, 0, 0 };
// 内存复制
Marshal.Copy(data, 0, dataptr, 8);
// 调用
zlgcanSendOneMessage(0xcf00400, dataptr, 8);

释放内存

Marshal.FreeHGlobal(IntPtr);

posted on 2024-12-20 18:47  卢晓春  阅读(368)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3