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