我发现很多有关C#中Rust DLL实现的US-ANSI字符串的信息,但这不能解决UTF-8编码的字符串的任何问题。
例如,"Brötchen"
一旦在C#中被调用,就会得到"Brötchen"
。
铁锈
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#
[DllImport(@"C:\Users\User\source\repos\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"
}
如何获得所需的结果?
我不认为这是How can I transform string to UTF-8 in C#?的副本,因为它的答案与Marshal.PtrToStringAuto(s)
和Marshal.PtrToStringUni(s)
相同。
答案 0 :(得分:1)
感谢@E_net4's comment建议阅读Rust FFI Omnibus,我得出的答案相当复杂,但是可以解决问题。
我认为我必须重写正在使用的类。此外,我正在使用libc库和CString
。
Cargo.toml
[package]
name = "testlib"
version = "0.1.0"
authors = ["John Doe <jdoe@doe.com>"]
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
libc = "0.2.48"
src / lib.rs
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#类
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
}
}
}
尽管这会存储所需的结果,但我仍然不确定是什么导致问题提供的代码中的解码错误。