2016-03-20 26 views
1

我有一個本地結構,(這是非常大的,所以我不得不使用新的關鍵字來實例化,下面只是爲了使一個MCVE我不能改變結構因爲它被提供爲外部依賴性),StructureToPtr沒有複製原生結構中的原始類型字段到ref結構正確

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將本地對象複製到託管對象,並使用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不successfuly複製?我一直在爭取一週,任何幫助都會受到歡迎。非常感謝。

回答

2

Marshal :: StructureToPtr()只能在託管結構和本機結構匹配時才能正確工作。到目前爲止,驗證這個最簡單的方法是檢查結構的大小,它們必須是相同的。因此,將此代碼添加到您的程序中:

auto nlen = sizeof(NativeStruct); 
auto mlen = Marshal::SizeOf(ManagedStruct::typeid); 
System::Diagnostics::Debug::Assert(nlen == mlen); 

Kaboom。本地結構需要96個字節,而受管理的結構需要104個。結果是可怕的,你會損壞內存,並且比LimitPrice成員的值複製到錯誤的偏移量有更多不愉快的副作用。

兩個基本的方法來解決這個問題。您可以簡單地使用唯一值填充所有受管結構成員,並檢查具有錯誤值的本機結構的第一個成員。它之前的成員是錯誤的。繼續下去,直到你不再擁有kaboom。或者你可以編寫在本地結構成員上使用offsetof()的代碼,並將它們與Marshal :: OffsetOf()進行比較。

爲了節省您的麻煩,問題是枚舉聲明。它們在本機結構中的大小是1個字節,但管理版本需要4個字節。修復:

public enum struct EnumOrderPriceTypeType : Byte 

public enum struct EnumDirectionType : Byte 

注意添加: Byte迫使枚舉取1個字節存儲空間。應該指出的是,一個接一個地複製成員而不是使用Marshal :: StructureToPtr()會更快,並且會爲您節省一週的麻煩。

+0

你真的是一個救星!謝謝。我已經學會了調試技巧。 – tesla1060