2016-02-29 4 views
4

Я пытаюсь написать расширение DLL для ArmA 3 и game docs говорят:Как реализовать функцию RVExtension для DLA ArmA 3 в Rust?

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 отказывается назвать его.

ответ

5

Благодаря совету @ Shepmaster о Dependency Walker, я смог обнаружить, что проблема связана с изменением имени функции. Я ожидал, что имя функции будет преобразовано в [email protected], но это не так. RVExtension был экспортирован в буквальном смысле, и ArmA не смог найти его по названию [email protected].

Странно, но похоже, что версия компилятора может сыграть определенную роль. Я попробовал ~ 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(

Некоторые другие компиляторы Ржавчина может также работать с:

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

Но , например, ночной 1.8 (MSVC ABI) 32-разрядный с VS 2015 не допускает символ @ d выдает ошибку во время компиляции. Версия MSVC не добавит @12.

Другие компиляторы могут добавить @12, а функция будет экспортироваться как [email protected]@12.


Стоит также отметить, что ArmA это 32-битное приложение, так что он не работает с 64-битной DLL.

+0

Любые идеи о том, как сделать то же самое с Mingw? Кажется, что-то похожее (https://forums.bistudio.com/topic/193084-building-extensions-on-mingw/?p=3073069) – xbelanch

+0

Извините, у меня нет опыта работы с MinGW. – Ridim