使用p / invoke从C#到C代码编组一个字符串数组

时间:2012-11-10 00:24:05

标签: c++ .net interop pinvoke marshalling

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

示例C代码

void print_string_array(const char** str_array, int length){
    for (int i = 0; i < length; ++i) {
        printf("Sting[%l] = %s\n", 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失败 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:尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

任何人都知道如何将一个字符串数组从c#传递给C?

编辑: 根据David Heffernam的建议添加了错误消息。 在C代码中将size_t更改为int,因为它不会影响我尝试执行的操作。 仍然会得到同样的错误。

3 个答案:

答案 0 :(得分:4)

您可以在C#中简单地声明您的函数:

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

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

另请注意,用于size_t参数的length在32位进程中为32位宽,在64位进程中为64位宽。所以正确的C#类型是IntPtr。我个人在C ++和C#代码中都声明它是int


最后一句忠告。遇到失败时,请在问题中包含错误消息。我怀疑你的第一个代码失败了这个错误:

  

对PInvoke函数'MyApp!MyApp.Program :: print_string_array'的调用使堆栈失衡。

如果你在问题中包含了它,那将会是一个很大的帮助。

答案 1 :(得分:2)

你的第二次尝试非常接近。请尝试以下方法:

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);

答案 2 :(得分:0)

为什么“print_string_array(IntPtr sa,int length);” 而不是“print_string_array(IntPtr [] sa,int length);” ? print_string_array看看C端是什么? print_string_array(char ** sa,int length); ?

相关问题