I'm trying to load a dll into my R script. Dll is written in rust. I read in R Studio documentation that .Call passes integers as int * in C which i interpret as &i32 in rust (also assuming that mutability is just rust thing, and i don't have to make it &mut i32 if i don't intent to mutate it). However R kept on crashing the session, so i start doing the trial and error. Made this file and tried to load it (the base taken from this repo):
#![cfg(windows)]
use winapi::shared::minwindef;
use winapi::shared::minwindef::{BOOL, DWORD, HINSTANCE, LPVOID};
use winapi::um::consoleapi;
/// Entry point which will be called by the system once the DLL has been loaded
/// in the target process. Declaring this function is optional.
///
/// # Safety
///
/// What you can safely do inside here is very limited, see the Microsoft documentation
/// about "DllMain". Rust also doesn't officially support a "life before main()",
/// though it is unclear what that that means exactly for DllMain.
#[no_mangle]
#[allow(non_snake_case, unused_variables)]
extern "system" fn DllMain(
dll_module: HINSTANCE,
call_reason: DWORD,
reserved: LPVOID)
-> BOOL
{
const DLL_PROCESS_ATTACH: DWORD = 1;
const DLL_PROCESS_DETACH: DWORD = 0;
match call_reason {
DLL_PROCESS_ATTACH => demo_init(),
DLL_PROCESS_DETACH => (),
_ => ()
}
minwindef::TRUE
}
fn demo_init() {
unsafe { consoleapi::AllocConsole() };
println!("Hello, world!");
}
#[no_mangle]
extern "cdecl" fn seven_cdecl_u32() -> u32 {
7
}
#[no_mangle]
extern "cdecl" fn seven_cdecl_u64() -> u64 {
7
}
#[no_mangle]
extern "cdecl" fn seven_cdecl_i32() -> i32 {
7
}
#[no_mangle]
extern "cdecl" fn seven_cdecl_i64() -> i64 {
7
}
#[no_mangle]
extern "stdcall" fn seven_stdcall_u32() -> u32 {
7
}
#[no_mangle]
extern "stdcall" fn seven_stdcall_u64() -> u64 {
7
}
#[no_mangle]
extern "stdcall" fn seven_stdcall_i32() -> i32 {
7
}
#[no_mangle]
extern "stdcall" fn seven_stdcall_i64() -> i64 {
7
}
#[no_mangle]
extern "system" fn seven_system_u32() -> u32 {
7
}
#[no_mangle]
extern "system" fn seven_system_i32() -> i32 {
7
}
#[no_mangle]
extern "system" fn seven_system_u64() -> u64 {
7
}
#[no_mangle]
extern "system" fn seven_system_i64() -> i64 {
7
}
#[no_mangle]
extern "C" fn seven_c_u32() -> u32 {
7
}
#[no_mangle]
extern "C" fn seven_c_i32() -> i32 {
7
}
#[no_mangle]
extern "C" fn seven_c_u64() -> u64 {
7
}
#[no_mangle]
extern "C" fn seven_c_i64() -> i64 {
7
}
CWD = r"(C:\\Users\grass\Desktop\codes\R\dlload)"
dllname = paste(CWD,r"(\rdll.dll)", sep="")
print(getwd())
dyn.load(dllname)
#print(.Call("seven_cdecl_i32", pakage=dllname))
#print(.Call("seven_cdecl_u32", pakage=dllname))
#print(.Call("seven_cdecl_i64", pakage=dllname))
#print(.Call("seven_cdecl_u64", pakage=dllname))
#print(.Call("seven_stdcall_i32", pakage=dllname))
#print(.Call("seven_stdcall_u32", pakage=dllname))
#print(.Call("seven_stdcall_i64", pakage=dllname))
#print(.Call("seven_stdcall_u64", pakage=dllname))
#print(.Call("seven_system_i32", pakage=dllname))
#print(.Call("seven_system_u32", pakage=dllname))
#print(.Call("seven_system_i64", pakage=dllname))
#print(.Call("seven_system_u64", pakage=dllname))
#print(.Call("seven_c_i32", pakage=dllname))
#print(.Call("seven_c_u32", pakage=dllname))
#print(.Call("seven_c_i64", pakage=dllname))
#print(.Call("seven_c_u64", pakage=dllname))
I was commenting out line by line but it never worked. But the entry point did work, and the hello world was printed. When i try to print a value of integer i pass to function (7) i get some absolute garbage, which made me think that memory layout is different. I read that all values in R are vectors which changes the layout, but i assumed that .Call is designed with this in mind.
Finally the documentation in R Studio claims that for R unaware functions .C should be used, but i don't understand how to get return value from .C as it evaluates to a list of parameters and a package name.
If anyone can tell me how to properly get arguments in rust from R and return from rust to R I would be grateful.