存在的问题:
问题1:C++ 与 C# 同样定义的结构体在内存布局上有时并不一致;
问题2:C# 中引入了垃圾自动回收机制,其垃圾回收器可能会重新定位指针所指向的结构体变量。
解决方案:
问题1方案:强制指定 C++、C# 结构体的内存布局,使其一致(两者都固定为:结构体的成员按其声明时出现的顺序依次布局,结构体成员的内存对齐为1字节对齐);
为题2方案:C# 调用时将待传递的结构体转化为字节数组,并使用 fixed 语句将该字节数组固定住。
示例代码如下:
1、C++结构体定义:
#pragma pack(1)
struct Person
{
#define Count_FavoriteNumbers 6
int id;
float favoriteNumbers[Count_FavoriteNumbers];
};
#pragma pack() // #pragma pack(1) end
C++ 导出函数:
#define DllExport extern "C" __declspec(dllexport)
DllExport void __stdcall InitPersonInfo_DLL(Person* p_Person)
{
p_Person->id = 0;
for (int i = 1; i <= Count_FavoriteNumbers; i++)
{
p_Person->favoriteNumbers[i - 1] = 1.11 * i;
}
}
2、C# 结构体定义:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Person
{
public const int Count_FavoriteNumbers = 6;
public int id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Count_FavoriteNumbers, ArraySubType = UnmanagedType.U4)]
public float[] favoriteNumbers = new float[Count_FavoriteNumbers];
}
C# 调用(WPF窗体程序):
public partial class MainWindow : Window
{
[DllImport("MFCLibrary_ExportFunction.dll", EntryPoint = "InitPersonInfo_DLL")]
static extern unsafe void InitPersonInfo_DLL(byte* p_Person);
public unsafe void InitPersonInfo(ref Person person)
{
byte[] structBytes = StructToBytes(person);
fixed (byte* p_Person = &structBytes[0])
{
InitPersonInfo_DLL(p_Person);
person = (Person)BytesToStruct(structBytes, person.GetType());
}
public MainWindow()
{
InitializeComponent();
Person zhangSan = new Person();
InitPersonInfo(ref zhangSan);
}
#region // 结构体与 byte[] 互转
// Struct 转换为 byte[]
public static byte[] StructToBytes(object structure)
{
int size = Marshal.SizeOf(structure);
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(structure, buffer, false);
byte[] bytes = new byte[size];
Marshal.Copy(buffer, bytes, 0, size);
return bytes;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
// byte[] 转换为 Struct
public static object BytesToStruct(byte[] bytes, Type strcutType)
{
int size = Marshal.SizeOf(strcutType);
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.Copy(bytes, 0, buffer, size);
return Marshal.PtrToStructure(buffer, strcutType);
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
#endregion
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