You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Rust Winapi打印Unicode国际字符出现乱码求助

问题:使用Rust的winapi crate打印国际字符时热敏打印机输出乱码

我正在尝试用Rust的winapi crate打印国际字符,但热敏打印机输出乱码。试过用UTF-8编码处理数据,没解决问题。有没有人成功通过winapi在热敏打印机上打印国际字符?以下是我尝试的三步代码片段:

Step 1: 打开打印机

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: 启动打印任务

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(), // 此处正常工作
};

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, // 打印份数
    struct_bytes.as_ptr() as *mut u8);
println!("Failed to start page. Error code: {}", unsafe {
    winapi::um::errhandlingapi::GetLastError()
});

Step 3: 使用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,
    )
};

重点说明

  • 使用RAW作为数据类型
  • 尽可能使用以W结尾的Unicode版本函数
  • 采用encode_utf16编码数据内容

解决方案

问题核心是RAW模式下打印机不识别UTF-16编码。热敏打印机通常依赖内置的单字节字符集(如CP1250、ISO-8859-2这类区域编码),而非UTF-16双字节编码。

具体修正步骤:

  1. 确认打印机支持的编码
    查阅热敏打印机手册,找到它兼容的字符编码(比如示例中的波兰语对应CP1250编码)。

  2. 将文本转换为打印机支持的编码
    放弃encode_utf16,改用对应编码转换字节流:

    // 示例:转换为CP1250编码(适配中欧字符)
    use encoding_rs::WINDOWS_1250;
    let text_to_print = "Zażółć gęślą jaźń";
    let (encoded, _, _) = WINDOWS_1250.encode(text_to_print);
    // encoded即为打印机可识别的字节数组
    

    需在Cargo.toml中添加encoding_rs依赖。

  3. 调整WritePrinter调用
    直接传入编码后的字节数组,替换原UTF-16数据:

    let mut bytes_written: u32 = 0;
    let write_result = unsafe {
        WritePrinter(
            printer_handle,                      
            encoded.as_ptr() as *mut winapi::ctypes::c_void,
            encoded.len().try_into().unwrap(),
            &mut bytes_written,
        )
    };
    
  4. 额外注意

    • 若打印机明确支持UTF-8,也可尝试传入UTF-8字节流,但老式热敏打印机大多不支持,优先以手册指定编码为准。
    • RAW模式下Windows不会做编码转换,所有数据需保证是打印机可直接解析的格式。

内容的提问来源于stack exchange,提问作者PKH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 18:45:13