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"
29 DEFAULT_DEBUG_CHANNEL(print
)
31 static char PrinterModel
[] = "Printer Model";
32 static char DefaultDevMode
[] = "Default DevMode";
33 static char PrinterDriverData
[] = "PrinterDriverData";
34 static char Printers
[] = "System\\CurrentControlSet\\Control\\Print\\Printers\\";
36 /******************************************************************
37 * StartDoc16 [GDI.377]
40 INT16 WINAPI
StartDoc16( HDC16 hdc
, const DOCINFO16
*lpdoc
)
43 TRACE("(%p)\n", lpdoc
);
44 TRACE("%d 0x%lx:0x%p 0x%lx:0x%p\n",lpdoc
->cbSize
,
45 lpdoc
->lpszDocName
,PTR_SEG_TO_LIN(lpdoc
->lpszDocName
),
46 lpdoc
->lpszOutput
,PTR_SEG_TO_LIN(lpdoc
->lpszOutput
));
47 TRACE("%d %s %s\n",lpdoc
->cbSize
,
48 (LPSTR
)PTR_SEG_TO_LIN(lpdoc
->lpszDocName
),
49 (LPSTR
)PTR_SEG_TO_LIN(lpdoc
->lpszOutput
));
50 retVal
= Escape16(hdc
, STARTDOC
,
51 strlen((LPSTR
)PTR_SEG_TO_LIN(lpdoc
->lpszDocName
)), lpdoc
->lpszDocName
, 0);
52 TRACE("Escape16 returned %d\n",retVal
);
56 /******************************************************************
60 INT16 WINAPI
EndPage16( HDC16 hdc
)
63 retVal
= Escape16(hdc
, NEWFRAME
, 0, 0, 0);
64 TRACE("Escape16 returned %d\n",retVal
);
68 /******************************************************************
69 * StartDoc32A [GDI32.347]
72 INT WINAPI
StartDocA(HDC hdc
,const DOCINFOA
* doc
)
76 strlen(doc
->lpszDocName
),
81 /*************************************************************************
82 * StartDoc32W [GDI32.348]
85 INT WINAPI
StartDocW(HDC hdc
, const DOCINFOW
* doc
) {
87 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
88 return 0; /* failure*/
91 /******************************************************************
92 * StartPage32 [GDI32.349]
95 INT WINAPI
StartPage(HDC hdc
)
101 /******************************************************************
102 * EndPage32 [GDI32.77]
105 INT WINAPI
EndPage(HDC hdc
)
107 return Escape(hdc
, NEWFRAME
, 0, 0, 0);
110 /******************************************************************
114 INT16 WINAPI
EndDoc16(HDC16 hdc
)
116 return Escape16(hdc
, ENDDOC
, 0, 0, 0);
119 /******************************************************************
120 * EndDoc32 [GDI32.76]
123 INT WINAPI
EndDoc(HDC hdc
)
125 return Escape(hdc
, ENDDOC
, 0, 0, 0);
128 /******************************************************************************
129 * AbortDoc16 [GDI.382]
131 INT16 WINAPI
AbortDoc16(HDC16 hdc
)
133 return Escape16(hdc
, ABORTDOC
, 0, 0, 0);
136 /******************************************************************************
137 * AbortDoc32 [GDI32.0]
139 INT WINAPI
AbortDoc(HDC hdc
)
141 FIXME("(%d): stub\n", hdc
);
145 /**********************************************************************
146 * QueryAbort (GDI.155)
148 * Calls the app's AbortProc function if avail.
151 * TRUE if no AbortProc avail or AbortProc wants to continue printing.
152 * FALSE if AbortProc wants to abort printing.
154 BOOL16 WINAPI
QueryAbort16(HDC16 hdc
, INT16 reserved
)
156 DC
*dc
= DC_GetDCPtr( hdc
);
158 if ((!dc
) || (!dc
->w
.lpfnPrint
))
160 return Callbacks
->CallDrvAbortProc(dc
->w
.lpfnPrint
, hdc
, 0);
163 /**********************************************************************
164 * SetAbortProc16 (GDI.381)
167 INT16 WINAPI
SetAbortProc16(HDC16 hdc
, SEGPTR abrtprc
)
169 return Escape16(hdc
, SETABORTPROC
, 0, abrtprc
, (SEGPTR
)0);
172 /**********************************************************************
173 * SetAbortProc32 (GDI32.301)
176 INT WINAPI
SetAbortProc(HDC hdc
, ABORTPROC abrtprc
)
183 /****************** misc. printer related functions */
186 * The following function should implement a queing system
198 static struct hpq
*hpqueue
;
200 /**********************************************************************
204 HPQ WINAPI
CreatePQ16(int size
)
211 tmp_size
= size
<< 2;
212 if (!(hpq
= GlobalAlloc16(GMEM_SHARE
|GMEM_MOVEABLE
, tmp_size
+ 8)))
214 pPQ
= GlobalLock16(hpq
);
223 FIXME("(%d): stub\n",size
);
228 /**********************************************************************
232 int WINAPI
DeletePQ16(HPQ hPQ
)
234 return GlobalFree16((HGLOBAL16
)hPQ
);
237 /**********************************************************************
238 * ExtractPQ (GDI.232)
241 int WINAPI
ExtractPQ16(HPQ hPQ
)
243 struct hpq
*queue
, *prev
, *current
, *currentPrev
;
244 int key
= 0, tag
= -1;
245 currentPrev
= prev
= NULL
;
246 queue
= current
= hpqueue
;
252 currentPrev
= current
;
253 current
= current
->next
;
256 if (current
->key
< key
)
268 prev
->next
= queue
->next
;
270 hpqueue
= queue
->next
;
274 TRACE("%x got tag %d key %d\n", hPQ
, tag
, key
);
279 /**********************************************************************
283 int WINAPI
InsertPQ16(HPQ hPQ
, int tag
, int key
)
285 struct hpq
*queueItem
= xmalloc(sizeof(struct hpq
));
286 queueItem
->next
= hpqueue
;
288 queueItem
->key
= key
;
289 queueItem
->tag
= tag
;
291 FIXME("(%x %d %d): stub???\n", hPQ
, tag
, key
);
295 /**********************************************************************
299 int WINAPI
MinPQ16(HPQ hPQ
)
301 FIXME("(%x): stub\n", hPQ
);
305 /**********************************************************************
309 int WINAPI
SizePQ16(HPQ hPQ
, int sizechange
)
311 FIXME("(%x %d): stub\n", hPQ
, sizechange
);
318 * The following functions implement part of the spooling process to
319 * print manager. I would like to see wine have a version of print managers
320 * that used LPR/LPD. For simplicity print jobs will be sent to a file for
323 typedef struct PRINTJOB
331 } PRINTJOB
, *PPRINTJOB
;
333 #define MAX_PRINT_JOBS 1
336 PPRINTJOB gPrintJobsTable
[MAX_PRINT_JOBS
];
339 static PPRINTJOB
FindPrintJobFromHandle(HANDLE16 hHandle
)
341 return gPrintJobsTable
[0];
344 /* TTD Need to do some DOS->UNIX file conversion here */
345 static int CreateSpoolFile(LPSTR pszOutput
)
349 char *psCmdP
= psCmd
;
351 /* TTD convert the 'output device' into a spool file name */
353 if (pszOutput
== NULL
|| *pszOutput
== '\0')
356 PROFILE_GetWineIniString( "spooler", pszOutput
, "", psCmd
, sizeof(psCmd
) );
357 TRACE("Got printerSpoolCommand '%s' for output device '%s'\n",
363 while (*psCmdP
&& isspace(*psCmdP
))
379 TRACE("In child need to exec %s\n",psCmdP
);
389 TRACE("Need to execute a cmnd and pipe the output to it\n");
393 TRACE("Just assume its a file\n");
395 if ((fd
= open(psCmdP
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0600)) < 0)
397 ERR("Failed to create spool file %s, errno = %d\n",
404 static int FreePrintJob(HANDLE16 hJob
)
409 pPrintJob
= FindPrintJobFromHandle(hJob
);
410 if (pPrintJob
!= NULL
)
412 gPrintJobsTable
[pPrintJob
->nIndex
] = NULL
;
413 free(pPrintJob
->pszOutput
);
414 free(pPrintJob
->pszTitle
);
415 if (pPrintJob
->fd
>= 0) close(pPrintJob
->fd
);
422 /**********************************************************************
426 HANDLE16 WINAPI
OpenJob16(LPSTR lpOutput
, LPSTR lpTitle
, HDC16 hDC
)
428 HANDLE16 hHandle
= (HANDLE16
)SP_ERROR
;
431 TRACE("'%s' '%s' %04x\n", lpOutput
, lpTitle
, hDC
);
433 pPrintJob
= gPrintJobsTable
[0];
434 if (pPrintJob
== NULL
)
438 /* Try an create a spool file */
439 fd
= CreateSpoolFile(lpOutput
);
444 pPrintJob
= xmalloc(sizeof(PRINTJOB
));
445 memset(pPrintJob
, 0, sizeof(PRINTJOB
));
447 pPrintJob
->pszOutput
= strdup(lpOutput
);
449 pPrintJob
->pszTitle
= strdup(lpTitle
);
450 pPrintJob
->hDC
= hDC
;
452 pPrintJob
->nIndex
= 0;
453 pPrintJob
->hHandle
= hHandle
;
454 gPrintJobsTable
[pPrintJob
->nIndex
] = pPrintJob
;
457 TRACE("return %04x\n", hHandle
);
461 /**********************************************************************
465 int WINAPI
CloseJob16(HANDLE16 hJob
)
468 PPRINTJOB pPrintJob
= NULL
;
470 TRACE("%04x\n", hJob
);
472 pPrintJob
= FindPrintJobFromHandle(hJob
);
473 if (pPrintJob
!= NULL
)
475 /* Close the spool file */
476 close(pPrintJob
->fd
);
483 /**********************************************************************
484 * WriteSpool (GDI.241)
487 int WINAPI
WriteSpool16(HANDLE16 hJob
, LPSTR lpData
, WORD cch
)
490 PPRINTJOB pPrintJob
= NULL
;
492 TRACE("%04x %08lx %04x\n", hJob
, (DWORD
)lpData
, cch
);
494 pPrintJob
= FindPrintJobFromHandle(hJob
);
495 if (pPrintJob
!= NULL
&& pPrintJob
->fd
>= 0 && cch
)
497 if (write(pPrintJob
->fd
, lpData
, cch
) != cch
)
501 if (pPrintJob
->hDC
== 0) {
502 TRACE("hDC == 0 so no QueryAbort\n");
504 else if (!(QueryAbort16(pPrintJob
->hDC
, (nRet
== SP_OUTOFDISK
) ? nRet
: 0 )))
506 CloseJob16(hJob
); /* printing aborted */
513 /**********************************************************************
514 * WriteDialog (GDI.242)
517 int WINAPI
WriteDialog16(HANDLE16 hJob
, LPSTR lpMsg
, WORD cchMsg
)
521 TRACE("%04x %04x '%s'\n", hJob
, cchMsg
, lpMsg
);
523 nRet
= MessageBox16(0, lpMsg
, "Printing Error", MB_OKCANCEL
);
528 /**********************************************************************
529 * DeleteJob (GDI.244)
532 int WINAPI
DeleteJob16(HANDLE16 hJob
, WORD wNotUsed
)
536 TRACE("%04x\n", hJob
);
538 nRet
= FreePrintJob(hJob
);
543 * The following two function would allow a page to be sent to the printer
544 * when it has been processed. For simplicity they havn't been implemented.
545 * This means a whole job has to be processed before it is sent to the printer.
548 /**********************************************************************
549 * StartSpoolPage (GDI.246)
552 int WINAPI
StartSpoolPage16(HANDLE16 hJob
)
554 FIXME("StartSpoolPage GDI.246 unimplemented\n");
560 /**********************************************************************
561 * EndSpoolPage (GDI.247)
564 int WINAPI
EndSpoolPage16(HANDLE16 hJob
)
566 FIXME("EndSpoolPage GDI.247 unimplemented\n");
571 /**********************************************************************
572 * GetSpoolJob (GDI.245)
575 DWORD WINAPI
GetSpoolJob16(int nOption
, LONG param
)
578 TRACE("In GetSpoolJob param 0x%lx noption %d\n",param
, nOption
);
583 /******************************************************************
584 * DrvGetPrinterDataInternal
586 * Helper for DrvGetPrinterData
588 static DWORD
DrvGetPrinterDataInternal(LPSTR RegStr_Printer
,
589 LPBYTE lpPrinterData
, int cbData
, int what
)
593 DWORD dwType
, cbQueryData
;
595 if (!(RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
))) {
596 if (what
== INT_PD_DEFAULT_DEVMODE
) { /* "Default DevMode" */
597 if (!(RegQueryValueExA(hkey
, DefaultDevMode
, 0, &dwType
, 0, &cbQueryData
))) {
600 else if ((cbQueryData
) && (cbQueryData
<= cbData
)) {
601 cbQueryData
= cbData
;
602 if (RegQueryValueExA(hkey
, DefaultDevMode
, 0,
603 &dwType
, lpPrinterData
, &cbQueryData
))
607 } else { /* "Printer Driver" */
609 RegQueryValueExA(hkey
, "Printer Driver", 0,
610 &dwType
, lpPrinterData
, &cbQueryData
);
614 if (hkey
) RegCloseKey(hkey
);
618 /******************************************************************
619 * DrvGetPrinterData [GDI.282]
622 DWORD WINAPI
DrvGetPrinterData16(LPSTR lpPrinter
, LPSTR lpProfile
,
623 LPDWORD lpType
, LPBYTE lpPrinterData
,
624 int cbData
, LPDWORD lpNeeded
)
626 LPSTR RegStr_Printer
;
627 HKEY hkey
= 0, hkey2
= 0;
629 DWORD dwType
, PrinterAttr
, cbPrinterAttr
, SetData
, size
;
631 if (HIWORD(lpPrinter
))
632 TRACE("printer %s\n",lpPrinter
);
634 TRACE("printer %p\n",lpPrinter
);
635 if (HIWORD(lpProfile
))
636 TRACE("profile %s\n",lpProfile
);
638 TRACE("profile %p\n",lpProfile
);
639 TRACE("lpType %p\n",lpType
);
641 if ((!lpPrinter
) || (!lpProfile
) || (!lpNeeded
))
642 return ERROR_INVALID_PARAMETER
;
644 RegStr_Printer
= HeapAlloc(GetProcessHeap(), 0,
645 strlen(Printers
) + strlen(lpPrinter
) + 2);
646 strcpy(RegStr_Printer
, Printers
);
647 strcat(RegStr_Printer
, lpPrinter
);
649 if (((DWORD
)lpProfile
== INT_PD_DEFAULT_DEVMODE
) || (HIWORD(lpProfile
) &&
650 (!strcmp(lpProfile
, DefaultDevMode
)))) {
651 size
= DrvGetPrinterDataInternal(RegStr_Printer
, lpPrinterData
, cbData
,
652 INT_PD_DEFAULT_DEVMODE
);
655 if ((lpPrinterData
) && (*lpNeeded
> cbData
))
656 res
= ERROR_MORE_DATA
;
658 else res
= ERROR_INVALID_PRINTER_NAME
;
661 if (((DWORD
)lpProfile
== INT_PD_DEFAULT_MODEL
) || (HIWORD(lpProfile
) &&
662 (!strcmp(lpProfile
, PrinterModel
)))) {
664 if (!lpPrinterData
) goto failed
;
666 res
= ERROR_MORE_DATA
;
669 size
= DrvGetPrinterDataInternal(RegStr_Printer
, lpPrinterData
, cbData
,
670 INT_PD_DEFAULT_MODEL
);
671 if ((size
+1) && (lpType
))
674 res
= ERROR_INVALID_PRINTER_NAME
;
678 if ((res
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
)))
681 if ((res
= RegQueryValueExA(hkey
, "Attributes", 0,
682 &dwType
, (LPBYTE
)&PrinterAttr
, &cbPrinterAttr
)))
684 if ((res
= RegOpenKeyA(hkey
, PrinterDriverData
, &hkey2
)))
687 res
= RegQueryValueExA(hkey2
, lpProfile
, 0,
688 lpType
, lpPrinterData
, lpNeeded
);
689 if ((res
!= ERROR_CANTREAD
) &&
691 (PRINTER_ATTRIBUTE_ENABLE_BIDI
|PRINTER_ATTRIBUTE_NETWORK
))
692 == PRINTER_ATTRIBUTE_NETWORK
))
694 if (!(res
) && (*lpType
== REG_DWORD
) && (*(LPDWORD
)lpPrinterData
== -1))
695 res
= ERROR_INVALID_DATA
;
700 RegSetValueExA(hkey2
, lpProfile
, 0, REG_DWORD
, (LPBYTE
)&SetData
, 4); /* no result returned */
705 if (hkey2
) RegCloseKey(hkey2
);
706 if (hkey
) RegCloseKey(hkey
);
707 HeapFree(GetProcessHeap(), 0, RegStr_Printer
);
712 /******************************************************************
713 * DrvSetPrinterData [GDI.281]
716 DWORD WINAPI
DrvSetPrinterData16(LPSTR lpPrinter
, LPSTR lpProfile
,
717 DWORD lpType
, LPBYTE lpPrinterData
,
720 LPSTR RegStr_Printer
;
724 if (HIWORD(lpPrinter
))
725 TRACE("printer %s\n",lpPrinter
);
727 TRACE("printer %p\n",lpPrinter
);
728 if (HIWORD(lpProfile
))
729 TRACE("profile %s\n",lpProfile
);
731 TRACE("profile %p\n",lpProfile
);
732 TRACE("lpType %08lx\n",lpType
);
734 if ((!lpPrinter
) || (!lpProfile
) ||
735 ((DWORD
)lpProfile
== INT_PD_DEFAULT_MODEL
) || (HIWORD(lpProfile
) &&
736 (!strcmp(lpProfile
, PrinterModel
))))
737 return ERROR_INVALID_PARAMETER
;
739 RegStr_Printer
= HeapAlloc(GetProcessHeap(), 0,
740 strlen(Printers
) + strlen(lpPrinter
) + 2);
741 strcpy(RegStr_Printer
, Printers
);
742 strcat(RegStr_Printer
, lpPrinter
);
744 if (((DWORD
)lpProfile
== INT_PD_DEFAULT_DEVMODE
) || (HIWORD(lpProfile
) &&
745 (!strcmp(lpProfile
, DefaultDevMode
)))) {
746 if ( RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
)
748 RegSetValueExA(hkey
, DefaultDevMode
, 0, REG_BINARY
,
749 lpPrinterData
, dwSize
) != ERROR_SUCCESS
)
750 res
= ERROR_INVALID_PRINTER_NAME
;
754 strcat(RegStr_Printer
, "\\");
756 if( (res
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
)) ==
760 res
= RegDeleteValueA(hkey
, lpProfile
);
762 res
= RegSetValueExA(hkey
, lpProfile
, 0, lpType
,
763 lpPrinterData
, dwSize
);
767 if (hkey
) RegCloseKey(hkey
);
768 HeapFree(GetProcessHeap(), 0, RegStr_Printer
);