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?

2
  • 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?) Commented Feb 20, 2016 at 7:42
  • Yes, Buf has a size Width*Height. Commented Feb 20, 2016 at 9:10

1 Answer 1

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.
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.