views:

374

answers:

3

Hello,

I have a TCP Client,which puts a packet in a structure

using System.Runtime.InteropServices;

[StructLayoutAttribute(LayoutKind.Sequential)]
public struct tPacket_5000_E
{
    public Int16 size;
    public Int16 opcode;
    public byte securityCount;
    public byte securityCRC;
    public byte flag;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.I1)]
    public byte[] blowfish;
    public UInt32 seedCount;
    public UInt32 seedCRC;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 5, ArraySubType = UnmanagedType.I1)]
    public UInt32[] seedsecurity;
}

The code I use to put the packet in the structure is:

tPacket_5000_E packet = new tPacket_5000_E();
GCHandle pin = GCHandle.Alloc(data, GCHandleType.Pinned);
packet = (tPacket_5000_E)Marshal.PtrToStructure(pin.AddrOfPinnedObject(), typeof(tPacket_5000_E));
pin.Free();

Now,before i continue I must tell you that I'm translating this project from C++ to C#.

This is the problem:

The last 3 members of tPacket_5000_E are Int32(i tried UInt32 too),which is DWORD in C++. The values before those three members,which are NOT Int32,are equal to those in C++.(I inject same packet in both C++ and C# project).

However,those three members have different values.

in C++ the values are(correct):

  1. seedCount:0x00000079
  2. seedCRC:0x000000d1
  3. SeedSecurity:
  4. -[0]:0x548ac099
  5. -[1]:0x03c4d378
  6. -[2]:0x292e9eab
  7. -[3]:0x4eee5ee3
  8. -[4]:0x1071206e

in C# the values are(incorrect):

  1. seedCount:0xd1000000
  2. seedCRC:0x99000000
  3. SeedSecurity:
  4. -[0]: 0x78548ac0
  5. -[1]: 0xab03c4d3
  6. -[2]: 0xe3292e9e
  7. -[3]: 0x6e4eee5e
  8. -[4]: 0x00107120

The packet in both applications is equal

byte[] data = new byte[] {
0x25, 0x00, 0x00, 0x50, 0x00, 0x00, 0x0E, 0x10, 
0xCE, 0xEF, 0x47, 0xDA, 0xC3, 0xFE, 0xFF, 0x79, 
0x00, 0x00, 0x00, 0xD1, 0x00, 0x00, 0x00, 0x99, 
0xC0, 0x8A, 0x54, 0x78, 0xD3, 0xC4, 0x03, 0xAB, 
0x9E, 0x2E, 0x29, 0xE3, 0x5E, 0xEE, 0x4E, 0x6E, 
0x20, 0x71, 0x10};

Click here for further information

Why the last three members in the struct are different and how to fix them?

Thanks in advance!

+9  A: 

I'd expect that the root of your problem is that the three byte values

public byte securityCount;
public byte securityCRC;
public byte flag;

cause the next 32-bit values not to be word-aligned, and your two sets of code are adding (or not adding) internal padding differently.

I expect that the different packings look something like this:

C++                                   C#
================================      ================================
[size          ][opcode        ]      [size          ][opcode        ]
[secCnt][secCrc][flag  ][blow0 ]      [secCnt][secCrc][flag  ][blow0 ]
[blow1 ][blow2 ][blow3 ][blow4 ]      [blow1 ][blow2 ][blow3 ][blow4 ]
[blow5 ][blow6 ][blow7 ][seedCou      [blow5 ][blow6 ][blow7 ]..PAD...
nt                     ][seedCRC      [seedCount                     ]
                       ][seedSec      [seedCRC                       ]
urity0                 ][seedSec      [seedSecurity0                 ]
urity1                 ][seedSec      [seedSecurity1                 ]
urity2                 ][seedSec      [seedSecurity2                 ]
urity3                 ][seedSec      [seedSecurity3                 ]
urity4                 ]              [seedSecurity4                 ]

... with C# inserting a byte of padding which causes later values to be one byte off.

You can try using

[StructLayout(LayoutKind.Sequential,Pack=1)]

before your struct definition, which should use the minimum amount of space possible.

Mastering Structs in C# has some good information on how/why this happens.

Daniel LeCheminant
@Daniel L,Can you suggest a solution to fix this?
John
@Daniel L,Thanks for your edit - it works now! :)
John
+1  A: 

I suspect that Daniel L is on the right track in his answer.

I would try adding a 4th byte after the flag. My guess is that your C++ compiler is aligning the values on word boundaries. That would "align" the C# version as well.

Reed Copsey
I just added a new byte under the flag(public byte notneeded;) the result:The value that should be placed at blowfish[0](the next member) is moved to the value i added and the the last three values are still the same.
John
Reed Copsey,you solution didn't work,but i highly appreciate your help,so i digged up your answer as well!I figured it out,thanks to Daniel L.Thank you guys for the fast support.
John
A: 

Why are you "translating this project from C++ to C#."? With C++/CLI you can continue to use your existing C++ code pretty much as-is, while still calling it from C#.

Dan