简体   繁体   中英

passing an array of structures from C# to C++ using IntPtr

I have a structure -->

   public struct readers
   {
       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1000)]
       public IntPtr[] tag_list;
   };

Marshalling has to be done in between "IntPtr[] tag_list" & structure TAG_IN_PARAM

   [StructLayout(LayoutKind.Sequential)]
   internal struct TAG_IN_PARAM
   {
       public int vis_cnt;
       public bool valid;
   }

Also its an array as => TAG_IN_PARAM[] tag_list = new TAG_IN_PARAM[1000];

I want to pass structure "readers" from C# to C++ DLL. However, i have been doing marshalling but garbage value is coming on DLL side.

// allocating memory Marshal.StructureToPtr(tag_list[j], Reader.tag_list[j], false);

OR IF ANY OTHER WAY I CAN DO IT, PLEASE CONVEY. Any help would be appreciated. Thanks in Advance.

The C++ type that you are trying to match is, according to your comment:

class Readers 
{
public:
    TAG_IN_PARAM* tag_list;
};

That's a pointer to an array.

But your C# code declares an inline array. Your C# code would match this:

class Readers 
{
public:
    TAG_IN_PARAM tag_list[1000];
};

Obviously, that's not the way you want to go.

You'll need to change your C# code to make it match. Unfortunately it seems that the marshaller will not marshal an array as a pointer to the first element, when the array is inside a struct. Since the array is the only thing in the struct you should simply pass the array as a parameter.

Alternatively, if you absolutely need to pass the array in a struct then I think you need to marshal by hand. Like this.

public struct readers
{
    public IntPtr tag_list;
};

And then you can simply pin your array.

TAG_IN_PARAM[] tag_list = ...;
GCHandle pinnedArray = GCHandle.Alloc(tag_list, GCHandleType.Pinned);
readers r;
r.tag_list = pinnedArray.AddrOfPinnedObject();
// call function passing r
pinnedArray.Free();

Unfortunately that does not quite work because C# bool is not blittable. So you could resolve that by using a different type for that field. For example byte or int depending on what's on the C++ side.

Yet another option is Marshal.StructureToPtr on each field. That would run like this:

TAG_IN_PARAM[] tag_list = ...;
int structSize = Marshal.SizeOf(typeof(TAG_IN_PARAM));
r.tag_list = Marshal.AllocHGlobal(tag_list.Length*structSize);
IntPtr ptr = r.tag_list;
for (int i = 0; i < tag_list.Length; i++)
{
    Marshal.StructureToPtr(tag_list[i], ptr, false);
    ptr += structSize;
    // or on older versions of .net without arithmetic support on IntPtr
    // ptr = (IntPtr) (long)ptr + structSize;
}
// call function passing r
Marshal.FreeHGlobal(r.tag_list);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM