Problems calling VC++ dll from C#

Announcements and discussion for PInvoke

Moderators: Bart Read, Luke Jefferson, Robert

Problems calling VC++ dll from C#

Postby AndyG » Wed Jan 14, 2009 7:27 pm

Hi

I'm struggling to call a legacy API from C#.

One of the calls I need to make takes a structure that contains, amongst other things, lots of fixed length char arrays.

I thought that I'd managed to create a matching definition in my C# code but when I debug the legacy API, all of the elements of the structure that are fixed length char arrays appear with a null terminator (character 0) as the last character - this has overwritten my actual last character of the string.

I based the C# structures on the document \"Default Marshaling for Strings\" (http://msdn.microsoft.com/en-us/library/s9ts558h(VS.85).aspx).

Here is an example of the first two elements of the structure. The legacy api struct definition starts with

typedef
struct CLASS_EXPORT SoeMstItem
{
char ORDNUM [ 6];
char CUSTID [ 7];

(Note that this may have a #pragma pack (4) before the definition).


The C# struct definition starts as

[StructLayout(LayoutKind.Sequential)]
internal struct SoeMstItem
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
internal string ORDNUM; // 6
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 7)]
internal string CUSTID; // 7

When I set up the structure, I do the following

SoeMstItem header = new SoeMstItem();
header.ORDNUM = \"123456\";
header.CUSTID = \"1234567\";

When I get into the legacy api in the VC++ debugger, ORDNUM is set to \"12345\" + character 0 and CUSTID is set to \"123456\" + character 0. So the buffers are the correct length but the marshalling appears to have done something with null terminated strings.

Does anyone have any suggestions about where I'm going wrong?
Thanks in advance
Andy
AndyG
 
Posts: 2
Joined: Wed Jan 14, 2009 7:08 pm

Postby AndyG » Thu Jan 15, 2009 1:41 am

After a few more hours playing around, the only way that I have found to make this work is to declare the elements of the structure as follows

[StructLayout(LayoutKind.Sequential)]
internal struct SoeMstItem
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=6)]
internal byte [] ORDNUM;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=7)]
internal byte [] CUSTID;

Then set the values with

header.ORDNUM = StrToByteArray(\"123456\");
header.CUSTID = StrToByteArray(\"1234567\");

public static byte[] StrToByteArray(string str)
{
System.Text.ASCIIEncoding encoding=new System.Text.ASCIIEncoding();
return encoding.GetBytes(str);
}


This is not exactly pleasant as I need to remember to pad each string out to it's correct length with spaces otherwise I get marshalling exceptions.

A simpler solution would be helpful if anyone can assist.
Thanks
Andy
AndyG
 
Posts: 2
Joined: Wed Jan 14, 2009 7:08 pm


Return to PInvoke.Net

Who is online

Users browsing this forum: No registered users and 0 guests