printing.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. * Printing interface for PuTTY.
  3. */
  4. #include "putty.h"
  5. #include <winspool.h>
  6. struct printer_enum_tag {
  7. int nprinters;
  8. DWORD enum_level;
  9. union {
  10. LPPRINTER_INFO_4 i4;
  11. LPPRINTER_INFO_5 i5;
  12. } info;
  13. };
  14. struct printer_job_tag {
  15. HANDLE hprinter;
  16. };
  17. DECL_WINDOWS_FUNCTION(static, BOOL, EnumPrinters,
  18. (DWORD, LPTSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD));
  19. DECL_WINDOWS_FUNCTION(static, BOOL, OpenPrinter,
  20. (LPTSTR, LPHANDLE, LPPRINTER_DEFAULTS));
  21. DECL_WINDOWS_FUNCTION(static, BOOL, ClosePrinter, (HANDLE));
  22. DECL_WINDOWS_FUNCTION(static, DWORD, StartDocPrinter, (HANDLE, DWORD, LPBYTE));
  23. DECL_WINDOWS_FUNCTION(static, BOOL, EndDocPrinter, (HANDLE));
  24. DECL_WINDOWS_FUNCTION(static, BOOL, StartPagePrinter, (HANDLE));
  25. DECL_WINDOWS_FUNCTION(static, BOOL, EndPagePrinter, (HANDLE));
  26. DECL_WINDOWS_FUNCTION(static, BOOL, WritePrinter,
  27. (HANDLE, LPVOID, DWORD, LPDWORD));
  28. static void init_winfuncs(void)
  29. {
  30. static bool initialised = false;
  31. if (initialised)
  32. return;
  33. {
  34. HMODULE winspool_module = load_system32_dll("winspool.drv");
  35. /* Some MSDN documentation claims that some of the below functions
  36. * should be loaded from spoolss.dll, but this doesn't seem to
  37. * be reliable in practice.
  38. * Nevertheless, we load spoolss.dll ourselves using our safe
  39. * loading method, against the possibility that winspool.drv
  40. * later loads it unsafely. */
  41. (void) load_system32_dll("spoolss.dll");
  42. GET_WINDOWS_FUNCTION_PP(winspool_module, EnumPrinters);
  43. GET_WINDOWS_FUNCTION_PP(winspool_module, OpenPrinter);
  44. GET_WINDOWS_FUNCTION_PP(winspool_module, ClosePrinter);
  45. GET_WINDOWS_FUNCTION_PP(winspool_module, StartDocPrinter);
  46. GET_WINDOWS_FUNCTION_PP(winspool_module, EndDocPrinter);
  47. GET_WINDOWS_FUNCTION_PP(winspool_module, StartPagePrinter);
  48. GET_WINDOWS_FUNCTION_PP(winspool_module, EndPagePrinter);
  49. GET_WINDOWS_FUNCTION_PP(winspool_module, WritePrinter);
  50. }
  51. initialised = true;
  52. }
  53. static bool printer_add_enum(int param, DWORD level, char **buffer,
  54. int offset, int *nprinters_ptr)
  55. {
  56. DWORD needed = 0, nprinters = 0;
  57. init_winfuncs();
  58. *buffer = sresize(*buffer, offset+512, char);
  59. /*
  60. * Exploratory call to EnumPrinters to determine how much space
  61. * we'll need for the output.
  62. *
  63. * If we get ERROR_INSUFFICIENT_BUFFER, that's fine, we're
  64. * prepared to deal with it. Any other error, we return failure.
  65. */
  66. if (p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), 512,
  67. &needed, &nprinters) == 0 &&
  68. GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  69. return false;
  70. if (needed < 512)
  71. needed = 512;
  72. *buffer = sresize(*buffer, offset+needed, char);
  73. if (p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset),
  74. needed, &needed, &nprinters) == 0)
  75. return false;
  76. *nprinters_ptr += nprinters;
  77. return true;
  78. }
  79. printer_enum *printer_start_enum(int *nprinters_ptr)
  80. {
  81. printer_enum *pe = snew(printer_enum);
  82. char *buffer = NULL;
  83. *nprinters_ptr = 0; /* default return value */
  84. buffer = snewn(512, char);
  85. /*
  86. * Determine what enumeration level to use.
  87. * When enumerating printers, we need to use PRINTER_INFO_4 on
  88. * NT-class systems to avoid Windows looking too hard for them and
  89. * slowing things down; and we need to avoid PRINTER_INFO_5 as
  90. * we've seen network printers not show up.
  91. * On 9x-class systems, PRINTER_INFO_4 isn't available and
  92. * PRINTER_INFO_5 is recommended.
  93. * Bletch.
  94. */
  95. if (osPlatformId != VER_PLATFORM_WIN32_NT) {
  96. pe->enum_level = 5;
  97. } else {
  98. pe->enum_level = 4;
  99. }
  100. if (!printer_add_enum(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
  101. pe->enum_level, &buffer, 0, nprinters_ptr))
  102. goto error;
  103. switch (pe->enum_level) {
  104. case 4:
  105. pe->info.i4 = (LPPRINTER_INFO_4)buffer;
  106. break;
  107. case 5:
  108. pe->info.i5 = (LPPRINTER_INFO_5)buffer;
  109. break;
  110. }
  111. pe->nprinters = *nprinters_ptr;
  112. return pe;
  113. error:
  114. sfree(buffer);
  115. sfree(pe);
  116. *nprinters_ptr = 0;
  117. return NULL;
  118. }
  119. char *printer_get_name(printer_enum *pe, int i)
  120. {
  121. if (!pe)
  122. return NULL;
  123. if (i < 0 || i >= pe->nprinters)
  124. return NULL;
  125. switch (pe->enum_level) {
  126. case 4:
  127. return pe->info.i4[i].pPrinterName;
  128. case 5:
  129. return pe->info.i5[i].pPrinterName;
  130. default:
  131. return NULL;
  132. }
  133. }
  134. void printer_finish_enum(printer_enum *pe)
  135. {
  136. if (!pe)
  137. return;
  138. switch (pe->enum_level) {
  139. case 4:
  140. sfree(pe->info.i4);
  141. break;
  142. case 5:
  143. sfree(pe->info.i5);
  144. break;
  145. }
  146. sfree(pe);
  147. }
  148. printer_job *printer_start_job(char *printer)
  149. {
  150. printer_job *pj = snew(printer_job);
  151. DOC_INFO_1 docinfo;
  152. bool jobstarted = false, pagestarted = false;
  153. init_winfuncs();
  154. pj->hprinter = NULL;
  155. if (!p_OpenPrinter(printer, &pj->hprinter, NULL))
  156. goto error;
  157. docinfo.pDocName = "PuTTY remote printer output";
  158. docinfo.pOutputFile = NULL;
  159. docinfo.pDatatype = "RAW";
  160. if (!p_StartDocPrinter(pj->hprinter, 1, (LPBYTE)&docinfo))
  161. goto error;
  162. jobstarted = true;
  163. if (!p_StartPagePrinter(pj->hprinter))
  164. goto error;
  165. pagestarted = true;
  166. return pj;
  167. error:
  168. if (pagestarted)
  169. p_EndPagePrinter(pj->hprinter);
  170. if (jobstarted)
  171. p_EndDocPrinter(pj->hprinter);
  172. if (pj->hprinter)
  173. p_ClosePrinter(pj->hprinter);
  174. sfree(pj);
  175. return NULL;
  176. }
  177. void printer_job_data(printer_job *pj, const void *data, size_t len)
  178. {
  179. DWORD written;
  180. if (!pj)
  181. return;
  182. p_WritePrinter(pj->hprinter, (void *)data, len, &written);
  183. }
  184. void printer_finish_job(printer_job *pj)
  185. {
  186. if (!pj)
  187. return;
  188. p_EndPagePrinter(pj->hprinter);
  189. p_EndDocPrinter(pj->hprinter);
  190. p_ClosePrinter(pj->hprinter);
  191. sfree(pj);
  192. }