Release 980809
[wine] / graphics / win16drv / init.c
1 /*
2  * Windows Device Context initialisation functions
3  *
4  * Copyright 1996 John Harvey
5  *           1998 Huw Davies
6  */
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/types.h>
11 #include <ctype.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <errno.h>
15 #include "windows.h"
16 #include "win16drv.h"
17 #include "gdi.h"
18 #include "bitmap.h"
19 #include "heap.h"
20 #include "color.h"
21 #include "font.h"
22 #include "callback.h"
23 #include "options.h"
24 #include "debug.h"
25 #include "dc.h"
26
27 #define SUPPORT_REALIZED_FONTS 1
28 #pragma pack(1)
29 typedef struct
30 {
31   SHORT nSize;
32   SEGPTR lpindata;
33   SEGPTR lpFont;
34   SEGPTR lpXForm;
35   SEGPTR lpDrawMode;
36 } EXTTEXTDATA, *LPEXTTEXTDATA;
37 #pragma pack(4)
38
39 SEGPTR          win16drv_SegPtr_TextXForm;
40 LPTEXTXFORM16   win16drv_TextXFormP;
41 SEGPTR          win16drv_SegPtr_DrawMode;
42 LPDRAWMODE      win16drv_DrawModeP;
43
44
45 static BOOL32 WIN16DRV_CreateDC( DC *dc, LPCSTR driver, LPCSTR device,
46                                  LPCSTR output, const DEVMODE16* initData );
47 static INT32 WIN16DRV_Escape( DC *dc, INT32 nEscape, INT32 cbInput, 
48                               SEGPTR lpInData, SEGPTR lpOutData );
49
50 static const DC_FUNCTIONS WIN16DRV_Funcs =
51 {
52     NULL,                            /* pArc */
53     NULL,                            /* pBitBlt */
54     NULL,                            /* pChord */
55     WIN16DRV_CreateDC,               /* pCreateDC */
56     NULL,                            /* pDeleteDC */
57     NULL,                            /* pDeleteObject */
58     WIN16DRV_Ellipse,                /* pEllipse */
59     WIN16DRV_EnumDeviceFonts,        /* pEnumDeviceFonts */
60     WIN16DRV_Escape,                 /* pEscape */
61     NULL,                            /* pExcludeClipRect */
62     NULL,                            /* pExcludeVisRect */
63     NULL,                            /* pExtFloodFill */
64     WIN16DRV_ExtTextOut,             /* pExtTextOut */
65     WIN16DRV_GetCharWidth,           /* pGetCharWidth */
66     NULL,                            /* pGetPixel */
67     WIN16DRV_GetTextExtentPoint,     /* pGetTextExtentPoint */
68     WIN16DRV_GetTextMetrics,         /* pGetTextMetrics */
69     NULL,                            /* pIntersectClipRect */
70     NULL,                            /* pIntersectVisRect */
71     WIN16DRV_LineTo,                 /* pLineTo */
72     WIN16DRV_MoveToEx,               /* pMoveToEx */
73     NULL,                            /* pOffsetClipRgn */
74     NULL,                            /* pOffsetViewportOrgEx */
75     NULL,                            /* pOffsetWindowOrgEx */
76     NULL,                            /* pPaintRgn */
77     WIN16DRV_PatBlt,                 /* pPatBlt */
78     NULL,                            /* pPie */
79     NULL,                            /* pPolyPolygon */
80     NULL,                            /* pPolyPolyline */
81     WIN16DRV_Polygon,                /* pPolygon */
82     WIN16DRV_Polyline,               /* pPolyline */
83     NULL,                            /* pPolyBezier */
84     NULL,                            /* pRealizePalette */
85     WIN16DRV_Rectangle,              /* pRectangle */
86     NULL,                            /* pRestoreDC */
87     NULL,                            /* pRoundRect */
88     NULL,                            /* pSaveDC */
89     NULL,                            /* pScaleViewportExtEx */
90     NULL,                            /* pScaleWindowExtEx */
91     NULL,                            /* pSelectClipRgn */
92     WIN16DRV_SelectObject,           /* pSelectObject */
93     NULL,                            /* pSelectPalette */
94     NULL,                            /* pSetBkColor */
95     NULL,                            /* pSetBkMode */
96     NULL,                            /* pSetDeviceClipping */
97     NULL,                            /* pSetDIBitsToDevice */
98     NULL,                            /* pSetMapMode */
99     NULL,                            /* pSetMapperFlags */
100     NULL,                            /* pSetPixel */
101     NULL,                            /* pSetPolyFillMode */
102     NULL,                            /* pSetROP2 */
103     NULL,                            /* pSetRelAbs */
104     NULL,                            /* pSetStretchBltMode */
105     NULL,                            /* pSetTextAlign */
106     NULL,                            /* pSetTextCharacterExtra */
107     NULL,                            /* pSetTextColor */
108     NULL,                            /* pSetTextJustification */
109     NULL,                            /* pSetViewportExtEx */
110     NULL,                            /* pSetViewportOrgEx */
111     NULL,                            /* pSetWindowExtEx */
112     NULL,                            /* pSetWindowOrgEx */
113     NULL,                            /* pStretchBlt */
114     NULL                             /* pStretchDIBits */
115 };
116
117
118
119
120
121 /**********************************************************************
122  *           WIN16DRV_Init
123  */
124 BOOL32 WIN16DRV_Init(void)
125 {
126     return DRIVER_RegisterDriver( NULL /* generic driver */, &WIN16DRV_Funcs );
127         
128 }
129
130 /* Tempory functions, for initialising structures */
131 /* These values should be calculated, not hardcoded */
132 void InitTextXForm(LPTEXTXFORM16 lpTextXForm)
133 {
134     lpTextXForm->txfHeight      = 0x0001;
135     lpTextXForm->txfWidth       = 0x000c;
136     lpTextXForm->txfEscapement  = 0x0000;
137     lpTextXForm->txfOrientation = 0x0000;
138     lpTextXForm->txfWeight      = 0x0190;
139     lpTextXForm->txfItalic      = 0x00;
140     lpTextXForm->txfUnderline   = 0x00;
141     lpTextXForm->txfStrikeOut   = 0x00; 
142     lpTextXForm->txfOutPrecision = 0x02;
143     lpTextXForm->txfClipPrecision = 0x01;
144     lpTextXForm->txfAccelerator = 0x0001;
145     lpTextXForm->txfOverhang    = 0x0000;
146 }
147
148
149 void InitDrawMode(LPDRAWMODE lpDrawMode)
150 {
151     lpDrawMode->Rop2            = 0x000d;       
152     lpDrawMode->bkMode          = 0x0001;     
153     lpDrawMode->bkColor         = 0x3fffffff;    
154     lpDrawMode->TextColor       = 0x20000000;  
155     lpDrawMode->TBreakExtra     = 0x0000;
156     lpDrawMode->BreakExtra      = 0x0000; 
157     lpDrawMode->BreakErr        = 0x0000;   
158     lpDrawMode->BreakRem        = 0x0000;   
159     lpDrawMode->BreakCount      = 0x0000; 
160     lpDrawMode->CharExtra       = 0x0000;  
161     lpDrawMode->LbkColor        = 0x00ffffff;   
162     lpDrawMode->LTextColor      = 0x00000000;     
163 }
164
165 BOOL32 WIN16DRV_CreateDC( DC *dc, LPCSTR driver, LPCSTR device, LPCSTR output,
166                           const DEVMODE16* initData )
167 {
168     LOADED_PRINTER_DRIVER *pLPD;
169     WORD wRet;
170     DeviceCaps *printerDevCaps;
171     int nPDEVICEsize;
172     PDEVICE_HEADER *pPDH;
173     WIN16DRV_PDEVICE *physDev;
174     char printerEnabled[20];
175     PROFILE_GetWineIniString( "wine", "printer", "off",
176                              printerEnabled, sizeof(printerEnabled) );
177     if (lstrcmpi32A(printerEnabled,"on"))
178     {
179         MSG("Printing disabled in wine.conf or .winerc file\n");
180         MSG("Use \"printer=on\" in the \"[wine]\" section to enable it.\n");
181         return FALSE;
182     }
183
184     TRACE(win16drv, "In creatdc for (%s,%s,%s) initData 0x%p\n",
185           driver, device, output, initData);
186
187     physDev = (WIN16DRV_PDEVICE *)HeapAlloc( SystemHeap, 0, sizeof(*physDev) );
188     if (!physDev) return FALSE;
189     dc->physDev = physDev;
190
191     pLPD = LoadPrinterDriver(driver);
192     if (pLPD == NULL)
193     {
194         WARN(win16drv, "Failed to find printer driver\n");
195         HeapFree( SystemHeap, 0, physDev );
196         return FALSE;
197     }
198     TRACE(win16drv, "windevCreateDC pLPD 0x%p\n", pLPD);
199
200     /* Now Get the device capabilities from the printer driver */
201     
202     printerDevCaps = (DeviceCaps *) malloc(sizeof(DeviceCaps));
203     memset(printerDevCaps, 0, sizeof(DeviceCaps));
204
205     /* Get GDIINFO which is the same as a DeviceCaps structure */
206     wRet = PRTDRV_Enable(printerDevCaps, GETGDIINFO, device, driver, output,NULL); 
207
208     /* Add this to the DC */
209     dc->w.devCaps = printerDevCaps;
210     dc->w.hVisRgn = CreateRectRgn32(0, 0, dc->w.devCaps->horzRes, dc->w.devCaps->vertRes);
211     dc->w.bitsPerPixel = dc->w.devCaps->bitsPixel;
212     
213     TRACE(win16drv, "Got devcaps width %d height %d bits %d planes %d\n",
214           dc->w.devCaps->horzRes, dc->w.devCaps->vertRes, 
215           dc->w.devCaps->bitsPixel, dc->w.devCaps->planes);
216
217     /* Now we allocate enough memory for the PDEVICE structure */
218     /* The size of this varies between printer drivers */
219     /* This PDEVICE is used by the printer DRIVER not by the GDI so must */
220     /* be accessable from 16 bit code */
221     nPDEVICEsize = dc->w.devCaps->pdeviceSize + sizeof(PDEVICE_HEADER);
222
223     /* TTD Shouldn't really do pointer arithmetic on segment points */
224     physDev->segptrPDEVICE = WIN16_GlobalLock16(GlobalAlloc16(GHND, nPDEVICEsize))+sizeof(PDEVICE_HEADER);
225     *((BYTE *)PTR_SEG_TO_LIN(physDev->segptrPDEVICE)+0) = 'N'; 
226     *((BYTE *)PTR_SEG_TO_LIN(physDev->segptrPDEVICE)+1) = 'B'; 
227
228     /* Set up the header */
229     pPDH = (PDEVICE_HEADER *)((BYTE*)PTR_SEG_TO_LIN(physDev->segptrPDEVICE) - sizeof(PDEVICE_HEADER)); 
230     pPDH->pLPD = pLPD;
231     
232     TRACE(win16drv, "PDEVICE allocated %08lx\n",(DWORD)(physDev->segptrPDEVICE));
233     
234     /* Now get the printer driver to initialise this data */
235     wRet = PRTDRV_Enable((LPVOID)physDev->segptrPDEVICE, INITPDEVICE, device, driver, output, NULL); 
236
237     physDev->FontInfo = NULL;
238     physDev->BrushInfo = NULL;
239     physDev->PenInfo = NULL;
240     win16drv_SegPtr_TextXForm = WIN16_GlobalLock16(GlobalAlloc16(GHND, sizeof(TEXTXFORM16)));
241     win16drv_TextXFormP = PTR_SEG_TO_LIN(win16drv_SegPtr_TextXForm);
242     
243     InitTextXForm(win16drv_TextXFormP);
244
245     /* TTD Lots more to do here */
246     win16drv_SegPtr_DrawMode = WIN16_GlobalLock16(GlobalAlloc16(GHND, sizeof(DRAWMODE)));
247     win16drv_DrawModeP = PTR_SEG_TO_LIN(win16drv_SegPtr_DrawMode);
248     
249     InitDrawMode(win16drv_DrawModeP);
250
251     return TRUE;
252 }
253
254 BOOL32 WIN16DRV_PatBlt( struct tagDC *dc, INT32 left, INT32 top,
255                         INT32 width, INT32 height, DWORD rop )
256 {
257   
258     WIN16DRV_PDEVICE *physDev = (WIN16DRV_PDEVICE *)dc->physDev;
259     BOOL32 bRet = 0;
260
261     bRet = PRTDRV_StretchBlt( physDev->segptrPDEVICE, left, top, width, height, (SEGPTR)NULL, 0, 0, width, height,
262                        PATCOPY, physDev->BrushInfo, win16drv_SegPtr_DrawMode, NULL);
263
264     return bRet;
265 }
266 /* 
267  * Escape (GDI.38)
268  */
269 static INT32 WIN16DRV_Escape( DC *dc, INT32 nEscape, INT32 cbInput, 
270                               SEGPTR lpInData, SEGPTR lpOutData )
271 {
272     WIN16DRV_PDEVICE *physDev = (WIN16DRV_PDEVICE *)dc->physDev;
273     int nRet = 0;
274
275     /* We should really process the nEscape parameter, but for now just
276        pass it all to the driver */
277     if (dc != NULL && physDev->segptrPDEVICE != 0)
278     {
279         switch(nEscape)
280           {
281           case ENABLEPAIRKERNING:
282             FIXME(win16drv,"Escape: ENABLEPAIRKERNING ignored.\n");
283             nRet = 1;
284             break;
285           case GETPAIRKERNTABLE:
286             FIXME(win16drv,"Escape: GETPAIRKERNTABLE ignored.\n");
287             nRet = 0;
288             break;
289           case SETABORTPROC:
290                 /* FIXME: The AbortProc should be called:
291                 - After every write to printer port or spool file
292                 - Several times when no more disk space
293                 - Before every metafile record when GDI does banding
294                 */ 
295 /*          dc->w.lpfnPrint = (FARPROC16)lpInData; FIXME! */
296             nRet = 1;
297             break;
298
299           case NEXTBAND:
300             {
301               LPPOINT16 newInData =  SEGPTR_NEW(POINT16);
302
303               nRet = PRTDRV_Control(physDev->segptrPDEVICE, nEscape,
304                                     SEGPTR_GET(newInData), lpOutData);
305               SEGPTR_FREE(newInData);
306               break;
307             }
308
309           case GETEXTENDEDTEXTMETRICS:
310             {
311               EXTTEXTDATA *textData = SEGPTR_NEW(EXTTEXTDATA);
312
313               textData->nSize = cbInput;
314               textData->lpindata = lpInData;
315               textData->lpFont = SEGPTR_GET( physDev->FontInfo );
316               textData->lpXForm = win16drv_SegPtr_TextXForm;
317               textData->lpDrawMode = win16drv_SegPtr_DrawMode;
318               nRet = PRTDRV_Control(physDev->segptrPDEVICE, nEscape,
319                                     SEGPTR_GET(textData), lpOutData);
320               SEGPTR_FREE(textData);
321             }
322           break;
323           case STARTDOC:
324             nRet = PRTDRV_Control(physDev->segptrPDEVICE, nEscape,
325                                   lpInData, lpOutData);
326             if (nRet != -1)
327             {
328               HDC32 *tmpHdc = SEGPTR_NEW(HDC32);
329
330 #define SETPRINTERDC SETABORTPROC
331
332               *tmpHdc = dc->hSelf;
333               PRTDRV_Control(physDev->segptrPDEVICE, SETPRINTERDC,
334                              SEGPTR_GET(tmpHdc), (SEGPTR)NULL);
335               SEGPTR_FREE(tmpHdc);
336             }
337             break;
338           default:
339             nRet = PRTDRV_Control(physDev->segptrPDEVICE, nEscape,
340                                   lpInData, lpOutData);
341             break;
342         }
343     }
344     else
345         WARN(win16drv, "Escape(nEscape = %04x) - ???\n", nEscape);      
346     return nRet;
347 }
348
349
350 /**********************************************************************
351  *           QueryAbort   (GDI.155)
352  *
353  *  Calls the app's AbortProc function if avail.
354  *
355  * RETURNS
356  * TRUE if no AbortProc avail or AbortProc wants to continue printing.
357  * FALSE if AbortProc wants to abort printing.
358  */
359 BOOL16 WINAPI QueryAbort(HDC16 hdc, INT16 reserved)
360 {
361     DC *dc = DC_GetDCPtr( hdc );
362
363     if ((!dc) || (!dc->w.lpfnPrint))
364         return TRUE;
365     return dc->w.lpfnPrint(hdc, 0);
366 }
367
368 /**********************************************************************
369  *           SetAbortProc   (GDI.381)
370  *
371  */
372 INT16 WINAPI SetAbortProc(HDC16 hdc, FARPROC16 abrtprc)
373 {
374     DC *dc = DC_GetDCPtr( hdc );
375
376     if (dc) {
377         dc->w.lpfnPrint = abrtprc;
378         return 1;
379     }
380     return -1;
381
382
383 /****************** misc. printer related functions */
384
385 /*
386  * The following function should implement a queing system
387  */
388 #ifndef HPQ 
389 #define HPQ WORD
390 #endif
391 struct hpq 
392 {
393     struct hpq  *next;
394     int          tag;
395     int          key;
396 };
397
398 static struct hpq *hpqueue;
399
400 HPQ WINAPI CreatePQ(int size) 
401 {
402 #if 0
403     HGLOBAL16 hpq = 0;
404     WORD tmp_size;
405     LPWORD pPQ;
406
407     tmp_size = size << 2;
408     if (!(hpq = GlobalAlloc16(GMEM_SHARE|GMEM_MOVEABLE, tmp_size + 8)))
409        return 0xffff;
410     pPQ = GlobalLock16(hpq);
411     *pPQ++ = 0;
412     *pPQ++ = tmp_size;
413     *pPQ++ = 0;
414     *pPQ++ = 0;
415     GlobalUnlock16(hpq);
416
417     return (HPQ)hpq;
418 #else
419     FIXME(win16drv, "(%d): stub\n",size);
420     return 1;
421 #endif
422 }
423
424 int WINAPI DeletePQ(HPQ hPQ) 
425 {
426     return GlobalFree16((HGLOBAL16)hPQ);
427 }
428
429 int WINAPI ExtractPQ(HPQ hPQ) 
430
431     struct hpq *queue, *prev, *current, *currentPrev;
432     int key = 0, tag = -1;
433     currentPrev = prev = NULL;
434     queue = current = hpqueue;
435     if (current)
436         key = current->key;
437     
438     while (current)
439     {
440         currentPrev = current;
441         current = current->next;
442         if (current)
443         {
444             if (current->key < key)
445             {
446                 queue = current;
447                 prev = currentPrev;
448             }
449         }
450     }
451     if (queue)
452     {
453         tag = queue->tag;
454         
455         if (prev)
456             prev->next = queue->next;
457         else
458             hpqueue = queue->next;
459         free(queue);
460     }
461     
462     TRACE(win16drv, "%x got tag %d key %d\n", hPQ, tag, key); 
463
464     return tag;
465 }
466
467 int WINAPI InsertPQ(HPQ hPQ, int tag, int key) 
468 {
469     struct hpq *queueItem = malloc(sizeof(struct hpq));
470     queueItem->next = hpqueue;
471     hpqueue = queueItem;
472     queueItem->key = key;
473     queueItem->tag = tag;
474     
475     FIXME(win16drv, "(%x %d %d): stub???\n", hPQ, tag, key);
476     return TRUE;
477 }
478 int WINAPI MinPQ(HPQ hPQ) 
479 {
480     FIXME(win16drv, "(%x): stub\n", hPQ); 
481     return 0;
482 }
483 int WINAPI SizePQ(HPQ hPQ, int sizechange) 
484 {  
485     FIXME(win16drv, "(%x %d): stub\n", hPQ, sizechange); 
486     return -1; 
487 }
488
489 /* 
490  * The following functions implement part of the spooling process to 
491  * print manager.  I would like to see wine have a version of print managers
492  * that used LPR/LPD.  For simplicity print jobs will be sent to a file for
493  * now.
494  */
495 typedef struct PRINTJOB
496 {
497     char        *pszOutput;
498     char        *pszTitle;
499     HDC16       hDC;
500     HANDLE16    hHandle;
501     int         nIndex;
502     int         fd;
503 } PRINTJOB, *PPRINTJOB;
504
505 #define MAX_PRINT_JOBS 1
506 #define SP_OK 1
507
508 PPRINTJOB gPrintJobsTable[MAX_PRINT_JOBS];
509
510
511 static PPRINTJOB FindPrintJobFromHandle(HANDLE16 hHandle)
512 {
513     return gPrintJobsTable[0];
514 }
515
516 /* TTD Need to do some DOS->UNIX file conversion here */
517 static int CreateSpoolFile(LPSTR pszOutput)
518 {
519     int fd=-1;
520     char psCmd[1024];
521     char *psCmdP = psCmd;
522
523     /* TTD convert the 'output device' into a spool file name */
524
525     if (pszOutput == NULL || *pszOutput == '\0')
526       return -1;
527
528     PROFILE_GetWineIniString( "spooler", pszOutput, "", psCmd, sizeof(psCmd) );
529     TRACE(win16drv, "Got printerSpoolCommand '%s' for output device '%s'\n",
530           psCmd, pszOutput);
531     if (!*psCmd)
532         psCmdP = pszOutput;
533     else
534     {
535         while (*psCmdP && isspace(*psCmdP))
536         {
537             psCmdP++;
538         };
539         if (!*psCmdP)
540             return -1;
541     }
542     if (*psCmdP == '|')
543     {
544         int fds[2];
545         if (pipe(fds))
546             return -1;
547         if (fork() == 0)
548         {
549             psCmdP++;
550
551             TRACE(win16drv, "In child need to exec %s\n",psCmdP);
552             close(0);
553             dup2(fds[0],0);
554             close (fds[1]);
555             system(psCmdP);
556             exit(0);
557             
558         }
559         close (fds[0]);
560         fd = fds[1];
561         TRACE(win16drv,"Need to execute a cmnd and pipe the output to it\n");
562     }
563     else
564     {
565         TRACE(win16drv, "Just assume its a file\n");
566
567         if ((fd = open(psCmdP, O_CREAT | O_TRUNC | O_WRONLY , 0600)) < 0)
568         {
569             ERR(win16drv, "Failed to create spool file %s, errno = %d\n", 
570                 psCmdP, errno);
571         }
572     }
573     return fd;
574 }
575
576 static int FreePrintJob(HANDLE16 hJob)
577 {
578     int nRet = SP_ERROR;
579     PPRINTJOB pPrintJob;
580
581     pPrintJob = FindPrintJobFromHandle(hJob);
582     if (pPrintJob != NULL)
583     {
584         gPrintJobsTable[pPrintJob->nIndex] = NULL;
585         free(pPrintJob->pszOutput);
586         free(pPrintJob->pszTitle);
587         if (pPrintJob->fd >= 0) close(pPrintJob->fd);
588         free(pPrintJob);
589         nRet = SP_OK;
590     }
591     return nRet;
592 }
593
594 HANDLE16 WINAPI OpenJob(LPSTR lpOutput, LPSTR lpTitle, HDC16 hDC)
595 {
596     HANDLE16 hHandle = (HANDLE16)SP_ERROR;
597     PPRINTJOB pPrintJob;
598
599     TRACE(win16drv, "'%s' '%s' %04x\n", lpOutput, lpTitle, hDC);
600
601     pPrintJob = gPrintJobsTable[0];
602     if (pPrintJob == NULL)
603     {
604         int fd;
605
606         /* Try an create a spool file */
607         fd = CreateSpoolFile(lpOutput);
608         if (fd >= 0)
609         {
610             hHandle = 1;
611
612             pPrintJob = malloc(sizeof(PRINTJOB));
613             memset(pPrintJob, 0, sizeof(PRINTJOB));
614
615             pPrintJob->pszOutput = strdup(lpOutput);
616             if(lpTitle)
617                 pPrintJob->pszTitle = strdup(lpTitle);
618             pPrintJob->hDC = hDC;
619             pPrintJob->fd = fd;
620             pPrintJob->nIndex = 0;
621             pPrintJob->hHandle = hHandle; 
622             gPrintJobsTable[pPrintJob->nIndex] = pPrintJob; 
623         }
624     }
625     TRACE(win16drv, "return %04x\n", hHandle);
626     return hHandle;
627 }
628
629 int WINAPI CloseJob(HANDLE16 hJob)
630 {
631     int nRet = SP_ERROR;
632     PPRINTJOB pPrintJob = NULL;
633
634     TRACE(win16drv, "%04x\n", hJob);
635
636     pPrintJob = FindPrintJobFromHandle(hJob);
637     if (pPrintJob != NULL)
638     {
639         /* Close the spool file */
640         close(pPrintJob->fd);
641         FreePrintJob(hJob);
642         nRet  = 1;
643     }
644     return nRet;
645 }
646
647 int WINAPI WriteSpool(HANDLE16 hJob, LPSTR lpData, WORD cch)
648 {
649     int nRet = SP_ERROR;
650     PPRINTJOB pPrintJob = NULL;
651
652     TRACE(win16drv, "%04x %08lx %04x\n", hJob, (DWORD)lpData, cch);
653
654     pPrintJob = FindPrintJobFromHandle(hJob);
655     if (pPrintJob != NULL && pPrintJob->fd >= 0 && cch)
656     {
657         if (write(pPrintJob->fd, lpData, cch) != cch)
658           nRet = SP_OUTOFDISK;
659         else
660           nRet = cch;
661         if (pPrintJob->hDC == 0) {
662             ERR(print, "hDC == 0 !\n");
663             return SP_ERROR;
664         }
665         if (!(QueryAbort(pPrintJob->hDC, (nRet == SP_OUTOFDISK) ? nRet : 0 )))
666         {
667             CloseJob(hJob); /* printing aborted */
668             nRet = SP_APPABORT;
669         }
670     }
671     return nRet;
672 }
673
674 int WINAPI WriteDialog(HANDLE16 hJob, LPSTR lpMsg, WORD cchMsg)
675 {
676     int nRet = 0;
677
678     TRACE(win16drv, "%04x %04x '%s'\n", hJob,  cchMsg, lpMsg);
679
680     nRet = MessageBox16(0, lpMsg, "Printing Error", MB_OKCANCEL);
681     return nRet;
682 }
683
684 int WINAPI DeleteJob(HANDLE16 hJob, WORD wNotUsed)
685 {
686     int nRet;
687
688     TRACE(win16drv, "%04x\n", hJob);
689
690     nRet = FreePrintJob(hJob);
691     return nRet;
692 }
693
694 /* 
695  * The following two function would allow a page to be sent to the printer
696  * when it has been processed.  For simplicity they havn't been implemented.
697  * This means a whole job has to be processed before it is sent to the printer.
698  */
699 int WINAPI StartSpoolPage(HANDLE16 hJob)
700 {
701     FIXME(win16drv, "StartSpoolPage GDI.246 unimplemented\n");
702     return 1;
703
704 }
705 int WINAPI EndSpoolPage(HANDLE16 hJob)
706 {
707     FIXME(win16drv, "EndSpoolPage GDI.247 unimplemented\n");
708     return 1;
709 }
710
711
712 DWORD WINAPI GetSpoolJob(int nOption, LONG param)
713 {
714     DWORD retval = 0;
715     TRACE(win16drv, "In GetSpoolJob param 0x%lx noption %d\n",param, nOption);
716     return retval;
717 }