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