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