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