C#调用Rust dll测试

Posted henreash

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#调用Rust dll测试相关的知识,希望对你有一定的参考价值。

C#调用Rust dll,重点在于字符串传递,其他类型比较自然。可以给函数传递json字符串,在传出json字符串,两端通过json序列化、反序列化,可以方便处理参数数据。也可以传递不带字符串的结构体(结构体内含字符串的情况没有验证)。

小的结构体实例序列号反序列化速度很快,C#端序列号后,调用10000次Rust端函数,执行反序列化后修改对象成员,再次序列号,仅耗时36ms。开发中使用字符串传递参数和传出处理结果,完全可行。

没什么难点,直接上码:

Rust:

use std::thread;
use libc::c_char, uint32_t;
use std::ffi::CStr, CString;
use std::str;
extern crate serde;
extern crate serde_json;

#[macro_use] //引入serde_derive中的宏
extern crate serde_derive;

#[derive(Debug, Serialize, Deserialize)]
struct Address
    street: String,
    city: String,


#[derive(Debug, Serialize, Deserialize)]
struct Person 
    name: String,
    age: u8,
    address: Address,
    phones: Vec<String>,


impl Person
    fn default() -> Self 
        Person
            name: "zhangsan".to_string(),
            age: 18u8,
            address: Address
                street: "East nanjing road".to_string(), 
                city: "shanghai".to_string(),
            ,
            phones: vec!["12345678".to_string(), "23456789".to_string()],
        
    

#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Kind 
    Ok,

    Done,
    BufferTooSmall,

    ArgumentNull,
    InternalError,


#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DbResult 
    kind: Kind,
    id: u32,


#[no_mangle]
pub extern fn GetDbResult() -> DbResult
    DbResult
        kind: Kind::Done,
        id: 100u32,
    


#[no_mangle]
pub extern fn process()
    let handles: Vec<_> = (0..10).map(|_|
        thread::spawn(||
            let mut x = 0;
            for _ in(0..5_000_000)
                x+=1
            
            x
        )
    ).collect();

    for h in handles
        println!("thread finished with count=", 
        h.join().map_err(|_| "Could not join a thread!").unwrap());
    
    println!("done!");


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)


#[no_mangle]
pub extern fn free_string(s: *mut c_char)
    unsafe
        if s.is_null()return
        CString::from_raw(s)
    ;


#[no_mangle]
pub extern fn result(istr: *const c_char) -> *mut c_char
    let s = mkstr(istr);

    let values: Person = serde_json::from_str(&s).unwrap();
    println!("Hello,,welcome to rust world,you name change to -rust!",values.name,values.name);
    let values2 = Personname:values.name + "-rust", ..values;
    let json = serde_json::to_string_pretty(&values2).unwrap();
    let cex = CString::new(json).expect("Failed to create CString!");

    cex.into_raw()

Cargo.toxml 

[package]
name = "rust_code"
version = "0.1.0"
authors = ["henreash <nmhys@126.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
libc = "0.2.48"
serde = "*"
serde_derive = "*"
serde_json = "*"

[lib]
name="rust_code"
crate-type=["dylib"]

C#代码:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SharpProcessor

    public partial class Form1 : Form
    
        [DllImport("rust_code.dll")]
        internal static extern void process();

        [DllImport("rust_code.dll")]
        internal static extern void free_string(IntPtr str);

        [DllImport("rust_code.dll")]
        internal static extern StringHandle result(string inputs);

        [DllImport("rust_code.dll")]
        internal static extern DbResult GetDbResult();

        public Form1()
        
            InitializeComponent();
        

        private Person GetTestData()
        
            return new Person 
                Name = "zhangsan",
                Age = 18,
                Addresss = new Address 
                    Street = "East nanjing road",
                    City = "Shanghai",
                ,
                Phones = new List<string> 
                    "12345678",
                    "23456789",
                
            ;
        

        private void button1_Click(object sender, EventArgs e)
        
            //process();
            //var str = "hello world, i come form c sharp";
            var str = JsonConvert.SerializeObject(GetTestData());
            using (var str2 = result(str))
            
                MessageBox.Show(str2.AsString());
            
            var dbResult = GetDbResult();
            MessageBox.Show($"dbResult._result  dbResult._id");
        
    


    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()
        
            Form1.free_string(handle);
            return true;
        
    

    public class Person
    
        [JsonProperty("name")]
        public string Name  get; set; 
        [JsonProperty("age")]
        public byte Age  get; set; 
        [JsonProperty("address")]
        public Address Addresss  get; set;  = new Address();
        [JsonProperty("phones")]
        public List<string> Phones  get; set;  = new List<string>();
    

    public class Address
    
        [JsonProperty("street")]
        public string Street  get; set; 
        [JsonProperty("city")]
        public string City  get; set; 
    

    [StructLayout(LayoutKind.Sequential)]
    public struct DbResult
    
        public enum Kind : uint
        
            Ok,

            Done,
            BufferTooSmall,

            ArgumentNull,
            InternalError
        

        public readonly Kind _result;
        public readonly uint _id;

        public bool IsSuccess()
        
            return _result == Kind.Ok || _result == Kind.Done;
        

        public bool IsDone()
        
            return _result == Kind.Done;
        

        public bool IsBufferTooSmall()
        
            return _result == Kind.BufferTooSmall;
        
    

运行结果:

耗时测试(首次执行耗时稍长,后面在执行,稳定在36ms左右):

        private void button1_Click(object sender, EventArgs e)
        
            var stop = new Stopwatch();
            stop.Start();
            var str = JsonConvert.SerializeObject(GetTestData());
            for (var i = 0; i < 10000; i++)
            
                using (var str2 = result(str))
                
                
            
            stop.Stop();
            MessageBox.Show(stop.ElapsedMilliseconds.ToString());
        

以上是关于C#调用Rust dll测试的主要内容,如果未能解决你的问题,请参考以下文章

VS2017下创建C++动态库导出符合并完成调用测试(DLL可供C#调用)

VS2017下创建C++动态库导出符合并完成调用测试(DLL可供C#调用)

C#调用C++写的DLL总结

从 C# windows 应用程序调用 C dll 会导致 svchost.exe 崩溃

C#调用C++ DLL类方法

PB调用C#编写的DLL