microsoft / windows-rs

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

Graphics::Printing : DocumentProperties return wrong size #3122

Closed ValentinGrim closed 3 months ago

ValentinGrim commented 3 months ago

Summary

Hi there,

I'm facing some challenges while trying to retrieve the DEVMODE of a printer using DocumentPropertiesW in Rust. I have existing C++ code that successfully accomplishes this using the standard Windows API. Here's the C++ code for reference:

bool getDevMode(TCHAR* deviceName, DEVMODE** devMode)
{
    HANDLE hPrinter = NULL;
    HWND hWnd = NULL;
    bool res = false;

    // Acquires the printer handle.
    if (OpenPrinter(deviceName, &(hPrinter), NULL) == 0)
        return false;

    // Acquires the DEVMODE structure size.
    DWORD dwNeeded = DocumentProperties(hWnd, hPrinter, deviceName, NULL, NULL, 0);
    if (dwNeeded > 0)
    {
        // Allocates a memory area to acquire DEVMODE structure information.
        *devMode = (LPDEVMODE)malloc(dwNeeded);
        if (*devMode != NULL)
        {
            // Acquires the DEVMODE structure.
            DWORD dwReturned = DocumentProperties(hWnd, hPrinter, deviceName, *devMode, NULL, DM_OUT_BUFFER);
            if (dwReturned > 0)
                res = true;
        }
    }
    // Closes the printer handle.
    if (hPrinter != NULL)
    {
        ClosePrinter(hPrinter);
        hPrinter = NULL;
    }
    return res;
}

I'm trying to reproduce this functionality in Rust, but I've encountered a couple of challenges:

Here's my Rust code:

    pub fn get_devmode (&mut self) -> bool {
        unsafe {
            // convert printer name form string
            let pname = PWSTR(self.printer_name.encode_utf16().chain(::std::iter::once(0)).collect::<Vec<u16>>().as_mut_ptr());
            match OpenPrinterW(pname, &mut self.printer_h, None) {
                Ok(_) => {}
                Err(e) => {
                    eprintln!("{e}");
                    return false;
                }
            }
            let hwnd: HWND = HWND::default();
            let size = DocumentPropertiesW(hwnd, self.printer_h, pname,None , None, 0);
            println!("Size : {size}"); // Gave me 18200 (and 17888 with DocumentPropertiesA)
            // Below here's where I don't know what to do, using DEVMODEW::default() result in STATUS_ACCESS_VIOLATION
            // let mut devmode = DEVMODEW::default();
            //let size = DocumentPropertiesW(hwnd, self.printer_h, pname,Some(&mut devmode) , None, DM_OUT_BUFFER.0);
        }
        return true;
    }

Crate manifest

No response

Crate code

No response

riverar commented 3 months ago

How about something like this? Can't guarantee this is the most idiomatic, maybe others have some suggestions.

[dependencies.windows]
version = "0.57.0"
features = [
    "Win32_Foundation",
    "Win32_Graphics_Gdi",
    "Win32_Graphics_Printing"
]
use std::{
    alloc::{alloc, alloc_zeroed, dealloc, Layout},
    mem::align_of,
};

use windows::{
    core::w,
    Win32::{
        Foundation::{HANDLE, HWND},
        Graphics::{
            Gdi::{DEVMODEW, DM_OUT_BUFFER},
            Printing::{DocumentPropertiesW, OpenPrinterW},
        },
    },
};

fn main() -> windows::core::Result<()> {
    unsafe {
        let device_name = w!("Brother MFC-L2740DW series");

        let mut handle = HANDLE::default();
        OpenPrinterW(device_name, &mut handle, None)?;

        let size = DocumentPropertiesW(HWND::default(), handle, device_name, None, None, 0);

        let layout = Layout::from_size_align(size as usize, align_of::<DEVMODEW>()).unwrap();
        let mut devmode = alloc_zeroed(layout) as *mut DEVMODEW;

        let written = DocumentPropertiesW(
            HWND::default(),
            handle,
            device_name,
            Some(devmode),
            None,
            DM_OUT_BUFFER.0,
        );

        dbg!((*devmode).dmYResolution);

        // ...
    }

    Ok(())
}
ValentinGrim commented 3 months ago

@riverar.

Adapted the sample you gave me and it work just as intended! Thank you very much.