最近由于有个未知的设备需要用到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.youkuaiyun.com/download/ericwuhk/10352801