0

I'm trying to get a string from memory using StrucLayout and FieldOffset

But I'm having a lot of trouble understanding how byte works.

Here is my code ATM :

[StructLayout(LayoutKind.Explicit)]
public unsafe struct InfoDetails
{
    [FieldOffset(0x14)]
    public fixed sbyte Name[50];

    public string getName
    {
        get
        {
            fixed (sbyte* namePtr = Name)
            {
                return new string(namePtr);
            }
        }
    }
}

This code returns : T. Expected result is TEZ.

Any advices on why I'm doing it wrong ? Thanks

Nashmár
  • 392
  • 1
  • 7
  • 22
Cesar
  • 453
  • 9
  • 21

3 Answers3

1

You seem to have a problem with string encoding. Consider the following test code:

unsafe
{
    InfoDetails d;
    var encoding = Encoding.Unicode;
    var stringBytes = encoding.GetBytes("TEZ");
    for(int i=0; i<stringBytes.Length; i++) d.Name[i] = (sbyte)stringBytes[i];
    Console.WriteLine(d.getName);
}

You will get indeed "T", but if you change the encoding to Encoding.ASCII you get "TEZ" as expected.

Solution: you need to know the encoding of the information beforehand, and generate the string accordingly. Looks like it's Unicode, so try this first:

fixed (sbyte* namePtr = Name)
{
  return new string(namePtr, 0, 50, Encoding.Unicode);
}
Konamiman
  • 49,681
  • 17
  • 108
  • 138
  • Hey, thanks for the answer, it's a lot better than what I had before but it gets me : "TEZ\0\0\0ꃀб\0\0\0\0\0\0\u0002\026\0\0\0\0䕀⚣\0" I've posted a solution that is working for now, I will try to improve it later ! – Cesar May 18 '18 at 07:44
  • That's weird. What are the exact bytes you are getting? – Konamiman May 18 '18 at 07:48
  • 2
    @Cesar that means your `Name[50]` declaration is not really correct. It assumes string is of fixed size of 50 bytes, but in this case string is much smaller, and the rest of those 50 bytes are not even all zeros but some garbage, which means they probably belong to something completely different. – Evk May 18 '18 at 07:51
1

You could change the signature to:

[FieldOffset(0x14)]
public fixed char Name[25];

public string getName
{
    get
    {
        fixed (char* namePtr = Name)
        {
            return new string(namePtr);
        }
    }
}

Note how I changed sbyte to char and I halved the size of the buffer (because sizeof(char) == 2)

Or you could even, more simply add a single cast to char*:

fixed (sbyte* namePtr = Name)
{
    return new string((char*)namePtr);
}

without changing anything else.

xanatos
  • 109,618
  • 12
  • 197
  • 280
  • Solution number one is giving "T". But solution number 2 is working perfectly and seems a lot better ! Thanks ! – Cesar May 18 '18 at 07:56
0

Thanks everybody for your answer, they helped me to get a working solution. I don't really know if it's the best one :

[StructLayout(LayoutKind.Explicit)]
    public unsafe struct InfoDetails
    {
        [FieldOffset(0x14)]
        public fixed byte Name[50];

        public string test
        {
            get
            {
                List<byte> clearBytes = new List<byte>();
                fixed (byte* namePtr = Name)
                {
                    for (int i = 0; i < 50; i++)
                    {
                        if (namePtr[i] == 0x0 && namePtr[i + 1] == 0x0)
                        {
                            break;
                        }
                        clearBytes.Add(namePtr[i]);
                    }
                    if (clearBytes.Count() % 2 != 0)
                    {
                        clearBytes.Add(0x00);
                    }
                    return Encoding.Unicode.GetString(clearBytes.ToArray());
                }
            }
        }

    }

Thanks a lot !

Cesar
  • 453
  • 9
  • 21
  • I think your solution is overcomplicated, plus manually dealing with string encodings is usually not a good idea. Isn't `new string(namePtr, 0, 50, Encoding.Unicode)` working for you? – Konamiman May 18 '18 at 07:42
  • @Konamiman You are compleetly right about the overcomplicated but your solution is leading to this : "TEZ\0\0\0ꃀб\0\0\0\0\0\0\u0002\026\0\0\0\0䕀⚣\0" – Cesar May 18 '18 at 07:47