如何在 Rust 中为 ArmA 3 DLL 实现 RVExtension函数
How to implement the RVExtension function for an ArmA 3 DLL in Rust?
我正在尝试为 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。
相关文章:
- 从C++调用dll实现的JNI
- 如何在c++中实现有状态dll
- 当DLL( 标头)是预期的交付时,如何在C 中实现预测模型(具有100个参数的10种类型)
- DLL和EXE中具有相同名称和父级但实现不同的类中的问题
- 在主应用程序中声明的 dll 中实现接口 - C++
- 为DLL实现C++类时出现错误LNK2019
- 如何在 Rust 中为 ArmA 3 DLL 实现 RVExtension函数
- 仅使用 DLL *.h 头文件构建(compile.link)应用程序代码,并在运行时加载 DLL 实现(显式链接)
- 如何在具有 DLL 的应用程序中实现单一实例
- 两个插件链接到具有不同实现(代码)的同名 DLL 或共享库对象 (so)
- 是否可以实现 JNI 以使用 DLL 中的 C++ 类将文件写入磁盘
- 在Delphi中实现一个C DLL
- 实现一个小型的C DLL来连接我们的C++代码和RawInput
- 在C++程序中实现DLL时遇到问题
- 实现CLR到旧的MFC/Win32 DLL和托管DLL到MFC/Win32应用程序
- c++实现虚类定义在dll外,在dll内
- 当我构建要与c#集成的dll(在vsc++中使用OpenCv库实现)时要考虑的事情是什么?
- 在非托管c++程序中实现一个c# DLL COM文件
- 代理dll:方法覆盖/方法转发(COM实现继承)
- 如何在JNI和用c++实现的DLL文件之间传递参数