最近由于有个未知的设备需要用到modbus通讯协议,底层需要与PLC通讯,坤跌,PLC啥型号也不清楚封在里面不能拆,前人只留了几个不能运行的QT代码以及不完整的文档。用惯了C#想要重新学QT,真不知猴年马月能完成项目。于是乎找了一个开源的基于C语言开发的modbus库,撸起袖子干了起来。撸代码的过程中,遇到调用c 库的char*转c#的string多次不成功的情况,各种冒框啊,折腾了大半天才算解决,最终记录如下,以备后面遇到同样的坑能少走点弯路。
.h file
#pragma once #define LineMaxLen 2048 #define KeyMaxLen 128 #define MaxFileLength 1024*10
#if defined(_MSC_VER) # if defined(DLLBUILD) /* define DLLBUILD when building the DLL */ # define MODBUS_API __declspec(dllexport) # else # define MODBUS_API __declspec(dllimport) # endif #else # define MODBUS_API #endif static char value[KeyMaxLen];//需要定义为全局变量,编译成dll后才能被c#正常调用,否则指针地址有数据,指针内容看到的返回值为空 MODBUS_API char* getValue(); MODBUS_API int sum(int a, int b); #endif
.c file
char* getValue()//char key[KeyMaxLen] { memset(value, 0, sizeof(value)); strcpy(value, "abcdefgh"); return value; }
.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; namespace RotPlatformControl_CsDll { public class CRotPlatformControl { [DllImport("modbus.dll", EntryPoint = "getValue", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr getValue();//不能用string,使用IntPtr对应于c中的函数返回类型char* } }
private void buttonHome_Click(object sender, EventArgs e) { IntPtr temp = CRotPlatformControl.getValue(); res=Marshal.PtrToStringAnsi(temp).ToString(); temp = IntPtr.Zero; lblMessage.Text = res.ToString(); }
UI显示“abcdefgh” 说明dll已经调用成功。
总结:
1. const char* 直接换成string
2. char*做形参或返回值,需要换成IntPtr
3. char*做形参并想要获取char*内容,使用ref IntPtr无用。只能将该char*改为返回值获得。
4. C库文件中需要定义为全局变量,编译成dll后才能被c#正常调用,否则指针地址有数据,指针内容看到的返回值为空。
modbus封库源码
https://download.csdn.net/download/ericwuhk/10352801