我有一些使用它的非托管C ++动态库和C#GUI应用程序。我需要传递一个指向带有嵌入式缓冲区和一些集成元数据成员的结构的指针。在C#端分配给C ++库的结构。然后库填充它,返回到C#应用程序,应用程序以某种方式使用它,最后释放。

我的第一种方法是使用StringBuilder作为嵌入式字符串缓冲区,但是我在运行时收到一个异常,该异常表明不允许将StringBuilder用作结构成员。我也得到了建议使用适当缓冲大小预先初始化的字符串。我已经尝试过这种方法,但是似乎无法在C ++部分上修改通过字符串传递的bufefr。这样对吗?

// C++
typedef struct SomeStruct{
    wchar_t* stringBuffer; // buffer
    uint64_t size;  // some additional integral fields
    int64_t  mTime; // some additional integral fields
};

// Native library API method
MYCDLL_API uint8_t __stdcall getSomeStructures(uint32_t index,
                                              SomeStruct* struct,
                                              uint64_t stringBufferSize);


// C# part
[DllImport(myLibraryname, CallingConvention = CallingConvention.StdCall)]
static extern RetCode getSomeStructures(UInt32 index,
                                        ref SomeStruct someStruct,
                                        UInt64 stringBufferSize);


该任务如何解决?如前所述,我需要传递对具有嵌入式可修改字符缓冲区的结构的引用,从C#到C ++。

最佳答案

我会将该字段声明为IntPtr

struct SomeStruct
{
    IntPtr stringBuffer;
    ulong size;
    long mTime;
}


声明这样的功能:

[DllImport(myLibraryname)]
static extern byte getSomeStructures(
    uint index,
    ref SomeStruct someStruct,
    ulong stringBufferSize
);


使用Marshal.AllocHGlobal()Marshal.FreeHGlobal()分配和释放缓冲区。使用Marshal.PtrToStringUni()从指针创建一个字符串。

SomeStruct someStruct;
someStruct.stringBuffer = Marshal.AllocHGlobal(1024);
try
{
    // initialize the rest of someStruct
    byte retval = getSomeStructures(index, ref someStruct, 1024);
    // check retval for errors
    string str = Marshal.PtrToStringUni(someStruct.stringBuffer);
}
finally
{
    Marshal.FreeHGlobal(someStruct.stringBuffer);
}


我假设名为size的参数是字节大小。如果实际上是一个长度,则需要考虑字符宽度为16个字节的情况,并且应该将参数名称更改为长度而不是大小。

10-07 19:01
查看更多