Print: open printing preferences for the selected printer on Windows (#2569)

When pressing Ctrl+P to open the Print dialog and clicking Setup (or Settings), print.printerSetup previously discarded the selected printer name and unconditionally launched explorer ms-settings:printers. On Windows 10, this opened the Windows Settings Printers and scanners page, displaying the list of installed printers instead of the printer driver printing preferences.

Launch Windows native Printing Preferences dialog for the target printer using rundll32.exe printui.dll,PrintUIEntry /e /n printer, falling back to the system default printer or Settings if no printer is available or detected. Add unit tests covering command construction and fallback behavior.

Fixes #2569.
This commit is contained in:
DENNIS MUUO
2026-10-17 15:14:43 +07:00
committed by bflatastic
parent 6daf74fb6d
commit b959cd90da
2 changed files with 64 additions and 2 deletions
+61 -2
View File
@@ -43,11 +43,32 @@ mod system {
let settings = craft_print::Job { printer: job.printer.map(str::to_string), title: job.title.into(), ..Default::default() };
craft_print::submit(job.pdf, &settings).map(|note| if note.is_empty() { note } else { format!(" ({note})") }).map_err(|e| e.to_string())
}
#[cfg(windows)]
pub(crate) fn setup_command(printer: Option<&str>, default_printer: Option<&str>) -> Command {
let target = printer
.map(str::trim)
.filter(|p| !p.is_empty())
.or_else(|| default_printer.map(str::trim).filter(|p| !p.is_empty()));
if let Some(name) = target {
let mut cmd = Command::new("rundll32.exe");
cmd.args(["printui.dll,PrintUIEntry", "/e", "/n", name]);
cmd
} else {
let mut cmd = Command::new("explorer");
cmd.arg("ms-settings:printers");
cmd
}
}
pub fn setup(printer: Option<&str>) -> Result<(), String> {
#[cfg(windows)]
{
let _ = printer;
Command::new("explorer").arg("ms-settings:printers").spawn().map(|_| ()).map_err(|e| e.to_string())
let list = printers();
let default = list.iter().find(|p| p.default).or_else(|| list.first()).map(|p| p.name.as_str());
let mut cmd = setup_command(printer, default);
match cmd.spawn() {
Ok(_) => Ok(()),
Err(_) => Command::new("explorer").arg("ms-settings:printers").spawn().map(|_| ()).map_err(|e| e.to_string()),
}
}
#[cfg(target_os = "macos")]
{
@@ -68,3 +89,41 @@ mod system {
}
}
}
#[cfg(all(test, windows, not(any(feature = "windows7", target_vendor = "win7"))))]
mod tests {
use super::system::setup_command;
use std::ffi::OsStr;
#[test]
fn setup_command_uses_printui_for_specified_printer() {
let cmd = setup_command(Some("Office Laser"), None);
assert_eq!(cmd.get_program(), "rundll32.exe");
let args: Vec<&OsStr> = cmd.get_args().collect();
assert_eq!(args, ["printui.dll,PrintUIEntry", "/e", "/n", "Office Laser"]);
}
#[test]
fn setup_command_falls_back_to_default_printer() {
let cmd = setup_command(None, Some("Default Proofer"));
assert_eq!(cmd.get_program(), "rundll32.exe");
let args: Vec<&OsStr> = cmd.get_args().collect();
assert_eq!(args, ["printui.dll,PrintUIEntry", "/e", "/n", "Default Proofer"]);
}
#[test]
fn setup_command_trims_whitespace_and_skips_empty() {
let cmd = setup_command(Some(" "), Some("Default Proofer"));
assert_eq!(cmd.get_program(), "rundll32.exe");
let args: Vec<&OsStr> = cmd.get_args().collect();
assert_eq!(args, ["printui.dll,PrintUIEntry", "/e", "/n", "Default Proofer"]);
}
#[test]
fn setup_command_falls_back_to_settings_when_no_printer() {
let cmd = setup_command(None, None);
assert_eq!(cmd.get_program(), "explorer");
let args: Vec<&OsStr> = cmd.get_args().collect();
assert_eq!(args, ["ms-settings:printers"]);
}
}