2013-09-14 2 views
3

Я пытаюсь сопоставить (довольно архаичное) строковое сообщение C++ в C# struct для обработки в каком-то новом программном обеспечении. Проблема, с которой я сталкиваюсь, заключается в том, что при сопоставлении строкового сообщения C++ в структуру C# я теряю символы (предположительно добавляя \ 0).Проблемы с struct mapping в C# для строк

данных

сообщение мне нужно процесс выглядит следующим образом: «91000222201»

Where: "91" is one value 
     "0002" is the next value 
     "222" is the third value 
     "01" is the final value 

Первая структура макета я попытался было это:

[StructLayout(LayoutKind.Sequential, Size = 11, CharSet = CharSet.Ansi), Serializable] 
public struct HeaderPacketStruct 
{ 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 2)] 
    public string Value1; 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 4)] 
    public string Value2; 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 3)] 
    public string Value3; 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 2)] 
    public string Value4; 
} 

Он обработал строку ... но в результате следующие значения:

HeaderPacketStruct.Value1 = "9" 
HeaderPacketStruct.Value1 = "000" 
HeaderPacketStruct.Value1 = "22" 
HeaderPacketStruct.Value1 = "0" 

Когда я столкнулся с SizeConst по каждой из строк на +1 (до ac вещная ссуда для «\ 0») он начал падать символы:

HeaderPacketStruct.Value1 = "91" 
HeaderPacketStruct.Value1 = "0022" 
HeaderPacketStruct.Value1 = "01" 
HeaderPacketStruct.Value1 = "" 

Похоже, что UnmanagedType.ByValTStr предполагает, что есть «\ 0» в конце строки. Есть ли способ обойти это?

Как в стороне, мне удалось заставить его работать с char [] в приведенной ниже структуре. Однако с этой структурой работать гораздо сложнее, потому что каждое из значений - это char [], а не строка (внутри структуры). Было бы очень больно переназначать char [] в строки для всей обработки.

StructLayout(LayoutKind.Sequential, Size = 11, CharSet = CharSet.Ansi), Serializable] 
public struct HeaderPacketStruct 
{ 
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 2)] 
    public char[] Value1; 
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)] 
    public char[] Value2; 
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3)] 
    public char[] Value3; 
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 2)] 
    public char[] Value4; 
} 
+0

Не было бы намного проще отобразить его на одну строку/полукокса [] поле и разобрать его с некоторыми свойствами только для чтения ? –

+0

В этом интерфейсе есть порядка 40 сообщений, и большинство из них - 70 + полей. Я думаю, что было бы намного проще и удобнее иметь выделенные структуры, в которых я могу сопоставить строки, чем синтаксический анализ каждого поля сообщения по полю. – typhoid

+0

ОК, это много. Но так же поддерживается 40 из этих структур компоновки. И последний, с char [], является прямым переводом того, что у вас есть в качестве входных данных. Я не думаю, что Маршал может много постобработки. Не его работа. –

ответ

2

Marshaling in .NET всегда багги. Маршалинг строк - двойная багги!

Я сделал несколько тестов, и ByValTStr ожидает, что последний символ будет '\0', поэтому он читает его и игнорирует (но проблема в том, что он читает его!). Вы не можете даже обмануть, используя LayoutKind.Explicit, потому что он взорвется с ошибкой, что два поля перекрываются.

Что вы можете сделать:

[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 2)] 
private char[] value1; 

public string Value1 
{ 
    get { return new string(this.value1); } 
    set { this.value1 = value.ToCharArray(); } 
} 

Это работает правильно.

+0

Ультимативно это то, что я сделал ... потребовалось некоторое время, чтобы написать все геттеры/сеттеры ... но он работает как чемпион. – typhoid

0

Просто добавьте правильно FieldOffsetAttribute s к случаю, когда вы добавили +1 в SizeConst. А также обратите внимание, что размер "91000222201" строки равна 12, а не 11. Попробуйте это:

[StructLayout(LayoutKind.Sequential, Size = 12, CharSet = CharSet.Ansi), Serializable] 
public struct HeaderPacketStruct 
{ 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 3), FieldOffset(0)] 
    public string Value1; 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 5), FieldOffset(2)] 
    public string Value2; 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 4), FieldOffset(6)] 
    public string Value3; 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 3), FieldOffset(9)] 
    public string Value4; 
} 
+0

Вы протестировали его? Сначала вам нужно 'LayoutKind.Explicit', Second I get' TypeLoadException', потому что поля перекрываются. – xanatos

+0

Нет, я не проверял. Я предложил ему работать. Если это не так, я вижу только один путь - то, как вы предложили. –

Смежные вопросы