raw_printer/
lib.rs

1#[cfg(test)]
2mod tests {
3    use super::*;
4
5    #[test]
6    #[cfg(target_os = "linux")]
7    fn test_write_to_device_linux() {
8        let result = write_to_device("/dev/usb/lp0", "^FDhello world");
9        assert!(result.is_ok());
10    }
11
12    #[test]
13    #[cfg(target_os = "windows")]
14    fn test_write_to_device_windows() {
15        let result = write_to_device("ZDesigner ZD220-203dpi ZPL", "^FDhello world");
16        assert!(result.is_ok());
17    }
18}
19
20/// # Platform-specific Behavior
21///
22/// This function returns a result containing the size of bytes written on success or an error.
23///
24/// - On Linux and Windows, the result type is `Result<usize, Error>`.
25/// - Note: On Windows, the original bytes written are u32 but cast to usize.
26///
27/// # Examples
28///
29/// ```
30/// let zpl = "^FDhello world";
31/// let printer = "/dev/usb/lp0";
32/// let result = raw_printer::write_to_device(printer, zpl);
33/// 
34/// assert!(result.is_ok());
35/// 
36/// ```
37#[cfg(target_os = "linux")]
38pub fn write_to_device(printer: &str, payload: &str) -> Result<usize, std::io::Error> {
39    use std::fs::OpenOptions;
40    use std::io::Write;
41
42    let device_path = OpenOptions::new().write(true).open(printer);
43
44    match device_path {
45        Ok(mut device) => {
46            let bytes_written = device.write(payload.as_bytes())?;
47            Ok(bytes_written)
48        }
49        Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e)),
50    }
51}
52
53#[cfg(target_os = "windows")]
54pub fn write_to_device(printer: &str, payload: &str) -> Result<usize, std::io::Error> {
55    use std::ffi::CString;
56    use std::ptr;
57    use windows::Win32::Foundation::HANDLE;
58    use windows::Win32::Graphics::Printing::{
59        ClosePrinter, EndDocPrinter, EndPagePrinter, OpenPrinterA, StartDocPrinterA,
60        StartPagePrinter, WritePrinter, DOC_INFO_1A, PRINTER_ACCESS_USE, PRINTER_DEFAULTSA,
61    };
62
63    let printer_name = CString::new(printer).unwrap_or_default(); // null-terminated string
64    let mut printer_handle: HANDLE = HANDLE(std::ptr::null_mut());
65
66    // Open the printer
67    unsafe {
68        let pd = PRINTER_DEFAULTSA {
69            pDatatype: windows::core::PSTR(ptr::null_mut()),
70            pDevMode: ptr::null_mut(),
71            DesiredAccess: PRINTER_ACCESS_USE,
72        };
73
74        if OpenPrinterA(
75            windows::core::PCSTR(printer_name.as_bytes().as_ptr()),
76            &mut printer_handle,
77            Some(&pd),
78        )
79        .is_ok()
80        {
81            let doc_info = DOC_INFO_1A {
82                pDocName: windows::core::PSTR("My Document\0".as_ptr() as *mut u8),
83                pOutputFile: windows::core::PSTR::null(),
84                pDatatype: windows::core::PSTR("RAW\0".as_ptr() as *mut u8),
85            };
86
87            // Start the document
88            let job = StartDocPrinterA(printer_handle, 1, &doc_info as *const _ as _);
89            if job == 0 {
90                return Err(std::io::Error::from(windows::core::Error::from_win32()));
91            }
92
93            // Start the page
94            if !StartPagePrinter(printer_handle).as_bool() {
95                return Err(std::io::Error::from(windows::core::Error::from_win32()));
96            }
97
98            let buffer = payload.as_bytes();
99
100            let mut bytes_written: u32 = 0;
101            if !WritePrinter(
102                printer_handle,
103                buffer.as_ptr() as _,
104                buffer.len() as u32,
105                &mut bytes_written,
106            )
107            .as_bool()
108            {
109                return Err(std::io::Error::from(windows::core::Error::from_win32()));
110            }
111
112            // End the page and document
113            let _ = EndPagePrinter(printer_handle);
114            let _ = EndDocPrinter(printer_handle);
115            let _ = ClosePrinter(printer_handle);
116            return Ok(bytes_written as usize);
117        } else {
118            return Err(std::io::Error::from(windows::core::Error::from_win32()));
119        }
120    }
121}