kernel32/tests: Add a test to check some fields in fake dlls.
[wine.git] / dlls / wineps.drv / escape.c
blobb3eff6813c0d8c88f3fa3e7791e6ff4d6e031a92
1 /*
2 * PostScript driver Escape function
4 * Copyright 1998 Huw D M Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <signal.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wingdi.h"
38 #include "wine/wingdi16.h"
39 #include "winuser.h"
40 #include "winreg.h"
41 #include "psdrv.h"
42 #include "wine/debug.h"
43 #include "winspool.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
47 DWORD write_spool( PHYSDEV dev, const void *data, DWORD num )
49 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
50 DWORD written;
52 if (!WritePrinter(physDev->job.hprinter, (LPBYTE) data, num, &written) || (written != num))
53 return SP_OUTOFDISK;
55 return num;
58 /**********************************************************************
59 * ExtEscape (WINEPS.@)
61 INT PSDRV_ExtEscape( PHYSDEV dev, INT nEscape, INT cbInput, LPCVOID in_data,
62 INT cbOutput, LPVOID out_data )
64 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
66 TRACE("%p,%d,%d,%p,%d,%p\n",
67 dev->hdc, nEscape, cbInput, in_data, cbOutput, out_data);
69 switch(nEscape)
71 case QUERYESCSUPPORT:
72 if(cbInput < sizeof(SHORT))
74 WARN("cbInput < sizeof(SHORT) (=%d) for QUERYESCSUPPORT\n", cbInput);
75 return 0;
76 } else {
77 DWORD num = (cbInput < sizeof(DWORD)) ? *(const USHORT *)in_data : *(const DWORD *)in_data;
78 TRACE("QUERYESCSUPPORT for %d\n", num);
80 switch(num) {
81 case NEXTBAND:
82 /*case BANDINFO:*/
83 case SETCOPYCOUNT:
84 case GETTECHNOLOGY:
85 case SETLINECAP:
86 case SETLINEJOIN:
87 case SETMITERLIMIT:
88 case SETCHARSET:
89 case EXT_DEVICE_CAPS:
90 case SET_BOUNDS:
91 case EPSPRINTING:
92 case POSTSCRIPT_DATA:
93 case PASSTHROUGH:
94 case POSTSCRIPT_PASSTHROUGH:
95 case POSTSCRIPT_IGNORE:
96 case BEGIN_PATH:
97 case CLIP_TO_PATH:
98 case END_PATH:
99 /*case DRAWPATTERNRECT:*/
101 /* PageMaker checks for it */
102 case DOWNLOADHEADER:
104 /* PageMaker doesn't check for DOWNLOADFACE and GETFACENAME but
105 * uses them, they are supposed to be supported by any PS printer.
107 case DOWNLOADFACE:
109 /* PageMaker checks for these as a part of process of detecting
110 * a "fully compatible" PS printer, but doesn't actually use them.
112 case OPENCHANNEL:
113 case CLOSECHANNEL:
114 return TRUE;
116 /* Windows PS driver reports 0, but still supports this escape */
117 case GETFACENAME:
118 return FALSE; /* suppress the FIXME below */
120 default:
121 FIXME("QUERYESCSUPPORT(%d) - not supported.\n", num);
122 return FALSE;
126 case OPENCHANNEL:
127 FIXME("OPENCHANNEL: stub\n");
128 return 1;
130 case CLOSECHANNEL:
131 FIXME("CLOSECHANNEL: stub\n");
132 return 1;
134 case DOWNLOADHEADER:
135 FIXME("DOWNLOADHEADER: stub\n");
136 /* should return name of the downloaded procset */
137 *(char *)out_data = 0;
138 return 1;
140 case GETFACENAME:
141 FIXME("GETFACENAME: stub\n");
142 lstrcpynA(out_data, "Courier", cbOutput);
143 return 1;
145 case DOWNLOADFACE:
146 FIXME("DOWNLOADFACE: stub\n");
147 return 1;
149 case MFCOMMENT:
151 FIXME("MFCOMMENT(%p, %d)\n", in_data, cbInput);
152 return 1;
154 case DRAWPATTERNRECT:
156 DRAWPATRECT *dpr = (DRAWPATRECT*)in_data;
158 FIXME("DRAWPATTERNRECT(pos (%d,%d), size %dx%d, style %d, pattern %x), stub!\n",
159 dpr->ptPosition.x, dpr->ptPosition.y,
160 dpr->ptSize.x, dpr->ptSize.y,
161 dpr->wStyle, dpr->wPattern
163 return 1;
165 case BANDINFO:
167 BANDINFOSTRUCT *ibi = (BANDINFOSTRUCT*)in_data;
168 BANDINFOSTRUCT *obi = (BANDINFOSTRUCT*)out_data;
170 FIXME("BANDINFO(graphics %d, text %d, rect %s), stub!\n", ibi->GraphicsFlag,
171 ibi->TextFlag, wine_dbgstr_rect(&ibi->GraphicsRect));
172 *obi = *ibi;
173 return 1;
175 case NEXTBAND:
177 RECT *r = out_data;
178 if(!physDev->job.banding) {
179 physDev->job.banding = TRUE;
180 SetRect(r, 0, 0, physDev->horzRes, physDev->vertRes);
181 TRACE("NEXTBAND returning %s\n", wine_dbgstr_rect(r));
182 return 1;
184 SetRectEmpty(r);
185 TRACE("NEXTBAND rect to 0,0 - 0,0\n" );
186 physDev->job.banding = FALSE;
187 return EndPage( dev->hdc );
190 case SETCOPYCOUNT:
192 const INT *NumCopies = in_data;
193 INT *ActualCopies = out_data;
194 if(cbInput != sizeof(INT)) {
195 WARN("cbInput != sizeof(INT) (=%d) for SETCOPYCOUNT\n", cbInput);
196 return 0;
198 TRACE("SETCOPYCOUNT %d\n", *NumCopies);
199 *ActualCopies = 1;
200 return 1;
203 case GETTECHNOLOGY:
205 LPSTR p = out_data;
206 strcpy(p, "PostScript");
207 *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
208 return 1;
211 case SETLINECAP:
213 INT newCap = *(const INT *)in_data;
214 if(cbInput != sizeof(INT)) {
215 WARN("cbInput != sizeof(INT) (=%d) for SETLINECAP\n", cbInput);
216 return 0;
218 TRACE("SETLINECAP %d\n", newCap);
219 return 0;
222 case SETLINEJOIN:
224 INT newJoin = *(const INT *)in_data;
225 if(cbInput != sizeof(INT)) {
226 WARN("cbInput != sizeof(INT) (=%d) for SETLINEJOIN\n", cbInput);
227 return 0;
229 TRACE("SETLINEJOIN %d\n", newJoin);
230 return 0;
233 case SETMITERLIMIT:
235 INT newLimit = *(const INT *)in_data;
236 if(cbInput != sizeof(INT)) {
237 WARN("cbInput != sizeof(INT) (=%d) for SETMITERLIMIT\n", cbInput);
238 return 0;
240 TRACE("SETMITERLIMIT %d\n", newLimit);
241 return 0;
244 case SETCHARSET:
245 /* Undocumented escape used by winword6.
246 Switches between ANSI and a special charset.
247 If *lpInData == 1 we require that
248 0x91 is quoteleft
249 0x92 is quoteright
250 0x93 is quotedblleft
251 0x94 is quotedblright
252 0x95 is bullet
253 0x96 is endash
254 0x97 is emdash
255 0xa0 is non break space - yeah right.
257 If *lpInData == 0 we get ANSI.
258 Since there's nothing else there, let's just make these the default
259 anyway and see what happens...
261 return 1;
263 case EXT_DEVICE_CAPS:
265 UINT cap = *(const UINT *)in_data;
266 if(cbInput != sizeof(UINT)) {
267 WARN("cbInput != sizeof(UINT) (=%d) for EXT_DEVICE_CAPS\n", cbInput);
268 return 0;
270 TRACE("EXT_DEVICE_CAPS %d\n", cap);
271 return 0;
274 case SET_BOUNDS:
276 const RECT *r = in_data;
277 if(cbInput != sizeof(RECT)) {
278 WARN("cbInput != sizeof(RECT) (=%d) for SET_BOUNDS\n", cbInput);
279 return 0;
281 TRACE("SET_BOUNDS %s\n", wine_dbgstr_rect(r));
282 return 0;
285 case EPSPRINTING:
287 UINT epsprint = *(const UINT*)in_data;
288 /* FIXME: In this mode we do not need to send page intros and page
289 * ends according to the doc. But I just ignore that detail
290 * for now.
292 TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
293 return 1;
296 case POSTSCRIPT_DATA:
297 case PASSTHROUGH:
298 case POSTSCRIPT_PASSTHROUGH:
300 /* Write directly to spool file, bypassing normal PS driver
301 * processing that is done along with writing PostScript code
302 * to the spool.
303 * We have a WORD before the data counting the size, but
304 * cbInput is just this +2.
305 * However Photoshop 7 has a bug that sets cbInput to 2 less than the
306 * length of the string, rather than 2 more. So we'll use the WORD at
307 * in_data[0] instead.
309 passthrough_enter(dev);
310 return write_spool(dev, ((char*)in_data) + 2, *(const WORD*)in_data);
313 case POSTSCRIPT_IGNORE:
315 BOOL ret = physDev->job.quiet;
316 TRACE("POSTSCRIPT_IGNORE %d\n", *(const short*)in_data);
317 physDev->job.quiet = *(const short*)in_data;
318 return ret;
321 case GETSETPRINTORIENT:
323 /* If lpInData is present, it is a 20 byte structure, first 32
324 * bit LONG value is the orientation. if lpInData is NULL, it
325 * returns the current orientation.
327 FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
328 return 1;
330 case BEGIN_PATH:
331 TRACE("BEGIN_PATH\n");
332 if(physDev->pathdepth)
333 FIXME("Nested paths not yet handled\n");
334 return ++physDev->pathdepth;
336 case END_PATH:
338 const struct PATH_INFO *info = (const struct PATH_INFO*)in_data;
340 TRACE("END_PATH\n");
341 if(!physDev->pathdepth) {
342 ERR("END_PATH called without a BEGIN_PATH\n");
343 return -1;
345 TRACE("RenderMode = %d, FillMode = %d, BkMode = %d\n",
346 info->RenderMode, info->FillMode, info->BkMode);
347 switch(info->RenderMode) {
348 case RENDERMODE_NO_DISPLAY:
349 PSDRV_WriteClosePath(dev); /* not sure if this is necessary, but it can't hurt */
350 break;
351 case RENDERMODE_OPEN:
352 case RENDERMODE_CLOSED:
353 default:
354 FIXME("END_PATH: RenderMode %d, not yet supported\n", info->RenderMode);
355 break;
357 return --physDev->pathdepth;
360 case CLIP_TO_PATH:
362 WORD mode = *(const WORD*)in_data;
364 switch(mode) {
365 case CLIP_SAVE:
366 TRACE("CLIP_TO_PATH: CLIP_SAVE\n");
367 PSDRV_WriteGSave(dev);
368 return 1;
369 case CLIP_RESTORE:
370 TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
371 PSDRV_WriteGRestore(dev);
372 return 1;
373 case CLIP_INCLUSIVE:
374 TRACE("CLIP_TO_PATH: CLIP_INCLUSIVE\n");
375 /* FIXME to clip or eoclip ? (see PATH_INFO.FillMode) */
376 PSDRV_WriteClip(dev);
377 PSDRV_WriteNewPath(dev);
378 return 1;
379 case CLIP_EXCLUSIVE:
380 FIXME("CLIP_EXCLUSIVE: not implemented\n");
381 return 0;
382 default:
383 FIXME("Unknown CLIP_TO_PATH mode %d\n", mode);
384 return 0;
387 default:
388 FIXME("Unimplemented code %d\n", nEscape);
389 return 0;
393 /************************************************************************
394 * PSDRV_StartPage
396 INT PSDRV_StartPage( PHYSDEV dev )
398 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
400 TRACE("%p\n", dev->hdc);
402 if(!physDev->job.OutOfPage) {
403 FIXME("Already started a page?\n");
404 return 1;
407 physDev->job.PageNo++;
409 if(!PSDRV_WriteNewPage( dev ))
410 return 0;
411 physDev->job.OutOfPage = FALSE;
412 return 1;
416 /************************************************************************
417 * PSDRV_EndPage
419 INT PSDRV_EndPage( PHYSDEV dev )
421 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
423 TRACE("%p\n", dev->hdc);
425 if(physDev->job.OutOfPage) {
426 FIXME("Already ended a page?\n");
427 return 1;
430 passthrough_leave(dev);
431 if(!PSDRV_WriteEndPage( dev ))
432 return 0;
433 PSDRV_EmptyDownloadList(dev, FALSE);
434 physDev->job.OutOfPage = TRUE;
435 return 1;
439 /************************************************************************
440 * PSDRV_StartDoc
442 INT PSDRV_StartDoc( PHYSDEV dev, const DOCINFOW *doc )
444 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
445 DOC_INFO_1W di;
446 PRINTER_DEFAULTSW prn_def;
448 TRACE("(%p, %p) => %s, %s, %s\n", physDev, doc, debugstr_w(doc->lpszDocName),
449 debugstr_w(doc->lpszOutput), debugstr_w(doc->lpszDatatype));
451 if(physDev->job.id) {
452 FIXME("hJob != 0. Now what?\n");
453 return 0;
456 prn_def.pDatatype = NULL;
457 prn_def.pDevMode = &physDev->pi->Devmode->dmPublic;
458 prn_def.DesiredAccess = PRINTER_ACCESS_USE;
460 if (!OpenPrinterW( physDev->pi->friendly_name, &physDev->job.hprinter, &prn_def ))
462 WARN("OpenPrinter(%s, ...) failed: %d\n",
463 debugstr_w(physDev->pi->friendly_name), GetLastError());
464 return 0;
467 di.pDocName = (LPWSTR) doc->lpszDocName;
468 di.pDatatype = NULL;
470 if(doc->lpszOutput)
471 di.pOutputFile = (LPWSTR) doc->lpszOutput;
472 else if(physDev->job.output)
473 di.pOutputFile = physDev->job.output;
474 else
475 di.pOutputFile = NULL;
477 TRACE("using output: %s\n", debugstr_w(di.pOutputFile));
479 /* redirection located in HKCU\Software\Wine\Printing\Spooler
480 is done during winspool.drv,ScheduleJob */
481 physDev->job.id = StartDocPrinterW(physDev->job.hprinter, 1, (LPBYTE) &di);
482 if(!physDev->job.id) {
483 WARN("StartDocPrinter() failed: %d\n", GetLastError());
484 ClosePrinter(physDev->job.hprinter);
485 return 0;
488 if (!PSDRV_WriteHeader( dev, doc->lpszDocName )) {
489 WARN("Failed to write header\n");
490 ClosePrinter(physDev->job.hprinter);
491 return 0;
494 physDev->job.banding = FALSE;
495 physDev->job.OutOfPage = TRUE;
496 physDev->job.PageNo = 0;
497 physDev->job.quiet = FALSE;
498 physDev->job.passthrough_state = passthrough_none;
499 physDev->job.doc_name = strdupW( doc->lpszDocName );
501 return physDev->job.id;
504 /************************************************************************
505 * PSDRV_EndDoc
507 INT PSDRV_EndDoc( PHYSDEV dev )
509 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
510 INT ret = 1;
512 TRACE("%p\n", dev->hdc);
514 if(!physDev->job.id) {
515 FIXME("hJob == 0. Now what?\n");
516 return 0;
519 if(!physDev->job.OutOfPage) {
520 WARN("Somebody forgot an EndPage\n");
521 PSDRV_EndPage( dev );
524 if (physDev->job.PageNo)
525 PSDRV_WriteFooter( dev );
527 ret = EndDocPrinter(physDev->job.hprinter);
528 ClosePrinter(physDev->job.hprinter);
529 physDev->job.hprinter = NULL;
530 physDev->job.id = 0;
531 HeapFree( GetProcessHeap(), 0, physDev->job.doc_name );
532 physDev->job.doc_name = NULL;
534 return ret;