从托管类复制到本机结构

时间:2016-12-20 08:43:12

标签: c# visual-c++ c++-cli

我需要从托管类填充本机结构。遵循技术(1.将托管数据复制到托管字节数组,2。使用memcopy填充本机结构)我发现这是一个常见的解决方案。 我假设以下代码不起作用的原因是我使用托管类而不是托管结构。托管类是我项目中的一项要求。我可以使用托管类使此代码工作,还是必须切换到托管结构?

这是c#托管类:

[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

2 个答案:

答案 0 :(得分:0)

没有。 AFAIK你做不到。您对托管ref class的内存布局一无所知。您可以在课程中分配内部value type。您可以将其固定并将其复制为整个块。

我也不明白你的代码。使用Marshal :: Copy复制托管内存。您可以将托管类转换为本机指针。比将其复制到托管内存并将此托管内存再次复制到本机内存!为什么呢?如果你有一个pin指针作为本机指针。

答案 1 :(得分:0)

Marshal.Copy用于在托管阵列和非托管阵列之间复制数据。这不是你在这里拥有的:你有一个托管对象和一个未经修饰的结构。为此,您需要PtrToStructureStructureToPtr方法。这些方法的目标是在托管对象和某种非托管内存之间进行复制。

// 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