retep998 / winapi-rs

Rust bindings to Windows API
https://crates.io/crates/winapi
Apache License 2.0
1.83k stars 389 forks source link

WritePrinter doesn't support international characters #1049

Open hvpavan opened 10 months ago

hvpavan commented 10 months ago

Has anyone been successful in printing international charset using raw datatype? Here is the 3 step process I have

Step 1: Open Printer

let printer_name = "MY_PRINTER_NAME";

// Convert the printer name to a wide string (UTF-16)
let mut printer_name_wide: Vec<u16> = printer_name.encode_utf16().chain(std::iter::once(0)).collect();

// Declare a pointer to store the printer handle
let mut printer_handle: winapi::um::winnt::HANDLE = std::ptr::null_mut();
let mut datatype: &str = "RAW"; // XPS_PASS, EMF, 
let datatype_utf8 = std::ffi::CString::new(datatype).expect("CString::new failed");                          

let mut defaults = **PRINTER_DEFAULTSW**  {
    pDataType: ptr::null_mut(),
    pDevMode: ptr::null_mut(),
    DesiredAccess: 0x40000000, //GENERIC_WRITE
};    

// Call OpenPrinterW to open the specified printer
let result = unsafe {
    OpenPrinter2W(
        printer_name_wide.as_mut_ptr(),
        &mut printer_handle,
        &mut defaults,
        std::ptr::null_mut(),
    )
};

Step 2: Start Doc Printer

let job_name = "PrintJob";

let job_name_utf8 = std::ffi::CString::new(job_name).expect("CString::new failed");                          
let mut datatype: &str = "RAW"; // XPS_PASS, EMF, 
let datatype_utf8 = std::ffi::CString::new(datatype).expect("CString::new failed");                          

let mut datatype_wide: Vec<u8> = datatype.as_bytes().to_vec();

let docinfo1w = DOC_INFO_1W {
    pDocName: job_name_utf8.as_ptr() as *mut u16,
    pOutputFile: ptr::null_mut(),
    pDatatype: datatype_utf8.as_ptr() as *mut u16, // This works
};

fn struct_to_bytes<T>(data: &T) -> Vec<u8> {
    unsafe {
        let size = std::mem::size_of::<T>();
        let ptr = data as *const T as *const u8;
        std::slice::from_raw_parts(ptr, size).to_vec()
    }
}    

let struct_bytes: Vec<u8> = struct_to_bytes(&docinfo1w);   

let result = StartDocPrinterA (
    printer_handle,
    1, // Number of copies
    struct_bytes.as_ptr() as *mut u8); // DOC_INFO_1W

println!("Failed to start page. Error code: {}", unsafe {
    winapi::um::errhandlingapi::GetLastError()
});

Step 3: Print using WritePrinter

let page_result = unsafe { StartPagePrinter(printer_handle) };

println!("Page started successfully!");

let text_to_print = "Hello, 你好, привет!";      
let text_utf8 = std::ffi::CString::new(text_to_print).expect("CString::new failed");                          

let mut bytes_written: u32 = 0;

let write_result = unsafe {
    WritePrinter(
        printer_handle,
        text_utf8.as_ptr() as *mut winapi::ctypes::c_void,
        text_utf8.as_bytes().len() as u32 * 2,                        
        &mut bytes_written,
    )
};
hvpavan commented 10 months ago

I have tried encoding using encode_utf16 as well with no luck,

let text_to_print = "Hello, 你好, привет!";
let utf16_text: Vec = text_to_print.encode_utf16().collect();

Kreijstal commented 6 months ago

Just use windows-rs