从托管 class 复制到本机结构
copy from managed class to native struct
我需要从托管 classes 中填充本机结构。以下技术(1. 将托管数据复制到托管字节数组,2. 使用 memcopy 填充本机结构)我发现这是一个常见的解决方案。
我假设以下代码不起作用的原因是我使用托管 classes 而不是托管结构。管理 classes 是我项目的要求。我可以使用托管 classes 使此代码工作,还是必须切换到托管结构?
这是 c# 管理的 class:
[StructLayout(LayoutKind.Sequential)]
public class man_s
{
public man_s()
{
// (do something which i can't do in a struct!)
}
// should go into a one-byte native bool
[MarshalAs(UnmanagedType.I1)]
public bool flag1;
public Int32 a;
public Int32 b;
};
...本机 cpp 结构:
struct nat_s
{
public:
bool flag1;
__int32 a;
__int32 b;
};
...应该将托管数据复制到本机结构的代码:
// setup some managed data
man_s^ mng = man_s();
mng->flag1 = true;
mng->a = 10;
mng->b = 20;
nat_s nat;
int s = sizeof(nat);
// size check is ok!
System::Diagnostics::Debug::Assert(sizeof(nat) == System::Runtime::InteropServices::Marshal::SizeOf(mng));
// copy into managed byte array
array<byte>^ byteArray = gcnew array<byte>(s);
System::Runtime::InteropServices::Marshal::Copy(IntPtr((void*)(&mng)), byteArray, 0, s);
// this doesn't bring up the expected results
pin_ptr<byte> start = &byteArray[0];
memcpy(&nat, start, s);
// does not work either
System::Runtime::InteropServices::Marshal::Copy(byteArray, 0, IntPtr((void*)(&nat)), s);enter code here
没有。 AFAIK 你不能那样做。您对托管 ref class
的内存布局一无所知。您可以在 class 中分配一个内部 value type
。您可以固定它并将其作为一个整体复制。
另外我不明白你的代码。您使用 Marshal::Copy 复制托管内存。您在将托管 class 转换为本机指针时执行此操作。比起将其复制到托管内存并将该托管内存再次复制到本机内存!为什么呢?如果你有一个针指针作为本地指针。
Marshal.Copy
is for copying data between managed arrays and unmanaged arrays. That's not what you have here: You have a managed object, and an unmnaged struct. For that, you want the PtrToStructure
and StructureToPtr
方法。这些方法的目标是在托管对象和某种非托管内存之间进行复制。
// Despite the name, man_s is a managed class, not a managed struct.
// This means it gets the ^ (which you had correct),
// but it also means it gets gcnew (which you were missing).
man_s^ mng = gcnew man_s();
nat_s nat;
// You had this code is correct.
Debug::Assert(sizeof(nat) == Marshal::SizeOf(mng));
// StructureToPtr copies to unmanaged memory.
// An unmanaged array (i.e., allocated with `malloc` or `new byte[]`)
// would work, but a pointer to the unmanaged struct will also work just fine.
// The `false` means "Don't destroy the object that's already at the destination",
// which I believe does not apply here.
Marshal::StructureToPtr(mng, &nat, false);
// You can go the other way as well.
Marshal::PtrToStructure(&nat, mng);
// or
man_s = Marshal::PtrToStructure<man_s>(&nat);
注意:我现在不在编译器上。您可能需要将 &nat
转换为 IntPtr
.
我需要从托管 classes 中填充本机结构。以下技术(1. 将托管数据复制到托管字节数组,2. 使用 memcopy 填充本机结构)我发现这是一个常见的解决方案。 我假设以下代码不起作用的原因是我使用托管 classes 而不是托管结构。管理 classes 是我项目的要求。我可以使用托管 classes 使此代码工作,还是必须切换到托管结构?
这是 c# 管理的 class:
[StructLayout(LayoutKind.Sequential)]
public class man_s
{
public man_s()
{
// (do something which i can't do in a struct!)
}
// should go into a one-byte native bool
[MarshalAs(UnmanagedType.I1)]
public bool flag1;
public Int32 a;
public Int32 b;
};
...本机 cpp 结构:
struct nat_s
{
public:
bool flag1;
__int32 a;
__int32 b;
};
...应该将托管数据复制到本机结构的代码:
// setup some managed data
man_s^ mng = man_s();
mng->flag1 = true;
mng->a = 10;
mng->b = 20;
nat_s nat;
int s = sizeof(nat);
// size check is ok!
System::Diagnostics::Debug::Assert(sizeof(nat) == System::Runtime::InteropServices::Marshal::SizeOf(mng));
// copy into managed byte array
array<byte>^ byteArray = gcnew array<byte>(s);
System::Runtime::InteropServices::Marshal::Copy(IntPtr((void*)(&mng)), byteArray, 0, s);
// this doesn't bring up the expected results
pin_ptr<byte> start = &byteArray[0];
memcpy(&nat, start, s);
// does not work either
System::Runtime::InteropServices::Marshal::Copy(byteArray, 0, IntPtr((void*)(&nat)), s);enter code here
没有。 AFAIK 你不能那样做。您对托管 ref class
的内存布局一无所知。您可以在 class 中分配一个内部 value type
。您可以固定它并将其作为一个整体复制。
另外我不明白你的代码。您使用 Marshal::Copy 复制托管内存。您在将托管 class 转换为本机指针时执行此操作。比起将其复制到托管内存并将该托管内存再次复制到本机内存!为什么呢?如果你有一个针指针作为本地指针。
Marshal.Copy
is for copying data between managed arrays and unmanaged arrays. That's not what you have here: You have a managed object, and an unmnaged struct. For that, you want the PtrToStructure
and StructureToPtr
方法。这些方法的目标是在托管对象和某种非托管内存之间进行复制。
// Despite the name, man_s is a managed class, not a managed struct.
// This means it gets the ^ (which you had correct),
// but it also means it gets gcnew (which you were missing).
man_s^ mng = gcnew man_s();
nat_s nat;
// You had this code is correct.
Debug::Assert(sizeof(nat) == Marshal::SizeOf(mng));
// StructureToPtr copies to unmanaged memory.
// An unmanaged array (i.e., allocated with `malloc` or `new byte[]`)
// would work, but a pointer to the unmanaged struct will also work just fine.
// The `false` means "Don't destroy the object that's already at the destination",
// which I believe does not apply here.
Marshal::StructureToPtr(mng, &nat, false);
// You can go the other way as well.
Marshal::PtrToStructure(&nat, mng);
// or
man_s = Marshal::PtrToStructure<man_s>(&nat);
注意:我现在不在编译器上。您可能需要将 &nat
转换为 IntPtr
.