I have an unmanaged static library (.dll) written on C++:
我有一个非托管静态库(.dll)写在c++:
// This is a personal academic project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include "program.h"
struct MyData
{
int32_t index;
char* name;
//uint8_t* data;
};
extern "C" {
__declspec(dllexport) MyData* GetMyData()
{
MyData* ms = new MyData();
ms->index = 5;
ms->name = "Happy string";
//ms->data = new uint8_t[5] { 4, 8, 16, 32, 64 };
return ms;
}
}
The 'GetMyData' method returns pointer to 'MyData' object.
“GetMyData”方法返回指向“MyData”对象的指针。
I imported this library into C# projeсt using 'PInvoke' and called the 'GetMyData' method.
我这个库导入到c# projeсt使用段的PInvoke”,称为“GetMyData”方法。
// This is a personal academic project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit)]
public class MyData
{
[FieldOffset(0)]
public Int32 index;
[FieldOffset(4)]
public String name;
//[FieldOffset(8)]
//public Byte[] data;
};
class Program
{
[DllImport("TestCpp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetMyData();
public static void Main(string[] args)
{
// Call 'GetMyData' method and get structure from pointer using marshaling.
var ptr = GetMyData();
var ms = Marshal.PtrToStructure<MyData>(ptr);
// Print my data into console
var str = ms.index.ToString();
str += ", " + ms.name;
//str += ", [" + string.Join(", ", ms.data) + "]";
Console.WriteLine(str);
Console.ReadKey();
}
}
This code works fine, but if I uncomment the using of 'data' member of 'MyData' type (in C++ and C# code), I will get exception in C# code on this line:
这段代码运行良好,但是如果我取消使用“MyData”类型的“data”成员(在c++和c#代码中),我将在这一行的c#代码中获得异常:
var ms = Marshal.PtrToStructure(ptr);
var = Marshal.PtrToStructure女士(ptr);
Error: System.Runtime.InteropServices.SafeArrayTypeMismatchException:
'Mismatch has occurred between the runtime type of the array and the sub type recorded in the metadata.'错误:System.Runtime.InteropServices。SafeArrayTypeMismatchException:“数组的运行时类型与元数据中记录的子类型之间发生了不匹配。”
As I understand the offset argument in the 'FieldOffset' attribute - it's a shift in bytes in unmanaged memory during convert unmanaged C++ object to managed C# object.
正如我所理解的“FieldOffset”属性中的偏移量参数——它是在将非托管c++对象转换为托管c#对象时,在非托管内存中的字节移位。
Field 'index' has 4 bytes size because it's 32-bit type.
字段'index'有4字节大小,因为它是32位类型。
Field 'name' is pointer to char array. For 32-bit architecture it's also 32-bit number (4 bytes).
字段“name”是指向char数组的指针。对于32位架构,它也是32位数字(4字节)。
Which offset in 'FieldOffset' attribute i need to use for 'data' field?
在“FieldOffset”属性中,我需要使用哪个偏移量来“数据”字段?
1 个解决方案
#1
3
You can't do it easily... As suggested by Ðаn do it manually or
你不可能轻易做到……所显示Ðаn手动或
[FieldOffset(8)]
public IntPtr _data;
public byte[] GetData()
{
// YOU MUST FREE _data C-side! You can't use
// C++ delete C#-side
var bytes = new byte[5];
Marshal.Copy(_data, bytes, 0, bytes.Length);
return bytes;
}
There is another (little) problem here: I'm against using LayoutKind.Explicit
unless you really need it. Start with LayoutKind.Sequential
and see if it is enough. Using LayoutKind.Sequential
you'll be more ready to switch from 32 to 64 bits, because the struct will be stretched for the size of the pointers.
这里还有一个(小)问题:我反对使用LayoutKind。明确,除非你真的需要它。从LayoutKind开始。然后看看是否足够。使用LayoutKind。接下来,您将更容易从32位切换到64位,因为结构体将根据指针的大小进行拉伸。
#1
3
You can't do it easily... As suggested by Ðаn do it manually or
你不可能轻易做到……所显示Ðаn手动或
[FieldOffset(8)]
public IntPtr _data;
public byte[] GetData()
{
// YOU MUST FREE _data C-side! You can't use
// C++ delete C#-side
var bytes = new byte[5];
Marshal.Copy(_data, bytes, 0, bytes.Length);
return bytes;
}
There is another (little) problem here: I'm against using LayoutKind.Explicit
unless you really need it. Start with LayoutKind.Sequential
and see if it is enough. Using LayoutKind.Sequential
you'll be more ready to switch from 32 to 64 bits, because the struct will be stretched for the size of the pointers.
这里还有一个(小)问题:我反对使用LayoutKind。明确,除非你真的需要它。从LayoutKind开始。然后看看是否足够。使用LayoutKind。接下来,您将更容易从32位切换到64位,因为结构体将根据指针的大小进行拉伸。