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)
74 TRACE("DocName = '%s' Output = '%s' Datatype = '%s'\n",
75 doc->lpszDocName, doc->lpszOutput, doc->lpszDatatype);
78 strlen(doc->lpszDocName),
83 /*************************************************************************
84 * StartDoc32W [GDI32.348]
87 INT WINAPI StartDocW(HDC hdc, const DOCINFOW* doc) {
89 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
90 return 0; /* failure*/
93 /******************************************************************
94 * StartPage32 [GDI32.349]
97 INT WINAPI StartPage(HDC hdc)
103 /******************************************************************
104 * EndPage32 [GDI32.77]
107 INT WINAPI EndPage(HDC hdc)
109 return Escape(hdc, NEWFRAME, 0, 0, 0);
112 /******************************************************************
116 INT16 WINAPI EndDoc16(HDC16 hdc)
118 return Escape16(hdc, ENDDOC, 0, 0, 0);
121 /******************************************************************
122 * EndDoc32 [GDI32.76]
125 INT WINAPI EndDoc(HDC hdc)
127 return Escape(hdc, ENDDOC, 0, 0, 0);
130 /******************************************************************************
131 * AbortDoc16 [GDI.382]
133 INT16 WINAPI AbortDoc16(HDC16 hdc)
135 return Escape16(hdc, ABORTDOC, 0, 0, 0);
138 /******************************************************************************
139 * AbortDoc32 [GDI32.0]
141 INT WINAPI AbortDoc(HDC hdc)
143 FIXME("(%d): stub\n", hdc);
147 /**********************************************************************
148 * QueryAbort (GDI.155)
150 * Calls the app's AbortProc function if avail.
153 * TRUE if no AbortProc avail or AbortProc wants to continue printing.
154 * FALSE if AbortProc wants to abort printing.
156 BOOL16 WINAPI QueryAbort16(HDC16 hdc, INT16 reserved)
158 DC *dc = DC_GetDCPtr( hdc );
162 ERR("Invalid hdc %04x\n", hdc);
166 if(!dc->w.lpfnPrint && !dc->w.spfnPrint)
169 if(dc->w.lpfnPrint && dc->w.spfnPrint)
170 FIXME("16 and 32 bit AbortProcs set?\n");
172 if(dc->w.spfnPrint) {
173 TRACE("Calling 16bit AbortProc\n");
174 ret = Callbacks->CallDrvAbortProc(dc->w.spfnPrint, hdc, 0);
176 TRACE("Calling 32bit AbortProc\n");
177 ret = dc->w.lpfnPrint(hdc,0);
182 /**********************************************************************
183 * SetAbortProc16 (GDI.381)
186 INT16 WINAPI SetAbortProc16(HDC16 hdc, SEGPTR abrtprc)
188 return Escape16(hdc, SETABORTPROC, 0, abrtprc, (SEGPTR)0);
191 /**********************************************************************
192 * SetAbortProc32 (GDI32.301)
195 INT WINAPI SetAbortProc(HDC hdc, ABORTPROC abrtprc)
197 DC *dc = DC_GetDCPtr( hdc );
199 dc->w.lpfnPrint = abrtprc;
204 /****************** misc. printer related functions */
207 * The following function should implement a queing system
219 static struct hpq *hpqueue;
221 /**********************************************************************
225 HPQ WINAPI CreatePQ16(int size)
232 tmp_size = size << 2;
233 if (!(hpq = GlobalAlloc16(GMEM_SHARE|GMEM_MOVEABLE, tmp_size + 8)))
235 pPQ = GlobalLock16(hpq);
244 FIXME("(%d): stub\n",size);
249 /**********************************************************************
253 int WINAPI DeletePQ16(HPQ hPQ)
255 return GlobalFree16((HGLOBAL16)hPQ);
258 /**********************************************************************
259 * ExtractPQ (GDI.232)
262 int WINAPI ExtractPQ16(HPQ hPQ)
264 struct hpq *queue, *prev, *current, *currentPrev;
265 int key = 0, tag = -1;
266 currentPrev = prev = NULL;
267 queue = current = hpqueue;
273 currentPrev = current;
274 current = current->next;
277 if (current->key < key)
289 prev->next = queue->next;
291 hpqueue = queue->next;
295 TRACE("%x got tag %d key %d\n", hPQ, tag, key);
300 /**********************************************************************
304 int WINAPI InsertPQ16(HPQ hPQ, int tag, int key)
306 struct hpq *queueItem = xmalloc(sizeof(struct hpq));
307 queueItem->next = hpqueue;
309 queueItem->key = key;
310 queueItem->tag = tag;
312 FIXME("(%x %d %d): stub???\n", hPQ, tag, key);
316 /**********************************************************************
320 int WINAPI MinPQ16(HPQ hPQ)
322 FIXME("(%x): stub\n", hPQ);
326 /**********************************************************************
330 int WINAPI SizePQ16(HPQ hPQ, int sizechange)
332 FIXME("(%x %d): stub\n", hPQ, sizechange);
339 * The following functions implement part of the spooling process to
340 * print manager. I would like to see wine have a version of print managers
341 * that used LPR/LPD. For simplicity print jobs will be sent to a file for
344 typedef struct PRINTJOB
352 } PRINTJOB, *PPRINTJOB;
354 #define MAX_PRINT_JOBS 1
357 PPRINTJOB gPrintJobsTable[MAX_PRINT_JOBS];
360 static PPRINTJOB FindPrintJobFromHandle(HANDLE16 hHandle)
362 return gPrintJobsTable[0];
365 /* TTD Need to do some DOS->UNIX file conversion here */
366 static int CreateSpoolFile(LPSTR pszOutput)
370 char *psCmdP = psCmd;
372 /* TTD convert the 'output device' into a spool file name */
374 if (pszOutput == NULL || *pszOutput == '\0')
377 PROFILE_GetWineIniString( "spooler", pszOutput, "", psCmd, sizeof(psCmd) );
378 TRACE("Got printerSpoolCommand '%s' for output device '%s'\n",
384 while (*psCmdP && isspace(*psCmdP))
400 TRACE("In child need to exec %s\n",psCmdP);
410 TRACE("Need to execute a cmnd and pipe the output to it\n");
414 TRACE("Just assume its a file\n");
416 if ((fd = open(psCmdP, O_CREAT | O_TRUNC | O_WRONLY , 0600)) < 0)
418 ERR("Failed to create spool file %s, errno = %d\n",
425 static int FreePrintJob(HANDLE16 hJob)
430 pPrintJob = FindPrintJobFromHandle(hJob);
431 if (pPrintJob != NULL)
433 gPrintJobsTable[pPrintJob->nIndex] = NULL;
434 free(pPrintJob->pszOutput);
435 free(pPrintJob->pszTitle);
436 if (pPrintJob->fd >= 0) close(pPrintJob->fd);
443 /**********************************************************************
447 HANDLE16 WINAPI OpenJob16(LPSTR lpOutput, LPSTR lpTitle, HDC16 hDC)
449 HANDLE16 hHandle = (HANDLE16)SP_ERROR;
452 TRACE("'%s' '%s' %04x\n", lpOutput, lpTitle, hDC);
454 pPrintJob = gPrintJobsTable[0];
455 if (pPrintJob == NULL)
459 /* Try an create a spool file */
460 fd = CreateSpoolFile(lpOutput);
465 pPrintJob = xmalloc(sizeof(PRINTJOB));
466 memset(pPrintJob, 0, sizeof(PRINTJOB));
468 pPrintJob->pszOutput = strdup(lpOutput);
470 pPrintJob->pszTitle = strdup(lpTitle);
471 pPrintJob->hDC = hDC;
473 pPrintJob->nIndex = 0;
474 pPrintJob->hHandle = hHandle;
475 gPrintJobsTable[pPrintJob->nIndex] = pPrintJob;
478 TRACE("return %04x\n", hHandle);
482 /**********************************************************************
486 int WINAPI CloseJob16(HANDLE16 hJob)
489 PPRINTJOB pPrintJob = NULL;
491 TRACE("%04x\n", hJob);
493 pPrintJob = FindPrintJobFromHandle(hJob);
494 if (pPrintJob != NULL)
496 /* Close the spool file */
497 close(pPrintJob->fd);
504 /**********************************************************************
505 * WriteSpool (GDI.241)
508 int WINAPI WriteSpool16(HANDLE16 hJob, LPSTR lpData, WORD cch)
511 PPRINTJOB pPrintJob = NULL;
513 TRACE("%04x %08lx %04x\n", hJob, (DWORD)lpData, cch);
515 pPrintJob = FindPrintJobFromHandle(hJob);
516 if (pPrintJob != NULL && pPrintJob->fd >= 0 && cch)
518 if (write(pPrintJob->fd, lpData, cch) != cch)
522 if (pPrintJob->hDC == 0) {
523 TRACE("hDC == 0 so no QueryAbort\n");
525 else if (!(QueryAbort16(pPrintJob->hDC, (nRet == SP_OUTOFDISK) ? nRet : 0 )))
527 CloseJob16(hJob); /* printing aborted */
534 /**********************************************************************
535 * WriteDialog (GDI.242)
538 int WINAPI WriteDialog16(HANDLE16 hJob, LPSTR lpMsg, WORD cchMsg)
542 TRACE("%04x %04x '%s'\n", hJob, cchMsg, lpMsg);
544 nRet = MessageBox16(0, lpMsg, "Printing Error", MB_OKCANCEL);
549 /**********************************************************************
550 * DeleteJob (GDI.244)
553 int WINAPI DeleteJob16(HANDLE16 hJob, WORD wNotUsed)
557 TRACE("%04x\n", hJob);
559 nRet = FreePrintJob(hJob);
564 * The following two function would allow a page to be sent to the printer
565 * when it has been processed. For simplicity they havn't been implemented.
566 * This means a whole job has to be processed before it is sent to the printer.
569 /**********************************************************************
570 * StartSpoolPage (GDI.246)
573 int WINAPI StartSpoolPage16(HANDLE16 hJob)
575 FIXME("StartSpoolPage GDI.246 unimplemented\n");
581 /**********************************************************************
582 * EndSpoolPage (GDI.247)
585 int WINAPI EndSpoolPage16(HANDLE16 hJob)
587 FIXME("EndSpoolPage GDI.247 unimplemented\n");
592 /**********************************************************************
593 * GetSpoolJob (GDI.245)
596 DWORD WINAPI GetSpoolJob16(int nOption, LONG param)
599 TRACE("In GetSpoolJob param 0x%lx noption %d\n",param, nOption);
604 /******************************************************************
605 * DrvGetPrinterDataInternal
607 * Helper for DrvGetPrinterData
609 static DWORD DrvGetPrinterDataInternal(LPSTR RegStr_Printer,
610 LPBYTE lpPrinterData, int cbData, int what)
614 DWORD dwType, cbQueryData;
616 if (!(RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey))) {
617 if (what == INT_PD_DEFAULT_DEVMODE) { /* "Default DevMode" */
618 if (!(RegQueryValueExA(hkey, DefaultDevMode, 0, &dwType, 0, &cbQueryData))) {
621 else if ((cbQueryData) && (cbQueryData <= cbData)) {
622 cbQueryData = cbData;
623 if (RegQueryValueExA(hkey, DefaultDevMode, 0,
624 &dwType, lpPrinterData, &cbQueryData))
628 } else { /* "Printer Driver" */
630 RegQueryValueExA(hkey, "Printer Driver", 0,
631 &dwType, lpPrinterData, &cbQueryData);
635 if (hkey) RegCloseKey(hkey);
639 /******************************************************************
640 * DrvGetPrinterData [GDI.282]
643 DWORD WINAPI DrvGetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
644 LPDWORD lpType, LPBYTE lpPrinterData,
645 int cbData, LPDWORD lpNeeded)
647 LPSTR RegStr_Printer;
648 HKEY hkey = 0, hkey2 = 0;
650 DWORD dwType, PrinterAttr, cbPrinterAttr, SetData, size;
652 if (HIWORD(lpPrinter))
653 TRACE("printer %s\n",lpPrinter);
655 TRACE("printer %p\n",lpPrinter);
656 if (HIWORD(lpProfile))
657 TRACE("profile %s\n",lpProfile);
659 TRACE("profile %p\n",lpProfile);
660 TRACE("lpType %p\n",lpType);
662 if ((!lpPrinter) || (!lpProfile) || (!lpNeeded))
663 return ERROR_INVALID_PARAMETER;
665 RegStr_Printer = HeapAlloc(GetProcessHeap(), 0,
666 strlen(Printers) + strlen(lpPrinter) + 2);
667 strcpy(RegStr_Printer, Printers);
668 strcat(RegStr_Printer, lpPrinter);
670 if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
671 (!strcmp(lpProfile, DefaultDevMode)))) {
672 size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
673 INT_PD_DEFAULT_DEVMODE);
676 if ((lpPrinterData) && (*lpNeeded > cbData))
677 res = ERROR_MORE_DATA;
679 else res = ERROR_INVALID_PRINTER_NAME;
682 if (((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
683 (!strcmp(lpProfile, PrinterModel)))) {
685 if (!lpPrinterData) goto failed;
687 res = ERROR_MORE_DATA;
690 size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
691 INT_PD_DEFAULT_MODEL);
692 if ((size+1) && (lpType))
695 res = ERROR_INVALID_PRINTER_NAME;
699 if ((res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)))
702 if ((res = RegQueryValueExA(hkey, "Attributes", 0,
703 &dwType, (LPBYTE)&PrinterAttr, &cbPrinterAttr)))
705 if ((res = RegOpenKeyA(hkey, PrinterDriverData, &hkey2)))
708 res = RegQueryValueExA(hkey2, lpProfile, 0,
709 lpType, lpPrinterData, lpNeeded);
710 if ((res != ERROR_CANTREAD) &&
712 (PRINTER_ATTRIBUTE_ENABLE_BIDI|PRINTER_ATTRIBUTE_NETWORK))
713 == PRINTER_ATTRIBUTE_NETWORK))
715 if (!(res) && (*lpType == REG_DWORD) && (*(LPDWORD)lpPrinterData == -1))
716 res = ERROR_INVALID_DATA;
721 RegSetValueExA(hkey2, lpProfile, 0, REG_DWORD, (LPBYTE)&SetData, 4); /* no result returned */
726 if (hkey2) RegCloseKey(hkey2);
727 if (hkey) RegCloseKey(hkey);
728 HeapFree(GetProcessHeap(), 0, RegStr_Printer);
733 /******************************************************************
734 * DrvSetPrinterData [GDI.281]
737 DWORD WINAPI DrvSetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
738 DWORD lpType, LPBYTE lpPrinterData,
741 LPSTR RegStr_Printer;
745 if (HIWORD(lpPrinter))
746 TRACE("printer %s\n",lpPrinter);
748 TRACE("printer %p\n",lpPrinter);
749 if (HIWORD(lpProfile))
750 TRACE("profile %s\n",lpProfile);
752 TRACE("profile %p\n",lpProfile);
753 TRACE("lpType %08lx\n",lpType);
755 if ((!lpPrinter) || (!lpProfile) ||
756 ((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
757 (!strcmp(lpProfile, PrinterModel))))
758 return ERROR_INVALID_PARAMETER;
760 RegStr_Printer = HeapAlloc(GetProcessHeap(), 0,
761 strlen(Printers) + strlen(lpPrinter) + 2);
762 strcpy(RegStr_Printer, Printers);
763 strcat(RegStr_Printer, lpPrinter);
765 if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
766 (!strcmp(lpProfile, DefaultDevMode)))) {
767 if ( RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)
769 RegSetValueExA(hkey, DefaultDevMode, 0, REG_BINARY,
770 lpPrinterData, dwSize) != ERROR_SUCCESS )
771 res = ERROR_INVALID_PRINTER_NAME;
775 strcat(RegStr_Printer, "\\");
777 if( (res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)) ==
781 res = RegDeleteValueA(hkey, lpProfile);
783 res = RegSetValueExA(hkey, lpProfile, 0, lpType,
784 lpPrinterData, dwSize);
788 if (hkey) RegCloseKey(hkey);
789 HeapFree(GetProcessHeap(), 0, RegStr_Printer);