元帅使用P/Invoke从C#到C代码的一系列字符串

Marshal an array of strings from C# to C code using p/invoke

本文关键字:代码 字符串 一系列 Invoke      更新时间:2023-10-16

我需要将C#字符串数组传递到C代码

示例C代码

void print_string_array(const char** str_array, int length){
    for (int i = 0; i < length; ++i) {
        printf("Sting[%l] = %sn", i, str_array[i]);
    }
}

c#我尝试过(这不起作用)

string foo[] = {"testing", "one", "two", "three"};  
print_string_array(foo, foo.Length);
[DllImport(my_C_dll, CharSet = CharSet.Ansi)]
private static extern void print_string_array([In][MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] string[] sa, int length);

系统失败。System.AccessviolationException:尝试读取或写下受保护的内存。这通常表明其他内存已损坏。

我也尝试过(这也没有起作用)

string[] foo = {"testing", "one", "two", "three"};  
IntPtr[] s_array = new IntPtr[foo.Length];
for(int i = 0; i < foo.Length; ++i) 
{
    s_array[i] = Marshal.StringToCoTaskMemAnsi(foo[i])
}
print_string_array( s_array, s_array.Length);
[DllImport(my_C_dll, CharSet = CharSet.Ansi)]
private static extern void print_string_array(IntPtr[] sa, int length);

这也因

而失败
System.AccessViolationException
System.AccessViolationException : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

有人知道如何将一系列字符串从C#传递到C?


更新:David Heffernan的建议添加了错误消息。将size_t更改为c代码中的int,因为它不会影响我要做的事情。仍然会遇到相同的错误。

您可以简单地在C#中声明您的功能:

[DllImport(my_C_dll, CallingConvention=CallingConvention.Cdecl)]
static extern void print_string_array([In] string[] str_array, IntPtr length);

编写,您的C 代码似乎将使用cdecl调用约定。因此,您可能需要进行C#声明匹配。我怀疑这是您面临的主要问题。

还请注意,您用于length参数的size_t在32位过程中为32位,在64位过程中宽64位。因此,正确的C#类型是IntPtr。我个人会在C 和C#代码中宣布它为int


最后一个建议。当您遇到失败时,将错误消息包括在问题中。我怀疑您的第一个代码失败了此错误:

调用pinvoke函数'myapp!myapp.program.program :: print_string_array'的堆栈不平衡。

,如果您将其包括在问题中,那将是一个很大的帮助。

您的第二次尝试非常接近。尝试以下内容:

string[] foo = {"testing", "one", "two", "three"};  
IntPtr[] s_array = new IntPtr[foo.Length];
for(int i = 0; i < foo.Length; ++i) 
{
    s_array[i] = Marshal.StringToHGlobalAnsi(foo[i])
}
GCHandle gH = GCHandle.Alloc(s_array, GCHandleType.Pinned);
print_string_array( gH.AddrOfPinnedObject(), s_array.Length);
gH.Free();
for(int i = 0; i < foo.Length; ++i) 
{
    Marshal.FreeHGlobal(s_array[i])
}
[DllImport(my_C_dll, CharSet = CharSet.Ansi)]
private static extern int print_string_array(IntPtr sa, int length);