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