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
20 #include "wine/winbase16.h"
21 #include "wine/wingdi16.h"
25 #include "debugtools.h"
31 DEFAULT_DEBUG_CHANNEL(print);
33 static char PrinterModel[] = "Printer Model";
34 static char DefaultDevMode[] = "Default DevMode";
35 static char PrinterDriverData[] = "PrinterDriverData";
36 static char Printers[] = "System\\CurrentControlSet\\Control\\Print\\Printers\\";
38 /******************************************************************
42 INT16 WINAPI StartDoc16( HDC16 hdc, const DOCINFO16 *lpdoc )
46 docA.cbSize = lpdoc->cbSize;
47 docA.lpszDocName = MapSL(lpdoc->lpszDocName);
48 docA.lpszOutput = MapSL(lpdoc->lpszOutput);
50 if(lpdoc->cbSize >= 14)
51 docA.lpszDatatype = MapSL(lpdoc->lpszDatatype);
53 docA.lpszDatatype = NULL;
55 if(lpdoc->cbSize >= 18)
56 docA.fwType = lpdoc->fwType;
60 return StartDocA(hdc, &docA);
63 /******************************************************************
66 * StartDoc calls the STARTDOC Escape with the input data pointing to DocName
67 * and the output data (which is used as a second input parameter).pointing at
68 * the whole docinfo structure. This seems to be an undocumented feature of
69 * the STARTDOC Escape.
71 INT WINAPI StartDocA(HDC hdc, const DOCINFOA* doc)
74 DC *dc = DC_GetDCPtr( hdc );
76 TRACE("DocName = '%s' Output = '%s' Datatype = '%s'\n",
77 doc->lpszDocName, doc->lpszOutput, doc->lpszDatatype);
79 if(!dc) return SP_ERROR;
81 if(dc->funcs->pStartDoc)
82 ret = dc->funcs->pStartDoc( dc, doc );
84 ret = Escape(hdc, STARTDOC, strlen(doc->lpszDocName),
85 doc->lpszDocName, (LPVOID)doc);
86 GDI_ReleaseObj( hdc );
90 /*************************************************************************
94 INT WINAPI StartDocW(HDC hdc, const DOCINFOW* doc)
99 docA.cbSize = doc->cbSize;
100 docA.lpszDocName = doc->lpszDocName ?
101 HEAP_strdupWtoA( GetProcessHeap(), 0, doc->lpszDocName ) : NULL;
102 docA.lpszOutput = doc->lpszOutput ?
103 HEAP_strdupWtoA( GetProcessHeap(), 0, doc->lpszOutput ) : NULL;
104 docA.lpszDatatype = doc->lpszDatatype ?
105 HEAP_strdupWtoA( GetProcessHeap(), 0, doc->lpszDatatype ) : NULL;
106 docA.fwType = doc->fwType;
108 ret = StartDocA(hdc, &docA);
111 HeapFree( GetProcessHeap(), 0, (LPSTR)docA.lpszDocName );
113 HeapFree( GetProcessHeap(), 0, (LPSTR)docA.lpszOutput );
114 if(docA.lpszDatatype)
115 HeapFree( GetProcessHeap(), 0, (LPSTR)docA.lpszDatatype );
120 /******************************************************************
124 INT16 WINAPI EndDoc16(HDC16 hdc)
129 /******************************************************************
133 INT WINAPI EndDoc(HDC hdc)
136 DC *dc = DC_GetDCPtr( hdc );
137 if(!dc) return SP_ERROR;
139 if(dc->funcs->pEndDoc)
140 ret = dc->funcs->pEndDoc( dc );
142 ret = Escape(hdc, ENDDOC, 0, 0, 0);
143 GDI_ReleaseObj( hdc );
147 /******************************************************************
148 * StartPage [GDI.379]
151 INT16 WINAPI StartPage16(HDC16 hdc)
153 return StartPage(hdc);
156 /******************************************************************
157 * StartPage [GDI32.@]
160 INT WINAPI StartPage(HDC hdc)
163 DC *dc = DC_GetDCPtr( hdc );
164 if(!dc) return SP_ERROR;
166 if(dc->funcs->pStartPage)
167 ret = dc->funcs->pStartPage( dc );
170 GDI_ReleaseObj( hdc );
174 /******************************************************************
178 INT16 WINAPI EndPage16( HDC16 hdc )
183 /******************************************************************
187 INT WINAPI EndPage(HDC hdc)
190 DC *dc = DC_GetDCPtr( hdc );
191 if(!dc) return SP_ERROR;
193 if(dc->funcs->pEndPage)
194 ret = dc->funcs->pEndPage( dc );
196 ret = Escape(hdc, NEWFRAME, 0, 0, 0);
197 GDI_ReleaseObj( hdc );
198 if (!QueryAbort16( hdc, 0 ))
206 /******************************************************************************
209 INT16 WINAPI AbortDoc16(HDC16 hdc)
211 return AbortDoc(hdc);
214 /******************************************************************************
217 INT WINAPI AbortDoc(HDC hdc)
220 DC *dc = DC_GetDCPtr( hdc );
221 if(!dc) return SP_ERROR;
223 if(dc->funcs->pAbortDoc)
224 ret = dc->funcs->pAbortDoc( dc );
226 ret = Escape(hdc, ABORTDOC, 0, 0, 0);
227 GDI_ReleaseObj( hdc );
231 /**********************************************************************
232 * QueryAbort (GDI.155)
234 * Calls the app's AbortProc function if avail.
237 * TRUE if no AbortProc avail or AbortProc wants to continue printing.
238 * FALSE if AbortProc wants to abort printing.
240 BOOL16 WINAPI QueryAbort16(HDC16 hdc, INT16 reserved)
243 DC *dc = DC_GetDCPtr( hdc );
246 ERR("Invalid hdc %04x\n", hdc);
250 if (dc->pAbortProc) ret = dc->pAbortProc(hdc, 0);
251 GDI_ReleaseObj( hdc );
255 /* ### start build ### */
256 extern WORD CALLBACK PRTDRV_CallTo16_word_ww(FARPROC16,WORD,WORD);
257 /* ### stop build ### */
259 /**********************************************************************
260 * SetAbortProc (GDI.381)
263 INT16 WINAPI SetAbortProc16(HDC16 hdc, SEGPTR abrtprc)
265 ABORTPROC proc32 = (ABORTPROC)THUNK_Alloc((FARPROC16)abrtprc,
266 (RELAY)PRTDRV_CallTo16_word_ww);
267 return SetAbortProc(hdc, proc32);
270 /**********************************************************************
271 * SetAbortProc (GDI32.@)
274 INT WINAPI SetAbortProc(HDC hdc, ABORTPROC abrtprc)
276 DC *dc = DC_GetDCPtr( hdc );
278 if(dc->pAbortProc) THUNK_Free((FARPROC)dc->pAbortProc);
279 dc->pAbortProc = abrtprc;
280 GDI_ReleaseObj( hdc );
285 /****************** misc. printer related functions */
288 * The following function should implement a queing system
297 static struct hpq *hpqueue;
299 /**********************************************************************
303 HPQ16 WINAPI CreatePQ16(INT16 size)
310 tmp_size = size << 2;
311 if (!(hpq = GlobalAlloc16(GMEM_SHARE|GMEM_MOVEABLE, tmp_size + 8)))
313 pPQ = GlobalLock16(hpq);
322 FIXME("(%d): stub\n",size);
327 /**********************************************************************
331 INT16 WINAPI DeletePQ16(HPQ16 hPQ)
333 return GlobalFree16((HGLOBAL16)hPQ);
336 /**********************************************************************
337 * ExtractPQ (GDI.232)
340 INT16 WINAPI ExtractPQ16(HPQ16 hPQ)
342 struct hpq *queue, *prev, *current, *currentPrev;
343 int key = 0, tag = -1;
344 currentPrev = prev = NULL;
345 queue = current = hpqueue;
351 currentPrev = current;
352 current = current->next;
355 if (current->key < key)
367 prev->next = queue->next;
369 hpqueue = queue->next;
370 HeapFree(GetProcessHeap(), 0, queue);
373 TRACE("%x got tag %d key %d\n", hPQ, tag, key);
378 /**********************************************************************
382 INT16 WINAPI InsertPQ16(HPQ16 hPQ, INT16 tag, INT16 key)
384 struct hpq *queueItem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct hpq));
385 if(queueItem == NULL) {
386 ERR("Memory exausted!\n");
389 queueItem->next = hpqueue;
391 queueItem->key = key;
392 queueItem->tag = tag;
394 FIXME("(%x %d %d): stub???\n", hPQ, tag, key);
398 /**********************************************************************
402 INT16 WINAPI MinPQ16(HPQ16 hPQ)
404 FIXME("(%x): stub\n", hPQ);
408 /**********************************************************************
412 INT16 WINAPI SizePQ16(HPQ16 hPQ, INT16 sizechange)
414 FIXME("(%x %d): stub\n", hPQ, sizechange);
421 * The following functions implement part of the spooling process to
422 * print manager. I would like to see wine have a version of print managers
423 * that used LPR/LPD. For simplicity print jobs will be sent to a file for
426 typedef struct PRINTJOB
434 } PRINTJOB, *PPRINTJOB;
436 #define MAX_PRINT_JOBS 1
439 PPRINTJOB gPrintJobsTable[MAX_PRINT_JOBS];
442 static PPRINTJOB FindPrintJobFromHandle(HANDLE16 hHandle)
444 return gPrintJobsTable[0];
447 static int CreateSpoolFile(LPCSTR pszOutput)
451 char *psCmdP = psCmd;
453 /* TTD convert the 'output device' into a spool file name */
455 if (pszOutput == NULL || *pszOutput == '\0')
458 if (!strncmp("LPR:",pszOutput,4))
459 sprintf(psCmd,"|lpr -P%s",pszOutput+4);
465 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\spooler", &hkey))
467 DWORD type, count = sizeof(psCmd);
468 RegQueryValueExA(hkey, pszOutput, 0, &type, psCmd, &count);
472 TRACE("Got printerSpoolCommand '%s' for output device '%s'\n",
475 psCmdP = (char *)pszOutput;
478 while (*psCmdP && isspace(*psCmdP))
494 TRACE("In child need to exec %s\n",psCmdP);
504 TRACE("Need to execute a cmnd and pipe the output to it\n");
508 DOS_FULL_NAME fullName;
510 TRACE("Just assume it's a file\n");
513 * The file name can be dos based, we have to find its
514 * Unix correspondant file name
516 DOSFS_GetFullName(psCmdP, FALSE, &fullName);
518 if ((fd = open(fullName.long_name, O_CREAT | O_TRUNC | O_WRONLY , 0600)) < 0)
520 ERR("Failed to create spool file %s (%s)\n",
521 fullName.long_name, strerror(errno));
527 static int FreePrintJob(HANDLE16 hJob)
532 pPrintJob = FindPrintJobFromHandle(hJob);
533 if (pPrintJob != NULL)
535 gPrintJobsTable[pPrintJob->nIndex] = NULL;
536 HeapFree(GetProcessHeap(), 0, pPrintJob->pszOutput);
537 HeapFree(GetProcessHeap(), 0, pPrintJob->pszTitle);
538 if (pPrintJob->fd >= 0) close(pPrintJob->fd);
539 HeapFree(GetProcessHeap(), 0, pPrintJob);
545 /**********************************************************************
549 HPJOB16 WINAPI OpenJob16(LPCSTR lpOutput, LPCSTR lpTitle, HDC16 hDC)
551 HPJOB16 hHandle = (HPJOB16)SP_ERROR;
554 TRACE("'%s' '%s' %04x\n", lpOutput, lpTitle, hDC);
556 pPrintJob = gPrintJobsTable[0];
557 if (pPrintJob == NULL)
561 /* Try an create a spool file */
562 fd = CreateSpoolFile(lpOutput);
565 pPrintJob = HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTJOB));
566 if(pPrintJob == NULL) {
567 WARN("Memory exausted!\n");
573 pPrintJob->pszOutput = HEAP_strdupA(GetProcessHeap(), 0, lpOutput);
575 pPrintJob->pszTitle = HEAP_strdupA(GetProcessHeap(), 0, lpTitle);
576 pPrintJob->hDC = hDC;
578 pPrintJob->nIndex = 0;
579 pPrintJob->hHandle = hHandle;
580 gPrintJobsTable[pPrintJob->nIndex] = pPrintJob;
583 TRACE("return %04x\n", hHandle);
587 /**********************************************************************
591 INT16 WINAPI CloseJob16(HPJOB16 hJob)
594 PPRINTJOB pPrintJob = NULL;
596 TRACE("%04x\n", hJob);
598 pPrintJob = FindPrintJobFromHandle(hJob);
599 if (pPrintJob != NULL)
601 /* Close the spool file */
602 close(pPrintJob->fd);
609 /**********************************************************************
610 * WriteSpool (GDI.241)
613 INT16 WINAPI WriteSpool16(HPJOB16 hJob, LPSTR lpData, INT16 cch)
616 PPRINTJOB pPrintJob = NULL;
618 TRACE("%04x %08lx %04x\n", hJob, (DWORD)lpData, cch);
620 pPrintJob = FindPrintJobFromHandle(hJob);
621 if (pPrintJob != NULL && pPrintJob->fd >= 0 && cch)
623 if (write(pPrintJob->fd, lpData, cch) != cch)
628 /* FIXME: We just cannot call 16 bit functions from here, since we
629 * have acquired several locks (DC). And we do not really need to.
631 if (pPrintJob->hDC == 0) {
632 TRACE("hDC == 0 so no QueryAbort\n");
634 else if (!(QueryAbort16(pPrintJob->hDC, (nRet == SP_OUTOFDISK) ? nRet : 0 )))
636 CloseJob16(hJob); /* printing aborted */
644 typedef INT WINAPI (*MSGBOX_PROC)( HWND, LPCSTR, LPCSTR, UINT );
646 /**********************************************************************
647 * WriteDialog (GDI.242)
650 INT16 WINAPI WriteDialog16(HPJOB16 hJob, LPSTR lpMsg, INT16 cchMsg)
653 MSGBOX_PROC pMessageBoxA;
656 TRACE("%04x %04x '%s'\n", hJob, cchMsg, lpMsg);
658 if ((mod = GetModuleHandleA("user32.dll")))
660 if ((pMessageBoxA = (MSGBOX_PROC)GetProcAddress( mod, "MessageBoxA" )))
661 ret = pMessageBoxA(0, lpMsg, "Printing Error", MB_OKCANCEL);
667 /**********************************************************************
668 * DeleteJob (GDI.244)
671 INT16 WINAPI DeleteJob16(HPJOB16 hJob, INT16 nNotUsed)
675 TRACE("%04x\n", hJob);
677 nRet = FreePrintJob(hJob);
682 * The following two function would allow a page to be sent to the printer
683 * when it has been processed. For simplicity they havn't been implemented.
684 * This means a whole job has to be processed before it is sent to the printer.
687 /**********************************************************************
688 * StartSpoolPage (GDI.246)
691 INT16 WINAPI StartSpoolPage16(HPJOB16 hJob)
693 FIXME("StartSpoolPage GDI.246 unimplemented\n");
699 /**********************************************************************
700 * EndSpoolPage (GDI.247)
703 INT16 WINAPI EndSpoolPage16(HPJOB16 hJob)
705 FIXME("EndSpoolPage GDI.247 unimplemented\n");
710 /**********************************************************************
711 * GetSpoolJob (GDI.245)
714 DWORD WINAPI GetSpoolJob16(int nOption, LONG param)
717 TRACE("In GetSpoolJob param 0x%lx noption %d\n",param, nOption);
722 /******************************************************************
723 * DrvGetPrinterDataInternal
725 * Helper for DrvGetPrinterData
727 static DWORD DrvGetPrinterDataInternal(LPSTR RegStr_Printer,
728 LPBYTE lpPrinterData, int cbData, int what)
732 DWORD dwType, cbQueryData;
734 if (!(RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey))) {
735 if (what == INT_PD_DEFAULT_DEVMODE) { /* "Default DevMode" */
736 if (!(RegQueryValueExA(hkey, DefaultDevMode, 0, &dwType, 0, &cbQueryData))) {
739 else if ((cbQueryData) && (cbQueryData <= cbData)) {
740 cbQueryData = cbData;
741 if (RegQueryValueExA(hkey, DefaultDevMode, 0,
742 &dwType, lpPrinterData, &cbQueryData))
746 } else { /* "Printer Driver" */
748 RegQueryValueExA(hkey, "Printer Driver", 0,
749 &dwType, lpPrinterData, &cbQueryData);
753 if (hkey) RegCloseKey(hkey);
757 /******************************************************************
758 * DrvGetPrinterData [GDI.282]
761 DWORD WINAPI DrvGetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
762 LPDWORD lpType, LPBYTE lpPrinterData,
763 int cbData, LPDWORD lpNeeded)
765 LPSTR RegStr_Printer;
766 HKEY hkey = 0, hkey2 = 0;
768 DWORD dwType, PrinterAttr, cbPrinterAttr, SetData, size;
770 if (HIWORD(lpPrinter))
771 TRACE("printer %s\n",lpPrinter);
773 TRACE("printer %p\n",lpPrinter);
774 if (HIWORD(lpProfile))
775 TRACE("profile %s\n",lpProfile);
777 TRACE("profile %p\n",lpProfile);
778 TRACE("lpType %p\n",lpType);
780 if ((!lpPrinter) || (!lpProfile) || (!lpNeeded))
781 return ERROR_INVALID_PARAMETER;
783 RegStr_Printer = HeapAlloc(GetProcessHeap(), 0,
784 strlen(Printers) + strlen(lpPrinter) + 2);
785 strcpy(RegStr_Printer, Printers);
786 strcat(RegStr_Printer, lpPrinter);
788 if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
789 (!strcmp(lpProfile, DefaultDevMode)))) {
790 size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
791 INT_PD_DEFAULT_DEVMODE);
794 if ((lpPrinterData) && (*lpNeeded > cbData))
795 res = ERROR_MORE_DATA;
797 else res = ERROR_INVALID_PRINTER_NAME;
800 if (((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
801 (!strcmp(lpProfile, PrinterModel)))) {
803 if (!lpPrinterData) goto failed;
805 res = ERROR_MORE_DATA;
808 size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
809 INT_PD_DEFAULT_MODEL);
810 if ((size+1) && (lpType))
813 res = ERROR_INVALID_PRINTER_NAME;
817 if ((res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)))
820 if ((res = RegQueryValueExA(hkey, "Attributes", 0,
821 &dwType, (LPBYTE)&PrinterAttr, &cbPrinterAttr)))
823 if ((res = RegOpenKeyA(hkey, PrinterDriverData, &hkey2)))
826 res = RegQueryValueExA(hkey2, lpProfile, 0,
827 lpType, lpPrinterData, lpNeeded);
828 if ((res != ERROR_CANTREAD) &&
830 (PRINTER_ATTRIBUTE_ENABLE_BIDI|PRINTER_ATTRIBUTE_NETWORK))
831 == PRINTER_ATTRIBUTE_NETWORK))
833 if (!(res) && (*lpType == REG_DWORD) && (*(LPDWORD)lpPrinterData == -1))
834 res = ERROR_INVALID_DATA;
839 RegSetValueExA(hkey2, lpProfile, 0, REG_DWORD, (LPBYTE)&SetData, 4); /* no result returned */
844 if (hkey2) RegCloseKey(hkey2);
845 if (hkey) RegCloseKey(hkey);
846 HeapFree(GetProcessHeap(), 0, RegStr_Printer);
851 /******************************************************************
852 * DrvSetPrinterData [GDI.281]
855 DWORD WINAPI DrvSetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
856 DWORD lpType, LPBYTE lpPrinterData,
859 LPSTR RegStr_Printer;
863 if (HIWORD(lpPrinter))
864 TRACE("printer %s\n",lpPrinter);
866 TRACE("printer %p\n",lpPrinter);
867 if (HIWORD(lpProfile))
868 TRACE("profile %s\n",lpProfile);
870 TRACE("profile %p\n",lpProfile);
871 TRACE("lpType %08lx\n",lpType);
873 if ((!lpPrinter) || (!lpProfile) ||
874 ((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
875 (!strcmp(lpProfile, PrinterModel))))
876 return ERROR_INVALID_PARAMETER;
878 RegStr_Printer = HeapAlloc(GetProcessHeap(), 0,
879 strlen(Printers) + strlen(lpPrinter) + 2);
880 strcpy(RegStr_Printer, Printers);
881 strcat(RegStr_Printer, lpPrinter);
883 if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
884 (!strcmp(lpProfile, DefaultDevMode)))) {
885 if ( RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)
887 RegSetValueExA(hkey, DefaultDevMode, 0, REG_BINARY,
888 lpPrinterData, dwSize) != ERROR_SUCCESS )
889 res = ERROR_INVALID_PRINTER_NAME;
893 strcat(RegStr_Printer, "\\");
895 if( (res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)) ==
899 res = RegDeleteValueA(hkey, lpProfile);
901 res = RegSetValueExA(hkey, lpProfile, 0, lpType,
902 lpPrinterData, dwSize);
906 if (hkey) RegCloseKey(hkey);
907 HeapFree(GetProcessHeap(), 0, RegStr_Printer);