项目场景:
碰到一个小伙伴,c#调用c++ dll接收char*,不知道如何进行C++DLL的封装,以及C#的调用;
下面分享一种比较好的做法;实际上,不仅是char*,任何数据都可以返回;
问题描述
在C++中,可以使用char *GetValue();
直接返回一个字符串;但是在C#中想要获取C++封装的DLL中的数据,则一般需要进行封装;
否则会产生一些内存问题;
原因分析:
C#对象属于托管堆,有垃圾回收机制管理内存。C++的内存是非托管的;如果封装和调用时候,稍不注意,两者就会因为机制的问题,产生内存异常的问题;
解决方案:
分享一种封装方法
- C++的DLL里面这样写
#pragma once
//C++修改代码如下:
typedef struct _ComMonDevices
{
char data[1024];
}ComMonDevices;
extern "C" __declspec(dllexport) void __stdcall getComMonDevices(ComMonDevices* lpDeviceInfo);
- C++具体实现:
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <string>
#include "export.h"
using namespace std;
//C++修改代码如下:
string getDevices()
{
return string("hello world");
}
void __stdcall getComMonDevices(ComMonDevices* lpDeviceInfo)
{
string com = getDevices(); //此处替换你自己的代码获取信息
if (lpDeviceInfo)
{
memset(lpDeviceInfo, 0, sizeof(ComMonDevices));
strcpy_s(lpDeviceInfo->data, com.c_str()); //注意一下comd的长度,需小于1024
}
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
- C#的主程序里面这样写
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace TestDLL1
{
internal class Program
{
//C#修改代码如下:
public struct ComMonDevices
{
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string strData; //数据区域,长度为1024
}
[DllImport("Dll1.dll", CallingConvention =CallingConvention.StdCall)]
public static extern void getComMonDevices(ref ComMonDevices lpDeviceInfo);
static void Main(string[] args)
{
ComMonDevices DeviceInfo = new ComMonDevices();
//获取信息
getComMonDevices(ref DeviceInfo);
string steTemp = DeviceInfo.strData;
Console.WriteLine(steTemp);
while (true) { }
}
}
}
-
最终的运行效果
-
想要源码工程的小伙伴,请看下面:
链接:链接: https://pan.baidu.com/s/1mTlCqTFuLAAKqFeDAHlrGw?pwd=pvtm 提取码: pvtm 复制这段内容后打开百度网盘手机App,操作更方便哦