microsoft / windows-rs

Rust for Windows
https://kennykerr.ca/rust-getting-started/
Apache License 2.0
10.1k stars 473 forks source link

Help needed: How to safely cast GetPrinter [u8] buffer to PRINTER_INFO #3139

Closed ValentinGrim closed 4 days ago

ValentinGrim commented 6 days ago

Summary

Hi,

I'm trying to get the printer info of a printer using GetPrinterW function but I'm stuck casting PRINTER_INFO_2W from raw [u8] buffer.

I based my code on issue 2975 that's use EnumPrinters.

I have this (see last line comments):

unsafe {
    let mut printer_h = HANDLE::default();
    if let Err(e) = OpenPrinterW(self.printer_name.as_pwstr(), &mut printer_h, None) {
        return err!("OpenPrinter", e);
    }

    let mut needed : u32 = 0;
    if let Err(e) = GetPrinterW(printer_h, 2, None, &mut needed) {
        if e.code() != HRESULT::from_win32(ERROR_INSUFFICIENT_BUFFER.0) {
            return err!("GetPrinter", e);
        }
    }

    let mut buffer: Vec<u8> = vec![0; needed as usize];
    if let Err(e) = GetPrinterW(printer_h, 2, Some(&mut buffer), &mut needed) {
        return err!("GetPrinter", e);
    }

    /** Here where I'm lost.
      * The line below is based on issue 2975 but it gave me a Vec, not a single element.
      * I also tried to get the first element but i get STATUS_ACCESS_VIOLATION on various item.
      * What have i missed ?
      **/
    let printer_info: &[PRINTER_INFO_2W] = std::slice::from_raw_parts(buffer.as_ptr() as *const _, needed as usize);

    /* ... */

    if let Err(e) = ClosePrinter(printer_h) {
        return err!("ClosePrinter", e);
    }
}

Any help would be apreciated, thank's in advance. Have a nice day.

Crate manifest

No response

Crate code

No response

kennykerr commented 4 days ago

I think you just need to cast the byte pointer to a pointer of the appropriate structure. I'm not sure why you're casting it to an array/slice of structures. The API docs seem to indicate that it returns a single structure.

ValentinGrim commented 4 days ago

Actually, windows-rs is the first crate that I use that made me use raw pointer in Rust. I'm not actually into casting raw pointer and unsafe code in general. That's a discovery for me.

Anyway, I think you mean something like that, and it work that way so I post it if someone needs it.

let printer_info = std::ptr::slice_from_raw_parts(buffer.as_ptr(), buffer.len()) as *const PRINTER_INFO_2W; 

Thanks