I have a project, in which I have:
- my executable (the app)
- a shared lib with some definitions
- a dynamically linked library
I can load the dll and call a function from my app. That works just fine. What I would like to do is to define a trait in the shared lib. So, that the app and the dll know the trait. Then create a struct in the dll and return that struct in a function that is called from the app. E.g.
The shared lib looks like this:
In the Cargo.toml
[lib]
create_type = ["staticlib"]
In the lib.rs
pub trait Plugin {
fn test(&self) -> String;
}
The dll:
In the Cargo.toml
[lib]
crate_type = ["dylib"]
In the lib.rs
extern crate shared_contract;
use shared_contract::Plugin;
use std::sync::Arc;
pub struct FooBar {
pub payload: String,
}
impl Plugin for FooBar {
fn test(&self) -> String {
self.payload.to_string()
}
}
#[no_mangle]
pub fn get_plugin() -> Arc<Plugin> {
println!("get_plugin called");
Arc::new(FooBar { payload: String::from("foobar_test") })
}
I use the libloading crate to load the dll and get access to "get_plugin()". The problem is, when I call "get_plugin()" from my app, it immediately crashes when it's supposed to return the struct. Is this not possible?
The in-process plugin infra/model is quite brittle at the moment. This fairly recent thread discussed some of the gotchas around it and might be helpful to you.
Thanks for the reply!
I just found that I forgot to declare the " get_plugin()" as extern... I changed it now to
pub fn extern get_plugin() -> Box<Plugin> {}
Cost me some time to notice as it worked when I just used a println!() instead of returning something. Which is wired. I don't want to admit just how much time I needed to find this 
Anyway, it seams to work as expected now sorry to bother you guys.
Presumably that’s because you were referencing it as an extern fn() -> ...
in the executable? I think if you were referencing it as just fn() -> ...
it would work without the extern modifier.
Yes, you are correct and I should have been more precise. The point is that the declaration has to match in both places. Thanks for pointing it out. Otherwise, if others read this it might stir up some confusion about how it works in rust.
Right - calling convention needs to match up, which extern
influences. Thanks for confirming.
When you're doing this you need to be careful to make sure the version of DLL and executable are compatible and that the definition for your Plugin
trait is exactly the same. The easiest way to solve this is to make one crate a dependency of the other.
I was working on a FFI guide a while back and dedicated an entire chapter to creating dynamic plugins for the dummy application. The code snippets make it look longer than it really is, but as I was writing it up I found a really nice mechanism for doing this sort of thing (using a Plugin
trait, using a macro to generate a pre-defined "registration" symbol from the DLL that returns a boxed trait object, etc).
1 Like
In my case the Plugin
trait is defined in the shared_lib. Both the dll and the app include the shared_lib crate. I have however a register plugin function in the app. This is where I load the symbol and get a handle for the plugin. I should have defined a type for that in the shared_lib crate instead of manually writing it there. Then I could have avoided my problem. This way I screwed up the calling convention... It took me a shamefully long time to find the problem but it turned out to be a minor issue in the scheme of things.
I have seen the link you provided. It already gave me some ideas. However, I don't interact with dll's that are not written in rust. I am tinkering with a frame work for more general apps using a browser as a gui and interacting between the gui and the app using websockets. I just wanted the possibility to use Plugins within my framework. There is no real world application. It's just for learning more about rust 
Anyway, thanks for the info I am pretty sure I will have a need for something like this in the future.