Search code examples
c#c++pinvoke

How to DLLImport function with array return type in c#?


Here it is: static uint8_t* Compress(const uint8_t* input, uint32_t inputSize, uint32_t* outputSize, int compressionLevel);

I've tried :

[DllImport("Mini7z.dll")]
public static extern byte[] Compress(byte[] input, uint inputSize, out uint outputSize, int compressionLevel);

and this

[DllImport("Mini7z.dll")]
public static extern byte[] Compress(byte[] input, uint inputSize, uint* outputSize, int compressionLevel);

but nothing seems to work


Solution

  • You need to tell the marshaller the size of the array he needs to generate upon return from the function. Therefore you need to specify an attribute on the return value.

    Try this:

            [DllImport("Mini7z.dll")]
            [return:MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1, SizeParamIndex = 2)]
            public static extern byte[] Compress(byte[] input, uint inputSize, [In, Out] ref uint outputSize, int compressionLevel);
    

    Note that this leaks the buffer. You need to call another method to free it. Eventually, you need to use an IntPtr as return type and do the marshalling manually to be able to return the memory correctly.

    Since the managed type byte[] cannot be converted back to the original pointer that was returned, you should do something like this:

            [DllImport("Mini7z.dll")]
            public static extern IntPtr Compress(byte[] input, uint inputSize, [In, Out] ref uint outputSize, int compressionLevel);
            [DllImport("Mini7z.dll")] 
            public static extern FreeMemory(IntPtr memory); // or however the method is named
            
            // Then, use like this:
            IntPtr data = Compress(input, inputSize, ref dataSize, 9);
            byte[] managedData = new byte[dataSize];
            Marshal.Copy(data, managedData, 0, dataSize);
            FreeMemory(data);