Marshal wchar_t ***从C ++到C#作为out参数?

时间:2018-02-13 13:08:29

标签: c# c++ marshalling

我在dll中有这些功能:

DWORD getTypes(const char* const i_formName, const char* const i_fieldName, wchar_t*** i_output, int* i_size)
{
    try
    {
        std::vector<std::wstring> i_temp;
        multilanguage.getTypes(i_formName, i_fieldName, i_temp);
        *i_size = i_temp.size();
        *i_output = new wchar_t *[*i_size];
        for (int i = 0; i < *i_size; ++i)
        {
            *i_output[i] = new wchar_t[i_temp[i].length() + 1];
            wcscpy_s(*i_output[i], i_temp[i].length() + 1, i_temp[i].c_str());
        }

        return 0;
    }
    catch (MultilanguageException & e)
    {
        return e.getErr();
    }
}

void FreeString(wchar_t ** i_output)
{
    if (NULL != (*i_output))
        delete[](*i_output);
}

这些函数有效,因为如果我在C ++程序中使用它们,我会得到预期的结果。

不幸的是我需要从C#程序中调用这些函数。我用以下方式包装了这些函数:

[DllImport("multilanguage_c.dll", EntryPoint = "getTypes", CallingConvention = CallingConvention.Cdecl)]
private static extern UInt32 _getTypes([In] string i_formName, 
                                       [In] string i_fieldName, 
                                       out IntPtr i_output, ref int size);

[DllImport("multilanguage_c.dll", EntryPoint = "FreeString", CallingConvention = CallingConvention.Cdecl)]
private static extern void _FreeString(ref IntPtr i_output);

static public string[] getTypes(string i_formName, string i_fieldName)
{
    IntPtr i_result = IntPtr.Zero;
    int size = 0;
    IntPtr stringSize = IntPtr.Zero;
    UInt32 err = _getTypes(i_formName, i_fieldName, out i_result, ref size);
    if (0 != err)
    {
        ExceptionHandler.ExcpetionThrower(err);
    }
    string[] ManagedStrArray = null;
    MarshalUnmananagedStrArray2ManagedStrArray(i_result, size, out ManagedStrArray);
    return ManagedStrArray;
}

static private void MarshalUnmananagedStrArray2ManagedStrArray(IntPtr pUnmanagedStringArray, // Pointer to an array of unmanaged WCHAR pointers.
                                                               int StringCount,  // The total number of WCHAR*s in pUnmanagedStringArray.
                                                               out string[] ManagedStringArray  // Receipient of the array of managed strings.
                                                               )
{
        // First allocate an array of IntPtrs.
        IntPtr[] pIntPtrArray = new IntPtr[StringCount];
        // Also allocate an array of managed strings using
        // the ManagedStringArray parameter.
        ManagedStringArray = new string[StringCount];

        // Copy the WCHAR*s from pUnmanagedStringArray to 
        // the array of IntPtrs (pIntPtrArray).
        Marshal.Copy(pUnmanagedStringArray, pIntPtrArray, 0, StringCount);

        // Then, one by one, convert each of the WCHAR*s 
        // inside the pIntPtrArray array into a managed string.
        for (int i = 0; i < StringCount; i++)
        {
            ManagedStringArray[i] = Marshal.PtrToStringAuto(pIntPtrArray[i]);
            _FreeString(ref pIntPtrArray[i]);
        }

        // Finally, free the entire buffer of unmanaged
        // WCHAR*s.
        _FreeString(ref pUnmanagedStringArray);
}

在函数MarshalUnmananagedStrArray2ManagedStrArray中,如果StringCount大于1,则在ManagedStringArray[i] = Marshal.PtrToStringAuto(pIntPtrArray[i]);的第二次尝试时,我会收到以下异常:

  

未处理的类型&#39; System.AccessViolationException&#39;发生在mscorlib.dll

我还试着评论_FreeString(ref pIntPtrArray[i]);行,认为_FreeString函数做错了什么但没有任何改变。非常感谢任何帮助!

0 个答案:

没有答案