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