将字符串数组作为缓冲区传递给C++;到C# 我使用了一些非托管C++动态库和C+GUI应用程序。我需要把已知大小的字符串数组传递给C++库,这会填充它。还有最大字符串长度值: // C++ part #define MAX_SOME_STRING_LEN 250; MYDLL_API uint8_t __stdcall getSomeStrings(wchar_t** strings, uint64_t count) { /// populate strings, not more characters then MAX_SOME_STRING_LEN for each string return 0; } // C# part [DllImport("biosec_lib.dll", CallingConvention = CallingConvention.StdCall)] static extern Byte getSomeStrings(string[] providers, UInt64 size); 我希望避免C++库侧的数组内存管理。我通过其他库API调用获得所需的字符串数组大小。然后在C#端分配合适的数组并调用此API方法,传递合适的数组 这是一个好方法吗?有没有更好的办法?在将数组中的每个字符串传递给API方法之前,是否可以为其保留最大字符串长度

将字符串数组作为缓冲区传递给C++;到C# 我使用了一些非托管C++动态库和C+GUI应用程序。我需要把已知大小的字符串数组传递给C++库,这会填充它。还有最大字符串长度值: // C++ part #define MAX_SOME_STRING_LEN 250; MYDLL_API uint8_t __stdcall getSomeStrings(wchar_t** strings, uint64_t count) { /// populate strings, not more characters then MAX_SOME_STRING_LEN for each string return 0; } // C# part [DllImport("biosec_lib.dll", CallingConvention = CallingConvention.StdCall)] static extern Byte getSomeStrings(string[] providers, UInt64 size); 我希望避免C++库侧的数组内存管理。我通过其他库API调用获得所需的字符串数组大小。然后在C#端分配合适的数组并调用此API方法,传递合适的数组 这是一个好方法吗?有没有更好的办法?在将数组中的每个字符串传递给API方法之前,是否可以为其保留最大字符串长度,c#,c++,marshalling,C#,C++,Marshalling,这是一种不同的方法。您应该分配一种“非托管”缓冲区,传递给DLL,然后转换结果并释放缓冲区。这与C语言中的方法完全相同,只是从托管环境调用 DLL的签名类似于: [DllImport("biosec_lib.dll", CallingConvention = CallingConvention.StdCall)] static extern Byte getSomeStrings(IntPtr buffer, UInt64 size); 要从C#调用它,您应该执行以下操作: I

这是一种不同的方法。您应该分配一种“非托管”缓冲区,传递给DLL,然后转换结果并释放缓冲区。这与C语言中的方法完全相同,只是从托管环境调用

DLL的签名类似于:

[DllImport("biosec_lib.dll", CallingConvention = CallingConvention.StdCall)]
static extern Byte getSomeStrings(IntPtr buffer, UInt64 size);
要从C#调用它,您应该执行以下操作:

        IntPtr unmanagedBuffer = Marshal.AllocHGlobal(100);
        // Your Unmanaged Call
        getSomeStrings(unmanagedBbuffer, 100);
        string yourString = Marshal.PtrToStringUni(unmanagedBuffer);
        Marshal.FreeHGlobal(unmanagedBuffer);

如果你不希望应用程序内存泄漏,别忘了打电话给FreeHGlobal。在“try/finally”子句中保护这一点很有趣。

如果您想在托管端使用IntPtr,您可以这样使用:

[DllImport("biosec_lib.dll", CallingConvention = CallingConvention.StdCall)]
static extern Byte getSomeStrings([In][Out] [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] String[] providers, UInt64 count);

问题不在于数组,C代码已经分配了它。问题在于数组元素。你是如何创造它们的?他们需要被释放吗?如果要使用C#程序分配的内存,则需要使用StringBuilder[],并使用具有足够容量的StringBuilder对象初始化。这是有风险的,当wcscpy()调用溢出缓冲区时,太低的容量会导致堆损坏。@HansPassant是的,我想分配它们,稍后在C#端释放。我知道你提到的溢出问题。我应该小心,缓冲区大小是为此提供的。否。count参数表示字符串数组的长度。调用者无法指定每个字符串缓冲区的长度。编写此代码的唯一真正安全的方法是C++代码来分配字符串。这确实需要处理内存管理,调用方必须再次释放字符串。pinvoke封送拆收器将假定您使用了CoTaskMemAlloc(),如果您没有使用,则为kaboom。
SizeConst=1
是否表示我知道编译时的数组大小?正如我在问题中提到的,我在运行时调用API方法时得到这个大小。编译时的已知大小-最大strng长度。不是字符串数组大小。是的,如果使用SizeConst参数,您必须在编译时知道数组大小。我想最好的方法是使用IntPtr。不幸的是,我只知道运行时的数组大小。图书馆电话告诉我它需要多大的阵列。我在整理我的工作,我们也许可以举行一次现场会议。cataktunahan@gmail.com我们可以解决它。谢谢你,我希望我们不需要。看来
StringBuilder
array-using适合我的问题。我会更新问题或写我的答案,如果没有其他人这样做,当完成它。在这种情况下,有可能使用一些RAII类的内存管理包装?这种方法是否适合为每个字符串传递缓冲区数组,而不是单个缓冲区?在C/C++中,以null结尾的字符串是字符数组。这是处理字符串的方式(有不同的方法,但这很流行)。由于使用DLL时需要确定DLL对内存的期望值,因此最安全的方法是发送缓冲区。这就像使用非托管DLL时的“规则”。甚至WindowsAPI也是这样工作的。如果DLL需要返回某些内容,则需要预先分配缓冲区以接收这些内容。甚至structs也是这样工作的。