Я пытаюсь написать расширение DLL для ArmA 3 и игровые документы сказать:
Ожидается, что 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 и даже Паскаль, но они мне мало помогают, потому что я плохо понимаю их 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 о Зависимость Уокер, Я смог обнаружить, что проблема была в искажении названия функции. Я ожидал, что имя функции будет преобразовано в _name@X
, но это не так. RVExtension
был экспортирован буквально, и ArmA не смог найти его по имени _RVExtension@12
,
Это странно, но кажется, что версия компилятора может сыграть свою роль. Я попробовал ~ 8 разных версий и смог заставить его работать только с 32-битной Rust nightly 1.8 (GNU ABI).
Рабочий код:
#![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(
Но, например, ночные 1.8 (MSVC ABI) 32-битные с VS 2015 не позволят @
символ и выдает ошибку во время компиляции. Версия MSVC не добавит @12
само собой.
Другие компиляторы могут добавить @12
и функция будет экспортирована как _RVExtension@12@12
,
Также стоит упомянуть, что ArmA является 32-битным приложением, поэтому оно не работает с 64-битной DLL.
Других решений пока нет …