Calling Rust from C#
Tags: rust, csharp, dll, struct
Published: 2017-10-02 20:43:08

---
title: Calling Rust from C#
published: true
description: A guide for calling a rust DLL from C# 
tags: Rust, csharp, DLL, Struct
---

#Intro
This is a guide for creating a Rust DLL and calling it from C#. We will cover native return values as well as structs. This guide assumes a windows environment, and also assumes that you have installed rust and set up a c# development environment.

##Rust Project Setup and Dependencies
It's pretty simple to create a rust library and get it to compile into a DLL. First, navigate to the folder where you want your project and run the following command:

`cargo new cs_call_rst`

This will create a new folder named cs_call_rust, and initilize it with a 'src' folder and a cargo.toml file. We can build our new project by changing into the newly created `cs_call_rust` folder and running:

`cargo build`

After running this command, you'll notice that there is now a new folder named `target` and it contains a folder named `debug` and in it are the output of our build. However, there's a problem, we didn't build a dll, we built a .rlib file. To tell the rust compiler to create a dll, open up `cargo.toml` and make it look like the following:

```
[package]
name = "cs_call_rst"
version = "0.1.0"
authors = ["Jeremy Mill <jeremymill@gmail.com>"]

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

[dependencies]

```

The `[package]` section tells the compiler some metadata about the package we're building, like who we are and what version this is. The next section, `[lib]` is where we tell the compiler to create a DLL, and name it 'our_rust'. When you run `cargo build` again, you should now see `our_rust.dll` in the output directory. 

##First external rust function
Now that we've got our project all set up, lets add our first rust function, then call it from c#. Open up `lib.rs` and add the following function:

```rust
#[no_mangle]
pub extern fn add_numbers(number1: i32, number2: i32) -> i32 {
    println!("Hello from rust!");
    number1 + number2
}
```

The first line, `#[no_mangle]` tells the compiler to keep the name `add_numbers` so that we can call it from external code. Next we define a public, externally available function, that takes in two 32 bit integers, and returns a 32 bit integer. The method prints a 'hello world'  and returns the added numbers. 

Run `cargo build` to build our DLL, because we'll be calling this function in the next step.

##C# project setup
I'm going to make the assumption that you're using visual studio for c# development, and that you already have a basic knowledge of c# and setting up a project. So, with that assumption, go ahead and create a new c# console application in visual studio. I'm naming mine `rust_dll_poc`.

Before we write any code, we need to add our DLL into our project. Right click on our project and select `add -> existing item -> our_rust.dll`. Next, in the bottom right 'properties' window (with the dll highlighted), make sure to change 'Copy Output Directory' from 'Do not copy' to 'Copy always'. This makes sure that the dll is copied to the build directory which will make debugging MUCH easier. Note, you will need to redo this step (or script it) with every change you make to the DLL. 

Next, add the following using statement to the top of our application:

```c#
using System.Runtime.InteropServices;
```

This library will let us load our DLL and call it. 

Next add the following private instance variable `Program` class:

```c#
[DllImport("our_rust.dll")]
private static extern Int32 add_numbers(Int32 number1, Int32 number2);
```

This allows us to declare that we're importing an external function, named add_numbers, it's signature, and where we're importing it from. You may know that c# normally treats the `int` as a 32 bit signed integer, however, when dealing with foreign functions, it is MUCH safer to be explicit in exactly what data type you're expecting on both ends, so we declared, explicitly, that we're expecting a 32 bit signed integer returned, and that the inputs should be 32 bit signed integers. 

Now, lets, call the function. Add the following code into `main`:

```c#
static void Main(string[] args)
{
    var addedNumbers = add_numbers(10, 5);
    Console.WriteLine(addedNumbers);
    Console.ReadLine();
}

```

You should see the following output:

```
Hello from rust!
15
```

Note!: If you see a `System.BadImageFormatException` When you try and run the above code, you (probably) have a mismatch in the build targets for our rust dll, and our c# application. C# and visual studio build for x86 by default, and rust-init will install a 64 bit compiler by default for a 64 bit architecture. You can build a 64 bit version of our c# application by following the steps outlined [here](https://msdn.microsoft.com/en-us/library/ms185328.aspx)

##Returning a simple struct
Ok, awesome, we now know how to return basic values. But how about a struct? We will start with a basic struct that requires no memory allocation. First, lets define our struct, and a method that returns an instance of it in `lib.rs` by adding the following code:

```rust
#[repr(C)]
pub struct SampleStruct {    
    pub field_one: i16,
    pub field_two: i32,
}

#[no_mangle]
pub extern fn get_simple_struct() -> SampleStruct {
    SampleStruct {
        field_one: 1,
        field_two: 2
    }
}

```
Now we need to define the corresponding struct in c# that matches the rust struct, import the new function, and call it! Add the following into our `program.cs` file:

