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