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