Calling Rust from C#

Jeremy Mill on October 02, 2017

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 guid... [Read Full]
markdown guide
 

I followed you article to bind up some common code. But got a problem whit bool always being true. Any thing special whit exposing a function using bool??

 

Yes, I had issues with bools as well, I didn't cover it in the article because it's weird. What I ended up doing was setting them up in c# as a byte and evaluating if it was a 1 or a 0, which SUCKS, but is totally doable. I tried getting a bunch of the marshal-as methods to work, but as of yet, none of them have. if you figure it out, let me know!

example:

rust:

#[repr(C)]
pub struct test {
 pub isbool: bool,
}

c#:

[StructLayout(LayoutKind.Sequential)]
public struct test 
{
    public byte isbool;
}
 

Thanks, it worked. Had the solution of sending and revising a u8. But whit the byte at least i don't have to change anything on the rust side.

Some suggested to use types from libc like c_bool, but i need to get abit better at rust. Have just started out. I'll let you know if i find a good solution

I've been doing rust FFI at work for a few more months since I wrote this post. There's some things that I'll probably need to go back and update when I get the time. c_bool is a possible solution, there's also some shorthand in c# that may end up working, but I'll make sure to let you know if/when I get it working!

 

C# bools are Win32 BOOLs are 32-bit signed integers, for historical reasons.

Still, Marshall as book "should" work, correct?

bool on the Rust side but byte on the C# side, or (better) make a user-defined struct on the C# side, e.g. "ByteBool", that holds a single byte value and implements the conversions to/from System.Boolean.

[StructLayout(LayoutKind.Sequential)]
public struct test
{
public ByteBool isbool;
}

 

Hey, thanks for the post. As you noted, the string handling is not ideal. I suggest you allocate a Box / Vec for the string, pass it to C#. From there, you just copy it into its native String type and call a Rust-defined free_string function. For users who are unexperienced with memory management / unsafety, the additional overhead seems justified for me.

Another minor I've noticed is the unideomatic return in one function (can be skipped at the end) ;)

 

Hey, thanks for the reply. I have a lot more experience with this now than when I wrote this. It definitely needs to be updated, i'll try and get around to it sooner than later

 
 

Don't have a link at hand, but I'd just return the char pointer directly (instead of storing it in a global) and ask for it again in the free function.

 

You should annotate the structs (on the C# side) with [StructLayout(LayoutKind.Sequential)] - otherwise CLR is free to reorder fields or add/remove padding which will break ABI.

 

You're totally correct. I have that in the production code this is modeled after and I forgot it. I'll add it in, thanks!

 

Hey, hope its not to late for a Question. I try your Tutorial, but i have a Problem to call a second function. It throw that he cant find an entryPoint for the second Function. Have you any Idea how i can call an another function in the same dll? Or have you maybe an Exemple?

 

Did you tried to use thread_local! instead of static mut?

 
 

What if we use fixed size char (byte) array? Would that make passing string simpler? Do you know how to do that?

 

I haven't done it yet, though I can think of no reason it wouldn't work. I'll see if I can throw together an example sometime today

 

The explicit Int32ing makes no sense. You're not being 'explicit' about the type - int is 100% always shorthand for Int32. It's as meaningless as writing Object instead of object.

code of conduct - report abuse