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