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