2

Could anyone please help me with the following?

I have a dll written in C and want to call a certain function in it from C#.

The function returns a pointer to a structure. Here is the structure:

typedef struct
{
    char          crv_name[40];
    char          crv_name2[12];
    char          units[40];
    char          creator[24];     
    char          index_units[8];
    double        first_dep_tim;
    double        last_dep_tim;
    double        level_spacing;
    EmptyValU     empty_val;
    long          num_ele;
}

Now, I know (from calling this from a C client) that the last member (num_ele) will be set to 1.

Now, that penultimate member is of type EmptyValU which is defined as:

typedef union
{
  double   d;
  float    f;
  long     l;
  ulong    ul;
  short    s;
  ushort   us;
  char     c;
}EmptyValU;

Now, I can call this ok fom C# and read everything up until empty_val. My value for num_ele is nonsense as I am clearly misaligned in memory after empty_val.

Here is my C# code:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CurveInfo
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
    public string crv_name;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)]
    public string crv_name2;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
    public string units;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 24)]
    public string creator;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
    public string index_units;
    public double first_dep_tim;
    public double last_dep_tim; 
    public double level_spacing; 
    [MarshalAs(UnmanagedType.Struct, SizeConst = 8)]
    public EmptyValU empty_val;
    public long num_ele;
}

and I have defined EmptyValU as:

[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct EmptyValU
{
    [FieldOffset(0)]
    public double d;
    [FieldOffset(0)]
    public float f;
    [FieldOffset(0)]
    long l;
    [FieldOffset(0)]
    ulong ul;
    [FieldOffset(0)]
    short s;
    [FieldOffset(0)]
    ushort us;
    [FieldOffset(0)]
    char c;
}

Like I say, when I call the function which returns a pointer to such a structure all the values are populated correctly up until the EmptyValU member, which, along with num_ele is not correctly populated. Something about the way I have to define the union in C# is what I am missing in order to keep the alignment correct.

Thanks for any help, Mitch.

Palle Due
  • 5,929
  • 4
  • 17
  • 32
user3738290
  • 445
  • 3
  • 16
  • See my overlay at following posting : https://stackoverflow.com/questions/60785592/convert-uint32-array-to-image-bitmap/60787258#60787258 – jdweng Mar 23 '20 at 15:58
  • You may be having an alignment issue. You may need to set the PACK size. See : https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.structlayoutattribute.pack?view=netframework-4.8 – jdweng Mar 23 '20 at 16:06

1 Answers1

1

I've solved this.

I C, a long (and ulong) is 4 bytes wide, but in C# they are 8 bytes wide.

So instead of:

[FieldOffset(0)]
long l;
[FieldOffset(0)]
ulong ul;

I should have had:

[FieldOffset(0)]
int l;
[FieldOffset(0)]
uint ul;

becasue in C# int and uint are 4 bytes wide.

For the same reason, on the C# side instead of:

public long num_ele;

I need:

public int num_ele;

Now it all works.

user3738290
  • 445
  • 3
  • 16