根据我的另一个问题here,由于这个社区,我已经能够将C ++中的字符串共享到C#。
但是,我需要达到一个级别,我需要使用内存映射从C ++到C#共享链式结构。
在示例场景中:
我的C ++结构:
struct STRUCT_2
{
char Name[260];
};
struct STRUCT_1
{
void Init()
{
this->Count = 0;
this->Index = 0;
}
DWORD Count;
DWORD Index;
STRUCT_2 Table[256];
};
我试图将其“转移”到C#:
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public unsafe struct STRUCT_2
{
[FieldOffset(0)]
public fixed char Name[260];
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public unsafe struct STRUCT_1
{
void Init()
{
this.Count = 0;
this.Index = 0;
}
[FieldOffset(0)]
public uint Count;
[FieldOffset(0)]
public uint Index;
[FieldOffset(100)]
[MarshalAs(UnmanagedType.LPStruct, SizeConst = 256)]
public STRUCT_2 Table;
}
这部分有效,基本上我可以看到来自计数和索引的值,但是我无法看到值,甚至无法在 STRUCT_2 中获取它们
我试图改变:
public STRUCT_2[] Table;
然后编译器告诉我:
“指定的Type必须是不包含引用的结构。”
所以我的问题是,如何在C#中使用 MemoryMappedFile 读取结构中的结构?
非常欢迎建议,想法或例子。
更新
在C#中填写可测试代码:
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public unsafe struct STRUCT_2
{
[FieldOffset(0)]
public fixed byte Name[260];
// Fix thanks to Ben Voigt
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public unsafe struct STRUCT_1
{
void Init()
{
this.Count = 0;
this.Index = 0;
}
[FieldOffset(0)]
public uint Count;
[FieldOffset(0)]
public uint Index;
[FieldOffset(100)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public STRUCT_2[] Table;
}
static void Main(string[] args)
{
MemoryMappedFileSecurity CustomSecurity = new MemoryMappedFileSecurity();
CustomSecurity.AddAccessRule(new System.Security.AccessControl.AccessRule<MemoryMappedFileRights>("everyone", MemoryMappedFileRights.FullControl, System.Security.AccessControl.AccessControlType.Allow));
var mappedFile = MemoryMappedFile.CreateOrOpen("Local\\STRUCT_MAPPING", 1024, MemoryMappedFileAccess.ReadWriteExecute, MemoryMappedFileOptions.None, CustomSecurity, System.IO.HandleInheritability.Inheritable);
using (var accessor = mappedFile.CreateViewAccessor())
{
STRUCT_1 data;
accessor.Read<STRUCT_1>(0, out data); // ERROR !
//The specified Type must be a struct containing no references.
Console.WriteLine(data.Count);
Console.WriteLine(data.Index);
}
}
答案 0 :(得分:1)
检查一下。
在Visual Studio 2017上测试,Windows 7 x64。
写入和读取数据可以找到。
这对我来说也很好。
花点时间。
一帆风顺!
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct STRUCT_2
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)]
public byte[] Name;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 4)]
public struct STRUCT_1
{
void Init()
{
this.Count = 0;
this.Index = 0;
}
public uint Count;
public uint Index;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] //! array size of 10.
public STRUCT_2 [] Table;
}
static void test3()
{
MemoryMappedFileSecurity CustomSecurity = new MemoryMappedFileSecurity();
CustomSecurity.AddAccessRule(new System.Security.AccessControl.AccessRule<MemoryMappedFileRights>
( "everyone"
, MemoryMappedFileRights.FullControl
, System.Security.AccessControl.AccessControlType.Allow));
using (var mappedFile = MemoryMappedFile.CreateOrOpen("Local\\STRUCT_MAPPING"
, 10 * 1024
, MemoryMappedFileAccess.ReadWriteExecute
, MemoryMappedFileOptions.None
, CustomSecurity
, System.IO.HandleInheritability.Inheritable))
{
using (var accessor = mappedFile.CreateViewAccessor())
{
//! test setting.
int table_count = 5;
//! write data.
STRUCT_1 write_data;
write_data.Index = 1;
write_data.Count = 2;
write_data.Table = new STRUCT_2[10];
for (int i = 0; i < 10; i++)
{
write_data.Table[i].Name = new byte[260];
write_data.Table[i].Name[0] = (byte)i;
}
//! ----------------------------
// Get size of struct
int size = Marshal.SizeOf(typeof(STRUCT_1));
byte[] data = new byte[size];
// Initialize unmanaged memory.
IntPtr p = Marshal.AllocHGlobal(size);
// Copy struct to unmanaged memory.
Marshal.StructureToPtr(write_data, p, false);
// Copy from unmanaged memory to byte array.
Marshal.Copy(p, data, 0, size);
// Write to memory mapped file.
accessor.WriteArray<byte>(0, data, 0, data.Length);
// Free unmanaged memory.
Marshal.FreeHGlobal(p);
p = IntPtr.Zero;
//! ----------------------------------------------
STRUCT_1 read_data;
size = Marshal.SizeOf(typeof(STRUCT_1));
data = new byte[size];
// Initialize unmanaged memory.
p = Marshal.AllocHGlobal(size);
// Read from memory mapped file.
accessor.ReadArray<byte>(0, data, 0, data.Length);
// Copy from byte array to unmanaged memory.
Marshal.Copy(data, 0, p, size);
// Copy unmanaged memory to struct.
read_data = (STRUCT_1)Marshal.PtrToStructure(p, typeof(STRUCT_1));
// Free unmanaged memory.
Marshal.FreeHGlobal(p);
p = IntPtr.Zero;
Console.WriteLine(read_data.Index);
Console.WriteLine(read_data.Count);
}
}
}