Skip to content

Commit cef7885

Browse files
committed
implement default printer
1 parent e15af1d commit cef7885

File tree

1 file changed

+47
-10
lines changed
  • paperjet/src/print/windows

1 file changed

+47
-10
lines changed

paperjet/src/print/windows/api.rs

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std::collections::HashMap;
22
use std::io::Read;
3-
use std::slice;
3+
use std::{ptr, slice};
44

5-
use windows::Win32::Graphics::Printing::{self, EnumPrintersW};
5+
use windows::Win32::Graphics::Printing;
6+
use windows::core::PWSTR;
67

78
use crate::error::PrintError;
89
use crate::options::PrintOptions;
@@ -16,7 +17,7 @@ impl CrossPlatformApi for PlatformSpecificApi {
1617
// First call to determine the buffer size (we use level 4 here, thus this is fast)
1718
// SAFETY: the only pointers we pass in are `buf_size` and `printers_len`, which are valid.
1819
let _ = unsafe {
19-
EnumPrintersW(
20+
Printing::EnumPrintersW(
2021
Printing::PRINTER_ENUM_LOCAL | Printing::PRINTER_ENUM_CONNECTIONS,
2122
None,
2223
4,
@@ -30,10 +31,10 @@ impl CrossPlatformApi for PlatformSpecificApi {
3031
// by the previous call to `EnumPrintersW`.
3132
let mut buf = vec![0u8; buf_size as usize];
3233
let result = unsafe {
33-
EnumPrintersW(
34+
Printing::EnumPrintersW(
3435
Printing::PRINTER_ENUM_LOCAL | Printing::PRINTER_ENUM_CONNECTIONS,
3536
None,
36-
5,
37+
4,
3738
Some(&mut buf),
3839
&mut buf_size,
3940
&mut printers_len,
@@ -51,7 +52,7 @@ impl CrossPlatformApi for PlatformSpecificApi {
5152
printers_len as usize,
5253
)
5354
.iter()
54-
.map(map_printer_info_4_to_printer)
55+
.map(|info4| map_printer_info_4_to_printer(info4))
5556
.collect::<Result<Vec<_>, _>>()
5657
}
5758
}
@@ -61,7 +62,29 @@ impl CrossPlatformApi for PlatformSpecificApi {
6162
}
6263

6364
fn get_default_printer() -> Option<Printer> {
64-
todo!("Not supported on Windows yet")
65+
let mut len = 0;
66+
67+
// First call to determine the string length
68+
// SAFETY: the first argument can be a null pointer, and the second is a valid pointer to an
69+
// integer.
70+
let _ = unsafe { Printing::GetDefaultPrinterW(PWSTR(ptr::null_mut()), &mut len) };
71+
72+
// Second call to fill the buffer with the string bytes
73+
// SAFETY: both pointers are valid and will be populated with valid contents by Windows.
74+
let mut buf = vec![0u16; len as usize];
75+
let status = unsafe { Printing::GetDefaultPrinterW(PWSTR(buf.as_mut_ptr()), &mut len) };
76+
if !status.as_bool() {
77+
return None;
78+
}
79+
80+
let name = String::from_utf16_lossy(&buf[..(buf.len() - 1)]);
81+
Some(Printer {
82+
identifier: name.clone(),
83+
name,
84+
instance: None,
85+
is_default: true,
86+
options: HashMap::new(),
87+
})
6588
}
6689

6790
fn print<I, R>(_readers: I, _printer: Printer, _options: PrintOptions) -> Result<(), PrintError>
@@ -74,10 +97,24 @@ impl CrossPlatformApi for PlatformSpecificApi {
7497
}
7598

7699
/// Converts the [`PRINTER_INFO_4W`] instance to a [`Printer`] instance.
77-
fn map_printer_info_4_to_printer(info: &Printing::PRINTER_INFO_4W) -> Result<Printer, PrintError> {
100+
///
101+
/// # Safety
102+
/// `info` must be a valid reference to a valid `PRINTER_INFO_4W`.
103+
unsafe fn map_printer_info_4_to_printer(
104+
info: &Printing::PRINTER_INFO_4W,
105+
) -> Result<Printer, PrintError> {
106+
// SAFETY: info is a valid `PRINTER_INFO_4W` instance, as per the precondition.
107+
let identifier = unsafe { info.pPrinterName.to_string()? };
108+
109+
if let Some(default_printer) = crate::get_default_printer() {
110+
if default_printer.identifier == identifier {
111+
return Ok(default_printer);
112+
}
113+
};
114+
78115
Ok(Printer {
79-
identifier: unsafe { info.pPrinterName.to_string()? },
80-
name: unsafe { info.pPrinterName.to_string()? },
116+
identifier: identifier.clone(),
117+
name: identifier,
81118
instance: None,
82119
is_default: false,
83120
options: HashMap::new(),

0 commit comments

Comments
 (0)