Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
356 views
in Technique[技术] by (71.8m points)

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

I need to pass an array of C# strings into C code

Example C code

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

C# that I have tried (This did not work)

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

Fails with a System.AccessViolationException System.AccessViolationException : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

I have also tried (This also did not work)

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

This also fails with a

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

Any one know how to pass an array of strings from c# to C?


Update: Added error messages per suggestion from David Heffernan. Change size_t to int in C code since it did not affect what I was trying to do. Still get the same errors.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can simply declare your function in C# like this:

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

As it is written, your C++ code would appear to use the cdecl calling convention. So you may need to make the C# declaration match. I suspect that is the main problem you are facing.

Note also that size_t, which you use for the length parameter is 32 bits wide in a 32 bit process, and 64 bits wide in a 64 bit process. So the correct C# type is IntPtr. Personally I'd declare it to be int in both the C++ and C# code.


One final word of advice. When you encounter failures, include the error messages in your questions. I suspect your first code failed with this error:

A call to PInvoke function 'MyApp!MyApp.Program::print_string_array' has unbalanced the stack.

And if you had included that in the question it would have been a great help.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...