trying to port some C++ structures to C# problem.

O

Olaf Baeyens

I am trying to port some C++ structures to C# but I have troubles with this
one.
Note: this is a file record, so I must keep this format.

#pragma pack( push, 1 )
typedef struct {
char title[80];

DWORD dwCount;
} STLHEADER, *LPSTLHEADER;
#pragma pack( pop )

Using Google I discovered that this could be ported to this C# variant,
note the 'Marshal' to create a 80 byte array.

[StructLayout(LayoutKind.Sequential, Pack=1)]
internal struct STLHEADER {
[MarshalAs (UnmanagedType.U1, SizeConst=80)]
public char[] title;

public int dwCount;
}

So far so good, but now I am stuck on this line "sizeof(STLHEADER)" needed
in a unsafe function.
error CS0208: Cannot take the address or size of a variable of a managed
type ('MySpace.STLHEADER')

And it has something to do with the Marshal thing.
I could replace the "sizeof(STLHEADER)" with 80+4 but I would really prefer
to have a more professional sollution.
Maybe there is another alternative way to define a 'char title[80]' byte
array?

Thanks for any feedback. :)
 
D

Dennis Myrén

Since you struct is using reference types(char []) you will need to use the
System.Runtime.InteropServices.Marshal.SizeOf method to determine the size
of your structure.

One more thing; you should change the char [] member into a byte [].
Otherwise, your data will not be parsed correctly, since char [80] in C# is
actually
160 bytes of size.
byte [] is in C# what char [] was in C++.
 
D

Dennis Myrén

And;
change
[MarshalAs (UnmanagedType.U1, SizeConst=80)]
into
[MarshalAs (UnmanagedType.ByValArray, SizeConst=80)]

So, now we have got:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct STLHEADER
{
[MarshalAs (UnmanagedType.ByValArray, SizeConst = 80)]
public byte [] title;
public int dwCount;
}
--
Regards,
Dennis JD Myrén
Oslo Kodebureau
Dennis Myrén said:
Since you struct is using reference types(char []) you will need to use
the
System.Runtime.InteropServices.Marshal.SizeOf method to determine the size
of your structure.

One more thing; you should change the char [] member into a byte [].
Otherwise, your data will not be parsed correctly, since char [80] in C#
is actually
160 bytes of size.
byte [] is in C# what char [] was in C++.


--
Regards,
Dennis JD Myrén
Oslo Kodebureau
Olaf Baeyens said:
I am trying to port some C++ structures to C# but I have troubles with
this
one.
Note: this is a file record, so I must keep this format.

#pragma pack( push, 1 )
typedef struct {
char title[80];

DWORD dwCount;
} STLHEADER, *LPSTLHEADER;
#pragma pack( pop )

Using Google I discovered that this could be ported to this C# variant,
note the 'Marshal' to create a 80 byte array.

[StructLayout(LayoutKind.Sequential, Pack=1)]
internal struct STLHEADER {
[MarshalAs (UnmanagedType.U1, SizeConst=80)]
public char[] title;

public int dwCount;
}

So far so good, but now I am stuck on this line "sizeof(STLHEADER)"
needed
in a unsafe function.
error CS0208: Cannot take the address or size of a variable of a managed
type ('MySpace.STLHEADER')

And it has something to do with the Marshal thing.
I could replace the "sizeof(STLHEADER)" with 80+4 but I would really
prefer
to have a more professional sollution.
Maybe there is another alternative way to define a 'char title[80]' byte
array?

Thanks for any feedback. :)
 
W

Willy Denoyette [MVP]

Not sure why you need this size for, but you have to:
- Declare the array element as UnmanagedType.ByValArray, and
- use the Marshal.SizeOf method to get the marshaled size of a struct.

[StructLayout(LayoutKind.Sequential, Pack=1)]
internal struct STLHEADER {
[MarshalAs (UnmanagedType.ByValArray, SizeConst=80)]
public char[] title;
public int dwCount;
}

....
STLHEADER stlh = new STLHEADER();
int marshaledSizeOfStruct = Marshal.SizeOf(stlh); // should be 84

Willy.
 
O

Olaf Baeyens

Wow thanks for the quick responce.

But Now I get this problem:

int iSTLHeaderSize=Marshal.SizeOf(STLHEADER);
Generates an error error "CS0118: 'MySpace.STLHEADER' denotes a 'class'
where a 'variable' was expected"
Odd since STLHEADER) is a structure type.

Another problem is this;

Normally without the char[] the code works fine

fixed (void *lSTLHeader=&STLFile.BufferPtr[0]) {
STLHEADER *pSTLHeader=(STLHEADER *)lSTLHeader;
....
}

