我有一个原生结构,(它非常大,所以我必须使用新的关键字来实例化,下面只是为了制作一个MCVE我不能改变结构,因为它是作为外部依赖提供的),
struct NativeStruct
{
char BrokerID[11];
char InvestorID[13];
char InstrumentID[31];
char OrderRef[13];
char UserID[16];
char OrderPriceType;
char Direction;
double LimitPrice;
}
我想将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();
我的问题是为什么LimitPrice
没有被成功复制?我一直在与这场斗争一周,欢迎任何帮助。非常感谢。
答案 0 :(得分:2)
Marshal :: StructureToPtr()只有在托管和本机结构是完全匹配时才能正常工作。到目前为止,验证这一点的最简单方法是检查结构的大小,它们必须相同。所以将此代码添加到您的程序中:
Course.find(id).update_attributes...
KABOOM。本机结构需要96个字节,托管结构需要104个。结果是可怕的,你破坏了内存,并且比LimitPrice成员值被复制到错误的偏移量有更多令人不快的副作用。
解决这个问题的两种基本方法。您只需使用唯一值填充所有托管结构成员,并检查具有错误值的本机结构的第一个成员。之前的成员是错的。继续前进,直到你不再获得kaboom。或者,您可以编写在本机struct成员上使用offsetof()的代码,并将它们与Marshal :: OffsetOf()进行比较。
为了省去麻烦,问题是枚举声明。它们在本机结构中的大小是1个字节,但是托管版本需要4个字节。修正:
auto nlen = sizeof(NativeStruct);
auto mlen = Marshal::SizeOf(ManagedStruct::typeid);
System::Diagnostics::Debug::Assert(nlen == mlen);
和
public enum struct EnumOrderPriceTypeType : Byte
注意添加的 public enum struct EnumDirectionType : Byte
强制枚举占用1个字节的存储空间。应该注意的是,逐个复制成员而不是使用Marshal :: StructureToPtr()会更快,并且可以为您节省一周的麻烦。