direct3d: Add a fixed function fog test.
[wine] / dlls / gdi32 / printdrv.c
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  *
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.
13  *
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.
18  *
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
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <signal.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #ifdef HAVE_IO_H
35 # include <io.h>
36 #endif
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 #include <fcntl.h>
41 #include "windef.h"
42 #include "winbase.h"
43 #include "winuser.h"
44 #include "wine/winbase16.h"
45 #include "wine/wingdi16.h"
46 #include "winspool.h"
47 #include "winerror.h"
48 #include "winreg.h"
49 #include "wownt32.h"
50 #include "wine/debug.h"
51 #include "gdi_private.h"
52
53 WINE_DEFAULT_DEBUG_CHANNEL(print);
54
55 static const char PrinterModel[]      = "Printer Model";
56 static const char DefaultDevMode[]    = "Default DevMode";
57 static const char PrinterDriverData[] = "PrinterDriverData";
58 static const char Printers[]          = "System\\CurrentControlSet\\Control\\Print\\Printers\\";
59
60
61 /******************************************************************
62  *                  StartDocA  [GDI32.@]
63  *
64  * StartDoc calls the STARTDOC Escape with the input data pointing to DocName
65  * and the output data (which is used as a second input parameter).pointing at
66  * the whole docinfo structure.  This seems to be an undocumented feature of
67  * the STARTDOC Escape.
68  *
69  * Note: we now do it the other way, with the STARTDOC Escape calling StartDoc.
70  */
71 INT WINAPI StartDocW(HDC hdc, const DOCINFOW* doc)
72 {
73     INT ret = 0;
74     DC *dc = DC_GetDCPtr( hdc );
75
76     TRACE("DocName = %s Output = %s Datatype = %s\n",
77           debugstr_w(doc->lpszDocName), debugstr_w(doc->lpszOutput),
78           debugstr_w(doc->lpszDatatype));
79
80     if(!dc) return SP_ERROR;
81
82     if (dc->funcs->pStartDoc) ret = dc->funcs->pStartDoc( dc->physDev, doc );
83     GDI_ReleaseObj( hdc );
84     return ret;
85 }
86
87 /*************************************************************************
88  *                  StartDocA [GDI32.@]
89  *
90  */
91 INT WINAPI StartDocA(HDC hdc, const DOCINFOA* doc)
92 {
93     LPWSTR szDocName = NULL, szOutput = NULL, szDatatype = NULL;
94     DOCINFOW docW;
95     INT ret, len;
96
97     docW.cbSize = doc->cbSize;
98     if (doc->lpszDocName)
99     {
100         len = MultiByteToWideChar(CP_ACP,0,doc->lpszDocName,-1,NULL,0);
101         szDocName = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
102         MultiByteToWideChar(CP_ACP,0,doc->lpszDocName,-1,szDocName,len);
103     }
104     if (doc->lpszOutput)
105     {
106         len = MultiByteToWideChar(CP_ACP,0,doc->lpszOutput,-1,NULL,0);
107         szOutput = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
108         MultiByteToWideChar(CP_ACP,0,doc->lpszOutput,-1,szOutput,len);
109     }
110     if (doc->lpszDatatype)
111     {
112         len = MultiByteToWideChar(CP_ACP,0,doc->lpszDatatype,-1,NULL,0);
113         szDatatype = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
114         MultiByteToWideChar(CP_ACP,0,doc->lpszDatatype,-1,szDatatype,len);
115     }
116
117     docW.lpszDocName = szDocName;
118     docW.lpszOutput = szOutput;
119     docW.lpszDatatype = szDatatype;
120     docW.fwType = doc->fwType;
121
122     ret = StartDocW(hdc, &docW);
123
124     HeapFree( GetProcessHeap(), 0, szDocName );
125     HeapFree( GetProcessHeap(), 0, szOutput );
126     HeapFree( GetProcessHeap(), 0, szDatatype );
127
128     return ret;
129 }
130
131
132 /******************************************************************
133  *                  EndDoc  [GDI32.@]
134  *
135  */
136 INT WINAPI EndDoc(HDC hdc)
137 {
138     INT ret = 0;
139     DC *dc = DC_GetDCPtr( hdc );
140     if(!dc) return SP_ERROR;
141
142     if (dc->funcs->pEndDoc) ret = dc->funcs->pEndDoc( dc->physDev );
143     GDI_ReleaseObj( hdc );
144     return ret;
145 }
146
147
148 /******************************************************************
149  *                  StartPage  [GDI32.@]
150  *
151  */
152 INT WINAPI StartPage(HDC hdc)
153 {
154     INT ret = 1;
155     DC *dc = DC_GetDCPtr( hdc );
156     if(!dc) return SP_ERROR;
157
158     if(dc->funcs->pStartPage)
159         ret = dc->funcs->pStartPage( dc->physDev );
160     else
161         FIXME("stub\n");
162     GDI_ReleaseObj( hdc );
163     return ret;
164 }
165
166
167 /******************************************************************
168  *                  EndPage  [GDI32.@]
169  *
170  */
171 INT WINAPI EndPage(HDC hdc)
172 {
173     ABORTPROC abort_proc;
174     INT ret = 0;
175     DC *dc = DC_GetDCPtr( hdc );
176     if(!dc) return SP_ERROR;
177
178     if (dc->funcs->pEndPage) ret = dc->funcs->pEndPage( dc->physDev );
179     abort_proc = dc->pAbortProc;
180     GDI_ReleaseObj( hdc );
181     if (abort_proc && !abort_proc( hdc, 0 ))
182     {
183         EndDoc( hdc );
184         ret = 0;
185     }
186     return ret;
187 }
188
189
190 /******************************************************************************
191  *                 AbortDoc  [GDI32.@]
192  */
193 INT WINAPI AbortDoc(HDC hdc)
194 {
195     INT ret = 0;
196     DC *dc = DC_GetDCPtr( hdc );
197     if(!dc) return SP_ERROR;
198
199     if (dc->funcs->pAbortDoc) ret = dc->funcs->pAbortDoc( dc->physDev );
200     GDI_ReleaseObj( hdc );
201     return ret;
202 }
203
204 /**********************************************************************
205  *           QueryAbort   (GDI.155)
206  *
207  *  Calls the app's AbortProc function if avail.
208  *
209  * RETURNS
210  * TRUE if no AbortProc avail or AbortProc wants to continue printing.
211  * FALSE if AbortProc wants to abort printing.
212  */
213 BOOL16 WINAPI QueryAbort16(HDC16 hdc16, INT16 reserved)
214 {
215     BOOL ret = TRUE;
216     HDC hdc = HDC_32( hdc16 );
217     DC *dc = DC_GetDCPtr( hdc );
218     ABORTPROC abproc;
219
220     if(!dc) {
221         ERR("Invalid hdc %p\n", hdc);
222         return FALSE;
223     }
224
225     abproc = dc->pAbortProc;
226     GDI_ReleaseObj( hdc );
227
228     if (abproc)
229         ret = abproc(hdc, 0);
230     return ret;
231 }
232
233
234 /**********************************************************************
235  *           call_abort_proc16
236  */
237 static BOOL CALLBACK call_abort_proc16( HDC hdc, INT code )
238 {
239     ABORTPROC16 proc16;
240     DC *dc = DC_GetDCPtr( hdc );
241
242     if (!dc) return FALSE;
243     proc16 = dc->pAbortProc16;
244     GDI_ReleaseObj( hdc );
245     if (proc16)
246     {
247         WORD args[2];
248         DWORD ret;
249
250         args[1] = HDC_16(hdc);
251         args[0] = code;
252         WOWCallback16Ex( (DWORD)proc16, WCB16_PASCAL, sizeof(args), args, &ret );
253         return LOWORD(ret);
254     }
255     return TRUE;
256 }
257
258
259 /**********************************************************************
260  *           SetAbortProc   (GDI.381)
261  */
262 INT16 WINAPI SetAbortProc16(HDC16 hdc16, ABORTPROC16 abrtprc)
263 {
264     HDC hdc = HDC_32( hdc16 );
265     DC *dc = DC_GetDCPtr( hdc );
266
267     if (!dc) return FALSE;
268     dc->pAbortProc16 = abrtprc;
269     GDI_ReleaseObj( hdc );
270     return SetAbortProc( hdc, call_abort_proc16 );
271 }
272
273 /**********************************************************************
274  *           SetAbortProc   (GDI32.@)
275  *
276  */
277 INT WINAPI SetAbortProc(HDC hdc, ABORTPROC abrtprc)
278 {
279     DC *dc = DC_GetDCPtr( hdc );
280
281     if (!dc) return FALSE;
282     dc->pAbortProc = abrtprc;
283     GDI_ReleaseObj( hdc );
284     return TRUE;
285 }
286
287
288 /****************** misc. printer related functions */
289
290 /*
291  * The following function should implement a queing system
292  */
293 struct hpq
294 {
295     struct hpq  *next;
296     int          tag;
297     int          key;
298 };
299
300 static struct hpq *hpqueue;
301
302 /**********************************************************************
303  *           CreatePQ   (GDI.230)
304  *
305  */
306 HPQ16 WINAPI CreatePQ16(INT16 size)
307 {
308 #if 0
309     HGLOBAL16 hpq = 0;
310     WORD tmp_size;
311     LPWORD pPQ;
312
313     tmp_size = size << 2;
314     if (!(hpq = GlobalAlloc16(GMEM_SHARE|GMEM_MOVEABLE, tmp_size + 8)))
315        return 0xffff;
316     pPQ = GlobalLock16(hpq);
317     *pPQ++ = 0;
318     *pPQ++ = tmp_size;
319     *pPQ++ = 0;
320     *pPQ++ = 0;
321     GlobalUnlock16(hpq);
322
323     return (HPQ16)hpq;
324 #else
325     FIXME("(%d): stub\n",size);
326     return 1;
327 #endif
328 }
329
330 /**********************************************************************
331  *           DeletePQ   (GDI.235)
332  *
333  */
334 INT16 WINAPI DeletePQ16(HPQ16 hPQ)
335 {
336     return GlobalFree16((HGLOBAL16)hPQ);
337 }
338
339 /**********************************************************************
340  *           ExtractPQ   (GDI.232)
341  *
342  */
343 INT16 WINAPI ExtractPQ16(HPQ16 hPQ)
344 {
345     struct hpq *queue, *prev, *current, *currentPrev;
346     int key = 0, tag = -1;
347     currentPrev = prev = NULL;
348     queue = current = hpqueue;
349     if (current)
350         key = current->key;
351
352     while (current)
353     {
354         currentPrev = current;
355         current = current->next;
356         if (current)
357         {
358             if (current->key < key)
359             {
360                 queue = current;
361                 prev = currentPrev;
362             }
363         }
364     }
365     if (queue)
366     {
367         tag = queue->tag;
368
369         if (prev)
370             prev->next = queue->next;
371         else
372             hpqueue = queue->next;
373         HeapFree(GetProcessHeap(), 0, queue);
374     }
375
376     TRACE("%x got tag %d key %d\n", hPQ, tag, key);
377
378     return tag;
379 }
380
381 /**********************************************************************
382  *           InsertPQ   (GDI.233)
383  *
384  */
385 INT16 WINAPI InsertPQ16(HPQ16 hPQ, INT16 tag, INT16 key)
386 {
387     struct hpq *queueItem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct hpq));
388     if(queueItem == NULL) {
389         ERR("Memory exausted!\n");
390         return FALSE;
391     }
392     queueItem->next = hpqueue;
393     hpqueue = queueItem;
394     queueItem->key = key;
395     queueItem->tag = tag;
396
397     FIXME("(%x %d %d): stub???\n", hPQ, tag, key);
398     return TRUE;
399 }
400
401 /**********************************************************************
402  *           MinPQ   (GDI.231)
403  *
404  */
405 INT16 WINAPI MinPQ16(HPQ16 hPQ)
406 {
407     FIXME("(%x): stub\n", hPQ);
408     return 0;
409 }
410
411 /**********************************************************************
412  *           SizePQ   (GDI.234)
413  *
414  */
415 INT16 WINAPI SizePQ16(HPQ16 hPQ, INT16 sizechange)
416 {
417     FIXME("(%x %d): stub\n", hPQ, sizechange);
418     return -1;
419 }
420
421
422
423 /*
424  * The following functions implement part of the spooling process to
425  * print manager.  I would like to see wine have a version of print managers
426  * that used LPR/LPD.  For simplicity print jobs will be sent to a file for
427  * now.
428  */
429 typedef struct PRINTJOB
430 {
431     char        *pszOutput;
432     char        *pszTitle;
433     HDC16       hDC;
434     HANDLE16    hHandle;
435     int         nIndex;
436     int         fd;
437 } PRINTJOB, *PPRINTJOB;
438
439 #define MAX_PRINT_JOBS 1
440 #define SP_OK 1
441
442 static PPRINTJOB gPrintJobsTable[MAX_PRINT_JOBS];
443
444
445 static PPRINTJOB FindPrintJobFromHandle(HANDLE16 hHandle)
446 {
447     return gPrintJobsTable[0];
448 }
449
450 static int CreateSpoolFile(LPCSTR pszOutput)
451 {
452     int fd=-1;
453     char psCmd[1024];
454     const char *psCmdP = psCmd;
455     HKEY hkey;
456
457     /* TTD convert the 'output device' into a spool file name */
458
459     if (pszOutput == NULL || *pszOutput == '\0')
460       return -1;
461
462     psCmd[0] = 0;
463     /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
464     if(!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\Spooler", &hkey))
465     {
466         DWORD type, count = sizeof(psCmd);
467         RegQueryValueExA(hkey, pszOutput, 0, &type, (LPBYTE)psCmd, &count);
468         RegCloseKey(hkey);
469     }
470     if (!psCmd[0] && !strncmp("LPR:",pszOutput,4))
471         sprintf(psCmd,"|lpr -P%s",pszOutput+4);
472
473     TRACE("Got printerSpoolCommand '%s' for output device '%s'\n",
474           psCmd, pszOutput);
475     if (!*psCmd)
476         psCmdP = pszOutput;
477     else
478     {
479         while (*psCmdP && isspace(*psCmdP))
480         {
481             psCmdP++;
482         }
483         if (!*psCmdP)
484             return -1;
485     }
486     TRACE("command: '%s'\n", psCmdP);
487 #ifdef HAVE_FORK
488     if (*psCmdP == '|')
489     {
490         int fds[2];
491         if (pipe(fds)) {
492             ERR("pipe() failed!\n"); 
493             return -1;
494         }
495         if (fork() == 0)
496         {
497             psCmdP++;
498
499             TRACE("In child need to exec %s\n",psCmdP);
500             close(0);
501             dup2(fds[0],0);
502             close (fds[1]);
503
504             /* reset signals that we previously set to SIG_IGN */
505             signal( SIGPIPE, SIG_DFL );
506             signal( SIGCHLD, SIG_DFL );
507
508             execl("/bin/sh", "/bin/sh", "-c", psCmdP, (char*)0);
509             _exit(1);
510
511         }
512         close (fds[0]);
513         fd = fds[1];
514         TRACE("Need to execute a cmnd and pipe the output to it\n");
515     }
516     else
517 #endif
518     {
519         char *buffer;
520         WCHAR psCmdPW[MAX_PATH];
521
522         TRACE("Just assume it's a file\n");
523
524         /**
525          * The file name can be dos based, we have to find its
526          * Unix correspondant file name
527          */
528         MultiByteToWideChar(CP_ACP, 0, psCmdP, -1, psCmdPW, MAX_PATH);
529         if ((buffer = wine_get_unix_file_name(psCmdPW)))
530         {
531             if ((fd = open(buffer, O_CREAT | O_TRUNC | O_WRONLY , 0600)) < 0)
532             {
533                 ERR("Failed to create spool file '%s' ('%s'). (error %s)\n",
534                     buffer, psCmdP, strerror(errno));
535             }
536             HeapFree(GetProcessHeap(), 0, buffer);
537         }
538     }
539     return fd;
540 }
541
542 static int FreePrintJob(HANDLE16 hJob)
543 {
544     int nRet = SP_ERROR;
545     PPRINTJOB pPrintJob;
546
547     pPrintJob = FindPrintJobFromHandle(hJob);
548     if (pPrintJob != NULL)
549     {
550         gPrintJobsTable[pPrintJob->nIndex] = NULL;
551         HeapFree(GetProcessHeap(), 0, pPrintJob->pszOutput);
552         HeapFree(GetProcessHeap(), 0, pPrintJob->pszTitle);
553         if (pPrintJob->fd >= 0) close(pPrintJob->fd);
554         HeapFree(GetProcessHeap(), 0, pPrintJob);
555         nRet = SP_OK;
556     }
557     return nRet;
558 }
559
560 /**********************************************************************
561  *           OpenJob   (GDI.240)
562  *
563  */
564 HPJOB16 WINAPI OpenJob16(LPCSTR lpOutput, LPCSTR lpTitle, HDC16 hDC)
565 {
566     HPJOB16 hHandle = (HPJOB16)SP_ERROR;
567     PPRINTJOB pPrintJob;
568
569     TRACE("'%s' '%s' %04x\n", lpOutput, lpTitle, hDC);
570
571     pPrintJob = gPrintJobsTable[0];
572     if (pPrintJob == NULL)
573     {
574         int fd;
575
576         /* Try and create a spool file */
577         fd = CreateSpoolFile(lpOutput);
578         if (fd >= 0)
579         {
580             pPrintJob = HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTJOB));
581             if(pPrintJob == NULL) {
582                 WARN("Memory exausted!\n");
583                 return hHandle;
584             }
585
586             hHandle = 1;
587
588             pPrintJob->pszOutput = HeapAlloc(GetProcessHeap(), 0, strlen(lpOutput)+1);
589             strcpy( pPrintJob->pszOutput, lpOutput );
590             if(lpTitle)
591             {
592                 pPrintJob->pszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(lpTitle)+1);
593                 strcpy( pPrintJob->pszTitle, lpTitle );
594             }
595             pPrintJob->hDC = hDC;
596             pPrintJob->fd = fd;
597             pPrintJob->nIndex = 0;
598             pPrintJob->hHandle = hHandle;
599             gPrintJobsTable[pPrintJob->nIndex] = pPrintJob;
600         }
601     }
602     TRACE("return %04x\n", hHandle);
603     return hHandle;
604 }
605
606 /**********************************************************************
607  *           CloseJob   (GDI.243)
608  *
609  */
610 INT16 WINAPI CloseJob16(HPJOB16 hJob)
611 {
612     int nRet = SP_ERROR;
613     PPRINTJOB pPrintJob = NULL;
614
615     TRACE("%04x\n", hJob);
616
617     pPrintJob = FindPrintJobFromHandle(hJob);
618     if (pPrintJob != NULL)
619     {
620         /* Close the spool file */
621         close(pPrintJob->fd);
622         FreePrintJob(hJob);
623         nRet  = 1;
624     }
625     return nRet;
626 }
627
628 /**********************************************************************
629  *           WriteSpool   (GDI.241)
630  *
631  */
632 INT16 WINAPI WriteSpool16(HPJOB16 hJob, LPSTR lpData, INT16 cch)
633 {
634     int nRet = SP_ERROR;
635     PPRINTJOB pPrintJob = NULL;
636
637     TRACE("%04x %p %04x\n", hJob, lpData, cch);
638
639     pPrintJob = FindPrintJobFromHandle(hJob);
640     if (pPrintJob != NULL && pPrintJob->fd >= 0 && cch)
641     {
642         if (write(pPrintJob->fd, lpData, cch) != cch)
643           nRet = SP_OUTOFDISK;
644         else
645           nRet = cch;
646 #if 0
647         /* FIXME: We just cannot call 16 bit functions from here, since we
648          * have acquired several locks (DC). And we do not really need to.
649          */
650         if (pPrintJob->hDC == 0) {
651             TRACE("hDC == 0 so no QueryAbort\n");
652         }
653         else if (!(QueryAbort16(pPrintJob->hDC, (nRet == SP_OUTOFDISK) ? nRet : 0 )))
654         {
655             CloseJob16(hJob); /* printing aborted */
656             nRet = SP_APPABORT;
657         }
658 #endif
659     }
660     return nRet;
661 }
662
663 typedef INT (WINAPI *MSGBOX_PROC)( HWND, LPCSTR, LPCSTR, UINT );
664
665 /**********************************************************************
666  *           WriteDialog   (GDI.242)
667  *
668  */
669 INT16 WINAPI WriteDialog16(HPJOB16 hJob, LPSTR lpMsg, INT16 cchMsg)
670 {
671     HMODULE mod;
672     MSGBOX_PROC pMessageBoxA;
673     INT16 ret = 0;
674
675     TRACE("%04x %04x '%s'\n", hJob,  cchMsg, lpMsg);
676
677     if ((mod = GetModuleHandleA("user32.dll")))
678     {
679         if ((pMessageBoxA = (MSGBOX_PROC)GetProcAddress( mod, "MessageBoxA" )))
680             ret = pMessageBoxA(0, lpMsg, "Printing Error", MB_OKCANCEL);
681     }
682     return ret;
683 }
684
685
686 /**********************************************************************
687  *           DeleteJob  (GDI.244)
688  *
689  */
690 INT16 WINAPI DeleteJob16(HPJOB16 hJob, INT16 nNotUsed)
691 {
692     int nRet;
693
694     TRACE("%04x\n", hJob);
695
696     nRet = FreePrintJob(hJob);
697     return nRet;
698 }
699
700 /*
701  * The following two function would allow a page to be sent to the printer
702  * when it has been processed.  For simplicity they havn't been implemented.
703  * This means a whole job has to be processed before it is sent to the printer.
704  */
705
706 /**********************************************************************
707  *           StartSpoolPage   (GDI.246)
708  *
709  */
710 INT16 WINAPI StartSpoolPage16(HPJOB16 hJob)
711 {
712     FIXME("StartSpoolPage GDI.246 unimplemented\n");
713     return 1;
714
715 }
716
717
718 /**********************************************************************
719  *           EndSpoolPage   (GDI.247)
720  *
721  */
722 INT16 WINAPI EndSpoolPage16(HPJOB16 hJob)
723 {
724     FIXME("EndSpoolPage GDI.247 unimplemented\n");
725     return 1;
726 }
727
728
729 /**********************************************************************
730  *           GetSpoolJob   (GDI.245)
731  *
732  */
733 DWORD WINAPI GetSpoolJob16(int nOption, LONG param)
734 {
735     DWORD retval = 0;
736     TRACE("In GetSpoolJob param 0x%x noption %d\n",param, nOption);
737     return retval;
738 }
739
740
741 /******************************************************************
742  *                  DrvGetPrinterDataInternal
743  *
744  * Helper for DrvGetPrinterData
745  */
746 static DWORD DrvGetPrinterDataInternal(LPSTR RegStr_Printer,
747 LPBYTE lpPrinterData, int cbData, int what)
748 {
749     DWORD res = -1;
750     HKEY hkey;
751     DWORD dwType, cbQueryData;
752
753     if (!(RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey))) {
754         if (what == INT_PD_DEFAULT_DEVMODE) { /* "Default DevMode" */
755             if (!(RegQueryValueExA(hkey, DefaultDevMode, 0, &dwType, 0, &cbQueryData))) {
756                 if (!lpPrinterData)
757                     res = cbQueryData;
758                 else if ((cbQueryData) && (cbQueryData <= cbData)) {
759                     cbQueryData = cbData;
760                     if (RegQueryValueExA(hkey, DefaultDevMode, 0,
761                                 &dwType, lpPrinterData, &cbQueryData))
762                         res = cbQueryData;
763                 }
764             }
765         } else { /* "Printer Driver" */
766             cbQueryData = 32;
767             RegQueryValueExA(hkey, "Printer Driver", 0,
768                         &dwType, lpPrinterData, &cbQueryData);
769             res = cbQueryData;
770         }
771     }
772     if (hkey) RegCloseKey(hkey);
773     return res;
774 }
775
776 /******************************************************************
777  *                DrvGetPrinterData     (GDI.282)
778  *
779  */
780 DWORD WINAPI DrvGetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
781                                LPDWORD lpType, LPBYTE lpPrinterData,
782                                int cbData, LPDWORD lpNeeded)
783 {
784     LPSTR RegStr_Printer;
785     HKEY hkey = 0, hkey2 = 0;
786     DWORD res = 0;
787     DWORD dwType, PrinterAttr, cbPrinterAttr, SetData, size;
788
789     if (HIWORD(lpPrinter))
790             TRACE("printer %s\n",lpPrinter);
791     else
792             TRACE("printer %p\n",lpPrinter);
793     if (HIWORD(lpProfile))
794             TRACE("profile %s\n",lpProfile);
795     else
796             TRACE("profile %p\n",lpProfile);
797     TRACE("lpType %p\n",lpType);
798
799     if ((!lpPrinter) || (!lpProfile) || (!lpNeeded))
800         return ERROR_INVALID_PARAMETER;
801
802     RegStr_Printer = HeapAlloc(GetProcessHeap(), 0,
803                                strlen(Printers) + strlen(lpPrinter) + 2);
804     strcpy(RegStr_Printer, Printers);
805     strcat(RegStr_Printer, lpPrinter);
806
807     if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
808     (!strcmp(lpProfile, DefaultDevMode)))) {
809         size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
810                                          INT_PD_DEFAULT_DEVMODE);
811         if (size+1) {
812             *lpNeeded = size;
813             if ((lpPrinterData) && (*lpNeeded > cbData))
814                 res = ERROR_MORE_DATA;
815         }
816         else res = ERROR_INVALID_PRINTER_NAME;
817     }
818     else
819     if (((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
820     (!strcmp(lpProfile, PrinterModel)))) {
821         *lpNeeded = 32;
822         if (!lpPrinterData) goto failed;
823         if (cbData < 32) {
824             res = ERROR_MORE_DATA;
825             goto failed;
826         }
827         size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
828                                          INT_PD_DEFAULT_MODEL);
829         if ((size+1) && (lpType))
830             *lpType = REG_SZ;
831         else
832             res = ERROR_INVALID_PRINTER_NAME;
833     }
834     else
835     {
836         if ((res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)))
837             goto failed;
838         cbPrinterAttr = 4;
839         if ((res = RegQueryValueExA(hkey, "Attributes", 0,
840                         &dwType, (LPBYTE)&PrinterAttr, &cbPrinterAttr)))
841             goto failed;
842         if ((res = RegOpenKeyA(hkey, PrinterDriverData, &hkey2)))
843             goto failed;
844         *lpNeeded = cbData;
845         res = RegQueryValueExA(hkey2, lpProfile, 0,
846                 lpType, lpPrinterData, lpNeeded);
847         if ((res != ERROR_CANTREAD) &&
848          ((PrinterAttr &
849         (PRINTER_ATTRIBUTE_ENABLE_BIDI|PRINTER_ATTRIBUTE_NETWORK))
850         == PRINTER_ATTRIBUTE_NETWORK))
851         {
852             if (!(res) && (*lpType == REG_DWORD) && (*(LPDWORD)lpPrinterData == -1))
853                 res = ERROR_INVALID_DATA;
854         }
855         else
856         {
857             SetData = -1;
858             RegSetValueExA(hkey2, lpProfile, 0, REG_DWORD, (LPBYTE)&SetData, 4); /* no result returned */
859         }
860     }
861
862 failed:
863     if (hkey2) RegCloseKey(hkey2);
864     if (hkey) RegCloseKey(hkey);
865     HeapFree(GetProcessHeap(), 0, RegStr_Printer);
866     return res;
867 }
868
869
870 /******************************************************************
871  *                 DrvSetPrinterData     (GDI.281)
872  *
873  */
874 DWORD WINAPI DrvSetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
875                                DWORD lpType, LPBYTE lpPrinterData,
876                                DWORD dwSize)
877 {
878     LPSTR RegStr_Printer;
879     HKEY hkey = 0;
880     DWORD res = 0;
881
882     if (HIWORD(lpPrinter))
883             TRACE("printer %s\n",lpPrinter);
884     else
885             TRACE("printer %p\n",lpPrinter);
886     if (HIWORD(lpProfile))
887             TRACE("profile %s\n",lpProfile);
888     else
889             TRACE("profile %p\n",lpProfile);
890     TRACE("lpType %08x\n",lpType);
891
892     if ((!lpPrinter) || (!lpProfile) ||
893     ((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
894     (!strcmp(lpProfile, PrinterModel))))
895         return ERROR_INVALID_PARAMETER;
896
897     RegStr_Printer = HeapAlloc(GetProcessHeap(), 0,
898                         strlen(Printers) + strlen(lpPrinter) + 2);
899     strcpy(RegStr_Printer, Printers);
900     strcat(RegStr_Printer, lpPrinter);
901
902     if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
903     (!strcmp(lpProfile, DefaultDevMode)))) {
904         if ( RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)
905              != ERROR_SUCCESS ||
906              RegSetValueExA(hkey, DefaultDevMode, 0, REG_BINARY,
907                               lpPrinterData, dwSize) != ERROR_SUCCESS )
908                 res = ERROR_INVALID_PRINTER_NAME;
909     }
910     else
911     {
912         strcat(RegStr_Printer, "\\");
913
914         if( (res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)) ==
915             ERROR_SUCCESS ) {
916
917             if (!lpPrinterData)
918                 res = RegDeleteValueA(hkey, lpProfile);
919             else
920                 res = RegSetValueExA(hkey, lpProfile, 0, lpType,
921                                        lpPrinterData, dwSize);
922         }
923     }
924
925     if (hkey) RegCloseKey(hkey);
926     HeapFree(GetProcessHeap(), 0, RegStr_Printer);
927     return res;
928 }