23 #include <freerdp/config.h>
25 #include <winpr/crt.h>
26 #include <winpr/wtsapi.h>
27 #include <winpr/string.h>
28 #include <winpr/windows.h>
36 #include <freerdp/client/printer.h>
38 #define WIDEN_INT(x) L##x
39 #define WIDEN(x) WIDEN_INT(x)
40 #define PRINTER_TAG CHANNELS_TAG("printer.client")
41 #ifdef WITH_DEBUG_WINPR
42 #define DEBUG_WINPR(...) WLog_DBG(PRINTER_TAG, __VA_ARGS__)
44 #define DEBUG_WINPR(...) \
52 rdpPrinterDriver driver;
56 } rdpWinPrinterDriver;
64 void* printjob_object;
72 rdpWinPrintJob* printjob;
75 static WCHAR* printer_win_get_printjob_name(
size_t id)
85 err = localtime_s(&tres, &tt);
87 str = calloc(len,
sizeof(WCHAR));
91 rc = swprintf_s(str, len,
92 WIDEN(
"FreeRDP Print %04d-%02d-%02d% 02d-%02d-%02d - Job %") WIDEN(PRIuz)
94 tres.tm_year + 1900, tres.tm_mon + 1, tres.tm_mday, tres.tm_hour, tres.tm_min,
105 static UINT printer_win_write_printjob(rdpPrintJob* printjob,
const BYTE* data,
size_t size)
107 rdpWinPrinter* printer;
112 if (!printjob || !data)
113 return ERROR_BAD_ARGUMENTS;
115 printer = (rdpWinPrinter*)printjob->printer;
117 return ERROR_BAD_ARGUMENTS;
119 if (!WritePrinter(printer->hPrinter, pBuf, cbBuf, &pcWritten))
120 return ERROR_INTERNAL_ERROR;
121 return CHANNEL_RC_OK;
124 static void printer_win_close_printjob(rdpPrintJob* printjob)
126 rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
127 rdpWinPrinter* win_printer;
132 win_printer = (rdpWinPrinter*)printjob->printer;
136 if (!EndPagePrinter(win_printer->hPrinter))
140 if (!EndDocPrinter(win_printer->hPrinter))
144 win_printer->printjob = NULL;
146 free(win_printjob->di.pDocName);
150 static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32
id)
152 rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
153 rdpWinPrintJob* win_printjob;
155 if (win_printer->printjob != NULL)
158 win_printjob = (rdpWinPrintJob*)calloc(1,
sizeof(rdpWinPrintJob));
162 win_printjob->printjob.id = id;
163 win_printjob->printjob.printer = printer;
164 win_printjob->di.pDocName = printer_win_get_printjob_name(
id);
165 win_printjob->di.pDatatype = NULL;
166 win_printjob->di.pOutputFile = NULL;
168 win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) & (win_printjob->di));
170 if (!win_printjob->handle)
172 free(win_printjob->di.pDocName);
177 if (!StartPagePrinter(win_printer->hPrinter))
179 free(win_printjob->di.pDocName);
184 win_printjob->printjob.Write = printer_win_write_printjob;
185 win_printjob->printjob.Close = printer_win_close_printjob;
187 win_printer->printjob = win_printjob;
189 return &win_printjob->printjob;
192 static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32
id)
194 rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
196 if (!win_printer->printjob)
199 if (win_printer->printjob->printjob.id !=
id)
202 return (rdpPrintJob*)win_printer->printjob;
205 static void printer_win_free_printer(rdpPrinter* printer)
207 rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
209 if (win_printer->printjob)
210 win_printer->printjob->printjob.Close((rdpPrintJob*)win_printer->printjob);
212 if (win_printer->hPrinter)
213 ClosePrinter(win_printer->hPrinter);
215 if (printer->backend)
216 printer->backend->ReleaseRef(printer->backend);
219 free(printer->driver);
223 static void printer_win_add_ref_printer(rdpPrinter* printer)
226 printer->references++;
229 static void printer_win_release_ref_printer(rdpPrinter* printer)
233 if (printer->references <= 1)
234 printer_win_free_printer(printer);
236 printer->references--;
239 static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver,
const WCHAR* name,
240 const WCHAR* drivername, BOOL is_default)
242 rdpWinPrinter* win_printer;
244 PRINTER_INFO_2* prninfo = NULL;
249 win_printer = (rdpWinPrinter*)calloc(1,
sizeof(rdpWinPrinter));
253 win_printer->printer.backend = &win_driver->driver;
254 win_printer->printer.id = win_driver->id_sequence++;
255 win_printer->printer.name = ConvertWCharToUtf8Alloc(name, NULL);
256 if (!win_printer->printer.name)
259 if (!win_printer->printer.name)
261 win_printer->printer.is_default = is_default;
263 win_printer->printer.CreatePrintJob = printer_win_create_printjob;
264 win_printer->printer.FindPrintJob = printer_win_find_printjob;
265 win_printer->printer.AddRef = printer_win_add_ref_printer;
266 win_printer->printer.ReleaseRef = printer_win_release_ref_printer;
268 if (!OpenPrinter(name, &(win_printer->hPrinter), NULL))
272 GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, 0, &needed);
276 prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed);
280 if (!GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, needed, &needed))
287 win_printer->printer.driver = ConvertWCharToUtf8Alloc(drivername, NULL);
289 win_printer->printer.driver = ConvertWCharToUtf8Alloc(prninfo->pDriverName, NULL);
291 if (!win_printer->printer.driver)
294 win_printer->printer.AddRef(&win_printer->printer);
295 win_printer->printer.backend->AddRef(win_printer->printer.backend);
296 return &win_printer->printer;
299 printer_win_free_printer(&win_printer->printer);
303 static void printer_win_release_enum_printers(rdpPrinter** printers)
305 rdpPrinter** cur = printers;
307 while ((cur != NULL) && ((*cur) != NULL))
309 if ((*cur)->ReleaseRef)
310 (*cur)->ReleaseRef(*cur);
316 static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
318 rdpPrinter** printers;
320 PRINTER_INFO_2* prninfo = NULL;
321 DWORD needed, returned;
322 BOOL haveDefault = FALSE;
323 LPWSTR defaultPrinter = NULL;
325 GetDefaultPrinter(NULL, &needed);
328 defaultPrinter = (LPWSTR)calloc(needed,
sizeof(WCHAR));
333 if (!GetDefaultPrinter(defaultPrinter, &needed))
334 defaultPrinter[0] =
'\0';
338 EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed,
342 prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed);
345 free(defaultPrinter);
350 if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE)prninfo,
351 needed, &needed, &returned))
355 printers = (rdpPrinter**)calloc((returned + 1),
sizeof(rdpPrinter*));
359 free(defaultPrinter);
365 for (
int i = 0; i < (int)returned; i++)
367 rdpPrinter* current = printers[num_printers];
368 current = printer_win_new_printer((rdpWinPrinterDriver*)driver, prninfo[i].pPrinterName,
369 prninfo[i].pDriverName,
370 _wcscmp(prninfo[i].pPrinterName, defaultPrinter) == 0);
373 printer_win_release_enum_printers(printers);
377 if (current->is_default)
379 printers[num_printers++] = current;
382 if (!haveDefault && (returned > 0))
383 printers[0]->is_default = TRUE;
386 free(defaultPrinter);
390 static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver,
const char* name,
391 const char* driverName, BOOL isDefault)
393 WCHAR* driverNameW = NULL;
395 rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
396 rdpPrinter* myPrinter = NULL;
400 nameW = ConvertUtf8ToWCharAlloc(name, NULL);
406 driverNameW = ConvertUtf8ToWCharAlloc(driverName, NULL);
411 myPrinter = printer_win_new_printer(win_driver, nameW, driverNameW, isDefault);
418 static void printer_win_add_ref_driver(rdpPrinterDriver* driver)
420 rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver;
426 static rdpWinPrinterDriver* win_driver = NULL;
428 static void printer_win_release_ref_driver(rdpPrinterDriver* driver)
430 rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver;
431 if (win->references <= 1)
440 FREERDP_ENTRY_POINT(UINT VCAPITYPE win_freerdp_printer_client_subsystem_entry(
void* arg))
442 rdpPrinterDriver** ppPrinter = (rdpPrinterDriver**)arg;
444 return ERROR_INVALID_PARAMETER;
448 win_driver = (rdpWinPrinterDriver*)calloc(1,
sizeof(rdpWinPrinterDriver));
451 return ERROR_OUTOFMEMORY;
453 win_driver->driver.EnumPrinters = printer_win_enum_printers;
454 win_driver->driver.ReleaseEnumPrinters = printer_win_release_enum_printers;
455 win_driver->driver.GetPrinter = printer_win_get_printer;
457 win_driver->driver.AddRef = printer_win_add_ref_driver;
458 win_driver->driver.ReleaseRef = printer_win_release_ref_driver;
460 win_driver->id_sequence = 1;
463 win_driver->driver.AddRef(&win_driver->driver);
465 *ppPrinter = &win_driver->driver;
466 return CHANNEL_RC_OK;