But because of the Marshal thing, it refuses to work so I found a tip to
use 'Marshal.PtrToStructure' on Google.
So I tried this:
fixed (void *lSTLHeader=&STLFile.BufferPtr[0]) {
STLHEADER *pSTLHeader= (STLHEADER *)
Marshal.PtrToStructure(lSTLHeader,typeof(STLHEADER) );
}

But 'Marshal.PtrToStructure' tells me now that lSTLHeader should be a
IntPtr, so now is the question how can I convert void *lSTLHeader to
IntPtr????

(As you can see I am very new to this Marshal thing)
I appreciate the help though. :)
 
D

Dennis Myrén

The SizeOf method has two overloads, one expecting a type, the other
expecting an instance of a type. I think the most efficient one would be
that one taking a type, so to get the size, do:
int size = Marshal.SizeOf(typeof(STLHEADER));

Olaf Baeyens said:
But because of the Marshal thing, it refuses to work so I found a tip to
use 'Marshal.PtrToStructure' on Google.
So I tried this:
fixed (void *lSTLHeader=&STLFile.BufferPtr[0]) {
STLHEADER *pSTLHeader= (STLHEADER *)
Marshal.PtrToStructure(lSTLHeader,typeof(STLHEADER) );
}
If your structure did not use reference types(byte []), you could have done:
byte [] buff = new byte [sizeof(STLHEADER)];
[LOAD RAW DATA INTO buff]
fixed (byte * pBuff = buff)
header = * ((STLHEADER *) pBuff);

However, since you use a reference type in the structure, i think this is
the way to do it:
byte [] buff = new byte [Marshal.SizeOf(typeof(STLHEADER))];
[LOAD RAW DATA INTO buff]
IntPtr ptr = Marshal.AllocHGlobal(buff.Length);
Marshal.Copy(buff, 0x0, ptr, buff.Length);
header = (STLHEADER) Marshal.PtrToStructure(ptr, typeof(STLHEADER));
Marshal.FreeHGlobal(ptr);



HTH.

--
Regards,
Dennis JD Myrén
Oslo Kodebureau
Olaf Baeyens said:
Wow thanks for the quick responce.

But Now I get this problem:

int iSTLHeaderSize=Marshal.SizeOf(STLHEADER);
Generates an error error "CS0118: 'MySpace.STLHEADER' denotes a 'class'
where a 'variable' was expected"
Odd since STLHEADER) is a structure type.

Another problem is this;

Normally without the char[] the code works fine

fixed (void *lSTLHeader=&STLFile.BufferPtr[0]) {
STLHEADER *pSTLHeader=(STLHEADER *)lSTLHeader;
....
}

But because of the Marshal thing, it refuses to work so I found a tip to
use 'Marshal.PtrToStructure' on Google.
So I tried this:
fixed (void *lSTLHeader=&STLFile.BufferPtr[0]) {
STLHEADER *pSTLHeader= (STLHEADER *)
Marshal.PtrToStructure(lSTLHeader,typeof(STLHEADER) );
}

But 'Marshal.PtrToStructure' tells me now that lSTLHeader should be a
IntPtr, so now is the question how can I convert void *lSTLHeader to
IntPtr????

(As you can see I am very new to this Marshal thing)
I appreciate the help though. :)
 
O

Olaf Baeyens

int size = Marshal.SizeOf(typeof(STLHEADER));This worked! typeof was missing. :)

The rest I am trying to implement now, I report back if it works.

But I am wondering, since I use pure C# why do I need marshalling at all?
The structure is created in C# and the parsing and loading functionality of
the binary file is also created in that same C# assembly.
So as far as I understand this, I do not have a situation between managed
and unmnaged code because it is pure C#.

There is probably a very logical reason for this. :)
 
W

Willy Denoyette [MVP]

See inline ****
Willy.
Olaf Baeyens said:
Wow thanks for the quick responce.

But Now I get this problem:

int iSTLHeaderSize=Marshal.SizeOf(STLHEADER);
Generates an error error "CS0118: 'MySpace.STLHEADER' denotes a 'class'
where a 'variable' was expected"
Odd since STLHEADER) is a structure type.
*** There's is nothin odd, SizeOf takes a variable argument like:
STLHEADER stlh = new STLHEADER();
int iSTLHeaderSize=Marshal.SizeOf(stlh);

or:
int iSTLHeaderSize=Marshal.SizeOf(typeof(STLHEADER));

Another problem is this;

Normally without the char[] the code works fine

fixed (void *lSTLHeader=&STLFile.BufferPtr[0]) {
STLHEADER *pSTLHeader=(STLHEADER *)lSTLHeader;
....
}

But because of the Marshal thing, it refuses to work so I found a tip to
use 'Marshal.PtrToStructure' on Google.
So I tried this:
fixed (void *lSTLHeader=&STLFile.BufferPtr[0]) {
STLHEADER *pSTLHeader= (STLHEADER *)
Marshal.PtrToStructure(lSTLHeader,typeof(STLHEADER) );
}

