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
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wine/winbase16.h"
34 #include "wine/wingdi16.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(print
);
43 static const char PrinterModel
[] = "Printer Model";
44 static const char DefaultDevMode
[] = "Default DevMode";
45 static const char PrinterDriverData
[] = "PrinterDriverData";
46 static const char Printers
[] = "System\\CurrentControlSet\\Control\\Print\\Printers\\";
48 /****************** misc. printer related functions */
51 * The following function should implement a queuing system
60 static struct hpq
*hpqueue
;
62 /**********************************************************************
66 HPQ16 WINAPI
CreatePQ16(INT16 size
)
74 if (!(hpq
= GlobalAlloc16(GMEM_SHARE
|GMEM_MOVEABLE
, tmp_size
+ 8)))
76 pPQ
= GlobalLock16(hpq
);
85 FIXME("(%d): stub\n",size
);
90 /**********************************************************************
94 INT16 WINAPI
DeletePQ16(HPQ16 hPQ
)
96 return GlobalFree16(hPQ
);
99 /**********************************************************************
100 * ExtractPQ (GDI.232)
103 INT16 WINAPI
ExtractPQ16(HPQ16 hPQ
)
105 struct hpq
*queue
, *prev
, *current
, *currentPrev
;
106 int key
= 0, tag
= -1;
108 queue
= current
= hpqueue
;
114 currentPrev
= current
;
115 current
= current
->next
;
118 if (current
->key
< key
)
130 prev
->next
= queue
->next
;
132 hpqueue
= queue
->next
;
133 HeapFree(GetProcessHeap(), 0, queue
);
136 TRACE("%x got tag %d key %d\n", hPQ
, tag
, key
);
141 /**********************************************************************
145 INT16 WINAPI
InsertPQ16(HPQ16 hPQ
, INT16 tag
, INT16 key
)
147 struct hpq
*queueItem
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct hpq
));
148 if(queueItem
== NULL
) {
149 ERR("Memory exhausted!\n");
152 queueItem
->next
= hpqueue
;
154 queueItem
->key
= key
;
155 queueItem
->tag
= tag
;
157 FIXME("(%x %d %d): stub???\n", hPQ
, tag
, key
);
161 /**********************************************************************
165 INT16 WINAPI
MinPQ16(HPQ16 hPQ
)
167 FIXME("(%x): stub\n", hPQ
);
171 /**********************************************************************
175 INT16 WINAPI
SizePQ16(HPQ16 hPQ
, INT16 sizechange
)
177 FIXME("(%x %d): stub\n", hPQ
, sizechange
);
184 * The following functions implement part of the spooling process to
185 * print manager. I would like to see wine have a version of print managers
186 * that used LPR/LPD. For simplicity print jobs will be sent to a file for
189 typedef struct PRINTJOB
195 } PRINTJOB
, *PPRINTJOB
;
197 #define MAX_PRINT_JOBS 1
200 static PPRINTJOB gPrintJobsTable
[MAX_PRINT_JOBS
];
203 static PPRINTJOB
FindPrintJobFromHandle(HANDLE16 hHandle
)
205 return gPrintJobsTable
[0];
208 /**********************************************************************
212 HPJOB16 WINAPI
OpenJob16(LPCSTR lpOutput
, LPCSTR lpTitle
, HDC16 hDC
)
214 HPJOB16 hHandle
= (HPJOB16
)SP_ERROR
;
217 TRACE("'%s' '%s' %04x\n", lpOutput
, lpTitle
, hDC
);
219 pPrintJob
= gPrintJobsTable
[0];
220 if (pPrintJob
== NULL
)
222 DOCINFOA info
= { sizeof(info
), lpTitle
, lpOutput
, NULL
, 0 };
225 id
= StartDocA( HDC_32(hDC
), &info
);
228 pPrintJob
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTJOB
));
229 if(pPrintJob
== NULL
) {
230 WARN("Memory exhausted!\n");
236 pPrintJob
->hDC
= hDC
;
238 pPrintJob
->nIndex
= 0;
239 pPrintJob
->hHandle
= hHandle
;
240 gPrintJobsTable
[pPrintJob
->nIndex
] = pPrintJob
;
243 TRACE("return %04x\n", hHandle
);
247 /**********************************************************************
251 INT16 WINAPI
CloseJob16(HPJOB16 hJob
)
256 TRACE("%04x\n", hJob
);
258 pPrintJob
= FindPrintJobFromHandle(hJob
);
259 if (pPrintJob
!= NULL
) nRet
= EndDoc( HDC_32(pPrintJob
->hDC
) );
263 /**********************************************************************
264 * WriteSpool (GDI.241)
267 INT16 WINAPI
WriteSpool16(HPJOB16 hJob
, LPSTR lpData
, INT16 cch
)
272 TRACE("%04x %p %04x\n", hJob
, lpData
, cch
);
274 pPrintJob
= FindPrintJobFromHandle(hJob
);
275 if (pPrintJob
!= NULL
&& cch
)
277 WORD
*data
= HeapAlloc( GetProcessHeap(), 0, cch
+ 2 );
279 if (!data
) return SP_OUTOFDISK
;
281 memcpy( data
+ 1, lpData
, cch
);
282 ExtEscape( HDC_32(pPrintJob
->hDC
), PASSTHROUGH
, cch
+ 2, (char *)data
, 0, NULL
);
283 HeapFree( GetProcessHeap(), 0, data
);
289 typedef INT (WINAPI
*MSGBOX_PROC
)( HWND
, LPCSTR
, LPCSTR
, UINT
);
291 /**********************************************************************
292 * WriteDialog (GDI.242)
295 INT16 WINAPI
WriteDialog16(HPJOB16 hJob
, LPSTR lpMsg
, INT16 cchMsg
)
298 MSGBOX_PROC pMessageBoxA
;
301 TRACE("%04x %04x '%s'\n", hJob
, cchMsg
, lpMsg
);
303 if ((mod
= GetModuleHandleA("user32.dll")))
305 if ((pMessageBoxA
= (MSGBOX_PROC
)GetProcAddress( mod
, "MessageBoxA" )))
306 ret
= pMessageBoxA(0, lpMsg
, "Printing Error", MB_OKCANCEL
);
312 /**********************************************************************
313 * DeleteJob (GDI.244)
316 INT16 WINAPI
DeleteJob16(HPJOB16 hJob
, INT16 nNotUsed
)
318 TRACE("%04x\n", hJob
);
320 return CloseJob16( hJob
);
324 * The following two function would allow a page to be sent to the printer
325 * when it has been processed. For simplicity they haven't been implemented.
326 * This means a whole job has to be processed before it is sent to the printer.
329 /**********************************************************************
330 * StartSpoolPage (GDI.246)
333 INT16 WINAPI
StartSpoolPage16(HPJOB16 hJob
)
335 FIXME("StartSpoolPage GDI.246 unimplemented\n");
341 /**********************************************************************
342 * EndSpoolPage (GDI.247)
345 INT16 WINAPI
EndSpoolPage16(HPJOB16 hJob
)
347 FIXME("EndSpoolPage GDI.247 unimplemented\n");
352 /**********************************************************************
353 * GetSpoolJob (GDI.245)
356 DWORD WINAPI
GetSpoolJob16(int nOption
, LONG param
)
358 TRACE("In GetSpoolJob param 0x%x noption %d\n",param
, nOption
);
363 /******************************************************************
364 * DrvGetPrinterDataInternal
366 * Helper for DrvGetPrinterData
368 static DWORD
DrvGetPrinterDataInternal(LPCSTR RegStr_Printer
,
369 LPBYTE lpPrinterData
, int cbData
, int what
)
373 DWORD dwType
, cbQueryData
;
375 if (!(RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
))) {
376 if (what
== INT_PD_DEFAULT_DEVMODE
) { /* "Default DevMode" */
377 if (!(RegQueryValueExA(hkey
, DefaultDevMode
, 0, &dwType
, 0, &cbQueryData
))) {
380 else if ((cbQueryData
) && (cbQueryData
<= cbData
)) {
381 cbQueryData
= cbData
;
382 if (RegQueryValueExA(hkey
, DefaultDevMode
, 0,
383 &dwType
, lpPrinterData
, &cbQueryData
))
387 } else { /* "Printer Driver" */
389 RegQueryValueExA(hkey
, "Printer Driver", 0,
390 &dwType
, lpPrinterData
, &cbQueryData
);
394 if (hkey
) RegCloseKey(hkey
);
398 /******************************************************************
399 * DrvGetPrinterData (GDI.282)
402 DWORD WINAPI
DrvGetPrinterData16(LPSTR lpPrinter
, LPSTR lpProfile
,
403 LPDWORD lpType
, LPBYTE lpPrinterData
,
404 int cbData
, LPDWORD lpNeeded
)
406 LPSTR RegStr_Printer
;
407 HKEY hkey
= 0, hkey2
= 0;
409 DWORD dwType
, PrinterAttr
, cbPrinterAttr
, SetData
, size
;
411 if (HIWORD(lpPrinter
))
412 TRACE("printer %s\n",lpPrinter
);
414 TRACE("printer %p\n",lpPrinter
);
415 if (HIWORD(lpProfile
))
416 TRACE("profile %s\n",lpProfile
);
418 TRACE("profile %p\n",lpProfile
);
419 TRACE("lpType %p\n",lpType
);
421 if ((!lpPrinter
) || (!lpProfile
) || (!lpNeeded
))
422 return ERROR_INVALID_PARAMETER
;
424 RegStr_Printer
= HeapAlloc(GetProcessHeap(), 0,
425 strlen(Printers
) + strlen(lpPrinter
) + 2);
426 strcpy(RegStr_Printer
, Printers
);
427 strcat(RegStr_Printer
, lpPrinter
);
429 if ((PtrToUlong(lpProfile
) == INT_PD_DEFAULT_DEVMODE
) || (HIWORD(lpProfile
) &&
430 (!strcmp(lpProfile
, DefaultDevMode
)))) {
431 size
= DrvGetPrinterDataInternal(RegStr_Printer
, lpPrinterData
, cbData
,
432 INT_PD_DEFAULT_DEVMODE
);
435 if ((lpPrinterData
) && (*lpNeeded
> cbData
))
436 res
= ERROR_MORE_DATA
;
438 else res
= ERROR_INVALID_PRINTER_NAME
;
441 if ((PtrToUlong(lpProfile
) == INT_PD_DEFAULT_MODEL
) || (HIWORD(lpProfile
) &&
442 (!strcmp(lpProfile
, PrinterModel
)))) {
444 if (!lpPrinterData
) goto failed
;
446 res
= ERROR_MORE_DATA
;
449 size
= DrvGetPrinterDataInternal(RegStr_Printer
, lpPrinterData
, cbData
,
450 INT_PD_DEFAULT_MODEL
);
451 if ((size
+1) && (lpType
))
454 res
= ERROR_INVALID_PRINTER_NAME
;
458 if ((res
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
)))
461 if ((res
= RegQueryValueExA(hkey
, "Attributes", 0,
462 &dwType
, (LPBYTE
)&PrinterAttr
, &cbPrinterAttr
)))
464 if ((res
= RegOpenKeyA(hkey
, PrinterDriverData
, &hkey2
)))
467 res
= RegQueryValueExA(hkey2
, lpProfile
, 0,
468 lpType
, lpPrinterData
, lpNeeded
);
469 if ((res
!= ERROR_CANTREAD
) &&
471 (PRINTER_ATTRIBUTE_ENABLE_BIDI
|PRINTER_ATTRIBUTE_NETWORK
))
472 == PRINTER_ATTRIBUTE_NETWORK
))
474 if (!(res
) && (*lpType
== REG_DWORD
) && (*(LPDWORD
)lpPrinterData
== -1))
475 res
= ERROR_INVALID_DATA
;
480 RegSetValueExA(hkey2
, lpProfile
, 0, REG_DWORD
, (LPBYTE
)&SetData
, 4); /* no result returned */
485 if (hkey2
) RegCloseKey(hkey2
);
486 if (hkey
) RegCloseKey(hkey
);
487 HeapFree(GetProcessHeap(), 0, RegStr_Printer
);
492 /******************************************************************
493 * DrvSetPrinterData (GDI.281)
496 DWORD WINAPI
DrvSetPrinterData16(LPSTR lpPrinter
, LPSTR lpProfile
,
497 DWORD lpType
, LPBYTE lpPrinterData
,
500 LPSTR RegStr_Printer
;
504 if (HIWORD(lpPrinter
))
505 TRACE("printer %s\n",lpPrinter
);
507 TRACE("printer %p\n",lpPrinter
);
508 if (HIWORD(lpProfile
))
509 TRACE("profile %s\n",lpProfile
);
511 TRACE("profile %p\n",lpProfile
);
512 TRACE("lpType %08x\n",lpType
);
514 if ((!lpPrinter
) || (!lpProfile
) ||
515 (PtrToUlong(lpProfile
) == INT_PD_DEFAULT_MODEL
) || (HIWORD(lpProfile
) &&
516 (!strcmp(lpProfile
, PrinterModel
))))
517 return ERROR_INVALID_PARAMETER
;
519 RegStr_Printer
= HeapAlloc(GetProcessHeap(), 0,
520 strlen(Printers
) + strlen(lpPrinter
) + 2);
521 strcpy(RegStr_Printer
, Printers
);
522 strcat(RegStr_Printer
, lpPrinter
);
524 if ((PtrToUlong(lpProfile
) == INT_PD_DEFAULT_DEVMODE
) || (HIWORD(lpProfile
) &&
525 (!strcmp(lpProfile
, DefaultDevMode
)))) {
526 if ( RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
)
528 RegSetValueExA(hkey
, DefaultDevMode
, 0, REG_BINARY
,
529 lpPrinterData
, dwSize
) != ERROR_SUCCESS
)
530 res
= ERROR_INVALID_PRINTER_NAME
;
534 strcat(RegStr_Printer
, "\\");
536 if( (res
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, RegStr_Printer
, &hkey
)) ==
540 res
= RegDeleteValueA(hkey
, lpProfile
);
542 res
= RegSetValueExA(hkey
, lpProfile
, 0, lpType
,
543 lpPrinterData
, dwSize
);
547 if (hkey
) RegCloseKey(hkey
);
548 HeapFree(GetProcessHeap(), 0, RegStr_Printer
);