0

I have a problem passing void pointer from unmanaged code to managed. There is a function's pointer in .cpp file

TESTCALLBACK_FUNCTION testCbFunc;

TESTCALLBACK_FUNCTION takes C++ structure

typedef void (*TESTCALLBACK_FUNCTION )(TImage image);
struct TImage
{
    int Width;                      //width
    int Height;                     //height
    void *Buf;                      //data buffer
};

C# function and structure

public void TImageReceived(TImage image)
{
    // logic
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1), Serializable]
public struct TImage
{
    public int Width;
    public int Height;
    public IntPtr Buf;
}

TImageReceived passed to unmanaged code and when it's called I receive exception.

System.Runtime.InteropServices.SafeArrayTypeMismatchException

If I passed NULL in field Buf from unmanaged code everything will works fine.

I know about MarshalAs atrribute, but the problem is that I cannot use SizeConst because Buf size is always different. But it always has size of Width*Height.

[MarshalAs(UnmanagedType.ByValArray,SizeConst=???)]

How to cast void* from unmanaged to managed code?

Alekstim
  • 452
  • 1
  • 8
  • 19
  • You also can't do much with `void*` in the unmanaged world either without having a mechanism to determine the size. So how does your unmanaged code determine the size of `Buf`? is there a calculation based on `Width` and `Height`? (e.g. perhaps `Buf` is simply a sequence of bytes representing Width*Height?) – Ben Cottrell Feb 20 '16 at 07:42
  • Yes, `Buf` has a size Width*Height. – Alekstim Feb 20 '16 at 09:10

1 Answers1

1

Based on your comment, and assuming that TImage from your C++ code maps neatly on to your struct (Warning - if you're using TImage from the Borland VCL, then that might not map on as neatly as you're hoping)

Buf has a size Width*Height

Your best option is to use Marshal.Copy, for example

using System.Runtime.InteropServices;

/* ... */

[StructLayout(LayoutKind.Sequential)]
public struct TImage 
{
    public int Width;
    public int Height;
    public IntPtr Buf;
}

/* ... */

public void TImageReceived(TImage image)
{
    var length = image.Height * image.Width;
    var bytes = new byte[length];
    Marshal.Copy(image.Buf, bytes, 0, length);
}

Related: Marshalling struct with embedded pointer from C# to unmanaged driver

...However...

If TImage belongs to Borland's VCL then I would suggest re-thinking the struct, because it will involve marshalling other data inherited from TImage's base class (Borland's documentation is unclear about the class' layout) - in which case, it would be easier to pass the arguments directly:

public void TImageReceived(IntPtr buf, int width, int height)
{
    var length = height * width;
    var bytes = new byte[length];
    Marshal.Copy(buf, bytes, 0, length);

    // etc.
}
Community
  • 1
  • 1
Ben Cottrell
  • 5,741
  • 1
  • 27
  • 34