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