But 'Marshal.PtrToStructure' tells me now that lSTLHeader should be a
IntPtr, so now is the question how can I convert void *lSTLHeader to
IntPtr????

(As you can see I am very new to this Marshal thing)
I appreciate the help though. :)

What you need is StructureToPtr, that is marshal a structure to a
pointer....

STLHEADER stlh = new STLHEADER(); // crate instance of struct
.... // initialize the struct fields
int iSTLHeaderSize=Marshal.SizeOf(stlh); // get size of marshaled struct
IntPtr stlhPtr = Marshal.AllocHGlobal( iSTLHeaderSize) // allocate
unmanaged memory with size of struct
Marshal.StructureToPtr(stlh , stlhPtr , true); // mashal managed
struct to unmanaged struct
.....// use unmanaged struct pointer to call unmanaged code functions
.....
Marshal.FreeHGlobal(stlhPtr ); // Free unmanaged memory when done

But again I'm not sure this is what you want, therefore I asked why you
needed the size of the struct.

Willy.
 
D

Dennis Myrén

Well, you could have avoided using Marshal utilities by manually loading the
members of STLHEADER
from a raw byte array source.

Marshalling could also have been avoided if the structure contained only
value types.
As the first example in my last post showed, you then could have used
"unsafe" code statements
in order to cast a raw byte array into a data structure.
This is possible since the structure is then stored in RAM in the exact way
as it was declared.
However, if reference types is used in the structure, you will need
something to marshal
them as if they were value types, because they are actually allocated on the
heap.

For instance, what i guess Marshal.SizeOf does, is locating any reference
types that are
members of the structure on the heap and measures it's size explicitly.
 
O

Olaf Baeyens

But again I'm not sure this is what you want, therefore I asked why you
needed the size of the struct.
Wel I have a binary STL file that contains a header and then a lot of 3D
triangles.
What I do is to load the complete file in memory, then maps a structure to
the header and if that structure is correct then I map another STLFACET
structure for every triangle.

It is code that is needed for my OpenGL visualization stuff, and since the
original data files can be huge, I try to avoid copying as much as I can.
Managed code is perfect for 3D modelling stuff. No more tracking of who
created the object and who should delete it. Wonderfull. :)

This STL parser is only the beginning part, I try to create the technology
to parse any potentional binary file formats (bmp, tiff, jpg,...) that I
might encounter.
I want to create a code base for this.
 
O

Olaf Baeyens

I really appreciate everybodies feedback. :)
Marshalling could also have been avoided if the structure contained only
value types.

Something like this?

[StructLayout(LayoutKind.Sequential, Pack=1)]
internal struct STLHEADER {
public DWORD title;
public DWORD dummy1;
public DWORD Dummy2;
.... 80 bytes
public DWORD Dummyx;

public int Count.
}

I was thinking to do it like this.
Is there no easy way to define a byte array of 80 bytes without Marshalling?
 
D

Dennis Myrén

Unfortunately, i do not think there is a way to do it without marshalling.
The only i can think of is as you suggested in your last post, like changing
byte [] title;
into
byte title0;
byte title1;
....
byte title79;

but it is not very beautiful, and i do not think you will earn anything from
that.
Then, you probably still want a byte array in the end of the day,
so you then would have to manually create a byte array later:
byte [] title = new byte [80] { header.title0, header.title1, ....,
header.title79 }
I actually think you would become less efficient with such an approach.

If you have other structures however, that do not use reference types, i
think you should stick with:
STLHEADER header;
byte [] buff = new byte [sizeof(STLHEADER)];
[LOAD RAW DATA INTO buff]
fixed (byte * pBuff = buff)
header = * ((STLHEADER *) pBuff);
since it is more efficient.

But for creating this particular structure, my best bet is still:
byte [] buff = new byte [Marshal.SizeOf(typeof(STLHEADER))];
[LOAD RAW DATA INTO buff]
IntPtr ptr = Marshal.AllocHGlobal(buff.Length);
Marshal.Copy(buff, 0x0, ptr, buff.Length);
STLHEADER header = (STLHEADER) Marshal.PtrToStructure(ptr,
typeof(STLHEADER));
Marshal.FreeHGlobal(ptr);

I think it is a very clean way after all.



--
Regards,
Dennis JD Myrén
Oslo Kodebureau
Olaf Baeyens said:
I really appreciate everybodies feedback. :)
Marshalling could also have been avoided if the structure contained only
value types.

Something like this?

[StructLayout(LayoutKind.Sequential, Pack=1)]
internal struct STLHEADER {
public DWORD title;
public DWORD dummy1;
public DWORD Dummy2;
... 80 bytes
public DWORD Dummyx;

public int Count.
}

I was thinking to do it like this.
Is there no easy way to define a byte array of 80 bytes without
Marshalling?
 
W

