Be more stringent in the 'Lock' invalid RECT check.
[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(cupsGetPrinters) *pcupsGetPrinters = NULL;
148     typeof(cupsGetDefault) *pcupsGetDefault = NULL;
149     typeof(cupsGetPPD) *pcupsGetPPD = NULL;
150     char                **printers;
151     int                 i,nrofdests,hadprinter = FALSE;
152     PRINTER_INFO_2A     pinfo2a;
153     const char*         def;
154     void *cupshandle = NULL;
155     const  char *ppd;
156     char   *port,*devline;
157     UNICODE_STRING  lpszNameW;
158     PWSTR pwstrNameW;
159     HKEY hkeyPrinters, hkeyPrinter;
160
161     cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
162     if (!cupshandle) 
163         return FALSE;
164
165 #define DYNCUPS(x)                                      \
166         p##x = wine_dlsym(cupshandle, #x, NULL,0);      \
167         if (!p##x) return FALSE;
168
169     DYNCUPS(cupsGetDefault);
170     DYNCUPS(cupsGetPPD);
171     DYNCUPS(cupsGetPrinters);
172 #undef DYNCUPS
173
174     def = pcupsGetDefault();
175
176     if (def && !strcmp(def,"none")) /* CUPS has "none" for no default printer */
177         def = NULL;
178
179     nrofdests = pcupsGetPrinters(&printers);
180     for (i=0;i<nrofdests;i++) {
181         /* First check that the printer doesn't exist already */
182         pwstrNameW = asciitounicode(&lpszNameW, printers[i]);
183         if (RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) ==
184             ERROR_SUCCESS) {
185              if (RegOpenKeyW(hkeyPrinters, pwstrNameW, &hkeyPrinter) ==
186                  ERROR_SUCCESS) {
187                   /* We know this printer already */
188                   RegCloseKey(hkeyPrinter);
189                   RegCloseKey(hkeyPrinters);
190                   RtlFreeUnicodeString(&lpszNameW);
191                   TRACE("Printer %s already known. Skipping detection\n", printers[i]);
192                   continue;
193              }
194              RegCloseKey(hkeyPrinters);
195         }
196         RtlFreeUnicodeString(&lpszNameW);
197
198         /* OK, we haven't seen this one yet. Request PPD for it */
199         ppd = pcupsGetPPD(printers[i]);
200         if (!ppd) {
201             WARN("No ppd file for %s.\n",printers[i]);
202             /* If this was going to be the default printer,
203              * forget it and use another one.
204              */
205             if (def && !strcmp(def,printers[i]))
206                 def = NULL;
207             continue;
208         }
209         unlink(ppd);
210
211         hadprinter = TRUE;
212
213         if (def && !strcmp(def,printers[i]))
214                 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
215
216         /* The default printer has no PPD file, just use the first one
217          * which has one.
218          */
219         if (!def) {
220                 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
221                 def = printers[i];
222         }
223         memset(&pinfo2a,0,sizeof(pinfo2a));
224         pinfo2a.pPrinterName    = printers[i];
225         pinfo2a.pDatatype       = "RAW";
226         pinfo2a.pPrintProcessor = "WinPrint";
227         pinfo2a.pDriverName     = "PS Driver";
228         pinfo2a.pComment        = "WINEPS Printer using CUPS";
229         pinfo2a.pLocation       = "<physical location of printer>";
230         port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(printers[i])+1);
231         sprintf(port,"LPR:%s",printers[i]);
232         pinfo2a.pPortName       = port;
233         pinfo2a.pParameters     = "<parameters?>";
234         pinfo2a.pShareName      = "<share name?>";
235         pinfo2a.pSepFile        = "<sep file?>";
236
237         devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
238         sprintf(devline,"WINEPS,%s",port);
239         WriteProfileStringA("devices",printers[i],devline);
240         HeapFree(GetProcessHeap(),0,devline);
241
242         if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
243             if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
244                 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",printers[i],GetLastError());
245         }
246         HeapFree(GetProcessHeap(),0,port);
247     }
248     wine_dlclose(cupshandle, NULL, 0);
249     return hadprinter;
250 }
251 #endif
252
253 static BOOL
254 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
255     PRINTER_INFO_2A     pinfo2a;
256     char                *s,*name,*prettyname,*devname;
257     BOOL                isps = FALSE;
258     char                *port,*devline;
259
260     while (isspace(*pent)) pent++;
261     s = strchr(pent,':');
262     if (!s) return FALSE;
263     *s='\0';
264     name = pent;
265     pent = s+1;
266     TRACE("%s\n",name);
267
268     /* Determine whether this is a postscript printer. */
269
270     /* 1. Check if name or aliases contain trigger phrases like 'ps' */
271     if (strstr(name,"ps")               ||
272         strstr(name,"pd")               ||      /* postscript double page */
273         strstr(name,"postscript")       ||
274         strstr(name,"PostScript")
275     ) {
276         TRACE("%s has 'ps' style name, assuming postscript.\n",name);
277         isps = TRUE;
278     }
279     /* 2. Check if this is a remote printer. These usually are postscript
280      *    capable
281      */
282     if (strstr(pent,":rm")) {
283         isps = TRUE;
284         TRACE("%s is remote, assuming postscript.\n",name);
285     }
286     /* 3. Check if we have an input filter program. If we have one, it
287      *    most likely is one capable of converting postscript.
288      *    (Could probably check for occurrence of 'gs' or 'ghostscript'
289      *     in the if file itself.)
290      */
291     if (strstr(pent,":if=/")) {
292         isps = TRUE;
293         TRACE("%s has inputfilter program, assuming postscript.\n",name);
294     }
295
296     /* If it is not a postscript printer, we cannot use it. */
297     if (!isps)
298         return FALSE;
299
300     prettyname = name;
301     /* Get longest name, usually the one at the right for later display. */
302     while ((s=strchr(prettyname,'|'))) prettyname = s+1;
303     s=strchr(name,'|');if (s) *s='\0';
304
305     /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
306      * if it is too long, we use it as comment below. */
307     devname = prettyname;
308     if (strlen(devname)>=CCHDEVICENAME-1)
309          devname = name;
310     if (strlen(devname)>=CCHDEVICENAME-1)
311         return FALSE;
312
313     if (isfirst) /* set first entry as default */
314             WINSPOOL_SetDefaultPrinter(devname,name,FALSE);
315
316     memset(&pinfo2a,0,sizeof(pinfo2a));
317     pinfo2a.pPrinterName        = devname;
318     pinfo2a.pDatatype           = "RAW";
319     pinfo2a.pPrintProcessor     = "WinPrint";
320     pinfo2a.pDriverName         = "PS Driver";
321     pinfo2a.pComment            = "WINEPS Printer using LPR";
322     pinfo2a.pLocation           = prettyname;
323     port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
324     sprintf(port,"LPR:%s",name);
325     pinfo2a.pPortName           = port;
326     pinfo2a.pParameters         = "<parameters?>";
327     pinfo2a.pShareName          = "<share name?>";
328     pinfo2a.pSepFile            = "<sep file?>";
329
330     devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
331     sprintf(devline,"WINEPS,%s",port);
332     WriteProfileStringA("devices",devname,devline);
333     HeapFree(GetProcessHeap(),0,devline);
334
335     if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
336         if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
337             ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
338     }
339     HeapFree(GetProcessHeap(),0,port);
340     return TRUE;
341 }
342
343 static BOOL
344 PRINTCAP_LoadPrinters(void) {
345     BOOL                hadprinter = FALSE, isfirst = TRUE;
346     char                buf[200];
347     FILE                *f;
348
349     f = fopen("/etc/printcap","r");
350     if (!f)
351         return FALSE;
352
353     while (fgets(buf,sizeof(buf),f)) {
354         char    *pent = NULL;
355         do {
356             char        *s;
357             s=strchr(buf,'\n'); if (s) *s='\0';
358             if ((buf[0]=='#') || (buf[0]=='\0'))
359                 continue;
360
361             if (pent) {
362                 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
363                 strcat(pent,buf);
364             } else {
365                 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
366                 strcpy(pent,buf);
367             }
368
369             if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
370                 pent[strlen(pent)-1] = '\0';
371             else
372                 break;
373         } while (fgets(buf,sizeof(buf),f));
374         if (pent)
375             hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
376         isfirst = FALSE;
377         if (pent) HeapFree(GetProcessHeap(),0,pent);
378         pent = NULL;
379         if (feof(f)) break;
380     }
381     fclose(f);
382     return hadprinter;
383 }
384
385 static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
386 {
387     return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
388                    lstrlenW(value) * sizeof(WCHAR));
389 }
390
391 void
392 WINSPOOL_LoadSystemPrinters() {
393     HKEY                hkPPD;
394     DRIVER_INFO_3A      di3a;
395     di3a.cVersion = 0x400;
396     di3a.pName = "PS Driver";
397     di3a.pEnvironment = NULL;   /* NULL means auto */
398     di3a.pDriverPath = "wineps16";
399     di3a.pDataFile = "<datafile?>";
400     di3a.pConfigFile = "wineps16";
401     di3a.pHelpFile = "<helpfile?>";
402     di3a.pDependentFiles = "<dependend files?>";
403     di3a.pMonitorName = "<monitor name?>";
404     di3a.pDefaultDataType = "RAW";
405
406     if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
407         ERR("Failed adding PS Driver (%ld)\n",GetLastError());
408         return;
409     }
410 #ifdef HAVE_CUPS_CUPS_H
411     /* If we have any CUPS based printers, skip looking for printcap printers */
412     if (CUPS_LoadPrinters())
413         return;
414 #endif
415
416     /* Check for [ppd] section in config file before parsing /etc/printcap */
417
418     if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
419             &hkPPD) == ERROR_SUCCESS)
420     {
421         RegCloseKey(hkPPD);
422         PRINTCAP_LoadPrinters();
423     }
424 }
425
426
427 /******************************************************************
428  *  WINSPOOL_GetOpenedPrinterEntry
429  *  Get the first place empty in the opened printer table
430  */
431 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
432 {
433     int i;
434
435     for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
436
437     if (i >= nb_printers)
438     {
439         LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_array,
440                                          (nb_printers + 16) * sizeof(*new_array) );
441         if (!new_array) return 0;
442         printer_array = new_array;
443         nb_printers += 16;
444     }
445
446     if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
447     {
448         strcpyW( printer_array[i], name );
449         return (HANDLE)(i + 1);
450     }
451     return 0;
452 }
453
454 /******************************************************************
455  *  WINSPOOL_GetOpenedPrinter
456  *  Get the pointer to the opened printer referred by the handle
457  */
458 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
459 {
460     int idx = (int)printerHandle;
461     if ((idx <= 0) || (idx > nb_printers))
462     {
463         SetLastError(ERROR_INVALID_HANDLE);
464         return NULL;
465     }
466     return printer_array[idx - 1];
467 }
468
469 /******************************************************************
470  *  WINSPOOL_GetOpenedPrinterRegKey
471  *
472  */
473 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
474 {
475     LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
476     DWORD ret;
477     HKEY hkeyPrinters;
478
479     if(!name) return ERROR_INVALID_HANDLE;
480
481     if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
482        ERROR_SUCCESS)
483         return ret;
484
485     if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
486     {
487         ERR("Can't find opened printer %s in registry\n",
488             debugstr_w(name));
489         RegCloseKey(hkeyPrinters);
490         return ERROR_INVALID_PRINTER_NAME; /* ? */
491     }
492     RegCloseKey(hkeyPrinters);
493     return ERROR_SUCCESS;
494 }
495
496 /***********************************************************
497  *      DEVMODEcpyAtoW
498  */
499 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
500 {
501     BOOL Formname;
502     ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
503     DWORD size;
504
505     Formname = (dmA->dmSize > off_formname);
506     size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
507     MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
508                         CCHDEVICENAME);
509     if(!Formname) {
510       memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
511              dmA->dmSize - CCHDEVICENAME);
512     } else {
513       memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
514              off_formname - CCHDEVICENAME);
515       MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
516                           CCHFORMNAME);
517       memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
518              (off_formname + CCHFORMNAME));
519     }
520     dmW->dmSize = size;
521     memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
522            dmA->dmDriverExtra);
523     return dmW;
524 }
525
526 /***********************************************************
527  *      DEVMODEdupAtoW
528  * Creates a unicode copy of supplied devmode on heap
529  */
530 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
531 {
532     LPDEVMODEW dmW;
533     DWORD size;
534     BOOL Formname;
535     ptrdiff_t off_formname;
536
537     TRACE("\n");
538     if(!dmA) return NULL;
539
540     off_formname = (char *)dmA->dmFormName - (char *)dmA;
541     Formname = (dmA->dmSize > off_formname);
542     size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
543     dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
544     return DEVMODEcpyAtoW(dmW, dmA);
545 }
546
547 /***********************************************************
548  *      DEVMODEdupWtoA
549  * Creates an ascii copy of supplied devmode on heap
550  */
551 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
552 {
553     LPDEVMODEA dmA;
554     DWORD size;
555     BOOL Formname;
556     ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
557
558     if(!dmW) return NULL;
559     Formname = (dmW->dmSize > off_formname);
560     size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
561     dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
562     WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
563                         CCHDEVICENAME, NULL, NULL);
564     if(!Formname) {
565       memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
566              dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
567     } else {
568       memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
569              off_formname - CCHDEVICENAME * sizeof(WCHAR));
570       WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
571                           CCHFORMNAME, NULL, NULL);
572       memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
573              (off_formname + CCHFORMNAME * sizeof(WCHAR)));
574     }
575     dmA->dmSize = size;
576     memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
577            dmW->dmDriverExtra);
578     return dmA;
579 }
580
581 /***********************************************************
582  *             PRINTER_INFO_2AtoW
583  * Creates a unicode copy of PRINTER_INFO_2A on heap
584  */
585 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
586 {
587     LPPRINTER_INFO_2W piW;
588     UNICODE_STRING usBuffer;
589
590     if(!piA) return NULL;
591     piW = HeapAlloc(heap, 0, sizeof(*piW));
592     memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
593     
594     piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
595     piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
596     piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
597     piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
598     piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
599     piW->pComment = asciitounicode(&usBuffer,piA->pComment);
600     piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
601     piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
602     piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
603     piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
604     piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
605     piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
606     return piW;
607 }
608
609 /***********************************************************
610  *       FREE_PRINTER_INFO_2W
611  * Free PRINTER_INFO_2W and all strings
612  */
613 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
614 {
615     if(!piW) return;
616
617     HeapFree(heap,0,piW->pServerName);
618     HeapFree(heap,0,piW->pPrinterName);
619     HeapFree(heap,0,piW->pShareName);
620     HeapFree(heap,0,piW->pPortName);
621     HeapFree(heap,0,piW->pDriverName);
622     HeapFree(heap,0,piW->pComment);
623     HeapFree(heap,0,piW->pLocation);
624     HeapFree(heap,0,piW->pDevMode);
625     HeapFree(heap,0,piW->pSepFile);
626     HeapFree(heap,0,piW->pPrintProcessor);
627     HeapFree(heap,0,piW->pDatatype);
628     HeapFree(heap,0,piW->pParameters);
629     HeapFree(heap,0,piW);
630     return;
631 }
632
633 /******************************************************************
634  *              DeviceCapabilities     [WINSPOOL.@]
635  *              DeviceCapabilitiesA    [WINSPOOL.@]
636  *
637  */
638 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
639                                LPSTR pOutput, LPDEVMODEA lpdm)
640 {
641     INT ret;
642
643     if (!GDI_CallDeviceCapabilities16)
644     {
645         GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
646                                                               (LPCSTR)104 );
647         if (!GDI_CallDeviceCapabilities16) return -1;
648     }
649     ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
650
651     /* If DC_PAPERSIZE map POINT16s to POINTs */
652     if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
653         POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
654         POINT *pt = (POINT *)pOutput;
655         INT i;
656         memcpy(tmp, pOutput, ret * sizeof(POINT16));
657         for(i = 0; i < ret; i++, pt++)
658         {
659             pt->x = tmp[i].x;
660             pt->y = tmp[i].y;
661         }
662         HeapFree( GetProcessHeap(), 0, tmp );
663     }
664     return ret;
665 }
666
667
668 /*****************************************************************************
669  *          DeviceCapabilitiesW        [WINSPOOL.@]
670  *
671  * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
672  *
673  */
674 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
675                                WORD fwCapability, LPWSTR pOutput,
676                                const DEVMODEW *pDevMode)
677 {
678     LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
679     LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
680     LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
681     INT ret;
682
683     if(pOutput && (fwCapability == DC_BINNAMES ||
684                    fwCapability == DC_FILEDEPENDENCIES ||
685                    fwCapability == DC_PAPERNAMES)) {
686       /* These need A -> W translation */
687         INT size = 0, i;
688         LPSTR pOutputA;
689         ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
690                                   dmA);
691         if(ret == -1)
692             return ret;
693         switch(fwCapability) {
694         case DC_BINNAMES:
695             size = 24;
696             break;
697         case DC_PAPERNAMES:
698         case DC_FILEDEPENDENCIES:
699             size = 64;
700             break;
701         }
702         pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
703         ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
704                                   dmA);
705         for(i = 0; i < ret; i++)
706             MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
707                                 pOutput + (i * size), size);
708         HeapFree(GetProcessHeap(), 0, pOutputA);
709     } else {
710         ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
711                                   (LPSTR)pOutput, dmA);
712     }
713     HeapFree(GetProcessHeap(),0,pPortA);
714     HeapFree(GetProcessHeap(),0,pDeviceA);
715     HeapFree(GetProcessHeap(),0,dmA);
716     return ret;
717 }
718
719 /******************************************************************
720  *              DocumentPropertiesA   [WINSPOOL.@]
721  *
722  */
723 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
724                                 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
725                                 LPDEVMODEA pDevModeInput,DWORD fMode )
726 {
727     LPSTR lpName = pDeviceName;
728     LONG ret;
729
730     TRACE("(%p,%p,%s,%p,%p,%ld)\n",
731         hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
732     );
733
734     if(!pDeviceName) {
735         LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
736         if(!lpNameW) {
737                 ERR("no name from hPrinter?\n");
738                 return -1;
739         }
740         lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
741     }
742
743     if (!GDI_CallExtDeviceMode16)
744     {
745         GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
746                                                          (LPCSTR)102 );
747         if (!GDI_CallExtDeviceMode16) {
748                 ERR("No CallExtDeviceMode16?\n");
749                 return -1;
750         }
751     }
752     ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
753                                   pDevModeInput, NULL, fMode);
754
755     if(!pDeviceName)
756         HeapFree(GetProcessHeap(),0,lpName);
757     return ret;
758 }
759
760
761 /*****************************************************************************
762  *          DocumentPropertiesW (WINSPOOL.@)
763  */
764 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
765                                 LPWSTR pDeviceName,
766                                 LPDEVMODEW pDevModeOutput,
767                                 LPDEVMODEW pDevModeInput, DWORD fMode)
768 {
769
770     LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
771     LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
772     LPDEVMODEA pDevModeOutputA = NULL;
773     LONG ret;
774
775     TRACE("(%p,%p,%s,%p,%p,%ld)\n",
776           hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
777           fMode);
778     if(pDevModeOutput) {
779         ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
780         if(ret < 0) return ret;
781         pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
782     }
783     ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
784                               pDevModeInputA, fMode);
785     if(pDevModeOutput) {
786         DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
787         HeapFree(GetProcessHeap(),0,pDevModeOutputA);
788     }
789     if(fMode == 0 && ret > 0)
790         ret += (CCHDEVICENAME + CCHFORMNAME);
791     HeapFree(GetProcessHeap(),0,pDevModeInputA);
792     HeapFree(GetProcessHeap(),0,pDeviceNameA);
793     return ret;
794 }
795
796 /******************************************************************
797  *              OpenPrinterA        [WINSPOOL.@]
798  *
799  */
800 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
801                          LPPRINTER_DEFAULTSA pDefault)
802 {
803     UNICODE_STRING lpPrinterNameW;
804     UNICODE_STRING usBuffer;
805     PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
806     PWSTR pwstrPrinterNameW;
807     BOOL ret;
808
809     pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
810
811     if(pDefault) {
812         DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
813         DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
814                                            pDefault->pDevMode);
815         DefaultW.DesiredAccess = pDefault->DesiredAccess;
816         pDefaultW = &DefaultW;
817     }
818     ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
819     if(pDefault) {
820         RtlFreeUnicodeString(&usBuffer);
821         HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
822     }
823     RtlFreeUnicodeString(&lpPrinterNameW);
824     return ret;
825 }
826
827 /******************************************************************
828  *              OpenPrinterW        [WINSPOOL.@]
829  *
830  */
831 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
832                          LPPRINTER_DEFAULTSW pDefault)
833 {
834     HKEY hkeyPrinters, hkeyPrinter;
835
836     if (!lpPrinterName) {
837        FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
838        SetLastError(ERROR_INVALID_PARAMETER);
839        return FALSE;
840     }
841
842     TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
843           pDefault);
844
845     /* Check Printer exists */
846     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
847        ERROR_SUCCESS) {
848         ERR("Can't create Printers key\n");
849         SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
850         return FALSE;
851     }
852
853     if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
854        RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
855        != ERROR_SUCCESS) {
856         TRACE("Can't find printer %s in registry\n",
857               debugstr_w(lpPrinterName));
858         RegCloseKey(hkeyPrinters);
859         SetLastError(ERROR_INVALID_PRINTER_NAME);
860         return FALSE;
861     }
862     RegCloseKey(hkeyPrinter);
863     RegCloseKey(hkeyPrinters);
864
865     if(!phPrinter) /* This seems to be what win95 does anyway */
866         return TRUE;
867
868     /* Get the unique handle of the printer*/
869     *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
870
871     if (pDefault != NULL)
872         FIXME("Not handling pDefault\n");
873
874     return TRUE;
875 }
876
877 /******************************************************************
878  *              AddMonitorA        [WINSPOOL.@]
879  *
880  */
881 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
882 {
883     FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
884     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
885     return FALSE;
886 }
887
888 /******************************************************************
889  *              DeletePrinterDriverA        [WINSPOOL.@]
890  *
891  */
892 BOOL WINAPI
893 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
894 {
895     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
896           debugstr_a(pDriverName));
897     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
898     return FALSE;
899 }
900
901
902 /******************************************************************
903  *              DeleteMonitorA        [WINSPOOL.@]
904  *
905  */
906 BOOL WINAPI
907 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
908 {
909     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
910           debugstr_a(pMonitorName));
911     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
912     return FALSE;
913 }
914
915
916 /******************************************************************
917  *              DeletePortA        [WINSPOOL.@]
918  *
919  */
920 BOOL WINAPI
921 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
922 {
923     FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
924           debugstr_a(pPortName));
925     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
926     return FALSE;
927 }
928
929 /******************************************************************************
930  *    SetPrinterW  [WINSPOOL.@]
931  */
932 BOOL WINAPI
933 SetPrinterW(
934   HANDLE  hPrinter,
935   DWORD     Level,
936   LPBYTE    pPrinter,
937   DWORD     Command) {
938
939     FIXME("():stub\n");
940     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
941     return FALSE;
942 }
943
944 /******************************************************************************
945  *    WritePrinter  [WINSPOOL.@]
946  */
947 BOOL WINAPI
948 WritePrinter(
949   HANDLE  hPrinter,
950   LPVOID  pBuf,
951   DWORD   cbBuf,
952   LPDWORD pcWritten) {
953
954     FIXME("():stub\n");
955     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
956     return FALSE;
957 }
958
959 /*****************************************************************************
960  *          AddFormA  [WINSPOOL.@]
961  */
962 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
963 {
964     FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
965     return 1;
966 }
967
968 /*****************************************************************************
969  *          AddFormW  [WINSPOOL.@]
970  */
971 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
972 {
973     FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
974     return 1;
975 }
976
977 /*****************************************************************************
978  *          AddJobA  [WINSPOOL.@]
979  */
980 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
981                         DWORD cbBuf, LPDWORD pcbNeeded)
982 {
983     FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
984           pcbNeeded);
985     return 1;
986 }
987
988 /*****************************************************************************
989  *          AddJobW  [WINSPOOL.@]
990  */
991 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
992                         LPDWORD pcbNeeded)
993 {
994     FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
995           pcbNeeded);
996     return 1;
997 }
998
999 /*****************************************************************************
1000  *          GetPrintProcessorDirectoryA  [WINSPOOL.@]
1001  */
1002 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR environ,
1003                                         DWORD level,  LPBYTE Info,
1004                                         DWORD cbBuf, LPDWORD needed)
1005 {
1006     FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", server, environ, level, Info,
1007           cbBuf);
1008     return 0;
1009 }
1010
1011 /*****************************************************************************
1012  *          WINSPOOL_OpenDriverReg [internal]
1013  *
1014  * opens the registry for the printer drivers depending on the given input
1015  * variable pEnvironment
1016  *
1017  * RETURNS:
1018  *    the opened hkey on success
1019  *    NULL on error
1020  */
1021 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1022 {   HKEY  retval;
1023     LPSTR lpKey, p = NULL;
1024
1025     TRACE("%s\n",
1026           (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1027
1028     if(pEnvironment)
1029         p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
1030                         pEnvironment;
1031     else {
1032         OSVERSIONINFOA ver;
1033         ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1034
1035         if(!GetVersionExA( &ver))
1036             return 0;
1037
1038         switch (ver.dwPlatformId) {
1039              case VER_PLATFORM_WIN32s:
1040                   ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1041                   return 0;
1042
1043              case VER_PLATFORM_WIN32_NT:
1044                   p = "Windows NT x86";
1045                   break;
1046              default:
1047                   p = "Windows 4.0";
1048                   break;
1049         }
1050         TRACE("set environment to %s\n", p);
1051     }
1052
1053     lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1054                        strlen(p) + strlen(Drivers));
1055     sprintf( lpKey, Drivers, p);
1056
1057     TRACE("%s\n", lpKey);
1058
1059     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1060        ERROR_SUCCESS)
1061        retval = 0;
1062
1063     if(pEnvironment && unicode)
1064        HeapFree( GetProcessHeap(), 0, p);
1065     HeapFree( GetProcessHeap(), 0, lpKey);
1066
1067     return retval;
1068 }
1069
1070 /*****************************************************************************
1071  *          AddPrinterW  [WINSPOOL.@]
1072  */
1073 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1074 {
1075     PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1076     LPDEVMODEA dmA;
1077     LPDEVMODEW dmW;
1078     HANDLE retval;
1079     HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1080     LONG size;
1081
1082     TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1083
1084     if(pName != NULL) {
1085         ERR("pName = %s - unsupported\n", debugstr_w(pName));
1086         SetLastError(ERROR_INVALID_PARAMETER);
1087         return 0;
1088     }
1089     if(Level != 2) {
1090         ERR("Level = %ld, unsupported!\n", Level);
1091         SetLastError(ERROR_INVALID_LEVEL);
1092         return 0;
1093     }
1094     if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1095         ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1096                 debugstr_w(pi->pPrinterName)
1097         );
1098         SetLastError(ERROR_INVALID_LEVEL);
1099         return 0;
1100     }
1101     if(!pPrinter) {
1102         SetLastError(ERROR_INVALID_PARAMETER);
1103         return 0;
1104     }
1105     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1106        ERROR_SUCCESS) {
1107         ERR("Can't create Printers key\n");
1108         return 0;
1109     }
1110     if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1111         if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1112             SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1113             RegCloseKey(hkeyPrinter);
1114             RegCloseKey(hkeyPrinters);
1115             return 0;
1116         }
1117         RegCloseKey(hkeyPrinter);
1118     }
1119     hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1120     if(!hkeyDrivers) {
1121         ERR("Can't create Drivers key\n");
1122         RegCloseKey(hkeyPrinters);
1123         return 0;
1124     }
1125     if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1126        ERROR_SUCCESS) {
1127         WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1128         RegCloseKey(hkeyPrinters);
1129         RegCloseKey(hkeyDrivers);
1130         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1131         return 0;
1132     }
1133     RegCloseKey(hkeyDriver);
1134     RegCloseKey(hkeyDrivers);
1135
1136     if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) {  /* FIXME */
1137         FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1138         SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1139         RegCloseKey(hkeyPrinters);
1140         return 0;
1141     }
1142
1143     if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1144        ERROR_SUCCESS) {
1145         FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1146         SetLastError(ERROR_INVALID_PRINTER_NAME);
1147         RegCloseKey(hkeyPrinters);
1148         return 0;
1149     }
1150     RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1151                    (LPBYTE)&pi->Attributes, sizeof(DWORD));
1152     set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1153
1154     /* See if we can load the driver.  We may need the devmode structure anyway
1155      *
1156      * FIXME:
1157      * Note that DocumentPropertiesW will briefly try to open the printer we
1158      * just create to find a DEVMODEA struct (it will use the WINEPS default
1159      * one in case it is not there, so we are ok).
1160      */
1161     size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1162     if(size < 0) {
1163         FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1164         size = sizeof(DEVMODEW);
1165     }
1166     if(pi->pDevMode)
1167         dmW = pi->pDevMode;
1168     else {
1169         dmW = HeapAlloc(GetProcessHeap(), 0, size);
1170         dmW->dmSize = size;
1171         if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
1172             ERR("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1173             SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1174             return 0;
1175         }
1176         /* set devmode to printer name */
1177         strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1178     }
1179
1180     /* Write DEVMODEA not DEVMODEW into reg.  This is what win9x does
1181        and we support these drivers.  NT writes DEVMODEW so somehow
1182        we'll need to distinguish between these when we support NT
1183        drivers */
1184     dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1185     RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
1186                    dmA->dmSize + dmA->dmDriverExtra);
1187     HeapFree(GetProcessHeap(), 0, dmA);
1188     if(!pi->pDevMode)
1189         HeapFree(GetProcessHeap(), 0, dmW);
1190     set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1191     set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1192     set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1193     set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1194
1195     set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1196     set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1197     set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1198     RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1199                    (LPBYTE)&pi->Priority, sizeof(DWORD));
1200     set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1201     set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1202     RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1203                    (LPBYTE)&pi->StartTime, sizeof(DWORD));
1204     RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1205                    (LPBYTE)&pi->Status, sizeof(DWORD));
1206     RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1207                    (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1208
1209     RegCloseKey(hkeyPrinter);
1210     RegCloseKey(hkeyPrinters);
1211     if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1212         ERR("OpenPrinter failing\n");
1213         return 0;
1214     }
1215     return retval;
1216 }
1217
1218 /*****************************************************************************
1219  *          AddPrinterA  [WINSPOOL.@]
1220  */
1221 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1222 {
1223     UNICODE_STRING pNameW;
1224     PWSTR pwstrNameW;
1225     PRINTER_INFO_2W *piW;
1226     PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1227     HANDLE ret;
1228
1229     TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1230     if(Level != 2) {
1231         ERR("Level = %ld, unsupported!\n", Level);
1232         SetLastError(ERROR_INVALID_LEVEL);
1233         return 0;
1234     }
1235     pwstrNameW = asciitounicode(&pNameW,pName);
1236     piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1237
1238     ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1239
1240     FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1241     RtlFreeUnicodeString(&pNameW);
1242     return ret;
1243 }
1244
1245
1246 /*****************************************************************************
1247  *          ClosePrinter  [WINSPOOL.@]
1248  */
1249 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1250 {
1251     int i = (int)hPrinter;
1252
1253     TRACE("Handle %p\n", hPrinter);
1254
1255     if ((i <= 0) || (i > nb_printers)) return FALSE;
1256     HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1257     printer_array[i - 1] = NULL;
1258     return TRUE;
1259 }
1260
1261 /*****************************************************************************
1262  *          DeleteFormA  [WINSPOOL.@]
1263  */
1264 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1265 {
1266     FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1267     return 1;
1268 }
1269
1270 /*****************************************************************************
1271  *          DeleteFormW  [WINSPOOL.@]
1272  */
1273 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1274 {
1275     FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1276     return 1;
1277 }
1278
1279 /*****************************************************************************
1280  *          DeletePrinter  [WINSPOOL.@]
1281  */
1282 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1283 {
1284     LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1285     HKEY hkeyPrinters;
1286
1287     if(!lpNameW) return FALSE;
1288     if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1289        ERROR_SUCCESS) {
1290         ERR("Can't open Printers key\n");
1291         return 0;
1292     }
1293
1294     /* This should use a recursive delete see Q142491 or SHDeleteKey */
1295     if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1296         SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1297         RegCloseKey(hkeyPrinters);
1298         return 0;
1299     }
1300
1301     ClosePrinter(hPrinter);
1302     return TRUE;
1303 }
1304
1305 /*****************************************************************************
1306  *          SetPrinterA  [WINSPOOL.@]
1307  */
1308 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1309                            DWORD Command)
1310 {
1311     FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1312     return FALSE;
1313 }
1314
1315 /*****************************************************************************
1316  *          SetJobA  [WINSPOOL.@]
1317  */
1318 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1319                        LPBYTE pJob, DWORD Command)
1320 {
1321     FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1322          Command);
1323     return FALSE;
1324 }
1325
1326 /*****************************************************************************
1327  *          SetJobW  [WINSPOOL.@]
1328  */
1329 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1330                        LPBYTE pJob, DWORD Command)
1331 {
1332     FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1333          Command);
1334     return FALSE;
1335 }
1336
1337 /*****************************************************************************
1338  *          EndDocPrinter  [WINSPOOL.@]
1339  */
1340 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1341 {
1342     FIXME("(hPrinter=%p): stub\n", hPrinter);
1343     return FALSE;
1344 }
1345
1346 /*****************************************************************************
1347  *          EndPagePrinter  [WINSPOOL.@]
1348  */
1349 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1350 {
1351     FIXME("(hPrinter=%p): stub\n", hPrinter);
1352     return FALSE;
1353 }
1354
1355 /*****************************************************************************
1356  *          StartDocPrinterA  [WINSPOOL.@]
1357  */
1358 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1359 {
1360     FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1361     return FALSE;
1362 }
1363
1364 /*****************************************************************************
1365  *          StartDocPrinterW  [WINSPOOL.@]
1366  */
1367 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1368 {
1369     FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1370     return FALSE;
1371 }
1372
1373 /*****************************************************************************
1374  *          StartPagePrinter  [WINSPOOL.@]
1375  */
1376 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1377 {
1378     FIXME("(hPrinter=%p): stub\n", hPrinter);
1379     return FALSE;
1380 }
1381
1382 /*****************************************************************************
1383  *          GetFormA  [WINSPOOL.@]
1384  */
1385 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1386                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1387 {
1388     FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1389          Level,pForm,cbBuf,pcbNeeded);
1390     return FALSE;
1391 }
1392
1393 /*****************************************************************************
1394  *          GetFormW  [WINSPOOL.@]
1395  */
1396 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1397                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1398 {
1399     FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1400           debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1401     return FALSE;
1402 }
1403
1404 /*****************************************************************************
1405  *          SetFormA  [WINSPOOL.@]
1406  */
1407 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1408                         LPBYTE pForm)
1409 {
1410     FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1411     return FALSE;
1412 }
1413
1414 /*****************************************************************************
1415  *          SetFormW  [WINSPOOL.@]
1416  */
1417 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1418                         LPBYTE pForm)
1419 {
1420     FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1421     return FALSE;
1422 }
1423
1424 /*****************************************************************************
1425  *          ReadPrinter  [WINSPOOL.@]
1426  */
1427 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1428                            LPDWORD pNoBytesRead)
1429 {
1430     FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1431     return FALSE;
1432 }
1433
1434 /*****************************************************************************
1435  *          ResetPrinterA  [WINSPOOL.@]
1436  */
1437 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1438 {
1439     FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1440     return FALSE;
1441 }
1442
1443 /*****************************************************************************
1444  *          ResetPrinterW  [WINSPOOL.@]
1445  */
1446 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1447 {
1448     FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1449     return FALSE;
1450 }
1451
1452 /*****************************************************************************
1453  *    WINSPOOL_GetDWORDFromReg
1454  *
1455  * Return DWORD associated with ValueName from hkey.
1456  */
1457 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1458 {
1459     DWORD sz = sizeof(DWORD), type, value = 0;
1460     LONG ret;
1461
1462     ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1463
1464     if(ret != ERROR_SUCCESS) {
1465         WARN("Got ret = %ld on name %s\n", ret, ValueName);
1466         return 0;
1467     }
1468     if(type != REG_DWORD) {
1469         ERR("Got type %ld\n", type);
1470         return 0;
1471     }
1472     return value;
1473 }
1474
1475 /*****************************************************************************
1476  *    WINSPOOL_GetStringFromReg
1477  *
1478  * Get ValueName from hkey storing result in ptr.  buflen is space left in ptr
1479  * String is stored either as unicode or ascii.
1480  * Bit of a hack here to get the ValueName if we want ascii.
1481  */
1482 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1483                                       DWORD buflen, DWORD *needed,
1484                                       BOOL unicode)
1485 {
1486     DWORD sz = buflen, type;
1487     LONG ret;
1488
1489     if(unicode)
1490         ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1491     else {
1492         LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1493         ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1494         HeapFree(GetProcessHeap(),0,ValueNameA);
1495     }
1496     if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1497         WARN("Got ret = %ld\n", ret);
1498         *needed = 0;
1499         return FALSE;
1500     }
1501     *needed = sz;
1502     return TRUE;
1503 }
1504
1505 /*****************************************************************************
1506  *    WINSPOOL_GetDefaultDevMode
1507  *
1508  * Get a default DevMode values for wineps.
1509  * FIXME - use ppd.
1510  */
1511
1512 static void WINSPOOL_GetDefaultDevMode(
1513         LPBYTE ptr,
1514         DWORD buflen, DWORD *needed,
1515         BOOL unicode)
1516 {
1517     DEVMODEA    dm;
1518
1519         /* fill default DEVMODE - should be read from ppd... */
1520         ZeroMemory( &dm, sizeof(dm) );
1521         strcpy(dm.dmDeviceName,"wineps");
1522         dm.dmSpecVersion = DM_SPECVERSION;
1523         dm.dmDriverVersion = 1;
1524         dm.dmSize = sizeof(DEVMODEA);
1525         dm.dmDriverExtra = 0;
1526         dm.dmFields =
1527                 DM_ORIENTATION | DM_PAPERSIZE |
1528                 DM_PAPERLENGTH | DM_PAPERWIDTH |
1529                 DM_SCALE |
1530                 DM_COPIES |
1531                 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1532                 DM_YRESOLUTION | DM_TTOPTION;
1533
1534         dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1535         dm.u1.s1.dmPaperSize = DMPAPER_A4;
1536         dm.u1.s1.dmPaperLength = 2970;
1537         dm.u1.s1.dmPaperWidth = 2100;
1538
1539         dm.dmScale = 100;
1540         dm.dmCopies = 1;
1541         dm.dmDefaultSource = DMBIN_AUTO;
1542         dm.dmPrintQuality = DMRES_MEDIUM;
1543         /* dm.dmColor */
1544         /* dm.dmDuplex */
1545         dm.dmYResolution = 300; /* 300dpi */
1546         dm.dmTTOption = DMTT_BITMAP;
1547         /* dm.dmCollate */
1548         /* dm.dmFormName */
1549         /* dm.dmLogPixels */
1550         /* dm.dmBitsPerPel */
1551         /* dm.dmPelsWidth */
1552         /* dm.dmPelsHeight */
1553         /* dm.dmDisplayFlags */
1554         /* dm.dmDisplayFrequency */
1555         /* dm.dmICMMethod */
1556         /* dm.dmICMIntent */
1557         /* dm.dmMediaType */
1558         /* dm.dmDitherType */
1559         /* dm.dmReserved1 */
1560         /* dm.dmReserved2 */
1561         /* dm.dmPanningWidth */
1562         /* dm.dmPanningHeight */
1563
1564     if(unicode) {
1565         if(buflen >= sizeof(DEVMODEW)) {
1566             DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
1567             memcpy(ptr, pdmW, sizeof(DEVMODEW));
1568             HeapFree(GetProcessHeap(),0,pdmW);
1569         }
1570         *needed = sizeof(DEVMODEW);
1571     }
1572     else
1573     {
1574         if(buflen >= sizeof(DEVMODEA)) {
1575             memcpy(ptr, &dm, sizeof(DEVMODEA));
1576         }
1577         *needed = sizeof(DEVMODEA);
1578     }
1579 }
1580
1581 /*****************************************************************************
1582  *    WINSPOOL_GetDevModeFromReg
1583  *
1584  * Get ValueName from hkey storing result in ptr.  buflen is space left in ptr
1585  * DevMode is stored either as unicode or ascii.
1586  */
1587 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1588                                        LPBYTE ptr,
1589                                        DWORD buflen, DWORD *needed,
1590                                        BOOL unicode)
1591 {
1592     DWORD sz = buflen, type;
1593     LONG ret;
1594
1595     if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1596     ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1597     if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1598     if (sz < sizeof(DEVMODEA))
1599     {
1600         ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1601         return FALSE;
1602     }
1603     /* ensures that dmSize is not erratically bogus if registry is invalid */
1604     if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1605         ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1606     if(unicode) {
1607         sz += (CCHDEVICENAME + CCHFORMNAME);
1608         if(buflen >= sz) {
1609             DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1610             memcpy(ptr, dmW, sz);
1611             HeapFree(GetProcessHeap(),0,dmW);
1612         }
1613     }
1614     *needed = sz;
1615     return TRUE;
1616 }
1617
1618 /*********************************************************************
1619  *    WINSPOOL_GetPrinter_2
1620  *
1621  * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1622  * The strings are either stored as unicode or ascii.
1623  */
1624 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1625                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1626                                   BOOL unicode)
1627 {
1628     DWORD size, left = cbBuf;
1629     BOOL space = (cbBuf > 0);
1630     LPBYTE ptr = buf;
1631
1632     *pcbNeeded = 0;
1633
1634     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1635                                  unicode)) {
1636         if(space && size <= left) {
1637             pi2->pPrinterName = (LPWSTR)ptr;
1638             ptr += size;
1639             left -= size;
1640         } else
1641             space = FALSE;
1642         *pcbNeeded += size;
1643     }
1644     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1645                                  unicode)) {
1646         if(space && size <= left) {
1647             pi2->pShareName = (LPWSTR)ptr;
1648             ptr += size;
1649             left -= size;
1650         } else
1651             space = FALSE;
1652         *pcbNeeded += size;
1653     }
1654     if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1655                                  unicode)) {
1656         if(space && size <= left) {
1657             pi2->pPortName = (LPWSTR)ptr;
1658             ptr += size;
1659             left -= size;
1660         } else
1661             space = FALSE;
1662         *pcbNeeded += size;
1663     }
1664     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1665                                  &size, unicode)) {
1666         if(space && size <= left) {
1667             pi2->pDriverName = (LPWSTR)ptr;
1668             ptr += size;
1669             left -= size;
1670         } else
1671             space = FALSE;
1672         *pcbNeeded += size;
1673     }
1674     if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1675                                  unicode)) {
1676         if(space && size <= left) {
1677             pi2->pComment = (LPWSTR)ptr;
1678             ptr += size;
1679             left -= size;
1680         } else
1681             space = FALSE;
1682         *pcbNeeded += size;
1683     }
1684     if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1685                                  unicode)) {
1686         if(space && size <= left) {
1687             pi2->pLocation = (LPWSTR)ptr;
1688             ptr += size;
1689             left -= size;
1690         } else
1691             space = FALSE;
1692         *pcbNeeded += size;
1693     }
1694     if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1695                                   &size, unicode)) {
1696         if(space && size <= left) {
1697             pi2->pDevMode = (LPDEVMODEW)ptr;
1698             ptr += size;
1699             left -= size;
1700         } else
1701             space = FALSE;
1702         *pcbNeeded += size;
1703     }
1704     else
1705     {
1706         MESSAGE( "no DevMode in registry. please setup your printer again.\n"
1707                  "use the default hard-coded DevMode(wineps/A4/300dpi).\n" );
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         dwType |= PRINTER_ENUM_LOCAL;
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 }