StructureToPtr 未将本机结构中的原始类型字段正确复制到引用结构
StructureToPtr not copying primitive type fields in native struct to ref struct correctly
我有一个本地结构,(它非常大所以我必须使用新关键字来实例化,下面只是为了制作一个 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 结构来镜像它,这也使用了如下两个枚举,
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
将native object复制到managed object,用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
没有复制成功?我已经为此奋斗了一个星期,欢迎任何帮助。非常感谢。
Marshal::StructureToPtr() 只有在托管结构和本机结构 完全 匹配时才能正常工作。到目前为止,验证这一点的最简单方法是检查结构的大小,它们必须相同。所以将此代码添加到您的程序中:
auto nlen = sizeof(NativeStruct);
auto mlen = Marshal::SizeOf(ManagedStruct::typeid);
System::Diagnostics::Debug::Assert(nlen == mlen);
轰隆隆。本机结构占用 96 个字节,托管结构占用 104 个字节。后果很严重,你破坏了内存,这比 LimitPrice 成员值被复制到错误的偏移量有更多不愉快的副作用。
解决此问题的两种基本方法。您可以简单地用唯一值填充 all 托管结构成员,并检查具有错误值的本机结构的第一个成员。前面那个成员错了。继续前进,直到你不再得到 kaboom。或者您可以编写在本机结构成员上使用 offsetof() 的代码,并将它们与 Marshal::OffsetOf().
进行比较
只是为了省去您的麻烦,问题是 enum 声明。它们在本机结构中的大小为 1 个字节,但托管版本需要 4 个字节。修复:
public enum struct EnumOrderPriceTypeType : Byte
和
public enum struct EnumDirectionType : Byte
请注意添加的 : Byte
以强制枚举占用 1 个字节的存储空间。应该注意的是,一个一个地复制成员而不是使用 Marshal::StructureToPtr() 更快,并且可以为您节省一周的麻烦。
我有一个本地结构,(它非常大所以我必须使用新关键字来实例化,下面只是为了制作一个 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 结构来镜像它,这也使用了如下两个枚举,
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
将native object复制到managed object,用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
没有复制成功?我已经为此奋斗了一个星期,欢迎任何帮助。非常感谢。
Marshal::StructureToPtr() 只有在托管结构和本机结构 完全 匹配时才能正常工作。到目前为止,验证这一点的最简单方法是检查结构的大小,它们必须相同。所以将此代码添加到您的程序中:
auto nlen = sizeof(NativeStruct);
auto mlen = Marshal::SizeOf(ManagedStruct::typeid);
System::Diagnostics::Debug::Assert(nlen == mlen);
轰隆隆。本机结构占用 96 个字节,托管结构占用 104 个字节。后果很严重,你破坏了内存,这比 LimitPrice 成员值被复制到错误的偏移量有更多不愉快的副作用。
解决此问题的两种基本方法。您可以简单地用唯一值填充 all 托管结构成员,并检查具有错误值的本机结构的第一个成员。前面那个成员错了。继续前进,直到你不再得到 kaboom。或者您可以编写在本机结构成员上使用 offsetof() 的代码,并将它们与 Marshal::OffsetOf().
进行比较只是为了省去您的麻烦,问题是 enum 声明。它们在本机结构中的大小为 1 个字节,但托管版本需要 4 个字节。修复:
public enum struct EnumOrderPriceTypeType : Byte
和
public enum struct EnumDirectionType : Byte
请注意添加的 : Byte
以强制枚举占用 1 个字节的存储空间。应该注意的是,一个一个地复制成员而不是使用 Marshal::StructureToPtr() 更快,并且可以为您节省一周的麻烦。