How to call an unmanaged C ++ function that allocates an output buffer for returning data in C #?

I have problems with the output parameter of the mshalling C ++ function returning an array of data in C #.

Here is the C ++ declaration:

#define DLL_API __declspec(dllexport)

typedef TPARAMETER_DATA
{
    char        *parameter;
    int     size;
} PARAMETER_DATA;

int DLL_API GetParameters(PARAMETER_DATA *outputData);

The function allocates memory for the char array, puts the data there and returns the number of allocated bytes in the "size" field. Here is my C # declaration:

[StructLayout(LayoutKind.Sequential)]
public struct PARAMETER_DATA
{        
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 50000)]        
    public byte[] data;   // tried also SizeParamIndex = 1 instead of SizeConst

    [MarshalAs(UnmanagedType.I4)]                      
    public int size;
}

[DllImport("thedll.dll", SetLastError = true, ExactSpelling = true)]
public extern static uint GetParameters(ref PARAMETER_DATA outputData); // tried also  'out' parameter

When calling a function in C #, I get an empty structure (size = 0, an empty array). I tried passing the outputData parameter with initializing the data field to a new byte [50000], but the data is not being returned.

DLL ( ) , , . # marshalling ( LPArray, LPString) - . - ?

EDIT:

++ - .

+3
4

, , , , . , .

#. , .

[StructLayout(LayoutKind.Sequential)]
public struct PARAMETER_DATA
{        
    public IntPtr data;   // tried also SizeParamIndex = 1 instead of SizeConst

    [MarshalAs(UnmanagedType.I4)]                      
    public int size;
}

[DllImport("thedll.dll", SetLastError = true, ExactSpelling = true)]
private extern static uint GetParameters(ref PARAMETER_DATA outputData);

public static uint GetParameters(out String result)
{
    PARAMETER_DATA outputData = new PARAMETER_DATA();
    result= Marshal.PtrToStringAnsi(outputData.data, outputData.size );
    Marshal.FreeHGlobal(outputData.data); // not sure about this
}
+1

# ++, ++

typedef TPARAMETER_DATA
{
    char    parameter[50000];
    int     size;
} PARAMETER_DATA;

, , - Marshaling, , - ++.

, , , , - SAFEARRAY. SAFEARRAY COM API, VB ( ). http://msdn.microsoft.com/en-us/library/ms221145.aspx

SAFEARRAY , . , ++, , .

, , ( , , SAFEARRAY )

typedef TPARAMETER_DATA
{
    SAFEARRAY * parameter;
    int         size; // I think this is redundant.
}

++ ,

SAFEARRAY * psa = SafeArrayCreateVector(VT_UI1, 0, 50000);
if ( ! psa)
    return E_OUTOFMEMORY;

HRESULT hr = SafeArrayLock(psa);
if (FAILED(hr))
{
    SafeArrayDestroy(psa);
    return hr;
}

CopyMemory(psa->pvData, mydataptr, 50000);
SafeArrayUnlock(psa);

PARAMETER_DATA pda = {psa, 50000};

#

[StructLayout(LayoutKind.Sequential)]
public struct PARAMETER_DATA
{        
    [MarshalAs(UnmanagedType.SafeArray)]        
    public byte[] data; // I used System.Array here, but I think byte[] is OK

    [MarshalAs(UnmanagedType.I4)]                      
    public int size;
}
0

, ? LPArray SizeParamIndex = 1

[StructLayout (LayoutKind.Sequential)]
public struct PARAMETER_DATA
{
  [MarshalAs (UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1, SizeParamIndex = 1)]
  public byte [] data; 

  [MarshalAs (UnmanagedType.I4)]
  public int size;
}
0
    For you reference, I use LayoutKind.Explicit and FieldOffset, and ignore ArraySubType in my project.

    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size=50004)]
    public struct PARAMETER_DATA
    {
        [FieldOffset(0)]
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50000)]
        public byte [] data;

        [FieldOffset (50000)]
        [MarshalAs (UnmanagedType.I4)]
        public int size;
    }

0
source

Source: https://habr.com/ru/post/1731515/


All Articles