Array in Structure

L

Lance

Hi all,

I've got a some structures defined as

//////
<StructLayout(LayoutKind.Sequential)> Public Structure GM_LayerInfo_t
Public mDescription As String
Public mNativeRect As GM_Rectangle_t
Public mGlobalRect As GM_Rectangle_t
Public mPixelWidth As Int32
Public mPixelHeight As Int32
Public mNativeProj As GM_Projection_t
Public mControlPoints As IntPtr
Public mNumGCPs As Int32
Public mMinElevation As Single
Public mMaxElevation As Single
Public mNumAreas As Int32
Public mNumLines As Int32
Public mNumPoints As Int32
Public mPixelSizeX As Double
Public mPixelSizeY As Double
Public mHasRasterData As Byte
Public mEnabled As Byte
Public mHasVectorData As Byte
Public mUsedDefaultPos As Byte
Public mFilename As String
Public mArchiveFilename As String
Public mTypeName As String
End Structure

<StructLayout(LayoutKind.Sequential)> Public Structure GM_ProjAttrValue_t
Public mAttr As PROJATTR
Public mValue As Double
End Structure

<StructLayout(LayoutKind.Sequential)> Public Structure GM_Projection_t
Public mProjSys As PROJSYS
Public mDatum As DATUM
Public mUnit As UNIT
Public mNumAttrs As Int32
<VBFixedArray(15)> Public mAttrList() As GM_ProjAttrValue_t
End Structure
///////

The Types PROJATTR, PROJSYS, DATUM, and UNIT are defined enums while GM_Rectangle_t is
another structure but these are not part of the problem (at lease I'm farily positive
they're not). It's the array in the GM_Projection_t structure that seems to be the
problem. Here it's fixed, but I've also attempted just leaving it dynamic and the same
problem occurs.

The array *should* almost always contains at least 1 element in it after fill the
structure (but it could be empty or it could contain up to 16 at max). Anyway, mAttrList
is always NOTHING when ever I fill the structure as it's coded above. (the code to fill
it at the botom of this message). Every other member of the structure is filled in fine.
However, if I don't make mAttrList an array - just defined within the structure as

/////
Public mAttrList As GM_ProjAttrValue_t
/////

then mAttrList is properly filled with the mAttr and mValue members of the
GM_ProjAttrValue_t structure (remember, there's *almost always* at least one attribute to
fill the mAttrList).


Here is the code making the call to fill the strucure

/////
' Convert the pointer to our structure
Dim theLayerInfo As GM_LayerInfo_t
theLayerInfo = CType(Marshal.PtrToStructure(theLayerInfoPtr, GetType(GM_LayerInfo_t)),
GM_LayerInfo_t)
/////
 
F

Fabio

"Lance" <[email protected]> ha scritto nel messaggio

Here is the code making the call to fill the strucure

/////
' Convert the pointer to our structure
Dim theLayerInfo As GM_LayerInfo_t
theLayerInfo = CType(Marshal.PtrToStructure(theLayerInfoPtr,
GetType(GM_LayerInfo_t)), GM_LayerInfo_t)
/////


First of all I think you need a read to namimng guidelines for types and
variables.

Regarding your problem I wonder why you are passing by marshalling and I
don't understand if your array is or not a fixed array.

Remember also that if you don't have a really need you should use a class
instead of an large structure.
 
L

Lance

just about all of this code was cut and pasted from an SDK, so the variable names wouldn't
be my first choice either. the SDK example also passes by marshalling.

the only thing i've changed from the SDK is the structure. it was originally

///// <StructLayout(LayoutKind.Sequential)> Public Structure GM_Projection_t
Public mProjSys As PROJSYS ' Projection system
Public mDatum As DATUM ' Horizontal datum
Public mUnit As UNIT ' Ground units
Public mNumAttrs As Int32 ' Number of attributes in attribute list
Public mAttrVal1 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal2 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal3 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal4 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal5 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal6 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal7 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal8 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal9 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal10 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal11 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal12 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal13 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal14 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal15 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal16 As GM_ProjAttrValue_t ' First attribute value
End Structure
/////

