Click to See Complete Forum and Search --> : How to create sizeable struct in C#?
kienntsim
February 23rd, 2006, 01:44 AM
In C++, I have a struct like that:
struct SocketData{
int cbsize;
char name[20];
int cmd[3];
char data[1];
};
It means that I can create a sizeable struct but all member datas are stored in continuous memory.
In C#, I know that array is defined as reference so I don't know how to create sizeable struct in C#.
boudino
February 23rd, 2006, 02:20 AM
In managed code, you have no control over memory and it is right so. You hasn't take care about it. Your demand makes sence only if you would like to pass your struct to unmanaged code (e.g. in P/Invoke). Then you can use StructLayoutAttribute and set it to sequential. See example.
[StructLayout(LayoutKind.Sequential)]
struct SocketData{
int cbsize;
char name[20];
int cmd[3];
char data[1];
};
kienntsim
February 23rd, 2006, 02:50 AM
I think the reason is:
[StructLayout(LayoutKind.Sequential)]
public struct SocketData
{
public int cbsize;
public char[] name;
public int[] cmd;
public char[] data;
}
public class Test
{
void Main()
{
SocketData sockData = new SocketData();
sockData.cbsize = 100;
sockData.name = new char(20);
sockData.cmd = new int(3);
sockData.data = new int(73); // 100 - 4 - 20 - 3 = 73
}
}
Because the struct contains array members that will be allocated after object declared so that they are all references and not sequential.
MadHatter
February 23rd, 2006, 03:01 AM
sorry I havent gotten back to your email (I'm just now sitting down to it & noticed you posted here).
you can define size constants in your struct:
struct SocketData {
public int cbsize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public char[] name;
public int cmd;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public char[] data;
}
then you should be able to marshal it as I did in the original thread you were asking about.
you can also mark the struct as explicit in the structlayout attribute (instead of sequential), and explicitly define how members will be laid out. I dont think that helps your situation though.
you said your struct will be sizable (I'm assuming by the 2 arrays you have there)? in my example (in the other thread) I allocated a buffer using the sizeof the struct (because the size was constant), but if you know how large you're going to allocate the 2 members, then you should be able to define the size of buffer you'll marshal the struct to, then do it exactly the same as before (once you pin the data in memory using gchandle you shouldnt have any problems marshaling it). I havent tried it so I could be wrong, but it sounds like this should work.
good luck... again, sorry I havent been of much help.
kienntsim
February 23rd, 2006, 03:25 AM
Here is a sample of sizeable struct that I used.
#include <stdio.h>
#include <memory.h>
struct SocketData{
int cbsize;
char name[20];
int cmd[3];
char data[1];
};
void main()
{
int x[] = {1, 2, 3, 4, 5};
char str[] = "Hello, world";
SocketData* lpSockData;
int size;
//1. The first allocated
size = sizeof(SocketData) + sizeof(x);
lpSockData = (SocketData *) new char[size];
lpSockData->cbsize = size;
memcpy(lpSockData->data, (char*) x, sizeof(x));
delete lpSockData;
//2. The second allocated
size = sizeof(SocketData) + sizeof(str);
lpSockData = (SocketData *) new char[size];
lpSockData->cbsize = size;
memcpy(lpSockData->data, (char*) str, sizeof(str));
delete lpSockData;
}
It is difficult for me to do so in C#.
MadHatter
February 23rd, 2006, 03:59 AM
perhaps you can use the binary formatter & just serialize the struct:
[Serializable]
struct SocketData {
public int cbsize;
public char[] name;
public int cmd;
public char[] data;
}
and the formatting code:
SocketData sd = new SocketData();
sd.name = new char[] {'t','e','s','t'};
sd.data = new char[] {'h','e','l','l','o',' ','w','o','r','d'};
sd.cmd = 12;
sd.cbsize = sd.data.Length;
byte[] buffer = null;
BinaryFormatter bf = new BinaryFormatter();
// encode the data into a byte array so you can send it
using(MemoryStream ms = new MemoryStream()) {
bf.Serialize(ms, sd);
buffer = ms.ToArray();
}
// send & recieve data over the socket
byte[] recieved = new byte[buffer.Length];
Array.Copy(buffer, recieved, buffer.Length);
// read in the byte array and deserialize it to SocketData
using(MemoryStream ms = new MemoryStream()) {
ms.Write(buffer, 0, buffer.Length);
ms.Seek(0, 0);
SocketData data = (SocketData)bf.Deserialize(ms);
}
I dont know if you have to communicate w/ the older system which copy's the struct from memory, in which case this isnt going to work for you. but if you're writing both ends in C# then you should be fine.
kienntsim
February 23rd, 2006, 04:11 AM
perhaps you can use the binary formatter & just serialize the struct:
[Serializable]
struct SocketData {
public int cbsize;
public char[] name;
public int cmd;
public char[] data;
}
and the formatting code:
SocketData sd = new SocketData();
sd.name = new char[] {'t','e','s','t'};
sd.data = new char[] {'h','e','l','l','o',' ','w','o','r','d'};
sd.cmd = 12;
sd.cbsize = sd.data.Length;
byte[] buffer = null;
BinaryFormatter bf = new BinaryFormatter();
// encode the data into a byte array so you can send it
using(MemoryStream ms = new MemoryStream()) {
bf.Serialize(ms, sd);
buffer = ms.ToArray();
}
// send & recieve data over the socket
byte[] recieved = new byte[buffer.Length];
Array.Copy(buffer, recieved, buffer.Length);
// read in the byte array and deserialize it to SocketData
using(MemoryStream ms = new MemoryStream()) {
ms.Write(buffer, 0, buffer.Length);
ms.Seek(0, 0);
SocketData data = (SocketData)bf.Deserialize(ms);
}
I dont know if you have to communicate w/ the older system which copy's the struct from memory, in which case this isnt going to work for you. but if you're writing both ends in C# then you should be fine.
I think it is quite good.
Thank you very much.
exterminator
February 23rd, 2006, 08:27 AM
The supposedly C++ code that you showed is not C++ not even correct C. main is int main() and not void main(). Ignoring these, even then you cannot be sure that the allocation is totally contiguous. Recall, structure alignment issue. If it is the arrays that you are worried about - if they would acquire contiguous allocations - be sure - they will. Regards.
kienntsim
February 23rd, 2006, 07:31 PM
That code I have written in VC++. I have checked memory address of all variable members of struct, it is contiguous. It may be not right in other C/C++ compilers.
Thank you for your advice.
kienntsim
February 24th, 2006, 02:40 AM
I go with MadHatter suggestion and I found that the length of the buffer serialized is quite bigger than real length of the struct. C# have a header for data serialized. If there is a way to solve it, reduce the length of buffer serialized?
hansipet
February 24th, 2006, 02:48 AM
Search for Unmanaged code Calls...There are a lot of description...
May be you can find something in the links below:
http://www.dotnet247.com/247reference/msgs/4/21576.aspx
http://www.csharphelp.com/archives/archive52.html
http://www.codeproject.com/csharp/ObjectPooling.asp
Regards
Hansjörg
MadHatter
February 24th, 2006, 09:20 AM
using a binary formatter, the framework stores some extra info about the object (like info about the assembly which serilized it).
the problem is that the framework doesnt include a way to get size of a struct which doesnt explicitly layout its offsets (or have them implied using a sequential layout). I dont know of any way to define offsets with an instance of an object (which is what you'd need to do to marshal it using the built in MarshalStructureToPtr.
you may want to search for marshaling sized objects at runtime, and see if there are any examples out there (I'm sure there are if its possible).
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.