Workaroung gcc 2.7.2.x sig 11 issue.
[wine.git] / misc / printdrv.c
blob2aac7a94cb1fe50361da558300f0a85e89099d54
1 /*
2 * Implementation of some printer driver bits
3 *
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Huw Davies
6 * Copyright 1998 Andreas Mohr
7 * Copyright 1999 Klaas van Gend
8 */
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include "ldt.h"
17 #include "winbase.h"
18 #include "wine/wingdi16.h"
19 #include "winspool.h"
20 #include "winerror.h"
21 #include "winreg.h"
22 #include "debugtools.h"
23 #include "gdi.h"
24 #include "dc.h"
25 #include "callback.h"
26 #include "xmalloc.h"
27 #include "options.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 )
42 INT16 retVal;
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);
53 return retVal;
56 /******************************************************************
57 * EndPage16 [GDI.380]
60 INT16 WINAPI EndPage16( HDC16 hdc )
62 INT16 retVal;
63 retVal = Escape16(hdc, NEWFRAME, 0, 0, 0);
64 TRACE("Escape16 returned %d\n",retVal);
65 return retVal;
68 /******************************************************************
69 * StartDoc32A [GDI32.347]
72 INT WINAPI StartDocA(HDC hdc ,const DOCINFOA* doc)
74 return Escape(hdc,
75 STARTDOC,
76 strlen(doc->lpszDocName),
77 doc->lpszDocName,
78 0);
81 /*************************************************************************
82 * StartDoc32W [GDI32.348]
85 INT WINAPI StartDocW(HDC hdc, const DOCINFOW* doc) {
86 FIXME("stub\n");
87 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
88 return 0; /* failure*/
91 /******************************************************************
92 * StartPage32 [GDI32.349]
95 INT WINAPI StartPage(HDC hdc)
97 FIXME("stub\n");
98 return 1;
101 /******************************************************************
102 * EndPage32 [GDI32.77]
105 INT WINAPI EndPage(HDC hdc)
107 return Escape(hdc, NEWFRAME, 0, 0, 0);
110 /******************************************************************
111 * EndDoc16 [GDI.378]
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);
142 return 1;
145 /**********************************************************************
146 * QueryAbort (GDI.155)
148 * Calls the app's AbortProc function if avail.
150 * RETURNS
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))
159 return TRUE;
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)
178 FIXME("stub\n");
179 return 1;
183 /****************** misc. printer related functions */
186 * The following function should implement a queing system
188 #ifndef HPQ
189 #define HPQ WORD
190 #endif
191 struct hpq
193 struct hpq *next;
194 int tag;
195 int key;
198 static struct hpq *hpqueue;
200 /**********************************************************************
201 * CreatePQ (GDI.230)
204 HPQ WINAPI CreatePQ16(int size)
206 #if 0
207 HGLOBAL16 hpq = 0;
208 WORD tmp_size;
209 LPWORD pPQ;
211 tmp_size = size << 2;
212 if (!(hpq = GlobalAlloc16(GMEM_SHARE|GMEM_MOVEABLE, tmp_size + 8)))
213 return 0xffff;
214 pPQ = GlobalLock16(hpq);
215 *pPQ++ = 0;
216 *pPQ++ = tmp_size;
217 *pPQ++ = 0;
218 *pPQ++ = 0;
219 GlobalUnlock16(hpq);
221 return (HPQ)hpq;
222 #else
223 FIXME("(%d): stub\n",size);
224 return 1;
225 #endif
228 /**********************************************************************
229 * DeletePQ (GDI.235)
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;
247 if (current)
248 key = current->key;
250 while (current)
252 currentPrev = current;
253 current = current->next;
254 if (current)
256 if (current->key < key)
258 queue = current;
259 prev = currentPrev;
263 if (queue)
265 tag = queue->tag;
267 if (prev)
268 prev->next = queue->next;
269 else
270 hpqueue = queue->next;
271 free(queue);
274 TRACE("%x got tag %d key %d\n", hPQ, tag, key);
276 return tag;
279 /**********************************************************************
280 * InsertPQ (GDI.233)
283 int WINAPI InsertPQ16(HPQ hPQ, int tag, int key)
285 struct hpq *queueItem = xmalloc(sizeof(struct hpq));
286 queueItem->next = hpqueue;
287 hpqueue = queueItem;
288 queueItem->key = key;
289 queueItem->tag = tag;
291 FIXME("(%x %d %d): stub???\n", hPQ, tag, key);
292 return TRUE;
295 /**********************************************************************
296 * MinPQ (GDI.231)
299 int WINAPI MinPQ16(HPQ hPQ)
301 FIXME("(%x): stub\n", hPQ);
302 return 0;
305 /**********************************************************************
306 * SizePQ (GDI.234)
309 int WINAPI SizePQ16(HPQ hPQ, int sizechange)
311 FIXME("(%x %d): stub\n", hPQ, sizechange);
312 return -1;
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
321 * now.
323 typedef struct PRINTJOB
325 char *pszOutput;
326 char *pszTitle;
327 HDC16 hDC;
328 HANDLE16 hHandle;
329 int nIndex;
330 int fd;
331 } PRINTJOB, *PPRINTJOB;
333 #define MAX_PRINT_JOBS 1
334 #define SP_OK 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)
347 int fd=-1;
348 char psCmd[1024];
349 char *psCmdP = psCmd;
351 /* TTD convert the 'output device' into a spool file name */
353 if (pszOutput == NULL || *pszOutput == '\0')
354 return -1;
356 PROFILE_GetWineIniString( "spooler", pszOutput, "", psCmd, sizeof(psCmd) );
357 TRACE("Got printerSpoolCommand '%s' for output device '%s'\n",
358 psCmd, pszOutput);
359 if (!*psCmd)
360 psCmdP = pszOutput;
361 else
363 while (*psCmdP && isspace(*psCmdP))
365 psCmdP++;
367 if (!*psCmdP)
368 return -1;
370 if (*psCmdP == '|')
372 int fds[2];
373 if (pipe(fds))
374 return -1;
375 if (fork() == 0)
377 psCmdP++;
379 TRACE("In child need to exec %s\n",psCmdP);
380 close(0);
381 dup2(fds[0],0);
382 close (fds[1]);
383 system(psCmdP);
384 exit(0);
387 close (fds[0]);
388 fd = fds[1];
389 TRACE("Need to execute a cmnd and pipe the output to it\n");
391 else
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",
398 psCmdP, errno);
401 return fd;
404 static int FreePrintJob(HANDLE16 hJob)
406 int nRet = SP_ERROR;
407 PPRINTJOB pPrintJob;
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);
416 free(pPrintJob);
417 nRet = SP_OK;
419 return nRet;
422 /**********************************************************************
423 * OpenJob (GDI.240)
426 HANDLE16 WINAPI OpenJob16(LPSTR lpOutput, LPSTR lpTitle, HDC16 hDC)
428 HANDLE16 hHandle = (HANDLE16)SP_ERROR;
429 PPRINTJOB pPrintJob;
431 TRACE("'%s' '%s' %04x\n", lpOutput, lpTitle, hDC);
433 pPrintJob = gPrintJobsTable[0];
434 if (pPrintJob == NULL)
436 int fd;
438 /* Try an create a spool file */
439 fd = CreateSpoolFile(lpOutput);
440 if (fd >= 0)
442 hHandle = 1;
444 pPrintJob = xmalloc(sizeof(PRINTJOB));
445 memset(pPrintJob, 0, sizeof(PRINTJOB));
447 pPrintJob->pszOutput = strdup(lpOutput);
448 if(lpTitle)
449 pPrintJob->pszTitle = strdup(lpTitle);
450 pPrintJob->hDC = hDC;
451 pPrintJob->fd = fd;
452 pPrintJob->nIndex = 0;
453 pPrintJob->hHandle = hHandle;
454 gPrintJobsTable[pPrintJob->nIndex] = pPrintJob;
457 TRACE("return %04x\n", hHandle);
458 return hHandle;
461 /**********************************************************************
462 * CloseJob (GDI.243)
465 int WINAPI CloseJob16(HANDLE16 hJob)
467 int nRet = SP_ERROR;
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);
477 FreePrintJob(hJob);
478 nRet = 1;
480 return nRet;
483 /**********************************************************************
484 * WriteSpool (GDI.241)
487 int WINAPI WriteSpool16(HANDLE16 hJob, LPSTR lpData, WORD cch)
489 int nRet = SP_ERROR;
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)
498 nRet = SP_OUTOFDISK;
499 else
500 nRet = 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 */
507 nRet = SP_APPABORT;
510 return nRet;
513 /**********************************************************************
514 * WriteDialog (GDI.242)
517 int WINAPI WriteDialog16(HANDLE16 hJob, LPSTR lpMsg, WORD cchMsg)
519 int nRet = 0;
521 TRACE("%04x %04x '%s'\n", hJob, cchMsg, lpMsg);
523 nRet = MessageBox16(0, lpMsg, "Printing Error", MB_OKCANCEL);
524 return nRet;
528 /**********************************************************************
529 * DeleteJob (GDI.244)
532 int WINAPI DeleteJob16(HANDLE16 hJob, WORD wNotUsed)
534 int nRet;
536 TRACE("%04x\n", hJob);
538 nRet = FreePrintJob(hJob);
539 return nRet;
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");
555 return 1;
560 /**********************************************************************
561 * EndSpoolPage (GDI.247)
564 int WINAPI EndSpoolPage16(HANDLE16 hJob)
566 FIXME("EndSpoolPage GDI.247 unimplemented\n");
567 return 1;
571 /**********************************************************************
572 * GetSpoolJob (GDI.245)
575 DWORD WINAPI GetSpoolJob16(int nOption, LONG param)
577 DWORD retval = 0;
578 TRACE("In GetSpoolJob param 0x%lx noption %d\n",param, nOption);
579 return retval;
583 /******************************************************************
584 * DrvGetPrinterDataInternal
586 * Helper for DrvGetPrinterData
588 static DWORD DrvGetPrinterDataInternal(LPSTR RegStr_Printer,
589 LPBYTE lpPrinterData, int cbData, int what)
591 DWORD res = -1;
592 HKEY hkey;
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))) {
598 if (!lpPrinterData)
599 res = cbQueryData;
600 else if ((cbQueryData) && (cbQueryData <= cbData)) {
601 cbQueryData = cbData;
602 if (RegQueryValueExA(hkey, DefaultDevMode, 0,
603 &dwType, lpPrinterData, &cbQueryData))
604 res = cbQueryData;
607 } else { /* "Printer Driver" */
608 cbQueryData = 32;
609 RegQueryValueExA(hkey, "Printer Driver", 0,
610 &dwType, lpPrinterData, &cbQueryData);
611 res = cbQueryData;
614 if (hkey) RegCloseKey(hkey);
615 return res;
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;
628 DWORD res = 0;
629 DWORD dwType, PrinterAttr, cbPrinterAttr, SetData, size;
631 if (HIWORD(lpPrinter))
632 TRACE("printer %s\n",lpPrinter);
633 else
634 TRACE("printer %p\n",lpPrinter);
635 if (HIWORD(lpProfile))
636 TRACE("profile %s\n",lpProfile);
637 else
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);
653 if (size+1) {
654 *lpNeeded = size;
655 if ((lpPrinterData) && (*lpNeeded > cbData))
656 res = ERROR_MORE_DATA;
658 else res = ERROR_INVALID_PRINTER_NAME;
660 else
661 if (((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
662 (!strcmp(lpProfile, PrinterModel)))) {
663 *lpNeeded = 32;
664 if (!lpPrinterData) goto failed;
665 if (cbData < 32) {
666 res = ERROR_MORE_DATA;
667 goto failed;
669 size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
670 INT_PD_DEFAULT_MODEL);
671 if ((size+1) && (lpType))
672 *lpType = REG_SZ;
673 else
674 res = ERROR_INVALID_PRINTER_NAME;
676 else
678 if ((res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)))
679 goto failed;
680 cbPrinterAttr = 4;
681 if ((res = RegQueryValueExA(hkey, "Attributes", 0,
682 &dwType, (LPBYTE)&PrinterAttr, &cbPrinterAttr)))
683 goto failed;
684 if ((res = RegOpenKeyA(hkey, PrinterDriverData, &hkey2)))
685 goto failed;
686 *lpNeeded = cbData;
687 res = RegQueryValueExA(hkey2, lpProfile, 0,
688 lpType, lpPrinterData, lpNeeded);
689 if ((res != ERROR_CANTREAD) &&
690 ((PrinterAttr &
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;
697 else
699 SetData = -1;
700 RegSetValueExA(hkey2, lpProfile, 0, REG_DWORD, (LPBYTE)&SetData, 4); /* no result returned */
704 failed:
705 if (hkey2) RegCloseKey(hkey2);
706 if (hkey) RegCloseKey(hkey);
707 HeapFree(GetProcessHeap(), 0, RegStr_Printer);
708 return res;
712 /******************************************************************
713 * DrvSetPrinterData [GDI.281]
716 DWORD WINAPI DrvSetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
717 DWORD lpType, LPBYTE lpPrinterData,
718 DWORD dwSize)
720 LPSTR RegStr_Printer;
721 HKEY hkey = 0;
722 DWORD res = 0;
724 if (HIWORD(lpPrinter))
725 TRACE("printer %s\n",lpPrinter);
726 else
727 TRACE("printer %p\n",lpPrinter);
728 if (HIWORD(lpProfile))
729 TRACE("profile %s\n",lpProfile);
730 else
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)
747 != ERROR_SUCCESS ||
748 RegSetValueExA(hkey, DefaultDevMode, 0, REG_BINARY,
749 lpPrinterData, dwSize) != ERROR_SUCCESS )
750 res = ERROR_INVALID_PRINTER_NAME;
752 else
754 strcat(RegStr_Printer, "\\");
756 if( (res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)) ==
757 ERROR_SUCCESS ) {
759 if (!lpPrinterData)
760 res = RegDeleteValueA(hkey, lpProfile);
761 else
762 res = RegSetValueExA(hkey, lpProfile, 0, lpType,
763 lpPrinterData, dwSize);
767 if (hkey) RegCloseKey(hkey);
768 HeapFree(GetProcessHeap(), 0, RegStr_Printer);
769 return res;