Willy Denoyette [MVP]

This is what I was afraid of ;-)
You can't map a managed struct/class to a buffer (probably a byte array) to
without copying ( part of) the buffer to an instance of that struct/class.
So I'm not clear as to what you mean with "What I do is to load the complete
file in memory, then maps a structure to...", does this mean you are DOING
this, or that you would LIKE to DO...

Willy.
 
O

Olaf Baeyens

I think it is a very clean way after all.Well I tried to implement this, and everything compiles, so let's see if it
also works. :)

Thank you for the feed-back. :)
 
O

Olaf Baeyens

This is what I was afraid of ;-)I am afraid of this too. :)
You can't map a managed struct/class to a buffer (probably a byte array) to
without copying ( part of) the buffer to an instance of that struct/class.
From security viewpoint this is great. And I don't mind this at all, only
you lose speed because of this copying.
Now, I am not a performance freak, none-performant critical parts should be
created in a secure way, even if it sacrifices a little bit of speed, but
the parts that needs to be really performant, I use unmanaged C++ for this.
So I'm not clear as to what you mean with "What I do is to load the complete
file in memory, then maps a structure to...", does this mean you are DOING
this, or that you would LIKE to DO...
I am porting a C++ working binary STL loader to C#.
So I am doing this in C++ now, and I would like to do this in C#.

So I am in a transition period, and existing programs must still work
without breaking everything.

The good news is that I now have some pointers to continue in...
So thanks for the feed-back.
 
O

Olaf Baeyens

Ok this compiles and it seems to do the trick.

Originally I wanted to do this:

fixed (void *lSTLHeader=&STLFile.BufferPtr[0]) {
STLHEADER *pSTLHeader=(STLHEADER *)lSTLHeader;
....
}


But since I use this:
internal struct STLHEADER {
[MarshalAs (UnmanagedType.ByValArray, SizeConst = 80)]
public byte [] title; // Allocate 80 bytes
}

In my structure then I must use this method instead

IntPtr ptr = Marshal.AllocHGlobal(iSTLHeaderSize);
Marshal.Copy(STLFile.BufferPtr, 0x0, ptr, iSTLHeaderSize);
STLHEADER header = (STLHEADER)
Marshal.PtrToStructure(ptr,typeof(STLHEADER));
....myfunctionality here ....
Marshal.FreeHGlobal(ptr);

Now lets find out if this works. :)
 
W

Willy Denoyette [MVP]

Olaf Baeyens said:
Well I tried to implement this, and everything compiles, so let's see if
it
also works. :)

Thank you for the feed-back. :)

No need to declare the individual bytes of the array, just declare your byte
array as:
[MarshalAs (UnmanagedType.ByValArray, SizeConst=80)]

Also no COPY is required if the struct starts with a byte[] field.

[StructLayout(LayoutKind.Sequential, Pack=1)]
internal struct STLHEADER {
[MarshalAs (UnmanagedType.ByValArray, SizeConst=80)]
public byte[] title;
public int dwCount;
}

class Tester
{
[DllImport("kernel32.dll", SetLastError=true)]
internal static extern int ReadFile(IntPtr handle, byte* bytes, int
bytesToRead, out int bytesRead, IntPtr mustBeZero);


int bytesRead;
int bytesToRead;
STLHEADER stlh = new STLHEADER();
bytesToRead = Marshal.SizeOf(typeof(STLHEADER));
unsafe {
using(FileStream fileStream = new FileStream(fileName, FileMode.Create))
{
fixed (byte* fPtr = stlh.title )
{
ReadFile(fileStream.Handle, fPtr, bytesToRead, out bytesRead,
IntPtr.Zero);
.....
// struct now contains data read from file
}
}

Don't now how your other structs look like, but maybe you can force it to
start with the smallest byte[] and convert the bytes in that to the correct
type considering correct alignment after reading.

Willy.
 
W

Willy Denoyette [MVP]

Ok, see my other reply regarding the Copy stuff which is IMO not needed.
Pretty sure at the end you will say "let's do this in MC++", goodluck
anyway.

Willy.
 
O

Olaf Baeyens

Hello Willy,

Thanks for the example.

My binary source is a byte[] that contains the complete loaded binary file.
This is specially designed like this, to make sure that the source could
come from any direction, in the current case a file, but maybe next a memory
block.

Also to speed up file access through a network, the complete file is opened,
loaded and closed in one operation. This way the file handles are released
so other programs might open it

If understand your example correctly, then you actually do the copying via
ReadFile() which is a great idea, but I doubt that it would work if the
source is coming from a byte[] source.
 
W

Willy Denoyette [MVP]

If understand your example correctly, then you actually do the copying via
ReadFile() which is a great idea, but I doubt that it would work if the
source is coming from a byte[] source.


If you mean "coming from a Memory stream", then the obvious answer is no.

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top