[175] | 1 |
|
---|
| 2 | /*
|
---|
| 3 | * bltWinPrnt.c --
|
---|
| 4 | *
|
---|
| 5 | * This module implements Win32 printer access.
|
---|
| 6 | *
|
---|
| 7 | * Copyright 1998 by Bell Labs Innovations for Lucent Technologies.
|
---|
| 8 | *
|
---|
| 9 | * Permission to use, copy, modify, and distribute this software and
|
---|
| 10 | * its documentation for any purpose and without fee is hereby
|
---|
| 11 | * granted, provided that the above copyright notice appear in all
|
---|
| 12 | * copies and that both that the copyright notice and warranty
|
---|
| 13 | * disclaimer appear in supporting documentation, and that the names
|
---|
| 14 | * of Lucent Technologies any of their entities not be used in
|
---|
| 15 | * advertising or publicity pertaining to distribution of the software
|
---|
| 16 | * without specific, written prior permission.
|
---|
| 17 | *
|
---|
| 18 | * Lucent Technologies disclaims all warranties with regard to this
|
---|
| 19 | * software, including all implied warranties of merchantability and
|
---|
| 20 | * fitness. In no event shall Lucent Technologies be liable for any
|
---|
| 21 | * special, indirect or consequential damages or any damages
|
---|
| 22 | * whatsoever resulting from loss of use, data or profits, whether in
|
---|
| 23 | * an action of contract, negligence or other tortuous action, arising
|
---|
| 24 | * out of or in connection with the use or performance of this
|
---|
| 25 | * software.
|
---|
| 26 | *
|
---|
| 27 | */
|
---|
| 28 |
|
---|
| 29 | #include <bltInt.h>
|
---|
| 30 | #include <bltHash.h>
|
---|
| 31 | #ifndef NO_PRINTER
|
---|
| 32 | #include <X11/Xutil.h>
|
---|
| 33 | #undef Status
|
---|
| 34 | #if defined(_MSC_VER) || defined(__BORLANDC__)
|
---|
| 35 | #include <winspool.h>
|
---|
| 36 | #endif /* _MSC_VER || __BORLANDC__ */
|
---|
| 37 |
|
---|
| 38 | /*
|
---|
| 39 | set pid [printer open name]
|
---|
| 40 | printer close $pid
|
---|
| 41 | printer write $pid $data
|
---|
| 42 | printer snap $pid .window
|
---|
| 43 | printer names
|
---|
| 44 | printer enum things
|
---|
| 45 | printer getattr $pid
|
---|
| 46 | printer setattr $pid
|
---|
| 47 |
|
---|
| 48 | set pid [open ]
|
---|
| 49 | blt::printer open {\\alprint\2a211} p1
|
---|
| 50 | p1 getattr varName
|
---|
| 51 | p1 setattr varName
|
---|
| 52 | p1 write $data
|
---|
| 53 | .graph print p1
|
---|
| 54 | p1 snap .window
|
---|
| 55 | p1 close
|
---|
| 56 | blt::printer names
|
---|
| 57 | blt::printer emum things
|
---|
| 58 | */
|
---|
| 59 |
|
---|
| 60 | #define PRINTER_THREAD_KEY "BLT Printer Data"
|
---|
| 61 |
|
---|
| 62 | typedef struct {
|
---|
| 63 | Blt_HashTable printerTable; /* Hash table of printer structures keyed by
|
---|
| 64 | * the name of the printer. */
|
---|
| 65 | int nextId;
|
---|
| 66 | } PrinterInterpData;
|
---|
| 67 |
|
---|
| 68 | typedef struct {
|
---|
| 69 | int type;
|
---|
| 70 | HDC hDC;
|
---|
| 71 | } PrintDrawable;
|
---|
| 72 |
|
---|
| 73 | typedef struct {
|
---|
| 74 | Tcl_Interp *interp;
|
---|
| 75 | Tcl_Command cmdToken; /* Token for vector's Tcl command. */
|
---|
| 76 | char *name;
|
---|
| 77 | char *fileName;
|
---|
| 78 | PrintDrawable drawable;
|
---|
| 79 | HANDLE hPrinter;
|
---|
| 80 | Blt_HashEntry *hashPtr;
|
---|
| 81 | Blt_HashTable *tablePtr;
|
---|
| 82 | char *driverName;
|
---|
| 83 | char *deviceName;
|
---|
| 84 | char *printerName;
|
---|
| 85 | char *docName;
|
---|
| 86 | char *portName;
|
---|
| 87 | DEVMODE *dmPtr;
|
---|
| 88 | int dmSize;
|
---|
| 89 | } PrintQueue;
|
---|
| 90 |
|
---|
| 91 | typedef struct {
|
---|
| 92 | DWORD token;
|
---|
| 93 | char *string;
|
---|
| 94 | } TokenString;
|
---|
| 95 |
|
---|
| 96 | static TokenString sizeTable[] =
|
---|
| 97 | {
|
---|
| 98 | /* Letter 8 1/2 x 11 in */
|
---|
| 99 | { DMPAPER_LETTER, "Letter" },
|
---|
| 100 | /* Letter Small 8 1/2 x 11 in */
|
---|
| 101 | { DMPAPER_LETTERSMALL, "Letter Small" },
|
---|
| 102 | /* Tabloid 11 x 17 in */
|
---|
| 103 | { DMPAPER_TABLOID, "Tabloid" },
|
---|
| 104 | /* Ledger 17 x 11 in */
|
---|
| 105 | { DMPAPER_LEDGER, "Ledger" },
|
---|
| 106 | /* Legal 8 1/2 x 14 in */
|
---|
| 107 | { DMPAPER_LEGAL, "Legal" },
|
---|
| 108 | /* Statement 5 1/2 x 8 1/2 in */
|
---|
| 109 | { DMPAPER_STATEMENT, "Statement" },
|
---|
| 110 | /* Executive 7 1/4 x 10 1/2 in */
|
---|
| 111 | { DMPAPER_EXECUTIVE, "Executive" },
|
---|
| 112 | /* A3 297 x 420 mm */
|
---|
| 113 | { DMPAPER_A3, "A3" },
|
---|
| 114 | /* A4 210 x 297 mm */
|
---|
| 115 | { DMPAPER_A4, "A4" },
|
---|
| 116 | /* A4 Small 210 x 297 mm */
|
---|
| 117 | { DMPAPER_A4SMALL, "A4 Small" },
|
---|
| 118 | /* A5 148 x 210 mm */
|
---|
| 119 | { DMPAPER_A5, "A5" },
|
---|
| 120 | /* B4 (JIS) 250 x 354 */
|
---|
| 121 | { DMPAPER_B4, "B4 (JIS)" },
|
---|
| 122 | /* B5 (JIS) 182 x 257 mm */
|
---|
| 123 | { DMPAPER_B5, "B5 (JIS)" },
|
---|
| 124 | /* Folio 8 1/2 x 13 in */
|
---|
| 125 | { DMPAPER_FOLIO, "Folio" },
|
---|
| 126 | /* Quarto 215 x 275 mm */
|
---|
| 127 | { DMPAPER_QUARTO, "Quarto" },
|
---|
| 128 | /* 10x14 in */
|
---|
| 129 | { DMPAPER_10X14, "10x14" },
|
---|
| 130 | /* 11x17 in */
|
---|
| 131 | { DMPAPER_11X17, "11x17" },
|
---|
| 132 | /* Note 8 1/2 x 11 in */
|
---|
| 133 | { DMPAPER_NOTE, "Note" },
|
---|
| 134 | /* Envelope #9 3 7/8 x 8 7/8 */
|
---|
| 135 | { DMPAPER_ENV_9, "Envelope #9" },
|
---|
| 136 | /* Envelope #10 4 1/8 x 9 1/2 */
|
---|
| 137 | { DMPAPER_ENV_10, "Envelope #10" },
|
---|
| 138 | /* Envelope #11 4 1/2 x 10 3/8 */
|
---|
| 139 | { DMPAPER_ENV_11, "Envelope #11" },
|
---|
| 140 | /* Envelope #12 4 \276 x 11 */
|
---|
| 141 | { DMPAPER_ENV_12, "Envelope #12" },
|
---|
| 142 | /* Envelope #14 5 x 11 1/2 */
|
---|
| 143 | { DMPAPER_ENV_14, "Envelope #14" },
|
---|
| 144 | /* C size sheet */
|
---|
| 145 | { DMPAPER_CSHEET, "C size sheet" },
|
---|
| 146 | /* D size sheet */
|
---|
| 147 | { DMPAPER_DSHEET, "D size sheet" },
|
---|
| 148 | /* E size sheet */
|
---|
| 149 | { DMPAPER_ESHEET, "E size sheet" },
|
---|
| 150 | /* Envelope DL 110 x 220mm */
|
---|
| 151 | { DMPAPER_ENV_DL, "Envelope DL" },
|
---|
| 152 | /* Envelope C5 162 x 229 mm */
|
---|
| 153 | { DMPAPER_ENV_C5, "Envelope C5" },
|
---|
| 154 | /* Envelope C3 324 x 458 mm */
|
---|
| 155 | { DMPAPER_ENV_C3, "Envelope C3" },
|
---|
| 156 | /* Envelope C4 229 x 324 mm */
|
---|
| 157 | { DMPAPER_ENV_C4, "Envelope C4" },
|
---|
| 158 | /* Envelope C6 114 x 162 mm */
|
---|
| 159 | { DMPAPER_ENV_C6, "Envelope C6" },
|
---|
| 160 | /* Envelope C65 114 x 229 mm */
|
---|
| 161 | { DMPAPER_ENV_C65, "Envelope C65" },
|
---|
| 162 | /* Envelope B4 250 x 353 mm */
|
---|
| 163 | { DMPAPER_ENV_B4, "Envelope B4" },
|
---|
| 164 | /* Envelope B5 176 x 250 mm */
|
---|
| 165 | { DMPAPER_ENV_B5, "Envelope B5" },
|
---|
| 166 | /* Envelope B6 176 x 125 mm */
|
---|
| 167 | { DMPAPER_ENV_B6, "Envelope B6" },
|
---|
| 168 | /* Envelope 110 x 230 mm */
|
---|
| 169 | { DMPAPER_ENV_ITALY, "Envelope Italy" },
|
---|
| 170 | /* Env Monarch 3 7/8 x 7 1/2 in */
|
---|
| 171 | { DMPAPER_ENV_MONARCH, "Envelope Monarch" },
|
---|
| 172 | /* 6 3/4 Envelope 3 5/8 x 6 1/2 in */
|
---|
| 173 | { DMPAPER_ENV_PERSONAL, "6 3/4 Envelope" },
|
---|
| 174 | /* US Std Fanfold 14 7/8 x 11 in */
|
---|
| 175 | { DMPAPER_FANFOLD_US, "US Std Fanfold" },
|
---|
| 176 | /* German Std Fanfold 8 1/2 x 12 in */
|
---|
| 177 | { DMPAPER_FANFOLD_STD_GERMAN, "German Std Fanfold" },
|
---|
| 178 | /* German Legal Fanfold 8 1/2 x 13 in */
|
---|
| 179 | { DMPAPER_FANFOLD_LGL_GERMAN, "German Legal Fanfold" },
|
---|
| 180 | /* B4 (ISO) 250 x 353 mm */
|
---|
| 181 | { DMPAPER_ISO_B4, "ISOB4" },
|
---|
| 182 | /* Japanese Postcard 100 x 148 mm */
|
---|
| 183 | { DMPAPER_JAPANESE_POSTCARD, "Postcard (JIS)" },
|
---|
| 184 | /* 9 x 11 in */
|
---|
| 185 | { DMPAPER_9X11, "9x11" },
|
---|
| 186 | /* 10 x 11 in */
|
---|
| 187 | { DMPAPER_10X11, "10x11" },
|
---|
| 188 | /* 15 x 11 in */
|
---|
| 189 | { DMPAPER_15X11, "15x11" },
|
---|
| 190 | /* Envelope Invite 220 x 220 mm */
|
---|
| 191 | { DMPAPER_ENV_INVITE, "Envelope Invite" },
|
---|
| 192 | /* Letter Extra 9 \275 x 12 in */
|
---|
| 193 | { DMPAPER_LETTER_EXTRA, "Letter Extra" },
|
---|
| 194 | /* Legal Extra 9 \275 x 15 in */
|
---|
| 195 | { DMPAPER_LEGAL_EXTRA, "Legal Extra" },
|
---|
| 196 | /* Tabloid Extra 11.69 x 18 in */
|
---|
| 197 | { DMPAPER_TABLOID_EXTRA, "Tabloid Extra" },
|
---|
| 198 | /* A4 Extra 9.27 x 12.69 in */
|
---|
| 199 | { DMPAPER_A4_EXTRA, "A4 Extra" },
|
---|
| 200 | /* Letter Transverse 8 \275 x 11 in */
|
---|
| 201 | { DMPAPER_LETTER_TRANSVERSE, "Letter Transverse" },
|
---|
| 202 | /* A4 Transverse 210 x 297 mm */
|
---|
| 203 | { DMPAPER_A4_TRANSVERSE, "A4 Transverse" },
|
---|
| 204 | /* Letter Extra Transverse 9\275 x 12 in */
|
---|
| 205 | { DMPAPER_LETTER_EXTRA_TRANSVERSE, "Letter Extra Transverse" },
|
---|
| 206 | /* SuperA/SuperA/A4 227 x 356 mm */
|
---|
| 207 | { DMPAPER_A_PLUS, "Super A Plus" },
|
---|
| 208 | /* SuperB/SuperB/A3 305 x 487 mm */
|
---|
| 209 | { DMPAPER_B_PLUS, "Super B Plus" },
|
---|
| 210 | /* Letter Plus 8.5 x 12.69 in */
|
---|
| 211 | { DMPAPER_LETTER_PLUS, "Letter Plus" },
|
---|
| 212 | /* A4 Plus 210 x 330 mm */
|
---|
| 213 | { DMPAPER_A4_PLUS, "A4 Plus" },
|
---|
| 214 | /* A5 Transverse 148 x 210 mm */
|
---|
| 215 | { DMPAPER_A5_TRANSVERSE, "A5 Transverse" },
|
---|
| 216 | /* B5 (JIS) Transverse 182 x 257 mm */
|
---|
| 217 | { DMPAPER_B5_TRANSVERSE, "B5 Transverse" },
|
---|
| 218 | /* A3 Extra 322 x 445 mm */
|
---|
| 219 | { DMPAPER_A3_EXTRA, "A3 Extra" },
|
---|
| 220 | /* A5 Extra 174 x 235 mm */
|
---|
| 221 | { DMPAPER_A5_EXTRA, "A5 Extra" },
|
---|
| 222 | /* B5 (ISO) Extra 201 x 276 mm */
|
---|
| 223 | { DMPAPER_B5_EXTRA, "B5 Extra" },
|
---|
| 224 | /* A2 420 x 594 mm */
|
---|
| 225 | { DMPAPER_A2, "A2" },
|
---|
| 226 | /* A3 Transverse 297 x 420 mm */
|
---|
| 227 | { DMPAPER_A3_TRANSVERSE, "A3 Transverse" },
|
---|
| 228 | /* A3 Extra Transverse 322 x 445 mm */
|
---|
| 229 | { DMPAPER_A3_EXTRA_TRANSVERSE, "A3 Extra Transverse" },
|
---|
| 230 | { 0, NULL }
|
---|
| 231 | };
|
---|
| 232 |
|
---|
| 233 | static TokenString statusTable[] =
|
---|
| 234 | {
|
---|
| 235 | { PRINTER_STATUS_BUSY, "Busy" },
|
---|
| 236 | { PRINTER_STATUS_DOOR_OPEN, "Door Open" },
|
---|
| 237 | { PRINTER_STATUS_ERROR, "Error" },
|
---|
| 238 | { PRINTER_STATUS_INITIALIZING, "Initializing" },
|
---|
| 239 | { PRINTER_STATUS_IO_ACTIVE, "IO Active" },
|
---|
| 240 | { PRINTER_STATUS_MANUAL_FEED, "Manual Feed" },
|
---|
| 241 | { PRINTER_STATUS_NOT_AVAILABLE, "Not Available" },
|
---|
| 242 | { PRINTER_STATUS_NO_TONER, "No Toner" },
|
---|
| 243 | { PRINTER_STATUS_OFFLINE, "Offline" },
|
---|
| 244 | { PRINTER_STATUS_OUTPUT_BIN_FULL, "Bin Full" },
|
---|
| 245 | { PRINTER_STATUS_OUT_OF_MEMORY, "Out Of Memory" },
|
---|
| 246 | { PRINTER_STATUS_PAGE_PUNT, "Page Punt" },
|
---|
| 247 | { PRINTER_STATUS_PAPER_JAM, "Paper Jam" },
|
---|
| 248 | { PRINTER_STATUS_PAPER_OUT, "Paper Out" },
|
---|
| 249 | { PRINTER_STATUS_PAPER_PROBLEM, "Paper Problem" },
|
---|
| 250 | { PRINTER_STATUS_PAUSED, "Paused" },
|
---|
| 251 | { PRINTER_STATUS_PENDING_DELETION, "Pending Deletion" },
|
---|
| 252 | { PRINTER_STATUS_POWER_SAVE, "Power Save" },
|
---|
| 253 | { PRINTER_STATUS_PRINTING, "Printing" },
|
---|
| 254 | { PRINTER_STATUS_PROCESSING, "Processing" },
|
---|
| 255 | { PRINTER_STATUS_SERVER_UNKNOWN, "Server Unknown" },
|
---|
| 256 | { PRINTER_STATUS_TONER_LOW, "Toner Low" },
|
---|
| 257 | { PRINTER_STATUS_USER_INTERVENTION, "User Intervention" },
|
---|
| 258 | { PRINTER_STATUS_WAITING, "Waiting" },
|
---|
| 259 | { PRINTER_STATUS_WARMING_UP, "Warming Up" },
|
---|
| 260 | { 0, NULL }
|
---|
| 261 | };
|
---|
| 262 |
|
---|
| 263 | static TokenString attributeTable[] =
|
---|
| 264 | {
|
---|
| 265 | { PRINTER_ATTRIBUTE_DEFAULT, "Default" },
|
---|
| 266 | { PRINTER_ATTRIBUTE_DIRECT, "Direct" },
|
---|
| 267 | { PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST, "Do Complete First" },
|
---|
| 268 | { PRINTER_ATTRIBUTE_ENABLE_BIDI, "Enable BIDI" },
|
---|
| 269 | { PRINTER_ATTRIBUTE_ENABLE_DEVQ, "Enable Devq" },
|
---|
| 270 | { PRINTER_ATTRIBUTE_HIDDEN, "Hidden" },
|
---|
| 271 | { PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS, "Keep Printed Jobs" },
|
---|
| 272 | { PRINTER_ATTRIBUTE_LOCAL, "Local" },
|
---|
| 273 | { PRINTER_ATTRIBUTE_NETWORK, "Network" },
|
---|
| 274 | { PRINTER_ATTRIBUTE_QUEUED, "Queued" },
|
---|
| 275 | { PRINTER_ATTRIBUTE_RAW_ONLY, "Raw Only" },
|
---|
| 276 | { PRINTER_ATTRIBUTE_SHARED, "Shared" },
|
---|
| 277 | { PRINTER_ATTRIBUTE_WORK_OFFLINE, "Offline" },
|
---|
| 278 | { 0, NULL }
|
---|
| 279 | };
|
---|
| 280 |
|
---|
| 281 | static TokenString binTable[] =
|
---|
| 282 | {
|
---|
| 283 | { DMBIN_UPPER, "Upper" },
|
---|
| 284 | { DMBIN_LOWER, "Lower" },
|
---|
| 285 | { DMBIN_MIDDLE, "Middle" },
|
---|
| 286 | { DMBIN_MANUAL, "Manual" },
|
---|
| 287 | { DMBIN_ENVELOPE, "Envelope" },
|
---|
| 288 | { DMBIN_ENVMANUAL, "Envelope Manual" },
|
---|
| 289 | { DMBIN_AUTO, "Automatic" },
|
---|
| 290 | { DMBIN_TRACTOR, "Tractor" },
|
---|
| 291 | { DMBIN_SMALLFMT, "Small Format" },
|
---|
| 292 | { DMBIN_LARGEFMT, "Large Format" },
|
---|
| 293 | { DMBIN_LARGECAPACITY, "Large Capacity" },
|
---|
| 294 | { DMBIN_CASSETTE, "Cassette" },
|
---|
| 295 | { DMBIN_FORMSOURCE, "Form Source" },
|
---|
| 296 | { 0, NULL }
|
---|
| 297 | };
|
---|
| 298 |
|
---|
| 299 | static TokenString orientationTable[] =
|
---|
| 300 | {
|
---|
| 301 | { DMORIENT_PORTRAIT, "Portrait" },
|
---|
| 302 | { DMORIENT_LANDSCAPE, "Landscape" },
|
---|
| 303 | { 0, NULL }
|
---|
| 304 | };
|
---|
| 305 |
|
---|
| 306 | static TokenString qualityTable[] =
|
---|
| 307 | {
|
---|
| 308 | { DMRES_HIGH, "High" },
|
---|
| 309 | { DMRES_MEDIUM, "Medium" },
|
---|
| 310 | { DMRES_LOW, "Low" },
|
---|
| 311 | { DMRES_DRAFT, "Draft" },
|
---|
| 312 | { 0, NULL }
|
---|
| 313 | };
|
---|
| 314 |
|
---|
| 315 | static TokenString colorTable[] =
|
---|
| 316 | {
|
---|
| 317 | { DMCOLOR_COLOR, "Color" },
|
---|
| 318 | { DMCOLOR_MONOCHROME, "Monochrome" },
|
---|
| 319 | { 0, NULL }
|
---|
| 320 | };
|
---|
| 321 |
|
---|
| 322 | static TokenString duplexTable[] =
|
---|
| 323 | {
|
---|
| 324 | { DMDUP_SIMPLEX, "Simplex" },
|
---|
| 325 | { DMDUP_HORIZONTAL, "Horizontal" },
|
---|
| 326 | { DMDUP_VERTICAL, "Vertical" },
|
---|
| 327 | { 0, NULL }
|
---|
| 328 | };
|
---|
| 329 |
|
---|
| 330 | static TokenString ttOptionTable[] =
|
---|
| 331 | {
|
---|
| 332 | { DMTT_BITMAP, "Bitmap" },
|
---|
| 333 | { DMTT_DOWNLOAD, "Download" },
|
---|
| 334 | { DMTT_SUBDEV, "Substitute Device" },
|
---|
| 335 | { DMTT_DOWNLOAD_OUTLINE, "Download Outline" },
|
---|
| 336 | { 0, NULL }
|
---|
| 337 | };
|
---|
| 338 |
|
---|
| 339 | static Tcl_ObjCmdProc PrinterCmd;
|
---|
| 340 | static Tcl_InterpDeleteProc PrinterInterpDeleteProc;
|
---|
| 341 |
|
---|
| 342 | void
|
---|
| 343 | Blt_GetPrinterScale(HDC printerDC, double *xRatioPtr, double *yRatioPtr)
|
---|
| 344 | {
|
---|
| 345 | double xScreen, yScreen;
|
---|
| 346 | double xPrinter, yPrinter;
|
---|
| 347 | HDC screenDC;
|
---|
| 348 |
|
---|
| 349 | xPrinter = (double)GetDeviceCaps(printerDC, LOGPIXELSX);
|
---|
| 350 | yPrinter = (double)GetDeviceCaps(printerDC, LOGPIXELSY);
|
---|
| 351 | screenDC = GetDC(NULL);
|
---|
| 352 | xScreen = (double)GetDeviceCaps(screenDC, LOGPIXELSX);
|
---|
| 353 | yScreen = (double)GetDeviceCaps(screenDC, LOGPIXELSY);
|
---|
| 354 | ReleaseDC(NULL, screenDC);
|
---|
| 355 | *xRatioPtr = (xPrinter / xScreen);
|
---|
| 356 | *yRatioPtr = (yPrinter / yScreen);
|
---|
| 357 | }
|
---|
| 358 |
|
---|
| 359 | static PrinterInterpData *
|
---|
| 360 | GetPrinterInterpData(Tcl_Interp *interp)
|
---|
| 361 | {
|
---|
| 362 | PrinterInterpData *dataPtr;
|
---|
| 363 | Tcl_InterpDeleteProc *proc;
|
---|
| 364 |
|
---|
| 365 | dataPtr = (PrinterInterpData *)
|
---|
| 366 | Tcl_GetAssocData(interp, PRINTER_THREAD_KEY, &proc);
|
---|
| 367 | if (dataPtr == NULL) {
|
---|
| 368 | dataPtr = Blt_Malloc(sizeof(PrinterInterpData));
|
---|
| 369 | dataPtr->nextId = 0;
|
---|
| 370 | assert(dataPtr);
|
---|
| 371 | Tcl_SetAssocData(interp, PRINTER_THREAD_KEY, PrinterInterpDeleteProc,
|
---|
| 372 | dataPtr);
|
---|
| 373 | Blt_InitHashTable(&dataPtr->printerTable, BLT_STRING_KEYS);
|
---|
| 374 | }
|
---|
| 375 | return dataPtr;
|
---|
| 376 | }
|
---|
| 377 |
|
---|
| 378 | static int
|
---|
| 379 | GetQueue(
|
---|
| 380 | Tcl_Interp *interp,
|
---|
| 381 | const char *name,
|
---|
| 382 | PrintQueue **queuePtrPtr)
|
---|
| 383 | {
|
---|
| 384 | Blt_HashEntry *hPtr;
|
---|
| 385 | PrinterInterpData *dataPtr;
|
---|
| 386 |
|
---|
| 387 | dataPtr = GetPrinterInterpData(interp);
|
---|
| 388 | hPtr = Blt_FindHashEntry(&dataPtr->printerTable, name);
|
---|
| 389 | if (hPtr == NULL) {
|
---|
| 390 | Tcl_AppendResult(interp, "can't find printer \"", name, "\"",
|
---|
| 391 | (char *)NULL);
|
---|
| 392 | return TCL_ERROR;
|
---|
| 393 | }
|
---|
| 394 | *queuePtrPtr = (PrintQueue *)Blt_GetHashValue(hPtr);
|
---|
| 395 | return TCL_OK;
|
---|
| 396 | }
|
---|
| 397 |
|
---|
| 398 | static int
|
---|
| 399 | GetQueueFromObj(
|
---|
| 400 | Tcl_Interp *interp,
|
---|
| 401 | Tcl_Obj *objPtr,
|
---|
| 402 | PrintQueue **queuePtrPtr)
|
---|
| 403 | {
|
---|
| 404 | return GetQueue(interp, Tcl_GetString(objPtr), queuePtrPtr);
|
---|
| 405 | }
|
---|
| 406 |
|
---|
| 407 | static void
|
---|
| 408 | CloseQueue(
|
---|
| 409 | PrintQueue *queuePtr)
|
---|
| 410 | {
|
---|
| 411 | ClosePrinter(queuePtr->hPrinter);
|
---|
| 412 | queuePtr->hPrinter = NULL;
|
---|
| 413 | }
|
---|
| 414 |
|
---|
| 415 | static int
|
---|
| 416 | OpenQueue(
|
---|
| 417 | Tcl_Interp *interp,
|
---|
| 418 | PrintQueue *queuePtr)
|
---|
| 419 | {
|
---|
| 420 | PRINTER_DEFAULTS pd;
|
---|
| 421 | HANDLE hPrinter;
|
---|
| 422 |
|
---|
| 423 | ZeroMemory(&pd, sizeof(pd));
|
---|
| 424 | pd.DesiredAccess = PRINTER_ALL_ACCESS;
|
---|
| 425 | if (!OpenPrinter(queuePtr->printerName, &hPrinter, &pd)) {
|
---|
| 426 | Tcl_AppendResult(interp, "can't open printer \"",
|
---|
| 427 | queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 428 | queuePtr->hPrinter = NULL;
|
---|
| 429 | return TCL_ERROR;
|
---|
| 430 | }
|
---|
| 431 | queuePtr->hPrinter = hPrinter;
|
---|
| 432 | return TCL_OK;
|
---|
| 433 | }
|
---|
| 434 |
|
---|
| 435 | static HGLOBAL
|
---|
| 436 | GetQueueProperties(
|
---|
| 437 | PrintQueue *queuePtr,
|
---|
| 438 | DEVMODE **dmPtrPtr)
|
---|
| 439 | {
|
---|
| 440 | HWND hWnd;
|
---|
| 441 | unsigned int dmSize;
|
---|
| 442 | HGLOBAL hMem;
|
---|
| 443 | DEVMODE *dmPtr;
|
---|
| 444 |
|
---|
| 445 | hWnd = GetDesktopWindow();
|
---|
| 446 | dmSize = DocumentProperties(hWnd, queuePtr->hPrinter,
|
---|
| 447 | queuePtr->printerName, NULL, NULL, 0);
|
---|
| 448 | if (dmSize == 0) {
|
---|
| 449 | Tcl_AppendResult(queuePtr->interp,
|
---|
| 450 | "can't get document properties for \"",
|
---|
| 451 | queuePtr->printerName,
|
---|
| 452 | "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 453 | return NULL;
|
---|
| 454 | }
|
---|
| 455 | hMem = GlobalAlloc(GHND, dmSize);
|
---|
| 456 | dmPtr = (DEVMODE *)GlobalLock(hMem);
|
---|
| 457 | if (!DocumentProperties(hWnd, queuePtr->hPrinter, queuePtr->printerName,
|
---|
| 458 | dmPtr, NULL, DM_OUT_BUFFER)) {
|
---|
| 459 | Tcl_AppendResult(queuePtr->interp,
|
---|
| 460 | "can't allocate document properties for \"",
|
---|
| 461 | queuePtr->printerName, "\": ", Blt_LastError(),
|
---|
| 462 | (char *)NULL);
|
---|
| 463 | GlobalUnlock(hMem);
|
---|
| 464 | GlobalFree(hMem);
|
---|
| 465 | return NULL;
|
---|
| 466 | }
|
---|
| 467 | *dmPtrPtr = dmPtr;
|
---|
| 468 | queuePtr->dmSize = dmSize;
|
---|
| 469 | return hMem;
|
---|
| 470 | }
|
---|
| 471 |
|
---|
| 472 | static int
|
---|
| 473 | SetQueueProperties(
|
---|
| 474 | Tcl_Interp *interp,
|
---|
| 475 | PrintQueue *queuePtr,
|
---|
| 476 | DEVMODE *dmPtr)
|
---|
| 477 | {
|
---|
| 478 | HWND hWnd;
|
---|
| 479 | int result;
|
---|
| 480 |
|
---|
| 481 | hWnd = GetDesktopWindow();
|
---|
| 482 | result = DocumentProperties(hWnd, queuePtr->hPrinter,
|
---|
| 483 | queuePtr->printerName, dmPtr, dmPtr, DM_IN_BUFFER | DM_OUT_BUFFER);
|
---|
| 484 | if (result == 0) {
|
---|
| 485 | Tcl_AppendResult(interp, "can't set document properties for \"",
|
---|
| 486 | queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 487 | return TCL_ERROR;
|
---|
| 488 | }
|
---|
| 489 | if (queuePtr->dmPtr != NULL) {
|
---|
| 490 | Blt_Free(queuePtr->dmPtr);
|
---|
| 491 | }
|
---|
| 492 | queuePtr->dmPtr = Blt_Malloc(queuePtr->dmSize);
|
---|
| 493 | *queuePtr->dmPtr = *dmPtr;
|
---|
| 494 | return TCL_OK;
|
---|
| 495 | }
|
---|
| 496 |
|
---|
| 497 | static void
|
---|
| 498 | DestroyQueue(PrintQueue *queuePtr)
|
---|
| 499 | {
|
---|
| 500 | if (queuePtr->drawable.hDC != NULL) {
|
---|
| 501 | DeleteDC(queuePtr->drawable.hDC);
|
---|
| 502 | }
|
---|
| 503 | if (queuePtr->printerName != NULL) {
|
---|
| 504 | Blt_Free(queuePtr->printerName);
|
---|
| 505 | }
|
---|
| 506 | if (queuePtr->deviceName != NULL) {
|
---|
| 507 | Blt_Free(queuePtr->deviceName);
|
---|
| 508 | }
|
---|
| 509 | if (queuePtr->portName != NULL) {
|
---|
| 510 | Blt_Free(queuePtr->portName);
|
---|
| 511 | }
|
---|
| 512 | if (queuePtr->driverName != NULL) {
|
---|
| 513 | Blt_Free(queuePtr->driverName);
|
---|
| 514 | }
|
---|
| 515 | if (queuePtr->hashPtr != NULL) {
|
---|
| 516 | Blt_DeleteHashEntry(queuePtr->tablePtr, queuePtr->hashPtr);
|
---|
| 517 | }
|
---|
| 518 | if (queuePtr->dmPtr != NULL) {
|
---|
| 519 | Blt_Free(queuePtr->dmPtr);
|
---|
| 520 | }
|
---|
| 521 | Blt_Free(queuePtr);
|
---|
| 522 | }
|
---|
| 523 |
|
---|
| 524 | static char *
|
---|
| 525 | AttributesToString(DWORD attributes, Tcl_DString * resultPtr)
|
---|
| 526 | {
|
---|
| 527 | register TokenString *p;
|
---|
| 528 |
|
---|
| 529 | Tcl_DStringInit(resultPtr);
|
---|
| 530 | for (p = attributeTable; p->string != NULL; p++) {
|
---|
| 531 | if (attributes & p->token) {
|
---|
| 532 | Tcl_DStringAppendElement(resultPtr, p->string);
|
---|
| 533 | }
|
---|
| 534 | }
|
---|
| 535 | return Tcl_DStringValue(resultPtr);
|
---|
| 536 | }
|
---|
| 537 |
|
---|
| 538 | static char *
|
---|
| 539 | StatusToString(DWORD status, Tcl_DString * resultPtr)
|
---|
| 540 | {
|
---|
| 541 | register TokenString *p;
|
---|
| 542 |
|
---|
| 543 | Tcl_DStringInit(resultPtr);
|
---|
| 544 | for (p = statusTable; p->string != NULL; p++) {
|
---|
| 545 | if (status & p->token) {
|
---|
| 546 | Tcl_DStringAppendElement(resultPtr, p->string);
|
---|
| 547 | }
|
---|
| 548 | }
|
---|
| 549 | return Tcl_DStringValue(resultPtr);
|
---|
| 550 | }
|
---|
| 551 |
|
---|
| 552 | static char *
|
---|
| 553 | TokenToString(TokenString *table, DWORD token)
|
---|
| 554 | {
|
---|
| 555 | register TokenString *p;
|
---|
| 556 |
|
---|
| 557 | for (p = table; p->string != NULL; p++) {
|
---|
| 558 | if (token == p->token) {
|
---|
| 559 | return p->string;
|
---|
| 560 | }
|
---|
| 561 | }
|
---|
| 562 | return "???";
|
---|
| 563 | }
|
---|
| 564 |
|
---|
| 565 | static DWORD
|
---|
| 566 | StringToToken(TokenString * table, char *string)
|
---|
| 567 | {
|
---|
| 568 | register TokenString *p;
|
---|
| 569 | char c;
|
---|
| 570 |
|
---|
| 571 | c = toupper(string[0]);
|
---|
| 572 | for (p = table; p->string != NULL; p++) {
|
---|
| 573 | if ((c == toupper(p->string[0])) &&
|
---|
| 574 | (strcasecmp(string, p->string) == 0)) {
|
---|
| 575 | return p->token;
|
---|
| 576 | }
|
---|
| 577 | }
|
---|
| 578 | return 0;
|
---|
| 579 | }
|
---|
| 580 |
|
---|
| 581 | static void
|
---|
| 582 | GetFormInfo(
|
---|
| 583 | Tcl_Interp *interp,
|
---|
| 584 | FORM_INFO_1 * infoArr,
|
---|
| 585 | int nForms,
|
---|
| 586 | char *varName)
|
---|
| 587 | {
|
---|
| 588 | Tcl_DString dString;
|
---|
| 589 | register int i;
|
---|
| 590 |
|
---|
| 591 | Tcl_DStringInit(&dString);
|
---|
| 592 | for (i = 0; i < nForms; i++) {
|
---|
| 593 | Tcl_DStringAppendElement(&dString, infoArr[i].pName);
|
---|
| 594 | }
|
---|
| 595 | Tcl_SetVar2(interp, varName, "EnumForms", Tcl_DStringValue(&dString),
|
---|
| 596 | TCL_LEAVE_ERR_MSG);
|
---|
| 597 | Tcl_DStringFree(&dString);
|
---|
| 598 | }
|
---|
| 599 |
|
---|
| 600 |
|
---|
| 601 | static int
|
---|
| 602 | GetPrinterAttributes(
|
---|
| 603 | Tcl_Interp *interp, /* Interpreter context. */
|
---|
| 604 | PrintQueue *queuePtr,
|
---|
| 605 | Tcl_Obj *objPtr) /* Name of array variable to contain
|
---|
| 606 | * printer device information. */
|
---|
| 607 | {
|
---|
| 608 | char *string;
|
---|
| 609 | Tcl_DString dString;
|
---|
| 610 | DEVMODE *dmPtr;
|
---|
| 611 | DWORD bytesNeeded;
|
---|
| 612 | HGLOBAL hMem1, hMem2;
|
---|
| 613 | PRINTER_INFO_2* pi2Ptr;
|
---|
| 614 | LPVOID buffer;
|
---|
| 615 | int result = TCL_ERROR;
|
---|
| 616 | char *varName;
|
---|
| 617 |
|
---|
| 618 | if (OpenQueue(interp, queuePtr) != TCL_OK) {
|
---|
| 619 | return TCL_ERROR;
|
---|
| 620 | }
|
---|
| 621 | Tcl_DStringInit(&dString);
|
---|
| 622 | hMem2 = NULL;
|
---|
| 623 |
|
---|
| 624 | GetPrinter(queuePtr->hPrinter, 2, NULL, 0, &bytesNeeded);
|
---|
| 625 |
|
---|
| 626 | /* Windows 95/98 seems to only want locked memory. Allocating
|
---|
| 627 | * unlocked memory will sometimes crash the printer driver and
|
---|
| 628 | * therefore Windows itself. */
|
---|
| 629 |
|
---|
| 630 | hMem1 = GlobalAlloc(GHND, bytesNeeded);
|
---|
| 631 | if (hMem1 == NULL) {
|
---|
| 632 | Tcl_AppendResult(interp, "can't allocate memory for printer \"",
|
---|
| 633 | queuePtr->name, "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 634 | goto error;
|
---|
| 635 | }
|
---|
| 636 | buffer = (LPVOID)GlobalLock(hMem1);
|
---|
| 637 | if (!GetPrinter(queuePtr->hPrinter, 2, buffer, bytesNeeded,
|
---|
| 638 | &bytesNeeded)) {
|
---|
| 639 | Tcl_AppendResult(interp, "can't get printer \"", queuePtr->name, "\": ",
|
---|
| 640 | Blt_LastError(), (char *)NULL);
|
---|
| 641 | goto error;
|
---|
| 642 | }
|
---|
| 643 | hMem2 = GetQueueProperties(queuePtr, &dmPtr);
|
---|
| 644 | if (hMem2 == NULL) {
|
---|
| 645 | Tcl_AppendResult(interp, "can't allocate memory for printer \"",
|
---|
| 646 | queuePtr->name, "\" properties: ", Blt_LastError(), (char *)NULL);
|
---|
| 647 | goto error;
|
---|
| 648 | }
|
---|
| 649 | pi2Ptr = (PRINTER_INFO_2 *)buffer;
|
---|
| 650 | varName = Tcl_GetString(objPtr);
|
---|
| 651 | Tcl_SetVar2(interp, varName, "ServerName", pi2Ptr->pServerName, 0);
|
---|
| 652 | Tcl_SetVar2(interp, varName, "PrinterName", pi2Ptr->pPrinterName, 0);
|
---|
| 653 | Tcl_SetVar2(interp, varName, "PortName", pi2Ptr->pPortName, 0);
|
---|
| 654 | Tcl_SetVar2(interp, varName, "DriverName", pi2Ptr->pDriverName, 0);
|
---|
| 655 | Tcl_SetVar2(interp, varName, "Comment", pi2Ptr->pComment, 0);
|
---|
| 656 | Tcl_SetVar2(interp, varName, "Location", pi2Ptr->pLocation, 0);
|
---|
| 657 | Tcl_SetVar2(interp, varName, "SepFile", pi2Ptr->pSepFile, 0);
|
---|
| 658 | Tcl_SetVar2(interp, varName, "PrintProcessor", pi2Ptr->pPrintProcessor, 0);
|
---|
| 659 | Tcl_SetVar2(interp, varName, "Datatype", pi2Ptr->pDatatype, 0);
|
---|
| 660 | Tcl_SetVar2(interp, varName, "Parameters", pi2Ptr->pParameters, 0);
|
---|
| 661 | Tcl_SetVar2(interp, varName, "Attributes",
|
---|
| 662 | AttributesToString(pi2Ptr->Attributes, &dString), 0);
|
---|
| 663 | Tcl_SetVar2(interp, varName, "Priority", Blt_Itoa(pi2Ptr->Priority), 0);
|
---|
| 664 | Tcl_SetVar2(interp, varName, "DefaultPriority",
|
---|
| 665 | Blt_Itoa(pi2Ptr->DefaultPriority), 0);
|
---|
| 666 | Tcl_SetVar2(interp, varName, "StartTime", Blt_Itoa(pi2Ptr->StartTime), 0);
|
---|
| 667 | Tcl_SetVar2(interp, varName, "UntilTime", Blt_Itoa(pi2Ptr->UntilTime), 0);
|
---|
| 668 | Tcl_SetVar2(interp, varName, "Status",
|
---|
| 669 | StatusToString(pi2Ptr->Status, &dString), 0);
|
---|
| 670 | Tcl_SetVar2(interp, varName, "Jobs", Blt_Itoa(pi2Ptr->cJobs), 0);
|
---|
| 671 | Tcl_SetVar2(interp, varName, "AveragePPM", Blt_Itoa(pi2Ptr->AveragePPM), 0);
|
---|
| 672 |
|
---|
| 673 | if (dmPtr->dmFields & DM_ORIENTATION) {
|
---|
| 674 | Tcl_SetVar2(interp, varName, "Orientation",
|
---|
| 675 | TokenToString(orientationTable, dmPtr->dmOrientation), 0);
|
---|
| 676 | }
|
---|
| 677 | if (dmPtr->dmFields & DM_PAPERSIZE) {
|
---|
| 678 | Tcl_SetVar2(interp, varName, "PaperSize",
|
---|
| 679 | TokenToString(sizeTable, dmPtr->dmPaperSize), 0);
|
---|
| 680 | }
|
---|
| 681 | if (dmPtr->dmFields & DM_PAPERWIDTH) {
|
---|
| 682 | Tcl_SetVar2(interp, varName, "PaperWidth",
|
---|
| 683 | Blt_Itoa(dmPtr->dmPaperWidth), 0);
|
---|
| 684 | }
|
---|
| 685 | if (dmPtr->dmFields & DM_PAPERLENGTH) {
|
---|
| 686 | Tcl_SetVar2(interp, varName, "PaperLength",
|
---|
| 687 | Blt_Itoa(dmPtr->dmPaperLength), 0);
|
---|
| 688 | }
|
---|
| 689 | if (dmPtr->dmFields & DM_SCALE) {
|
---|
| 690 | Tcl_SetVar2(interp, varName, "Scale", Blt_Itoa(dmPtr->dmScale), 0);
|
---|
| 691 | }
|
---|
| 692 | if (dmPtr->dmFields & DM_COPIES) {
|
---|
| 693 | Tcl_SetVar2(interp, varName, "Copies", Blt_Itoa(dmPtr->dmCopies), 0);
|
---|
| 694 | }
|
---|
| 695 | if (dmPtr->dmFields & DM_DEFAULTSOURCE) {
|
---|
| 696 | Tcl_SetVar2(interp, varName, "DefaultSource",
|
---|
| 697 | TokenToString(binTable, dmPtr->dmDefaultSource), 0);
|
---|
| 698 | }
|
---|
| 699 | if (dmPtr->dmFields & DM_PRINTQUALITY) {
|
---|
| 700 | if (dmPtr->dmPrintQuality < 0) {
|
---|
| 701 | string = TokenToString(qualityTable, dmPtr->dmPrintQuality);
|
---|
| 702 | } else {
|
---|
| 703 | string = Blt_Itoa(dmPtr->dmPrintQuality);
|
---|
| 704 | }
|
---|
| 705 | Tcl_SetVar2(interp, varName, "PrintQuality", string, 0);
|
---|
| 706 | }
|
---|
| 707 | if (dmPtr->dmFields & DM_COLOR) {
|
---|
| 708 | Tcl_SetVar2(interp, varName, "Color",
|
---|
| 709 | TokenToString(colorTable, dmPtr->dmColor), 0);
|
---|
| 710 | }
|
---|
| 711 | if (dmPtr->dmFields & DM_DUPLEX) {
|
---|
| 712 | Tcl_SetVar2(interp, varName, "Duplex",
|
---|
| 713 | TokenToString(duplexTable, dmPtr->dmDuplex), 0);
|
---|
| 714 | }
|
---|
| 715 | if (dmPtr->dmFields & DM_YRESOLUTION) {
|
---|
| 716 | Tcl_SetVar2(interp, varName, "YResolution",
|
---|
| 717 | Blt_Itoa(dmPtr->dmYResolution), 0);
|
---|
| 718 | }
|
---|
| 719 | if (dmPtr->dmFields & DM_TTOPTION) {
|
---|
| 720 | Tcl_SetVar2(interp, varName, "TTOption",
|
---|
| 721 | TokenToString(ttOptionTable, dmPtr->dmTTOption), 0);
|
---|
| 722 | }
|
---|
| 723 | if (dmPtr->dmFields & DM_COLLATE) {
|
---|
| 724 | if (dmPtr->dmCollate == DMCOLLATE_TRUE) {
|
---|
| 725 | string = "true";
|
---|
| 726 | } else if (dmPtr->dmCollate == DMCOLLATE_FALSE) {
|
---|
| 727 | string = "false";
|
---|
| 728 | } else {
|
---|
| 729 | string = "???";
|
---|
| 730 | }
|
---|
| 731 | Tcl_SetVar2(interp, varName, "Collate", string, 0);
|
---|
| 732 | }
|
---|
| 733 | if (dmPtr->dmFields & DM_FORMNAME) {
|
---|
| 734 | Tcl_SetVar2(interp, varName, "FormName", dmPtr->dmFormName, 0);
|
---|
| 735 | }
|
---|
| 736 | Tcl_SetVar2(interp, varName, "OutputFile", dmPtr->dmDeviceName, 0);
|
---|
| 737 | result = TCL_OK;
|
---|
| 738 |
|
---|
| 739 | error:
|
---|
| 740 | Tcl_DStringFree(&dString);
|
---|
| 741 | CloseQueue(queuePtr);
|
---|
| 742 | if (hMem1 != NULL) {
|
---|
| 743 | GlobalUnlock(hMem1);
|
---|
| 744 | GlobalFree(hMem1);
|
---|
| 745 | }
|
---|
| 746 | if (hMem2 != NULL) {
|
---|
| 747 | GlobalUnlock(hMem2);
|
---|
| 748 | GlobalFree(hMem2);
|
---|
| 749 | }
|
---|
| 750 | return result;
|
---|
| 751 | }
|
---|
| 752 |
|
---|
| 753 | static int
|
---|
| 754 | SetQueueAttributes(
|
---|
| 755 | Tcl_Interp *interp,
|
---|
| 756 | PrintQueue *queuePtr,
|
---|
| 757 | Tcl_Obj *objPtr)
|
---|
| 758 | {
|
---|
| 759 | char *string;
|
---|
| 760 | DEVMODE *dmPtr;
|
---|
| 761 | int value;
|
---|
| 762 | HGLOBAL hMem;
|
---|
| 763 | int result;
|
---|
| 764 | char *varName;
|
---|
| 765 |
|
---|
| 766 | if (OpenQueue(interp, queuePtr) != TCL_OK) {
|
---|
| 767 | return TCL_ERROR;
|
---|
| 768 | }
|
---|
| 769 | hMem = GetQueueProperties(queuePtr, &dmPtr);
|
---|
| 770 | CloseQueue(queuePtr);
|
---|
| 771 | if (hMem == NULL) {
|
---|
| 772 | return TCL_ERROR;
|
---|
| 773 | }
|
---|
| 774 | dmPtr->dmFields = 0;
|
---|
| 775 | varName = Tcl_GetString(objPtr);
|
---|
| 776 | string = (char *)Tcl_GetVar2(interp, varName, "Orientation", 0);
|
---|
| 777 | if (string != NULL) {
|
---|
| 778 | value = StringToToken(orientationTable, string);
|
---|
| 779 | if (value > 0) {
|
---|
| 780 | dmPtr->dmFields |= DM_ORIENTATION;
|
---|
| 781 | dmPtr->dmOrientation = value;
|
---|
| 782 | }
|
---|
| 783 | }
|
---|
| 784 | string = (char *)Tcl_GetVar2(interp, varName, "PaperSize", 0);
|
---|
| 785 | if (string != NULL) {
|
---|
| 786 | value = StringToToken(sizeTable, string);
|
---|
| 787 | if (value > 0) {
|
---|
| 788 | dmPtr->dmFields |= DM_PAPERSIZE;
|
---|
| 789 | dmPtr->dmPaperSize = value;
|
---|
| 790 | }
|
---|
| 791 | }
|
---|
| 792 | string = (char *)Tcl_GetVar2(interp, varName, "PaperWidth", 0);
|
---|
| 793 | if (string != NULL) {
|
---|
| 794 | if (Tcl_GetInt(interp, string, &value) == TCL_OK) {
|
---|
| 795 | dmPtr->dmFields |= DM_PAPERWIDTH;
|
---|
| 796 | dmPtr->dmPaperWidth = value;
|
---|
| 797 | }
|
---|
| 798 | }
|
---|
| 799 | string = (char *)Tcl_GetVar2(interp, varName, "PaperLength", 0);
|
---|
| 800 | if (string != NULL) {
|
---|
| 801 | if (Tcl_GetInt(interp, string, &value) == TCL_OK) {
|
---|
| 802 | dmPtr->dmFields |= DM_PAPERLENGTH;
|
---|
| 803 | dmPtr->dmPaperLength = value;
|
---|
| 804 | }
|
---|
| 805 | }
|
---|
| 806 | string = (char *)Tcl_GetVar2(interp, varName, "Scale", 0);
|
---|
| 807 | if (string != NULL) {
|
---|
| 808 | if (Tcl_GetInt(interp, string, &value) == TCL_OK) {
|
---|
| 809 | dmPtr->dmFields |= DM_SCALE;
|
---|
| 810 | dmPtr->dmScale = value;
|
---|
| 811 | }
|
---|
| 812 | }
|
---|
| 813 | string = (char *)Tcl_GetVar2(interp, varName, "Copies", 0);
|
---|
| 814 | if (string != NULL) {
|
---|
| 815 | if (Tcl_GetInt(interp, string, &value) == TCL_OK) {
|
---|
| 816 | dmPtr->dmFields |= DM_COPIES;
|
---|
| 817 | dmPtr->dmCopies = value;
|
---|
| 818 | }
|
---|
| 819 | }
|
---|
| 820 | string = (char *)Tcl_GetVar2(interp, varName, "DefaultSource", 0);
|
---|
| 821 | if (string != NULL) {
|
---|
| 822 | value = StringToToken(binTable, string);
|
---|
| 823 | if (value > 0) {
|
---|
| 824 | dmPtr->dmFields |= DM_DEFAULTSOURCE;
|
---|
| 825 | dmPtr->dmDefaultSource = value;
|
---|
| 826 | }
|
---|
| 827 | }
|
---|
| 828 | string = (char *)Tcl_GetVar2(interp, varName, "PrintQuality", 0);
|
---|
| 829 | if (string != NULL) {
|
---|
| 830 | value = StringToToken(qualityTable, string);
|
---|
| 831 | if (value > 0) {
|
---|
| 832 | dmPtr->dmFields |= DM_PRINTQUALITY;
|
---|
| 833 | dmPtr->dmPrintQuality = value;
|
---|
| 834 | }
|
---|
| 835 | }
|
---|
| 836 | string = (char *)Tcl_GetVar2(interp, varName, "Color", 0);
|
---|
| 837 | if (string != NULL) {
|
---|
| 838 | value = StringToToken(colorTable, string);
|
---|
| 839 | if (value > 0) {
|
---|
| 840 | dmPtr->dmFields |= DM_COLOR;
|
---|
| 841 | dmPtr->dmColor = value;
|
---|
| 842 | }
|
---|
| 843 | }
|
---|
| 844 | string = (char *)Tcl_GetVar2(interp, varName, "Duplex", 0);
|
---|
| 845 | if (string != NULL) {
|
---|
| 846 | value = StringToToken(duplexTable, string);
|
---|
| 847 | if (value > 0) {
|
---|
| 848 | dmPtr->dmFields |= DM_DUPLEX;
|
---|
| 849 | dmPtr->dmDuplex = value;
|
---|
| 850 | }
|
---|
| 851 | }
|
---|
| 852 | string = (char *)Tcl_GetVar2(interp, varName, "YResolution", 0);
|
---|
| 853 | if (string != NULL) {
|
---|
| 854 | if (Tcl_GetInt(interp, string, &value) == TCL_OK) {
|
---|
| 855 | dmPtr->dmFields |= DM_YRESOLUTION;
|
---|
| 856 | dmPtr->dmYResolution = value;
|
---|
| 857 | }
|
---|
| 858 | }
|
---|
| 859 | string = (char *)Tcl_GetVar2(interp, varName, "TTOption", 0);
|
---|
| 860 | if (string != NULL) {
|
---|
| 861 | value = StringToToken(ttOptionTable, string);
|
---|
| 862 | if (value > 0) {
|
---|
| 863 | dmPtr->dmFields |= DM_TTOPTION;
|
---|
| 864 | dmPtr->dmTTOption = value;
|
---|
| 865 | }
|
---|
| 866 | }
|
---|
| 867 | string = (char *)Tcl_GetVar2(interp, varName, "Collate", 0);
|
---|
| 868 | if (string != NULL) {
|
---|
| 869 | if (Tcl_GetBoolean(interp, string, &value) == TCL_OK) {
|
---|
| 870 | dmPtr->dmFields |= DM_COLLATE;
|
---|
| 871 | dmPtr->dmCollate = value;
|
---|
| 872 | }
|
---|
| 873 | }
|
---|
| 874 | string = (char *)Tcl_GetVar2(interp, varName, "OutputFile", 0);
|
---|
| 875 | if (string != NULL) {
|
---|
| 876 | if (queuePtr->fileName != NULL) {
|
---|
| 877 | Blt_Free(queuePtr->fileName);
|
---|
| 878 | }
|
---|
| 879 | queuePtr->fileName = Blt_Strdup(string);
|
---|
| 880 | }
|
---|
| 881 | if (queuePtr->dmPtr != NULL) {
|
---|
| 882 | Blt_Free(queuePtr->dmPtr);
|
---|
| 883 | }
|
---|
| 884 | string = (char *)Tcl_GetVar2(interp, varName, "DocumentName", 0);
|
---|
| 885 | if (string != NULL) {
|
---|
| 886 | if (queuePtr->docName != NULL) {
|
---|
| 887 | Blt_Free(queuePtr->docName);
|
---|
| 888 | }
|
---|
| 889 | queuePtr->docName = Blt_Strdup(string);
|
---|
| 890 | }
|
---|
| 891 | result = SetQueueProperties(interp, queuePtr, dmPtr);
|
---|
| 892 | GlobalUnlock(hMem);
|
---|
| 893 | GlobalFree(hMem);
|
---|
| 894 | CloseQueue(queuePtr);
|
---|
| 895 | return result;
|
---|
| 896 | }
|
---|
| 897 |
|
---|
| 898 | /*ARGSUSED*/
|
---|
| 899 | static int
|
---|
| 900 | EnumOp(
|
---|
| 901 | ClientData clientData, /* Not used. */
|
---|
| 902 | Tcl_Interp *interp,
|
---|
| 903 | int objc,
|
---|
| 904 | Tcl_Obj *CONST *objv)
|
---|
| 905 | {
|
---|
| 906 | TokenString *p;
|
---|
| 907 | char c;
|
---|
| 908 | unsigned int length;
|
---|
| 909 | char *attr;
|
---|
| 910 |
|
---|
| 911 | attr = Tcl_GetStringFromObj(objv[2], &length);
|
---|
| 912 | c = attr[0];
|
---|
| 913 | if ((c == 'p') && (strncmp(attr, "paper", length) == 0)) {
|
---|
| 914 | p = sizeTable;
|
---|
| 915 | } else if ((c == 'q') && (strncmp(attr, "quality", length) == 0)) {
|
---|
| 916 | p = qualityTable;
|
---|
| 917 | } else if ((c == 'b') && (strncmp(attr, "bin", length) == 0)) {
|
---|
| 918 | p = binTable;
|
---|
| 919 | } else if ((c == 'o') && (strncmp(attr, "orientation", length) == 0)) {
|
---|
| 920 | p = orientationTable;
|
---|
| 921 | } else if ((c == 'c') && (strncmp(attr, "color", length) == 0)) {
|
---|
| 922 | p = colorTable;
|
---|
| 923 | } else if ((c == 'd') && (strncmp(attr, "duplex", length) == 0)) {
|
---|
| 924 | p = duplexTable;
|
---|
| 925 | } else if ((c == 't') && (strncmp(attr, "ttoption", length) == 0)) {
|
---|
| 926 | p = ttOptionTable;
|
---|
| 927 | } else {
|
---|
| 928 | Tcl_AppendResult(interp, "bad enumeration field \"", attr,
|
---|
| 929 | "\": should be \"paper\", \"quality\", \"bin\", \"orientation\", \"color\", \"duplex\", or \"ttoption\"",
|
---|
| 930 | (char *)NULL);
|
---|
| 931 | return TCL_ERROR;
|
---|
| 932 | }
|
---|
| 933 | for ( /*empty*/ ; p->string != NULL; p++) {
|
---|
| 934 | Tcl_AppendElement(interp, p->string);
|
---|
| 935 | }
|
---|
| 936 | return TCL_OK;
|
---|
| 937 | }
|
---|
| 938 |
|
---|
| 939 | /*ARGSUSED*/
|
---|
| 940 | static int
|
---|
| 941 | OpenOp(
|
---|
| 942 | ClientData clientData, /* Interpreter-specific data. */
|
---|
| 943 | Tcl_Interp *interp,
|
---|
| 944 | int objc,
|
---|
| 945 | Tcl_Obj *CONST *objv)
|
---|
| 946 | {
|
---|
| 947 | PrinterInterpData *dataPtr = clientData;
|
---|
| 948 | PrintQueue *queuePtr;
|
---|
| 949 | LPVOID buffer;
|
---|
| 950 | PRINTER_INFO_2* pi2Ptr;
|
---|
| 951 | DWORD bytesNeeded;
|
---|
| 952 | int isNew;
|
---|
| 953 | Blt_HashEntry *hPtr;
|
---|
| 954 | HANDLE hMem;
|
---|
| 955 | char *name;
|
---|
| 956 |
|
---|
| 957 | name = Tcl_GetString(objv[2]);
|
---|
| 958 | hPtr = Blt_CreateHashEntry(&dataPtr->printerTable, name, &isNew);
|
---|
| 959 | if (isNew) {
|
---|
| 960 | queuePtr = Blt_Calloc(1, sizeof(PrintQueue));
|
---|
| 961 | queuePtr->name = Blt_GetHashKey(&dataPtr->printerTable, hPtr);
|
---|
| 962 | queuePtr->interp = interp;
|
---|
| 963 | Tcl_SetResult(interp, name, TCL_VOLATILE);
|
---|
| 964 | Blt_SetHashValue(hPtr, queuePtr);
|
---|
| 965 | queuePtr->hashPtr = hPtr;
|
---|
| 966 | queuePtr->tablePtr = &dataPtr->printerTable;
|
---|
| 967 | queuePtr->printerName = Blt_Strdup(name);
|
---|
| 968 | } else {
|
---|
| 969 | Tcl_AppendResult(interp, "printer \"", name, "\" is already open",
|
---|
| 970 | (char *)NULL);
|
---|
| 971 | return TCL_ERROR;
|
---|
| 972 | }
|
---|
| 973 | if (OpenQueue(interp, queuePtr) != TCL_OK) {
|
---|
| 974 | DestroyQueue(queuePtr);
|
---|
| 975 | return TCL_ERROR;
|
---|
| 976 | }
|
---|
| 977 | /* Call the first time to determine the amount of memory needed. */
|
---|
| 978 | GetPrinter(queuePtr->hPrinter, 2, NULL, 0, &bytesNeeded);
|
---|
| 979 | if ((bytesNeeded == 0) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
|
---|
| 980 | Tcl_AppendResult(interp, "can't get size of attribute buffer for \"",
|
---|
| 981 | name, "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 982 | return TCL_ERROR;
|
---|
| 983 | }
|
---|
| 984 | /* Allocate a buffer to contain all printer information. */
|
---|
| 985 | hMem = GlobalAlloc(GHND, bytesNeeded);
|
---|
| 986 | if (hMem == NULL) {
|
---|
| 987 | return TCL_ERROR;
|
---|
| 988 | }
|
---|
| 989 | buffer = (LPVOID)GlobalLock(hMem);
|
---|
| 990 |
|
---|
| 991 | /* And call the again to actually get the printer. */
|
---|
| 992 | if (!GetPrinter(queuePtr->hPrinter, 2, buffer, bytesNeeded,
|
---|
| 993 | &bytesNeeded)) {
|
---|
| 994 | Tcl_AppendResult(interp, "can't get printer attributes for \"",
|
---|
| 995 | name, "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 996 | GlobalUnlock(hMem);
|
---|
| 997 | GlobalFree(hMem);
|
---|
| 998 | return TCL_ERROR;
|
---|
| 999 | }
|
---|
| 1000 | pi2Ptr = (PRINTER_INFO_2 *)buffer;
|
---|
| 1001 | if (pi2Ptr->pDevMode != NULL) {
|
---|
| 1002 | queuePtr->deviceName = Blt_Strdup(pi2Ptr->pDevMode->dmDeviceName);
|
---|
| 1003 | }
|
---|
| 1004 | queuePtr->driverName = Blt_Strdup(pi2Ptr->pDriverName);
|
---|
| 1005 | /*
|
---|
| 1006 | queuePtr->printerName = Blt_Strdup(pi2Ptr->pPrinterName);
|
---|
| 1007 | */
|
---|
| 1008 | queuePtr->portName = Blt_Strdup(pi2Ptr->pPortName);
|
---|
| 1009 | GlobalUnlock(hMem);
|
---|
| 1010 | GlobalFree(hMem);
|
---|
| 1011 | return TCL_OK;
|
---|
| 1012 | }
|
---|
| 1013 |
|
---|
| 1014 | /*ARGSUSED*/
|
---|
| 1015 | static int
|
---|
| 1016 | NamesOp(
|
---|
| 1017 | ClientData clientData, /* Interpreter-specific data. */
|
---|
| 1018 | Tcl_Interp *interp,
|
---|
| 1019 | int objc, /* Not used. */
|
---|
| 1020 | Tcl_Obj *CONST *objv) /* Not used. */
|
---|
| 1021 | {
|
---|
| 1022 | DWORD nPrinters, bytesNeeded;
|
---|
| 1023 | int elemSize, level;
|
---|
| 1024 | unsigned char *buffer;
|
---|
| 1025 | int result, flags;
|
---|
| 1026 | HANDLE hMem;
|
---|
| 1027 |
|
---|
| 1028 | if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
|
---|
| 1029 | level = 4;
|
---|
| 1030 | elemSize = sizeof(PRINTER_INFO_4);
|
---|
| 1031 | flags = PRINTER_ENUM_NAME;
|
---|
| 1032 | } else {
|
---|
| 1033 | level = 5;
|
---|
| 1034 | elemSize = sizeof(PRINTER_INFO_5);
|
---|
| 1035 | flags = PRINTER_ENUM_LOCAL;
|
---|
| 1036 | }
|
---|
| 1037 | result = EnumPrinters(
|
---|
| 1038 | flags, /* Flags */
|
---|
| 1039 | NULL, /* Printer name */
|
---|
| 1040 | level, /* Information level: 1, 2, 4, or 5 */
|
---|
| 1041 | NULL, /* Array of returned information */
|
---|
| 1042 | 0, /* Size of array */
|
---|
| 1043 | &bytesNeeded, /* Size needed for array */
|
---|
| 1044 | &nPrinters); /* Number of structures returned */
|
---|
| 1045 |
|
---|
| 1046 | if ((!result) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
|
---|
| 1047 | Tcl_AppendResult(interp, "can't enumerate printers (memory alloc): ",
|
---|
| 1048 | Blt_LastError(), (char *)NULL);
|
---|
| 1049 | return TCL_ERROR;
|
---|
| 1050 | }
|
---|
| 1051 | hMem = GlobalAlloc(GHND, bytesNeeded);
|
---|
| 1052 | buffer = (unsigned char *)GlobalLock(hMem);
|
---|
| 1053 |
|
---|
| 1054 | result = EnumPrinters(
|
---|
| 1055 | flags, /* Flags */
|
---|
| 1056 | NULL, /* Printer name */
|
---|
| 1057 | level, /* Information level: 1, 2, 4, or 5 */
|
---|
| 1058 | buffer, /* Array of returned information */
|
---|
| 1059 | bytesNeeded, /* Size of array */
|
---|
| 1060 | &bytesNeeded, /* Size needed for array */
|
---|
| 1061 | &nPrinters); /* Number of structures returned */
|
---|
| 1062 |
|
---|
| 1063 | if (!result) {
|
---|
| 1064 | Tcl_AppendResult(interp, "can't enumerate printers: ",
|
---|
| 1065 | Blt_LastError(), (char *)NULL);
|
---|
| 1066 | return TCL_ERROR;
|
---|
| 1067 | }
|
---|
| 1068 | if (objc > 2) {
|
---|
| 1069 | register unsigned int i;
|
---|
| 1070 | char *pattern;
|
---|
| 1071 | char *p;
|
---|
| 1072 |
|
---|
| 1073 | p = buffer;
|
---|
| 1074 | pattern = Tcl_GetString(objv[2]);
|
---|
| 1075 | for (i = 0; i < nPrinters; i++) {
|
---|
| 1076 | if (Tcl_StringMatch(p, pattern)) {
|
---|
| 1077 | Tcl_AppendElement(interp, *(char **)p);
|
---|
| 1078 | }
|
---|
| 1079 | p += elemSize;
|
---|
| 1080 | }
|
---|
| 1081 | } else {
|
---|
| 1082 | register unsigned int i;
|
---|
| 1083 | char *p;
|
---|
| 1084 |
|
---|
| 1085 | p = buffer;
|
---|
| 1086 | for (i = 0; i < nPrinters; i++) {
|
---|
| 1087 | Tcl_AppendElement(interp, *(char **)p);
|
---|
| 1088 | p += elemSize;
|
---|
| 1089 | }
|
---|
| 1090 | }
|
---|
| 1091 | GlobalUnlock(hMem);
|
---|
| 1092 | GlobalFree(hMem);
|
---|
| 1093 | return TCL_OK;
|
---|
| 1094 | }
|
---|
| 1095 |
|
---|
| 1096 | /*ARGSUSED*/
|
---|
| 1097 | static int
|
---|
| 1098 | CloseOp(
|
---|
| 1099 | ClientData clientData, /* Interpreter-specific data. */
|
---|
| 1100 | Tcl_Interp *interp,
|
---|
| 1101 | int objc, /* Not used. */
|
---|
| 1102 | Tcl_Obj *CONST *objv)
|
---|
| 1103 | {
|
---|
| 1104 | PrintQueue *queuePtr;
|
---|
| 1105 |
|
---|
| 1106 | if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {
|
---|
| 1107 | return TCL_ERROR;
|
---|
| 1108 | }
|
---|
| 1109 | DestroyQueue(queuePtr);
|
---|
| 1110 | return TCL_OK;
|
---|
| 1111 | }
|
---|
| 1112 |
|
---|
| 1113 | /*ARGSUSED*/
|
---|
| 1114 | static int
|
---|
| 1115 | GetAttrOp(
|
---|
| 1116 | ClientData clientData, /* Interpreter-specific data. */
|
---|
| 1117 | Tcl_Interp *interp,
|
---|
| 1118 | int objc, /* Not used. */
|
---|
| 1119 | Tcl_Obj *CONST *objv)
|
---|
| 1120 | {
|
---|
| 1121 | PrintQueue *queuePtr;
|
---|
| 1122 |
|
---|
| 1123 | if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {
|
---|
| 1124 | return TCL_ERROR;
|
---|
| 1125 | }
|
---|
| 1126 | return GetPrinterAttributes(interp, queuePtr, objv[3]);
|
---|
| 1127 | }
|
---|
| 1128 |
|
---|
| 1129 | /*ARGSUSED*/
|
---|
| 1130 | static int
|
---|
| 1131 | SetAttrOp(
|
---|
| 1132 | ClientData clientData, /* Interpreter-specific data. */
|
---|
| 1133 | Tcl_Interp *interp,
|
---|
| 1134 | int objc, /* Not used. */
|
---|
| 1135 | Tcl_Obj *CONST *objv)
|
---|
| 1136 | {
|
---|
| 1137 | PrintQueue *queuePtr;
|
---|
| 1138 |
|
---|
| 1139 | if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {
|
---|
| 1140 | return TCL_ERROR;
|
---|
| 1141 | }
|
---|
| 1142 | return SetQueueAttributes(interp, queuePtr, objv[3]);
|
---|
| 1143 | }
|
---|
| 1144 |
|
---|
| 1145 | /*
|
---|
| 1146 | * --------------------------------------------------------------------------
|
---|
| 1147 | *
|
---|
| 1148 | * SnapOp --
|
---|
| 1149 | *
|
---|
| 1150 | * Prints a snapshot of a Tk_Window to the designated printer.
|
---|
| 1151 | *
|
---|
| 1152 | * Results:
|
---|
| 1153 | * Returns a standard Tcl result. If an error occurred
|
---|
| 1154 | * TCL_ERROR is returned and interp->result will contain an
|
---|
| 1155 | * error message.
|
---|
| 1156 | *
|
---|
| 1157 | * -------------------------------------------------------------------------
|
---|
| 1158 | */
|
---|
| 1159 | static int
|
---|
| 1160 | SnapOp(
|
---|
| 1161 | ClientData clientData, /* Interpreter-specific data. */
|
---|
| 1162 | Tcl_Interp *interp,
|
---|
| 1163 | int objc,
|
---|
| 1164 | Tcl_Obj *CONST *objv)
|
---|
| 1165 | {
|
---|
| 1166 | BITMAPINFO bi;
|
---|
| 1167 | DIBSECTION ds;
|
---|
| 1168 | HBITMAP hBitmap;
|
---|
| 1169 | HPALETTE hPalette;
|
---|
| 1170 | HDC hDC, printDC, memDC;
|
---|
| 1171 | void *data;
|
---|
| 1172 | Tk_Window tkwin;
|
---|
| 1173 | TkWinDCState state;
|
---|
| 1174 | int result;
|
---|
| 1175 | PrintQueue *queuePtr;
|
---|
| 1176 | DOCINFO di;
|
---|
| 1177 | double pageWidth, pageHeight;
|
---|
| 1178 | int jobId;
|
---|
| 1179 | char *driverName;
|
---|
| 1180 | DEVMODE *dmPtr;
|
---|
| 1181 | HGLOBAL hMem;
|
---|
| 1182 | Tcl_DString dString;
|
---|
| 1183 | char *path;
|
---|
| 1184 |
|
---|
| 1185 | Tcl_DStringInit(&dString);
|
---|
| 1186 | if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {
|
---|
| 1187 | return TCL_ERROR;
|
---|
| 1188 | }
|
---|
| 1189 | path = Tcl_GetString(objv[3]);
|
---|
| 1190 | tkwin = Tk_NameToWindow(interp, path, Tk_MainWindow(interp));
|
---|
| 1191 | if (tkwin == NULL) {
|
---|
| 1192 | return TCL_ERROR;
|
---|
| 1193 | }
|
---|
| 1194 | if (Tk_WindowId(tkwin) == None) {
|
---|
| 1195 | Tk_MakeWindowExist(tkwin);
|
---|
| 1196 | }
|
---|
| 1197 |
|
---|
| 1198 | result = TCL_ERROR;
|
---|
| 1199 | hDC = TkWinGetDrawableDC(Tk_Display(tkwin), Tk_WindowId(tkwin), &state);
|
---|
| 1200 |
|
---|
| 1201 | ZeroMemory(&bi, sizeof(bi));
|
---|
| 1202 | bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
---|
| 1203 | bi.bmiHeader.biWidth = Tk_Width(tkwin);
|
---|
| 1204 | bi.bmiHeader.biHeight = Tk_Height(tkwin);
|
---|
| 1205 | bi.bmiHeader.biPlanes = 1;
|
---|
| 1206 | bi.bmiHeader.biBitCount = 32;
|
---|
| 1207 | bi.bmiHeader.biCompression = BI_RGB;
|
---|
| 1208 | hBitmap = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &data, NULL, 0);
|
---|
| 1209 | memDC = CreateCompatibleDC(hDC);
|
---|
| 1210 | SelectBitmap(memDC, hBitmap);
|
---|
| 1211 | hPalette = Blt_GetSystemPalette();
|
---|
| 1212 | if (hPalette != NULL) {
|
---|
| 1213 | SelectPalette(hDC, hPalette, FALSE);
|
---|
| 1214 | RealizePalette(hDC);
|
---|
| 1215 | SelectPalette(memDC, hPalette, FALSE);
|
---|
| 1216 | RealizePalette(memDC);
|
---|
| 1217 | }
|
---|
| 1218 | /* Copy the window contents to the memory surface. */
|
---|
| 1219 | if (!BitBlt(memDC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), hDC, 0, 0,
|
---|
| 1220 | SRCCOPY)) {
|
---|
| 1221 | Tcl_AppendResult(interp, "can't blit \"", Tk_PathName(tkwin), "\": ",
|
---|
| 1222 | Blt_LastError(), (char *)NULL);
|
---|
| 1223 | goto done;
|
---|
| 1224 | }
|
---|
| 1225 | /* Now that the DIB contains the image of the window, get the
|
---|
| 1226 | * databits and write them to the printer device, stretching the
|
---|
| 1227 | * image to the fit the printer's resolution. */
|
---|
| 1228 | if (GetObject(hBitmap, sizeof(DIBSECTION), &ds) == 0) {
|
---|
| 1229 | Tcl_AppendResult(interp, "can't get DIB object: ", Blt_LastError(),
|
---|
| 1230 | (char *)NULL);
|
---|
| 1231 | goto done;
|
---|
| 1232 | }
|
---|
| 1233 | driverName = NULL;
|
---|
| 1234 | if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
|
---|
| 1235 | driverName = queuePtr->driverName;
|
---|
| 1236 | }
|
---|
| 1237 | if (OpenQueue(interp, queuePtr) != TCL_OK) {
|
---|
| 1238 | goto done;
|
---|
| 1239 | }
|
---|
| 1240 | hMem = GetQueueProperties(queuePtr, &dmPtr);
|
---|
| 1241 | if (hMem == NULL) {
|
---|
| 1242 | goto done;
|
---|
| 1243 | }
|
---|
| 1244 | printDC = CreateDC(driverName, queuePtr->deviceName, NULL, dmPtr);
|
---|
| 1245 | GlobalUnlock(hMem);
|
---|
| 1246 | GlobalFree(hMem);
|
---|
| 1247 | if (printDC == NULL) {
|
---|
| 1248 | Tcl_AppendResult(interp, "can't allocate printer DC for \"",
|
---|
| 1249 | queuePtr->name, "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 1250 | goto done;
|
---|
| 1251 | }
|
---|
| 1252 | {
|
---|
| 1253 | double scale, sx, sy;
|
---|
| 1254 |
|
---|
| 1255 | /* Get the resolution of the printer device. */
|
---|
| 1256 | sx = (double)GetDeviceCaps(printDC, HORZRES)/(double)Tk_Width(tkwin);
|
---|
| 1257 | sy = (double)GetDeviceCaps(printDC, VERTRES)/(double)Tk_Height(tkwin);
|
---|
| 1258 | scale = MIN(sx, sy);
|
---|
| 1259 | pageWidth = scale * Tk_Width(tkwin);
|
---|
| 1260 | pageHeight = scale * Tk_Height(tkwin);
|
---|
| 1261 | }
|
---|
| 1262 | ZeroMemory(&di, sizeof(di));
|
---|
| 1263 | di.cbSize = sizeof(di);
|
---|
| 1264 | Tcl_DStringAppend(&dString, "Snapshot of \"", -1);
|
---|
| 1265 | Tcl_DStringAppend(&dString, Tk_PathName(tkwin), -1);
|
---|
| 1266 | Tcl_DStringAppend(&dString, "\"", -1);
|
---|
| 1267 | di.lpszDocName = Tcl_DStringValue(&dString);
|
---|
| 1268 | jobId = StartDoc(printDC, &di);
|
---|
| 1269 | if (jobId <= 0) {
|
---|
| 1270 | Tcl_AppendResult(interp, "can't start document: ", Blt_LastError(),
|
---|
| 1271 | (char *)NULL);
|
---|
| 1272 | goto done;
|
---|
| 1273 | }
|
---|
| 1274 | if (StartPage(printDC) <= 0) {
|
---|
| 1275 | Tcl_AppendResult(interp, "error starting page: ", Blt_LastError(),
|
---|
| 1276 | (char *)NULL);
|
---|
| 1277 | goto done;
|
---|
| 1278 | }
|
---|
| 1279 | StretchDIBits(printDC, 0, 0, ROUND(pageWidth), ROUND(pageHeight), 0, 0,
|
---|
| 1280 | Tk_Width(tkwin), Tk_Height(tkwin), ds.dsBm.bmBits,
|
---|
| 1281 | (LPBITMAPINFO)&ds.dsBmih, DIB_RGB_COLORS, SRCCOPY);
|
---|
| 1282 | EndPage(printDC);
|
---|
| 1283 | EndDoc(printDC);
|
---|
| 1284 | DeleteDC(printDC);
|
---|
| 1285 | Tcl_SetResult(interp, Blt_Itoa(jobId), TCL_VOLATILE);
|
---|
| 1286 | result = TCL_OK;
|
---|
| 1287 |
|
---|
| 1288 | done:
|
---|
| 1289 | Tcl_DStringFree(&dString);
|
---|
| 1290 | if (queuePtr->hPrinter != NULL) {
|
---|
| 1291 | CloseQueue(queuePtr);
|
---|
| 1292 | }
|
---|
| 1293 | DeleteBitmap(hBitmap);
|
---|
| 1294 | DeleteDC(memDC);
|
---|
| 1295 | TkWinReleaseDrawableDC(Tk_WindowId(tkwin), hDC, &state);
|
---|
| 1296 | if (hPalette != NULL) {
|
---|
| 1297 | DeletePalette(hPalette);
|
---|
| 1298 | }
|
---|
| 1299 | return result;
|
---|
| 1300 | }
|
---|
| 1301 |
|
---|
| 1302 | /*ARGSUSED*/
|
---|
| 1303 | static int
|
---|
| 1304 | WriteOp(
|
---|
| 1305 | ClientData clientData, /* Interpreter-specific data. */
|
---|
| 1306 | Tcl_Interp *interp,
|
---|
| 1307 | int objc, /* Not used. */
|
---|
| 1308 | Tcl_Obj *CONST *objv)
|
---|
| 1309 | {
|
---|
| 1310 | DWORD bytesLeft, nBytes;
|
---|
| 1311 | DOC_INFO_1 di1;
|
---|
| 1312 | DWORD jobId;
|
---|
| 1313 | char *title;
|
---|
| 1314 | register char *data;
|
---|
| 1315 | static int nextJob = 0;
|
---|
| 1316 | char string[200];
|
---|
| 1317 | PrintQueue *queuePtr;
|
---|
| 1318 | int result;
|
---|
| 1319 |
|
---|
| 1320 | if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {
|
---|
| 1321 | return TCL_ERROR;
|
---|
| 1322 | }
|
---|
| 1323 | if (OpenQueue(interp, queuePtr) != TCL_OK) {
|
---|
| 1324 | return TCL_ERROR;
|
---|
| 1325 | }
|
---|
| 1326 | if (objc == 5) {
|
---|
| 1327 | title = Tcl_GetString(objv[3]);
|
---|
| 1328 | data = Tcl_GetStringFromObj(objv[4], &bytesLeft);
|
---|
| 1329 | } else {
|
---|
| 1330 | sprintf(string, "Print Job #%d", nextJob++);
|
---|
| 1331 | title = string;
|
---|
| 1332 | data = Tcl_GetStringFromObj(objv[3], &bytesLeft);
|
---|
| 1333 | }
|
---|
| 1334 | ZeroMemory(&di1, sizeof(DOC_INFO_1));
|
---|
| 1335 | di1.pDocName = title;
|
---|
| 1336 | if (queuePtr->fileName != NULL) {
|
---|
| 1337 | di1.pOutputFile = queuePtr->fileName;
|
---|
| 1338 | } else {
|
---|
| 1339 | di1.pOutputFile = NULL;
|
---|
| 1340 | }
|
---|
| 1341 | di1.pDatatype = "RAW";
|
---|
| 1342 |
|
---|
| 1343 | result = TCL_ERROR;
|
---|
| 1344 | /* Start new document */
|
---|
| 1345 | jobId = StartDocPrinter(queuePtr->hPrinter, 1, (unsigned char *)&di1);
|
---|
| 1346 | if (jobId == 0) {
|
---|
| 1347 | Tcl_AppendResult(interp, "error starting document on \"",
|
---|
| 1348 | queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 1349 | goto error;
|
---|
| 1350 | }
|
---|
| 1351 | /* Start new page */
|
---|
| 1352 | if (!StartPagePrinter(queuePtr->hPrinter)) {
|
---|
| 1353 | Tcl_AppendResult(interp, "error starting page on \"",
|
---|
| 1354 | queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 1355 | goto error;
|
---|
| 1356 | }
|
---|
| 1357 | do {
|
---|
| 1358 | if (!WritePrinter(queuePtr->hPrinter, data, bytesLeft, &nBytes)) {
|
---|
| 1359 | Tcl_AppendResult(interp, "can't write data to \"",
|
---|
| 1360 | queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 1361 | EndDocPrinter(queuePtr->hPrinter);
|
---|
| 1362 | goto error;
|
---|
| 1363 | }
|
---|
| 1364 | data += nBytes;
|
---|
| 1365 | bytesLeft -= nBytes;
|
---|
| 1366 | } while (bytesLeft > 0);
|
---|
| 1367 | /* End last page */
|
---|
| 1368 | if (!EndPagePrinter(queuePtr->hPrinter)) {
|
---|
| 1369 | Tcl_AppendResult(interp, "error ending page on \"",
|
---|
| 1370 | queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 1371 | goto error;
|
---|
| 1372 | }
|
---|
| 1373 | /* End document */
|
---|
| 1374 | if (!EndDocPrinter(queuePtr->hPrinter)) {
|
---|
| 1375 | Tcl_AppendResult(interp, "error ending document on \"",
|
---|
| 1376 | queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 1377 | goto error;
|
---|
| 1378 | }
|
---|
| 1379 | result = TCL_OK;
|
---|
| 1380 | error:
|
---|
| 1381 | CloseQueue(queuePtr);
|
---|
| 1382 | return result;
|
---|
| 1383 | }
|
---|
| 1384 |
|
---|
| 1385 | static Blt_OpSpec printerOps[] =
|
---|
| 1386 | {
|
---|
| 1387 | {"close", 1, (Blt_Op)CloseOp, 3, 3, "pid",},
|
---|
| 1388 | {"enum", 1, (Blt_Op)EnumOp, 3, 3, "attribute",},
|
---|
| 1389 | {"getattrs", 1, (Blt_Op)GetAttrOp, 4, 4, "pid varName",},
|
---|
| 1390 | {"names", 1, (Blt_Op)NamesOp, 2, 3, "?pattern?",},
|
---|
| 1391 | {"open", 1, (Blt_Op)OpenOp, 3, 3, "printerName",},
|
---|
| 1392 | {"setattrs", 1, (Blt_Op)SetAttrOp, 4, 4, "pid varName",},
|
---|
| 1393 | {"snap", 1, (Blt_Op)SnapOp, 4, 4, "pid window",},
|
---|
| 1394 | {"write", 1, (Blt_Op)WriteOp, 4, 5, "pid ?title? string",},
|
---|
| 1395 | };
|
---|
| 1396 | static int nPrinterOps = sizeof(printerOps) / sizeof(Blt_OpSpec);
|
---|
| 1397 |
|
---|
| 1398 | /* ARGSUSED */
|
---|
| 1399 | static int
|
---|
| 1400 | PrinterCmd(
|
---|
| 1401 | ClientData clientData, /* Not used. */
|
---|
| 1402 | Tcl_Interp *interp,
|
---|
| 1403 | int objc,
|
---|
| 1404 | Tcl_Obj *CONST *objv)
|
---|
| 1405 | {
|
---|
| 1406 | Blt_Op proc;
|
---|
| 1407 | int result;
|
---|
| 1408 |
|
---|
| 1409 | proc = Blt_GetOpFromObj(interp, nPrinterOps, printerOps, BLT_OP_ARG1,
|
---|
| 1410 | objc, objv, 0);
|
---|
| 1411 | if (proc == NULL) {
|
---|
| 1412 | return TCL_ERROR;
|
---|
| 1413 | }
|
---|
| 1414 | result = (*proc) (clientData, interp, objc, objv);
|
---|
| 1415 | return result;
|
---|
| 1416 | }
|
---|
| 1417 |
|
---|
| 1418 | /*
|
---|
| 1419 | * -----------------------------------------------------------------------
|
---|
| 1420 | *
|
---|
| 1421 | * PrinterInterpDeleteProc --
|
---|
| 1422 | *
|
---|
| 1423 | * This is called when the interpreter hosting one or more printer
|
---|
| 1424 | * commands is destroyed.
|
---|
| 1425 | *
|
---|
| 1426 | * Results:
|
---|
| 1427 | * None.
|
---|
| 1428 | *
|
---|
| 1429 | * Side effects:
|
---|
| 1430 | * Closes and removes all open printers.
|
---|
| 1431 | *
|
---|
| 1432 | * ------------------------------------------------------------------------
|
---|
| 1433 | */
|
---|
| 1434 | /* ARGSUSED */
|
---|
| 1435 | static void
|
---|
| 1436 | PrinterInterpDeleteProc(clientData, interp)
|
---|
| 1437 | ClientData clientData; /* Interpreter-specific data. */
|
---|
| 1438 | Tcl_Interp *interp;
|
---|
| 1439 | {
|
---|
| 1440 | PrinterInterpData *dataPtr = clientData;
|
---|
| 1441 | Blt_HashEntry *hPtr;
|
---|
| 1442 | Blt_HashSearch cursor;
|
---|
| 1443 | PrintQueue *queuePtr;
|
---|
| 1444 |
|
---|
| 1445 | for (hPtr = Blt_FirstHashEntry(&dataPtr->printerTable, &cursor);
|
---|
| 1446 | hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
|
---|
| 1447 | queuePtr = (PrintQueue *)Blt_GetHashValue(hPtr);
|
---|
| 1448 | queuePtr->hashPtr = NULL;
|
---|
| 1449 | DestroyQueue(queuePtr);
|
---|
| 1450 | }
|
---|
| 1451 | Blt_DeleteHashTable(&dataPtr->printerTable);
|
---|
| 1452 | Tcl_DeleteAssocData(interp, PRINTER_THREAD_KEY);
|
---|
| 1453 | Blt_Free(dataPtr);
|
---|
| 1454 | }
|
---|
| 1455 |
|
---|
| 1456 |
|
---|
| 1457 | int
|
---|
| 1458 | Blt_PrinterInit(Tcl_Interp *interp)
|
---|
| 1459 | {
|
---|
| 1460 | static Blt_ObjCmdSpec cmdSpec = {
|
---|
| 1461 | "printer", PrinterCmd
|
---|
| 1462 | };
|
---|
| 1463 | PrinterInterpData *dataPtr;
|
---|
| 1464 |
|
---|
| 1465 | dataPtr = GetPrinterInterpData(interp);
|
---|
| 1466 | cmdSpec.clientData = dataPtr;
|
---|
| 1467 | if (Blt_InitObjCmd(interp, "blt", &cmdSpec) == NULL) {
|
---|
| 1468 | return TCL_ERROR;
|
---|
| 1469 | }
|
---|
| 1470 | return TCL_OK;
|
---|
| 1471 | }
|
---|
| 1472 | |
---|
| 1473 |
|
---|
| 1474 |
|
---|
| 1475 | /* Public routines */
|
---|
| 1476 | int
|
---|
| 1477 | Blt_GetOpenPrinter(
|
---|
| 1478 | Tcl_Interp *interp,
|
---|
| 1479 | const char *name,
|
---|
| 1480 | Drawable *drawablePtr)
|
---|
| 1481 | {
|
---|
| 1482 | PrintQueue *queuePtr;
|
---|
| 1483 |
|
---|
| 1484 | if (GetQueue(interp, name, &queuePtr) != TCL_OK) {
|
---|
| 1485 | return TCL_ERROR;
|
---|
| 1486 | }
|
---|
| 1487 | if (queuePtr->drawable.hDC == NULL) {
|
---|
| 1488 | char *driverName;
|
---|
| 1489 | HGLOBAL hMem;
|
---|
| 1490 | DEVMODE *dmPtr;
|
---|
| 1491 | HDC hDC;
|
---|
| 1492 |
|
---|
| 1493 | driverName = NULL;
|
---|
| 1494 | if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
|
---|
| 1495 | driverName = queuePtr->driverName;
|
---|
| 1496 | }
|
---|
| 1497 | if (OpenQueue(interp, queuePtr) != TCL_OK) {
|
---|
| 1498 | return TCL_ERROR;
|
---|
| 1499 | }
|
---|
| 1500 | hMem = GetQueueProperties(queuePtr, &dmPtr);
|
---|
| 1501 | if (hMem == NULL) {
|
---|
| 1502 | CloseQueue(queuePtr);
|
---|
| 1503 | return TCL_ERROR;
|
---|
| 1504 | }
|
---|
| 1505 | if (queuePtr->dmPtr != NULL) {
|
---|
| 1506 | *dmPtr = *queuePtr->dmPtr;
|
---|
| 1507 | }
|
---|
| 1508 | hDC = CreateDC(driverName, queuePtr->deviceName, NULL, dmPtr);
|
---|
| 1509 | GlobalUnlock(hMem);
|
---|
| 1510 | GlobalFree(hMem);
|
---|
| 1511 | CloseQueue(queuePtr);
|
---|
| 1512 | if (hDC == NULL) {
|
---|
| 1513 | Tcl_AppendResult(interp, "can't allocate printer DC for \"",
|
---|
| 1514 | queuePtr->name, "\": ", Blt_LastError(), (char *)NULL);
|
---|
| 1515 | return TCL_ERROR;
|
---|
| 1516 | }
|
---|
| 1517 | queuePtr->drawable.hDC = hDC;
|
---|
| 1518 | queuePtr->drawable.type = TWD_WINDC;
|
---|
| 1519 | }
|
---|
| 1520 | *drawablePtr = (Drawable)(&queuePtr->drawable);
|
---|
| 1521 | return TCL_OK;
|
---|
| 1522 | }
|
---|
| 1523 |
|
---|
| 1524 | #include <commdlg.h>
|
---|
| 1525 |
|
---|
| 1526 | int
|
---|
| 1527 | Blt_PrintDialog(
|
---|
| 1528 | Tcl_Interp *interp,
|
---|
| 1529 | Drawable *drawablePtr)
|
---|
| 1530 | {
|
---|
| 1531 | PRINTDLG dlg;
|
---|
| 1532 | static PrintDrawable drawable;
|
---|
| 1533 | int mode, result;
|
---|
| 1534 |
|
---|
| 1535 | ZeroMemory(&dlg, sizeof(PRINTDLG));
|
---|
| 1536 | dlg.lStructSize = sizeof(PRINTDLG);
|
---|
| 1537 | dlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION;
|
---|
| 1538 | mode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
|
---|
| 1539 | result = PrintDlg(&dlg);
|
---|
| 1540 | Tcl_SetServiceMode(mode);
|
---|
| 1541 | if (!result) {
|
---|
| 1542 | if (!CommDlgExtendedError()) {
|
---|
| 1543 | return TCL_RETURN; /* User canceled. */
|
---|
| 1544 | }
|
---|
| 1545 | Tcl_AppendResult(interp, "can't access printer:", Blt_LastError(),
|
---|
| 1546 | (char *)NULL);
|
---|
| 1547 | return TCL_ERROR;
|
---|
| 1548 | }
|
---|
| 1549 | *drawablePtr = (Drawable)&drawable;
|
---|
| 1550 | drawable.type = TWD_WINDC;
|
---|
| 1551 | drawable.hDC = dlg.hDC;
|
---|
| 1552 | return TCL_OK;
|
---|
| 1553 | }
|
---|
| 1554 |
|
---|
| 1555 | int
|
---|
| 1556 | Blt_StartPrintJob(
|
---|
| 1557 | Tcl_Interp *interp,
|
---|
| 1558 | Drawable drawable)
|
---|
| 1559 | {
|
---|
| 1560 | DOCINFO di;
|
---|
| 1561 | PrintDrawable *drawPtr = (PrintDrawable *)drawable;
|
---|
| 1562 | int jobId;
|
---|
| 1563 |
|
---|
| 1564 | ZeroMemory((char *)&di, sizeof(DOCINFO));
|
---|
| 1565 | di.cbSize = sizeof(DOCINFO);
|
---|
| 1566 | di.lpszDocName = "Unknown";
|
---|
| 1567 | jobId = StartDoc(drawPtr->hDC, &di);
|
---|
| 1568 | if (jobId == 0) {
|
---|
| 1569 | Tcl_AppendResult(interp, "error starting document: ",
|
---|
| 1570 | Blt_LastError(), (char *)NULL);
|
---|
| 1571 | return TCL_ERROR;
|
---|
| 1572 | }
|
---|
| 1573 | return TCL_OK;
|
---|
| 1574 | }
|
---|
| 1575 |
|
---|
| 1576 | int
|
---|
| 1577 | Blt_EndPrintJob(
|
---|
| 1578 | Tcl_Interp *interp,
|
---|
| 1579 | Drawable drawable)
|
---|
| 1580 | {
|
---|
| 1581 | PrintDrawable *drawPtr = (PrintDrawable *)drawable;
|
---|
| 1582 |
|
---|
| 1583 | EndPage(drawPtr->hDC);
|
---|
| 1584 | EndDoc(drawPtr->hDC);
|
---|
| 1585 | return TCL_OK;
|
---|
| 1586 | }
|
---|
| 1587 |
|
---|
| 1588 | #endif /*NO_PRINTER*/
|
---|