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