C++ cli StructureToPtr未将本机结构中的基元类型字段正确复制到ref结构

C++ cli StructureToPtr未将本机结构中的基元类型字段正确复制到ref结构,c++-cli,C++ Cli,我有一个本机结构(它相当大,所以我必须使用新的关键字来实例化,下面只是做一个MCVE,我不能更改该结构,因为它是作为外部依赖项提供的) 我想将NativeStruct转换为托管对象,所以我定义了一个ref struct来镜像它,这也使用了两个枚举,如下所示 public enum struct EnumOrderPriceTypeType { AnyPrice = (Byte)'1', LimitPrice = (Byte)'2', BestPrice = (Byte)'

我有一个本机结构(它相当大,所以我必须使用新的关键字来实例化,下面只是做一个MCVE,我不能更改该结构,因为它是作为外部依赖项提供的)

我想将NativeStruct转换为托管对象,所以我定义了一个ref struct来镜像它,这也使用了两个枚举,如下所示

public enum struct EnumOrderPriceTypeType
{
    AnyPrice = (Byte)'1',
    LimitPrice = (Byte)'2',
    BestPrice = (Byte)'3',
    LastPrice = (Byte)'4',
    LastPricePlusOneTicks = (Byte)'5',
    LastPricePlusTwoTicks = (Byte)'6',
    LastPricePlusThreeTicks = (Byte)'7',
    AskPrice1 = (Byte)'8',
    AskPrice1PlusOneTicks = (Byte)'9',
    AskPrice1PlusTwoTicks = (Byte)'A',
    AskPrice1PlusThreeTicks = (Byte)'B',
    BidPrice1 = (Byte)'C',
    BidPrice1PlusOneTicks = (Byte)'D',
    BidPrice1PlusTwoTicks = (Byte)'E',
    BidPrice1PlusThreeTicks = (Byte)'F'
};

public enum struct EnumDirectionType
{
    Buy = (Byte)'0',
    Sell = (Byte)'1'
};

[StructLayout(LayoutKind::Sequential)]
public ref struct ManagedStruct
{
    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 11)]
    String^ BrokerID;
    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 13)]
    String^ InvestorID;
    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 31)]
    String^ InstrumentID;
    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 13)]
    String^ OrderRef;
    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 16)]
    String^ UserID;
    EnumOrderPriceTypeType OrderPriceType;
    EnumDirectionType Direction;
    double LimitPrice;
};
然后我使用
StructureToPtr
将本机对象复制到托管对象,并使用
WriteLine
测试复制是否成功

NativeStruct *native = new NativeStruct();
ManagedStruct^ managed = gcnew ManagedStruct();
managed->LimitPrice = 95.5;
managed->BrokerID = "666666";
Marshal::StructureToPtr(managed, IntPtr(native), false);
int i;

for (i = 0; i < 11; i++)
    Console::Write(native->BrokerID[i]);
Console::WriteLine();
Console::WriteLine(native->LimitPrice);
Console::WriteLine(L"Hello ");
Console::ReadLine();
NativeStruct*native=new NativeStruct();
ManagedStruct^managed=gcnew ManagedStruct();
管理价格=95.5;
托管->BrokerID=“666666”;
封送:StructureToPtr(托管,IntPtr(本机),false);
int i;
对于(i=0;i<11;i++)
控制台::Write(本机->BrokerID[i]);
控制台::WriteLine();
控制台::WriteLine(本机->限价);
控制台:WriteLine(L“Hello”);
控制台::ReadLine();
我的问题是为什么
LimitPrice
没有成功复制?我已经为此奋斗了一周,欢迎任何帮助。非常感谢。

仅当托管结构和本机结构完全匹配时,Marshal::StructureToPtr()才能正常工作。到目前为止,验证这一点的最简单方法是检查结构的尺寸,它们必须相同。因此,请将此代码添加到您的程序中:

auto nlen = sizeof(NativeStruct);
auto mlen = Marshal::SizeOf(ManagedStruct::typeid);
System::Diagnostics::Debug::Assert(nlen == mlen);
卡布姆。本机结构需要96个字节,托管结构需要104个字节。后果是可怕的,你破坏了内存,这比LimitPrice成员值被复制到错误的偏移量有更多不愉快的副作用

解决这一问题的两种基本方法。您只需使用唯一的值填充所有托管结构成员,并检查本机结构中第一个值错误的成员。之前的成员是错误的。继续走,直到你再也找不到卡布姆为止。或者,您可以编写在本机结构成员上使用offsetof()的代码,并将它们与Marshal::offsetof()进行比较

为了省去您的麻烦,问题在于枚举声明。它们在本机结构中的大小为1字节,但托管版本的大小为4字节。修正:

  public enum struct EnumOrderPriceTypeType : Byte


注意添加了
:Byte
,以强制枚举占用1字节的存储空间。需要注意的是,一个接一个地复制成员而不是使用Marshal::StructureToPtr()会更快,并且会为您节省一周的麻烦。

您真是个救命稻草!!谢谢我已经学会了调试技巧。
  public enum struct EnumOrderPriceTypeType : Byte
  public enum struct EnumDirectionType : Byte