如何在 Rust 中为 ArmA 3 DLL 实现 RVExtension函数

How to implement the RVExtension function for an ArmA 3 DLL in Rust?

本文关键字:DLL 实现 RVExtension 函数 ArmA Rust 中为      更新时间:2023-10-16

我正在尝试为 ArmA 3 编写一个 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 甚至 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拒绝打电话。

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

这很奇怪,但似乎编译器版本可能会发挥作用。我尝试了~8个不同的版本,并且只能使其仅适用于Rust每晚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的每晚1.8(MSVC ABI)32位将不允许@符号,并在编译时引发错误。MSVC 版本本身不会添加@12

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


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