Rust Winapi is printing garbage while printing unicode international characters

85 views Asked by At

I have been dabbling with winapi crate for printing international characters. For some reason the thermal printer seems to be printing garbage.

I have tried to encode using utf8 encoding of data but with no luck.

Has anyone been able to print international charset using winapi on a thermal printer?

Here is the 3 step code snippet of what I have tried:

Step 1: Open Printer
--------------------

    let printer_name = "MY_PRINTER_NAME";

    let mut printer_name_wide: Vec<u16> = printer_name.encode_utf16().chain(std::iter::once(0)).collect();
    let mut printer_handle: winapi::um::winnt::HANDLE = std::ptr::null_mut();
    let datatype: &str = "RAW"; // XPS_PASS, EMF, 
    let datatype_wide: Vec<u16> = datatype.encode_utf16().chain(std::iter::once(0)).collect();                      

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

    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 utf16_job_name: Vec<u16> = job_name.encode_utf16().collect();     

            let datatype: &str = "RAW"; // XPS_PASS, EMF, 
            let mut datatype_utf16: Vec<u16> = datatype.encode_utf16().chain(std::iter::once(0)).collect();
            
            let docinfo1w = DOC_INFO_1W {
                pDocName: utf16_job_name.as_ptr() as *mut u16,
                pOutputFile: ptr::null_mut(),
                pDatatype: datatype_utf16.as_mut_ptr(), // 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 = StartDocPrinterW (
                printer_handle,
                1, // Number of copies
                struct_bytes.as_ptr() as *mut u8);
                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 = "Zażółć gęślą jaźń";
                let utf16_text: Vec<u16> = text_to_print.encode_utf16().chain(std::iter::once(0)).collect();       

                let mut bytes_written: u32 = 0;

                let write_result = unsafe {
                    WritePrinter(
                        printer_handle,                      
                        utf16_text.as_ptr() as *mut winapi::ctypes::c_void,
                        utf16_text.len().try_into().unwrap(),
                        &mut bytes_written,
                    )
                };

Points to Highlight:

  • Used RAW as datatype
  • As for as possible, have used unicode version of functions, that ends with W than A
  • Encoded, data using encode_utf16
0

There are 0 answers