123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- /*
- * Printing interface for PuTTY.
- */
- #include "putty.h"
- #include <winspool.h>
- struct printer_enum_tag {
- int nprinters;
- DWORD enum_level;
- union {
- LPPRINTER_INFO_4 i4;
- LPPRINTER_INFO_5 i5;
- } info;
- };
- struct printer_job_tag {
- HANDLE hprinter;
- };
- DECL_WINDOWS_FUNCTION(static, BOOL, EnumPrinters,
- (DWORD, LPTSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD));
- DECL_WINDOWS_FUNCTION(static, BOOL, OpenPrinter,
- (LPTSTR, LPHANDLE, LPPRINTER_DEFAULTS));
- DECL_WINDOWS_FUNCTION(static, BOOL, ClosePrinter, (HANDLE));
- DECL_WINDOWS_FUNCTION(static, DWORD, StartDocPrinter, (HANDLE, DWORD, LPBYTE));
- DECL_WINDOWS_FUNCTION(static, BOOL, EndDocPrinter, (HANDLE));
- DECL_WINDOWS_FUNCTION(static, BOOL, StartPagePrinter, (HANDLE));
- DECL_WINDOWS_FUNCTION(static, BOOL, EndPagePrinter, (HANDLE));
- DECL_WINDOWS_FUNCTION(static, BOOL, WritePrinter,
- (HANDLE, LPVOID, DWORD, LPDWORD));
- static void init_winfuncs(void)
- {
- static bool initialised = false;
- if (initialised)
- return;
- {
- HMODULE winspool_module = load_system32_dll("winspool.drv");
- /* Some MSDN documentation claims that some of the below functions
- * should be loaded from spoolss.dll, but this doesn't seem to
- * be reliable in practice.
- * Nevertheless, we load spoolss.dll ourselves using our safe
- * loading method, against the possibility that winspool.drv
- * later loads it unsafely. */
- (void) load_system32_dll("spoolss.dll");
- GET_WINDOWS_FUNCTION_PP(winspool_module, EnumPrinters);
- GET_WINDOWS_FUNCTION_PP(winspool_module, OpenPrinter);
- GET_WINDOWS_FUNCTION_PP(winspool_module, ClosePrinter);
- GET_WINDOWS_FUNCTION_PP(winspool_module, StartDocPrinter);
- GET_WINDOWS_FUNCTION_PP(winspool_module, EndDocPrinter);
- GET_WINDOWS_FUNCTION_PP(winspool_module, StartPagePrinter);
- GET_WINDOWS_FUNCTION_PP(winspool_module, EndPagePrinter);
- GET_WINDOWS_FUNCTION_PP(winspool_module, WritePrinter);
- }
- initialised = true;
- }
- static bool printer_add_enum(int param, DWORD level, char **buffer,
- int offset, int *nprinters_ptr)
- {
- DWORD needed = 0, nprinters = 0;
- init_winfuncs();
- *buffer = sresize(*buffer, offset+512, char);
- /*
- * Exploratory call to EnumPrinters to determine how much space
- * we'll need for the output.
- *
- * If we get ERROR_INSUFFICIENT_BUFFER, that's fine, we're
- * prepared to deal with it. Any other error, we return failure.
- */
- if (p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), 512,
- &needed, &nprinters) == 0 &&
- GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- return false;
- if (needed < 512)
- needed = 512;
- *buffer = sresize(*buffer, offset+needed, char);
- if (p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset),
- needed, &needed, &nprinters) == 0)
- return false;
- *nprinters_ptr += nprinters;
- return true;
- }
- printer_enum *printer_start_enum(int *nprinters_ptr)
- {
- printer_enum *pe = snew(printer_enum);
- char *buffer = NULL;
- *nprinters_ptr = 0; /* default return value */
- buffer = snewn(512, char);
- /*
- * Determine what enumeration level to use.
- * When enumerating printers, we need to use PRINTER_INFO_4 on
- * NT-class systems to avoid Windows looking too hard for them and
- * slowing things down; and we need to avoid PRINTER_INFO_5 as
- * we've seen network printers not show up.
- * On 9x-class systems, PRINTER_INFO_4 isn't available and
- * PRINTER_INFO_5 is recommended.
- * Bletch.
- */
- if (osPlatformId != VER_PLATFORM_WIN32_NT) {
- pe->enum_level = 5;
- } else {
- pe->enum_level = 4;
- }
- if (!printer_add_enum(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
- pe->enum_level, &buffer, 0, nprinters_ptr))
- goto error;
- switch (pe->enum_level) {
- case 4:
- pe->info.i4 = (LPPRINTER_INFO_4)buffer;
- break;
- case 5:
- pe->info.i5 = (LPPRINTER_INFO_5)buffer;
- break;
- }
- pe->nprinters = *nprinters_ptr;
- return pe;
- error:
- sfree(buffer);
- sfree(pe);
- *nprinters_ptr = 0;
- return NULL;
- }
- char *printer_get_name(printer_enum *pe, int i)
- {
- if (!pe)
- return NULL;
- if (i < 0 || i >= pe->nprinters)
- return NULL;
- switch (pe->enum_level) {
- case 4:
- return pe->info.i4[i].pPrinterName;
- case 5:
- return pe->info.i5[i].pPrinterName;
- default:
- return NULL;
- }
- }
- void printer_finish_enum(printer_enum *pe)
- {
- if (!pe)
- return;
- switch (pe->enum_level) {
- case 4:
- sfree(pe->info.i4);
- break;
- case 5:
- sfree(pe->info.i5);
- break;
- }
- sfree(pe);
- }
- printer_job *printer_start_job(char *printer)
- {
- printer_job *pj = snew(printer_job);
- DOC_INFO_1 docinfo;
- bool jobstarted = false, pagestarted = false;
- init_winfuncs();
- pj->hprinter = NULL;
- if (!p_OpenPrinter(printer, &pj->hprinter, NULL))
- goto error;
- docinfo.pDocName = "PuTTY remote printer output";
- docinfo.pOutputFile = NULL;
- docinfo.pDatatype = "RAW";
- if (!p_StartDocPrinter(pj->hprinter, 1, (LPBYTE)&docinfo))
- goto error;
- jobstarted = true;
- if (!p_StartPagePrinter(pj->hprinter))
- goto error;
- pagestarted = true;
- return pj;
- error:
- if (pagestarted)
- p_EndPagePrinter(pj->hprinter);
- if (jobstarted)
- p_EndDocPrinter(pj->hprinter);
- if (pj->hprinter)
- p_ClosePrinter(pj->hprinter);
- sfree(pj);
- return NULL;
- }
- void printer_job_data(printer_job *pj, const void *data, size_t len)
- {
- DWORD written;
- if (!pj)
- return;
- p_WritePrinter(pj->hprinter, (void *)data, len, &written);
- }
- void printer_finish_job(printer_job *pj)
- {
- if (!pj)
- return;
- p_EndPagePrinter(pj->hprinter);
- p_EndDocPrinter(pj->hprinter);
- p_ClosePrinter(pj->hprinter);
- sfree(pj);
- }
|