New CUPS libraries return "none" as default printer instead of NULL.
[wine] / dlls / winspool / info.c
1 /*
2  * WINSPOOL functions
3  *
4  * Copyright 1996 John Harvey
5  * Copyright 1998 Andreas Mohr
6  * Copyright 1999 Klaas van Gend
7  * Copyright 1999, 2000 Huw D M Davies
8  * Copyright 2001 Marcus Meissner
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 #include "config.h"
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <stddef.h>
32 #ifdef HAVE_CUPS
33 # include <cups/cups.h>
34 #endif
35 #include "winspool.h"
36 #include "winbase.h"
37 #include "winerror.h"
38 #include "winreg.h"
39 #include "wine/windef16.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42 #include "heap.h"
43 #include "winnls.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
46
47 static LPWSTR *printer_array;
48 static int nb_printers;
49
50 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
51                                                      WORD fwCapability, LPSTR lpszOutput,
52                                                      LPDEVMODEA lpdm );
53 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
54                                               LPSTR lpszDevice, LPSTR lpszPort,
55                                               LPDEVMODEA lpdmInput, LPSTR lpszProfile,
56                                               DWORD fwMode );
57
58 static char Printers[] =
59 "System\\CurrentControlSet\\control\\Print\\Printers\\";
60 static char Drivers[] =
61 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
62
63 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
64
65 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
66                                       'i','o','n',' ','F','i','l','e',0};
67 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
68 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
69 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
70                                    'M','o','d','e',0};
71 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
72                                    'i','l','e','s',0};
73 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
74 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
75 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
76 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
77 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
78 static WCHAR NameW[] = {'N','a','m','e',0};
79 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
80 static WCHAR PortW[] = {'P','o','r','t',0};
81 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
82                                    's','s','o','r',0};
83 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
84                                   'v','e','r',0};
85 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
86                                      'v','e','r','D','a','t','a',0};
87 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
88                                   'i','l','e',0};
89 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
90 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
91
92 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
93 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
94                                       DWORD Level, LPBYTE pDriverInfo,
95                                       DWORD cbBuf, LPDWORD pcbNeeded,
96                                       BOOL unicode);
97 static void
98 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
99     char qbuf[200];
100
101     /* If forcing, or no profile string entry for device yet, set the entry
102      *
103      * The always change entry if not WINEPS yet is discussable.
104      */
105     if (force                                                           ||
106         !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf))    ||
107         !strcmp(qbuf,"*")                                               ||
108         !strstr(qbuf,"WINEPS")
109     ) {
110         char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
111
112         sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
113         WriteProfileStringA("windows","device",buf);
114         HeapFree(GetProcessHeap(),0,buf);
115     }
116 }
117
118 #ifdef HAVE_CUPS
119 BOOL
120 CUPS_LoadPrinters(void) {
121     char                **printers;
122     int                 i,nrofdests,hadprinter = FALSE;
123     PRINTER_INFO_2A     pinfo2a;
124     const char*         def = cupsGetDefault();
125
126     nrofdests = cupsGetPrinters(&printers);
127
128     if (def && !strcmp(def,"none")) /* CUPS has "none" for no default printer */
129         def = NULL;
130
131     for (i=0;i<nrofdests;i++) {
132         const char *ppd = cupsGetPPD(printers[i]);
133         char    *port,*devline;
134
135         if (!ppd) {
136             WARN("No ppd file for %s.\n",printers[i]);
137             /* If this was going to be the default printer,
138              * forget it and use another one.
139              */
140             if (def && !strcmp(def,printers[i]))
141                 def = NULL;
142             continue;
143         }
144         unlink(ppd);
145
146         hadprinter = TRUE;
147
148         if (def && !strcmp(def,printers[i]))
149                 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
150
151         /* The default printer has no PPD file, just use the first one
152          * which has one.
153          */
154         if (!def) {
155                 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
156                 def = printers[i];
157         }
158         memset(&pinfo2a,0,sizeof(pinfo2a));
159         pinfo2a.pPrinterName    = printers[i];
160         pinfo2a.pDatatype       = "RAW";
161         pinfo2a.pPrintProcessor = "WinPrint";
162         pinfo2a.pDriverName     = "PS Driver";
163         pinfo2a.pComment        = "WINEPS Printer using CUPS";
164         pinfo2a.pLocation       = "<physical location of printer>";
165         port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(printers[i])+1);
166         sprintf(port,"LPR:%s",printers[i]);
167         pinfo2a.pPortName       = port;
168         pinfo2a.pParameters     = "<parameters?>";
169         pinfo2a.pShareName      = "<share name?>";
170         pinfo2a.pSepFile        = "<sep file?>";
171
172         devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
173         sprintf(devline,"WINEPS,%s",port);
174         WriteProfileStringA("devices",printers[i],devline);
175         HeapFree(GetProcessHeap(),0,devline);
176
177         if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
178             if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
179                 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",printers[i],GetLastError());
180         }
181         HeapFree(GetProcessHeap(),0,port);
182     }
183     return hadprinter;
184 }
185 #endif
186
187 static BOOL
188 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
189     PRINTER_INFO_2A     pinfo2a;
190     char                *s,*name,*prettyname,*devname;
191     BOOL                isps = FALSE;
192     char                *port,*devline;
193
194     while (isspace(*pent)) pent++;
195     s = strchr(pent,':');
196     if (!s) return FALSE;
197     *s='\0';
198     name = pent;
199     pent = s+1;
200     TRACE("%s\n",name);
201
202     /* Determine whether this is a postscript printer. */
203
204     /* 1. Check if name or aliases contain trigger phrases like 'ps' */
205     if (strstr(name,"ps")               ||
206         strstr(name,"pd")               ||      /* postscript double page */
207         strstr(name,"postscript")       ||
208         strstr(name,"PostScript")
209     ) {
210         TRACE("%s has 'ps' style name, assuming postscript.\n",name);
211         isps = TRUE;
212     }
213     /* 2. Check if this is a remote printer. These usually are postscript
214      *    capable
215      */
216     if (strstr(pent,":rm")) {
217         isps = TRUE;
218         TRACE("%s is remote, assuming postscript.\n",name);
219     }
220     /* 3. Check if we have an input filter program. If we have one, it
221      *    most likely is one capable of converting postscript.
222      *    (Could probably check for occurrence of 'gs' or 'ghostscript'
223      *     in the if file itself.)
224      */
225     if (strstr(pent,":if=/")) {
226         isps = TRUE;
227         TRACE("%s has inputfilter program, assuming postscript.\n",name);
228     }
229
230     /* If it is not a postscript printer, we cannot use it. */
231     if (!isps)
232         return FALSE;
233
234     prettyname = name;
235     /* Get longest name, usually the one at the right for later display. */
236     while ((s=strchr(prettyname,'|'))) prettyname = s+1;
237     s=strchr(name,'|');if (s) *s='\0';
238
239     /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
240      * if it is too long, we use it as comment below. */
241     devname = prettyname;
242     if (strlen(devname)>=CCHDEVICENAME-1)
243          devname = name;
244     if (strlen(devname)>=CCHDEVICENAME-1)
245         return FALSE;
246
247     if (isfirst) /* set first entry as default */
248             WINSPOOL_SetDefaultPrinter(devname,name,FALSE);
249
250     memset(&pinfo2a,0,sizeof(pinfo2a));
251     pinfo2a.pPrinterName        = devname;
252     pinfo2a.pDatatype           = "RAW";
253     pinfo2a.pPrintProcessor     = "WinPrint";
254     pinfo2a.pDriverName         = "PS Driver";
255     pinfo2a.pComment            = "WINEPS Printer using LPR";
256     pinfo2a.pLocation           = prettyname;
257     port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
258     sprintf(port,"LPR:%s",name);
259     pinfo2a.pPortName           = port;
260     pinfo2a.pParameters         = "<parameters?>";
261     pinfo2a.pShareName          = "<share name?>";
262     pinfo2a.pSepFile            = "<sep file?>";
263
264     devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
265     sprintf(devline,"WINEPS,%s",port);
266     WriteProfileStringA("devices",devname,devline);
267     HeapFree(GetProcessHeap(),0,devline);
268
269     if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
270         if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
271             ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
272     }
273     HeapFree(GetProcessHeap(),0,port);
274     return TRUE;
275 }
276
277 static BOOL
278 PRINTCAP_LoadPrinters(void) {
279     BOOL                hadprinter = FALSE, isfirst = TRUE;
280     char                buf[200];
281     FILE                *f;
282
283     f = fopen("/etc/printcap","r");
284     if (!f)
285         return FALSE;
286
287     while (fgets(buf,sizeof(buf),f)) {
288         char    *pent = NULL;
289         do {
290             char        *s;
291             s=strchr(buf,'\n'); if (s) *s='\0';
292             if ((buf[0]=='#') || (buf[0]=='\0'))
293                 continue;
294
295             if (pent) {
296                 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
297                 strcat(pent,buf);
298             } else {
299                 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
300                 strcpy(pent,buf);
301             }
302
303             if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
304                 pent[strlen(pent)-1] = '\0';
305             else
306                 break;
307         } while (fgets(buf,sizeof(buf),f));
308         if (pent)
309             hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
310         isfirst = FALSE;
311         if (pent) HeapFree(GetProcessHeap(),0,pent);
312         pent = NULL;
313         if (feof(f)) break;
314     }
315     fclose(f);
316     return hadprinter;
317 }
318
319 static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
320 {
321     return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
322                    lstrlenW(value) * sizeof(WCHAR));
323 }
324
325 void
326 WINSPOOL_LoadSystemPrinters() {
327     HKEY                hkPPD;
328     DRIVER_INFO_3A      di3a;
329     di3a.cVersion = 0x400;
330     di3a.pName = "PS Driver";
331     di3a.pEnvironment = NULL;   /* NULL means auto */
332     di3a.pDriverPath = "wineps.drv";
333     di3a.pDataFile = "<datafile?>";
334     di3a.pConfigFile = "wineps.drv";
335     di3a.pHelpFile = "<helpfile?>";
336     di3a.pDependentFiles = "<dependend files?>";
337     di3a.pMonitorName = "<monitor name?>";
338     di3a.pDefaultDataType = "RAW";
339
340     if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
341         ERR("Failed adding PS Driver (%ld)\n",GetLastError());
342         return;
343     }
344 #ifdef HAVE_CUPS
345     /* If we have any CUPS based printers, skip looking for printcap printers */
346     if (CUPS_LoadPrinters())
347         return;
348 #endif
349
350     /* Check for [ppd] section in config file before parsing /etc/printcap */
351
352     if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
353             &hkPPD) == ERROR_SUCCESS)
354     {
355         RegCloseKey(hkPPD);
356         PRINTCAP_LoadPrinters();
357     }
358 }
359
360
361 /******************************************************************
362  *  WINSPOOL_GetOpenedPrinterEntry
363  *  Get the first place empty in the opened printer table
364  */
365 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
366 {
367     int i;
368
369     for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
370
371     if (i >= nb_printers)
372     {
373         LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), 0, printer_array,
374                                          (nb_printers + 16) * sizeof(*new_array) );
375         if (!new_array) return 0;
376         printer_array = new_array;
377         nb_printers += 16;
378     }
379
380     if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
381     {
382         strcpyW( printer_array[i], name );
383         return (HANDLE)(i + 1);
384     }
385     return 0;
386 }
387
388 /******************************************************************
389  *  WINSPOOL_GetOpenedPrinter
390  *  Get the pointer to the opened printer referred by the handle
391  */
392 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
393 {
394     int idx = (int)printerHandle;
395     if ((idx <= 0) || (idx > nb_printers))
396     {
397         SetLastError(ERROR_INVALID_HANDLE);
398         return NULL;
399     }
400     return printer_array[idx - 1];
401 }
402
403 /******************************************************************
404  *  WINSPOOL_GetOpenedPrinterRegKey
405  *
406  */
407 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
408 {
409     LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
410     DWORD ret;
411     HKEY hkeyPrinters;
412
413     if(!name) return ERROR_INVALID_HANDLE;
414
415     if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
416        ERROR_SUCCESS)
417         return ret;
418
419     if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
420     {
421         ERR("Can't find opened printer %s in registry\n",
422             debugstr_w(name));
423         RegCloseKey(hkeyPrinters);
424         return ERROR_INVALID_PRINTER_NAME; /* ? */
425     }
426     RegCloseKey(hkeyPrinters);
427     return ERROR_SUCCESS;
428 }
429
430 /***********************************************************
431  *      DEVMODEcpyAtoW
432  */
433 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
434 {
435     BOOL Formname;
436     ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
437     DWORD size;
438
439     Formname = (dmA->dmSize > off_formname);
440     size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
441     MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
442                         CCHDEVICENAME);
443     if(!Formname) {
444       memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
445              dmA->dmSize - CCHDEVICENAME);
446     } else {
447       memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
448              off_formname - CCHDEVICENAME);
449       MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
450                           CCHFORMNAME);
451       memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
452              (off_formname + CCHFORMNAME));
453     }
454     dmW->dmSize = size;
455     memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
456            dmA->dmDriverExtra);
457     return dmW;
458 }
459
460 /***********************************************************
461  *      DEVMODEdupAtoW
462  * Creates a unicode copy of supplied devmode on heap
463  */
464 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
465 {
466     LPDEVMODEW dmW;
467     DWORD size;
468     BOOL Formname;
469     ptrdiff_t off_formname;
470
471     TRACE("\n");
472     if(!dmA) return NULL;
473
474     off_formname = (char *)dmA->dmFormName - (char *)dmA;
475     Formname = (dmA->dmSize > off_formname);
476     size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
477     dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
478     return DEVMODEcpyAtoW(dmW, dmA);
479 }
480
481 /***********************************************************
482  *      DEVMODEdupWtoA
483  * Creates an ascii copy of supplied devmode on heap
484  */
485 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
486 {
487     LPDEVMODEA dmA;
488     DWORD size;
489     BOOL Formname;
490     ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
491
492     if(!dmW) return NULL;
493     Formname = (dmW->dmSize > off_formname);
494     size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
495     dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
496     WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
497                         CCHDEVICENAME, NULL, NULL);
498     if(!Formname) {
499       memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
500              dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
501     } else {
502       memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
503              off_formname - CCHDEVICENAME * sizeof(WCHAR));
504       WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
505                           CCHFORMNAME, NULL, NULL);
506       memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
507              (off_formname + CCHFORMNAME * sizeof(WCHAR)));
508     }
509     dmA->dmSize = size;
510     memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
511            dmW->dmDriverExtra);
512     return dmA;
513 }
514
515 /***********************************************************
516  *             PRINTER_INFO_2AtoW
517  * Creates a unicode copy of PRINTER_INFO_2A on heap
518  */
519 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
520 {
521     LPPRINTER_INFO_2W piW;
522     if(!piA) return NULL;
523     piW = HeapAlloc(heap, 0, sizeof(*piW));
524     memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
525     piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
526     piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
527     piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
528     piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
529     piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
530     piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
531     piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
532     piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
533     piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
534     piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
535     piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
536     piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
537     return piW;
538 }
539
540 /***********************************************************
541  *       FREE_PRINTER_INFO_2W
542  * Free PRINTER_INFO_2W and all strings
543  */
544 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
545 {
546     if(!piW) return;
547
548     HeapFree(heap,0,piW->pServerName);
549     HeapFree(heap,0,piW->pPrinterName);
550     HeapFree(heap,0,piW->pShareName);
551     HeapFree(heap,0,piW->pPortName);
552     HeapFree(heap,0,piW->pDriverName);
553     HeapFree(heap,0,piW->pComment);
554     HeapFree(heap,0,piW->pLocation);
555     HeapFree(heap,0,piW->pDevMode);
556     HeapFree(heap,0,piW->pSepFile);
557     HeapFree(heap,0,piW->pPrintProcessor);
558     HeapFree(heap,0,piW->pDatatype);
559     HeapFree(heap,0,piW->pParameters);
560     HeapFree(heap,0,piW);
561     return;
562 }
563
564 /******************************************************************
565  *              DeviceCapabilities     [WINSPOOL.@]
566  *              DeviceCapabilitiesA    [WINSPOOL.@]
567  *
568  */
569 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
570                                LPSTR pOutput, LPDEVMODEA lpdm)
571 {
572     INT ret;
573
574     if (!GDI_CallDeviceCapabilities16)
575     {
576         GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
577                                                               (LPCSTR)104 );
578         if (!GDI_CallDeviceCapabilities16) return -1;
579     }
580     ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
581
582     /* If DC_PAPERSIZE map POINT16s to POINTs */
583     if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
584         POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
585         POINT *pt = (POINT *)pOutput;
586         INT i;
587         memcpy(tmp, pOutput, ret * sizeof(POINT16));
588         for(i = 0; i < ret; i++, pt++)
589         {
590             pt->x = tmp[i].x;
591             pt->y = tmp[i].y;
592         }
593         HeapFree( GetProcessHeap(), 0, tmp );
594     }
595     return ret;
596 }
597
598
599 /*****************************************************************************
600  *          DeviceCapabilitiesW        [WINSPOOL.@]
601  *
602  * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
603  *
604  */
605 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
606                                WORD fwCapability, LPWSTR pOutput,
607                                const DEVMODEW *pDevMode)
608 {
609     LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
610     LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
611     LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
612     INT ret;
613
614     if(pOutput && (fwCapability == DC_BINNAMES ||
615                    fwCapability == DC_FILEDEPENDENCIES ||
616                    fwCapability == DC_PAPERNAMES)) {
617       /* These need A -> W translation */
618         INT size = 0, i;
619         LPSTR pOutputA;
620         ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
621                                   dmA);
622         if(ret == -1)
623             return ret;
624         switch(fwCapability) {
625         case DC_BINNAMES:
626             size = 24;
627             break;
628         case DC_PAPERNAMES:
629         case DC_FILEDEPENDENCIES:
630             size = 64;
631             break;
632         }
633         pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
634         ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
635                                   dmA);
636         for(i = 0; i < ret; i++)
637             MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
638                                 pOutput + (i * size), size);
639         HeapFree(GetProcessHeap(), 0, pOutputA);
640     } else {
641         ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
642                                   (LPSTR)pOutput, dmA);
643     }
644     HeapFree(GetProcessHeap(),0,pPortA);
645     HeapFree(GetProcessHeap(),0,pDeviceA);
646     HeapFree(GetProcessHeap(),0,dmA);
647     return ret;
648 }
649
650 /******************************************************************
651  *              DocumentPropertiesA   [WINSPOOL.@]
652  *
653  */
654 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
655                                 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
656                                 LPDEVMODEA pDevModeInput,DWORD fMode )
657 {
658     LPSTR lpName = pDeviceName;
659     LONG ret;
660
661     TRACE("(%d,%d,%s,%p,%p,%ld)\n",
662         hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
663     );
664
665     if(!pDeviceName) {
666         LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
667         if(!lpNameW) {
668                 ERR("no name from hPrinter?\n");
669                 return -1;
670         }
671         lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
672     }
673
674     if (!GDI_CallExtDeviceMode16)
675     {
676         GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
677                                                          (LPCSTR)102 );
678         if (!GDI_CallExtDeviceMode16) {
679                 ERR("No CallExtDeviceMode16?\n");
680                 return -1;
681         }
682     }
683     ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
684                                   pDevModeInput, NULL, fMode);
685
686     if(!pDeviceName)
687         HeapFree(GetProcessHeap(),0,lpName);
688     return ret;
689 }
690
691
692 /*****************************************************************************
693  *          DocumentPropertiesW (WINSPOOL.@)
694  */
695 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
696                                 LPWSTR pDeviceName,
697                                 LPDEVMODEW pDevModeOutput,
698                                 LPDEVMODEW pDevModeInput, DWORD fMode)
699 {
700
701     LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
702     LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
703     LPDEVMODEA pDevModeOutputA = NULL;
704     LONG ret;
705
706     TRACE("(%d,%d,%s,%p,%p,%ld)\n",
707           hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
708           fMode);
709     if(pDevModeOutput) {
710         ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
711         if(ret < 0) return ret;
712         pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
713     }
714     ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
715                               pDevModeInputA, fMode);
716     if(pDevModeOutput) {
717         DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
718         HeapFree(GetProcessHeap(),0,pDevModeOutputA);
719     }
720     if(fMode == 0 && ret > 0)
721         ret += (CCHDEVICENAME + CCHFORMNAME);
722     HeapFree(GetProcessHeap(),0,pDevModeInputA);
723     HeapFree(GetProcessHeap(),0,pDeviceNameA);
724     return ret;
725 }
726
727 /******************************************************************
728  *              OpenPrinterA        [WINSPOOL.@]
729  *
730  */
731 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
732                          LPPRINTER_DEFAULTSA pDefault)
733 {
734     LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
735     PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
736     BOOL ret;
737
738     if(pDefault) {
739         DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
740                                              pDefault->pDatatype);
741         DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
742                                            pDefault->pDevMode);
743         DefaultW.DesiredAccess = pDefault->DesiredAccess;
744         pDefaultW = &DefaultW;
745     }
746     ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
747     if(pDefault) {
748         HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
749         HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
750     }
751     HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
752     return ret;
753 }
754
755 /******************************************************************
756  *              OpenPrinterW        [WINSPOOL.@]
757  *
758  */
759 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
760                          LPPRINTER_DEFAULTSW pDefault)
761 {
762     HKEY hkeyPrinters, hkeyPrinter;
763
764     if (!lpPrinterName) {
765        FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
766        SetLastError(ERROR_INVALID_PARAMETER);
767        return FALSE;
768     }
769
770     TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
771           pDefault);
772
773     /* Check Printer exists */
774     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
775        ERROR_SUCCESS) {
776         ERR("Can't create Printers key\n");
777         SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
778         return FALSE;
779     }
780
781     if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
782        RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
783        != ERROR_SUCCESS) {
784         TRACE("Can't find printer %s in registry\n",
785               debugstr_w(lpPrinterName));
786         RegCloseKey(hkeyPrinters);
787         SetLastError(ERROR_INVALID_PRINTER_NAME);
788         return FALSE;
789     }
790     RegCloseKey(hkeyPrinter);
791     RegCloseKey(hkeyPrinters);
792
793     if(!phPrinter) /* This seems to be what win95 does anyway */
794         return TRUE;
795
796     /* Get the unique handle of the printer*/
797     *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
798
799     if (pDefault != NULL)
800         FIXME("Not handling pDefault\n");
801
802     return TRUE;
803 }
804
805 /******************************************************************
806  *              AddMonitorA        [WINSPOOL.@]
807  *
808  */
809 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
810 {
811     FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
812     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
813     return FALSE;
814 }
815
816 /******************************************************************
817  *              DeletePrinterDriverA        [WINSPOOL.@]
818  *
819  */
820 BOOL WINAPI
821 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
822 {
823     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
824           debugstr_a(pDriverName));
825     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
826     return FALSE;
827 }
828
829
830 /******************************************************************
831  *              DeleteMonitorA        [WINSPOOL.@]
832  *
833  */
834 BOOL WINAPI
835 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
836 {
837     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
838           debugstr_a(pMonitorName));
839     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
840     return FALSE;
841 }
842
843
844 /******************************************************************
845  *              DeletePortA        [WINSPOOL.@]
846  *
847  */
848 BOOL WINAPI
849 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
850 {
851     FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
852           debugstr_a(pPortName));
853     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
854     return FALSE;
855 }
856
857 /******************************************************************************
858  *    SetPrinterW  [WINSPOOL.@]
859  */
860 BOOL WINAPI
861 SetPrinterW(
862   HANDLE  hPrinter,
863   DWORD     Level,
864   LPBYTE    pPrinter,
865   DWORD     Command) {
866
867     FIXME("():stub\n");
868     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
869     return FALSE;
870 }
871
872 /******************************************************************************
873  *    WritePrinter  [WINSPOOL.@]
874  */
875 BOOL WINAPI
876 WritePrinter(
877   HANDLE  hPrinter,
878   LPVOID  pBuf,
879   DWORD   cbBuf,
880   LPDWORD pcWritten) {
881
882     FIXME("():stub\n");
883     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
884     return FALSE;
885 }
886
887 /*****************************************************************************
888  *          AddFormA  [WINSPOOL.@]
889  */
890 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
891 {
892     FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
893     return 1;
894 }
895
896 /*****************************************************************************
897  *          AddFormW  [WINSPOOL.@]
898  */
899 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
900 {
901     FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
902     return 1;
903 }
904
905 /*****************************************************************************
906  *          AddJobA  [WINSPOOL.@]
907  */
908 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
909                         DWORD cbBuf, LPDWORD pcbNeeded)
910 {
911     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
912           pcbNeeded);
913     return 1;
914 }
915
916 /*****************************************************************************
917  *          AddJobW  [WINSPOOL.@]
918  */
919 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
920                         LPDWORD pcbNeeded)
921 {
922     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
923           pcbNeeded);
924     return 1;
925 }
926
927 /*****************************************************************************
928  *          WINSPOOL_OpenDriverReg [internal]
929  *
930  * opens the registry for the printer drivers depending on the given input
931  * variable pEnvironment
932  *
933  * RETURNS:
934  *    the opened hkey on success
935  *    NULL on error
936  */
937 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
938 {   HKEY  retval;
939     LPSTR lpKey, p = NULL;
940
941     TRACE("%s\n",
942           (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
943
944     if(pEnvironment)
945         p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
946                         pEnvironment;
947     else {
948         OSVERSIONINFOA ver;
949         ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
950
951         if(!GetVersionExA( &ver))
952             return 0;
953
954         switch (ver.dwPlatformId) {
955              case VER_PLATFORM_WIN32s:
956                   ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
957                   return 0;
958
959              case VER_PLATFORM_WIN32_NT:
960                   p = "Windows NT x86";
961                   break;
962              default:
963                   p = "Windows 4.0";
964                   break;
965         }
966         TRACE("set environment to %s\n", p);
967     }
968
969     lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
970                        strlen(p) + strlen(Drivers));
971     sprintf( lpKey, Drivers, p);
972
973     TRACE("%s\n", lpKey);
974
975     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
976        ERROR_SUCCESS)
977        retval = 0;
978
979     if(pEnvironment && unicode)
980        HeapFree( GetProcessHeap(), 0, p);
981     HeapFree( GetProcessHeap(), 0, lpKey);
982
983     return retval;
984 }
985
986 /*****************************************************************************
987  *          AddPrinterW  [WINSPOOL.@]
988  */
989 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
990 {
991     PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
992     LPDEVMODEA dmA;
993     LPDEVMODEW dmW;
994     HANDLE retval;
995     HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
996     LONG size;
997
998     TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
999
1000     if(pName != NULL) {
1001         ERR("pName = %s - unsupported\n", debugstr_w(pName));
1002         SetLastError(ERROR_INVALID_PARAMETER);
1003         return 0;
1004     }
1005     if(Level != 2) {
1006         ERR("Level = %ld, unsupported!\n", Level);
1007         SetLastError(ERROR_INVALID_LEVEL);
1008         return 0;
1009     }
1010     if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1011         ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1012                 debugstr_w(pi->pPrinterName)
1013         );
1014         SetLastError(ERROR_INVALID_LEVEL);
1015         return 0;
1016     }
1017     if(!pPrinter) {
1018         SetLastError(ERROR_INVALID_PARAMETER);
1019         return 0;
1020     }
1021     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1022        ERROR_SUCCESS) {
1023         ERR("Can't create Printers key\n");
1024         return 0;
1025     }
1026     if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1027         if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1028             SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1029             RegCloseKey(hkeyPrinter);
1030             RegCloseKey(hkeyPrinters);
1031             return 0;
1032         }
1033         RegCloseKey(hkeyPrinter);
1034     }
1035     hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1036     if(!hkeyDrivers) {
1037         ERR("Can't create Drivers key\n");
1038         RegCloseKey(hkeyPrinters);
1039         return 0;
1040     }
1041     if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1042        ERROR_SUCCESS) {
1043         WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1044         RegCloseKey(hkeyPrinters);
1045         RegCloseKey(hkeyDrivers);
1046         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1047         return 0;
1048     }
1049     RegCloseKey(hkeyDriver);
1050     RegCloseKey(hkeyDrivers);
1051
1052     if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) {  /* FIXME */
1053         FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1054         SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1055         RegCloseKey(hkeyPrinters);
1056         return 0;
1057     }
1058
1059     if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1060        ERROR_SUCCESS) {
1061         FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1062         SetLastError(ERROR_INVALID_PRINTER_NAME);
1063         RegCloseKey(hkeyPrinters);
1064         return 0;
1065     }
1066     RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1067                    (LPBYTE)&pi->Attributes, sizeof(DWORD));
1068     set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1069
1070     /* See if we can load the driver.  We may need the devmode structure anyway
1071      *
1072      * FIXME:
1073      * Note that DocumentPropertiesW will briefly try to open the printer we
1074      * just create to find a DEVMODEA struct (it will use the WINEPS default
1075      * one in case it is not there, so we are ok).
1076      */
1077     size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
1078     if(size < 0) {
1079         FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1080         size = sizeof(DEVMODEW);
1081     }
1082     if(pi->pDevMode)
1083         dmW = pi->pDevMode;
1084     else {
1085         dmW = HeapAlloc(GetProcessHeap(), 0, size);
1086         dmW->dmSize = size;
1087         if (0>DocumentPropertiesW(0,-1,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
1088             ERR("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1089             SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1090             return 0;
1091         }
1092         /* set devmode to printer name */
1093         strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1094     }
1095
1096     /* Write DEVMODEA not DEVMODEW into reg.  This is what win9x does
1097        and we support these drivers.  NT writes DEVMODEW so somehow
1098        we'll need to distinguish between these when we support NT
1099        drivers */
1100     dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1101     RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
1102                    dmA->dmSize + dmA->dmDriverExtra);
1103     HeapFree(GetProcessHeap(), 0, dmA);
1104     if(!pi->pDevMode)
1105         HeapFree(GetProcessHeap(), 0, dmW);
1106     set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1107     set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1108     set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1109     set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1110
1111     set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1112     set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1113     set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1114     RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1115                    (LPBYTE)&pi->Priority, sizeof(DWORD));
1116     set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1117     set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1118     RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1119                    (LPBYTE)&pi->StartTime, sizeof(DWORD));
1120     RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1121                    (LPBYTE)&pi->Status, sizeof(DWORD));
1122     RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1123                    (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1124
1125     RegCloseKey(hkeyPrinter);
1126     RegCloseKey(hkeyPrinters);
1127     if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1128         ERR("OpenPrinter failing\n");
1129         return 0;
1130     }
1131     return retval;
1132 }
1133
1134 /*****************************************************************************
1135  *          AddPrinterA  [WINSPOOL.@]
1136  */
1137 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1138 {
1139     WCHAR *pNameW;
1140     PRINTER_INFO_2W *piW;
1141     PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1142     HANDLE ret;
1143
1144     TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1145     if(Level != 2) {
1146         ERR("Level = %ld, unsupported!\n", Level);
1147         SetLastError(ERROR_INVALID_LEVEL);
1148         return 0;
1149     }
1150     pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
1151     piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1152
1153     ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
1154
1155     FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1156     HeapFree(GetProcessHeap(),0,pNameW);
1157     return ret;
1158 }
1159
1160
1161 /*****************************************************************************
1162  *          ClosePrinter  [WINSPOOL.@]
1163  */
1164 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1165 {
1166     int i = (int)hPrinter;
1167
1168     TRACE("Handle %d\n", hPrinter);
1169
1170     if ((i <= 0) || (i > nb_printers)) return FALSE;
1171     HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1172     printer_array[i - 1] = NULL;
1173     return TRUE;
1174 }
1175
1176 /*****************************************************************************
1177  *          DeleteFormA  [WINSPOOL.@]
1178  */
1179 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1180 {
1181     FIXME("(%d,%s): stub\n", hPrinter, pFormName);
1182     return 1;
1183 }
1184
1185 /*****************************************************************************
1186  *          DeleteFormW  [WINSPOOL.@]
1187  */
1188 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1189 {
1190     FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
1191     return 1;
1192 }
1193
1194 /*****************************************************************************
1195  *          DeletePrinter  [WINSPOOL.@]
1196  */
1197 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1198 {
1199     LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1200     HKEY hkeyPrinters;
1201
1202     if(!lpNameW) return FALSE;
1203     if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1204        ERROR_SUCCESS) {
1205         ERR("Can't open Printers key\n");
1206         return 0;
1207     }
1208
1209     /* This should use a recursive delete see Q142491 or SHDeleteKey */
1210     if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1211         SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1212         RegCloseKey(hkeyPrinters);
1213         return 0;
1214     }
1215
1216     ClosePrinter(hPrinter);
1217     return TRUE;
1218 }
1219
1220 /*****************************************************************************
1221  *          SetPrinterA  [WINSPOOL.@]
1222  */
1223 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1224                            DWORD Command)
1225 {
1226     FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1227     return FALSE;
1228 }
1229
1230 /*****************************************************************************
1231  *          SetJobA  [WINSPOOL.@]
1232  */
1233 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1234                        LPBYTE pJob, DWORD Command)
1235 {
1236     FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1237          Command);
1238     return FALSE;
1239 }
1240
1241 /*****************************************************************************
1242  *          SetJobW  [WINSPOOL.@]
1243  */
1244 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1245                        LPBYTE pJob, DWORD Command)
1246 {
1247     FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1248          Command);
1249     return FALSE;
1250 }
1251
1252 /*****************************************************************************
1253  *          GetFormA  [WINSPOOL.@]
1254  */
1255 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1256                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1257 {
1258     FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1259          Level,pForm,cbBuf,pcbNeeded);
1260     return FALSE;
1261 }
1262
1263 /*****************************************************************************
1264  *          GetFormW  [WINSPOOL.@]
1265  */
1266 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1267                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1268 {
1269     FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1270           debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1271     return FALSE;
1272 }
1273
1274 /*****************************************************************************
1275  *          SetFormA  [WINSPOOL.@]
1276  */
1277 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1278                         LPBYTE pForm)
1279 {
1280     FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1281     return FALSE;
1282 }
1283
1284 /*****************************************************************************
1285  *          SetFormW  [WINSPOOL.@]
1286  */
1287 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1288                         LPBYTE pForm)
1289 {
1290     FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1291     return FALSE;
1292 }
1293
1294 /*****************************************************************************
1295  *          ReadPrinter  [WINSPOOL.@]
1296  */
1297 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1298                            LPDWORD pNoBytesRead)
1299 {
1300     FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1301     return FALSE;
1302 }
1303
1304 /*****************************************************************************
1305  *          ResetPrinterA  [WINSPOOL.@]
1306  */
1307 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1308 {
1309     FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1310     return FALSE;
1311 }
1312
1313 /*****************************************************************************
1314  *          ResetPrinterW  [WINSPOOL.@]
1315  */
1316 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1317 {
1318     FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1319     return FALSE;
1320 }
1321
1322 /*****************************************************************************
1323  *    WINSPOOL_GetDWORDFromReg
1324  *
1325  * Return DWORD associated with ValueName from hkey.
1326  */
1327 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1328 {
1329     DWORD sz = sizeof(DWORD), type, value = 0;
1330     LONG ret;
1331
1332     ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1333
1334     if(ret != ERROR_SUCCESS) {
1335         WARN("Got ret = %ld on name %s\n", ret, ValueName);
1336         return 0;
1337     }
1338     if(type != REG_DWORD) {
1339         ERR("Got type %ld\n", type);
1340         return 0;
1341     }
1342     return value;
1343 }
1344
1345 /*****************************************************************************
1346  *    WINSPOOL_GetStringFromReg
1347  *
1348  * Get ValueName from hkey storing result in ptr.  buflen is space left in ptr
1349  * String is stored either as unicode or ascii.
1350  * Bit of a hack here to get the ValueName if we want ascii.
1351  */
1352 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1353                                       DWORD buflen, DWORD *needed,
1354                                       BOOL unicode)
1355 {
1356     DWORD sz = buflen, type;
1357     LONG ret;
1358
1359     if(unicode)
1360         ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1361     else {
1362         LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1363         ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1364         HeapFree(GetProcessHeap(),0,ValueNameA);
1365     }
1366     if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1367         WARN("Got ret = %ld\n", ret);
1368         *needed = 0;
1369         return FALSE;
1370     }
1371     *needed = sz;
1372     return TRUE;
1373 }
1374
1375 /*****************************************************************************
1376  *    WINSPOOL_GetDefaultDevMode
1377  *
1378  * Get a default DevMode values for wineps.
1379  * FIXME - use ppd.
1380  */
1381
1382 static void WINSPOOL_GetDefaultDevMode(
1383         LPBYTE ptr,
1384         DWORD buflen, DWORD *needed,
1385         BOOL unicode)
1386 {
1387     DEVMODEA    dm;
1388
1389         /* fill default DEVMODE - should be read from ppd... */
1390         ZeroMemory( &dm, sizeof(dm) );
1391         strcpy(dm.dmDeviceName,"wineps");
1392         dm.dmSpecVersion = DM_SPECVERSION;
1393         dm.dmDriverVersion = 1;
1394         dm.dmSize = sizeof(DEVMODEA);
1395         dm.dmDriverExtra = 0;
1396         dm.dmFields =
1397                 DM_ORIENTATION | DM_PAPERSIZE |
1398                 DM_PAPERLENGTH | DM_PAPERWIDTH |
1399                 DM_SCALE |
1400                 DM_COPIES |
1401                 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1402                 DM_YRESOLUTION | DM_TTOPTION;
1403
1404         dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1405         dm.u1.s1.dmPaperSize = DMPAPER_A4;
1406         dm.u1.s1.dmPaperLength = 2970;
1407         dm.u1.s1.dmPaperWidth = 2100;
1408
1409         dm.dmScale = 100;
1410         dm.dmCopies = 1;
1411         dm.dmDefaultSource = DMBIN_AUTO;
1412         dm.dmPrintQuality = DMRES_MEDIUM;
1413         /* dm.dmColor */
1414         /* dm.dmDuplex */
1415         dm.dmYResolution = 300; /* 300dpi */
1416         dm.dmTTOption = DMTT_BITMAP;
1417         /* dm.dmCollate */
1418         /* dm.dmFormName */
1419         /* dm.dmLogPixels */
1420         /* dm.dmBitsPerPel */
1421         /* dm.dmPelsWidth */
1422         /* dm.dmPelsHeight */
1423         /* dm.dmDisplayFlags */
1424         /* dm.dmDisplayFrequency */
1425         /* dm.dmICMMethod */
1426         /* dm.dmICMIntent */
1427         /* dm.dmMediaType */
1428         /* dm.dmDitherType */
1429         /* dm.dmReserved1 */
1430         /* dm.dmReserved2 */
1431         /* dm.dmPanningWidth */
1432         /* dm.dmPanningHeight */
1433
1434     if(unicode) {
1435         if(buflen >= sizeof(DEVMODEW)) {
1436             DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
1437             memcpy(ptr, pdmW, sizeof(DEVMODEW));
1438             HeapFree(GetProcessHeap(),0,pdmW);
1439         }
1440         *needed = sizeof(DEVMODEW);
1441     }
1442     else
1443     {
1444         if(buflen >= sizeof(DEVMODEA)) {
1445             memcpy(ptr, &dm, sizeof(DEVMODEA));
1446         }
1447         *needed = sizeof(DEVMODEA);
1448     }
1449 }
1450
1451 /*****************************************************************************
1452  *    WINSPOOL_GetDevModeFromReg
1453  *
1454  * Get ValueName from hkey storing result in ptr.  buflen is space left in ptr
1455  * DevMode is stored either as unicode or ascii.
1456  */
1457 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1458                                        LPBYTE ptr,
1459                                        DWORD buflen, DWORD *needed,
1460                                        BOOL unicode)
1461 {
1462     DWORD sz = buflen, type;
1463     LONG ret;
1464
1465     if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1466     ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1467     if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1468     if (sz < sizeof(DEVMODEA))
1469     {
1470         ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1471         return FALSE;
1472     }
1473     /* ensures that dmSize is not erratically bogus if registry is invalid */
1474     if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1475         ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1476     if(unicode) {
1477         sz += (CCHDEVICENAME + CCHFORMNAME);
1478         if(buflen >= sz) {
1479             DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1480             memcpy(ptr, dmW, sz);
1481             HeapFree(GetProcessHeap(),0,dmW);
1482         }
1483     }
1484     *needed = sz;
1485     return TRUE;
1486 }
1487
1488 /*********************************************************************
1489  *    WINSPOOL_GetPrinter_2
1490  *
1491  * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1492  * The strings are either stored as unicode or ascii.
1493  */
1494 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1495                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1496                                   BOOL unicode)
1497 {
1498     DWORD size, left = cbBuf;
1499     BOOL space = (cbBuf > 0);
1500     LPBYTE ptr = buf;
1501
1502     *pcbNeeded = 0;
1503
1504     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1505                                  unicode)) {
1506         if(space && size <= left) {
1507             pi2->pPrinterName = (LPWSTR)ptr;
1508             ptr += size;
1509             left -= size;
1510         } else
1511             space = FALSE;
1512         *pcbNeeded += size;
1513     }
1514     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1515                                  unicode)) {
1516         if(space && size <= left) {
1517             pi2->pShareName = (LPWSTR)ptr;
1518             ptr += size;
1519             left -= size;
1520         } else
1521             space = FALSE;
1522         *pcbNeeded += size;
1523     }
1524     if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1525                                  unicode)) {
1526         if(space && size <= left) {
1527             pi2->pPortName = (LPWSTR)ptr;
1528             ptr += size;
1529             left -= size;
1530         } else
1531             space = FALSE;
1532         *pcbNeeded += size;
1533     }
1534     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1535                                  &size, unicode)) {
1536         if(space && size <= left) {
1537             pi2->pDriverName = (LPWSTR)ptr;
1538             ptr += size;
1539             left -= size;
1540         } else
1541             space = FALSE;
1542         *pcbNeeded += size;
1543     }
1544     if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1545                                  unicode)) {
1546         if(space && size <= left) {
1547             pi2->pComment = (LPWSTR)ptr;
1548             ptr += size;
1549             left -= size;
1550         } else
1551             space = FALSE;
1552         *pcbNeeded += size;
1553     }
1554     if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1555                                  unicode)) {
1556         if(space && size <= left) {
1557             pi2->pLocation = (LPWSTR)ptr;
1558             ptr += size;
1559             left -= size;
1560         } else
1561             space = FALSE;
1562         *pcbNeeded += size;
1563     }
1564     if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1565                                   &size, unicode)) {
1566         if(space && size <= left) {
1567             pi2->pDevMode = (LPDEVMODEW)ptr;
1568             ptr += size;
1569             left -= size;
1570         } else
1571             space = FALSE;
1572         *pcbNeeded += size;
1573     }
1574     else
1575     {
1576         MESSAGE( "no DevMode in registry. please setup your printer again.\n"
1577                  "use the default hard-coded DevMode(wineps/A4/300dpi).\n" );
1578         WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1579         if(space && size <= left) {
1580             pi2->pDevMode = (LPDEVMODEW)ptr;
1581             ptr += size;
1582             left -= size;
1583         } else
1584             space = FALSE;
1585         *pcbNeeded += size;
1586     }
1587     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1588                                  &size, unicode)) {
1589         if(space && size <= left) {
1590             pi2->pSepFile = (LPWSTR)ptr;
1591             ptr += size;
1592             left -= size;
1593         } else
1594             space = FALSE;
1595         *pcbNeeded += size;
1596     }
1597     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1598                                  &size, unicode)) {
1599         if(space && size <= left) {
1600             pi2->pPrintProcessor = (LPWSTR)ptr;
1601             ptr += size;
1602             left -= size;
1603         } else
1604             space = FALSE;
1605         *pcbNeeded += size;
1606     }
1607     if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1608                                  &size, unicode)) {
1609         if(space && size <= left) {
1610             pi2->pDatatype = (LPWSTR)ptr;
1611             ptr += size;
1612             left -= size;
1613         } else
1614             space = FALSE;
1615         *pcbNeeded += size;
1616     }
1617     if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1618                                  &size, unicode)) {
1619         if(space && size <= left) {
1620             pi2->pParameters = (LPWSTR)ptr;
1621             ptr += size;
1622             left -= size;
1623         } else
1624             space = FALSE;
1625         *pcbNeeded += size;
1626     }
1627     if(pi2) {
1628         pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1629         pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1630         pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1631                                                         "Default Priority");
1632         pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1633         pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1634     }
1635
1636     if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1637         memset(pi2, 0, sizeof(*pi2));
1638
1639     return space;
1640 }
1641
1642 /*********************************************************************
1643  *    WINSPOOL_GetPrinter_4
1644  *
1645  * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1646  */
1647 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1648                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1649                                   BOOL unicode)
1650 {
1651     DWORD size, left = cbBuf;
1652     BOOL space = (cbBuf > 0);
1653     LPBYTE ptr = buf;
1654
1655     *pcbNeeded = 0;
1656
1657     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1658                                  unicode)) {
1659         if(space && size <= left) {
1660             pi4->pPrinterName = (LPWSTR)ptr;
1661             ptr += size;
1662             left -= size;
1663         } else
1664             space = FALSE;
1665         *pcbNeeded += size;
1666     }
1667     if(pi4) {
1668         pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1669     }
1670
1671     if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1672         memset(pi4, 0, sizeof(*pi4));
1673
1674     return space;
1675 }
1676
1677 /*********************************************************************
1678  *    WINSPOOL_GetPrinter_5
1679  *
1680  * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1681  */
1682 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1683                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1684                                   BOOL unicode)
1685 {
1686     DWORD size, left = cbBuf;
1687     BOOL space = (cbBuf > 0);
1688     LPBYTE ptr = buf;
1689
1690     *pcbNeeded = 0;
1691
1692     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1693                                  unicode)) {
1694         if(space && size <= left) {
1695             pi5->pPrinterName = (LPWSTR)ptr;
1696             ptr += size;
1697             left -= size;
1698         } else
1699             space = FALSE;
1700         *pcbNeeded += size;
1701     }
1702     if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1703                                  unicode)) {
1704         if(space && size <= left) {
1705             pi5->pPortName = (LPWSTR)ptr;
1706             ptr += size;
1707             left -= size;
1708         } else
1709             space = FALSE;
1710         *pcbNeeded += size;
1711     }
1712     if(pi5) {
1713         pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1714         pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1715                                                                 "dnsTimeout");
1716         pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1717                                                                  "txTimeout");
1718     }
1719
1720     if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1721         memset(pi5, 0, sizeof(*pi5));
1722
1723     return space;
1724 }
1725
1726 /*****************************************************************************
1727  *          WINSPOOL_GetPrinter
1728  *
1729  *    Implementation of GetPrinterA|W.  Relies on PRINTER_INFO_*W being
1730  *    essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1731  *    just a collection of pointers to strings.
1732  */
1733 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1734                                 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1735 {
1736     LPCWSTR name;
1737     DWORD size, needed = 0;
1738     LPBYTE ptr = NULL;
1739     HKEY hkeyPrinter, hkeyPrinters;
1740     BOOL ret;
1741
1742     TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1743
1744     if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1745
1746     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1747        ERROR_SUCCESS) {
1748         ERR("Can't create Printers key\n");
1749         return FALSE;
1750     }
1751     if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1752     {
1753         ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1754         RegCloseKey(hkeyPrinters);
1755         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1756         return FALSE;
1757     }
1758
1759     switch(Level) {
1760     case 2:
1761       {
1762         PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1763
1764         size = sizeof(PRINTER_INFO_2W);
1765         if(size <= cbBuf) {
1766             ptr = pPrinter + size;
1767             cbBuf -= size;
1768             memset(pPrinter, 0, size);
1769         } else {
1770             pi2 = NULL;
1771             cbBuf = 0;
1772         }
1773         ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1774                                     unicode);
1775         needed += size;
1776         break;
1777       }
1778
1779     case 4:
1780       {
1781         PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1782
1783         size = sizeof(PRINTER_INFO_4W);
1784         if(size <= cbBuf) {
1785             ptr = pPrinter + size;
1786             cbBuf -= size;
1787             memset(pPrinter, 0, size);
1788         } else {
1789             pi4 = NULL;
1790             cbBuf = 0;
1791         }
1792         ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1793                                     unicode);
1794         needed += size;
1795         break;
1796       }
1797
1798
1799     case 5:
1800       {
1801         PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1802
1803         size = sizeof(PRINTER_INFO_5W);
1804         if(size <= cbBuf) {
1805             ptr = pPrinter + size;
1806             cbBuf -= size;
1807             memset(pPrinter, 0, size);
1808         } else {
1809             pi5 = NULL;
1810             cbBuf = 0;
1811         }
1812
1813         ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1814                                     unicode);
1815         needed += size;
1816         break;
1817       }
1818
1819     default:
1820         FIXME("Unimplemented level %ld\n", Level);
1821         SetLastError(ERROR_INVALID_LEVEL);
1822         RegCloseKey(hkeyPrinters);
1823         RegCloseKey(hkeyPrinter);
1824         return FALSE;
1825     }
1826
1827     RegCloseKey(hkeyPrinter);
1828     RegCloseKey(hkeyPrinters);
1829
1830     TRACE("returing %d needed = %ld\n", ret, needed);
1831     if(pcbNeeded) *pcbNeeded = needed;
1832     if(!ret)
1833         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1834     return ret;
1835 }
1836
1837 /*****************************************************************************
1838  *          GetPrinterW  [WINSPOOL.@]
1839  */
1840 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1841                         DWORD cbBuf, LPDWORD pcbNeeded)
1842 {
1843     return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1844                                TRUE);
1845 }
1846
1847 /*****************************************************************************
1848  *          GetPrinterA  [WINSPOOL.@]
1849  */
1850 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1851                     DWORD cbBuf, LPDWORD pcbNeeded)
1852 {
1853     return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1854                                FALSE);
1855 }
1856
1857 /*****************************************************************************
1858  *          WINSPOOL_EnumPrinters
1859  *
1860  *    Implementation of EnumPrintersA|W
1861  */
1862 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1863                                   DWORD dwLevel, LPBYTE lpbPrinters,
1864                                   DWORD cbBuf, LPDWORD lpdwNeeded,
1865                                   LPDWORD lpdwReturned, BOOL unicode)
1866
1867 {
1868     HKEY hkeyPrinters, hkeyPrinter;
1869     WCHAR PrinterName[255];
1870     DWORD needed = 0, number = 0;
1871     DWORD used, i, left;
1872     PBYTE pi, buf;
1873
1874     if(lpbPrinters)
1875         memset(lpbPrinters, 0, cbBuf);
1876     if(lpdwReturned)
1877         *lpdwReturned = 0;
1878     if(lpdwNeeded)
1879         *lpdwNeeded = 0;
1880
1881     /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1882     if(dwType == PRINTER_ENUM_DEFAULT)
1883         return TRUE;
1884
1885     if (dwType & PRINTER_ENUM_CONNECTIONS) {
1886         FIXME("We dont handle PRINTER_ENUM_CONNECTIONS\n");
1887         dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we dont handle that */
1888         dwType |= PRINTER_ENUM_LOCAL;
1889     }
1890
1891     if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1892         FIXME("dwType = %08lx\n", dwType);
1893         SetLastError(ERROR_INVALID_FLAGS);
1894         return FALSE;
1895     }
1896
1897     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1898        ERROR_SUCCESS) {
1899         ERR("Can't create Printers key\n");
1900         return FALSE;
1901     }
1902
1903     if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1904                         NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1905         RegCloseKey(hkeyPrinters);
1906         ERR("Can't query Printers key\n");
1907         return FALSE;
1908     }
1909     TRACE("Found %ld printers\n", number);
1910
1911     switch(dwLevel) {
1912     case 1:
1913         RegCloseKey(hkeyPrinters);
1914         if (lpdwReturned)
1915             *lpdwReturned = number;
1916         return TRUE;
1917
1918     case 2:
1919         used = number * sizeof(PRINTER_INFO_2W);
1920         break;
1921     case 4:
1922         used = number * sizeof(PRINTER_INFO_4W);
1923         break;
1924     case 5:
1925         used = number * sizeof(PRINTER_INFO_5W);
1926         break;
1927
1928     default:
1929         SetLastError(ERROR_INVALID_LEVEL);
1930         RegCloseKey(hkeyPrinters);
1931         return FALSE;
1932     }
1933     pi = (used <= cbBuf) ? lpbPrinters : NULL;
1934
1935     for(i = 0; i < number; i++) {
1936         if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1937            ERROR_SUCCESS) {
1938             ERR("Can't enum key number %ld\n", i);
1939             RegCloseKey(hkeyPrinters);
1940             return FALSE;
1941         }
1942         TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1943         if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1944            ERROR_SUCCESS) {
1945             ERR("Can't open key %s\n", debugstr_w(PrinterName));
1946             RegCloseKey(hkeyPrinters);
1947             return FALSE;
1948         }
1949
1950         if(cbBuf > used) {
1951             buf = lpbPrinters + used;
1952             left = cbBuf - used;
1953         } else {
1954             buf = NULL;
1955             left = 0;
1956         }
1957
1958         switch(dwLevel) {
1959         case 2:
1960             WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1961                                   left, &needed, unicode);
1962             used += needed;
1963             if(pi) pi += sizeof(PRINTER_INFO_2W);
1964             break;
1965         case 4:
1966             WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1967                                   left, &needed, unicode);
1968             used += needed;
1969             if(pi) pi += sizeof(PRINTER_INFO_4W);
1970             break;
1971         case 5:
1972             WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1973                                   left, &needed, unicode);
1974             used += needed;
1975             if(pi) pi += sizeof(PRINTER_INFO_5W);
1976             break;
1977         default:
1978             ERR("Shouldn't be here!\n");
1979             RegCloseKey(hkeyPrinter);
1980             RegCloseKey(hkeyPrinters);
1981             return FALSE;
1982         }
1983         RegCloseKey(hkeyPrinter);
1984     }
1985     RegCloseKey(hkeyPrinters);
1986
1987     if(lpdwNeeded)
1988         *lpdwNeeded = used;
1989
1990     if(used > cbBuf) {
1991         if(lpbPrinters)
1992             memset(lpbPrinters, 0, cbBuf);
1993         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1994         return FALSE;
1995     }
1996     if(lpdwReturned)
1997         *lpdwReturned = number;
1998     SetLastError(ERROR_SUCCESS);
1999     return TRUE;
2000 }
2001
2002
2003 /******************************************************************
2004  *              EnumPrintersW        [WINSPOOL.@]
2005  *
2006  *    Enumerates the available printers, print servers and print
2007  *    providers, depending on the specified flags, name and level.
2008  *
2009  * RETURNS:
2010  *
2011  *    If level is set to 1:
2012  *      Not implemented yet!
2013  *      Returns TRUE with an empty list.
2014  *
2015  *    If level is set to 2:
2016  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2017  *      Returns an array of PRINTER_INFO_2 data structures in the
2018  *      lpbPrinters buffer. Note that according to MSDN also an
2019  *      OpenPrinter should be performed on every remote printer.
2020  *
2021  *    If level is set to 4 (officially WinNT only):
2022  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2023  *      Fast: Only the registry is queried to retrieve printer names,
2024  *      no connection to the driver is made.
2025  *      Returns an array of PRINTER_INFO_4 data structures in the
2026  *      lpbPrinters buffer.
2027  *
2028  *    If level is set to 5 (officially WinNT4/Win9x only):
2029  *      Fast: Only the registry is queried to retrieve printer names,
2030  *      no connection to the driver is made.
2031  *      Returns an array of PRINTER_INFO_5 data structures in the
2032  *      lpbPrinters buffer.
2033  *
2034  *    If level set to 3 or 6+:
2035  *          returns zero (failure!)
2036  *
2037  *    Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2038  *    for information.
2039  *
2040  * BUGS:
2041  *    - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2042  *    - Only levels 2, 4 and 5 are implemented at the moment.
2043  *    - 16-bit printer drivers are not enumerated.
2044  *    - Returned amount of bytes used/needed does not match the real Windoze
2045  *      implementation (as in this implementation, all strings are part
2046  *      of the buffer, whereas Win32 keeps them somewhere else)
2047  *    - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2048  *
2049  * NOTE:
2050  *    - In a regular Wine installation, no registry settings for printers
2051  *      exist, which makes this function return an empty list.
2052  */
2053 BOOL  WINAPI EnumPrintersW(
2054                 DWORD dwType,        /* [in] Types of print objects to enumerate */
2055                 LPWSTR lpszName,     /* [in] name of objects to enumerate */
2056                 DWORD dwLevel,       /* [in] type of printer info structure */
2057                 LPBYTE lpbPrinters,  /* [out] buffer which receives info */
2058                 DWORD cbBuf,         /* [in] max size of buffer in bytes */
2059                 LPDWORD lpdwNeeded,  /* [out] pointer to var: # bytes used/needed */
2060                 LPDWORD lpdwReturned /* [out] number of entries returned */
2061                 )
2062 {
2063     return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2064                                  lpdwNeeded, lpdwReturned, TRUE);
2065 }
2066
2067 /******************************************************************
2068  *              EnumPrintersA        [WINSPOOL.@]
2069  *
2070  */
2071 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2072                           DWORD dwLevel, LPBYTE lpbPrinters,
2073                           DWORD cbBuf, LPDWORD lpdwNeeded,
2074                           LPDWORD lpdwReturned)
2075 {
2076     BOOL ret;
2077     LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
2078
2079     ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
2080                                 lpdwNeeded, lpdwReturned, FALSE);
2081     HeapFree(GetProcessHeap(),0,lpszNameW);
2082     return ret;
2083 }
2084
2085 /*****************************************************************************
2086  *          WINSPOOL_GetDriverInfoFromReg [internal]
2087  *
2088  *    Enters the information from the registry into the DRIVER_INFO struct
2089  *
2090  * RETURNS
2091  *    zero if the printer driver does not exist in the registry
2092  *    (only if Level > 1) otherwise nonzero
2093  */
2094 static BOOL WINSPOOL_GetDriverInfoFromReg(
2095                             HKEY    hkeyDrivers,
2096                             LPWSTR  DriverName,
2097                             LPWSTR  pEnvironment,
2098                             DWORD   Level,
2099                             LPBYTE  ptr,            /* DRIVER_INFO */
2100                             LPBYTE  pDriverStrings, /* strings buffer */
2101                             DWORD   cbBuf,          /* size of string buffer */
2102                             LPDWORD pcbNeeded,      /* space needed for str. */
2103                             BOOL    unicode)        /* type of strings */
2104 {   DWORD  dw, size, tmp, type;
2105     HKEY   hkeyDriver;
2106     LPBYTE strPtr = pDriverStrings;
2107
2108     TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2109           debugstr_w(DriverName), debugstr_w(pEnvironment),
2110           Level, ptr, pDriverStrings, cbBuf, unicode);
2111
2112     if(unicode) {
2113         *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2114             if (*pcbNeeded <= cbBuf)
2115                strcpyW((LPWSTR)strPtr, DriverName);
2116     } else {
2117         *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2118                                           NULL, NULL);
2119         if(*pcbNeeded <= cbBuf)
2120             WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2121                                 NULL, NULL);
2122     }
2123     if(Level == 1) {
2124        if(ptr)
2125           ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2126        return TRUE;
2127     } else {
2128        if(ptr)
2129           ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2130        strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2131     }
2132
2133     if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2134         ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2135         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2136         return FALSE;
2137     }
2138
2139     size = sizeof(dw);
2140     if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2141         ERROR_SUCCESS)
2142          WARN("Can't get Version\n");
2143     else if(ptr)
2144          ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2145
2146     if(!pEnvironment)
2147         pEnvironment = DefaultEnvironmentW;
2148     if(unicode)
2149         size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2150     else
2151         size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2152                                    NULL, NULL);
2153     *pcbNeeded += size;
2154     if(*pcbNeeded <= cbBuf) {
2155         if(unicode)
2156             strcpyW((LPWSTR)strPtr, pEnvironment);
2157         else
2158             WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2159                                 NULL, NULL);
2160         if(ptr)
2161             ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2162         strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2163     }
2164
2165     if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2166                                  unicode)) {
2167         *pcbNeeded += size;
2168         if(*pcbNeeded <= cbBuf)
2169             WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2170                                       unicode);
2171         if(ptr)
2172             ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2173         strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2174     }
2175
2176     if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2177                                  unicode)) {
2178         *pcbNeeded += size;
2179         if(*pcbNeeded <= cbBuf)
2180             WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2181                                       &tmp, unicode);
2182         if(ptr)
2183             ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2184         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2185     }
2186
2187     if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2188                                  0, &size, unicode)) {
2189         *pcbNeeded += size;
2190         if(*pcbNeeded <= cbBuf)
2191             WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2192                                       size, &tmp, unicode);
2193         if(ptr)
2194             ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2195         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2196     }
2197
2198     if(Level == 2 ) {
2199         RegCloseKey(hkeyDriver);
2200         TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2201         return TRUE;
2202     }
2203
2204     if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2205                                  unicode)) {
2206         *pcbNeeded += size;
2207         if(*pcbNeeded <= cbBuf)
2208             WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2209                                       size, &tmp, unicode);
2210         if(ptr)
2211             ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2212         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2213     }
2214
2215     if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2216                              &size, unicode)) {
2217         *pcbNeeded += size;
2218         if(*pcbNeeded <= cbBuf)
2219             WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2220                                       size, &tmp, unicode);
2221         if(ptr)
2222             ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2223         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2224     }
2225
2226     if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2227                                  unicode)) {
2228         *pcbNeeded += size;
2229         if(*pcbNeeded <= cbBuf)
2230             WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2231                                       size, &tmp, unicode);
2232         if(ptr)
2233             ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2234         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2235     }
2236
2237     if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2238                                  unicode)) {
2239         *pcbNeeded += size;
2240         if(*pcbNeeded <= cbBuf)
2241             WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2242                                       size, &tmp, unicode);
2243         if(ptr)
2244             ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2245         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2246     }
2247
2248     TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2249     RegCloseKey(hkeyDriver);
2250     return TRUE;
2251 }
2252
2253 /*****************************************************************************
2254  *          WINSPOOL_GetPrinterDriver
2255  */
2256 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2257                                       DWORD Level, LPBYTE pDriverInfo,
2258                                       DWORD cbBuf, LPDWORD pcbNeeded,
2259                                       BOOL unicode)
2260 {
2261     LPCWSTR name;
2262     WCHAR DriverName[100];
2263     DWORD ret, type, size, needed = 0;
2264     LPBYTE ptr = NULL;
2265     HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2266
2267     TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2268           Level,pDriverInfo,cbBuf, pcbNeeded);
2269
2270     ZeroMemory(pDriverInfo, cbBuf);
2271
2272     if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2273
2274     if(Level < 1 || Level > 3) {
2275         SetLastError(ERROR_INVALID_LEVEL);
2276         return FALSE;
2277     }
2278     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2279        ERROR_SUCCESS) {
2280         ERR("Can't create Printers key\n");
2281         return FALSE;
2282     }
2283     if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2284        != ERROR_SUCCESS) {
2285         ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2286         RegCloseKey(hkeyPrinters);
2287         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2288         return FALSE;
2289     }
2290     size = sizeof(DriverName);
2291     DriverName[0] = 0;
2292     ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2293                            (LPBYTE)DriverName, &size);
2294     RegCloseKey(hkeyPrinter);
2295     RegCloseKey(hkeyPrinters);
2296     if(ret != ERROR_SUCCESS) {
2297         ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2298         return FALSE;
2299     }
2300
2301     hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2302     if(!hkeyDrivers) {
2303         ERR("Can't create Drivers key\n");
2304         return FALSE;
2305     }
2306
2307     switch(Level) {
2308     case 1:
2309         size = sizeof(DRIVER_INFO_1W);
2310         break;
2311     case 2:
2312         size = sizeof(DRIVER_INFO_2W);
2313         break;
2314     case 3:
2315         size = sizeof(DRIVER_INFO_3W);
2316         break;
2317     default:
2318         ERR("Invalid level\n");
2319         return FALSE;
2320     }
2321
2322     if(size <= cbBuf)
2323         ptr = pDriverInfo + size;
2324
2325     if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2326                          pEnvironment, Level, pDriverInfo,
2327                          (cbBuf < size) ? NULL : ptr,
2328                          (cbBuf < size) ? 0 : cbBuf - size,
2329                          &needed, unicode)) {
2330             RegCloseKey(hkeyDrivers);
2331             return FALSE;
2332     }
2333
2334     RegCloseKey(hkeyDrivers);
2335
2336     if(pcbNeeded) *pcbNeeded = size + needed;
2337     TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2338     if(cbBuf >= needed) return TRUE;
2339     SetLastError(ERROR_INSUFFICIENT_BUFFER);
2340     return FALSE;
2341 }
2342
2343 /*****************************************************************************
2344  *          GetPrinterDriverA  [WINSPOOL.@]
2345  */
2346 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2347                               DWORD Level, LPBYTE pDriverInfo,
2348                               DWORD cbBuf, LPDWORD pcbNeeded)
2349 {
2350     BOOL ret;
2351     LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
2352     ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
2353                                     cbBuf, pcbNeeded, FALSE);
2354     HeapFree(GetProcessHeap(),0,pEnvW);
2355     return ret;
2356 }
2357 /*****************************************************************************
2358  *          GetPrinterDriverW  [WINSPOOL.@]
2359  */
2360 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2361                                   DWORD Level, LPBYTE pDriverInfo,
2362                                   DWORD cbBuf, LPDWORD pcbNeeded)
2363 {
2364     return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2365                                      pDriverInfo, cbBuf, pcbNeeded, TRUE);
2366 }
2367
2368 /*****************************************************************************
2369  *       GetPrinterDriverDirectoryA  [WINSPOOL.@]
2370  */
2371 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2372                                        DWORD Level, LPBYTE pDriverDirectory,
2373                                        DWORD cbBuf, LPDWORD pcbNeeded)
2374 {
2375     DWORD needed;
2376
2377     TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
2378           pDriverDirectory, cbBuf, pcbNeeded);
2379     if(pName != NULL) {
2380         FIXME("pName = `%s' - unsupported\n", pName);
2381         SetLastError(ERROR_INVALID_PARAMETER);
2382         return FALSE;
2383     }
2384     if(pEnvironment != NULL) {
2385         FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
2386         SetLastError(ERROR_INVALID_ENVIRONMENT);
2387         return FALSE;
2388     }
2389     if(Level != 1)  /* win95 ignores this so we just carry on */
2390         WARN("Level = %ld - assuming 1\n", Level);
2391
2392     /* FIXME should read from registry */
2393     needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
2394     needed++;
2395     if(pcbNeeded)
2396         *pcbNeeded = needed;
2397     if(needed > cbBuf) {
2398         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2399         return FALSE;
2400     }
2401     return TRUE;
2402 }
2403
2404
2405 /*****************************************************************************
2406  *       GetPrinterDriverDirectoryW  [WINSPOOL.@]
2407  */
2408 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2409                                        DWORD Level, LPBYTE pDriverDirectory,
2410                                        DWORD cbBuf, LPDWORD pcbNeeded)
2411 {
2412     LPSTR pNameA = NULL, pEnvironmentA = NULL;
2413     BOOL ret;
2414
2415     if(pName)
2416         pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
2417     if(pEnvironment)
2418         pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
2419     ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
2420                                       pDriverDirectory, cbBuf, pcbNeeded );
2421     if(pNameA)
2422         HeapFree( GetProcessHeap(), 0, pNameA );
2423     if(pEnvironmentA)
2424         HeapFree( GetProcessHeap(), 0, pEnvironmentA );
2425
2426     return ret;
2427 }
2428
2429 /*****************************************************************************
2430  *          AddPrinterDriverA  [WINSPOOL.@]
2431  */
2432 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2433 {
2434     DRIVER_INFO_3A di3;
2435     HKEY hkeyDrivers, hkeyName;
2436
2437     TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2438
2439     if(level != 2 && level != 3) {
2440         SetLastError(ERROR_INVALID_LEVEL);
2441         return FALSE;
2442     }
2443     if(pName != NULL) {
2444         FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2445         SetLastError(ERROR_INVALID_PARAMETER);
2446         return FALSE;
2447     }
2448     if(!pDriverInfo) {
2449         WARN("pDriverInfo == NULL\n");
2450         SetLastError(ERROR_INVALID_PARAMETER);
2451         return FALSE;
2452     }
2453
2454     if(level == 3)
2455         di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2456     else {
2457         memset(&di3, 0, sizeof(di3));
2458         *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2459     }
2460
2461     if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2462        !di3.pDataFile) {
2463         SetLastError(ERROR_INVALID_PARAMETER);
2464         return FALSE;
2465     }
2466     if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2467     if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2468     if(!di3.pHelpFile) di3.pHelpFile = "";
2469     if(!di3.pMonitorName) di3.pMonitorName = "";
2470
2471     hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2472
2473     if(!hkeyDrivers) {
2474         ERR("Can't create Drivers key\n");
2475         return FALSE;
2476     }
2477
2478     if(level == 2) { /* apparently can't overwrite with level2 */
2479         if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2480             RegCloseKey(hkeyName);
2481             RegCloseKey(hkeyDrivers);
2482             WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2483             SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2484             return FALSE;
2485         }
2486     }
2487     if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2488         RegCloseKey(hkeyDrivers);
2489         ERR("Can't create Name key\n");
2490         return FALSE;
2491     }
2492     RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2493                    0);
2494     RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2495     RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2496     RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2497                    sizeof(DWORD));
2498     RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2499     RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2500                    di3.pDependentFiles, 0);
2501     RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2502     RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2503     RegCloseKey(hkeyName);
2504     RegCloseKey(hkeyDrivers);
2505
2506     return TRUE;
2507 }
2508 /*****************************************************************************
2509  *          AddPrinterDriverW  [WINSPOOL.@]
2510  */
2511 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2512                                    LPBYTE pDriverInfo)
2513 {
2514     FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2515           level,pDriverInfo);
2516     return FALSE;
2517 }
2518
2519
2520 /*****************************************************************************
2521  *          PrinterProperties  [WINSPOOL.@]
2522  *
2523  *     Displays a dialog to set the properties of the printer.
2524  *
2525  * RETURNS
2526  *     nonzero on success or zero on failure
2527  *
2528  * BUGS
2529  *         implemented as stub only
2530  */
2531 BOOL WINAPI PrinterProperties(HWND hWnd,      /* [in] handle to parent window */
2532                               HANDLE hPrinter /* [in] handle to printer object */
2533 ){
2534     FIXME("(%d,%d): stub\n", hWnd, hPrinter);
2535     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2536     return FALSE;
2537 }
2538
2539 /*****************************************************************************
2540  *          EnumJobsA [WINSPOOL.@]
2541  *
2542  */
2543 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2544                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2545                       LPDWORD pcReturned)
2546 {
2547     FIXME("stub\n");
2548     if(pcbNeeded) *pcbNeeded = 0;
2549     if(pcReturned) *pcReturned = 0;
2550     return TRUE;
2551 }
2552
2553
2554 /*****************************************************************************
2555  *          EnumJobsW [WINSPOOL.@]
2556  *
2557  */
2558 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2559                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2560                       LPDWORD pcReturned)
2561 {
2562     FIXME("stub\n");
2563     if(pcbNeeded) *pcbNeeded = 0;
2564     if(pcReturned) *pcReturned = 0;
2565     return TRUE;
2566 }
2567
2568 /*****************************************************************************
2569  *          WINSPOOL_EnumPrinterDrivers [internal]
2570  *
2571  *    Delivers information about all printer drivers installed on the
2572  *    localhost or a given server
2573  *
2574  * RETURNS
2575  *    nonzero on success or zero on failure. If the buffer for the returned
2576  *    information is too small the function will return an error
2577  *
2578  * BUGS
2579  *    - only implemented for localhost, foreign hosts will return an error
2580  */
2581 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2582                                         DWORD Level, LPBYTE pDriverInfo,
2583                                         DWORD cbBuf, LPDWORD pcbNeeded,
2584                                         LPDWORD pcReturned, BOOL unicode)
2585
2586 {   HKEY  hkeyDrivers;
2587     DWORD i, needed, number = 0, size = 0;
2588     WCHAR DriverNameW[255];
2589     PBYTE ptr;
2590
2591     TRACE("%s,%s,%ld,%p,%ld,%d\n",
2592           debugstr_w(pName), debugstr_w(pEnvironment),
2593           Level, pDriverInfo, cbBuf, unicode);
2594
2595     /* check for local drivers */
2596     if(pName) {
2597         ERR("remote drivers unsupported! Current remote host is %s\n",
2598              debugstr_w(pName));
2599         return FALSE;
2600     }
2601
2602     /* check input parameter */
2603     if((Level < 1) || (Level > 3)) {
2604         ERR("unsupported level %ld \n", Level);
2605         return FALSE;
2606     }
2607
2608     /* initialize return values */
2609     if(pDriverInfo)
2610         memset( pDriverInfo, 0, cbBuf);
2611     *pcbNeeded  = 0;
2612     *pcReturned = 0;
2613
2614     hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2615     if(!hkeyDrivers) {
2616         ERR("Can't open Drivers key\n");
2617         return FALSE;
2618     }
2619
2620     if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2621                         NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2622         RegCloseKey(hkeyDrivers);
2623         ERR("Can't query Drivers key\n");
2624         return FALSE;
2625     }
2626     TRACE("Found %ld Drivers\n", number);
2627
2628     /* get size of single struct
2629      * unicode and ascii structure have the same size
2630      */
2631     switch (Level) {
2632         case 1:
2633             size = sizeof(DRIVER_INFO_1A);
2634             break;
2635         case 2:
2636             size = sizeof(DRIVER_INFO_2A);
2637             break;
2638         case 3:
2639             size = sizeof(DRIVER_INFO_3A);
2640             break;
2641     }
2642
2643     /* calculate required buffer size */
2644     *pcbNeeded = size * number;
2645
2646     for( i = 0,  ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2647          i < number;
2648          i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2649         if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2650                        != ERROR_SUCCESS) {
2651             ERR("Can't enum key number %ld\n", i);
2652             RegCloseKey(hkeyDrivers);
2653             return FALSE;
2654         }
2655         if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2656                          pEnvironment, Level, ptr,
2657                          (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2658                          (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2659                          &needed, unicode)) {
2660             RegCloseKey(hkeyDrivers);
2661             return FALSE;
2662         }
2663         (*pcbNeeded) += needed;
2664     }
2665
2666     RegCloseKey(hkeyDrivers);
2667
2668     if(cbBuf < *pcbNeeded){
2669         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2670         return FALSE;
2671     }
2672
2673     return TRUE;
2674 }
2675
2676 /*****************************************************************************
2677  *          EnumPrinterDriversW  [WINSPOOL.@]
2678  *
2679  *    see function EnumPrinterDrivers for RETURNS, BUGS
2680  */
2681 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2682                                 LPBYTE pDriverInfo, DWORD cbBuf,
2683                                 LPDWORD pcbNeeded, LPDWORD pcReturned)
2684 {
2685     return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2686                                        cbBuf, pcbNeeded, pcReturned, TRUE);
2687 }
2688
2689 /*****************************************************************************
2690  *          EnumPrinterDriversA  [WINSPOOL.@]
2691  *
2692  *    see function EnumPrinterDrivers for RETURNS, BUGS
2693  */
2694 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2695                                 LPBYTE pDriverInfo, DWORD cbBuf,
2696                                 LPDWORD pcbNeeded, LPDWORD pcReturned)
2697 {   BOOL ret;
2698     WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2699
2700     if(pName)
2701         pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2702     if(pEnvironment)
2703         pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2704
2705     ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2706                                       cbBuf, pcbNeeded, pcReturned, FALSE);
2707     if(pNameW)
2708         HeapFree(GetProcessHeap(), 0, pNameW);
2709     if(pEnvironmentW)
2710         HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2711
2712     return ret;
2713 }
2714
2715
2716 /******************************************************************************
2717  *              EnumPortsA   (WINSPOOL.@)
2718  */
2719 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2720                        LPDWORD bufneeded,LPDWORD bufreturned)
2721 {
2722     FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2723     return FALSE;
2724 }
2725
2726 /******************************************************************************
2727  *              GetDefaultPrinterA   (WINSPOOL.@)
2728  *
2729  * Based on PRINTDLG_GetDefaultPrinterName in dlls/commdlg/printdlg.c
2730  */
2731 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
2732 {
2733    char *ptr;
2734
2735    if (*namesize < 1)
2736    {
2737       SetLastError (ERROR_INSUFFICIENT_BUFFER);
2738       return FALSE;
2739    }
2740
2741    if (!GetProfileStringA ("windows", "device", "", name, *namesize))
2742    {
2743       SetLastError (ERROR_FILE_NOT_FOUND);
2744       return FALSE;
2745    }
2746
2747    if ((ptr = strchr (name, ',')) == NULL)
2748    {
2749       SetLastError (ERROR_FILE_NOT_FOUND);
2750       return FALSE;
2751    }
2752
2753    *ptr = '\0';
2754    *namesize = strlen (name) + 1;
2755    return TRUE;
2756 }
2757
2758
2759 /******************************************************************************
2760  *              GetDefaultPrinterW   (WINSPOOL.@)
2761  */
2762 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
2763 {
2764    char *buf;
2765    BOOL  ret;
2766
2767    if (*namesize < 1)
2768    {
2769       SetLastError (ERROR_INSUFFICIENT_BUFFER);
2770       return FALSE;
2771    }
2772
2773    buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
2774    ret = GetDefaultPrinterA (buf, namesize);
2775    if (ret)
2776    {
2777        DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
2778        if (!len)
2779        {
2780            SetLastError (ERROR_INSUFFICIENT_BUFFER);
2781            ret = FALSE;
2782        }
2783        else *namesize = len;
2784    }
2785
2786    HeapFree (GetProcessHeap (), 0, buf);
2787    return ret;
2788 }
2789
2790
2791 /******************************************************************************
2792  *              SetPrinterDataExA   (WINSPOOL.@)
2793  */
2794 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2795                                LPSTR pValueName, DWORD Type,
2796                                LPBYTE pData, DWORD cbData)
2797 {
2798     HKEY hkeyPrinter, hkeySubkey;
2799     DWORD ret;
2800
2801     TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2802           debugstr_a(pValueName), Type, pData, cbData);
2803
2804     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2805        != ERROR_SUCCESS)
2806         return ret;
2807
2808     if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2809        != ERROR_SUCCESS) {
2810         ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2811         RegCloseKey(hkeyPrinter);
2812         return ret;
2813     }
2814     ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2815     RegCloseKey(hkeySubkey);
2816     RegCloseKey(hkeyPrinter);
2817     return ret;
2818 }
2819
2820 /******************************************************************************
2821  *              SetPrinterDataExW   (WINSPOOL.@)
2822  */
2823 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2824                                LPWSTR pValueName, DWORD Type,
2825                                LPBYTE pData, DWORD cbData)
2826 {
2827     HKEY hkeyPrinter, hkeySubkey;
2828     DWORD ret;
2829
2830     TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2831           debugstr_w(pValueName), Type, pData, cbData);
2832
2833     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2834        != ERROR_SUCCESS)
2835         return ret;
2836
2837     if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2838        != ERROR_SUCCESS) {
2839         ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2840         RegCloseKey(hkeyPrinter);
2841         return ret;
2842     }
2843     ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2844     RegCloseKey(hkeySubkey);
2845     RegCloseKey(hkeyPrinter);
2846     return ret;
2847 }
2848
2849 /******************************************************************************
2850  *              SetPrinterDataA   (WINSPOOL.@)
2851  */
2852 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
2853                                LPBYTE pData, DWORD cbData)
2854 {
2855     return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
2856                              pData, cbData);
2857 }
2858
2859 /******************************************************************************
2860  *              SetPrinterDataW   (WINSPOOL.@)
2861  */
2862 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
2863                              LPBYTE pData, DWORD cbData)
2864 {
2865     return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
2866                              pData, cbData);
2867 }
2868
2869 /******************************************************************************
2870  *              GetPrinterDataExA   (WINSPOOL.@)
2871  */
2872 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2873                                LPSTR pValueName, LPDWORD pType,
2874                                LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2875 {
2876     HKEY hkeyPrinter, hkeySubkey;
2877     DWORD ret;
2878
2879     TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2880           debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
2881           pcbNeeded);
2882
2883     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2884        != ERROR_SUCCESS)
2885         return ret;
2886
2887     if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2888        != ERROR_SUCCESS) {
2889         WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
2890         RegCloseKey(hkeyPrinter);
2891         return ret;
2892     }
2893     *pcbNeeded = nSize;
2894     ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2895     RegCloseKey(hkeySubkey);
2896     RegCloseKey(hkeyPrinter);
2897     return ret;
2898 }
2899
2900 /******************************************************************************
2901  *              GetPrinterDataExW   (WINSPOOL.@)
2902  */
2903 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2904                                LPWSTR pValueName, LPDWORD pType,
2905                                LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2906 {
2907     HKEY hkeyPrinter, hkeySubkey;
2908     DWORD ret;
2909
2910     TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2911           debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
2912           pcbNeeded);
2913
2914     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2915        != ERROR_SUCCESS)
2916         return ret;
2917
2918     if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2919        != ERROR_SUCCESS) {
2920         WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
2921         RegCloseKey(hkeyPrinter);
2922         return ret;
2923     }
2924     *pcbNeeded = nSize;
2925     ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2926     RegCloseKey(hkeySubkey);
2927     RegCloseKey(hkeyPrinter);
2928     return ret;
2929 }
2930
2931 /******************************************************************************
2932  *              GetPrinterDataA   (WINSPOOL.@)
2933  */
2934 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
2935                              LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2936 {
2937     return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
2938                              pData, nSize, pcbNeeded);
2939 }
2940
2941 /******************************************************************************
2942  *              GetPrinterDataW   (WINSPOOL.@)
2943  */
2944 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
2945                              LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2946 {
2947     return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
2948                              pData, nSize, pcbNeeded);
2949 }
2950
2951 /*******************************************************************************
2952  *              EnumPrinterDataExW      [WINSPOOL.@]
2953  */
2954 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
2955                                 LPBYTE pEnumValues, DWORD cbEnumValues,
2956                                 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
2957 {
2958     HKEY                    hkPrinter, hkSubKey;
2959     DWORD                   r, ret, dwIndex, cValues, cbMaxValueNameLen,
2960                             cbValueNameLen, cbMaxValueLen, cbValueLen,
2961                             cbBufSize, dwType;
2962     LPWSTR                  lpValueName;
2963     HANDLE                  hHeap;
2964     PBYTE                   lpValue;
2965     PPRINTER_ENUM_VALUESW   ppev;
2966
2967     TRACE ("%08x %s\n", hPrinter, debugstr_w (pKeyName));
2968
2969     if (pKeyName == NULL || *pKeyName == 0)
2970         return ERROR_INVALID_PARAMETER;
2971
2972     ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
2973     if (ret != ERROR_SUCCESS)
2974     {
2975         TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%08x) returned %li\n",
2976                 hPrinter, ret);
2977         return ret;
2978     }
2979
2980     ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
2981     if (ret != ERROR_SUCCESS)
2982     {
2983         r = RegCloseKey (hkPrinter);
2984         if (r != ERROR_SUCCESS)
2985             WARN ("RegCloseKey returned %li\n", r);
2986         TRACE ("RegOpenKeyExW (%08x, %s) returned %li\n", hPrinter,
2987                 debugstr_w (pKeyName), ret);
2988         return ret;
2989     }
2990
2991     ret = RegCloseKey (hkPrinter);
2992     if (ret != ERROR_SUCCESS)
2993     {
2994         ERR ("RegCloseKey returned %li\n", ret);
2995         r = RegCloseKey (hkSubKey);
2996         if (r != ERROR_SUCCESS)
2997             WARN ("RegCloseKey returned %li\n", r);
2998         return ret;
2999     }
3000
3001     ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3002             &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3003     if (ret != ERROR_SUCCESS)
3004     {
3005         r = RegCloseKey (hkSubKey);
3006         if (r != ERROR_SUCCESS)
3007             WARN ("RegCloseKey returned %li\n", r);
3008         TRACE ("RegQueryInfoKeyW (%08x) returned %li\n", hkSubKey, ret);
3009         return ret;
3010     }
3011
3012     TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3013             "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3014
3015     if (cValues == 0)                   /* empty key */
3016     {
3017         r = RegCloseKey (hkSubKey);
3018         if (r != ERROR_SUCCESS)
3019             WARN ("RegCloseKey returned %li\n", r);
3020         *pcbEnumValues = *pnEnumValues = 0;
3021         return ERROR_SUCCESS;
3022     }
3023
3024     ++cbMaxValueNameLen;                        /* allow for trailing '\0' */
3025
3026     hHeap = GetProcessHeap ();
3027     if (hHeap == (HANDLE) NULL)
3028     {
3029         ERR ("GetProcessHeap failed\n");
3030         r = RegCloseKey (hkSubKey);
3031         if (r != ERROR_SUCCESS)
3032             WARN ("RegCloseKey returned %li\n", r);
3033         return ERROR_OUTOFMEMORY;
3034     }
3035
3036     lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3037     if (lpValueName == NULL)
3038     {
3039         ERR ("Failed to allocate %li bytes from process heap\n",
3040                 cbMaxValueNameLen * sizeof (WCHAR));
3041         r = RegCloseKey (hkSubKey);
3042         if (r != ERROR_SUCCESS)
3043             WARN ("RegCloseKey returned %li\n", r);
3044         return ERROR_OUTOFMEMORY;
3045     }
3046
3047     lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3048     if (lpValue == NULL)
3049     {
3050         ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3051         if (HeapFree (hHeap, 0, lpValueName) == 0)
3052             WARN ("HeapFree failed with code %li\n", GetLastError ());
3053         r = RegCloseKey (hkSubKey);
3054         if (r != ERROR_SUCCESS)
3055             WARN ("RegCloseKey returned %li\n", r);
3056         return ERROR_OUTOFMEMORY;
3057     }
3058
3059     TRACE ("pass 1: calculating buffer required for all names and values\n");
3060
3061     cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3062
3063     TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3064
3065     for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3066     {
3067         cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3068         ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3069                 NULL, NULL, lpValue, &cbValueLen);
3070         if (ret != ERROR_SUCCESS)
3071         {
3072             if (HeapFree (hHeap, 0, lpValue) == 0)
3073                 WARN ("HeapFree failed with code %li\n", GetLastError ());
3074             if (HeapFree (hHeap, 0, lpValueName) == 0)
3075                 WARN ("HeapFree failed with code %li\n", GetLastError ());
3076             r = RegCloseKey (hkSubKey);
3077             if (r != ERROR_SUCCESS)
3078                 WARN ("RegCloseKey returned %li\n", r);
3079             TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3080             return ret;
3081         }
3082
3083         TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3084                 debugstr_w (lpValueName), dwIndex,
3085                 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3086
3087         cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3088         cbBufSize += cbValueLen;
3089     }
3090
3091     TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3092
3093     *pcbEnumValues = cbBufSize;
3094     *pnEnumValues = cValues;
3095
3096     if (cbEnumValues < cbBufSize)       /* buffer too small */
3097     {
3098         if (HeapFree (hHeap, 0, lpValue) == 0)
3099             WARN ("HeapFree failed with code %li\n", GetLastError ());
3100         if (HeapFree (hHeap, 0, lpValueName) == 0)
3101             WARN ("HeapFree failed with code %li\n", GetLastError ());
3102         r = RegCloseKey (hkSubKey);
3103         if (r != ERROR_SUCCESS)
3104             WARN ("RegCloseKey returned %li\n", r);
3105         TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3106         return ERROR_MORE_DATA;
3107     }
3108
3109     TRACE ("pass 2: copying all names and values to buffer\n");
3110
3111     ppev = (PPRINTER_ENUM_VALUESW) pEnumValues;         /* array of structs */
3112     pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3113
3114     for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3115     {
3116         cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3117         ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3118                 NULL, &dwType, lpValue, &cbValueLen);
3119         if (ret != ERROR_SUCCESS)
3120         {
3121             if (HeapFree (hHeap, 0, lpValue) == 0)
3122                 WARN ("HeapFree failed with code %li\n", GetLastError ());
3123             if (HeapFree (hHeap, 0, lpValueName) == 0)
3124                 WARN ("HeapFree failed with code %li\n", GetLastError ());
3125             r = RegCloseKey (hkSubKey);
3126             if (r != ERROR_SUCCESS)
3127                 WARN ("RegCloseKey returned %li\n", r);
3128             TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3129             return ret;
3130         }
3131
3132         cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3133         memcpy (pEnumValues, lpValueName, cbValueNameLen);
3134         ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3135         pEnumValues += cbValueNameLen;
3136
3137         /* return # of *bytes* (including trailing \0), not # of chars */
3138         ppev[dwIndex].cbValueName = cbValueNameLen;
3139
3140         ppev[dwIndex].dwType = dwType;
3141
3142         memcpy (pEnumValues, lpValue, cbValueLen);
3143         ppev[dwIndex].pData = pEnumValues;
3144         pEnumValues += cbValueLen;
3145
3146         ppev[dwIndex].cbData = cbValueLen;
3147
3148         TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3149                 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3150     }
3151
3152     if (HeapFree (hHeap, 0, lpValue) == 0)
3153     {
3154         ret = GetLastError ();
3155         ERR ("HeapFree failed with code %li\n", ret);
3156         if (HeapFree (hHeap, 0, lpValueName) == 0)
3157             WARN ("HeapFree failed with code %li\n", GetLastError ());
3158         r = RegCloseKey (hkSubKey);
3159         if (r != ERROR_SUCCESS)
3160             WARN ("RegCloseKey returned %li\n", r);
3161         return ret;
3162     }
3163
3164     if (HeapFree (hHeap, 0, lpValueName) == 0)
3165     {
3166         ret = GetLastError ();
3167         ERR ("HeapFree failed with code %li\n", ret);
3168         r = RegCloseKey (hkSubKey);
3169         if (r != ERROR_SUCCESS)
3170             WARN ("RegCloseKey returned %li\n", r);
3171         return ret;
3172     }
3173
3174     ret = RegCloseKey (hkSubKey);
3175     if (ret != ERROR_SUCCESS)
3176     {
3177         ERR ("RegCloseKey returned %li\n", ret);
3178         return ret;
3179     }
3180
3181     return ERROR_SUCCESS;
3182 }
3183
3184 /*******************************************************************************
3185  *              EnumPrinterDataExA      [WINSPOOL.@]
3186  *
3187  * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3188  * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers.  This is
3189  * what Windows 2000 SP1 does.
3190  *
3191  */
3192 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3193                                 LPBYTE pEnumValues, DWORD cbEnumValues,
3194                                 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3195 {
3196     INT     len;
3197     LPWSTR  pKeyNameW;
3198     DWORD   ret, dwIndex, dwBufSize;
3199     HANDLE  hHeap;
3200     LPSTR   pBuffer;
3201
3202     TRACE ("%08x %s\n", hPrinter, pKeyName);
3203
3204     if (pKeyName == NULL || *pKeyName == 0)
3205         return ERROR_INVALID_PARAMETER;
3206
3207     len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3208     if (len == 0)
3209     {
3210         ret = GetLastError ();
3211         ERR ("MultiByteToWideChar failed with code %li\n", ret);
3212         return ret;
3213     }
3214
3215     hHeap = GetProcessHeap ();
3216     if (hHeap == (HANDLE) NULL)
3217     {
3218         ERR ("GetProcessHeap failed\n");
3219         return ERROR_OUTOFMEMORY;
3220     }
3221
3222     pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3223     if (pKeyNameW == NULL)
3224     {
3225         ERR ("Failed to allocate %li bytes from process heap\n",
3226                 (LONG) len * sizeof (WCHAR));
3227         return ERROR_OUTOFMEMORY;
3228     }
3229
3230     if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3231     {
3232         ret = GetLastError ();
3233         ERR ("MultiByteToWideChar failed with code %li\n", ret);
3234         if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3235             WARN ("HeapFree failed with code %li\n", GetLastError ());
3236         return ret;
3237     }
3238
3239     ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3240             pcbEnumValues, pnEnumValues);
3241     if (ret != ERROR_SUCCESS)
3242     {
3243         if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3244             WARN ("HeapFree failed with code %li\n", GetLastError ());
3245         TRACE ("EnumPrinterDataExW returned %li\n", ret);
3246         return ret;
3247     }
3248
3249     if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3250     {
3251         ret = GetLastError ();
3252         ERR ("HeapFree failed with code %li\n", ret);
3253         return ret;
3254     }
3255
3256     if (*pnEnumValues == 0)     /* empty key */
3257         return ERROR_SUCCESS;
3258
3259     dwBufSize = 0;
3260     for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3261     {
3262         PPRINTER_ENUM_VALUESW ppev =
3263                 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3264
3265         if (dwBufSize < ppev->cbValueName)
3266             dwBufSize = ppev->cbValueName;
3267
3268         if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3269                 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3270             dwBufSize = ppev->cbData;
3271     }
3272
3273     TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3274
3275     pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3276     if (pBuffer == NULL)
3277     {
3278         ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3279         return ERROR_OUTOFMEMORY;
3280     }
3281
3282     for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3283     {
3284         PPRINTER_ENUM_VALUESW ppev =
3285                 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3286
3287         len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3288                 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3289                 NULL);
3290         if (len == 0)
3291         {
3292             ret = GetLastError ();
3293             ERR ("WideCharToMultiByte failed with code %li\n", ret);
3294             if (HeapFree (hHeap, 0, pBuffer) == 0)
3295                 WARN ("HeapFree failed with code %li\n", GetLastError ());
3296             return ret;
3297         }
3298
3299         memcpy (ppev->pValueName, pBuffer, len);
3300
3301         TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3302
3303         if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3304                 ppev->dwType != REG_MULTI_SZ)
3305             continue;
3306
3307         len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3308                 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3309         if (len == 0)
3310         {
3311             ret = GetLastError ();
3312             ERR ("WideCharToMultiByte failed with code %li\n", ret);
3313             if (HeapFree (hHeap, 0, pBuffer) == 0)
3314                 WARN ("HeapFree failed with code %li\n", GetLastError ());
3315             return ret;
3316         }
3317
3318         memcpy (ppev->pData, pBuffer, len);
3319
3320         TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3321         TRACE ("  (only first string of REG_MULTI_SZ printed)\n");
3322     }
3323
3324     if (HeapFree (hHeap, 0, pBuffer) == 0)
3325     {
3326         ret = GetLastError ();
3327         ERR ("HeapFree failed with code %li\n", ret);
3328         return ret;
3329     }
3330
3331     return ERROR_SUCCESS;
3332 }