具有嵌入式字符串缓冲区的编组结构

时间:2014-07-22 09:59:59

标签: c# c++ interop pinvoke marshalling

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

我的第一种方法是使用StringBuilder作为嵌入式字符串缓冲区,但我在运行时收到一个异常,表示不允许使用StringBuilder作为结构成员。我也建议使用字符串preinited与适当的缓冲区大小。我试过这种方法,但似乎通过字符串传递的bufefr无法在C ++部分修改。是不是?

// 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 ++。

2 个答案:

答案 0 :(得分:1)

我将该字段声明为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个字节的字符,并且您应该将参数名称更改为长度而不是大小。

答案 1 :(得分:0)

尝试使用以下结构声明:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SomeStruct
{
    [MarshalAs(UnmanagedType.LPWStr)]
    public string stringBuffer;
    public UInt64 size;
    public Int64 mTime;
};

[DllImport("Win32Project1.dll", EntryPoint = "GetSomeStructures")]
static extern int GetSomeStructures(
        uint index, ref SomeStruct str, ulong stringBufferSize);

static void Main(string[] args)
{
    var a = new SomeStruct(){
        stringBuffer = "asd",
        size=10,
        mTime = 20
    };



    Console.WriteLine(GetSomeStructures(1, ref a, 1));
}