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