5

I have a native library with some native ntype in it and would like to p/invoke some functions in it.

I was able to marshal for:

foo1(ntype** p) ==> foo1(IntPtr[] p)

But don't know how to do it for:

foo1(ntype*[] p) ==> foo1(<???> p)

At least IntPtr[] did not worked.

Edit

The unmanaged function I'm trying to marshal with is:

extern mxArray* mclCreateSimpleFunctionHandle(mxFunctionPtr fcn);

where mxFunctionPtr is:

typedef void(*mxFunctionPtr)(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);

This represent a call to the following matlab function signature:

function [varargout] = callback(varargins)
%[
    %% Do callback code %%
%]

Obviously, from my expectations, this function pointer should provide me with 2 lists of mxArray*:

  • The list of input arguments (i.e. prhs, initialized on matlab's side)
  • The list of output arguments (i.e. plhs, all initialized to zero but in which I should write into)

Currently from the tests I've made, it only returns for firsts mxArray* in plhs and prhs lists

CitizenInsane
  • 4,755
  • 1
  • 25
  • 56
  • C functions that take pointers and arrays are hopelessly ambiguous. There's no difference between ntype** and ntype*[] unless you somehow gave it different semantics in your code. – Hans Passant Jan 05 '12 at 14:33

2 Answers2

2

First thing to do is to translate your native ntype into a managed struct.

For instance:

public struct Ntype
{
    public int Field1;
    public long Field2;
}

Then you define your method with a simple IntPtr parameter in your C# code.

[DllImport]
static void foo1(IntPtr myParam);

Finally here's how you use it:

IntPtr buffer = IntPtr.Zero;

try
{
    // Allocates a buffer. The size must be known
    buffer = Marshal.AllocHGlobal(0x1000);

    // Call to your unmanaged method that fills the buffer
    foo1(buffer);

    // Casting the unmanaged memory to managed structure that represents
    // your data
    Ntype obj = (Ntype)Marshal.PtrToStructure(buffer, typeof(Ntype));
}
finally
{
    // Free unmanaged memory
    if (buffer != IntPtr.Zero)
    {
        Marshal.FreeHGlobal(buffer);
    }
}
ken2k
  • 48,145
  • 10
  • 116
  • 176
  • Why doesn't he just not define the structure in both his C# and C++ code, and send the address of the pointer to the C++ code, your suggested code can get people in trouble. – Security Hound Jan 05 '12 at 16:23
  • Thanks @ken2k and @Ramhound for your help. I think I don't really need to have the structure, only a pointer to it is fine for me. In fact i'm trying to solve on calling `mclCreateSimpleFunctionHandle` as described in [link](http://stackoverflow.com/q/7892254/684399). Apparently, this function is only returning for a pointer to the first `mxArray*` and I'm trying to get the full list of `mxArray*` (I'm not interested in `mxArray` itself)... At least for readers on this other post, guess I'm on my way to fix it. – CitizenInsane Jan 05 '12 at 18:09
2

Got it

The correct marshalling for 'SomeTime* []' in:

extern mxArray* mclCreateSimpleFunctionHandle(mxFunctionPtr fcn);
typedef void(*mxFunctionPtr)(int nlhs, mxArray* plhs[], int nrhs, mxArray* prhs[]);

is:

// For function pointer
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public delegate void MCRInteropDelegate(int nlhs,
                                        [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt, SizeParamIndex = 0)][Out] IntPtr[] plhs, 
                                        int nrhs,
                                        [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt, SizeParamIndex = 2)][In] IntPtr[] prhs);

// For API function
[DllImport(DLLNAME, EntryPoint = "mclCreateSimpleFunctionHandle", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
private static extern IntPtr _mclCreateSimpleFunctionHandle(MCRInteropDelegate fctn);

Explanation

MarshalAs attribute indicates to marshal SomeTime*[] as a LPArray of IntPtr, where the size of the array is contained by function's parameter at the zero-based index SizeParamIndex

CitizenInsane
  • 4,755
  • 1
  • 25
  • 56