c# 调用c库dll 遇到char*转string的解决办法

20 篇文章 0 订阅

最近由于有个未知的设备需要用到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



  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用 C# 中的 DllImport 属性来调用 C++ DLL 中的函数,具体步骤如下: 1. 在 C++ DLL 中定义一个函数 style_transfer,该函数需要使用 extern "C" 声明,并使用 __declspec(dllexport) 修饰符导出。该函数的参数和返回值类型需要与 C# 中的声明一致。 2. 在 C# 中声明 DLLImport 属性,用于指定 C++ DLL 的名称和函数签名。 3. 在 C#调用 C++ DLL 中的函数。 下面是一个简单的示例,演示如何在 C#调用 C++ DLL 中的 style_transfer 函数: C++ DLL 代码: ```cpp // example.cpp #include "stdafx.h" extern "C" __declspec(dllexport) unsigned char* style_transfer(unsigned char* image, int width, int height) { // 将 image 进行样式换 // ... // 返回样式换后的图像数据 return transformed_image; } ``` C# 代码: ```csharp using System; using System.Runtime.InteropServices; class Program { [DllImport("example.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr style_transfer(IntPtr image, int width, int height); static void Main(string[] args) { // 加载图像数据 byte[] image_data = LoadImageData("test.jpg"); // 将 byte[] 换为 IntPtr IntPtr image_ptr = Marshal.AllocHGlobal(image_data.Length); Marshal.Copy(image_data, 0, image_ptr, image_data.Length); // 调用 C++ DLL 中的函数 IntPtr transformed_image_ptr = style_transfer(image_ptr, width, height); // 将 IntPtr 换为 byte[] byte[] transformed_image_data = new byte[width * height * 3]; Marshal.Copy(transformed_image_ptr, transformed_image_data, 0, transformed_image_data.Length); // 释放内存 Marshal.FreeHGlobal(image_ptr); Marshal.FreeHGlobal(transformed_image_ptr); } static byte[] LoadImageData(string filename) { // 读取图像数据 // ... return image_data; } } ``` 在上面的示例中,我们首先在 C++ DLL 中定义了一个名为 style_transfer 的函数,并使用 __declspec(dllexport) 修饰符导出。然后我们在 C# 中使用 DllImport 属性指定了 example.dll 的名称和 style_transfer 函数的签名。在 Main 函数中,我们首先加载图像数据,并将其换为 IntPtr 类型。然后我们调用 style_transfer 函数,并将图像数据的指针作为参数传递给该函数。最后,我们将返回的图像数据换为 byte[] 类型,并释放内存。 需要注意的是,在使用 C++ DLL 时,需要注意函数的调用约定。C++ 默认使用的是 __cdecl 调用约定,而 C# 默认使用的是 __stdcall 调用约定。因此,在使用 C++ DLL 时,需要使用 CallingConvention 属性指定函数的调用约定,以免出现调用错误的情况。另外,在调用函数时,需要将 byte[] 换为 IntPtr 类型,并在使用完后释放内存。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值