Removed a few dependencies on kernel32 functions.
[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 <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include "ldt.h"
17 #include "winbase.h"
18 #include "wine/winbase16.h"
19 #include "wine/wingdi16.h"
20 #include "winspool.h"
21 #include "winerror.h"
22 #include "winreg.h"
23 #include "debugtools.h"
24 #include "gdi.h"
25 #include "dc.h"
26 #include "callback.h"
27 #include "options.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  *                  StartDoc16  [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 = PTR_SEG_TO_LIN(lpdoc->lpszDocName);
48     docA.lpszOutput = PTR_SEG_TO_LIN(lpdoc->lpszOutput);
49
50     if(lpdoc->cbSize >= 14)
51         docA.lpszDatatype = PTR_SEG_TO_LIN(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.347]
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.348]
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  *                  EndDoc16  [GDI.378]
122  *
123  */
124 INT16 WINAPI EndDoc16(HDC16 hdc)
125 {
126     return EndDoc(hdc);
127 }
128
129 /******************************************************************
130  *                  EndDoc  [GDI32.76]
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  *                  StartPage16  [GDI.379]
149  *
150  */
151 INT16 WINAPI StartPage16(HDC16 hdc)
152 {
153     return StartPage(hdc);
154 }
155
156 /******************************************************************
157  *                  StartPage  [GDI32.349]
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  *                  EndPage16  [GDI.380]
176  *
177  */
178 INT16 WINAPI EndPage16( HDC16 hdc )
179 {
180     return EndPage(hdc);
181 }
182
183 /******************************************************************
184  *                  EndPage  [GDI32.77]
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     return ret;
199 }
200
201 /******************************************************************************
202  *                 AbortDoc16  [GDI.382]
203  */
204 INT16 WINAPI AbortDoc16(HDC16 hdc)
205 {
206     return AbortDoc(hdc);
207 }
208
209 /******************************************************************************
210  *                 AbortDoc  [GDI32.105]
211  */
212 INT WINAPI AbortDoc(HDC hdc)
213 {
214     INT ret;
215     DC *dc = DC_GetDCPtr( hdc );
216     if(!dc) return SP_ERROR;
217
218     if(dc->funcs->pAbortDoc)
219         ret = dc->funcs->pAbortDoc( dc );
220     else
221         ret = Escape(hdc, ABORTDOC, 0, 0, 0);
222     GDI_ReleaseObj( hdc );
223     return ret;
224 }
225
226 /**********************************************************************
227  *           QueryAbort16   (GDI.155)
228  *
229  *  Calls the app's AbortProc function if avail.
230  *
231  * RETURNS
232  * TRUE if no AbortProc avail or AbortProc wants to continue printing.
233  * FALSE if AbortProc wants to abort printing.
234  */
235 BOOL16 WINAPI QueryAbort16(HDC16 hdc, INT16 reserved)
236 {
237     BOOL ret = TRUE;
238     DC *dc = DC_GetDCPtr( hdc );
239
240     if(!dc) {
241         ERR("Invalid hdc %04x\n", hdc);
242         return FALSE;
243     }
244
245     if (dc->w.pAbortProc) ret = dc->w.pAbortProc(hdc, 0);
246     GDI_ReleaseObj( hdc );
247     return ret;
248 }
249
250 /* ### start build ### */
251 extern WORD CALLBACK PRTDRV_CallTo16_word_ww(FARPROC16,WORD,WORD);
252 /* ### stop build ### */
253
254 /**********************************************************************
255  *           SetAbortProc16   (GDI.381)
256  *
257  */
258 INT16 WINAPI SetAbortProc16(HDC16 hdc, SEGPTR abrtprc)
259 {
260     ABORTPROC proc32 = (ABORTPROC)THUNK_Alloc((FARPROC16)abrtprc,
261                                               (RELAY)PRTDRV_CallTo16_word_ww);
262     return SetAbortProc(hdc, proc32);
263 }
264
265 /**********************************************************************
266  *           SetAbortProc   (GDI32.301)
267  *
268  */
269 INT WINAPI SetAbortProc(HDC hdc, ABORTPROC abrtprc)
270 {
271     DC *dc = DC_GetDCPtr( hdc );
272
273     if(dc->w.pAbortProc) THUNK_Free((FARPROC)dc->w.pAbortProc);
274     dc->w.pAbortProc = abrtprc;
275     GDI_ReleaseObj( hdc );
276     return TRUE;
277 }
278
279
280 /****************** misc. printer related functions */
281
282 /*
283  * The following function should implement a queing system
284  */
285 struct hpq 
286 {
287     struct hpq  *next;
288     int          tag;
289     int          key;
290 };
291
292 static struct hpq *hpqueue;
293
294 /**********************************************************************
295  *           CreatePQ   (GDI.230)
296  *
297  */
298 HPQ16 WINAPI CreatePQ16(INT16 size) 
299 {
300 #if 0
301     HGLOBAL16 hpq = 0;
302     WORD tmp_size;
303     LPWORD pPQ;
304
305     tmp_size = size << 2;
306     if (!(hpq = GlobalAlloc16(GMEM_SHARE|GMEM_MOVEABLE, tmp_size + 8)))
307        return 0xffff;
308     pPQ = GlobalLock16(hpq);
309     *pPQ++ = 0;
310     *pPQ++ = tmp_size;
311     *pPQ++ = 0;
312     *pPQ++ = 0;
313     GlobalUnlock16(hpq);
314
315     return (HPQ16)hpq;
316 #else
317     FIXME("(%d): stub\n",size);
318     return 1;
319 #endif
320 }
321
322 /**********************************************************************
323  *           DeletePQ   (GDI.235)
324  *
325  */
326 INT16 WINAPI DeletePQ16(HPQ16 hPQ) 
327 {
328     return GlobalFree16((HGLOBAL16)hPQ);
329 }
330
331 /**********************************************************************
332  *           ExtractPQ   (GDI.232)
333  *
334  */
335 INT16 WINAPI ExtractPQ16(HPQ16 hPQ) 
336
337     struct hpq *queue, *prev, *current, *currentPrev;
338     int key = 0, tag = -1;
339     currentPrev = prev = NULL;
340     queue = current = hpqueue;
341     if (current)
342         key = current->key;
343     
344     while (current)
345     {
346         currentPrev = current;
347         current = current->next;
348         if (current)
349         {
350             if (current->key < key)
351             {
352                 queue = current;
353                 prev = currentPrev;
354             }
355         }
356     }
357     if (queue)
358     {
359         tag = queue->tag;
360         
361         if (prev)
362             prev->next = queue->next;
363         else
364             hpqueue = queue->next;
365         HeapFree(GetProcessHeap(), 0, queue);
366     }
367     
368     TRACE("%x got tag %d key %d\n", hPQ, tag, key); 
369
370     return tag;
371 }
372
373 /**********************************************************************
374  *           InsertPQ   (GDI.233)
375  *
376  */
377 INT16 WINAPI InsertPQ16(HPQ16 hPQ, INT16 tag, INT16 key) 
378 {
379     struct hpq *queueItem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct hpq));
380     if(queueItem == NULL) {
381         ERR("Memory exausted!");
382         return FALSE;
383     }
384     queueItem->next = hpqueue;
385     hpqueue = queueItem;
386     queueItem->key = key;
387     queueItem->tag = tag;
388     
389     FIXME("(%x %d %d): stub???\n", hPQ, tag, key);
390     return TRUE;
391 }
392
393 /**********************************************************************
394  *           MinPQ   (GDI.231)
395  *
396  */
397 INT16 WINAPI MinPQ16(HPQ16 hPQ) 
398 {
399     FIXME("(%x): stub\n", hPQ); 
400     return 0;
401 }
402
403 /**********************************************************************
404  *           SizePQ   (GDI.234)
405  *
406  */
407 INT16 WINAPI SizePQ16(HPQ16 hPQ, INT16 sizechange) 
408 {  
409     FIXME("(%x %d): stub\n", hPQ, sizechange); 
410     return -1; 
411 }
412
413
414
415 /* 
416  * The following functions implement part of the spooling process to 
417  * print manager.  I would like to see wine have a version of print managers
418  * that used LPR/LPD.  For simplicity print jobs will be sent to a file for
419  * now.
420  */
421 typedef struct PRINTJOB
422 {
423     char        *pszOutput;
424     char        *pszTitle;
425     HDC16       hDC;
426     HANDLE16    hHandle;
427     int         nIndex;
428     int         fd;
429 } PRINTJOB, *PPRINTJOB;
430
431 #define MAX_PRINT_JOBS 1
432 #define SP_OK 1
433
434 PPRINTJOB gPrintJobsTable[MAX_PRINT_JOBS];
435
436
437 static PPRINTJOB FindPrintJobFromHandle(HANDLE16 hHandle)
438 {
439     return gPrintJobsTable[0];
440 }
441
442 static int CreateSpoolFile(LPCSTR pszOutput)
443 {
444     int fd=-1;
445     char psCmd[1024];
446     char *psCmdP = psCmd;
447
448     /* TTD convert the 'output device' into a spool file name */
449
450     if (pszOutput == NULL || *pszOutput == '\0')
451       return -1;
452
453     PROFILE_GetWineIniString( "spooler", pszOutput, "", psCmd, sizeof(psCmd) );
454     TRACE("Got printerSpoolCommand '%s' for output device '%s'\n",
455           psCmd, pszOutput);
456     if (!*psCmd)
457         psCmdP = (char *)pszOutput;
458     else
459     {
460         while (*psCmdP && isspace(*psCmdP))
461         {
462             psCmdP++;
463         };
464         if (!*psCmdP)
465             return -1;
466     }
467     if (*psCmdP == '|')
468     {
469         int fds[2];
470         if (pipe(fds))
471             return -1;
472         if (fork() == 0)
473         {
474             psCmdP++;
475
476             TRACE("In child need to exec %s\n",psCmdP);
477             close(0);
478             dup2(fds[0],0);
479             close (fds[1]);
480             system(psCmdP);
481             exit(0);
482             
483         }
484         close (fds[0]);
485         fd = fds[1];
486         TRACE("Need to execute a cmnd and pipe the output to it\n");
487     }
488     else
489     {
490         DOS_FULL_NAME fullName;
491
492         TRACE("Just assume it's a file\n");
493
494         /**
495          * The file name can be dos based, we have to find its
496          * Unix correspondant file name
497          */
498         DOSFS_GetFullName(psCmdP, FALSE, &fullName);
499
500         if ((fd = open(fullName.long_name, O_CREAT | O_TRUNC | O_WRONLY , 0600)) < 0)
501         {
502             ERR("Failed to create spool file %s (%s)\n", 
503                 fullName.long_name, strerror(errno));
504         }
505     }
506     return fd;
507 }
508
509 static int FreePrintJob(HANDLE16 hJob)
510 {
511     int nRet = SP_ERROR;
512     PPRINTJOB pPrintJob;
513
514     pPrintJob = FindPrintJobFromHandle(hJob);
515     if (pPrintJob != NULL)
516     {
517         gPrintJobsTable[pPrintJob->nIndex] = NULL;
518         HeapFree(GetProcessHeap(), 0, pPrintJob->pszOutput);
519         HeapFree(GetProcessHeap(), 0, pPrintJob->pszTitle);
520         if (pPrintJob->fd >= 0) close(pPrintJob->fd);
521         HeapFree(GetProcessHeap(), 0, pPrintJob);
522         nRet = SP_OK;
523     }
524     return nRet;
525 }
526
527 /**********************************************************************
528  *           OpenJob   (GDI.240)
529  *
530  */
531 HPJOB16 WINAPI OpenJob16(LPCSTR lpOutput, LPCSTR lpTitle, HDC16 hDC)
532 {
533     HPJOB16 hHandle = (HPJOB16)SP_ERROR;
534     PPRINTJOB pPrintJob;
535
536     TRACE("'%s' '%s' %04x\n", lpOutput, lpTitle, hDC);
537
538     pPrintJob = gPrintJobsTable[0];
539     if (pPrintJob == NULL)
540     {
541         int fd;
542
543         /* Try an create a spool file */
544         fd = CreateSpoolFile(lpOutput);
545         if (fd >= 0)
546         {
547             pPrintJob = HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTJOB));
548             if(pPrintJob == NULL) {
549                 WARN("Memory exausted!");
550                 return hHandle;
551             }
552             
553             hHandle = 1;
554
555             pPrintJob->pszOutput = HEAP_strdupA(GetProcessHeap(), 0, lpOutput);
556             if(lpTitle)
557                 pPrintJob->pszTitle = HEAP_strdupA(GetProcessHeap(), 0, lpTitle);
558             pPrintJob->hDC = hDC;
559             pPrintJob->fd = fd;
560             pPrintJob->nIndex = 0;
561             pPrintJob->hHandle = hHandle; 
562             gPrintJobsTable[pPrintJob->nIndex] = pPrintJob; 
563         }
564     }
565     TRACE("return %04x\n", hHandle);
566     return hHandle;
567 }
568
569 /**********************************************************************
570  *           CloseJob   (GDI.243)
571  *
572  */
573 INT16 WINAPI CloseJob16(HPJOB16 hJob)
574 {
575     int nRet = SP_ERROR;
576     PPRINTJOB pPrintJob = NULL;
577
578     TRACE("%04x\n", hJob);
579
580     pPrintJob = FindPrintJobFromHandle(hJob);
581     if (pPrintJob != NULL)
582     {
583         /* Close the spool file */
584         close(pPrintJob->fd);
585         FreePrintJob(hJob);
586         nRet  = 1;
587     }
588     return nRet;
589 }
590
591 /**********************************************************************
592  *           WriteSpool   (GDI.241)
593  *
594  */
595 INT16 WINAPI WriteSpool16(HPJOB16 hJob, LPSTR lpData, INT16 cch)
596 {
597     int nRet = SP_ERROR;
598     PPRINTJOB pPrintJob = NULL;
599
600     TRACE("%04x %08lx %04x\n", hJob, (DWORD)lpData, cch);
601
602     pPrintJob = FindPrintJobFromHandle(hJob);
603     if (pPrintJob != NULL && pPrintJob->fd >= 0 && cch)
604     {
605         if (write(pPrintJob->fd, lpData, cch) != cch)
606           nRet = SP_OUTOFDISK;
607         else
608           nRet = cch;
609         if (pPrintJob->hDC == 0) {
610             TRACE("hDC == 0 so no QueryAbort\n");
611         }
612         else if (!(QueryAbort16(pPrintJob->hDC, (nRet == SP_OUTOFDISK) ? nRet : 0 )))
613         {
614             CloseJob16(hJob); /* printing aborted */
615             nRet = SP_APPABORT;
616         }
617     }
618     return nRet;
619 }
620
621 /**********************************************************************
622  *           WriteDialog   (GDI.242)
623  *
624  */
625 INT16 WINAPI WriteDialog16(HPJOB16 hJob, LPSTR lpMsg, INT16 cchMsg)
626 {
627     TRACE("%04x %04x '%s'\n", hJob,  cchMsg, lpMsg);
628
629     return Callout.MessageBoxA(0, lpMsg, "Printing Error", MB_OKCANCEL);
630 }
631
632
633 /**********************************************************************
634  *           DeleteJob  (GDI.244)
635  *
636  */
637 INT16 WINAPI DeleteJob16(HPJOB16 hJob, INT16 nNotUsed)
638 {
639     int nRet;
640
641     TRACE("%04x\n", hJob);
642
643     nRet = FreePrintJob(hJob);
644     return nRet;
645 }
646
647 /* 
648  * The following two function would allow a page to be sent to the printer
649  * when it has been processed.  For simplicity they havn't been implemented.
650  * This means a whole job has to be processed before it is sent to the printer.
651  */
652
653 /**********************************************************************
654  *           StartSpoolPage   (GDI.246)
655  *
656  */
657 INT16 WINAPI StartSpoolPage16(HPJOB16 hJob)
658 {
659     FIXME("StartSpoolPage GDI.246 unimplemented\n");
660     return 1;
661
662 }
663
664
665 /**********************************************************************
666  *           EndSpoolPage   (GDI.247)
667  *
668  */
669 INT16 WINAPI EndSpoolPage16(HPJOB16 hJob)
670 {
671     FIXME("EndSpoolPage GDI.247 unimplemented\n");
672     return 1;
673 }
674
675
676 /**********************************************************************
677  *           GetSpoolJob   (GDI.245)
678  *
679  */
680 DWORD WINAPI GetSpoolJob16(int nOption, LONG param)
681 {
682     DWORD retval = 0;
683     TRACE("In GetSpoolJob param 0x%lx noption %d\n",param, nOption);
684     return retval;
685 }
686
687
688 /******************************************************************
689  *                  DrvGetPrinterDataInternal
690  *
691  * Helper for DrvGetPrinterData
692  */
693 static DWORD DrvGetPrinterDataInternal(LPSTR RegStr_Printer,
694 LPBYTE lpPrinterData, int cbData, int what)
695 {
696     DWORD res = -1;
697     HKEY hkey;
698     DWORD dwType, cbQueryData;
699
700     if (!(RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey))) {
701         if (what == INT_PD_DEFAULT_DEVMODE) { /* "Default DevMode" */
702             if (!(RegQueryValueExA(hkey, DefaultDevMode, 0, &dwType, 0, &cbQueryData))) {
703                 if (!lpPrinterData)
704                     res = cbQueryData;
705                 else if ((cbQueryData) && (cbQueryData <= cbData)) {
706                     cbQueryData = cbData;
707                     if (RegQueryValueExA(hkey, DefaultDevMode, 0,
708                                 &dwType, lpPrinterData, &cbQueryData))
709                         res = cbQueryData;
710                 }
711             }
712         } else { /* "Printer Driver" */
713             cbQueryData = 32;
714             RegQueryValueExA(hkey, "Printer Driver", 0,
715                         &dwType, lpPrinterData, &cbQueryData);
716             res = cbQueryData;
717         }
718     }
719     if (hkey) RegCloseKey(hkey);
720     return res;
721 }
722
723 /******************************************************************
724  *                DrvGetPrinterData     [GDI.282]
725  *
726  */
727 DWORD WINAPI DrvGetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
728                                LPDWORD lpType, LPBYTE lpPrinterData,
729                                int cbData, LPDWORD lpNeeded)
730 {
731     LPSTR RegStr_Printer;
732     HKEY hkey = 0, hkey2 = 0;
733     DWORD res = 0;
734     DWORD dwType, PrinterAttr, cbPrinterAttr, SetData, size;
735
736     if (HIWORD(lpPrinter))
737             TRACE("printer %s\n",lpPrinter);
738     else
739             TRACE("printer %p\n",lpPrinter);
740     if (HIWORD(lpProfile))
741             TRACE("profile %s\n",lpProfile);
742     else
743             TRACE("profile %p\n",lpProfile);
744     TRACE("lpType %p\n",lpType);
745
746     if ((!lpPrinter) || (!lpProfile) || (!lpNeeded))
747         return ERROR_INVALID_PARAMETER;
748
749     RegStr_Printer = HeapAlloc(GetProcessHeap(), 0,
750                                strlen(Printers) + strlen(lpPrinter) + 2);
751     strcpy(RegStr_Printer, Printers);
752     strcat(RegStr_Printer, lpPrinter);
753
754     if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
755     (!strcmp(lpProfile, DefaultDevMode)))) {
756         size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
757                                          INT_PD_DEFAULT_DEVMODE);
758         if (size+1) {
759             *lpNeeded = size;
760             if ((lpPrinterData) && (*lpNeeded > cbData))
761                 res = ERROR_MORE_DATA;
762         }
763         else res = ERROR_INVALID_PRINTER_NAME;
764     }
765     else
766     if (((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
767     (!strcmp(lpProfile, PrinterModel)))) {
768         *lpNeeded = 32;
769         if (!lpPrinterData) goto failed;
770         if (cbData < 32) {
771             res = ERROR_MORE_DATA;
772             goto failed;
773         }
774         size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
775                                          INT_PD_DEFAULT_MODEL);
776         if ((size+1) && (lpType))
777             *lpType = REG_SZ;
778         else
779             res = ERROR_INVALID_PRINTER_NAME;
780     }
781     else
782     {
783         if ((res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)))
784             goto failed;
785         cbPrinterAttr = 4;
786         if ((res = RegQueryValueExA(hkey, "Attributes", 0,
787                         &dwType, (LPBYTE)&PrinterAttr, &cbPrinterAttr)))
788             goto failed;
789         if ((res = RegOpenKeyA(hkey, PrinterDriverData, &hkey2)))
790             goto failed;
791         *lpNeeded = cbData;
792         res = RegQueryValueExA(hkey2, lpProfile, 0,
793                 lpType, lpPrinterData, lpNeeded);
794         if ((res != ERROR_CANTREAD) &&
795          ((PrinterAttr &
796         (PRINTER_ATTRIBUTE_ENABLE_BIDI|PRINTER_ATTRIBUTE_NETWORK))
797         == PRINTER_ATTRIBUTE_NETWORK))
798         {
799             if (!(res) && (*lpType == REG_DWORD) && (*(LPDWORD)lpPrinterData == -1))
800                 res = ERROR_INVALID_DATA;
801         }
802         else
803         {
804             SetData = -1;
805             RegSetValueExA(hkey2, lpProfile, 0, REG_DWORD, (LPBYTE)&SetData, 4); /* no result returned */
806         }
807     }
808         
809 failed:
810     if (hkey2) RegCloseKey(hkey2);
811     if (hkey) RegCloseKey(hkey);
812     HeapFree(GetProcessHeap(), 0, RegStr_Printer);
813     return res;
814 }
815
816
817 /******************************************************************
818  *                 DrvSetPrinterData     [GDI.281]
819  *
820  */
821 DWORD WINAPI DrvSetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
822                                DWORD lpType, LPBYTE lpPrinterData,
823                                DWORD dwSize)
824 {
825     LPSTR RegStr_Printer;
826     HKEY hkey = 0;
827     DWORD res = 0;
828
829     if (HIWORD(lpPrinter))
830             TRACE("printer %s\n",lpPrinter);
831     else
832             TRACE("printer %p\n",lpPrinter);
833     if (HIWORD(lpProfile))
834             TRACE("profile %s\n",lpProfile);
835     else
836             TRACE("profile %p\n",lpProfile);
837     TRACE("lpType %08lx\n",lpType);
838
839     if ((!lpPrinter) || (!lpProfile) ||
840     ((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
841     (!strcmp(lpProfile, PrinterModel))))
842         return ERROR_INVALID_PARAMETER;
843
844     RegStr_Printer = HeapAlloc(GetProcessHeap(), 0,
845                         strlen(Printers) + strlen(lpPrinter) + 2);
846     strcpy(RegStr_Printer, Printers);
847     strcat(RegStr_Printer, lpPrinter);
848
849     if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
850     (!strcmp(lpProfile, DefaultDevMode)))) {
851         if ( RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey) 
852              != ERROR_SUCCESS ||
853              RegSetValueExA(hkey, DefaultDevMode, 0, REG_BINARY, 
854                               lpPrinterData, dwSize) != ERROR_SUCCESS )
855                 res = ERROR_INVALID_PRINTER_NAME;
856     }
857     else
858     {
859         strcat(RegStr_Printer, "\\");
860
861         if( (res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)) ==
862             ERROR_SUCCESS ) {
863
864             if (!lpPrinterData) 
865                 res = RegDeleteValueA(hkey, lpProfile);
866             else
867                 res = RegSetValueExA(hkey, lpProfile, 0, lpType,
868                                        lpPrinterData, dwSize);
869         }
870     }
871
872     if (hkey) RegCloseKey(hkey);
873     HeapFree(GetProcessHeap(), 0, RegStr_Printer);
874     return res;
875 }