_Edit: As Kalyanov Dmitry pointed out, I missed adding a Struct Layout annotation. This annotation ensures that the C# compiler won't rearrange our struct and break our return values_


```c#
namespace rust_dll_poc
{
    [StructLayout(LayoutKind.Sequential)]
    public struct SampleStruct
    {
        public Int16 field_one;
        public Int32 field_two;
    }

    class Program
    {
        [DllImport("our_rust.dll")]
        private static extern SampleStruct get_simple_struct();
        ...
```

and then we call it inside of `Main`:

```c#
static void Main(string[] args)
{
    var simple_struct = get_simple_struct();
    Console.WriteLine(simple_struct.field_one);
    Console.WriteLine(simple_struct.field_two);
    ....
```

You should see the following output (you remembered to move your updated DLL into the project directory, right?)

```
1
2
```

##What about Strings?
Strings are, in my opinion, the most subtly complicated thing in programming. This is doubly true when working between two different languages, and even MORE true when dealing with an interface between managed and unmanaged code. Our strategy will be to store static string onto the heap and return a `char *`in a struct to the memory address. We will store this address in a static variable in rust to make deallocation easier. We will also define a function `free_string` which, when called by c#, will signal to rust that we're done with the string, and it is OK to deallocate that memory. It's worth noting here that this is VERY oversimplified and most definitely NOT thread safe. How this should 'actually' be implemented is highly dependent on the code you're writing. 

Lets first add a using statement to the required standard libraries:

```rust
//external crates
use std::os::raw::c_char;
use std::ffi::CString;
```

Next we're going to create a mutable static variable which will hold the address of the string we're putting onto the heap:

```rust
static mut STRING_POINTER: *mut c_char = 0 as *mut c_char;
```

It's important to know that anytime we access this static variable, we will have the mark the block as unsafe. More information on why can be found [here](https://doc.rust-lang.org/book/first-edition/const-and-static.html). 

Next we're going to edit our struct to have a c_char field:

```rust
#[repr(C)]
pub struct SampleStruct {    
    pub field_one: i16,
    pub field_two: i32,
    pub string_field: *mut c_char,
}
```

Now, lets create two helper methods, one that stores strings onto the heap and transfers ownership (private) and one that frees that memory (public). Information on these methods, and REALLY important safety considerations can be found [here](https://doc.rust-lang.org/std/ffi/struct.CString.html#method.from_raw)

```rust
fn store_string_on_heap(string_to_store: &'static str) -> *mut c_char {
    //create a new raw pointer
    let pntr = CString::new(string_to_store).unwrap().into_raw();
    //store it in our static variable (REQUIRES UNSAFE)
    unsafe {
        STRING_POINTER = pntr;
    }
    //return the c_char
    return pntr;
}

#[no_mangle]
pub extern fn free_string() {
    unsafe {
        let _ = CString::from_raw(STRING_POINTER);
        STRING_POINTER = 0 as *mut c_char;
    }
}
```

Now, lets update `get_simple_struct` to include our code:


```rust
#[no_mangle]
pub extern fn get_simple_struct() -> SampleStruct {
    let test_string: &'static str = "Hi, I'm a string in rust";
    SampleStruct {
        field_one: 1,
        field_two: 2,
        string_field: store_string_on_heap(test_string),
    }
}
```

Awesome! Our rust code is all ready! Lets edit our C# struct next. We will need to use the IntPtr type for our string field. We're supposed to be able to use the 'MarshalAs' data attributes to automatically turn this field into a string, but I have not been able to make it work.

```c#
[StructLayout(LayoutKind.Sequential)]
public struct SampleStruct
{
    public Int16 field_one;
    public Int32 field_two;
    public IntPtr string_field;
}
```

and if we add the following line into main below the other Console.WriteLines, we should be able to see our text:

```c#
Console.WriteLine(Marshal.PtrToStringAnsi(simple_struct.string_field));
```

finally, we need to tell rust that it's OK to deallocate that memory, so we need to import the `free_string` method just like we did with the other methods and call it `free_string(); 

The output should like this this:

```
1
2
Hi, I'm a string in rust
```

I hope all of this was useful to you! The complete c# can be found [here](https://gist.github.com/LivingInSyn/3f80d2bef2d7b9c7aa8e1efa277f80db) and the complete rust code can be found [here](https://gist.github.com/LivingInSyn/81395282fdeeb8257b60ff279e2a39b4). Good luck, and happy coding!