Reputation: 608
I am trying to read in a structure that was written to a file by a C++ program (I don't have the source code). I have been trying to read this structure into C# and marshal it so far without success.
The structure is basically a set of strings of fixed length, two-bytes per character. In C++, they can be declared as TCHAR[8].
The data on disk looks like as follows:
I have tried the following C# code that I know can successfully read in the values as a string:
public void ReadTwoStringsOfFixedLength()
{
string field1 = string.Empty;
string field2 = string.Empty;
FileReadString(handle, out field1, 16);
FileReadString(handle, out field2, 16);
}
public static void FileReadString(BinaryReader reader, out string outVal, int length)
{
var mem = new MemoryStream();
outVal = string.Empty;
byte b = 0;
for (int i = 0; i < length; i++)
{
b = reader.ReadByte();
if (b != 0) mem.WriteByte(b);
}
outVal = Encoding.GetEncoding(1252).GetString(mem.ToArray());
}
However, what I really would like to do is use c# structs, since this data is represented as a struct in C++ (and contains other fields which I have not depicted here).
I have tried various methods of attempting to marshal this data based on answers I have read on StackOverflow, but none have yielded the result I wanted. In most cases, either the string encoding was incorrect, I ended up with a memory exception or I ended up with only the first character in each field (probably due to null-termination?)
Here is my code:
void Main()
{
byte[] abBuffer = handle.ReadBytes(Marshal.SizeOf(typeof(MyStruct)));
//Access data
GCHandle pinnedPacket = GCHandle.Alloc(abBuffer, GCHandleType.Pinned);
var atTestStruct = (MyStruct)Marshal.PtrToStructure(pinnedPacket.AddrOfPinnedObject(), typeof(MyStruct));
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi), Serializable]
struct MyStruct
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
string Field1 // Resulting value = "F";
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
string Field2; // Resulting value = "F"
}
Note that I have also attempted to use CharSet.Unicode
, however the resulting strings are garbled.
Any help to fix the code would be much appreciated.
Upvotes: 0
Views: 749
Reputation: 310907
I think you need to set CharSet = CharSet.Unicode
on your StructLayout
.
46 00 69 00
in ASCII/ANSI is considered a single character and a null terminator. The documentation shows that CharSet.Unicode
is needed for two-byte characters, such as those you're showing.
The SizeConst
value must also be the number of characters, not bytes.
Upvotes: 1