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);