I am trying to convert this example to Rust 1.3 with winapi-rs 0.2.4.
I have:
fn send_key_event(vk: u16, flags: u32) {
let mut input = winapi::INPUT {
type_: winapi::INPUT_KEYBOARD,
union_: winapi::KEYBDINPUT {
wVk: vk,
wScan: 0,
dwFlags: flags,
time: 0,
dwExtraInfo: 0,
}
};
unsafe {
user32::SendInput(1, &mut input, mem::size_of::<winapi::INPUT>() as i32);
}
}
which does not compile with:
error: mismatched types:
expected `winapi::winuser::MOUSEINPUT`,
found `winapi::winuser::KEYBDINPUT`
(expected struct `winapi::winuser::MOUSEINPUT`,
found struct `winapi::winuser::KEYBDINPUT`) [E0308]
Haw do I send keystrokes to the active window?
The definition of winapi::INPUT in the version of winapi-rs you use is incorrect. It appears to have been fixed today (or yesterday, depending on where you are).
Related
I'm trying to pass a ID3D11Device instance from Rust to a C FFI Library (FFMPEG).
I made this sample code:
pub fn create_d3d11_device(&mut self, device: &mut Box<windows::Win32::Graphics::Direct3D11::ID3D11Device>, context: &mut Box<windows::Win32::Graphics::Direct3D11::ID3D11DeviceContext>) {
let av_device : Box<AVBufferRef> = self.alloc(HwDeviceType::D3d11va);
unsafe {
let device_context = Box::from_raw(av_device.data as *mut AVHWDeviceContext);
let mut d3d11_device_context = Box::from_raw(device_context.hwctx as *mut AVD3D11VADeviceContext);
d3d11_device_context.device = device.as_mut() as *mut _;
d3d11_device_context.device_context = context.as_mut() as *mut _;
let avp = Box::into_raw(av_device);
av_hwdevice_ctx_init(avp);
self.av_hwdevice = Some(Box::from_raw(avp));
}
}
On the Rust side the Device does work, but on the C side, when FFMEPG calls ID3D11DeviceContext_QueryInterface the app crashes with the following error: Exception 0xc0000005 encountered at address 0x7ff9fb99ad38: User-mode data execution prevention (DEP) violation at location 0x7ff9fb99ad38
The address is actually the pointer for the lpVtbl of QueryInterface, like seen here:
The disassembly of the address also looks correct (this is done on an another debugging session):
(lldb) disassemble --start-address 0x00007ffffdf3ad38
0x7ffffdf3ad38: addb %ah, 0x7ffffd(%rdi,%riz,8)
0x7ffffdf3ad3f: addb %al, (%rax)
0x7ffffdf3ad41: movabsl -0x591fffff80000219, %eax
0x7ffffdf3ad4a: outl %eax, $0xfd
Do you have any pointer to debug this further?
EDIT: I made a Minimal Reproducion Sample. Interestingly this does not causes a DEP Violation, but simply a Segfault.
On the C side:
int test_ffi(ID3D11Device *device){
ID3D11DeviceContext *context;
device->lpVtbl->GetImmediateContext(device, &context);
if (!context) return 1;
return 0;
}
On the Rust side:
unsafe fn main_rust(){
let mut device = None;
let mut device_context = None;
let _ = match windows::Win32::Graphics::Direct3D11::D3D11CreateDevice(None, D3D_DRIVER_TYPE_HARDWARE, OtherHinstance::default(), D3D11_CREATE_DEVICE_DEBUG, &[], D3D11_SDK_VERSION, &mut device, std::ptr::null_mut(), &mut device_context) {
Ok(e) => e,
Err(e) => panic!("Creation Failed: {}", e)
};
let mut device = match device {
Some(e) => e,
None => panic!("Creation Failed2")
};
let mut f2 : ID3D11Device = transmute_copy(&device); //Transmuting the WinAPI into a bindgen ID3D11Device
test_ffi(&mut f2);
}
The bindgen build.rs:
extern crate bindgen;
use std::env;
use std::path::PathBuf;
fn main() {
// Tell cargo to tell rustc to link the system bzip2
// shared library.
println!("cargo:rustc-link-lib=ffi_demoLIB");
println!("cargo:rustc-link-lib=d3d11");
// Tell cargo to invalidate the built crate whenever the wrapper changes
println!("cargo:rerun-if-changed=library.h");
// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("library.h")
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.blacklist_type("_IMAGE_TLS_DIRECTORY64")
.blacklist_type("IMAGE_TLS_DIRECTORY64")
.blacklist_type("PIMAGE_TLS_DIRECTORY64")
.blacklist_type("IMAGE_TLS_DIRECTORY")
.blacklist_type("PIMAGE_TLS_DIRECTORY")
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
The Complete Repo can be found over here: https://github.com/TheElixZammuto/demo-ffi
According to https://github.com/microsoft/windows-rs/issues/1710#issuecomment-1111522946 my error was that I was trasmutating the structs, while what I should have done is to cast the references:
let f2 : &mut ID3D11Device = transmute_copy(&mut device); //Transmuting the WinAPI into a bindgen ID3D11Device
test_ffi(f2);
I would like to get my username in an std::String using the windows-rs crate.
use bindings::Windows::Win32::{
System::WindowsProgramming::GetUserNameW,
Foundation::PWSTR,
};
fn main() {
let mut pcbbuffer: u32 = 255;
let mut helper: u16 = 0;
let lpbuffer = PWSTR(&mut helper);
println!("lpbuffer: {:?}\npcbbuffer: {:?}", lpbuffer, pcbbuffer);
unsafe {
let success = GetUserNameW(lpbuffer, &mut pcbbuffer);
println!("GetUserNameW succeeded: {:?}\nlpbuffer: {:?}\npcbbuffer: {:?}", success.as_bool(), lpbuffer, pcbbuffer);
}
}
produces the output:
lpbuffer: PWSTR(0xca20f5f76e)
pcbbuffer: 255
GetUserNameW succeeded: true
lpbuffer: PWSTR(0x7200650073)
pcbbuffer: 5
The username is "user" that's 4 + 1 terminating character = 5 which is good. I also see the GetUserNameW function succeeded and the pointer to the string changed.
What are the next steps?
The code as posted works by coincidence alone. It sports a spectacular buffer overflow, hardly what you'd want to see in Rust code. Specifically, you're taking the address of a single u16 value, and pass it into an API, telling it that the pointed-to memory were 255 elements in size.
That needs to be solved: You will have to allocate a buffer large enough to hold the API's output first.
Converting a UTF-16 encoded string to a Rust String with its native encoding can be done using several different ways, such as String::from_utf16_lossy().
The following code roughly sketches out the approach:
fn main() {
let mut cb_buffer = 257_u32;
// Create a buffer of the required size
let mut buffer = Vec::<u16>::with_capacity(cb_buffer as usize);
// Construct a `PWSTR` by taking the address to the first element in the buffer
let lp_buffer = PWSTR(buffer.as_mut_ptr());
let result = unsafe { GetUserNameW(lp_buffer, &mut cb_buffer) };
// If the API returned success, and more than 0 characters were written
if result.as_bool() && cb_buffer > 0 {
// Construct a slice over the valid data
let buffer = unsafe { slice::from_raw_parts(lp_buffer.0, cb_buffer as usize - 1) };
// And convert from UTF-16 to Rust's native encoding
let user_name = String::from_utf16_lossy(buffer);
println!("User name: {}", user_name);
}
}
Trying to generate a random number from the Standard Normal distribution. Need to multiply the value by 0.1 to get the number range i'm looking for. I tried using the documentation from rand_dist you can find here: https://docs.rs/rand_distr/0.3.0/rand_distr/struct.StandardNormal.html
My Cargo.toml is the following:
[package]
name = "test_rng"
version = "0.1.0"
authors = ["Jack"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.7.3"
rand_distr = "0.3.0"
The starting rust code is the example provided in the rand_dist docs from above:
use rand::prelude::*;
use rand_distr::StandardNormal;
fn main() {
let val: f64 = thread_rng().sample(StandardNormal);
println!("{}", val);
}
When I run this it works as expected and the output is:
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
Finished dev [unoptimized + debuginfo] target(s) in 2.11s
Running `target\debug\test_rng.exe`
0.48398855288705356
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
This is where I'm hitting an issue, when I try to multiply the number by 0.1 in the following code I get the resulting error:
fn main() {
let val: f64 = 0.1 * thread_rng().sample(StandardNormal);
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
error[E0284]: type annotations needed: cannot satisfy `<f64 as std::ops::Mul<_>>::Output == f64`
--> src\main.rs:5:24
|
5 | let val: f64 = 0.1 * thread_rng().sample(StandardNormal);
| ^ cannot satisfy `<f64 as std::ops::Mul<_>>::Output == f64`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0284`.
error: could not compile `test_rng`.
To learn more, run the command again with --verbose.
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
I tried to change 0.1 to 0.1_f64 but that gave the same error.
I tried to convert random number to f64 (which it should already be) with as f64 but that resulted in the following:
fn main() {
let val: f64 = 0.1 * thread_rng().sample(StandardNormal) as f64;
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
error[E0282]: type annotations needed
--> src\main.rs:5:39
|
5 | let val: f64 = 0.1 * thread_rng().sample(StandardNormal) as f64;
| ^^^^^^ cannot infer type for type parameter `T` declared on the associated function `sample`
|
= note: type must be known at this point
help: consider specifying the type arguments in the method call
|
5 | let val: f64 = 0.1 * thread_rng().sample::<T, D>(StandardNormal) as f64;
| ^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0282`.
error: could not compile `test_rng`.
To learn more, run the command again with --verbose.
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
Thought it was a precedence issue so I tried wrapping second half in parenthesis but got the same error.
I can get it to work by making the variable mutable and separating the line into two operations like the following:
fn main() {
let mut val: f64 = thread_rng().sample(StandardNormal);
val *= 0.1;
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
Finished dev [unoptimized + debuginfo] target(s) in 1.62s
Running `target\debug\test_rng.exe`
-0.034993448117065
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
Any idea what is going on with the multiplication of the f64 with the output of the random number?
You can use the following:
fn main() {
let val: f64 = 0.1 * thread_rng().sample::<f64,_>(StandardNormal);
println!("{}", val);
}
This explicitly forces the sample function to return a f64. What was likely going on is that the rust type inference doesn't realize that the RHS needs to be f64, though I'm not sure exactly why.
Edit:
I think some the blame here goes to the definition of sample, in that it uses an unrestricted type parameter. An MVE for this would be:
pub trait Marker{}
impl Marker for f64{}
impl Marker for f32{}
fn does_not_work<T>() -> T{
unimplemented!()
}
fn does_work<T: Marker>() -> T{
unimplemented!()
}
fn main() {
let val: f64 = 0.1 * does_work();
let val: f64 = 0.1 * does_not_work();
}
It's somewhat understandable that the compiler can't infer types for does_not_work, b/c how is it meant to know about every possible type that could multiply with f64? However of we restrict things to only certain types with a trait, then the list of possible types becomes finite and type inference works again.
I've been trying to convert between a scancode and a character. This system has worked before but as of now, for no reason that I can tell, has stopped working.
static mut SCANCODE_BUFFER: winapi::shared::minwindef::PBYTE = std::ptr::null_mut();
static mut layout: winapi::shared::minwindef::HKL = std::ptr::null_mut();
pub fn SCANCODE_TO_CHAR(scancode: u32) -> char {
unsafe {
let mut result = [0 as u16; 2];
if GetKeyboardState(SCANCODE_BUFFER) == winapi::shared::minwindef::FALSE {
return 0 as char;
}
let vk = MapVirtualKeyExA(scancode, 1, layout);
ToAsciiEx(vk, scancode, SCANCODE_BUFFER, result.as_mut_ptr(), 0, layout);
result[0] as u8 as char
}
}
pub fn initialize() {
unsafe {
SCANCODE_BUFFER = [0 as u8; 256].as_mut_ptr();
layout = GetKeyboardLayout(0);
}
}
I've done some debugging, and it seems that the function call:
GetKeyboardState(SCANCODE_BUFFER)
Is causing the program to end with the this:
(exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
Does anyone know how this might be fixed?
Extra info:
SCANCODE_BUFFER is definitely not a null pointer.
Sorry for posting this. SCANCODE_BUFFER was pointing to dropped memory. I must have been extremely lucky in the past.
I tried to import the GetBinaryTypeA function:
use std::ffi::CString;
use ::std::os::raw::{c_char, c_ulong};
extern { fn GetBinaryTypeA(s: *const c_char, out: *mut c_ulong) -> i32; }
fn main() {
let path = "absolute/path/to/bin.exe";
let cpath = CString::new(path).unwrap();
let mut out: c_ulong = 0;
println!("{:?}", cpath);
unsafe { GetBinaryTypeA(cpath.as_ptr(), out as *mut c_ulong); }
println!("{:?}", cpath);
}
Output:
error: process didn't exit successfully: `target\debug\bin_deploy.exe` (exit code: 3221225477)
Process finished with exit code -1073741819 (0xC0000005)
If I set an invalid path then it executes successfully and GetLastError() returns 2 ("The system cannot find the file specified"), so it looks like the imported function works.
I received the same error using the kernel32-sys crate. Where else can the error be?
You are casting the value 0 to a pointer. On the vast majority of computers in use today, the pointer with the value 0 is known as NULL. Thus, you are trying to write to the NULL pointer, which causes a crash.
You want to write to the address of the value:
&mut out as *mut c_ulong
Which doesn't even need the cast:
unsafe {
GetBinaryTypeA(cpath.as_ptr(), &mut out);
}