Regarding Marshaling Data Structure and IntPtr!

G

Guest

I saw this article here:
http://www.arstdesign.com/articles/interopmarshaling.html

But i had some problems doing this.

Codes:

/* C Structure

typdef struct {
int avalue;
int bvalue;
unsigned char cvalue[10];
} TestA;

*/

// C# Structure
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct TestA
{
public const int strlength = 10;
public short avalue;
public short bvalue;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=strlength)]
public string cvalue;
}

/* C function

SOMEAPI int SOME_DECL Get_Details(int, TestA *);
*/

// My C# platform invocation - follow your article
[DllImport("Some3rdParty.dll", EntryPoint="#1", SetLastError=true,
ExactSpelling=true, CharSet=CharSet.Ansi)]

private static extern short Get_Details(short handle, IntPtr lpParam);

// The implementation based on the article

TestA myTestA = new TestA();

int result = 0;

int size = Marshal.SizeOf(typeof(TestA));

IntPtr pncmetrics = Marshal.AllocHGlobal(size);

Marshal.StructureToPtr(myTestA, pncmetrics, true);

// somehandle is a short handle global value get from other methods call

result = Get_Details(somehandle, pncmetrics);

Marshal.PtrToStructure(pncmetrics, myTestA); // this part, it break and i
receive an error, check below!

Marshal.FreeHGlobal(pncmetrics);

--Error------------------

An unhandled exception of type 'System.ArgumentException' occurred in
mscorlib.dll

Additional information: The structure must not be a value class.
 
B

BMermuys

Hi,


[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct TestA
{
public const int strlength = 10;
public int avalue;
public int bvalue;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=strlength)]
public string cvalue;
}

Or you sure cvalue is a C-null-terminated string, if it is not then you
should use something like:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct TestA
{
public const int strlength = 10;
public int avalue;
public int bvalue;

[MarshalAs(UnmanagedType.ByValArray, SizeConst=strlength)]
public byte cvalue;
}


[DllImport("Some3rdParty.dll", EntryPoint="#1", SetLastError=true,
ExactSpelling=true, CharSet=CharSet.Ansi)]
private static extern int Get_Details( int handle, ref TestA a );


This should work, no need for IntPtr's in this case, but if you want to use
PtrToStruct, use the other overload:
TestA a = (TestA)PtrToStruct( ptr, typeof(TestA) );

And C int are C# int's not short's.

HTH,
greetings
 
G

Guest

Hi BMermuys,

I got an error, in debug mode, when it reach this line of code:

int testing;

testing = Get_Details(handle, ref myTestA); // error when debug

Errors:
--------
An unhandled exception of type 'System.TypeLoadException' occurred in
ProjectA.dll

Additional information: Can not marshal field cvalue of type TestA: Invalid
managed/unmanaged type combination (Byte/SByte must be paired with I1 or U1).

What does it means?

Yeah, i had modified to what you had recommended on the structure and inside
the p/invoke.

Had also change from short to int.

Any tips please. Thanks.
 
B

BMermuys

Hi,
inline

Chua Wen Ching said:
Hi BMermuys,

I got an error, in debug mode, when it reach this line of code:

int testing;

testing = Get_Details(handle, ref myTestA); // error when debug

Errors:
--------
An unhandled exception of type 'System.TypeLoadException' occurred in
ProjectA.dll

Additional information: Can not marshal field cvalue of type TestA: Invalid
managed/unmanaged type combination (Byte/SByte must be paired with I1 or U1).

What does it means?

I made a typo, this :

[MarshalAs(UnmanagedType.ByValArray, SizeConst=strlength)]
public byte cvalue;

should offcourse be:

[MarshalAs(UnmanagedType.ByValArray, SizeConst=strlength)]
public byte[] cvalue;


HTH,
greetings

Yeah, i had modified to what you had recommended on the structure and inside
the p/invoke.

Had also change from short to int.

Any tips please. Thanks.

BMermuys said:
Hi,


[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct TestA
{
public const int strlength = 10;
public int avalue;
public int bvalue;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=strlength)]
public string cvalue;
}

Or you sure cvalue is a C-null-terminated string, if it is not then you
should use something like:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct TestA
{
public const int strlength = 10;
public int avalue;
public int bvalue;

[MarshalAs(UnmanagedType.ByValArray, SizeConst=strlength)]
public byte cvalue;
}


[DllImport("Some3rdParty.dll", EntryPoint="#1", SetLastError=true,
ExactSpelling=true, CharSet=CharSet.Ansi)]
private static extern int Get_Details( int handle, ref TestA a );


This should work, no need for IntPtr's in this case, but if you want to use
PtrToStruct, use the other overload:
TestA a = (TestA)PtrToStruct( ptr, typeof(TestA) );

And C int are C# int's not short's.

HTH,
greetings
 
G

Guest

Thanks BMermuys, it works.

I found another solution, but sometimes it works and it don't. I wrote
inside my blog.

http://chua_wen_ching.blogspot.com/

Thanks.

BMermuys said:
Hi,
inline

Chua Wen Ching said:
Hi BMermuys,

I got an error, in debug mode, when it reach this line of code:

int testing;

testing = Get_Details(handle, ref myTestA); // error when debug

Errors:
--------
An unhandled exception of type 'System.TypeLoadException' occurred in
ProjectA.dll

Additional information: Can not marshal field cvalue of type TestA: Invalid
managed/unmanaged type combination (Byte/SByte must be paired with I1 or U1).

What does it means?

I made a typo, this :

[MarshalAs(UnmanagedType.ByValArray, SizeConst=strlength)]
public byte cvalue;

should offcourse be:

[MarshalAs(UnmanagedType.ByValArray, SizeConst=strlength)]
public byte[] cvalue;


HTH,
greetings

Yeah, i had modified to what you had recommended on the structure and inside
the p/invoke.

Had also change from short to int.

Any tips please. Thanks.

BMermuys said:
Hi,


[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct TestA
{
public const int strlength = 10;
public int avalue;
public int bvalue;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=strlength)]
public string cvalue;
}

Or you sure cvalue is a C-null-terminated string, if it is not then you
should use something like:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct TestA
{
public const int strlength = 10;
public int avalue;
public int bvalue;

[MarshalAs(UnmanagedType.ByValArray, SizeConst=strlength)]
public byte cvalue;
}


[DllImport("Some3rdParty.dll", EntryPoint="#1", SetLastError=true,
ExactSpelling=true, CharSet=CharSet.Ansi)]
private static extern int Get_Details( int handle, ref TestA a );


This should work, no need for IntPtr's in this case, but if you want to use
PtrToStruct, use the other overload:
TestA a = (TestA)PtrToStruct( ptr, typeof(TestA) );

And C int are C# int's not short's.

HTH,
greetings
 

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