I was trying to change the structure to better reflect and behave more like the original C
Header file definition of
/////
typedef struct
{
PROJSYS mProjSys; // Projection system
DATUM mDatum; // Horizontal datum
UNIT mUnit; // Ground units
uint32 mNumAttrs; // Number of attributes in attribute list
GM_ProjAttrValue_t mAttrList[ 16 ]; // Attribute list
} GM_Projection_t;
/////
 
F

Fabio

"Lance" <[email protected]> ha scritto nel messaggio

the SDK example also passes by marshalling.

Ok, but why?
You need it?
If you don't use PInvoke the use of marshalling is masochist.
Also the use of StructLayout and VBFixedArray is not good if you don't need
it.
 
L

Lance

to tell you the truth, i hadn't really thought about whether or not marshaling is needed;
it's just a cut and paste from the SDK. the only thing i've changed from the SDK is the
structure so as to more accurately behave like the C Header file version as mentioned
previously (obviously failing at that...).

I've removed <StructLayout(LayoutKind.Sequential)> from the structure. Do you think
marshaling is the issue?
 
T

Tom Shelton

Lance said:
just about all of this code was cut and pasted from an SDK, so the variable names wouldn't
be my first choice either. the SDK example also passes by marshalling.

the only thing i've changed from the SDK is the structure. it was originally

///// <StructLayout(LayoutKind.Sequential)> Public Structure GM_Projection_t
Public mProjSys As PROJSYS ' Projection system
Public mDatum As DATUM ' Horizontal datum
Public mUnit As UNIT ' Ground units
Public mNumAttrs As Int32 ' Number of attributes in attribute list
Public mAttrVal1 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal2 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal3 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal4 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal5 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal6 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal7 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal8 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal9 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal10 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal11 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal12 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal13 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal14 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal15 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal16 As GM_ProjAttrValue_t ' First attribute value
End Structure
/////

I was trying to change the structure to better reflect and behave more like the original C
Header file definition of
/////
typedef struct
{
PROJSYS mProjSys; // Projection system
DATUM mDatum; // Horizontal datum
UNIT mUnit; // Ground units
uint32 mNumAttrs; // Number of attributes in attribute list
GM_ProjAttrValue_t mAttrList[ 16 ]; // Attribute list
} GM_Projection_t;
/////

Lance, if you are passing this to an unmanged function via P/Invoke (a
declare statement) then you should leave it like the original. The
marshaller in .NET 1.1 does not support arrays of structures in
structures....
 
L

Lance

