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