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;
75static 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,
105static UINT printer_win_write_printjob(rdpPrintJob* printjob,
const BYTE* data,
size_t size)
110 if (size > UINT32_MAX)
111 return ERROR_BAD_ARGUMENTS;
113 if (!printjob || !data)
114 return ERROR_BAD_ARGUMENTS;
116 rdpWinPrinter* printer = (rdpWinPrinter*)printjob->printer;
118 return ERROR_BAD_ARGUMENTS;
120 DWORD cbBuf = WINPR_ASSERTING_INT_CAST(uint32_t, size);
121 if (!WritePrinter(printer->hPrinter, pBuf, cbBuf, &pcWritten))
122 return ERROR_INTERNAL_ERROR;
123 return CHANNEL_RC_OK;
126static void printer_win_close_printjob(rdpPrintJob* printjob)
128 rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
129 rdpWinPrinter* win_printer;
134 win_printer = (rdpWinPrinter*)printjob->printer;
138 if (!EndPagePrinter(win_printer->hPrinter))
142 if (!EndDocPrinter(win_printer->hPrinter))
146 win_printer->printjob = NULL;
148 free(win_printjob->di.pDocName);
152static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32
id)
154 rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
155 rdpWinPrintJob* win_printjob;
157 if (win_printer->printjob != NULL)
160 win_printjob = (rdpWinPrintJob*)calloc(1,
sizeof(rdpWinPrintJob));
164 win_printjob->printjob.id = id;
165 win_printjob->printjob.printer = printer;
166 win_printjob->di.pDocName = printer_win_get_printjob_name(
id);
167 win_printjob->di.pDatatype = NULL;
168 win_printjob->di.pOutputFile = NULL;
170 win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) & (win_printjob->di));
172 if (!win_printjob->handle)
174 free(win_printjob->di.pDocName);
179 if (!StartPagePrinter(win_printer->hPrinter))
181 free(win_printjob->di.pDocName);
186 win_printjob->printjob.Write = printer_win_write_printjob;
187 win_printjob->printjob.Close = printer_win_close_printjob;
189 win_printer->printjob = win_printjob;
191 return &win_printjob->printjob;
194static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32
id)
196 rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
198 if (!win_printer->printjob)
201 if (win_printer->printjob->printjob.id !=
id)
204 return (rdpPrintJob*)win_printer->printjob;
207static void printer_win_free_printer(rdpPrinter* printer)
209 rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
211 if (win_printer->printjob)
212 win_printer->printjob->printjob.Close((rdpPrintJob*)win_printer->printjob);
214 if (win_printer->hPrinter)
215 ClosePrinter(win_printer->hPrinter);
217 if (printer->backend)
218 printer->backend->ReleaseRef(printer->backend);
221 free(printer->driver);
225static void printer_win_add_ref_printer(rdpPrinter* printer)
228 printer->references++;
231static void printer_win_release_ref_printer(rdpPrinter* printer)
235 if (printer->references <= 1)
236 printer_win_free_printer(printer);
238 printer->references--;
241static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver,
const WCHAR* name,
242 const WCHAR* drivername, BOOL is_default)
244 rdpWinPrinter* win_printer;
246 PRINTER_INFO_2* prninfo = NULL;
251 win_printer = (rdpWinPrinter*)calloc(1,
sizeof(rdpWinPrinter));
255 win_printer->printer.backend = &win_driver->driver;
256 win_printer->printer.id = win_driver->id_sequence++;
257 win_printer->printer.name = ConvertWCharToUtf8Alloc(name, NULL);
258 if (!win_printer->printer.name)
261 if (!win_printer->printer.name)
263 win_printer->printer.is_default = is_default;
265 win_printer->printer.CreatePrintJob = printer_win_create_printjob;
266 win_printer->printer.FindPrintJob = printer_win_find_printjob;
267 win_printer->printer.AddRef = printer_win_add_ref_printer;
268 win_printer->printer.ReleaseRef = printer_win_release_ref_printer;
270 if (!OpenPrinter(name, &(win_printer->hPrinter), NULL))
274 GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, 0, &needed);
278 prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed);
282 if (!GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, needed, &needed))
289 win_printer->printer.driver = ConvertWCharToUtf8Alloc(drivername, NULL);
291 win_printer->printer.driver = ConvertWCharToUtf8Alloc(prninfo->pDriverName, NULL);
293 if (!win_printer->printer.driver)
296 win_printer->printer.AddRef(&win_printer->printer);
297 win_printer->printer.backend->AddRef(win_printer->printer.backend);
298 return &win_printer->printer;
301 printer_win_free_printer(&win_printer->printer);
305static void printer_win_release_enum_printers(rdpPrinter** printers)
307 rdpPrinter** cur = printers;
309 while ((cur != NULL) && ((*cur) != NULL))
311 if ((*cur)->ReleaseRef)
312 (*cur)->ReleaseRef(*cur);
318static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
320 rdpPrinter** printers;
322 PRINTER_INFO_2* prninfo = NULL;
323 DWORD needed, returned;
324 BOOL haveDefault = FALSE;
325 LPWSTR defaultPrinter = NULL;
327 GetDefaultPrinter(NULL, &needed);
330 defaultPrinter = (LPWSTR)calloc(needed,
sizeof(WCHAR));
335 if (!GetDefaultPrinter(defaultPrinter, &needed))
336 defaultPrinter[0] =
'\0';
340 EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed,
344 prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed);
347 free(defaultPrinter);
352 if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE)prninfo,
353 needed, &needed, &returned))
357 printers = (rdpPrinter**)calloc((returned + 1),
sizeof(rdpPrinter*));
361 free(defaultPrinter);
367 for (
int i = 0; i < (int)returned; i++)
369 rdpPrinter* current = printers[num_printers];
370 current = printer_win_new_printer((rdpWinPrinterDriver*)driver, prninfo[i].pPrinterName,
371 prninfo[i].pDriverName,
372 _wcscmp(prninfo[i].pPrinterName, defaultPrinter) == 0);
375 printer_win_release_enum_printers(printers);
379 if (current->is_default)
381 printers[num_printers++] = current;
384 if (!haveDefault && (returned > 0))
385 printers[0]->is_default = TRUE;
388 free(defaultPrinter);
392static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver,
const char* name,
393 const char* driverName, BOOL isDefault)
395 WCHAR* driverNameW = NULL;
397 rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
398 rdpPrinter* myPrinter = NULL;
402 nameW = ConvertUtf8ToWCharAlloc(name, NULL);
408 driverNameW = ConvertUtf8ToWCharAlloc(driverName, NULL);
413 myPrinter = printer_win_new_printer(win_driver, nameW, driverNameW, isDefault);
420static void printer_win_add_ref_driver(rdpPrinterDriver* driver)
422 rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver;
428static rdpWinPrinterDriver* win_driver = NULL;
430static void printer_win_release_ref_driver(rdpPrinterDriver* driver)
432 rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver;
433 if (win->references <= 1)
442FREERDP_ENTRY_POINT(UINT VCAPITYPE win_freerdp_printer_client_subsystem_entry(
void* arg))
444 rdpPrinterDriver** ppPrinter = (rdpPrinterDriver**)arg;
446 return ERROR_INVALID_PARAMETER;
450 win_driver = (rdpWinPrinterDriver*)calloc(1,
sizeof(rdpWinPrinterDriver));
453 return ERROR_OUTOFMEMORY;
455 win_driver->driver.EnumPrinters = printer_win_enum_printers;
456 win_driver->driver.ReleaseEnumPrinters = printer_win_release_enum_printers;
457 win_driver->driver.GetPrinter = printer_win_get_printer;
459 win_driver->driver.AddRef = printer_win_add_ref_driver;
460 win_driver->driver.ReleaseRef = printer_win_release_ref_driver;
462 win_driver->id_sequence = 1;
465 win_driver->driver.AddRef(&win_driver->driver);
467 *ppPrinter = &win_driver->driver;
468 return CHANNEL_RC_OK;