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