如何用Rust的windows crate调用EnumPrintersA获取PRINTER_INFO_4A列表
Rust调用EnumPrintersA获取PRINTER_INFO_4A列表
实现步骤与代码示例
EnumPrintersA需要分两次调用完成数据获取:先获取所需缓冲区大小,再分配内存读取实际打印机信息。以下是完整实现:
use windows::Win32::Graphics::Printing::{EnumPrintersA, PRINTER_INFO_4A}; use windows::Win32::Foundation::PCSTR; use windows_core::Result; fn get_printer_info_list() -> Result<Vec<PRINTER_INFO_4A>> { unsafe { // 1. 首次调用:获取所需缓冲区大小 let mut pcbneeded = 0; // 传入null参数触发返回所需大小,忽略返回的打印机数量 EnumPrintersA( 2, // PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS PCSTR::null(), 4, // 指定获取PRINTER_INFO_4A结构 None, // 缓冲区传None对应null指针 &mut pcbneeded, std::ptr::null_mut(), // 数量参数传null )?; // 根据返回的大小分配缓冲区 let mut buffer = vec![0u8; pcbneeded as usize]; // 2. 二次调用:获取实际打印机数据 let mut pcbreturned = 0; EnumPrintersA( 2, PCSTR::null(), 4, Some(&mut buffer), // 传入分配好的可变缓冲区 &mut pcbneeded, &mut pcbreturned, )?; // 将字节缓冲区转换为PRINTER_INFO_4A切片 let info_slice = std::slice::from_raw_parts( buffer.as_ptr() as *const PRINTER_INFO_4A, pcbreturned as usize, ); // 转换为Vec返回 Ok(info_slice.to_vec()) } } fn main() -> Result<()> { let printers = get_printer_info_list()?; for (i, printer) in printers.iter().enumerate() { println!("打印机 {}: {:?}", i + 1, printer.pPrinterName); } Ok(()) }
关键细节解答
1. 变量声明要点
pcbneeded:u32类型,用于存储API返回的所需缓冲区字节数。pcbreturned:u32类型,存储实际返回的PRINTER_INFO_4A结构体数量。buffer:Vec<u8>,自动管理内存的缓冲区,首次调用后根据pcbneeded动态分配大小。
2. 两次调用的参数传递规则
- 首次调用:
name:传PCSTR::null(),配合flags=2枚举本地和已连接打印机。pprinterenum:传None,对应C语言的NULL指针,告诉API只返回所需缓冲区大小。pcreturned:传std::ptr::null_mut(),首次调用不需要返回打印机数量。
- 二次调用:
pprinterenum:传Some(&mut buffer),将分配好的可变字节缓冲区传给API。pcreturned:传&mut pcbreturned的指针,用于接收返回的打印机数量。
3. 缓冲区转换为目标结构体
利用std::slice::from_raw_parts将字节缓冲区的指针转换为PRINTER_INFO_4A类型的切片,再通过to_vec()转换为Vec<PRINTER_INFO_4A>,完成类型安全的转换。
内容的提问来源于stack exchange,提问作者e-Ra
相关产品推荐
相关产品推荐

