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
);
48 docA
.lpszDatatype
= NULL
;
51 return StartDocA(hdc
, &docA
);
54 /******************************************************************
55 * StartDocA [GDI32.347]
58 INT WINAPI
StartDocA(HDC hdc
, const DOCINFOA
* doc
)
60 DC
*dc
= DC_GetDCPtr( hdc
);
62 TRACE("DocName = '%s' Output = '%s' Datatype = '%s'\n",
63 doc
->lpszDocName
, doc
->lpszOutput
, doc
->lpszDatatype
);
67 if(dc
->funcs
->pStartDoc
)
68 return dc
->funcs
->pStartDoc( dc
, doc
);
70 return Escape(hdc
, STARTDOC
, strlen(doc
->lpszDocName
),
74 /*************************************************************************
75 * StartDocW [GDI32.348]
78 INT WINAPI
StartDocW(HDC hdc
, const DOCINFOW
* doc
)
83 docA
.cbSize
= doc
->cbSize
;
84 docA
.lpszDocName
= doc
->lpszDocName
?
85 HEAP_strdupWtoA( GetProcessHeap(), 0, doc
->lpszDocName
) : NULL
;
86 docA
.lpszOutput
= doc
->lpszOutput
?
87 HEAP_strdupWtoA( GetProcessHeap(), 0, doc
->lpszOutput
) : NULL
;
88 docA
.lpszDatatype
= doc
->lpszDatatype
?
89 HEAP_strdupWtoA( GetProcessHeap(), 0, doc
->lpszDatatype
) : NULL
;
90 docA
.fwType
= doc
->fwType
;
92 ret
= StartDocA(hdc
, &docA
);
95 HeapFree( GetProcessHeap(), 0, (LPSTR
)docA
.lpszDocName
);
97 HeapFree( GetProcessHeap(), 0, (LPSTR
)docA
.lpszOutput
);
99 HeapFree( GetProcessHeap(), 0, (LPSTR
)docA
.lpszDatatype
);
104 /******************************************************************
108 INT16 WINAPI
EndDoc16(HDC16 hdc
)
113 /******************************************************************
117 INT WINAPI
EndDoc(HDC hdc
)
119 DC
*dc
= DC_GetDCPtr( hdc
);
122 if(dc
->funcs
->pEndDoc
)
123 return dc
->funcs
->pEndDoc( dc
);
125 return Escape(hdc
, ENDDOC
, 0, 0, 0);
128 /******************************************************************
129 * StartPage16 [GDI.379]
132 INT16 WINAPI
StartPage16(HDC16 hdc
)
134 return StartPage(hdc
);
137 /******************************************************************
138 * StartPage [GDI32.349]
141 INT WINAPI
StartPage(HDC hdc
)
143 DC
*dc
= DC_GetDCPtr( hdc
);
146 if(dc
->funcs
->pStartPage
)
147 return dc
->funcs
->pStartPage( dc
);
153 /******************************************************************
154 * EndPage16 [GDI.380]
157 INT16 WINAPI
EndPage16( HDC16 hdc
)
162 /******************************************************************
166 INT WINAPI
EndPage(HDC hdc
)
168 DC
*dc
= DC_GetDCPtr( hdc
);
171 if(dc
->funcs
->pEndPage
)
172 return dc
->funcs
->pEndPage( dc
);
174 return Escape(hdc
, NEWFRAME
, 0, 0, 0);
177 /******************************************************************************
178 * AbortDoc16 [GDI.382]
180 INT16 WINAPI
AbortDoc16(HDC16 hdc
)
182 return AbortDoc(hdc
);
185 /******************************************************************************
186 * AbortDoc [GDI32.105]
188 INT WINAPI
AbortDoc(HDC hdc
)
190 DC
*dc
= DC_GetDCPtr( hdc
);
193 if(dc
->funcs
->pAbortDoc
)
194 return dc
->funcs
->pAbortDoc( dc
);
196 return Escape(hdc
, ABORTDOC
, 0, 0, 0);
199 /**********************************************************************
200 * QueryAbort16 (GDI.155)
202 * Calls the app's AbortProc function if avail.
205 * TRUE if no AbortProc avail or AbortProc wants to continue printing.
206 * FALSE if AbortProc wants to abort printing.
208 BOOL16 WINAPI
QueryAbort16(HDC16 hdc
, INT16 reserved
)
210 DC
*dc
= DC_GetDCPtr( hdc
);
214 ERR("Invalid hdc %04x\n", hdc
);
218 if(!dc
->w
.lpfnPrint
&& !dc
->w
.spfnPrint
)
221 if(dc
->w
.lpfnPrint
&& dc
->w
.spfnPrint
)
222 FIXME("16 and 32 bit AbortProcs set?\n");
224 if(dc
->w
.spfnPrint
) {
225 TRACE("Calling 16bit AbortProc\n");
226 ret
= Callbacks
->CallDrvAbortProc(dc
->w
.spfnPrint
, hdc
, 0);
228 TRACE("Calling 32bit AbortProc\n");
229 ret
= dc
->w
.lpfnPrint(hdc
,0);
234 /**********************************************************************
235 * SetAbortProc16 (GDI.381)
238 INT16 WINAPI
SetAbortProc16(HDC16 hdc
, SEGPTR abrtprc
)
240 return Escape16(hdc
, SETABORTPROC
, 0, abrtprc
, (SEGPTR
)0);
243 /**********************************************************************
244 * SetAbortProc32 (GDI32.301)
247 INT WINAPI
SetAbortProc(HDC hdc
, ABORTPROC abrtprc
)
249 DC
*dc
= DC_GetDCPtr( hdc
);
251 dc
->w
.lpfnPrint
= abrtprc
;
256 /****************** misc. printer related functions */
259 * The following function should implement a queing system
271 static struct hpq
*hpqueue
;
273 /**********************************************************************
277 HPQ WINAPI
CreatePQ16(int size
)
284 tmp_size
= size
<< 2;
285 if (!(hpq
= GlobalAlloc16(GMEM_SHARE
|GMEM_MOVEABLE
, tmp_size
+ 8)))
287 pPQ
= GlobalLock16(hpq
);
296 FIXME("(%d): stub\n",size
);
301 /**********************************************************************
305 int WINAPI
DeletePQ16(HPQ hPQ
)
307 return GlobalFree16((HGLOBAL16
)hPQ
);
310 /**********************************************************************
311 * ExtractPQ (GDI.232)
314 int WINAPI
ExtractPQ16(HPQ hPQ
)
316 struct hpq
*queue
, *prev
, *current
, *currentPrev
;
317 int key
= 0, tag
= -1;
318 currentPrev
= prev
= NULL
;
319 queue
= current
= hpqueue
;
325 currentPrev
= current
;
326 current
= current
->next
;
329 if (current
->key
< key
)
341 prev
->next
= queue
->next
;
343 hpqueue
= queue
->next
;
347 TRACE("%x got tag %d key %d\n", hPQ
, tag
, key
);
352 /**********************************************************************
356 int WINAPI
InsertPQ16(HPQ hPQ
, int tag
, int key
)
358 struct hpq
*queueItem
= xmalloc(sizeof(struct hpq
));
359 queueItem
->next
= hpqueue
;
361 queueItem
->key
= key
;
362 queueItem
->tag
= tag
;
364 FIXME("(%x %d %d): stub???\n", hPQ
, tag
, key
);
368 /**********************************************************************
372 int WINAPI
MinPQ16(HPQ hPQ
)
374 FIXME("(%x): stub\n", hPQ
);
378 /**********************************************************************
382 int WINAPI
SizePQ16(HPQ hPQ
, int sizechange
)
384 FIXME("(%x %d): stub\n", hPQ
, sizechange
);
391 * The following functions implement part of the spooling process to
392 * print manager. I would like to see wine have a version of print managers
393 * that used LPR/LPD. For simplicity print jobs will be sent to a file for
396 typedef struct PRINTJOB
404 } PRINTJOB
, *PPRINTJOB
;
406 #define MAX_PRINT_JOBS 1
409 PPRINTJOB gPrintJobsTable
[MAX_PRINT_JOBS
];
412 static PPRINTJOB
FindPrintJobFromHandle(HANDLE16 hHandle
)
414 return gPrintJobsTable
[0];
417 /* TTD Need to do some DOS->UNIX file conversion here */
418 static int CreateSpoolFile(LPCSTR pszOutput
)
422 char *psCmdP
= psCmd
;
424 /* TTD convert the 'output device' into a spool file name */
426 if (pszOutput
== NULL
|| *pszOutput
== '\0')
429 PROFILE_GetWineIniString( "spooler", pszOutput
, "", psCmd
, sizeof(psCmd
) );
430 TRACE("Got printerSpoolCommand '%s' for output device '%s'\n",
433 psCmdP
= (char *)pszOutput
;
436 while (*psCmdP
&& isspace(*psCmdP
))
452 TRACE("In child need to exec %s\n",psCmdP
);
462 TRACE("Need to execute a cmnd and pipe the output to it\n");
466 TRACE("Just assume its a file\n");
468 if ((fd
= open(psCmdP
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0600)) < 0)
470 ERR("Failed to create spool file %s, errno = %d\n",
477 static int FreePrintJob(HANDLE16 hJob
)
482 pPrintJob
= FindPrintJobFromHandle(hJob
);
483 if (pPrintJob
!= NULL
)
485 gPrintJobsTable
[pPrintJob
->nIndex
] = NULL
;
486 free(pPrintJob
->pszOutput
);
487 free(pPrintJob
->pszTitle
);
488 if (pPrintJob
->fd
>= 0) close(pPrintJob
->fd
);
495 /**********************************************************************
499 HANDLE16 WINAPI
OpenJob16(LPCSTR lpOutput
, LPCSTR lpTitle
, HDC16 hDC
)
501 HANDLE16 hHandle
= (HANDLE16
)SP_ERROR
;
504 TRACE("'%s' '%s' %04x\n", lpOutput
, lpTitle
, hDC
);
506 pPrintJob
= gPrintJobsTable
[0];
507 if (pPrintJob
== NULL
)
511 /* Try an create a spool file */
512 fd
= CreateSpoolFile(lpOutput
);
517 pPrintJob
= xmalloc(sizeof(PRINTJOB
));
518 memset(pPrintJob
, 0, sizeof(PRINTJOB
));
520 pPrintJob
->pszOutput
= strdup(lpOutput
);
522 pPrintJob
->pszTitle
= strdup(lpTitle
);
523 pPrintJob
->hDC
= hDC
;
525 pPrintJob
->nIndex
= 0;
526 pPrintJob
->hHandle
= hHandle
;
527 gPrintJobsTable
[pPrintJob
->nIndex
] = pPrintJob
;
530 TRACE("return %04x\n", hHandle
);
534 /**********************************************************************
538 int WINAPI
CloseJob16(HANDLE16 hJob
)
541 PPRINTJOB pPrintJob
= NULL
;
543 TRACE("%04x\n", hJob
);
545 pPrintJob
= FindPrintJobFromHandle(hJob
);
546 if (pPrintJob
!= NULL
)
548 /* Close the spool file */
549 close(pPrintJob
->fd
);
556 /**********************************************************************
557 * WriteSpool (GDI.241)
560 int WINAPI
WriteSpool16(HANDLE16 hJob
, LPSTR lpData
, WORD cch
)
563 PPRINTJOB pPrintJob
= NULL
;
565 TRACE("%04x %08lx %04x\n", hJob
, (DWORD
)lpData
, cch
);
567 pPrintJob
= FindPrintJobFromHandle(hJob
);
568 if (pPrintJob
!= NULL
&& pPrintJob
->fd
>= 0 && cch
)
570 if (write(pPrintJob
->fd
, lpData
, cch
) != cch
)
574 if (pPrintJob
->hDC
== 0) {
575 TRACE("hDC == 0 so no QueryAbort\n");
577 else if (!(QueryAbort16(pPrintJob
->hDC
, (nRet
== SP_OUTOFDISK
) ? nRet
: 0 )))
579 CloseJob16(hJob
); /* printing aborted */
586 /**********************************************************************
587 * WriteDialog (GDI.242)
590 int WINAPI
WriteDialog16(HANDLE16 hJob
, LPSTR lpMsg
, WORD cchMsg
)
594 TRACE("%04x %04x '%s'\n", hJob
, cchMsg
, lpMsg
);
596 nRet
= MessageBox16(0, lpMsg
, "Printing Error", MB_OKCANCEL
);
601 /**********************************************************************
602 * DeleteJob (GDI.244)
605 int WINAPI
DeleteJob16(HANDLE16 hJob
, WORD wNotUsed
)
609 TRACE("%04x\n", hJob
);
611 nRet
= FreePrintJob(hJob
);
616 * The following two function would allow a page to be sent to the printer
617 * when it has been processed. For simplicity they havn't been implemented.
618 * This means a whole job has to be processed before it is sent to the printer.
621 /**********************************************************************
622 * StartSpoolPage (GDI.246)
625 int WINAPI
StartSpoolPage16(HANDLE16 hJob
)
627 FIXME("StartSpoolPage GDI.246 unimplemented\n");
633 /**********************************************************************
634 * EndSpoolPage (GDI.247)
637 int WINAPI
EndSpoolPage16(HANDLE16 hJob
)
639 FIXME("EndSpoolPage GDI.247 unimplemented\n");
644 /**********************************************************************
645 * GetSpoolJob (GDI.245)
648 DWORD WINAPI
GetSpoolJob16(int nOption
, LONG param
)
651 TRACE("In GetSpoolJob param 0x%lx noption %d\n",param
, nOption
);
656 /******************************************************************
657 * DrvGetPrinterDataInternal
659 * Helper for DrvGetPrinterData
661 static DWORD
DrvGetPrinterDataInternal(LPSTR RegStr_Printer
,
662 LPBYTE lpPrinterData
, int cbData
, int what
)
666 DWORD dwType
, cbQueryData
;
668 if (!(RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
))) {
669 if (what
== INT_PD_DEFAULT_DEVMODE
) { /* "Default DevMode" */
670 if (!(RegQueryValueExA(hkey
, DefaultDevMode
, 0, &dwType
, 0, &cbQueryData
))) {
673 else if ((cbQueryData
) && (cbQueryData
<= cbData
)) {
674 cbQueryData
= cbData
;
675 if (RegQueryValueExA(hkey
, DefaultDevMode
, 0,
676 &dwType
, lpPrinterData
, &cbQueryData
))
680 } else { /* "Printer Driver" */
682 RegQueryValueExA(hkey
, "Printer Driver", 0,
683 &dwType
, lpPrinterData
, &cbQueryData
);
687 if (hkey
) RegCloseKey(hkey
);
691 /******************************************************************
692 * DrvGetPrinterData [GDI.282]
695 DWORD WINAPI
DrvGetPrinterData16(LPSTR lpPrinter
, LPSTR lpProfile
,
696 LPDWORD lpType
, LPBYTE lpPrinterData
,
697 int cbData
, LPDWORD lpNeeded
)
699 LPSTR RegStr_Printer
;
700 HKEY hkey
= 0, hkey2
= 0;
702 DWORD dwType
, PrinterAttr
, cbPrinterAttr
, SetData
, size
;
704 if (HIWORD(lpPrinter
))
705 TRACE("printer %s\n",lpPrinter
);
707 TRACE("printer %p\n",lpPrinter
);
708 if (HIWORD(lpProfile
))
709 TRACE("profile %s\n",lpProfile
);
711 TRACE("profile %p\n",lpProfile
);
712 TRACE("lpType %p\n",lpType
);
714 if ((!lpPrinter
) || (!lpProfile
) || (!lpNeeded
))
715 return ERROR_INVALID_PARAMETER
;
717 RegStr_Printer
= HeapAlloc(GetProcessHeap(), 0,
718 strlen(Printers
) + strlen(lpPrinter
) + 2);
719 strcpy(RegStr_Printer
, Printers
);
720 strcat(RegStr_Printer
, lpPrinter
);
722 if (((DWORD
)lpProfile
== INT_PD_DEFAULT_DEVMODE
) || (HIWORD(lpProfile
) &&
723 (!strcmp(lpProfile
, DefaultDevMode
)))) {
724 size
= DrvGetPrinterDataInternal(RegStr_Printer
, lpPrinterData
, cbData
,
725 INT_PD_DEFAULT_DEVMODE
);
728 if ((lpPrinterData
) && (*lpNeeded
> cbData
))
729 res
= ERROR_MORE_DATA
;
731 else res
= ERROR_INVALID_PRINTER_NAME
;
734 if (((DWORD
)lpProfile
== INT_PD_DEFAULT_MODEL
) || (HIWORD(lpProfile
) &&
735 (!strcmp(lpProfile
, PrinterModel
)))) {
737 if (!lpPrinterData
) goto failed
;
739 res
= ERROR_MORE_DATA
;
742 size
= DrvGetPrinterDataInternal(RegStr_Printer
, lpPrinterData
, cbData
,
743 INT_PD_DEFAULT_MODEL
);
744 if ((size
+1) && (lpType
))
747 res
= ERROR_INVALID_PRINTER_NAME
;
751 if ((res
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
)))
754 if ((res
= RegQueryValueExA(hkey
, "Attributes", 0,
755 &dwType
, (LPBYTE
)&PrinterAttr
, &cbPrinterAttr
)))
757 if ((res
= RegOpenKeyA(hkey
, PrinterDriverData
, &hkey2
)))
760 res
= RegQueryValueExA(hkey2
, lpProfile
, 0,
761 lpType
, lpPrinterData
, lpNeeded
);
762 if ((res
!= ERROR_CANTREAD
) &&
764 (PRINTER_ATTRIBUTE_ENABLE_BIDI
|PRINTER_ATTRIBUTE_NETWORK
))
765 == PRINTER_ATTRIBUTE_NETWORK
))
767 if (!(res
) && (*lpType
== REG_DWORD
) && (*(LPDWORD
)lpPrinterData
== -1))
768 res
= ERROR_INVALID_DATA
;
773 RegSetValueExA(hkey2
, lpProfile
, 0, REG_DWORD
, (LPBYTE
)&SetData
, 4); /* no result returned */
778 if (hkey2
) RegCloseKey(hkey2
);
779 if (hkey
) RegCloseKey(hkey
);
780 HeapFree(GetProcessHeap(), 0, RegStr_Printer
);
785 /******************************************************************
786 * DrvSetPrinterData [GDI.281]
789 DWORD WINAPI
DrvSetPrinterData16(LPSTR lpPrinter
, LPSTR lpProfile
,
790 DWORD lpType
, LPBYTE lpPrinterData
,
793 LPSTR RegStr_Printer
;
797 if (HIWORD(lpPrinter
))
798 TRACE("printer %s\n",lpPrinter
);
800 TRACE("printer %p\n",lpPrinter
);
801 if (HIWORD(lpProfile
))
802 TRACE("profile %s\n",lpProfile
);
804 TRACE("profile %p\n",lpProfile
);
805 TRACE("lpType %08lx\n",lpType
);
807 if ((!lpPrinter
) || (!lpProfile
) ||
808 ((DWORD
)lpProfile
== INT_PD_DEFAULT_MODEL
) || (HIWORD(lpProfile
) &&
809 (!strcmp(lpProfile
, PrinterModel
))))
810 return ERROR_INVALID_PARAMETER
;
812 RegStr_Printer
= HeapAlloc(GetProcessHeap(), 0,
813 strlen(Printers
) + strlen(lpPrinter
) + 2);
814 strcpy(RegStr_Printer
, Printers
);
815 strcat(RegStr_Printer
, lpPrinter
);
817 if (((DWORD
)lpProfile
== INT_PD_DEFAULT_DEVMODE
) || (HIWORD(lpProfile
) &&
818 (!strcmp(lpProfile
, DefaultDevMode
)))) {
819 if ( RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
)
821 RegSetValueExA(hkey
, DefaultDevMode
, 0, REG_BINARY
,
822 lpPrinterData
, dwSize
) != ERROR_SUCCESS
)
823 res
= ERROR_INVALID_PRINTER_NAME
;
827 strcat(RegStr_Printer
, "\\");
829 if( (res
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
)) ==
833 res
= RegDeleteValueA(hkey
, lpProfile
);
835 res
= RegSetValueExA(hkey
, lpProfile
, 0, lpType
,
836 lpPrinterData
, dwSize
);
840 if (hkey
) RegCloseKey(hkey
);
841 HeapFree(GetProcessHeap(), 0, RegStr_Printer
);