pinvoke structure marshalling with embedded fixed strings... I'm going mad

B

Beorne

I have a cpp application with this structure:

//////////////C++///////////////
typedef struct StatusStructure
{
char FixedLenString[255];
long LongVariable;
double DoubleVariable;
BOOL BoolVariable;
} StatusStructure;
//////////////end C++///////////////

I have to recover this struct from my C# application. The struct will
be provided me by a pointer in the lparam of a windows message, this
is done by a propertary dll I can't modify.

FIRST TRY:
To begin with simple things I have made a dll cpp application with the
following function:

//////////////C++///////////////
.....
NICAMSDRIVER_API StatusStructure getOS(void);
.....
Operating_Status os;
Operating_Status getOS(void)
{
for (int i=0; i < 255; i++) os.FixedLenString = 'k';
os.LongVariable = 100;
os.DoubleVariable = 103.5;
os.BoolVariable = true;
return os;
}
//////////////end C++///////////////

Now the C# application:

//////////////C#///////////////
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct StatusStructure
{
[MarshalAs(UnmanagedType.LPStr, SizeConst = 255)] public string
FixedLenString;
public int LongVariable;
public double DoubleVariable;
public bool BoolVariable;
}
....
[DllImport("myDll")]
unsafe static extern Operating_Status getOS();
....
private void testFunction()
{
unsafe
{
StatusStructure os = getOS();
}
}
//////////////endC#///////////////

When I launch this application I get a
System.Runtime.InteropServices.MarshalDirectiveException
The exception that is thrown by the marshaler when it encounters a
MarshalAsAttribute it does not support.

I haven't understood this exception, perhaps my C# Operating_Status
struct is not compatible with the C++ struct StatusStructure ...
But I have used [MarshalAs(UnmanagedType.LPStr, SizeConst = 255)] as
written in "Default Marshaling for Strings" in
ms-help://MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.VisualStudio.v80.en/
dv_fxinterop/html/9baea3ce-27b3-4b4f-af98-9ad0f9467e6f.htm

SECOND TRY
The propertary dll I'll use will return me the struct StatusStructure
in a Windows message lparam, that in C# is a Message.LParam property
that returns an IntPtr.
So I rewrote my test c++ application returning a pointer instead of a
structure:

//////////////C++///////////////
.....
NICAMSDRIVER_API Operating_Status* getOS1(void);
.....
Operating_Status os;
Operating_Status* getOS1(void) // same as before, only returning a
pointer
{
for (int i=0; i < 255; i++) os.FixedLenString = 'k';
os.LongVariable = 100;
os.DoubleVariable = 103.5;
os.BoolVariable = true;
return &os;
}
//////////////endC++///////////////

Then I rewrote the C# application to browse the pointer of the
structure and to cast it in the following way:

//////////////C#///////////////
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] // same
as before
struct StatusStructure
{
[MarshalAs(UnmanagedType.LPStr, SizeConst = 255)] public string
FixedLenString;
public int LongVariable;
public double DoubleVariable;
public bool BoolVariable;
}
....
[DllImport("myDll")]
unsafe static extern IntPtr getOS1();
....
private void testFunction()
{
unsafe
{
IntPtr s = getOS1();
StatusStructure* ps; // <- error
ps = (StatusStructure*)s; // <- error
}
}
//////////////endC#///////////////

Here I have two of the same compilation error:
Cannot take the address of, get the size of, or declare a pointer to a
managed type ('Surveyor2.FormMain.StatusStructure')

I'm driving mad in marshalling, I think the cause is the fixed string
but I don't know how to proceed ...

Thank you very much
 
N

Nicholas Paldino [.NET/C# MVP]

In this case, instead of using UnmanagedType.LPStr, you want to use
UnmanagedType.ByValTStr.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Beorne said:
I have a cpp application with this structure:

//////////////C++///////////////
typedef struct StatusStructure
{
char FixedLenString[255];
long LongVariable;
double DoubleVariable;
BOOL BoolVariable;
} StatusStructure;
//////////////end C++///////////////

I have to recover this struct from my C# application. The struct will
be provided me by a pointer in the lparam of a windows message, this
is done by a propertary dll I can't modify.

FIRST TRY:
To begin with simple things I have made a dll cpp application with the
following function:

//////////////C++///////////////
....
NICAMSDRIVER_API StatusStructure getOS(void);
....
Operating_Status os;
Operating_Status getOS(void)
{
for (int i=0; i < 255; i++) os.FixedLenString = 'k';
os.LongVariable = 100;
os.DoubleVariable = 103.5;
os.BoolVariable = true;
return os;
}
//////////////end C++///////////////

Now the C# application:

//////////////C#///////////////
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct StatusStructure
{
[MarshalAs(UnmanagedType.LPStr, SizeConst = 255)] public string
FixedLenString;
public int LongVariable;
public double DoubleVariable;
public bool BoolVariable;
}
...
[DllImport("myDll")]
unsafe static extern Operating_Status getOS();
...
private void testFunction()
{
unsafe
{
StatusStructure os = getOS();
}
}
//////////////endC#///////////////

When I launch this application I get a
System.Runtime.InteropServices.MarshalDirectiveException
The exception that is thrown by the marshaler when it encounters a
MarshalAsAttribute it does not support.

I haven't understood this exception, perhaps my C# Operating_Status
struct is not compatible with the C++ struct StatusStructure ...
But I have used [MarshalAs(UnmanagedType.LPStr, SizeConst = 255)] as
written in "Default Marshaling for Strings" in
ms-help://MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.VisualStudio.v80.en/
dv_fxinterop/html/9baea3ce-27b3-4b4f-af98-9ad0f9467e6f.htm

SECOND TRY
The propertary dll I'll use will return me the struct StatusStructure
in a Windows message lparam, that in C# is a Message.LParam property
that returns an IntPtr.
So I rewrote my test c++ application returning a pointer instead of a
structure:

//////////////C++///////////////
....
NICAMSDRIVER_API Operating_Status* getOS1(void);
....
Operating_Status os;
Operating_Status* getOS1(void) // same as before, only returning a
pointer
{
for (int i=0; i < 255; i++) os.FixedLenString = 'k';
os.LongVariable = 100;
os.DoubleVariable = 103.5;
os.BoolVariable = true;
return &os;
}
//////////////endC++///////////////

Then I rewrote the C# application to browse the pointer of the
structure and to cast it in the following way:

//////////////C#///////////////
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] // same
as before
struct StatusStructure
{
[MarshalAs(UnmanagedType.LPStr, SizeConst = 255)] public string
FixedLenString;
public int LongVariable;
public double DoubleVariable;
public bool BoolVariable;
}
...
[DllImport("myDll")]
unsafe static extern IntPtr getOS1();
...
private void testFunction()
{
unsafe
{
IntPtr s = getOS1();
StatusStructure* ps; // <- error
ps = (StatusStructure*)s; // <- error
}
}
//////////////endC#///////////////

Here I have two of the same compilation error:
Cannot take the address of, get the size of, or declare a pointer to a
managed type ('Surveyor2.FormMain.StatusStructure')

I'm driving mad in marshalling, I think the cause is the fixed string
but I don't know how to proceed ...

Thank you very much
 
Top