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, WINPR_CAST_CONST_PTR_AWAY(pBuf, 
void*), 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(WINPR_CAST_CONST_PTR_AWAY(name, WCHAR*), &(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;