C struct to C# mapping

  • Thread starter Thread starter Tor Aadnevik
  • Start date Start date
T

Tor Aadnevik

Hi,

I'm trying to call a win32 function using pinvoke and C# .Net.

The function takes a struct reference as a parameter (lpInfo), but on return
the struct is not filled with data, and I'm suspecting that I have made a
mistake mapping up the struct.



DBSTAT DBenum ( XInt32 hDBase,

LPSTR lpszPath,

XDWORD nLevel,

DBENUMCB Callback,

DWORD UserData,

LPVOID lpInfo);



The C struct is like this (truncated):

typedef struct _seginfo {

CHAR Name [ strSHORT + 1 ];

CHAR Desc [ strLONG + 1 ];

DWORD Created;

WORD DClass;

WORD UType;

Int32 Top;

Int32 Bottom;

WORD wPoints;

FLOAT fHStart;

WORD uHUnit;

FLOAT fVScale;

WORD SmpSize; // for smpFILE = file size

// for smpREGULAR

WORD TixPerSmp;

// for smpRANGE

XDWORD *lpUpdateCount;

// any

Int32 lAliasOffset;

} SGMINFO;



strSHORT = 10;

strLONG = 256;

Can anyone help me with a correct C# mapping?
 
Tor,
Can anyone help me with a correct C# mapping?

I'm guessing it should look something like this

struct SGMINFO
{
[MmshalAs(UnmanagedType.ByValTStr, SizeConst=11)]
public string Name;
[MmshalAs(UnmanagedType.ByValTStr, SizeConst=257
public string Desc;
public uint Created;
public ushort DClass;
public ushort UType;
public int Top;
public int Bottom;
public ushort wPoints;
public float fHStart;
public ushort uHUnit;
public float fVScale;
public ushort SmpSize;
public ushort TixPerSmp;
public IntPtr lpUpdateCount;
public int lAliasOffset;
}


Mattias
 
Hi Mattias,
Thanks for your answer!

The struct is still not filled with data.
I see that a sizeof( SGMINFO) i C is 255 bytes, and Marshal.SizeOf(
typeof( SGMINFO )) in .Net is 344 bytes.
Maybe this is due to the fact that a char in ansi C is 1 byte wheras a char
in C# is 2 bytes?
Or do you think this is not the case?

Regards Tor



Mattias Sjögren said:
Tor,
Can anyone help me with a correct C# mapping?

I'm guessing it should look something like this

struct SGMINFO
{
[MmshalAs(UnmanagedType.ByValTStr, SizeConst=11)]
public string Name;
[MmshalAs(UnmanagedType.ByValTStr, SizeConst=257
public string Desc;
public uint Created;
public ushort DClass;
public ushort UType;
public int Top;
public int Bottom;
public ushort wPoints;
public float fHStart;
public ushort uHUnit;
public float fVScale;
public ushort SmpSize;
public ushort TixPerSmp;
public IntPtr lpUpdateCount;
public int lAliasOffset;
}


Mattias
 
Mattias Sjögren said:
Tor,
Can anyone help me with a correct C# mapping?

I'm guessing it should look something like this

struct SGMINFO
{
[MmshalAs(UnmanagedType.ByValTStr, SizeConst=11)]
public string Name;
[MmshalAs(UnmanagedType.ByValTStr, SizeConst=257
public string Desc;
public uint Created;
public ushort DClass;
public ushort UType;
public int Top;
public int Bottom;
public ushort wPoints;
public float fHStart;
public ushort uHUnit;
public float fVScale;
public ushort SmpSize;
public ushort TixPerSmp;
public IntPtr lpUpdateCount;
public int lAliasOffset;
}

I think it needs a StructLayoutAttribute:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
 
I think it needs a StructLayoutAttribute:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

That's the default for C# structs so it's optional. You don't have to
add it but it doesn't change anything if you do.


Mattias
 
The struct is still not filled with data.

How are you using it?

I see that a sizeof( SGMINFO) i C is 255 bytes,

I find that hard to believe since the Desc field alone is 257 bytes.

and Marshal.SizeOf(typeof( SGMINFO )) in .Net is 344 bytes.

I get 312 or 308 depending on the packing.

Maybe this is due to the fact that a char in ansi C is 1 byte wheras a char
in C# is 2 bytes?

The size of a char to the marshaler is whatever you set with the
StructLayout attribute. If you keep the default (CharSet.Ansi) it's
one byte per character.


Mattias
 
Mattias Sjögren said:
How are you using it?
public delegate bool EnumCallbackCB( string EnumName, uint UserData );
[ DllImport( "WDBase.dll", CharSet=CharSet.Auto, EntryPoint="DBenumA",
SetLastError=true, ExactSpelling=true )]
public static extern WarriorCommon.DBStat DBEnum( UInt32 DBHandler, string
Path, Int32 Level, EnumCallbackCB Callback, Int32 SizeOfUserData, ref
SGMINFO sgm );
I find that hard to believe since the Desc field alone is 257 bytes.
Dont understand it, I checked again and sizeof(SGMINFO) is only 244 in C,
I get 312 or 308 depending on the packing.
Sorry I did't mention that the struct was truncated. The complete listing
goes like this

[ StructLayout( LayoutKind.Sequential )]
public struct SGMINFO{
[[MarshalAs(UnmanagedType.ByValTStr, SizeConst=11)]
public string Name;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=257)]
public string Desc;
public uint Created;//DWORD
public uint Modified;//DWORD
public uint Code;//DWORD
public ushort bIsAliased;//WORD
public ushort SType;//WORD
public ushort DType;//WORD
public ushort DClass;//WORD
public ushort UType;//WORD
public int Top;//Int32
public int Bottom;//Int32
public ushort wPoints;//WORD
public float fHStart;//FLOAT
public float fHStep;//FLOAT
public ushort uHUnit;//WORD
public float fVScale;//FLOAT
public float fVMin;//FLOAT
public float fVMax;//FLOAT/
public ushort SmpSize;
public ushort TixPerSmp;//WORD
public ushort SmpPerBlk;//WORD
public ushort IxPerBlk;//WORD
public IntPtr lpUpdateCount;//XDWORD
public int lAliasOffset;//Int32}
 
[ DllImport( "WDBase.dll", CharSet=CharSet.Auto, EntryPoint="DBenumA",
SetLastError=true, ExactSpelling=true )]
public static extern WarriorCommon.DBStat DBEnum( UInt32 DBHandler, string
Path, Int32 Level, EnumCallbackCB Callback, Int32 SizeOfUserData, ref
SGMINFO sgm );

You may have to add the attributes [In, Out] to the last parameter to
get changes to marshal back.

Dont understand it, I checked again and sizeof(SGMINFO) is only 244 in C,

Then your value for strLONG must be wrong.


Mattias
 
Mattias Sjögren said:
You may have to add the attributes [In, Out] to the last parameter to
get changes to marshal back.

Would that be a MarshalAsAttribute declaration?

Regards
Tor
 
You may have to add the attributes [In, Out] to the last parameter to
Would that be a MarshalAsAttribute declaration?

No, the InAttribute and OutAttribute classes.


Mattias
 

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

Back
Top