使用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双字节编码。
具体修正步骤:
确认打印机支持的编码
查阅热敏打印机手册,找到它兼容的字符编码(比如示例中的波兰语对应CP1250编码)。将文本转换为打印机支持的编码
放弃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依赖。调整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, ) };额外注意
- 若打印机明确支持UTF-8,也可尝试传入UTF-8字节流,但老式热敏打印机大多不支持,优先以手册指定编码为准。
- RAW模式下Windows不会做编码转换,所有数据需保证是打印机可直接解析的格式。
内容的提问来源于stack exchange,提问作者PKH
相关产品推荐
相关产品推荐

