syntax for fixed array in C#?

G

Guest

Hello,

I am making calls into a legacy DLL. One function in this DLL expects as a parameter a struct with several fields, each of which is a 40-char array. The effect of this function is to copy characters into these char array fields.

I am calling this function with (roughly) the following:

[StructLayout(LayoutKind.Explicit, Size=120, CharSet=CharSet.Auto)]
public class Foo
{
[FieldOffset(0)] public byte A;
[FieldOffset(40)] public byte B;
[FieldOffset(80)] public byte C;
}

[DllImport("Legacy.dll")]
public static extern int copyChars (Foo fooVar);

N.B. I am using defining them as byte fields because the DLL returns 8-bit chars, and its easier to see what's going on in the debugger that way.

The calls appear to be successful, as the debugger shows enough information to see that the expected data is going to the expected fields.

My problem is getting those characters into a C# string. If I use

char dst = new char[41];
int nResult = new ASCIIEncoding().GetChars(fooVar.A, 0, 40, dst, 0);

the compiler complains that it cannot convert a byte field (fooVar.A) to a byte array. If, on the other hand, I avoid this complaint by changing the formal declaration of fooVar.A from
[FieldOffset(0)] public byte A;

to

[FieldOffset(0)] public byte[] A;

the compiler is happy, but I get a runtime exception complaining that A cannot be marshaled. (I don't know what the issue is there.)

I realize the details of this are fairly esoteric. I suspect there is some simple casting syntax where I can tell the compiler that, yes, A is a byte array, but the 4000 variations I have tried have failed.
On the other hand, if there is a way to accomplish what I'm trying to without jumping through this particular hoop, I'd welcome hearing baout it.

Thanks in advance,
 
D

Daniel O'Connell [C# MVP]

PHil Coveney said:
Hello,

I am making calls into a legacy DLL. One function in this DLL expects
as a parameter a struct with several fields, each of which is a 40-char
array. The effect of this function is to copy characters into these char
array fields.

AFAIK, there is no way in C# 1.0/1.1 to create a fixed array. The only way I
can think of off the top of my head would be a byte array and manually
parsing out your values into the structure, PITA, but it should work.

However, C# 2.0 does address this with the fixed keyword, but I'm afraid
that won't be of any help to you for quite some time as its not expected
until next year.
I am calling this function with (roughly) the following:

[StructLayout(LayoutKind.Explicit, Size=120, CharSet=CharSet.Auto)]
public class Foo
{
[FieldOffset(0)] public byte A;
[FieldOffset(40)] public byte B;
[FieldOffset(80)] public byte C;
}

[DllImport("Legacy.dll")]
public static extern int copyChars (Foo fooVar);

N.B. I am using defining them as byte fields because the DLL returns
8-bit chars, and its easier to see what's going on in the debugger that
way.

The calls appear to be successful, as the debugger shows enough
information to see that the expected data is going to the expected fields.

My problem is getting those characters into a C# string. If I use

char dst = new char[41];
int nResult = new ASCIIEncoding().GetChars(fooVar.A, 0, 40, dst, 0);

the compiler complains that it cannot convert a byte field (fooVar.A) to
a byte array. If, on the other hand, I avoid this complaint by changing
the formal declaration of fooVar.A from
[FieldOffset(0)] public byte A;

to

[FieldOffset(0)] public byte[] A;

the compiler is happy, but I get a runtime exception complaining that A
cannot be marshaled. (I don't know what the issue is there.)

I realize the details of this are fairly esoteric. I suspect there is
some simple casting syntax where I can tell the compiler that, yes, A is a
byte array, but the 4000 variations I have tried have failed.
On the other hand, if there is a way to accomplish what I'm trying to
without jumping through this particular hoop, I'd welcome hearing baout
it.

Thanks in advance,
 
A

Austin Ehlers

[StructLayout(LayoutKind.Explicit, Size=120, CharSet=CharSet.Auto)]
public class Foo
{
[FieldOffset(0)] public byte A;
[FieldOffset(40)] public byte B;
[FieldOffset(80)] public byte C;
}

<snip>
Assuming the above Foo, this code will work

Foo foo=new Foo();
//call Legacy
string str=null;
fixed(byte* bP=&foo.A)
{
byte[] A=new byte[40];
for(int x=0;x<A.Length;x++)
A[x]=bP[x];
str=Encoding.ASCII.GetString(A); //if the bytes use
all 8 bits, you'll get bad values. Look at other Encoding.* classes
}

You can also declare the byte fields as byte* to save a step.

Austin
 
G

Guest

Austin, Daniel,

Thanks guys.

Using fixed, as Austin's example shows, worked fine. It was also a relief to know that I was not overlooking some simple and obvious alternative.

Austin, thanks for the tip about ASCIIEncoding, too. In the case I have to solve, I'm guaranteed to have printable ASCII so I don't have to worry about bit 8, but I'll take a look around for an alternative anyway.

--
PC


Austin Ehlers said:
[StructLayout(LayoutKind.Explicit, Size=120, CharSet=CharSet.Auto)]
public class Foo
{
[FieldOffset(0)] public byte A;
[FieldOffset(40)] public byte B;
[FieldOffset(80)] public byte C;
}

<snip>
Assuming the above Foo, this code will work

Foo foo=new Foo();
//call Legacy
string str=null;
fixed(byte* bP=&foo.A)
{
byte[] A=new byte[40];
for(int x=0;x<A.Length;x++)
A[x]=bP[x];
str=Encoding.ASCII.GetString(A); //if the bytes use
all 8 bits, you'll get bad values. Look at other Encoding.* classes
}

You can also declare the byte fields as byte* to save a step.

Austin
 

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