i am indeed passing it to a declare statement (i'm utilizing an unmanaged DLL). however,
I'm using .NET 2.0. It occurs to me that the SDK uses examples written for Pre .Net 2.0
(1.1, I think) so that may be causing some confusion.

Tom Shelton said:
just about all of this code was cut and pasted from an SDK, so the variable names
wouldn't
be my first choice either. the SDK example also passes by marshalling.

the only thing i've changed from the SDK is the structure. it was originally

///// <StructLayout(LayoutKind.Sequential)> Public Structure GM_Projection_t
Public mProjSys As PROJSYS ' Projection system
Public mDatum As DATUM ' Horizontal datum
Public mUnit As UNIT ' Ground units
Public mNumAttrs As Int32 ' Number of attributes in attribute
list
Public mAttrVal1 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal2 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal3 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal4 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal5 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal6 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal7 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal8 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal9 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal10 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal11 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal12 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal13 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal14 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal15 As GM_ProjAttrValue_t ' First attribute value
Public mAttrVal16 As GM_ProjAttrValue_t ' First attribute value
End Structure
/////

I was trying to change the structure to better reflect and behave more like the
original C
Header file definition of
/////
typedef struct
{
PROJSYS mProjSys; // Projection system
DATUM mDatum; // Horizontal datum
UNIT mUnit; // Ground units
uint32 mNumAttrs; // Number of attributes in attribute list
GM_ProjAttrValue_t mAttrList[ 16 ]; // Attribute list
} GM_Projection_t;
/////

Lance, if you are passing this to an unmanged function via P/Invoke (a
declare statement) then you should leave it like the original. The
marshaller in .NET 1.1 does not support arrays of structures in
structures....
 
T

Tom Shelton

Lance said:
Hi all,

I've got a some structures defined as

//////
<StructLayout(LayoutKind.Sequential)> Public Structure GM_LayerInfo_t
Public mDescription As String
Public mNativeRect As GM_Rectangle_t
Public mGlobalRect As GM_Rectangle_t
Public mPixelWidth As Int32
Public mPixelHeight As Int32
Public mNativeProj As GM_Projection_t
Public mControlPoints As IntPtr
Public mNumGCPs As Int32
Public mMinElevation As Single
Public mMaxElevation As Single
Public mNumAreas As Int32
Public mNumLines As Int32
Public mNumPoints As Int32
Public mPixelSizeX As Double
Public mPixelSizeY As Double
Public mHasRasterData As Byte
Public mEnabled As Byte
Public mHasVectorData As Byte
Public mUsedDefaultPos As Byte
Public mFilename As String
Public mArchiveFilename As String
Public mTypeName As String
End Structure

<StructLayout(LayoutKind.Sequential)> Public Structure GM_ProjAttrValue_t
Public mAttr As PROJATTR
Public mValue As Double
End Structure

<StructLayout(LayoutKind.Sequential)> Public Structure GM_Projection_t
Public mProjSys As PROJSYS
Public mDatum As DATUM
Public mUnit As UNIT
Public mNumAttrs As Int32
<VBFixedArray(15)> Public mAttrList() As GM_ProjAttrValue_t
End Structure
///////

VBFixedArray is not appropriate for marshalling scenarios... You
should be using:

<MarshalAs (UnmanagedType.ByValArray, SizeConst:=15)>

Of course, this isn't going to work either in .NET 1.1 or lower. The
marshaller doesn't support arrays of structs inside of a structure.
 
L

Lance

hey! that nearly fixed it! now it correctly reads the only existing attribute, but the
remaining 15 (remember, it was a typo-the array holds up to 16 values) all return an
attribute value of 0 (which is a valid enum in PROJATTR). Preferably, they'd be empty but
i guess that's just not possible.

thanks tom!
 
F

Fabio

to tell you the truth, i hadn't really thought about whether or not
marshaling is needed; it's just a cut and paste from the SDK. the only
thing i've changed from the SDK is the structure so as to more accurately
behave like the C Header file version as mentioned previously (obviously
failing at that...).

I've removed <StructLayout(LayoutKind.Sequential)> from the structure. Do
you think marshaling is the issue?

Listen to me: if you don't use this structure for PInvoke remove all the
attributes and use it in the .Net way (remove also all the Marshal
references).

Marshalling is used to comunicate from managed (.net) and unmanaged (native
win32) world, if you don't need this avoid to use it and you'll live more
happy.

If you copy an example from an SDK it is presumed to be used as the SDK
says, so if you change the structure this is no more the structure of the
SDK, so you cannot apply the same logic to it (I hope the SDK explain why it
was using the marshalling and the structure itself, and I hope you read it).
 
L

Lance

Tom's solution worked. I am indeed making calls to an unmanaged DLL, so to the best of my
knowledge (newly aquired knowledge ;-) ) marshaling is needed.

As far as the SDK goes, the VB Example was written for .NET 1.1. The author suggested I
try and update the original translated-to-VB structures, enum, etc to take advantage of
..NET 2.0.

The author of the SDK has explained to me himself that it's supplied VB Example is - and
i'm quoting here, "In general the VB definitions are not kept up to date with the source
C++ declarations for the functions and types.
The VB code is just there to serve as a reference and not a complete sample of how to use
the SDK from VB."

Lance
 

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