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>
37#include <freerdp/utils/helpers.h>
39#define WIDEN_INT(x) L##x
40#define WIDEN(x) WIDEN_INT(x)
41#define PRINTER_TAG CHANNELS_TAG("printer.client")
42#ifdef WITH_DEBUG_WINPR
43#define DEBUG_WINPR(...) WLog_DBG(PRINTER_TAG, __VA_ARGS__)
45#define DEBUG_WINPR(...) \
53 rdpPrinterDriver driver;
65 void* printjob_object;
73 rdpWinPrintJob* printjob;
76WINPR_ATTR_MALLOC(free, 1)
77static WCHAR* printer_win_get_printjob_name(
size_t id)
79 struct tm tres = WINPR_C_ARRAY_INIT;
83 const time_t tt = time(
nullptr);
84 const errno_t err = localtime_s(&tres, &tt);
90 str = calloc(len + 1,
sizeof(WCHAR));
95 const int rc = swprintf_s(
97 WIDEN(
"%s Print %04d-%02d-%02d %02d-%02d-%02d - Job %") WIDEN(PRIuz) WIDEN(
"\0"),
98 freerdp_getApplicationDetailsStringW(), tres.tm_year + 1900, tres.tm_mon + 1,
99 tres.tm_mday, tres.tm_hour, tres.tm_min, tres.tm_sec,
id);
105 len = WINPR_ASSERTING_INT_CAST(
size_t, rc) + 1ull;
116static UINT printer_win_write_printjob(rdpPrintJob* printjob,
const BYTE* data,
size_t size)
121 if (size > UINT32_MAX)
122 return ERROR_BAD_ARGUMENTS;
124 if (!printjob || !data)
125 return ERROR_BAD_ARGUMENTS;
127 rdpWinPrinter* printer = (rdpWinPrinter*)printjob->printer;
129 return ERROR_BAD_ARGUMENTS;
131 DWORD cbBuf = WINPR_ASSERTING_INT_CAST(uint32_t, size);
132 if (!WritePrinter(printer->hPrinter, WINPR_CAST_CONST_PTR_AWAY(pBuf,
void*), cbBuf, &pcWritten))
133 return ERROR_INTERNAL_ERROR;
134 return CHANNEL_RC_OK;
137static void printer_win_close_printjob(rdpPrintJob* printjob)
139 rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
140 rdpWinPrinter* win_printer;
145 win_printer = (rdpWinPrinter*)printjob->printer;
149 if (!EndPagePrinter(win_printer->hPrinter))
153 if (!EndDocPrinter(win_printer->hPrinter))
157 win_printer->printjob =
nullptr;
159 free(win_printjob->di.pDocName);
163static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32
id)
165 rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
166 rdpWinPrintJob* win_printjob;
168 if (win_printer->printjob !=
nullptr)
171 win_printjob = (rdpWinPrintJob*)calloc(1,
sizeof(rdpWinPrintJob));
175 win_printjob->printjob.id = id;
176 win_printjob->printjob.printer = printer;
177 win_printjob->di.pDocName = printer_win_get_printjob_name(
id);
178 win_printjob->di.pDatatype =
nullptr;
179 win_printjob->di.pOutputFile =
nullptr;
181 win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) & (win_printjob->di));
183 if (!win_printjob->handle)
185 free(win_printjob->di.pDocName);
190 if (!StartPagePrinter(win_printer->hPrinter))
192 free(win_printjob->di.pDocName);
197 win_printjob->printjob.Write = printer_win_write_printjob;
198 win_printjob->printjob.Close = printer_win_close_printjob;
200 win_printer->printjob = win_printjob;
202 return &win_printjob->printjob;
205static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32
id)
207 rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
209 if (!win_printer->printjob)
212 if (win_printer->printjob->printjob.id !=
id)
215 return (rdpPrintJob*)win_printer->printjob;
218static void printer_win_free_printer(rdpPrinter* printer)
220 rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
222 if (win_printer->printjob)
223 win_printer->printjob->printjob.Close((rdpPrintJob*)win_printer->printjob);
225 if (win_printer->hPrinter)
226 ClosePrinter(win_printer->hPrinter);
228 if (printer->backend)
229 printer->backend->ReleaseRef(printer->backend);
232 free(printer->driver);
236static void printer_win_add_ref_printer(rdpPrinter* printer)
239 printer->references++;
242static void printer_win_release_ref_printer(rdpPrinter* printer)
246 if (printer->references <= 1)
247 printer_win_free_printer(printer);
249 printer->references--;
252static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver,
const WCHAR* name,
253 const WCHAR* drivername, BOOL is_default)
255 rdpWinPrinter* win_printer;
257 PRINTER_INFO_2* prninfo =
nullptr;
262 win_printer = (rdpWinPrinter*)calloc(1,
sizeof(rdpWinPrinter));
266 win_printer->printer.backend = &win_driver->driver;
267 win_printer->printer.id = win_driver->id_sequence++;
268 win_printer->printer.name = ConvertWCharToUtf8Alloc(name,
nullptr);
269 if (!win_printer->printer.name)
272 if (!win_printer->printer.name)
274 win_printer->printer.is_default = is_default;
276 win_printer->printer.CreatePrintJob = printer_win_create_printjob;
277 win_printer->printer.FindPrintJob = printer_win_find_printjob;
278 win_printer->printer.AddRef = printer_win_add_ref_printer;
279 win_printer->printer.ReleaseRef = printer_win_release_ref_printer;
281 if (!OpenPrinter(WINPR_CAST_CONST_PTR_AWAY(name, WCHAR*), &(win_printer->hPrinter),
nullptr))
285 GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, 0, &needed);
289 prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed);
293 if (!GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, needed, &needed))
300 win_printer->printer.driver = ConvertWCharToUtf8Alloc(drivername,
nullptr);
302 win_printer->printer.driver = ConvertWCharToUtf8Alloc(prninfo->pDriverName,
nullptr);
304 if (!win_printer->printer.driver)
307 win_printer->printer.AddRef(&win_printer->printer);
308 win_printer->printer.backend->AddRef(win_printer->printer.backend);
309 return &win_printer->printer;
312 printer_win_free_printer(&win_printer->printer);
316static void printer_win_release_enum_printers(rdpPrinter** printers)
318 rdpPrinter** cur = printers;
320 while ((cur !=
nullptr) && ((*cur) !=
nullptr))
322 if ((*cur)->ReleaseRef)
323 (*cur)->ReleaseRef(*cur);
329static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
331 rdpPrinter** printers;
333 PRINTER_INFO_2* prninfo =
nullptr;
334 DWORD needed, returned;
335 BOOL haveDefault = FALSE;
336 LPWSTR defaultPrinter =
nullptr;
338 GetDefaultPrinter(
nullptr, &needed);
341 defaultPrinter = (LPWSTR)calloc(needed,
sizeof(WCHAR));
346 if (!GetDefaultPrinter(defaultPrinter, &needed))
347 defaultPrinter[0] =
'\0';
351 EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
nullptr, 2,
nullptr, 0, &needed,
355 prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed);
358 free(defaultPrinter);
363 if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
nullptr, 2, (LPBYTE)prninfo,
364 needed, &needed, &returned))
368 printers = (rdpPrinter**)calloc((returned + 1),
sizeof(rdpPrinter*));
372 free(defaultPrinter);
378 for (
int i = 0; i < (int)returned; i++)
380 rdpPrinter* current = printers[num_printers];
381 current = printer_win_new_printer((rdpWinPrinterDriver*)driver, prninfo[i].pPrinterName,
382 prninfo[i].pDriverName,
383 _wcscmp(prninfo[i].pPrinterName, defaultPrinter) == 0);
386 printer_win_release_enum_printers(printers);
390 if (current->is_default)
392 printers[num_printers++] = current;
395 if (!haveDefault && (returned > 0))
396 printers[0]->is_default = TRUE;
399 free(defaultPrinter);
403static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver,
const char* name,
404 const char* driverName, BOOL isDefault)
406 WCHAR* driverNameW =
nullptr;
407 WCHAR* nameW =
nullptr;
408 rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
409 rdpPrinter* myPrinter =
nullptr;
413 nameW = ConvertUtf8ToWCharAlloc(name,
nullptr);
419 driverNameW = ConvertUtf8ToWCharAlloc(driverName,
nullptr);
424 myPrinter = printer_win_new_printer(win_driver, nameW, driverNameW, isDefault);
431static void printer_win_add_ref_driver(rdpPrinterDriver* driver)
433 rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver;
439static rdpWinPrinterDriver* win_driver =
nullptr;
441static void printer_win_release_ref_driver(rdpPrinterDriver* driver)
443 rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver;
444 if (win->references <= 1)
447 win_driver =
nullptr;
453FREERDP_ENTRY_POINT(UINT VCAPITYPE win_freerdp_printer_client_subsystem_entry(
void* arg))
455 rdpPrinterDriver** ppPrinter = (rdpPrinterDriver**)arg;
457 return ERROR_INVALID_PARAMETER;
461 win_driver = (rdpWinPrinterDriver*)calloc(1,
sizeof(rdpWinPrinterDriver));
464 return ERROR_OUTOFMEMORY;
466 win_driver->driver.EnumPrinters = printer_win_enum_printers;
467 win_driver->driver.ReleaseEnumPrinters = printer_win_release_enum_printers;
468 win_driver->driver.GetPrinter = printer_win_get_printer;
470 win_driver->driver.AddRef = printer_win_add_ref_driver;
471 win_driver->driver.ReleaseRef = printer_win_release_ref_driver;
473 win_driver->id_sequence = 1;
476 win_driver->driver.AddRef(&win_driver->driver);
478 *ppPrinter = &win_driver->driver;
479 return CHANNEL_RC_OK;