Convert CPP header file

I am trying to port a CPP DLL into Rust on Windows. A service will load the plugin dynamically and then start calling regulated functions on the plugin to exchange data and status.
I did convert some parts successfully :slight_smile: like:

APIENTRY APIRES About(PluginInfo& info)
{
    info = ExtPluginInfo;
    return(RET_OK);
}

Rust equivalent:

pub const RET_OK: u32 = 0;

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn About(info: &mut PluginInfo) -> u32 {
    *info = EXT_PLUGIN_INFO;
    RET_OK
}

At some point, however, the server sends/receives object references! I need to interact with that reference in Rust or create and pass it to the server.
For example, when my plugin DLL gets loaded, the server calls the Create function on that DLL. The function should provide a valid reference to a plugin class instance, which the server calls its hooks at the proper times.

// IPlugin in the header.h file
class IPlugin
{
public:
   virtual APIRES  Start(IServerAPI* server)=0;
   virtual APIRES  Stop(void)=0;
};

// main.cpp
APIENTRY APIRES Create(IPlugin** plugin)
{
    if (!plugin) return(RET_ERR_PARAMS);
    if (((*plugin) = new(std::nothrow) PluginInstance()) == NULL)
        return(RET_ERR_MEM);
    return(RET_OK);
}
// ...
class PluginInstance: public IPlugin
{
public:
  APIRES Start(IServerAPI* server) {}
  virtual APIRES Stop(void) {}
}

To convert this, I defined a trait reflecting the IPlugin and a corresponding PluginInstance struct, but it fails. How can I convert the Create function into Rust, passing a proper value?
My try:

pub trait IPlugin {
    fn Start(&mut self, server: *mut dyn IServerApi) ->ApiRes;
    fn Stop(&mut self) -> ApiRes;
}

#[repr(C)]
#[derive(Clone, Default)]
pub struct MyPlugin;
impl IPlugin for MyPlugin {
    fn Start(&mut self, server: *mut dyn IServerApi) -> u32 {
        info!("start");
        RET_OK
    }
    fn Stop(&mut self) -> u32 {
        info!("stop");
        RET_OK
    }
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Create(plugin: *mut *mut dyn IPlugin) -> u32 {
    info!("Create");
    if plugin.is_null() {
        error!(" called with null plugin");
        return RET_ERR_INVALID_PARAMETER;
    }

    let mine = Box::new(MyPlugin::default());
    let mine_ptr = Box::into_raw(mine);
    unsafe { *plugin = mine_ptr as *mut dyn IPlugin;    }

    info!("success");
    MT_RET_OK
}

The "success" gets printed, but then the server throws an error when trying to call the Start. I think the instance that I passed is not correct!

the vtable structure is different between rust and C++, you either create a C++ stub that exports C ABI, or you have to manually layout the vtable struct according to the C++ definition.

also recommend to checkout cxx-rs:

1 Like