Rozon, I had this exact same problem, and I was about to give up on the solution until I found this question here, and read Joe's response to it. Joe mentions the Marshal object to move data between regular MEMORY and a managed object... Here is what I did, and what worked like magic for me... If you haven't already figured this out, here is a whole break-down of what I did, and how I got it to work.. (Thank you Joe!)...
First, you must be able to create a managed instance of your structure. This shouldn't be too hard, it just means a lot of extra attributes on your structure.
For example, here's a data structure that holds some information about a server. Of course, the string sizes are not accurate, so make SURE your string sizes ARE!
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
struct TServerInformation {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
public string ComputerName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
public string HostName;
[MarshalAs(UnmanagedType.U4)]
public Int32 IPAddress;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)]
public string AdminName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public string WindowsDir;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
public string Domain;
};
Also, make CERTAIN you are using the correct Charset, in the case that it was compiled to use Unicode, you need to make sure the Charset reflects that.
Now, here's the cool part...
To get the SIZE of the struct, (and the size of the buffer you need to hold it), you need only to use:
byte[] buff = new byte[Marshal.SizeOf(pStruct)];
And, with that, you can now do whatever it is you do to GET this data delivered to you, (which I assume you already have all that figured out...) and then the magic can begin. What we do, is allocate a block of unmanaged memory, then copy the buffer into the block of memory, then copy it back out into our structure, and free the unmanaged memory block. This can easily be put into an extension function that can operate on any byte[], giving you the ability to call something like:
pStruct = (TServerInformation)buff.FromMemory();
The following code is what worked wonders for me. Oh, and do not forget to put try/catch/finally blocks around this in production code...
// Create our Managed Object...
TServerInformation pStruct = new TServerInformation();
// Allocate our block of unmanaged memory...
IntPtr pMem = Marshal.AllocHGlobal(Marshal.SizeOf(pStruct));
// Copy our buff buffer into that new block of memory...
Marshal.Copy(buff, 0, pMem, buff.Length);
// Type-cast that block of memory with the results of the Marshal object's help...
pStruct = (TServerInformation)Marshal.PtrToStructure(pMem, pStruct.GetType());
// Free that block of memory, that is no longer needed now that the data exists in managed form.
Marshal.FreeHGlobal(pMem);
And there you have it! This avoids all the extra header info that is included when you use Serialization, AND, it's about the only way I've found to get accurate "sizeof()" data from a managed structure. I'm sure there may be other ways to do this, but so far, this is the best I have found, after about 5 days of searching, hacking, searching, debugging, hacking, and searching some more... :)
If this works for you, let me know... I'm curious to see if it fixes your problem as well.