【问题标题】:How to implement the RVExtension function for an ArmA 3 DLL in Rust?如何在 Rust 中为 ArmA 3 DLL 实现 RVExtension 函数?
【发布时间】:2016-02-29 14:07:24
【问题描述】:

我正在尝试为 ArmA 3 和 game docs 编写一个 DLL 扩展:

dll 应包含表单的入口点 _RVExtension@12,带有以下 C 签名:

void __stdcall RVExtension(char *output, int outputSize, const char *function);

部分C++代码示例为:

// ...

extern "C" {
    __declspec(dllexport) void __stdcall RVExtension(
        char *output,
        int outputSize,
        const char *function
    ); 
};

void __stdcall RVExtension(
    char *output,
    int outputSize,
    const char *function
) {
    outputSize -= 1;
    strncpy(output,function,outputSize);
}

文档还有很多其他语言的示例,例如:C#, D and even Pascal,但这些对我没有多大帮助,因为我不太了解他们的 FFI =(。

我被以下 Rust 代码卡住了:

#[no_mangle]
pub extern "stdcall" fn RVExtension(
    game_output: *mut c_char,
    output_size: c_int,
    game_input: *const c_char
) {
    // ...
}

但 ArmA 拒绝调用它。

【问题讨论】:

    标签: c++ rust ffi


    【解决方案1】:

    感谢@Shepmaster 对Dependency Walker 的建议,我能够发现问题出在函数名称错误上。我预计函数名称会转换为_name@X,但事实并非如此。 RVExtension 是按字面意思导出的,而 ArmA 无法通过名称 _RVExtension@12 找到它。

    这很奇怪,但似乎编译器版本可能会起作用。我尝试了大约 8 个不同的版本,并且只能使用 Rust nightly 1.8 (GNU ABI) 32 位。

    工作代码是:

    #![feature(libc)]
    extern crate libc;
    
    use libc::{strncpy, size_t};
    
    use std::os::raw::c_char;
    use std::ffi::{CString, CStr};
    use std::str;
    
    #[allow(non_snake_case)]
    #[no_mangle]
    /// copy the input to the output
    pub extern "stdcall" fn _RVExtension(
        response_ptr: *mut c_char,
        response_size: size_t,
        request_ptr: *const c_char,
    ) {
        // get str from arma
        let utf8_arr: &[u8] = unsafe { CStr::from_ptr(request_ptr).to_bytes() };
        let request: &str = str::from_utf8(utf8_arr).unwrap();
    
        // send str to arma
        let response: *const c_char = CString::new(request).unwrap().as_ptr();
        unsafe { strncpy(response_ptr, response, response_size) };
    }
    

    也可以将函数改写成:

    #[export_name="_RVExtension"]
    pub extern "stdcall" fn RVExtension(
    

    其他一些 Rust 编译器也可以使用:

    #[export_name="_RVExtension@12"]
    pub extern "stdcall" fn RVExtension(
    

    但是,例如,使用 VS 2015 的 nightly 1.8 (MSVC ABI) 32 位将不允许 @ 符号并在编译时引发错误。 MSVC版本不会自行添加@12

    其他编译器可能会添加@12,函数会导出为_RVExtension@12@12


    值得一提的是 ArmA 是 32 位应用程序,因此它不适用于 64 位 DLL。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-08
    • 2022-12-11
    • 2020-06-19
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    相关资源
    最近更新 更多