Share via


create a struct with a fixed length array of bytes and some single bytes in C# then marshal it as an array

Question

Wednesday, June 22, 2011 6:11 PM

I Searched, I cant find an exact answer.

I'm creating a C# wrapper dll (namespace and class) marshaling for a Delphi driver dll.

Constraints:

I cant use fixed keyword as I am tryin not to use any "unsafe" calls in my managed C# wrapper of a dll.

The dll cant be changed.

Basically I have a func that takes a pointer to an array of bytes. I can get this to work fine.  However the practiclal way to do this for our customers is to allow then to create a struct with an array in it as is done in our C++ , C builder, Delphi, and VB 6.0 samples.  My problem is having a fixed or variable length array inside a struct in C#.  (without using "fixed")

I cant seem to get a constructor to do this either???

I could use a class instead of struct if i have to?

This is the C++ code equivelant I'm trying to emulate:

 struct TUSBAI1616Config
{
    byte ChannelRange[16];
    byte CalibMode;
    byte TrigMode;
    byte StartStopCH;
    byte Oversample;
};

This is then passed to the dll as a paameter by refference and is treated like an array of  20 bytes which works fine in C++.

 ZeroMemory(&Config, sizeof(Config));
 Config.CalibMode = 0; //Take actual data, not internal calibration sources.
 Config.TrigMode = 5; //Scan selected channels each counter rising edge.
 Config.Oversample = 0;//No oversample.
 ConfigBufSize = sizeof(Config);
 ADC_SetConfig (DeviceIndex, &Config, &ConfigBufSize);

Heres my latest C# code attempt, commented code didnt work:

 

 

 

public struct

 

{

 

 

 

 

 

 

 

 

 

public byte

 

public byte

 

public byte

 

public byte

 

public byte

 

 

 

public TUSBAI1616Config Config = new TUSBAI1616Config

 

 

 

 

 

 

 

public byte[] configArray = new byte

 

I cant get the array inside the struct to be a fixed lenght of 16 or dynamically set it with a constructor without errors??

Then heres an attempt to initialize the sstruct elements and copy/convert to an array and pass it to the dll.

This throws an exception because the array is still NULL.  Also if anyone has a cleaner way to conver the struct to an array let me know.  I'll work on that next, once I get the 16 byte sub array to work.

Config.CalibMode = 0;

 

Config.TrigMode = 5;

 

Config.Oversample = 0;

 

ConfigBufSize = 20;

 

 

 

 

 

for (int

 

for (int

 

AIOUSB.ADC_SetConfig(DeviceIndex, configArray, out ConfigBufSize);

 

Any suggestions would be greatly appreciated.

Can i make a 16 byte array a type then use it as a member of the struct?

Can a List help?  Would a class allow me to do this? Collection?

I'll keep searching, reading, struggling, testing....

Thanks in advace :) Thanks, Richard

i = 0; i < 16; i++)

 

{

configArray[i] = Config.ChannelRange[i];

}

configArray[16] = Config.CalibMode;

configArray[17] = Config.TrigMode;

configArray[17] = Config.StartStopCH;

configArray[18] = Config.Oversample;

 

 

i = 0; i < 16; i++)

 

{

Config.ChannelRange[i] = 0;  // exception!

}

 

 

// temp copy struct to array for dll call: ($$$Hack)

 

// sizeof(Config);

 

//No oversample.

 

//Scan selected channels each counter rising edge.

 

//Take actual data, not internal calibration sources.

[20];

 

// temp array for Config dll call:

 

//Config.ChannelRange = new byte[nDimension];

 

//int nDimension = 16;

();

 

 

 

//public TUSBAI1616Config Config;

Oversample;

 

}

 

StartStopCH;

 

 

TrigMode;

 

 

CalibMode;

 

 

[] ChannelRange;

 

 

 

//}

 

//ChannelRange = new ChannelRange[size];

 

//{

 

//TUSBAI1616Config(int size)

 

TUSBAI1616Config

 

// Struct for Config:

All replies (4)

Wednesday, June 22, 2011 9:01 PM ✅Answered | 1 vote

If the size 16 is fixed, then it's not a good choice for a parameter.  If you want to create a fixed length byte declaraion in a struct you can do it this way:

public struct WithFixedLength
{
  public readonly byte[] Data = new byte[16];
}

You will not be able to reassign the value of Data but you will be able to change the indices of the array.

If you want to convert a struct into a binary array, you need to use the Marshal class:

TUSBAI1616Config config;
int size = Marshal.SizeOf(config);   
byte[] data = new byte[size];   
IntPtr pointer = Marshal.AllocHGlobal(size);   
Marshal.StructureToPtr(config, pointer , true);   
Marshal.Copy(pointer, data , 0, size);   
Marshal.FreeHGlobal(pointer); 

Evan


Thursday, June 23, 2011 4:15 PM ✅Answered | 1 vote

To have the ChannelRange marshalled as an embedded array, you just need to apply a MarshalAs attribute.

Using a class instead of a struct allows the use of a default constructor. Note that a class is, by default, marshalled as a pointer to a struct. No need to pass it by reference.

public class TUSBAI1616Config
{ 
    public TUSBAI1616Config() 
    {
        ChannelRange = new byte [16];
        CalibMode = 0;
        TrigMode = 0;
        StartStopCH = 0;
        Oversample = 0;
    }

    [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)]
    public byte [] ChannelRange; 
    public byte CalibMode; 
    public byte TrigMode; 
    public byte StartStopCH; 
    public byte Oversample; 
} 

public TUSBAI1616Config Config = new TUSBAI1616Config();

Wednesday, June 22, 2011 7:00 PM

OK I'm learning reading MS Visual C# 2010 book on structs and arrays.

This is a corected version with contructor that takes size parameter and inits the array size:

Dang this editor sucks big time for pasted code, sorry.

 

// Struct for Config:

public struct   TUSBAI1616Config

   public TUSBAI1616Config(int size)

   {

      ChannelRange =

 new byte [size];

      CalibMode = 0;

      TrigMode = 0;

      StartStopCH = 0;

      Oversample = 0;

   }

   public byte [] ChannelRange;

   public byte CalibMode;

   public byte TrigMode;

   public byte StartStopCH;

   public byte Oversample; 

public TUSBAI1616Config Config = new TUSBAI1616Config(16);

This may work I'll try it. May want to use a class to then be able to overload the default contructor.  Cant seem to pass the 16 in as a reference to an int variable though?

May also want to make the members private not public not sure on that yet.

  Thanks, Richard

 


Friday, July 8, 2011 5:04 PM

Vin Jin Thanks for marking as answered.

Great replies. Thank you.

Yeh I ultimately pass an array of 21 bytes to the driver so these methods help keep the C# code clean and safe.

Cheers,

Richard

Thanks, Richard