Getting a UTF-8 encoded String from a Rust DLL in C#
我发现了很多关于C中rust dll实现的US-ANSI字符串的信息,但这并不能解决UTF-8编码字符串的任何问题。
例如,
锈病
1 2 3 4 5 6 7 8 9 10 | use std::os::raw::c_char; use std::ffi::CString; #[no_mangle] pub extern fn string_test() -> *mut c_char { let c_to_print = CString::new("Br?tchen") .expect("CString::new failed!"); let r = c_to_print; r.into_raw() } |
C.*
1 2 3 4 5 6 7 8 9 10 11 12 13 | [DllImport(@"C:\Users\User\source epos\testlib\target\debug\testlib.dll")] private static extern IntPtr string_test(); public static void run() { var s = string_test(); var res = Marshal.PtrToStringAnsi(s); // var res = Marshal.PtrToStringUni(s); // var res = Marshal.PtrToStringAuto(s); // Are resulting in: ????n Console.WriteLine(res); // prints"Br??tchen", expected"Br?tchen" } |
我如何获得想要的结果?
我不认为这是如何用C将字符串转换为UTF-8的副本?因为它的回答方式与
多亏了@e_net4的评论,我建议阅读Rust FFI的综合信息,我得到了一个相当复杂但有效的答案。
我想我必须重写我正在使用的类。此外,我正在使用libc库和
卡莫尔
1 2 3 4 5 6 7 8 9 10 11 | [package] name ="testlib" version ="0.1.0" authors = ["John Doe <[email protected]>"] edition ="2018" [lib] crate-type = ["cdylib"] [dependencies] libc ="0.2.48" |
钢骨混凝土
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | extern crate libc; use libc::{c_char, uint32_t}; use std::ffi::{CStr, CString}; use std::str; // Takes foreign C# string as input, converts it to Rust String fn mkstr(s: *const c_char) -> String { let c_str = unsafe { assert!(!s.is_null()); CStr::from_ptr(s) }; let r_str = c_str.to_str() .expect("Could not successfully convert string form foreign code!"); String::from(r_str) } // frees string from ram, takes string pointer as input #[no_mangle] pub extern fn free_string(s: *mut c_char) { unsafe { if s.is_null() { return } CString::from_raw(s) }; } // method, that takes the foreign C# string as input, // converts it to a rust string, and returns it as a raw CString. #[no_mangle] pub extern fn result(istr: *const c_char) -> *mut c_char { let s = mkstr(istr); let cex = CString::new(s) .expect("Failed to create CString!"); cex.into_raw() } |
C级
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | using System; using System.Text; using System.Runtime.InteropServices; namespace Testclass { internal class Native { [DllImport("testlib.dll")] internal static extern void free_string(IntPtr str); [DllImport("testlib.dll")] internal static extern StringHandle result(string inputstr); } internal class StringHandle : SafeHandle { public StringHandle() : base(IntPtr.Zero, true) { } public override bool IsInvalid { get { return false; } } public string AsString() { int len = 0; while (Marshal.ReadByte(handle,len) != 0) { ++len; } byte[] buffer = new byte[len]; Marshal.Copy(handle, buffer, 0, buffer.Length); return Encoding.UTF8.GetString(buffer); } protected override bool ReleaseHandle() { Native.free_string(handle); return true; } } internal class StringTesting: IDisposable { private StringHandle str; private string resString; public StringTesting(string word) { str = Native.result(word); } public override string ToString() { if (resString == null) { resString = str.AsString(); } return resString; } public void Dispose() { str.Dispose(); } } class Testclass { public static string Testclass(string inputstr) { return new StringTesting(inputstr).ToString(); } public static Main() { Console.WriteLine(new Testclass("Br?tchen")); // output: Br?tchen } } } |
虽然这会保存期望的结果,但我仍然不确定是什么导致了问题提供的代码的错误解码。