4

There appears to be multiple ways to do this, but the examples I've tried haven't worked for me.

I read somewhere that using unsafe pointers would be the way to go for more complex structures that require pointers. (sorry but I haven't been able to find the source again)

My latest attempt looks something like this:

unsafe public struct ComplexStruct {
    public Int32 NumSubStruct;
    public SubStruct*[] arr;
}

unsafe public static extern UInt32 DLL_Call(ref ComplexStruct p);

function {
unsafe {
    ComplexStruct p = new ComplexStruct();
    p.NumSubStruct = 2;
    p.arr= new SubStruct*[p.NumSubStruct];
    SubStruct p1 = new SubStruct();
    SubStruct p2 = new SubStruct();
    p.arr[0] = &p1;
    p.arr[1] = &p2;


    testLogHandlerHandle = DLL_Call(ref p);
}
}

I get an error which says that SubStruct cannot be marshaled (Signature is not interop compatible).

Is it possible to pass the object without marshaling? (the DLL should be loaded in the same process space as the C# application).

If not, what would be the simplest way to pass a copy of the object?

Note: changing the DLL is a non-issue. I am vaguely aware of some other solutions, such as C++/CLI, but I only have a relatively small number of structure types that need to be passed in such a way.

EDIT: A few notes:

  1. The array needs to by dynamic
  2. The actual structs a bit more complicated (there's 4 layers of nested structures like this) so I think adding them would detract from the question, but for completeness, here is how I would declare these in C++:

    struct ComplexStruct {
    
         unsigned int NumSubStruct;
    
         SubStruct** arr;
    
    };
    
    struct SubStruct {
    
         unsigned int NumSubStruct;
    
         //some more datamembers here as well
    
         SubSubStruct** arr;
    
    };
    

(the extra indirection isn't necessary, but I figured it might be useful to be able to declare the array of SubStruct pointers as IntPtrs)

00500005
  • 3,727
  • 3
  • 31
  • 38
  • Can you show the C++ declaration for the two structs? Personally I doubt very much that `unsafe` is the way to go. – David Heffernan May 10 '12 at 19:52
  • That extra indirection is going to hurt you. It would be easier without it. – David Heffernan May 10 '12 at 20:28
  • In the end, you didn't get an answer using the unsafe way. This might help: https://stackoverflow.com/questions/17549123/c-sharp-performance-using-unsafe-pointers-instead-of-intptr-and-marshal – Soleil May 06 '18 at 20:16

2 Answers2

1

Like this maybe?

unsafe public struct ComplexStruct 
{ 
  public Int32 NumSubStruct; 
  public SubStruct** arr; 
}

unsafe static void Main(string[] args)
{
  ComplexStruct p = new ComplexStruct();
  p.NumSubStruct = 2;
  SubStruct[] s = new SubStruct[p.NumSubStruct];
  // no need to new here, valuetype array
  s[0].value = 1;
  s[1].value = 2;
  fixed (SubStruct* sp = s)
  fixed (SubStruct** spp = new SubStruct*[] { sp })
  {
    p.arr = spp;
    testLogHandlerHandle = DLL_Call(ref p);
  }
}
leppie
  • 115,091
  • 17
  • 196
  • 297
  • Both the above and fixed (SubStruct* sp1 = &s[0]) fixed (SubStruct* sp2 = &s[1]) fixed (SubStruct** spp = new SubStruct*[] { sp1, sp2 }) give me a memory access violation. The DLL gets to execute and the data appears to pass correctly though (at least with the second version). – 00500005 May 10 '12 at 20:39
0

You should use something like this and this.

[StructLayout(LayoutKind.Sequential)]
public struct ComplexStruct
{
    public Int32 NumSubStruct;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_NO_SUB_STRUCTS)]
    public SubStruct[] arr;
}

public static extern UInt32 DLL_Call(IntPtr p);

Then marshal it with something like this:

IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ComplexStruct)));

try
{
    // Copy the struct to unmanaged memory.
    Marshal.StructureToPtr(p, ptr, false);

    testLogHandlerHandle = DLL_Call(ptr);
}
finally
{
    // Free the unmanaged memory.
    Marshal.FreeHGlobal(ptr);
}

Try to get rid of all the unsafe stuff, I doubt its necessary!

DavWEB
  • 420
  • 4
  • 14
  • I'm assuming that using an arbitrarily high number for SizeConst would be very bad for performance. Ideas for doing so dynamically? – 00500005 May 10 '12 at 20:02
  • Should be easy enough to do dynamically. – David Heffernan May 10 '12 at 20:04
  • Don't know if this works, but the SizeConst is probably just for Marshal.SizeOf(). If you calculate the size yourself, then it should be possible to do it dynamically. Worst case StructureToPtr won't work aswell and you would have to copy over each SubStructure yourself. – DavWEB May 10 '12 at 20:08