23#include <freerdp/config.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;
64 void* printjob_object;
72 rdpWinPrintJob* printjob;
75WINPR_ATTR_MALLOC(free, 1)
76static WCHAR* printer_win_get_printjob_name(
size_t id)
82 const time_t tt = time(NULL);
83 const errno_t err = localtime_s(&tres, &tt);
89 str = calloc(len + 1,
sizeof(WCHAR));
94 const int rc = swprintf_s(
96 WIDEN(
"%s Print %04d-%02d-%02d% 02d-%02d-%02d - Job %") WIDEN(PRIuz) WIDEN(
"\0"),
97 freerdp_getApplicationDetailsStringW(), tres.tm_year + 1900, tres.tm_mon + 1,
98 tres.tm_mday, tres.tm_hour, tres.tm_min, tres.tm_sec,
id);
104 len = WINPR_ASSERTING_INT_CAST(
size_t, rc) + 1ull;
115static UINT printer_win_write_printjob(rdpPrintJob* printjob,
const BYTE* data,
size_t size)
120 if (size > UINT32_MAX)
121 return ERROR_BAD_ARGUMENTS;
123 if (!printjob || !data)
124 return ERROR_BAD_ARGUMENTS;
126 rdpWinPrinter* printer = (rdpWinPrinter*)printjob->printer;
128 return ERROR_BAD_ARGUMENTS;
130 DWORD cbBuf = WINPR_ASSERTING_INT_CAST(uint32_t, size);
131 if (!WritePrinter(printer->hPrinter, WINPR_CAST_CONST_PTR_AWAY(pBuf,
void*), cbBuf, &pcWritten))
132 return ERROR_INTERNAL_ERROR;
133 return CHANNEL_RC_OK;
136static void printer_win_close_printjob(rdpPrintJob* printjob)
138 rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
139 rdpWinPrinter* win_printer;
144 win_printer = (rdpWinPrinter*)printjob->printer;
148 if (!EndPagePrinter(win_printer->hPrinter))
152 if (!EndDocPrinter(win_printer->hPrinter))
156 win_printer->printjob = NULL;
158 free(win_printjob->di.pDocName);
162static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32
id)
164 rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
165 rdpWinPrintJob* win_printjob;
167 if (win_printer->printjob != NULL)
170 win_printjob = (rdpWinPrintJob*)calloc(1,
sizeof(rdpWinPrintJob));
174 win_printjob->printjob.id = id;
175 win_printjob->printjob.printer = printer;
176 win_printjob->di.pDocName = printer_win_get_printjob_name(
id);
177 win_printjob->di.pDatatype = NULL;
178 win_printjob->di.pOutputFile = NULL;
180 win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) & (win_printjob->di));
182 if (!win_printjob->handle)
184 free(win_printjob->di.pDocName);
189 if (!StartPagePrinter(win_printer->hPrinter))
191 free(win_printjob->di.pDocName);
196 win_printjob->printjob.Write = printer_win_write_printjob;
197 win_printjob->printjob.Close = printer_win_close_printjob;
199 win_printer->printjob = win_printjob;
201 return &win_printjob->printjob;
204static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32
id)
206 rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
208 if (!win_printer->printjob)
211 if (win_printer->printjob->printjob.id !=
id)
214 return (rdpPrintJob*)win_printer->printjob;
217static void printer_win_free_printer(rdpPrinter* printer)
219 rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
221 if (win_printer->printjob)
222 win_printer->printjob->printjob.Close((rdpPrintJob*)win_printer->printjob);
224 if (win_printer->hPrinter)
225 ClosePrinter(win_printer->hPrinter);
227 if (printer->backend)
228 printer->backend->ReleaseRef(printer->backend);
231 free(printer->driver);
235static void printer_win_add_ref_printer(rdpPrinter* printer)
238 printer->references++;
241static void printer_win_release_ref_printer(rdpPrinter* printer)
245 if (printer->references <= 1)
246 printer_win_free_printer(printer);
248 printer->references--;
251static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver,
const WCHAR* name,
252 const WCHAR* drivername, BOOL is_default)
254 rdpWinPrinter* win_printer;
256 PRINTER_INFO_2* prninfo = NULL;
261 win_printer = (rdpWinPrinter*)calloc(1,
sizeof(rdpWinPrinter));
265 win_printer->printer.backend = &win_driver->driver;
266 win_printer->printer.id = win_driver->id_sequence++;
267 win_printer->printer.name = ConvertWCharToUtf8Alloc(name, NULL);
268 if (!win_printer->printer.name)
271 if (!win_printer->printer.name)
273 win_printer->printer.is_default = is_default;
275 win_printer->printer.CreatePrintJob = printer_win_create_printjob;
276 win_printer->printer.FindPrintJob = printer_win_find_printjob;
277 win_printer->printer.AddRef = printer_win_add_ref_printer;
278 win_printer->printer.ReleaseRef = printer_win_release_ref_printer;
280 if (!OpenPrinter(WINPR_CAST_CONST_PTR_AWAY(name, WCHAR*), &(win_printer->hPrinter), NULL))
284 GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, 0, &needed);
288 prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed);
292 if (!GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, needed, &needed))
299 win_printer->printer.driver = ConvertWCharToUtf8Alloc(drivername, NULL);
301 win_printer->printer.driver = ConvertWCharToUtf8Alloc(prninfo->pDriverName, NULL);
303 if (!win_printer->printer.driver)
306 win_printer->printer.AddRef(&win_printer->printer);
307 win_printer->printer.backend->AddRef(win_printer->printer.backend);
308 return &win_printer->printer;
311 printer_win_free_printer(&win_printer->printer);
315static void printer_win_release_enum_printers(rdpPrinter** printers)
317 rdpPrinter** cur = printers;
319 while ((cur != NULL) && ((*cur) != NULL))
321 if ((*cur)->ReleaseRef)
322 (*cur)->ReleaseRef(*cur);
328static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
330 rdpPrinter** printers;
332 PRINTER_INFO_2* prninfo = NULL;
333 DWORD needed, returned;
334 BOOL haveDefault = FALSE;
335 LPWSTR defaultPrinter = NULL;
337 GetDefaultPrinter(NULL, &needed);
340 defaultPrinter = (LPWSTR)calloc(needed,
sizeof(WCHAR));
345 if (!GetDefaultPrinter(defaultPrinter, &needed))
346 defaultPrinter[0] =
'\0';
350 EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed,
354 prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed);
357 free(defaultPrinter);
362 if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE)prninfo,
363 needed, &needed, &returned))
367 printers = (rdpPrinter**)calloc((returned + 1),
sizeof(rdpPrinter*));
371 free(defaultPrinter);
377 for (
int i = 0; i < (int)returned; i++)
379 rdpPrinter* current = printers[num_printers];
380 current = printer_win_new_printer((rdpWinPrinterDriver*)driver, prninfo[i].pPrinterName,
381 prninfo[i].pDriverName,
382 _wcscmp(prninfo[i].pPrinterName, defaultPrinter) == 0);
385 printer_win_release_enum_printers(printers);
389 if (current->is_default)
391 printers[num_printers++] = current;
394 if (!haveDefault && (returned > 0))
395 printers[0]->is_default = TRUE;
398 free(defaultPrinter);
402static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver,
const char* name,
403 const char* driverName, BOOL isDefault)
405 WCHAR* driverNameW = NULL;
407 rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
408 rdpPrinter* myPrinter = NULL;
412 nameW = ConvertUtf8ToWCharAlloc(name, NULL);
418 driverNameW = ConvertUtf8ToWCharAlloc(driverName, NULL);
423 myPrinter = printer_win_new_printer(win_driver, nameW, driverNameW, isDefault);
430static void printer_win_add_ref_driver(rdpPrinterDriver* driver)
432 rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver;
438static rdpWinPrinterDriver* win_driver = NULL;
440static void printer_win_release_ref_driver(rdpPrinterDriver* driver)
442 rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver;
443 if (win->references <= 1)
452FREERDP_ENTRY_POINT(UINT VCAPITYPE win_freerdp_printer_client_subsystem_entry(
void* arg))
454 rdpPrinterDriver** ppPrinter = (rdpPrinterDriver**)arg;
456 return ERROR_INVALID_PARAMETER;
460 win_driver = (rdpWinPrinterDriver*)calloc(1,
sizeof(rdpWinPrinterDriver));
463 return ERROR_OUTOFMEMORY;
465 win_driver->driver.EnumPrinters = printer_win_enum_printers;
466 win_driver->driver.ReleaseEnumPrinters = printer_win_release_enum_printers;
467 win_driver->driver.GetPrinter = printer_win_get_printer;
469 win_driver->driver.AddRef = printer_win_add_ref_driver;
470 win_driver->driver.ReleaseRef = printer_win_release_ref_driver;
472 win_driver->id_sequence = 1;
475 win_driver->driver.AddRef(&win_driver->driver);
477 *ppPrinter = &win_driver->driver;
478 return CHANNEL_RC_OK;