2 * Implementation of some printer driver bits
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Huw Davies
6 * Copyright 1998 Andreas Mohr
7 * Copyright 1999 Klaas van Gend
18 #include "wine/wingdi16.h"
22 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(print
)
32 static char PrinterModel
[] = "Printer Model";
33 static char DefaultDevMode
[] = "Default DevMode";
34 static char PrinterDriverData
[] = "PrinterDriverData";
35 static char Printers
[] = "System\\CurrentControlSet\\Control\\Print\\Printers\\";
37 /******************************************************************
38 * StartDoc16 [GDI.377]
41 INT16 WINAPI
StartDoc16( HDC16 hdc
, const DOCINFO16
*lpdoc
)
45 docA
.cbSize
= lpdoc
->cbSize
;
46 docA
.lpszDocName
= PTR_SEG_TO_LIN(lpdoc
->lpszDocName
);
47 docA
.lpszOutput
= PTR_SEG_TO_LIN(lpdoc
->lpszOutput
);
49 if(lpdoc
->cbSize
>= 14)
50 docA
.lpszDatatype
= PTR_SEG_TO_LIN(lpdoc
->lpszDatatype
);
52 docA
.lpszDatatype
= NULL
;
54 if(lpdoc
->cbSize
>= 18)
55 docA
.fwType
= lpdoc
->fwType
;
59 return StartDocA(hdc
, &docA
);
62 /******************************************************************
63 * StartDocA [GDI32.347]
65 * StartDoc calls the STARTDOC Escape with the input data pointing to DocName
66 * and the output data (which is used as a second input parameter).pointing at
67 * the whole docinfo structure. This seems to be an undocumented feature of
68 * the STARTDOC Escape.
70 INT WINAPI
StartDocA(HDC hdc
, const DOCINFOA
* doc
)
72 DC
*dc
= DC_GetDCPtr( hdc
);
74 TRACE("DocName = '%s' Output = '%s' Datatype = '%s'\n",
75 doc
->lpszDocName
, doc
->lpszOutput
, doc
->lpszDatatype
);
79 if(dc
->funcs
->pStartDoc
)
80 return dc
->funcs
->pStartDoc( dc
, doc
);
82 return Escape(hdc
, STARTDOC
, strlen(doc
->lpszDocName
),
83 doc
->lpszDocName
, (LPVOID
)doc
);
86 /*************************************************************************
87 * StartDocW [GDI32.348]
90 INT WINAPI
StartDocW(HDC hdc
, const DOCINFOW
* doc
)
95 docA
.cbSize
= doc
->cbSize
;
96 docA
.lpszDocName
= doc
->lpszDocName
?
97 HEAP_strdupWtoA( GetProcessHeap(), 0, doc
->lpszDocName
) : NULL
;
98 docA
.lpszOutput
= doc
->lpszOutput
?
99 HEAP_strdupWtoA( GetProcessHeap(), 0, doc
->lpszOutput
) : NULL
;
100 docA
.lpszDatatype
= doc
->lpszDatatype
?
101 HEAP_strdupWtoA( GetProcessHeap(), 0, doc
->lpszDatatype
) : NULL
;
102 docA
.fwType
= doc
->fwType
;
104 ret
= StartDocA(hdc
, &docA
);
107 HeapFree( GetProcessHeap(), 0, (LPSTR
)docA
.lpszDocName
);
109 HeapFree( GetProcessHeap(), 0, (LPSTR
)docA
.lpszOutput
);
110 if(docA
.lpszDatatype
)
111 HeapFree( GetProcessHeap(), 0, (LPSTR
)docA
.lpszDatatype
);
116 /******************************************************************
120 INT16 WINAPI
EndDoc16(HDC16 hdc
)
125 /******************************************************************
129 INT WINAPI
EndDoc(HDC hdc
)
131 DC
*dc
= DC_GetDCPtr( hdc
);
134 if(dc
->funcs
->pEndDoc
)
135 return dc
->funcs
->pEndDoc( dc
);
137 return Escape(hdc
, ENDDOC
, 0, 0, 0);
140 /******************************************************************
141 * StartPage16 [GDI.379]
144 INT16 WINAPI
StartPage16(HDC16 hdc
)
146 return StartPage(hdc
);
149 /******************************************************************
150 * StartPage [GDI32.349]
153 INT WINAPI
StartPage(HDC hdc
)
155 DC
*dc
= DC_GetDCPtr( hdc
);
158 if(dc
->funcs
->pStartPage
)
159 return dc
->funcs
->pStartPage( dc
);
165 /******************************************************************
166 * EndPage16 [GDI.380]
169 INT16 WINAPI
EndPage16( HDC16 hdc
)
174 /******************************************************************
178 INT WINAPI
EndPage(HDC hdc
)
180 DC
*dc
= DC_GetDCPtr( hdc
);
183 if(dc
->funcs
->pEndPage
)
184 return dc
->funcs
->pEndPage( dc
);
186 return Escape(hdc
, NEWFRAME
, 0, 0, 0);
189 /******************************************************************************
190 * AbortDoc16 [GDI.382]
192 INT16 WINAPI
AbortDoc16(HDC16 hdc
)
194 return AbortDoc(hdc
);
197 /******************************************************************************
198 * AbortDoc [GDI32.105]
200 INT WINAPI
AbortDoc(HDC hdc
)
202 DC
*dc
= DC_GetDCPtr( hdc
);
205 if(dc
->funcs
->pAbortDoc
)
206 return dc
->funcs
->pAbortDoc( dc
);
208 return Escape(hdc
, ABORTDOC
, 0, 0, 0);
211 /**********************************************************************
212 * QueryAbort16 (GDI.155)
214 * Calls the app's AbortProc function if avail.
217 * TRUE if no AbortProc avail or AbortProc wants to continue printing.
218 * FALSE if AbortProc wants to abort printing.
220 BOOL16 WINAPI
QueryAbort16(HDC16 hdc
, INT16 reserved
)
222 DC
*dc
= DC_GetDCPtr( hdc
);
225 ERR("Invalid hdc %04x\n", hdc
);
229 if(!dc
->w
.pAbortProc
)
231 return dc
->w
.pAbortProc(hdc
, 0);
234 /* ### start build ### */
235 extern WORD CALLBACK
PRTDRV_CallTo16_word_ww(FARPROC16
,WORD
,WORD
);
236 /* ### stop build ### */
238 /**********************************************************************
239 * SetAbortProc16 (GDI.381)
242 INT16 WINAPI
SetAbortProc16(HDC16 hdc
, SEGPTR abrtprc
)
244 ABORTPROC proc32
= (ABORTPROC
)THUNK_Alloc((FARPROC16
)abrtprc
,
245 (RELAY
)PRTDRV_CallTo16_word_ww
);
246 return SetAbortProc(hdc
, proc32
);
249 /**********************************************************************
250 * SetAbortProc32 (GDI32.301)
253 INT WINAPI
SetAbortProc(HDC hdc
, ABORTPROC abrtprc
)
255 DC
*dc
= DC_GetDCPtr( hdc
);
257 if(dc
->w
.pAbortProc
) THUNK_Free((FARPROC
)dc
->w
.pAbortProc
);
258 dc
->w
.pAbortProc
= abrtprc
;
263 /****************** misc. printer related functions */
266 * The following function should implement a queing system
275 static struct hpq
*hpqueue
;
277 /**********************************************************************
281 HPQ16 WINAPI
CreatePQ16(INT16 size
)
288 tmp_size
= size
<< 2;
289 if (!(hpq
= GlobalAlloc16(GMEM_SHARE
|GMEM_MOVEABLE
, tmp_size
+ 8)))
291 pPQ
= GlobalLock16(hpq
);
300 FIXME("(%d): stub\n",size
);
305 /**********************************************************************
309 INT16 WINAPI
DeletePQ16(HPQ16 hPQ
)
311 return GlobalFree16((HGLOBAL16
)hPQ
);
314 /**********************************************************************
315 * ExtractPQ (GDI.232)
318 INT16 WINAPI
ExtractPQ16(HPQ16 hPQ
)
320 struct hpq
*queue
, *prev
, *current
, *currentPrev
;
321 int key
= 0, tag
= -1;
322 currentPrev
= prev
= NULL
;
323 queue
= current
= hpqueue
;
329 currentPrev
= current
;
330 current
= current
->next
;
333 if (current
->key
< key
)
345 prev
->next
= queue
->next
;
347 hpqueue
= queue
->next
;
351 TRACE("%x got tag %d key %d\n", hPQ
, tag
, key
);
356 /**********************************************************************
360 INT16 WINAPI
InsertPQ16(HPQ16 hPQ
, INT16 tag
, INT16 key
)
362 struct hpq
*queueItem
= xmalloc(sizeof(struct hpq
));
363 queueItem
->next
= hpqueue
;
365 queueItem
->key
= key
;
366 queueItem
->tag
= tag
;
368 FIXME("(%x %d %d): stub???\n", hPQ
, tag
, key
);
372 /**********************************************************************
376 INT16 WINAPI
MinPQ16(HPQ16 hPQ
)
378 FIXME("(%x): stub\n", hPQ
);
382 /**********************************************************************
386 INT16 WINAPI
SizePQ16(HPQ16 hPQ
, INT16 sizechange
)
388 FIXME("(%x %d): stub\n", hPQ
, sizechange
);
395 * The following functions implement part of the spooling process to
396 * print manager. I would like to see wine have a version of print managers
397 * that used LPR/LPD. For simplicity print jobs will be sent to a file for
400 typedef struct PRINTJOB
408 } PRINTJOB
, *PPRINTJOB
;
410 #define MAX_PRINT_JOBS 1
413 PPRINTJOB gPrintJobsTable
[MAX_PRINT_JOBS
];
416 static PPRINTJOB
FindPrintJobFromHandle(HANDLE16 hHandle
)
418 return gPrintJobsTable
[0];
421 /* TTD Need to do some DOS->UNIX file conversion here */
422 static int CreateSpoolFile(LPCSTR pszOutput
)
426 char *psCmdP
= psCmd
;
428 /* TTD convert the 'output device' into a spool file name */
430 if (pszOutput
== NULL
|| *pszOutput
== '\0')
433 PROFILE_GetWineIniString( "spooler", pszOutput
, "", psCmd
, sizeof(psCmd
) );
434 TRACE("Got printerSpoolCommand '%s' for output device '%s'\n",
437 psCmdP
= (char *)pszOutput
;
440 while (*psCmdP
&& isspace(*psCmdP
))
456 TRACE("In child need to exec %s\n",psCmdP
);
466 TRACE("Need to execute a cmnd and pipe the output to it\n");
470 TRACE("Just assume its a file\n");
472 if ((fd
= open(psCmdP
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0600)) < 0)
474 ERR("Failed to create spool file %s, errno = %d\n",
481 static int FreePrintJob(HANDLE16 hJob
)
486 pPrintJob
= FindPrintJobFromHandle(hJob
);
487 if (pPrintJob
!= NULL
)
489 gPrintJobsTable
[pPrintJob
->nIndex
] = NULL
;
490 free(pPrintJob
->pszOutput
);
491 free(pPrintJob
->pszTitle
);
492 if (pPrintJob
->fd
>= 0) close(pPrintJob
->fd
);
499 /**********************************************************************
503 HPJOB16 WINAPI
OpenJob16(LPCSTR lpOutput
, LPCSTR lpTitle
, HDC16 hDC
)
505 HPJOB16 hHandle
= (HPJOB16
)SP_ERROR
;
508 TRACE("'%s' '%s' %04x\n", lpOutput
, lpTitle
, hDC
);
510 pPrintJob
= gPrintJobsTable
[0];
511 if (pPrintJob
== NULL
)
515 /* Try an create a spool file */
516 fd
= CreateSpoolFile(lpOutput
);
521 pPrintJob
= xmalloc(sizeof(PRINTJOB
));
522 memset(pPrintJob
, 0, sizeof(PRINTJOB
));
524 pPrintJob
->pszOutput
= strdup(lpOutput
);
526 pPrintJob
->pszTitle
= strdup(lpTitle
);
527 pPrintJob
->hDC
= hDC
;
529 pPrintJob
->nIndex
= 0;
530 pPrintJob
->hHandle
= hHandle
;
531 gPrintJobsTable
[pPrintJob
->nIndex
] = pPrintJob
;
534 TRACE("return %04x\n", hHandle
);
538 /**********************************************************************
542 INT16 WINAPI
CloseJob16(HPJOB16 hJob
)
545 PPRINTJOB pPrintJob
= NULL
;
547 TRACE("%04x\n", hJob
);
549 pPrintJob
= FindPrintJobFromHandle(hJob
);
550 if (pPrintJob
!= NULL
)
552 /* Close the spool file */
553 close(pPrintJob
->fd
);
560 /**********************************************************************
561 * WriteSpool (GDI.241)
564 INT16 WINAPI
WriteSpool16(HPJOB16 hJob
, LPSTR lpData
, INT16 cch
)
567 PPRINTJOB pPrintJob
= NULL
;
569 TRACE("%04x %08lx %04x\n", hJob
, (DWORD
)lpData
, cch
);
571 pPrintJob
= FindPrintJobFromHandle(hJob
);
572 if (pPrintJob
!= NULL
&& pPrintJob
->fd
>= 0 && cch
)
574 if (write(pPrintJob
->fd
, lpData
, cch
) != cch
)
578 if (pPrintJob
->hDC
== 0) {
579 TRACE("hDC == 0 so no QueryAbort\n");
581 else if (!(QueryAbort16(pPrintJob
->hDC
, (nRet
== SP_OUTOFDISK
) ? nRet
: 0 )))
583 CloseJob16(hJob
); /* printing aborted */
590 /**********************************************************************
591 * WriteDialog (GDI.242)
594 INT16 WINAPI
WriteDialog16(HPJOB16 hJob
, LPSTR lpMsg
, INT16 cchMsg
)
598 TRACE("%04x %04x '%s'\n", hJob
, cchMsg
, lpMsg
);
600 nRet
= MessageBox16(0, lpMsg
, "Printing Error", MB_OKCANCEL
);
605 /**********************************************************************
606 * DeleteJob (GDI.244)
609 INT16 WINAPI
DeleteJob16(HPJOB16 hJob
, INT16 nNotUsed
)
613 TRACE("%04x\n", hJob
);
615 nRet
= FreePrintJob(hJob
);
620 * The following two function would allow a page to be sent to the printer
621 * when it has been processed. For simplicity they havn't been implemented.
622 * This means a whole job has to be processed before it is sent to the printer.
625 /**********************************************************************
626 * StartSpoolPage (GDI.246)
629 INT16 WINAPI
StartSpoolPage16(HPJOB16 hJob
)
631 FIXME("StartSpoolPage GDI.246 unimplemented\n");
637 /**********************************************************************
638 * EndSpoolPage (GDI.247)
641 INT16 WINAPI
EndSpoolPage16(HPJOB16 hJob
)
643 FIXME("EndSpoolPage GDI.247 unimplemented\n");
648 /**********************************************************************
649 * GetSpoolJob (GDI.245)
652 DWORD WINAPI
GetSpoolJob16(int nOption
, LONG param
)
655 TRACE("In GetSpoolJob param 0x%lx noption %d\n",param
, nOption
);
660 /******************************************************************
661 * DrvGetPrinterDataInternal
663 * Helper for DrvGetPrinterData
665 static DWORD
DrvGetPrinterDataInternal(LPSTR RegStr_Printer
,
666 LPBYTE lpPrinterData
, int cbData
, int what
)
670 DWORD dwType
, cbQueryData
;
672 if (!(RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
))) {
673 if (what
== INT_PD_DEFAULT_DEVMODE
) { /* "Default DevMode" */
674 if (!(RegQueryValueExA(hkey
, DefaultDevMode
, 0, &dwType
, 0, &cbQueryData
))) {
677 else if ((cbQueryData
) && (cbQueryData
<= cbData
)) {
678 cbQueryData
= cbData
;
679 if (RegQueryValueExA(hkey
, DefaultDevMode
, 0,
680 &dwType
, lpPrinterData
, &cbQueryData
))
684 } else { /* "Printer Driver" */
686 RegQueryValueExA(hkey
, "Printer Driver", 0,
687 &dwType
, lpPrinterData
, &cbQueryData
);
691 if (hkey
) RegCloseKey(hkey
);
695 /******************************************************************
696 * DrvGetPrinterData [GDI.282]
699 DWORD WINAPI
DrvGetPrinterData16(LPSTR lpPrinter
, LPSTR lpProfile
,
700 LPDWORD lpType
, LPBYTE lpPrinterData
,
701 int cbData
, LPDWORD lpNeeded
)
703 LPSTR RegStr_Printer
;
704 HKEY hkey
= 0, hkey2
= 0;
706 DWORD dwType
, PrinterAttr
, cbPrinterAttr
, SetData
, size
;
708 if (HIWORD(lpPrinter
))
709 TRACE("printer %s\n",lpPrinter
);
711 TRACE("printer %p\n",lpPrinter
);
712 if (HIWORD(lpProfile
))
713 TRACE("profile %s\n",lpProfile
);
715 TRACE("profile %p\n",lpProfile
);
716 TRACE("lpType %p\n",lpType
);
718 if ((!lpPrinter
) || (!lpProfile
) || (!lpNeeded
))
719 return ERROR_INVALID_PARAMETER
;
721 RegStr_Printer
= HeapAlloc(GetProcessHeap(), 0,
722 strlen(Printers
) + strlen(lpPrinter
) + 2);
723 strcpy(RegStr_Printer
, Printers
);
724 strcat(RegStr_Printer
, lpPrinter
);
726 if (((DWORD
)lpProfile
== INT_PD_DEFAULT_DEVMODE
) || (HIWORD(lpProfile
) &&
727 (!strcmp(lpProfile
, DefaultDevMode
)))) {
728 size
= DrvGetPrinterDataInternal(RegStr_Printer
, lpPrinterData
, cbData
,
729 INT_PD_DEFAULT_DEVMODE
);
732 if ((lpPrinterData
) && (*lpNeeded
> cbData
))
733 res
= ERROR_MORE_DATA
;
735 else res
= ERROR_INVALID_PRINTER_NAME
;
738 if (((DWORD
)lpProfile
== INT_PD_DEFAULT_MODEL
) || (HIWORD(lpProfile
) &&
739 (!strcmp(lpProfile
, PrinterModel
)))) {
741 if (!lpPrinterData
) goto failed
;
743 res
= ERROR_MORE_DATA
;
746 size
= DrvGetPrinterDataInternal(RegStr_Printer
, lpPrinterData
, cbData
,
747 INT_PD_DEFAULT_MODEL
);
748 if ((size
+1) && (lpType
))
751 res
= ERROR_INVALID_PRINTER_NAME
;
755 if ((res
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
)))
758 if ((res
= RegQueryValueExA(hkey
, "Attributes", 0,
759 &dwType
, (LPBYTE
)&PrinterAttr
, &cbPrinterAttr
)))
761 if ((res
= RegOpenKeyA(hkey
, PrinterDriverData
, &hkey2
)))
764 res
= RegQueryValueExA(hkey2
, lpProfile
, 0,
765 lpType
, lpPrinterData
, lpNeeded
);
766 if ((res
!= ERROR_CANTREAD
) &&
768 (PRINTER_ATTRIBUTE_ENABLE_BIDI
|PRINTER_ATTRIBUTE_NETWORK
))
769 == PRINTER_ATTRIBUTE_NETWORK
))
771 if (!(res
) && (*lpType
== REG_DWORD
) && (*(LPDWORD
)lpPrinterData
== -1))
772 res
= ERROR_INVALID_DATA
;
777 RegSetValueExA(hkey2
, lpProfile
, 0, REG_DWORD
, (LPBYTE
)&SetData
, 4); /* no result returned */
782 if (hkey2
) RegCloseKey(hkey2
);
783 if (hkey
) RegCloseKey(hkey
);
784 HeapFree(GetProcessHeap(), 0, RegStr_Printer
);
789 /******************************************************************
790 * DrvSetPrinterData [GDI.281]
793 DWORD WINAPI
DrvSetPrinterData16(LPSTR lpPrinter
, LPSTR lpProfile
,
794 DWORD lpType
, LPBYTE lpPrinterData
,
797 LPSTR RegStr_Printer
;
801 if (HIWORD(lpPrinter
))
802 TRACE("printer %s\n",lpPrinter
);
804 TRACE("printer %p\n",lpPrinter
);
805 if (HIWORD(lpProfile
))
806 TRACE("profile %s\n",lpProfile
);
808 TRACE("profile %p\n",lpProfile
);
809 TRACE("lpType %08lx\n",lpType
);
811 if ((!lpPrinter
) || (!lpProfile
) ||
812 ((DWORD
)lpProfile
== INT_PD_DEFAULT_MODEL
) || (HIWORD(lpProfile
) &&
813 (!strcmp(lpProfile
, PrinterModel
))))
814 return ERROR_INVALID_PARAMETER
;
816 RegStr_Printer
= HeapAlloc(GetProcessHeap(), 0,
817 strlen(Printers
) + strlen(lpPrinter
) + 2);
818 strcpy(RegStr_Printer
, Printers
);
819 strcat(RegStr_Printer
, lpPrinter
);
821 if (((DWORD
)lpProfile
== INT_PD_DEFAULT_DEVMODE
) || (HIWORD(lpProfile
) &&
822 (!strcmp(lpProfile
, DefaultDevMode
)))) {
823 if ( RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
)
825 RegSetValueExA(hkey
, DefaultDevMode
, 0, REG_BINARY
,
826 lpPrinterData
, dwSize
) != ERROR_SUCCESS
)
827 res
= ERROR_INVALID_PRINTER_NAME
;
831 strcat(RegStr_Printer
, "\\");
833 if( (res
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
)) ==
837 res
= RegDeleteValueA(hkey
, lpProfile
);
839 res
= RegSetValueExA(hkey
, lpProfile
, 0, lpType
,
840 lpPrinterData
, dwSize
);
844 if (hkey
) RegCloseKey(hkey
);
845 HeapFree(GetProcessHeap(), 0, RegStr_Printer
);