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 );
213 ERR("Invalid hdc %04x\n", hdc);
217 if(!dc->w.pAbortProc)
219 return dc->w.pAbortProc(hdc, 0);
222 /* ### start build ### */
223 extern WORD CALLBACK PRTDRV_CallTo16_word_ww(FARPROC16,WORD,WORD);
224 /* ### stop build ### */
226 /**********************************************************************
227 * SetAbortProc16 (GDI.381)
230 INT16 WINAPI SetAbortProc16(HDC16 hdc, SEGPTR abrtprc)
232 ABORTPROC proc32 = (ABORTPROC)THUNK_Alloc((FARPROC16)abrtprc,
233 (RELAY)PRTDRV_CallTo16_word_ww);
234 return SetAbortProc(hdc, proc32);
237 /**********************************************************************
238 * SetAbortProc32 (GDI32.301)
241 INT WINAPI SetAbortProc(HDC hdc, ABORTPROC abrtprc)
243 DC *dc = DC_GetDCPtr( hdc );
245 if(dc->w.pAbortProc) THUNK_Free((FARPROC)dc->w.pAbortProc);
246 dc->w.pAbortProc = abrtprc;
251 /****************** misc. printer related functions */
254 * The following function should implement a queing system
263 static struct hpq *hpqueue;
265 /**********************************************************************
269 HPQ16 WINAPI CreatePQ16(INT16 size)
276 tmp_size = size << 2;
277 if (!(hpq = GlobalAlloc16(GMEM_SHARE|GMEM_MOVEABLE, tmp_size + 8)))
279 pPQ = GlobalLock16(hpq);
288 FIXME("(%d): stub\n",size);
293 /**********************************************************************
297 INT16 WINAPI DeletePQ16(HPQ16 hPQ)
299 return GlobalFree16((HGLOBAL16)hPQ);
302 /**********************************************************************
303 * ExtractPQ (GDI.232)
306 INT16 WINAPI ExtractPQ16(HPQ16 hPQ)
308 struct hpq *queue, *prev, *current, *currentPrev;
309 int key = 0, tag = -1;
310 currentPrev = prev = NULL;
311 queue = current = hpqueue;
317 currentPrev = current;
318 current = current->next;
321 if (current->key < key)
333 prev->next = queue->next;
335 hpqueue = queue->next;
339 TRACE("%x got tag %d key %d\n", hPQ, tag, key);
344 /**********************************************************************
348 INT16 WINAPI InsertPQ16(HPQ16 hPQ, INT16 tag, INT16 key)
350 struct hpq *queueItem = xmalloc(sizeof(struct hpq));
351 queueItem->next = hpqueue;
353 queueItem->key = key;
354 queueItem->tag = tag;
356 FIXME("(%x %d %d): stub???\n", hPQ, tag, key);
360 /**********************************************************************
364 INT16 WINAPI MinPQ16(HPQ16 hPQ)
366 FIXME("(%x): stub\n", hPQ);
370 /**********************************************************************
374 INT16 WINAPI SizePQ16(HPQ16 hPQ, INT16 sizechange)
376 FIXME("(%x %d): stub\n", hPQ, sizechange);
383 * The following functions implement part of the spooling process to
384 * print manager. I would like to see wine have a version of print managers
385 * that used LPR/LPD. For simplicity print jobs will be sent to a file for
388 typedef struct PRINTJOB
396 } PRINTJOB, *PPRINTJOB;
398 #define MAX_PRINT_JOBS 1
401 PPRINTJOB gPrintJobsTable[MAX_PRINT_JOBS];
404 static PPRINTJOB FindPrintJobFromHandle(HANDLE16 hHandle)
406 return gPrintJobsTable[0];
409 /* TTD Need to do some DOS->UNIX file conversion here */
410 static int CreateSpoolFile(LPCSTR pszOutput)
414 char *psCmdP = psCmd;
416 /* TTD convert the 'output device' into a spool file name */
418 if (pszOutput == NULL || *pszOutput == '\0')
421 PROFILE_GetWineIniString( "spooler", pszOutput, "", psCmd, sizeof(psCmd) );
422 TRACE("Got printerSpoolCommand '%s' for output device '%s'\n",
425 psCmdP = (char *)pszOutput;
428 while (*psCmdP && isspace(*psCmdP))
444 TRACE("In child need to exec %s\n",psCmdP);
454 TRACE("Need to execute a cmnd and pipe the output to it\n");
458 TRACE("Just assume its a file\n");
460 if ((fd = open(psCmdP, O_CREAT | O_TRUNC | O_WRONLY , 0600)) < 0)
462 ERR("Failed to create spool file %s, errno = %d\n",
469 static int FreePrintJob(HANDLE16 hJob)
474 pPrintJob = FindPrintJobFromHandle(hJob);
475 if (pPrintJob != NULL)
477 gPrintJobsTable[pPrintJob->nIndex] = NULL;
478 free(pPrintJob->pszOutput);
479 free(pPrintJob->pszTitle);
480 if (pPrintJob->fd >= 0) close(pPrintJob->fd);
487 /**********************************************************************
491 HPJOB16 WINAPI OpenJob16(LPCSTR lpOutput, LPCSTR lpTitle, HDC16 hDC)
493 HPJOB16 hHandle = (HPJOB16)SP_ERROR;
496 TRACE("'%s' '%s' %04x\n", lpOutput, lpTitle, hDC);
498 pPrintJob = gPrintJobsTable[0];
499 if (pPrintJob == NULL)
503 /* Try an create a spool file */
504 fd = CreateSpoolFile(lpOutput);
509 pPrintJob = xmalloc(sizeof(PRINTJOB));
510 memset(pPrintJob, 0, sizeof(PRINTJOB));
512 pPrintJob->pszOutput = strdup(lpOutput);
514 pPrintJob->pszTitle = strdup(lpTitle);
515 pPrintJob->hDC = hDC;
517 pPrintJob->nIndex = 0;
518 pPrintJob->hHandle = hHandle;
519 gPrintJobsTable[pPrintJob->nIndex] = pPrintJob;
522 TRACE("return %04x\n", hHandle);
526 /**********************************************************************
530 INT16 WINAPI CloseJob16(HPJOB16 hJob)
533 PPRINTJOB pPrintJob = NULL;
535 TRACE("%04x\n", hJob);
537 pPrintJob = FindPrintJobFromHandle(hJob);
538 if (pPrintJob != NULL)
540 /* Close the spool file */
541 close(pPrintJob->fd);
548 /**********************************************************************
549 * WriteSpool (GDI.241)
552 INT16 WINAPI WriteSpool16(HPJOB16 hJob, LPSTR lpData, INT16 cch)
555 PPRINTJOB pPrintJob = NULL;
557 TRACE("%04x %08lx %04x\n", hJob, (DWORD)lpData, cch);
559 pPrintJob = FindPrintJobFromHandle(hJob);
560 if (pPrintJob != NULL && pPrintJob->fd >= 0 && cch)
562 if (write(pPrintJob->fd, lpData, cch) != cch)
566 if (pPrintJob->hDC == 0) {
567 TRACE("hDC == 0 so no QueryAbort\n");
569 else if (!(QueryAbort16(pPrintJob->hDC, (nRet == SP_OUTOFDISK) ? nRet : 0 )))
571 CloseJob16(hJob); /* printing aborted */
578 /**********************************************************************
579 * WriteDialog (GDI.242)
582 INT16 WINAPI WriteDialog16(HPJOB16 hJob, LPSTR lpMsg, INT16 cchMsg)
586 TRACE("%04x %04x '%s'\n", hJob, cchMsg, lpMsg);
588 nRet = MessageBox16(0, lpMsg, "Printing Error", MB_OKCANCEL);
593 /**********************************************************************
594 * DeleteJob (GDI.244)
597 INT16 WINAPI DeleteJob16(HPJOB16 hJob, INT16 nNotUsed)
601 TRACE("%04x\n", hJob);
603 nRet = FreePrintJob(hJob);
608 * The following two function would allow a page to be sent to the printer
609 * when it has been processed. For simplicity they havn't been implemented.
610 * This means a whole job has to be processed before it is sent to the printer.
613 /**********************************************************************
614 * StartSpoolPage (GDI.246)
617 INT16 WINAPI StartSpoolPage16(HPJOB16 hJob)
619 FIXME("StartSpoolPage GDI.246 unimplemented\n");
625 /**********************************************************************
626 * EndSpoolPage (GDI.247)
629 INT16 WINAPI EndSpoolPage16(HPJOB16 hJob)
631 FIXME("EndSpoolPage GDI.247 unimplemented\n");
636 /**********************************************************************
637 * GetSpoolJob (GDI.245)
640 DWORD WINAPI GetSpoolJob16(int nOption, LONG param)
643 TRACE("In GetSpoolJob param 0x%lx noption %d\n",param, nOption);
648 /******************************************************************
649 * DrvGetPrinterDataInternal
651 * Helper for DrvGetPrinterData
653 static DWORD DrvGetPrinterDataInternal(LPSTR RegStr_Printer,
654 LPBYTE lpPrinterData, int cbData, int what)
658 DWORD dwType, cbQueryData;
660 if (!(RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey))) {
661 if (what == INT_PD_DEFAULT_DEVMODE) { /* "Default DevMode" */
662 if (!(RegQueryValueExA(hkey, DefaultDevMode, 0, &dwType, 0, &cbQueryData))) {
665 else if ((cbQueryData) && (cbQueryData <= cbData)) {
666 cbQueryData = cbData;
667 if (RegQueryValueExA(hkey, DefaultDevMode, 0,
668 &dwType, lpPrinterData, &cbQueryData))
672 } else { /* "Printer Driver" */
674 RegQueryValueExA(hkey, "Printer Driver", 0,
675 &dwType, lpPrinterData, &cbQueryData);
679 if (hkey) RegCloseKey(hkey);
683 /******************************************************************
684 * DrvGetPrinterData [GDI.282]
687 DWORD WINAPI DrvGetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
688 LPDWORD lpType, LPBYTE lpPrinterData,
689 int cbData, LPDWORD lpNeeded)
691 LPSTR RegStr_Printer;
692 HKEY hkey = 0, hkey2 = 0;
694 DWORD dwType, PrinterAttr, cbPrinterAttr, SetData, size;
696 if (HIWORD(lpPrinter))
697 TRACE("printer %s\n",lpPrinter);
699 TRACE("printer %p\n",lpPrinter);
700 if (HIWORD(lpProfile))
701 TRACE("profile %s\n",lpProfile);
703 TRACE("profile %p\n",lpProfile);
704 TRACE("lpType %p\n",lpType);
706 if ((!lpPrinter) || (!lpProfile) || (!lpNeeded))
707 return ERROR_INVALID_PARAMETER;
709 RegStr_Printer = HeapAlloc(GetProcessHeap(), 0,
710 strlen(Printers) + strlen(lpPrinter) + 2);
711 strcpy(RegStr_Printer, Printers);
712 strcat(RegStr_Printer, lpPrinter);
714 if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
715 (!strcmp(lpProfile, DefaultDevMode)))) {
716 size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
717 INT_PD_DEFAULT_DEVMODE);
720 if ((lpPrinterData) && (*lpNeeded > cbData))
721 res = ERROR_MORE_DATA;
723 else res = ERROR_INVALID_PRINTER_NAME;
726 if (((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
727 (!strcmp(lpProfile, PrinterModel)))) {
729 if (!lpPrinterData) goto failed;
731 res = ERROR_MORE_DATA;
734 size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
735 INT_PD_DEFAULT_MODEL);
736 if ((size+1) && (lpType))
739 res = ERROR_INVALID_PRINTER_NAME;
743 if ((res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)))
746 if ((res = RegQueryValueExA(hkey, "Attributes", 0,
747 &dwType, (LPBYTE)&PrinterAttr, &cbPrinterAttr)))
749 if ((res = RegOpenKeyA(hkey, PrinterDriverData, &hkey2)))
752 res = RegQueryValueExA(hkey2, lpProfile, 0,
753 lpType, lpPrinterData, lpNeeded);
754 if ((res != ERROR_CANTREAD) &&
756 (PRINTER_ATTRIBUTE_ENABLE_BIDI|PRINTER_ATTRIBUTE_NETWORK))
757 == PRINTER_ATTRIBUTE_NETWORK))
759 if (!(res) && (*lpType == REG_DWORD) && (*(LPDWORD)lpPrinterData == -1))
760 res = ERROR_INVALID_DATA;
765 RegSetValueExA(hkey2, lpProfile, 0, REG_DWORD, (LPBYTE)&SetData, 4); /* no result returned */
770 if (hkey2) RegCloseKey(hkey2);
771 if (hkey) RegCloseKey(hkey);
772 HeapFree(GetProcessHeap(), 0, RegStr_Printer);
777 /******************************************************************
778 * DrvSetPrinterData [GDI.281]
781 DWORD WINAPI DrvSetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
782 DWORD lpType, LPBYTE lpPrinterData,
785 LPSTR RegStr_Printer;
789 if (HIWORD(lpPrinter))
790 TRACE("printer %s\n",lpPrinter);
792 TRACE("printer %p\n",lpPrinter);
793 if (HIWORD(lpProfile))
794 TRACE("profile %s\n",lpProfile);
796 TRACE("profile %p\n",lpProfile);
797 TRACE("lpType %08lx\n",lpType);
799 if ((!lpPrinter) || (!lpProfile) ||
800 ((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
801 (!strcmp(lpProfile, PrinterModel))))
802 return ERROR_INVALID_PARAMETER;
804 RegStr_Printer = HeapAlloc(GetProcessHeap(), 0,
805 strlen(Printers) + strlen(lpPrinter) + 2);
806 strcpy(RegStr_Printer, Printers);
807 strcat(RegStr_Printer, lpPrinter);
809 if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
810 (!strcmp(lpProfile, DefaultDevMode)))) {
811 if ( RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)
813 RegSetValueExA(hkey, DefaultDevMode, 0, REG_BINARY,
814 lpPrinterData, dwSize) != ERROR_SUCCESS )
815 res = ERROR_INVALID_PRINTER_NAME;
819 strcat(RegStr_Printer, "\\");
821 if( (res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)) ==
825 res = RegDeleteValueA(hkey, lpProfile);
827 res = RegSetValueExA(hkey, lpProfile, 0, lpType,
828 lpPrinterData, dwSize);
832 if (hkey) RegCloseKey(hkey);
833 HeapFree(GetProcessHeap(), 0, RegStr_Printer);