将字符串数组从c#传递到c++;-内存管理

将字符串数组从c#传递到c++;-内存管理,c#,c++,dll,interop,C#,C++,Dll,Interop,在我的代码中,我有一个接受字符串数组的c DLL: void Helper::ProcessEvent(事件\记录事件,wchar\u t**OutPutFormattedData) 我用以下代码调用它: [DllImport("Helper.dll", EntryPoint = "ProcessEvent")] internal static extern uint ProcessEvent( [In, Out] ref EVENT_RECORD pE

在我的代码中,我有一个接受字符串数组的c DLL: void Helper::ProcessEvent(事件\记录事件,wchar\u t**OutPutFormattedData)

我用以下代码调用它:

[DllImport("Helper.dll", EntryPoint = "ProcessEvent")]
    internal static extern uint ProcessEvent(
        [In, Out] 
        ref EVENT_RECORD pEvent,
        [In, Out] 
        [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] ref string[] pResult);
< C++代码>这里是我用来填充数组的主要代码:

for(int i=0;i<list.Size;i++)
{
    EventWrapperClass *EWC = new EventWrapperClass();
    EWC = list.Events[i];
    OutPutFormattedData[i] = new wchar_t [wcslen(HelperFormatMessage(L"%s: %s\n",EWC->GetProperyName(),EWC->GetProperyValue()))+1];
    wcscpy(OutPutFormattedData[i] ,HelperFormatMessage(L"%s: %s\n",EWC->GetProperyName(),EWC->GetProperyValue()));
我有两个问题:

为什么在调用C++函数后检查C数组中的数组的值,我看到它是空的(数据存在于C++代码中,我调试了它)?< /p> <> >如果我在C++ DLL中分配内存,我需要释放它吗?在C++或C语言中?

非常感谢

编辑:

c++的标志:

static __declspec(dllexport) void ProcessEvent(PEVENT_RECORD pEvent, wchar_t** OutPutFormattedData);

我不知道问题1,但知道问题2:

for(int i=0;i<list.Size;i++) 
{
    EventWrapperClass *EWC = new EventWrapperClass();
    EWC = list.Events[i]; 
    ...
}
因为不需要创建新对象


然后,如果不再需要该事件,请在循环中删除它,并确保随后清除该列表。只有当您100%确定不再需要该活动时,才可以执行此操作。这很容易产生悬空指针

我不知道问题1,但知道问题2:

for(int i=0;i<list.Size;i++) 
{
    EventWrapperClass *EWC = new EventWrapperClass();
    EWC = list.Events[i]; 
    ...
}
因为不需要创建新对象

然后,如果不再需要该事件,请在循环中删除它,并确保随后清除该列表。只有当您100%确定不再需要该活动时,才可以执行此操作。这很容易产生悬空指针

如果在C#中分配(托管或非托管)缓冲区(或数组或字符),然后填写C++:
1.在C#中解除分配。
2.缓冲区应为[in],且在C#签名中没有ref或out。

如果在C++中分配缓冲区(或字符数组):
1.将缓冲区作为[out]out IntPtr传递。
2.将Debug定位方法添加到C++签名中。 3.将缓冲区复制到C#缓冲区或新字符串
4.用C++语言调用C++中的C++ DeloLoad 您可以使用System.Runtime.InteropServices.Marshal在C#中分配/取消分配未管理的内存。不要使用释放在.NET外部分配的内存

System.Runtime.InteropServices.Marshal还可用于将内存从外部缓冲区(IntPtr)复制到.NET缓冲区或字符串

将导入的方法标记为private,并使用使用.NET参数的public(或protected或internal)方法包装(例如,使用System.Runtime.InteropServices.Marshal.Copy并调用外部解除分配的方法)

C++:

C#:

如果在C#中分配(托管或非托管)缓冲区(或数组或字符),然后填写C++:
1.在C#中解除分配。
2.缓冲区应为[in],且在C#签名中没有ref或out。

如果在C++中分配缓冲区(或字符数组):
1.将缓冲区作为[out]out IntPtr传递。
2.将Debug定位方法添加到C++签名中。 3.将缓冲区复制到C#缓冲区或新字符串
4.用C++语言调用C++中的C++ DeloLoad 您可以使用System.Runtime.InteropServices.Marshal在C#中分配/取消分配未管理的内存。不要使用释放在.NET外部分配的内存

System.Runtime.InteropServices.Marshal还可用于将内存从外部缓冲区(IntPtr)复制到.NET缓冲区或字符串

将导入的方法标记为private,并使用使用.NET参数的public(或protected或internal)方法包装(例如,使用System.Runtime.InteropServices.Marshal.Copy并调用外部解除分配的方法)

C++:

C#:


莫蒂,C++的签名是什么?要添加的编辑问题。它上面有DllExport吗?这是c++的标志:static\u declspec(DllExport)void ProcessEvent(PEVENT\u RECORD PEVENT,wchar\u t**OutPutFormattedData)@莫蒂,C++的签名是什么?编辑问题要添加。它上面有DllExport吗?这是c++的标志:static\u declspec(DllExport)void ProcessEvent(PEVENT\u RECORD PEVENT,wchar\u t**OutPutFormattedData);
EventWrapperClass *EWC = list.Events[i];
int ProcessEvent(PEVENT_RECORD eventData, wchar_t*& message)
{
    // example code
    message = new wchar_t[100];
    if (message == 0)
        return 1;
}

void DeallocateString(wchar_t* array)
{
    delete[] arrayPtr;
}

wchar_t* ErrorCodeToMessage(int errorCode)
{
    switch (errorCode)
    {
        case 0: return 0; // return NULL pointer
        case 1: return L"No!!!";
        default: return L"WTF!?";
    }
}
[DllImport("Helper.dll", EntryPoint = "ProcessEvent")]
private static extern uint ProcessEventExternal(
    [In, Out] ref EventData eventData,
    [In, Out, MarshalAs(UnmanagedType.SysInt))] ref IntPtr resultMessages);

[DllImport("Helper.dll", EntryPoint = "DeallocateString")]
private static extern voidDeallocateStringExternal(
    [In, MarshalAs(UnmanagedType.SysInt)] IntPtr arrayPtr);

[DllImport("Helper.dll", EntryPoint = "ErrorCodeToMessage")]
private static extern
    [return: MarshalAs(UnmanagedType.SysInt)] IntPtr
    ErrorCodeToMessageExternal(int errorCode);

public string ProcessEvent(ref EventData eventData)
{
    IntPtr resultPtr = IntPtr.Zero;
    uint errorCode = ProcessEventExternal(eventData, ref resultPtr);

    if (errorCode != null)
    {
        var errorPtr = ErrorCodeToMessageExternal(errorCode);

        // returns constant string - no need to deallocate
        var errorMessage = Marshal.PtrToStringUni(errorPtr);

        throw new ApplicationException(errorMessage);
    }

    var result = Marshal.PtrToStringUni(resultPtr);
    ExternalDeallocate(resultPtr);

    return result;
}