consume COM library from C# to rust - rust

Question
I want to rewrite my project from C# to rust.
But I stuck in Segmentation Fault situation.
I think I misunderstood something, or meet crate limitation, hope for some help.
Rust Code
find interface UUID
regedit capture
find CLSID
regedit capture
other id (I'm not sure shall we need it)
regedit capture
use windows::core::{GUID, HRESULT, IUnknown, IUnknown_Vtbl, interface};
use windows::Win32::System::Com::{
COINIT_APARTMENTTHREADED,
CLSCTX_ALL,
CoInitializeEx,
CoCreateInstance};
// define interface
#[interface("288EFDEC-3CF0-4F6C-8473-4E4CD47A93C7")]
unsafe trait Inhicshisx: IUnknown {
fn VPNGetRandomX(&self) -> HRESULT;
}
fn run() -> Result<(), anyhow::Error> {
unsafe {
// 2F5AECD5-B5CD-41E1-8265-E2F6AA4548CB
const CLSID: GUID = GUID {
data1: 0x2F5AECD5,
data2: 0xB5CD,
data3: 0x41E1,
data4: [0x82, 0x65, 0xE2, 0xF6, 0xAA, 0x45, 0x48, 0xCB],
};
// initialize runtime
CoInitializeEx(Some(ptr::null_mut() as *mut c_void), COINIT_APARTMENTTHREADED)?;
// create COM object
let hisx: Inhicshisx = CoCreateInstance(&CLSID, None, CLSCTX_ALL)?;
// call object function
let value = hisx.VPNGetRandomX();
}
Ok(())
}
C# Part
add a reference
regedit capture
call function
using CSHISXLib;
string MyStr0;
CSHISXLib.Inhicshisx CSHISXLibObj = new CSHISXLib.nhicshisx();
MyStr0 = CSHISXLibObj.VPNGetRandomX();
Console.WriteLine(MyStr0);
It works.
Update information
According to #IInspectable help, I can generate interface by oleview.exe tool.
generated interface
[
odl,
uuid(288EFDEC-3CF0-4F6C-8473-4E4CD47A93C7),
helpstring("Inhicshisx Interface"),
dual,
oleautomation
]
interface Inhicshisx : IDispatch {
[id(0x00000001), helpstring("method VPNGetRandomX")]
HRESULT VPNGetRandomX([out, retval] BSTR* strRandom);
[id(0x00000002), helpstring("method VPNH_SignX")]
HRESULT VPNH_SignX(
[in] BSTR strRandom,
[in, optional, defaultvalue("")] BSTR strCardType,
[in, optional, defaultvalue("")] BSTR strServiceType,
[out, retval] BSTR* strRet);
}
Rust code change
use windows::core::BSTR;
#[interface("288EFDEC-3CF0-4F6C-8473-4E4CD47A93C7")]
unsafe trait Inhicshisx: IDispatch {
fn VPNGetRandomX(&self) -> BSTR;
fn VPNH_SignX(&self, *mut BSTR, *mut BSTR, *mut BSTR) -> BSTR;
}
But it still cause Segmentation Fault, hope some advice 🙏

Thank for #IInspectable advice.
Segmentation Fault caused by wrong interface.
Find the COM interface
you can use oleview to display for COM library interface. In my case, the interface like this.
interface Inhicshisx : IDispatch {
[id(0x00000001), helpstring("method VPNGetRandomX")]
HRESULT VPNGetRandomX([out, retval] BSTR* strRandom);
[id(0x00000002), helpstring("method VPNH_SignX")]
HRESULT VPNH_SignX(
[in] BSTR strRandom,
[in, optional, defaultvalue("")] BSTR strCardType,
[in, optional, defaultvalue("")] BSTR strServiceType,
[out, retval] BSTR* strRet);
}
Declare interface in Rust
#[interface("288EFDEC-3CF0-4F6C-8473-4E4CD47A93C7")]
unsafe trait Inhicshisx: IDispatch {
fn VPNGetRandomX(&self, random: *mut BSTR) -> HRESULT;
fn VPNH_SignX(&self, random: BSTR, card_type: BSTR, service_type: BSTR, sign: *mut BSTR) -> HRESULT;
}

Related

How to make static container for referring a mutable instance from callback passed to C code?

For the library I need to write I have a struct representing a service written in C:
struct RustService {
id: u8, /* it's me setting the id in the first place */
service: *mut c_void,
status: *mut c_void,
value: Option<u32>,
/* various fields here */
}
impl RustService {
fn new() -> /* can be wrapped*/RustService {
/* ... */
}
}
I have several callbacks passed to C library like this:
#[no_mangle]
extern "C" fn callback_handle(service: *mut c_void, size: *mut u32, buffer: *mut u8)
{
let id: u8 = c_library_get_id(service);
let instance: &mut RustService = /* get that from static container based on id */
if size = mem::size_of::<u32>() as u32 {
let value = buffer.cast::<u32>().read();
instance.value = Some(value);
} else {
panic!("Invalid length passed.");
}
}
What am I looking for is a proven/good practice that would apply here that works without causing deadlock, where my callback could refer back to the right instance using the library in C. That library in C can run multiple instances, however it's not that important. Alternatively I can accept a single instance pattern, that would work in this case.
Other methods of RustService would need to call for example a function with the following signature (from bindgen):
extern "C" pub fn clibCoreWork(status: *mut clibStatus, service: *mut clibService) -> u32;
and guts of that function may decide to call these callbacks mentioned above.
The approach I've taken shoots me in the foot as the inner Mutex deadlocks even in the single thread:
lazy_static! {
static ref MY_INSTANCES: Mutex<HashMap<u8, Weak<Mutex<RustService>>>> = Mutex::new(HashMap::new());
}
I dug the internet but fellow Rustaceans didn't seem to post anything about such problem.
Note: I cannot change underlying types in the C library I'm using. In the ideal world it would let me store pointer to user data and I'd brutally convert it to a mutable reference in unsafe code.

Invoke libc::c_void-Pointer as function in Rust with parameters [duplicate]

This question already has an answer here:
How can I call a raw address from Rust?
(1 answer)
Closed 3 years ago.
Hello people of the internet,
I'm struggeling to invoke a function that is stored in a libc::c_void-Pointer. I can't tell Rust that the pointer is invokable and I can't figure out how to.
I want to translate this C++ Code
void * malloc(size_t size) {
static void *(*real_malloc)(size_t) = nullptr;
if (real_malloc == nullptr) {
real_malloc = reinterpret_cast<void *(*)(size_t)> (dlsym(RTLD_NEXT, "malloc"));
}
// do some logging stuff
void * ptr = real_malloc(size);
return ptr;
}
to Rust.
#[no_mangle]
pub extern fn malloc(bytes: usize) {
let c_string = "malloc\0".as_mut_ptr() as *mut i8; // char array for libc
let real_malloc: *mut libc::c_void = libc::dlsym(libc::RTLD_NEXT, c_string);
return real_malloc(bytes);
}
That's my progress so far after 1h of searching on the internet and trying. I'm new to Rust and not yet familiar with Rust/FFI / Rust with libc. I tried a lot with unsafe{}, casts with as but I always stuck at the following problem:
return real_malloc(bytes);
^^^^^^^^^^^^^^^^^^ expected (), found *-ptr
Q1: How can I call the function behind the void-Pointer stored in real_malloc?
Q2: Is my Rust-String to C-String conversion feasible this way?
I figured it out! Perhaps there is a better way but it works.
The trick is to "cast" the void-Pointer to c-function-Type with std::mem::transmute since it won't work with as
type LibCMallocT = fn(usize) -> *mut libc::c_void;
// C-Style string for symbol-name
let c_string = "malloc\0".as_ptr() as *mut i8; // char array for libc
// Void-Pointer to address of symbol
let real_malloc_addr: *mut libc::c_void = unsafe {libc::dlsym(libc::RTLD_NEXT, c_string)};
// transmute: "Reinterprets the bits of a value of one type as another type"
// Transform void-pointer-type to callable C-Function
let real_malloc: LibCMallocT = unsafe { std::mem::transmute(real_malloc_addr) }
When the shared object is build, one can verify that it works like this:
LD_PRELOAD=./target/debug/libmalloc_log_lib.so some-binary
My full code:
extern crate libc;
use std::io::Write;
const MSG: &str = "HELLO WORLD\n";
type LibCMallocT = fn(usize) -> *mut libc::c_void;
#[no_mangle] // then "malloc" is the symbol name so that ELF-Files can find it (if this lib is preloaded)
pub extern fn malloc(bytes: usize) -> *mut libc::c_void {
/// Disable logging aka return immediately the pointer from the real malloc (libc malloc)
static mut RETURN_IMMEDIATELY: bool = false;
// C-Style string for symbol-name
let c_string = "malloc\0".as_ptr() as *mut i8; // char array for libc
// Void-Pointer to address of symbol
let real_malloc_addr: *mut libc::c_void = unsafe {libc::dlsym(libc::RTLD_NEXT, c_string)};
// transmute: "Reinterprets the bits of a value of one type as another type"
// Transform void-pointer-type to callable C-Function
let real_malloc: LibCMallocT = unsafe { std::mem::transmute(real_malloc_addr) };
unsafe {
if !RETURN_IMMEDIATELY {
// let's do logging and other stuff that potentially
// needs malloc() itself
// This Variable prevent infinite loops because 'std::io::stdout().write_all'
// also uses malloc itself
// TODO: Do proper synchronisazion
// (lock whole method? thread_local variable?)
RETURN_IMMEDIATELY = true;
match std::io::stdout().write_all(MSG.as_bytes()) {
_ => ()
};
RETURN_IMMEDIATELY = false
}
}
(real_malloc)(bytes)
}
PS: Thanks to https://stackoverflow.com/a/46134764/2891595 (After I googled a lot more I found the trick with transmute!)

GraphicsMagick FFI issue

As an exercise, I'm attempting to write a GraphicsMagick FFI wrapper in Rust. I'm having an issue replicating some reference C code:
Demo C code:
Image
*image = (Image *) NULL;
ImageInfo
*imageInfo;
ExceptionInfo
exception;
InitializeMagick(NULL);
imageInfo=CloneImageInfo(0);
GetExceptionInfo(&exception);
And here is my (naive) translation to Rust:
let img: *mut ffi::Image;
let img_info: *mut ffi::ImageInfo;
let exception: *mut ffi::ExceptionInfo = ptr::null_mut();
unsafe {
ffi::InitializeMagick(ptr::null_mut());
img_info =
ffi::CloneImageInfo(ptr::null_mut() as *const ffi::ImageInfo);
ffi::GetExceptionInfo(exception);
// ...
}
This compiles just fine, but when I try to run it, I see:
magick/error.c:388: GetExceptionInfo: Assertion `exception != (ExceptionInfo *) ((void *)0)' failed
which is caused by ffi::GetExceptionInfo(exception). The only difference seems to be that the C exception isn't "initialized", but I don't know enough about C to know if there is a difference between a null and an empty/uninitialized pointer.
The difference between your C and Rust code is that the C version allocates an ExceptionInfo instance on the stack and passes into the GetExceptionInfo a pointer referencing that instance.
Your Rust code, on the other hand, passes a NULL pointer.
GetExceptionInfo specifically guards against being passed a NULL pointer, you can see the assertion's code here, in magick/error.c.
I don't know what kind of FFI bindings you use, but if the ExceptionInfo is fully defined in them then you should be able to allocate it on the stack and pass a reference to it just like in the C version:
let mut exception: ffi::ExceptionInfo = unsafe {std::mem::uninitialized()};
unsafe {ffi::GetExceptionInfo (&mut exception);}
The error message states (rewritten a bit):
Assertion exception != NULL failed
That is, you cannot pass NULL to that method. Note the C code:
ExceptionInfo exception;
This is not a pointer. You need to allocate space for it and then pass in a reference to the allocated space.
The documentation shows the definition:
typedef struct _ExceptionInfo
{
char
*reason,
*description;
ExceptionType
severity;
unsigned long
signature;
} ExceptionInfo;
You will need to represent this in Rust. Something like this untested code:
extern crate libc;
#[repr(C)]
struct ExceptionInfo {
reason: *const libc::c_char,
description: *const libc::c_char,
severity: ExceptionType,
signature: libc::c_ulong,
}
#[repr(C)]
enum ExceptionType {
UndefinedException,
WarningException = 300,
// the rest
}
Then you need to allocate it and pass a reference. More untested code:
let img_info;
let mut exception = ffi::ExceptionInfo::new();
unsafe {
ffi::InitializeMagick(ptr::null_mut());
img_info =
ffi::CloneImageInfo(ptr::null_mut() as *const ffi::ImageInfo);
ffi::GetExceptionInfo(&mut exception);
// ...
}
Note that Rust style is 4 space indents.

Wrapping a Rust struct in a C++ class

I would like to wrap a Rust struct in a C++ class.
Rust:
#[repr(C)]
pub struct RustStruct {
num: i32,
// other members..
}
pub extern "C" fn update(rust_struct: *mut RustStruct) {
(*rust_struct).num = 1i32;
}
extern "C" {
void update(void*);
}
C++:
class Wrapper {
public:
Wrapper();
// ..
private:
void* rustStruct;
// ..
};
Wrapper::Wrapper() {
update(rustStruct); // crash
}
int main() {
std::cout << "Testing..";
}
I understand why this wouldn't work. My question is: how can I achieve what I'm basically trying to do (wrap a rust struct in a c++ class)?
There is a mix of multiple FFIs concepts in your answer, so first let me recommend that your read the Reference.
There are two ways to achieve what you wish, you can either:
use a POD struct (Plain Old Data), aka C-compatible struct
use an opaque pointer (void* in C)
Mixing them, as you did, does not make sense.
Which to pick?
Both solutions have advantages and disadvantages, it's basically an expressiveness versus performance trade-off.
On the one hand, opaque pointers are more expressive: they can point to any Rust type. However:
they require dynamic memory allocation
they require being manipulated by Rust functions (so always indirectly from C or C++)
On the other hand, POD struct do not require either of those, but they are limited to only a subset of types expressible in Rust.
How to use a POD?
This is the easiest, actually, so let's start with it!
In Rust:
#[repr(C)]
pub struct RustStruct {
num: i32,
// other members, also PODs!
}
In C++
struct RustStruct {
int32_t num;
// other members, also with Standard Layout
// http://en.cppreference.com/w/cpp/types/is_standard_layout
};
class Wrapper {
public:
private:
RustStruct rustStruct;
};
Note that I just got along with your question stricto censu here, you could actually merge the two in a single C++ class:
class RustStruct {
public:
private:
int32_t num;
// other members, also with Standard Layout
// http://en.cppreference.com/w/cpp/types/is_standard_layout
};
Just avoid virtual methods.
How to use an opaque pointer?
This gets trickier:
Only the Rust code may correctly create/copy/destruct the type
Beware of leaking...
So, we need to implement a lot of functions in Rust:
#![feature(box_raw, box_syntax)]
use std::boxed;
pub struct RustStruct {
num: i32,
// other members, anything goes
}
pub extern "C" fn createRustStruct() -> *mut RustStruct {
boxed::into_raw(box RustStruct::new())
}
pub extern "C" fn destroyRustStruct(o: *mut RustStruct) {
boxed::from_raw(o);
}
Alright... now on to C++:
struct RustStruct;
RustStruct* createRustStruct();
void destroyRustStruct(RustStruct*);
class Wrapper {
public:
Wrapper(): rustStruct(RustStructPtr(createRustStruct())) {}
private:
struct Deleter {
void operator()(RustStruct* rs) const {
destroyRustStruct(rs);
}
};
typedef std::unique_ptr<RustStruct, Deleter> RustStructPtr;
RustStructPtr rustStruct;
}; // class Wrapper
So, yes, a bit more involved, and Wrapper is not copyable either (copy has to be delegated to Rust too). Anyway, this should get you started!
Note: if you have a lot of opaque pointers to wrap, a templated C++ class taking the copy/destroy functions as template parameters could alleviate a lot of boiler plate.

C library freeing a pointer coming from Rust

I want to do Rust bindings to a C library which requires a callback, and this callback must return a C-style char* pointer to the C library which will then free it.
The callback must be in some sense exposed to the user of my library (probably using closures), and I want to provide a Rust interface as convenient as possible (meaning accepting a String output if possible).
However, the C library complains when trying to free() a pointer coming from memory allocated by Rust, probably because Rust uses jemalloc and the C library uses malloc.
So currently I can see two workarounds using libc::malloc(), but both of them have disadvantages:
Give the user of the library a slice that he must fill (inconvenient, and imposes length restrictions)
Take his String output, copy it to an array allocated by malloc, and then free the String (useless copy and allocation)
Can anybody see a better solution?
Here is an equivalent of the interface of the C library, and the implementation of the ideal case (if the C library could free a String allocated in Rust)
extern crate libc;
use std::ffi::CString;
use libc::*;
use std::mem;
extern "C" {
// The second parameter of this function gets passed as an argument of my callback
fn need_callback(callback: extern fn(arbitrary_data: *mut c_void) -> *mut c_char,
arbitrary_data: *mut c_void);
}
// This function must return a C-style char[] that will be freed by the C library
extern fn my_callback(arbitrary_data: *mut c_void) -> *mut c_char {
unsafe {
let mut user_callback: *mut &'static mut FnMut() -> String = mem::transmute(arbitrary_data); //'
let user_string = (*user_callback)();
let c_string = CString::new(user_string).unwrap();
let ret: *mut c_char = mem::transmute(c_string.as_ptr());
mem::forget(c_string); // To prevent deallocation by Rust
ret
}
}
pub fn call_callback(mut user_callback: &mut FnMut() -> String) {
unsafe {
need_callback(my_callback, mem::transmute(&mut user_callback));
}
}
The C part would be equivalent to this:
#include <stdlib.h>
typedef char* (*callback)(void *arbitrary_data);
void need_callback(callback cb, void *arbitrary_data) {
char *user_return = cb(arbitrary_data);
free(user_return); // Complains as the pointer has been allocated with jemalloc
}
It might require some annoying work on your part, but what about exposing a type that implements Write, but is backed by memory allocated via malloc? Then, your client can use the write! macro (and friends) instead of allocating a String.
Here's how it currently works with Vec:
let mut v = Vec::new();
write!(&mut v, "hello, world");
You would "just" need to implement the two methods and then you would have a stream-like interface.

Resources