Test for %Systemroot%.
[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, (const BYTE*)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 = (const char *)dmA->dmFormName - (const 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, (const 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 = (const char *)dmW->dmFormName - (const 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, (const 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,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
961     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
962     return FALSE;
963 }
964
965 /******************************************************************************
966  *              AddMonitorW        [WINSPOOL.@]
967  */
968 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
969 {
970     FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
971     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
972     return FALSE;
973 }
974
975 /******************************************************************
976  *              DeletePrinterDriverA        [WINSPOOL.@]
977  *
978  */
979 BOOL WINAPI
980 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
981 {
982     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
983           debugstr_a(pDriverName));
984     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
985     return FALSE;
986 }
987
988 /******************************************************************
989  *              DeletePrinterDriverW        [WINSPOOL.@]
990  *
991  */
992 BOOL WINAPI
993 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
994 {
995     FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
996           debugstr_w(pDriverName));
997     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
998     return FALSE;
999 }
1000
1001 /******************************************************************
1002  *              DeleteMonitorA        [WINSPOOL.@]
1003  *
1004  */
1005 BOOL WINAPI
1006 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1007 {
1008     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1009           debugstr_a(pMonitorName));
1010     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1011     return FALSE;
1012 }
1013
1014 /******************************************************************
1015  *              DeleteMonitorW        [WINSPOOL.@]
1016  *
1017  */
1018 BOOL WINAPI
1019 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1020 {
1021     FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1022           debugstr_w(pMonitorName));
1023     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1024     return FALSE;
1025 }
1026
1027 /******************************************************************
1028  *              DeletePortA        [WINSPOOL.@]
1029  *
1030  */
1031 BOOL WINAPI
1032 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1033 {
1034     FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1035           debugstr_a(pPortName));
1036     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1037     return FALSE;
1038 }
1039
1040 /******************************************************************
1041  *              DeletePortW        [WINSPOOL.@]
1042  *
1043  */
1044 BOOL WINAPI
1045 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1046 {
1047     FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1048           debugstr_w(pPortName));
1049     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1050     return FALSE;
1051 }
1052
1053 /******************************************************************************
1054  *    SetPrinterW  [WINSPOOL.@]
1055  */
1056 BOOL WINAPI
1057 SetPrinterW(
1058   HANDLE  hPrinter,
1059   DWORD     Level,
1060   LPBYTE    pPrinter,
1061   DWORD     Command) {
1062
1063     FIXME("():stub\n");
1064     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1065     return FALSE;
1066 }
1067
1068 /******************************************************************************
1069  *    WritePrinter  [WINSPOOL.@]
1070  */
1071 BOOL WINAPI
1072 WritePrinter(
1073   HANDLE  hPrinter,
1074   LPVOID  pBuf,
1075   DWORD   cbBuf,
1076   LPDWORD pcWritten) {
1077
1078     FIXME("():stub\n");
1079     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1080     return FALSE;
1081 }
1082
1083 /*****************************************************************************
1084  *          AddFormA  [WINSPOOL.@]
1085  */
1086 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1087 {
1088     FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1089     return 1;
1090 }
1091
1092 /*****************************************************************************
1093  *          AddFormW  [WINSPOOL.@]
1094  */
1095 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1096 {
1097     FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1098     return 1;
1099 }
1100
1101 /*****************************************************************************
1102  *          AddJobA  [WINSPOOL.@]
1103  */
1104 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
1105                         DWORD cbBuf, LPDWORD pcbNeeded)
1106 {
1107     FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1108           pcbNeeded);
1109     return 1;
1110 }
1111
1112 /*****************************************************************************
1113  *          AddJobW  [WINSPOOL.@]
1114  */
1115 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
1116                         LPDWORD pcbNeeded)
1117 {
1118     FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1119           pcbNeeded);
1120     return 1;
1121 }
1122
1123 /*****************************************************************************
1124  *          GetPrintProcessorDirectoryA  [WINSPOOL.@]
1125  */
1126 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1127                                         DWORD level,  LPBYTE Info,
1128                                         DWORD cbBuf, LPDWORD needed)
1129 {
1130     FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1131           level, Info, cbBuf);
1132     return 0;
1133 }
1134
1135 /*****************************************************************************
1136  *          GetPrintProcessorDirectoryW  [WINSPOOL.@]
1137  */
1138 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1139                                         DWORD level,  LPBYTE Info,
1140                                         DWORD cbBuf, LPDWORD needed)
1141 {
1142     FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1143           level, Info, cbBuf);
1144     return 0;
1145 }
1146
1147 /*****************************************************************************
1148  *          WINSPOOL_OpenDriverReg [internal]
1149  *
1150  * opens the registry for the printer drivers depending on the given input
1151  * variable pEnvironment
1152  *
1153  * RETURNS:
1154  *    the opened hkey on success
1155  *    NULL on error
1156  */
1157 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1158 {   HKEY  retval;
1159     LPSTR lpKey, p = NULL;
1160
1161     TRACE("%s\n",
1162           (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1163
1164     if(pEnvironment)
1165         p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
1166                         pEnvironment;
1167     else {
1168         OSVERSIONINFOA ver;
1169         ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1170
1171         if(!GetVersionExA( &ver))
1172             return 0;
1173
1174         switch (ver.dwPlatformId) {
1175              case VER_PLATFORM_WIN32s:
1176                   ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1177                   return 0;
1178
1179              case VER_PLATFORM_WIN32_NT:
1180                   p = "Windows NT x86";
1181                   break;
1182              default:
1183                   p = "Windows 4.0";
1184                   break;
1185         }
1186         TRACE("set environment to %s\n", p);
1187     }
1188
1189     lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1190                        strlen(p) + strlen(Drivers));
1191     sprintf( lpKey, Drivers, p);
1192
1193     TRACE("%s\n", lpKey);
1194
1195     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1196        ERROR_SUCCESS)
1197        retval = 0;
1198
1199     if(pEnvironment && unicode)
1200        HeapFree( GetProcessHeap(), 0, p);
1201     HeapFree( GetProcessHeap(), 0, lpKey);
1202
1203     return retval;
1204 }
1205
1206 /*****************************************************************************
1207  *          AddPrinterW  [WINSPOOL.@]
1208  */
1209 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1210 {
1211     PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1212     LPDEVMODEA dmA;
1213     LPDEVMODEW dmW;
1214     HANDLE retval;
1215     HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1216     LONG size;
1217
1218     TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1219
1220     if(pName != NULL) {
1221         ERR("pName = %s - unsupported\n", debugstr_w(pName));
1222         SetLastError(ERROR_INVALID_PARAMETER);
1223         return 0;
1224     }
1225     if(Level != 2) {
1226         ERR("Level = %ld, unsupported!\n", Level);
1227         SetLastError(ERROR_INVALID_LEVEL);
1228         return 0;
1229     }
1230     if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1231         ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1232                 debugstr_w(pi->pPrinterName)
1233         );
1234         SetLastError(ERROR_INVALID_LEVEL);
1235         return 0;
1236     }
1237     if(!pPrinter) {
1238         SetLastError(ERROR_INVALID_PARAMETER);
1239         return 0;
1240     }
1241     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1242        ERROR_SUCCESS) {
1243         ERR("Can't create Printers key\n");
1244         return 0;
1245     }
1246     if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1247         if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1248             SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1249             RegCloseKey(hkeyPrinter);
1250             RegCloseKey(hkeyPrinters);
1251             return 0;
1252         }
1253         RegCloseKey(hkeyPrinter);
1254     }
1255     hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1256     if(!hkeyDrivers) {
1257         ERR("Can't create Drivers key\n");
1258         RegCloseKey(hkeyPrinters);
1259         return 0;
1260     }
1261     if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1262        ERROR_SUCCESS) {
1263         WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1264         RegCloseKey(hkeyPrinters);
1265         RegCloseKey(hkeyDrivers);
1266         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1267         return 0;
1268     }
1269     RegCloseKey(hkeyDriver);
1270     RegCloseKey(hkeyDrivers);
1271
1272     if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) {  /* FIXME */
1273         FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1274         SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1275         RegCloseKey(hkeyPrinters);
1276         return 0;
1277     }
1278
1279     if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1280        ERROR_SUCCESS) {
1281         FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1282         SetLastError(ERROR_INVALID_PRINTER_NAME);
1283         RegCloseKey(hkeyPrinters);
1284         return 0;
1285     }
1286     RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1287                    (LPBYTE)&pi->Attributes, sizeof(DWORD));
1288     set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1289
1290     /* See if we can load the driver.  We may need the devmode structure anyway
1291      *
1292      * FIXME:
1293      * Note that DocumentPropertiesW will briefly try to open the printer we
1294      * just create to find a DEVMODEA struct (it will use the WINEPS default
1295      * one in case it is not there, so we are ok).
1296      */
1297     size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1298
1299     if(size < 0) {
1300         FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1301         size = sizeof(DEVMODEW);
1302     }
1303     if(pi->pDevMode)
1304         dmW = pi->pDevMode;
1305     else 
1306     {
1307             dmW = HeapAlloc(GetProcessHeap(), 0, size);
1308         ZeroMemory(dmW,size);
1309             dmW->dmSize = size;
1310             if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) 
1311         {
1312                 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1313             HeapFree(GetProcessHeap(),0,dmW);
1314             dmW=NULL;
1315             }
1316         else
1317         {
1318                 /* set devmode to printer name */
1319                 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1320         }
1321     }
1322
1323     /* Write DEVMODEA not DEVMODEW into reg.  This is what win9x does
1324        and we support these drivers.  NT writes DEVMODEW so somehow
1325        we'll need to distinguish between these when we support NT
1326        drivers */
1327     if (dmW)
1328     {
1329         dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1330         RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, 
1331                        (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1332         HeapFree(GetProcessHeap(), 0, dmA);
1333         if(!pi->pDevMode)
1334             HeapFree(GetProcessHeap(), 0, dmW);
1335     }
1336     set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1337     set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1338     set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1339     set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1340
1341     set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1342     set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1343     set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1344     RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1345                    (LPBYTE)&pi->Priority, sizeof(DWORD));
1346     set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1347     set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1348     RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1349                    (LPBYTE)&pi->StartTime, sizeof(DWORD));
1350     RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1351                    (LPBYTE)&pi->Status, sizeof(DWORD));
1352     RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1353                    (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1354
1355     RegCloseKey(hkeyPrinter);
1356     RegCloseKey(hkeyPrinters);
1357     if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1358         ERR("OpenPrinter failing\n");
1359         return 0;
1360     }
1361     return retval;
1362 }
1363
1364 /*****************************************************************************
1365  *          AddPrinterA  [WINSPOOL.@]
1366  */
1367 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1368 {
1369     UNICODE_STRING pNameW;
1370     PWSTR pwstrNameW;
1371     PRINTER_INFO_2W *piW;
1372     PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1373     HANDLE ret;
1374
1375     TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1376     if(Level != 2) {
1377         ERR("Level = %ld, unsupported!\n", Level);
1378         SetLastError(ERROR_INVALID_LEVEL);
1379         return 0;
1380     }
1381     pwstrNameW = asciitounicode(&pNameW,pName);
1382     piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1383
1384     ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1385
1386     FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1387     RtlFreeUnicodeString(&pNameW);
1388     return ret;
1389 }
1390
1391
1392 /*****************************************************************************
1393  *          ClosePrinter  [WINSPOOL.@]
1394  */
1395 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1396 {
1397     int i = (int)hPrinter;
1398
1399     TRACE("Handle %p\n", hPrinter);
1400
1401     if ((i <= 0) || (i > nb_printers)) return FALSE;
1402     HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1403     printer_array[i - 1] = NULL;
1404     return TRUE;
1405 }
1406
1407 /*****************************************************************************
1408  *          DeleteFormA  [WINSPOOL.@]
1409  */
1410 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1411 {
1412     FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1413     return 1;
1414 }
1415
1416 /*****************************************************************************
1417  *          DeleteFormW  [WINSPOOL.@]
1418  */
1419 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1420 {
1421     FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1422     return 1;
1423 }
1424
1425 /*****************************************************************************
1426  *   WINSPOOL_SHRegDeleteKey
1427  *
1428  *   Recursively delete subkeys.
1429  *   Cut & paste from shlwapi.
1430  * 
1431  */
1432 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1433 {
1434   DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1435   WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1436   HKEY hSubKey = 0;
1437
1438   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1439   if(!dwRet)
1440   {
1441     /* Find how many subkeys there are */
1442     dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1443                              &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1444     if(!dwRet)
1445     {
1446       dwMaxSubkeyLen++;
1447       if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1448         /* Name too big: alloc a buffer for it */
1449         lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1450
1451       if(!lpszName)
1452         dwRet = ERROR_NOT_ENOUGH_MEMORY;
1453       else
1454       {
1455         /* Recursively delete all the subkeys */
1456         for(i = 0; i < dwKeyCount && !dwRet; i++)
1457         {
1458           dwSize = dwMaxSubkeyLen;
1459           dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1460           if(!dwRet)
1461             dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1462         }
1463
1464         if (lpszName != szNameBuf)
1465           HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1466       }
1467     }
1468
1469     RegCloseKey(hSubKey);
1470     if(!dwRet)
1471       dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1472   }
1473   return dwRet;
1474 }
1475
1476 /*****************************************************************************
1477  *          DeletePrinter  [WINSPOOL.@]
1478  */
1479 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1480 {
1481     LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1482     HKEY hkeyPrinters;
1483
1484     if(!lpNameW) return FALSE;
1485     if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1486         WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1487         RegCloseKey(hkeyPrinters);
1488     }
1489     WriteProfileStringW(devicesW, lpNameW, NULL);
1490     return TRUE;
1491 }
1492
1493 /*****************************************************************************
1494  *          SetPrinterA  [WINSPOOL.@]
1495  */
1496 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1497                            DWORD Command)
1498 {
1499     FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1500     return FALSE;
1501 }
1502
1503 /*****************************************************************************
1504  *          SetJobA  [WINSPOOL.@]
1505  */
1506 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1507                        LPBYTE pJob, DWORD Command)
1508 {
1509     FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1510          Command);
1511     return FALSE;
1512 }
1513
1514 /*****************************************************************************
1515  *          SetJobW  [WINSPOOL.@]
1516  */
1517 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1518                        LPBYTE pJob, DWORD Command)
1519 {
1520     FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1521          Command);
1522     return FALSE;
1523 }
1524
1525 /*****************************************************************************
1526  *          EndDocPrinter  [WINSPOOL.@]
1527  */
1528 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1529 {
1530     FIXME("(hPrinter=%p): stub\n", hPrinter);
1531     return FALSE;
1532 }
1533
1534 /*****************************************************************************
1535  *          EndPagePrinter  [WINSPOOL.@]
1536  */
1537 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1538 {
1539     FIXME("(hPrinter=%p): stub\n", hPrinter);
1540     return FALSE;
1541 }
1542
1543 /*****************************************************************************
1544  *          StartDocPrinterA  [WINSPOOL.@]
1545  */
1546 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1547 {
1548     FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1549     return FALSE;
1550 }
1551
1552 /*****************************************************************************
1553  *          StartDocPrinterW  [WINSPOOL.@]
1554  */
1555 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1556 {
1557     FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1558     return FALSE;
1559 }
1560
1561 /*****************************************************************************
1562  *          StartPagePrinter  [WINSPOOL.@]
1563  */
1564 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1565 {
1566     FIXME("(hPrinter=%p): stub\n", hPrinter);
1567     return FALSE;
1568 }
1569
1570 /*****************************************************************************
1571  *          GetFormA  [WINSPOOL.@]
1572  */
1573 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1574                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1575 {
1576     FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1577          Level,pForm,cbBuf,pcbNeeded);
1578     return FALSE;
1579 }
1580
1581 /*****************************************************************************
1582  *          GetFormW  [WINSPOOL.@]
1583  */
1584 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1585                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1586 {
1587     FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1588           debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1589     return FALSE;
1590 }
1591
1592 /*****************************************************************************
1593  *          SetFormA  [WINSPOOL.@]
1594  */
1595 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1596                         LPBYTE pForm)
1597 {
1598     FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1599     return FALSE;
1600 }
1601
1602 /*****************************************************************************
1603  *          SetFormW  [WINSPOOL.@]
1604  */
1605 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1606                         LPBYTE pForm)
1607 {
1608     FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1609     return FALSE;
1610 }
1611
1612 /*****************************************************************************
1613  *          ReadPrinter  [WINSPOOL.@]
1614  */
1615 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1616                            LPDWORD pNoBytesRead)
1617 {
1618     FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1619     return FALSE;
1620 }
1621
1622 /*****************************************************************************
1623  *          ResetPrinterA  [WINSPOOL.@]
1624  */
1625 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1626 {
1627     FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1628     return FALSE;
1629 }
1630
1631 /*****************************************************************************
1632  *          ResetPrinterW  [WINSPOOL.@]
1633  */
1634 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1635 {
1636     FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1637     return FALSE;
1638 }
1639
1640 /*****************************************************************************
1641  *    WINSPOOL_GetDWORDFromReg
1642  *
1643  * Return DWORD associated with ValueName from hkey.
1644  */
1645 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1646 {
1647     DWORD sz = sizeof(DWORD), type, value = 0;
1648     LONG ret;
1649
1650     ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1651
1652     if(ret != ERROR_SUCCESS) {
1653         WARN("Got ret = %ld on name %s\n", ret, ValueName);
1654         return 0;
1655     }
1656     if(type != REG_DWORD) {
1657         ERR("Got type %ld\n", type);
1658         return 0;
1659     }
1660     return value;
1661 }
1662
1663 /*****************************************************************************
1664  *    WINSPOOL_GetStringFromReg
1665  *
1666  * Get ValueName from hkey storing result in ptr.  buflen is space left in ptr
1667  * String is stored either as unicode or ascii.
1668  * Bit of a hack here to get the ValueName if we want ascii.
1669  */
1670 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1671                                       DWORD buflen, DWORD *needed,
1672                                       BOOL unicode)
1673 {
1674     DWORD sz = buflen, type;
1675     LONG ret;
1676
1677     if(unicode)
1678         ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1679     else {
1680         LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1681         ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1682         HeapFree(GetProcessHeap(),0,ValueNameA);
1683     }
1684     if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1685         WARN("Got ret = %ld\n", ret);
1686         *needed = 0;
1687         return FALSE;
1688     }
1689     *needed = sz;
1690     return TRUE;
1691 }
1692
1693 /*****************************************************************************
1694  *    WINSPOOL_GetDefaultDevMode
1695  *
1696  * Get a default DevMode values for wineps.
1697  * FIXME - use ppd.
1698  */
1699
1700 static void WINSPOOL_GetDefaultDevMode(
1701         LPBYTE ptr,
1702         DWORD buflen, DWORD *needed,
1703         BOOL unicode)
1704 {
1705     DEVMODEA    dm;
1706
1707         /* fill default DEVMODE - should be read from ppd... */
1708         ZeroMemory( &dm, sizeof(dm) );
1709         strcpy(dm.dmDeviceName,"wineps");
1710         dm.dmSpecVersion = DM_SPECVERSION;
1711         dm.dmDriverVersion = 1;
1712         dm.dmSize = sizeof(DEVMODEA);
1713         dm.dmDriverExtra = 0;
1714         dm.dmFields =
1715                 DM_ORIENTATION | DM_PAPERSIZE |
1716                 DM_PAPERLENGTH | DM_PAPERWIDTH |
1717                 DM_SCALE |
1718                 DM_COPIES |
1719                 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1720                 DM_YRESOLUTION | DM_TTOPTION;
1721
1722         dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1723         dm.u1.s1.dmPaperSize = DMPAPER_A4;
1724         dm.u1.s1.dmPaperLength = 2970;
1725         dm.u1.s1.dmPaperWidth = 2100;
1726
1727         dm.dmScale = 100;
1728         dm.dmCopies = 1;
1729         dm.dmDefaultSource = DMBIN_AUTO;
1730         dm.dmPrintQuality = DMRES_MEDIUM;
1731         /* dm.dmColor */
1732         /* dm.dmDuplex */
1733         dm.dmYResolution = 300; /* 300dpi */
1734         dm.dmTTOption = DMTT_BITMAP;
1735         /* dm.dmCollate */
1736         /* dm.dmFormName */
1737         /* dm.dmLogPixels */
1738         /* dm.dmBitsPerPel */
1739         /* dm.dmPelsWidth */
1740         /* dm.dmPelsHeight */
1741         /* dm.dmDisplayFlags */
1742         /* dm.dmDisplayFrequency */
1743         /* dm.dmICMMethod */
1744         /* dm.dmICMIntent */
1745         /* dm.dmMediaType */
1746         /* dm.dmDitherType */
1747         /* dm.dmReserved1 */
1748         /* dm.dmReserved2 */
1749         /* dm.dmPanningWidth */
1750         /* dm.dmPanningHeight */
1751
1752     if(unicode) {
1753         if(buflen >= sizeof(DEVMODEW)) {
1754             DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
1755             memcpy(ptr, pdmW, sizeof(DEVMODEW));
1756             HeapFree(GetProcessHeap(),0,pdmW);
1757         }
1758         *needed = sizeof(DEVMODEW);
1759     }
1760     else
1761     {
1762         if(buflen >= sizeof(DEVMODEA)) {
1763             memcpy(ptr, &dm, sizeof(DEVMODEA));
1764         }
1765         *needed = sizeof(DEVMODEA);
1766     }
1767 }
1768
1769 /*****************************************************************************
1770  *    WINSPOOL_GetDevModeFromReg
1771  *
1772  * Get ValueName from hkey storing result in ptr.  buflen is space left in ptr
1773  * DevMode is stored either as unicode or ascii.
1774  */
1775 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1776                                        LPBYTE ptr,
1777                                        DWORD buflen, DWORD *needed,
1778                                        BOOL unicode)
1779 {
1780     DWORD sz = buflen, type;
1781     LONG ret;
1782
1783     if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1784     ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1785     if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1786     if (sz < sizeof(DEVMODEA))
1787     {
1788         TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1789         return FALSE;
1790     }
1791     /* ensures that dmSize is not erratically bogus if registry is invalid */
1792     if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1793         ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1794     if(unicode) {
1795         sz += (CCHDEVICENAME + CCHFORMNAME);
1796         if(buflen >= sz) {
1797             DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
1798             memcpy(ptr, dmW, sz);
1799             HeapFree(GetProcessHeap(),0,dmW);
1800         }
1801     }
1802     *needed = sz;
1803     return TRUE;
1804 }
1805
1806 /*********************************************************************
1807  *    WINSPOOL_GetPrinter_2
1808  *
1809  * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1810  * The strings are either stored as unicode or ascii.
1811  */
1812 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1813                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1814                                   BOOL unicode)
1815 {
1816     DWORD size, left = cbBuf;
1817     BOOL space = (cbBuf > 0);
1818     LPBYTE ptr = buf;
1819
1820     *pcbNeeded = 0;
1821
1822     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1823                                  unicode)) {
1824         if(space && size <= left) {
1825             pi2->pPrinterName = (LPWSTR)ptr;
1826             ptr += size;
1827             left -= size;
1828         } else
1829             space = FALSE;
1830         *pcbNeeded += size;
1831     }
1832     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1833                                  unicode)) {
1834         if(space && size <= left) {
1835             pi2->pShareName = (LPWSTR)ptr;
1836             ptr += size;
1837             left -= size;
1838         } else
1839             space = FALSE;
1840         *pcbNeeded += size;
1841     }
1842     if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1843                                  unicode)) {
1844         if(space && size <= left) {
1845             pi2->pPortName = (LPWSTR)ptr;
1846             ptr += size;
1847             left -= size;
1848         } else
1849             space = FALSE;
1850         *pcbNeeded += size;
1851     }
1852     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1853                                  &size, unicode)) {
1854         if(space && size <= left) {
1855             pi2->pDriverName = (LPWSTR)ptr;
1856             ptr += size;
1857             left -= size;
1858         } else
1859             space = FALSE;
1860         *pcbNeeded += size;
1861     }
1862     if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1863                                  unicode)) {
1864         if(space && size <= left) {
1865             pi2->pComment = (LPWSTR)ptr;
1866             ptr += size;
1867             left -= size;
1868         } else
1869             space = FALSE;
1870         *pcbNeeded += size;
1871     }
1872     if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1873                                  unicode)) {
1874         if(space && size <= left) {
1875             pi2->pLocation = (LPWSTR)ptr;
1876             ptr += size;
1877             left -= size;
1878         } else
1879             space = FALSE;
1880         *pcbNeeded += size;
1881     }
1882     if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1883                                   &size, unicode)) {
1884         if(space && size <= left) {
1885             pi2->pDevMode = (LPDEVMODEW)ptr;
1886             ptr += size;
1887             left -= size;
1888         } else
1889             space = FALSE;
1890         *pcbNeeded += size;
1891     }
1892     else
1893     {
1894         WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1895         if(space && size <= left) {
1896             pi2->pDevMode = (LPDEVMODEW)ptr;
1897             ptr += size;
1898             left -= size;
1899         } else
1900             space = FALSE;
1901         *pcbNeeded += size;
1902     }
1903     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1904                                  &size, unicode)) {
1905         if(space && size <= left) {
1906             pi2->pSepFile = (LPWSTR)ptr;
1907             ptr += size;
1908             left -= size;
1909         } else
1910             space = FALSE;
1911         *pcbNeeded += size;
1912     }
1913     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1914                                  &size, unicode)) {
1915         if(space && size <= left) {
1916             pi2->pPrintProcessor = (LPWSTR)ptr;
1917             ptr += size;
1918             left -= size;
1919         } else
1920             space = FALSE;
1921         *pcbNeeded += size;
1922     }
1923     if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1924                                  &size, unicode)) {
1925         if(space && size <= left) {
1926             pi2->pDatatype = (LPWSTR)ptr;
1927             ptr += size;
1928             left -= size;
1929         } else
1930             space = FALSE;
1931         *pcbNeeded += size;
1932     }
1933     if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1934                                  &size, unicode)) {
1935         if(space && size <= left) {
1936             pi2->pParameters = (LPWSTR)ptr;
1937             ptr += size;
1938             left -= size;
1939         } else
1940             space = FALSE;
1941         *pcbNeeded += size;
1942     }
1943     if(pi2) {
1944         pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1945         pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1946         pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1947                                                         "Default Priority");
1948         pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1949         pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1950     }
1951
1952     if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1953         memset(pi2, 0, sizeof(*pi2));
1954
1955     return space;
1956 }
1957
1958 /*********************************************************************
1959  *    WINSPOOL_GetPrinter_4
1960  *
1961  * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1962  */
1963 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1964                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1965                                   BOOL unicode)
1966 {
1967     DWORD size, left = cbBuf;
1968     BOOL space = (cbBuf > 0);
1969     LPBYTE ptr = buf;
1970
1971     *pcbNeeded = 0;
1972
1973     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1974                                  unicode)) {
1975         if(space && size <= left) {
1976             pi4->pPrinterName = (LPWSTR)ptr;
1977             ptr += size;
1978             left -= size;
1979         } else
1980             space = FALSE;
1981         *pcbNeeded += size;
1982     }
1983     if(pi4) {
1984         pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1985     }
1986
1987     if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1988         memset(pi4, 0, sizeof(*pi4));
1989
1990     return space;
1991 }
1992
1993 /*********************************************************************
1994  *    WINSPOOL_GetPrinter_5
1995  *
1996  * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1997  */
1998 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1999                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2000                                   BOOL unicode)
2001 {
2002     DWORD size, left = cbBuf;
2003     BOOL space = (cbBuf > 0);
2004     LPBYTE ptr = buf;
2005
2006     *pcbNeeded = 0;
2007
2008     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2009                                  unicode)) {
2010         if(space && size <= left) {
2011             pi5->pPrinterName = (LPWSTR)ptr;
2012             ptr += size;
2013             left -= size;
2014         } else
2015             space = FALSE;
2016         *pcbNeeded += size;
2017     }
2018     if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2019                                  unicode)) {
2020         if(space && size <= left) {
2021             pi5->pPortName = (LPWSTR)ptr;
2022             ptr += size;
2023             left -= size;
2024         } else
2025             space = FALSE;
2026         *pcbNeeded += size;
2027     }
2028     if(pi5) {
2029         pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2030         pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2031                                                                 "dnsTimeout");
2032         pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2033                                                                  "txTimeout");
2034     }
2035
2036     if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2037         memset(pi5, 0, sizeof(*pi5));
2038
2039     return space;
2040 }
2041
2042 /*****************************************************************************
2043  *          WINSPOOL_GetPrinter
2044  *
2045  *    Implementation of GetPrinterA|W.  Relies on PRINTER_INFO_*W being
2046  *    essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2047  *    just a collection of pointers to strings.
2048  */
2049 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2050                                 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2051 {
2052     LPCWSTR name;
2053     DWORD size, needed = 0;
2054     LPBYTE ptr = NULL;
2055     HKEY hkeyPrinter, hkeyPrinters;
2056     BOOL ret;
2057
2058     TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2059
2060     if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2061
2062     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2063        ERROR_SUCCESS) {
2064         ERR("Can't create Printers key\n");
2065         return FALSE;
2066     }
2067     if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2068     {
2069         ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2070         RegCloseKey(hkeyPrinters);
2071         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2072         return FALSE;
2073     }
2074
2075     switch(Level) {
2076     case 2:
2077       {
2078         PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2079
2080         size = sizeof(PRINTER_INFO_2W);
2081         if(size <= cbBuf) {
2082             ptr = pPrinter + size;
2083             cbBuf -= size;
2084             memset(pPrinter, 0, size);
2085         } else {
2086             pi2 = NULL;
2087             cbBuf = 0;
2088         }
2089         ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2090                                     unicode);
2091         needed += size;
2092         break;
2093       }
2094
2095     case 4:
2096       {
2097         PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2098
2099         size = sizeof(PRINTER_INFO_4W);
2100         if(size <= cbBuf) {
2101             ptr = pPrinter + size;
2102             cbBuf -= size;
2103             memset(pPrinter, 0, size);
2104         } else {
2105             pi4 = NULL;
2106             cbBuf = 0;
2107         }
2108         ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2109                                     unicode);
2110         needed += size;
2111         break;
2112       }
2113
2114
2115     case 5:
2116       {
2117         PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2118
2119         size = sizeof(PRINTER_INFO_5W);
2120         if(size <= cbBuf) {
2121             ptr = pPrinter + size;
2122             cbBuf -= size;
2123             memset(pPrinter, 0, size);
2124         } else {
2125             pi5 = NULL;
2126             cbBuf = 0;
2127         }
2128
2129         ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2130                                     unicode);
2131         needed += size;
2132         break;
2133       }
2134
2135     default:
2136         FIXME("Unimplemented level %ld\n", Level);
2137         SetLastError(ERROR_INVALID_LEVEL);
2138         RegCloseKey(hkeyPrinters);
2139         RegCloseKey(hkeyPrinter);
2140         return FALSE;
2141     }
2142
2143     RegCloseKey(hkeyPrinter);
2144     RegCloseKey(hkeyPrinters);
2145
2146     TRACE("returning %d needed = %ld\n", ret, needed);
2147     if(pcbNeeded) *pcbNeeded = needed;
2148     if(!ret)
2149         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2150     return ret;
2151 }
2152
2153 /*****************************************************************************
2154  *          GetPrinterW  [WINSPOOL.@]
2155  */
2156 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2157                         DWORD cbBuf, LPDWORD pcbNeeded)
2158 {
2159     return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2160                                TRUE);
2161 }
2162
2163 /*****************************************************************************
2164  *          GetPrinterA  [WINSPOOL.@]
2165  */
2166 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2167                     DWORD cbBuf, LPDWORD pcbNeeded)
2168 {
2169     return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2170                                FALSE);
2171 }
2172
2173 /*****************************************************************************
2174  *          WINSPOOL_EnumPrinters
2175  *
2176  *    Implementation of EnumPrintersA|W
2177  */
2178 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2179                                   DWORD dwLevel, LPBYTE lpbPrinters,
2180                                   DWORD cbBuf, LPDWORD lpdwNeeded,
2181                                   LPDWORD lpdwReturned, BOOL unicode)
2182
2183 {
2184     HKEY hkeyPrinters, hkeyPrinter;
2185     WCHAR PrinterName[255];
2186     DWORD needed = 0, number = 0;
2187     DWORD used, i, left;
2188     PBYTE pi, buf;
2189
2190     if(lpbPrinters)
2191         memset(lpbPrinters, 0, cbBuf);
2192     if(lpdwReturned)
2193         *lpdwReturned = 0;
2194     if(lpdwNeeded)
2195         *lpdwNeeded = 0;
2196
2197     /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2198     if(dwType == PRINTER_ENUM_DEFAULT)
2199         return TRUE;
2200
2201     if (dwType & PRINTER_ENUM_CONNECTIONS) {
2202         FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2203         dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2204         if(!dwType) return TRUE;
2205     }
2206
2207     if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2208         FIXME("dwType = %08lx\n", dwType);
2209         SetLastError(ERROR_INVALID_FLAGS);
2210         return FALSE;
2211     }
2212
2213     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2214        ERROR_SUCCESS) {
2215         ERR("Can't create Printers key\n");
2216         return FALSE;
2217     }
2218
2219     if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2220                         NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2221         RegCloseKey(hkeyPrinters);
2222         ERR("Can't query Printers key\n");
2223         return FALSE;
2224     }
2225     TRACE("Found %ld printers\n", number);
2226
2227     switch(dwLevel) {
2228     case 1:
2229         RegCloseKey(hkeyPrinters);
2230         if (lpdwReturned)
2231             *lpdwReturned = number;
2232         return TRUE;
2233
2234     case 2:
2235         used = number * sizeof(PRINTER_INFO_2W);
2236         break;
2237     case 4:
2238         used = number * sizeof(PRINTER_INFO_4W);
2239         break;
2240     case 5:
2241         used = number * sizeof(PRINTER_INFO_5W);
2242         break;
2243
2244     default:
2245         SetLastError(ERROR_INVALID_LEVEL);
2246         RegCloseKey(hkeyPrinters);
2247         return FALSE;
2248     }
2249     pi = (used <= cbBuf) ? lpbPrinters : NULL;
2250
2251     for(i = 0; i < number; i++) {
2252         if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2253            ERROR_SUCCESS) {
2254             ERR("Can't enum key number %ld\n", i);
2255             RegCloseKey(hkeyPrinters);
2256             return FALSE;
2257         }
2258         TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2259         if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2260            ERROR_SUCCESS) {
2261             ERR("Can't open key %s\n", debugstr_w(PrinterName));
2262             RegCloseKey(hkeyPrinters);
2263             return FALSE;
2264         }
2265
2266         if(cbBuf > used) {
2267             buf = lpbPrinters + used;
2268             left = cbBuf - used;
2269         } else {
2270             buf = NULL;
2271             left = 0;
2272         }
2273
2274         switch(dwLevel) {
2275         case 2:
2276             WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2277                                   left, &needed, unicode);
2278             used += needed;
2279             if(pi) pi += sizeof(PRINTER_INFO_2W);
2280             break;
2281         case 4:
2282             WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2283                                   left, &needed, unicode);
2284             used += needed;
2285             if(pi) pi += sizeof(PRINTER_INFO_4W);
2286             break;
2287         case 5:
2288             WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2289                                   left, &needed, unicode);
2290             used += needed;
2291             if(pi) pi += sizeof(PRINTER_INFO_5W);
2292             break;
2293         default:
2294             ERR("Shouldn't be here!\n");
2295             RegCloseKey(hkeyPrinter);
2296             RegCloseKey(hkeyPrinters);
2297             return FALSE;
2298         }
2299         RegCloseKey(hkeyPrinter);
2300     }
2301     RegCloseKey(hkeyPrinters);
2302
2303     if(lpdwNeeded)
2304         *lpdwNeeded = used;
2305
2306     if(used > cbBuf) {
2307         if(lpbPrinters)
2308             memset(lpbPrinters, 0, cbBuf);
2309         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2310         return FALSE;
2311     }
2312     if(lpdwReturned)
2313         *lpdwReturned = number;
2314     SetLastError(ERROR_SUCCESS);
2315     return TRUE;
2316 }
2317
2318
2319 /******************************************************************
2320  *              EnumPrintersW        [WINSPOOL.@]
2321  *
2322  *    Enumerates the available printers, print servers and print
2323  *    providers, depending on the specified flags, name and level.
2324  *
2325  * RETURNS:
2326  *
2327  *    If level is set to 1:
2328  *      Not implemented yet!
2329  *      Returns TRUE with an empty list.
2330  *
2331  *    If level is set to 2:
2332  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2333  *      Returns an array of PRINTER_INFO_2 data structures in the
2334  *      lpbPrinters buffer. Note that according to MSDN also an
2335  *      OpenPrinter should be performed on every remote printer.
2336  *
2337  *    If level is set to 4 (officially WinNT only):
2338  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2339  *      Fast: Only the registry is queried to retrieve printer names,
2340  *      no connection to the driver is made.
2341  *      Returns an array of PRINTER_INFO_4 data structures in the
2342  *      lpbPrinters buffer.
2343  *
2344  *    If level is set to 5 (officially WinNT4/Win9x only):
2345  *      Fast: Only the registry is queried to retrieve printer names,
2346  *      no connection to the driver is made.
2347  *      Returns an array of PRINTER_INFO_5 data structures in the
2348  *      lpbPrinters buffer.
2349  *
2350  *    If level set to 3 or 6+:
2351  *          returns zero (failure!)
2352  *
2353  *    Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2354  *    for information.
2355  *
2356  * BUGS:
2357  *    - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2358  *    - Only levels 2, 4 and 5 are implemented at the moment.
2359  *    - 16-bit printer drivers are not enumerated.
2360  *    - Returned amount of bytes used/needed does not match the real Windoze
2361  *      implementation (as in this implementation, all strings are part
2362  *      of the buffer, whereas Win32 keeps them somewhere else)
2363  *    - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2364  *
2365  * NOTE:
2366  *    - In a regular Wine installation, no registry settings for printers
2367  *      exist, which makes this function return an empty list.
2368  */
2369 BOOL  WINAPI EnumPrintersW(
2370                 DWORD dwType,        /* [in] Types of print objects to enumerate */
2371                 LPWSTR lpszName,     /* [in] name of objects to enumerate */
2372                 DWORD dwLevel,       /* [in] type of printer info structure */
2373                 LPBYTE lpbPrinters,  /* [out] buffer which receives info */
2374                 DWORD cbBuf,         /* [in] max size of buffer in bytes */
2375                 LPDWORD lpdwNeeded,  /* [out] pointer to var: # bytes used/needed */
2376                 LPDWORD lpdwReturned /* [out] number of entries returned */
2377                 )
2378 {
2379     return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2380                                  lpdwNeeded, lpdwReturned, TRUE);
2381 }
2382
2383 /******************************************************************
2384  *              EnumPrintersA        [WINSPOOL.@]
2385  *
2386  */
2387 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2388                           DWORD dwLevel, LPBYTE lpbPrinters,
2389                           DWORD cbBuf, LPDWORD lpdwNeeded,
2390                           LPDWORD lpdwReturned)
2391 {
2392     BOOL ret;
2393     UNICODE_STRING lpszNameW;
2394     PWSTR pwstrNameW;
2395     
2396     pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2397     ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2398                                 lpdwNeeded, lpdwReturned, FALSE);
2399     RtlFreeUnicodeString(&lpszNameW);
2400     return ret;
2401 }
2402
2403 /*****************************************************************************
2404  *          WINSPOOL_GetDriverInfoFromReg [internal]
2405  *
2406  *    Enters the information from the registry into the DRIVER_INFO struct
2407  *
2408  * RETURNS
2409  *    zero if the printer driver does not exist in the registry
2410  *    (only if Level > 1) otherwise nonzero
2411  */
2412 static BOOL WINSPOOL_GetDriverInfoFromReg(
2413                             HKEY    hkeyDrivers,
2414                             LPWSTR  DriverName,
2415                             LPWSTR  pEnvironment,
2416                             DWORD   Level,
2417                             LPBYTE  ptr,            /* DRIVER_INFO */
2418                             LPBYTE  pDriverStrings, /* strings buffer */
2419                             DWORD   cbBuf,          /* size of string buffer */
2420                             LPDWORD pcbNeeded,      /* space needed for str. */
2421                             BOOL    unicode)        /* type of strings */
2422 {   DWORD  dw, size, tmp, type;
2423     HKEY   hkeyDriver;
2424     LPBYTE strPtr = pDriverStrings;
2425
2426     TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2427           debugstr_w(DriverName), debugstr_w(pEnvironment),
2428           Level, ptr, pDriverStrings, cbBuf, unicode);
2429
2430     if(unicode) {
2431         *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2432             if (*pcbNeeded <= cbBuf)
2433                strcpyW((LPWSTR)strPtr, DriverName);
2434     } else {
2435         *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2436                                           NULL, NULL);
2437         if(*pcbNeeded <= cbBuf)
2438             WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2439                                 NULL, NULL);
2440     }
2441     if(Level == 1) {
2442        if(ptr)
2443           ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2444        return TRUE;
2445     } else {
2446        if(ptr)
2447           ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2448        strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2449     }
2450
2451     if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2452         ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2453         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2454         return FALSE;
2455     }
2456
2457     size = sizeof(dw);
2458     if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2459         ERROR_SUCCESS)
2460          WARN("Can't get Version\n");
2461     else if(ptr)
2462          ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2463
2464     if(!pEnvironment)
2465         pEnvironment = (LPWSTR)DefaultEnvironmentW;
2466     if(unicode)
2467         size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2468     else
2469         size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2470                                    NULL, NULL);
2471     *pcbNeeded += size;
2472     if(*pcbNeeded <= cbBuf) {
2473         if(unicode)
2474             strcpyW((LPWSTR)strPtr, pEnvironment);
2475         else
2476             WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2477                                 NULL, NULL);
2478         if(ptr)
2479             ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2480         strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2481     }
2482
2483     if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2484                                  unicode)) {
2485         *pcbNeeded += size;
2486         if(*pcbNeeded <= cbBuf)
2487             WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2488                                       unicode);
2489         if(ptr)
2490             ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2491         strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2492     }
2493
2494     if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2495                                  unicode)) {
2496         *pcbNeeded += size;
2497         if(*pcbNeeded <= cbBuf)
2498             WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2499                                       &tmp, unicode);
2500         if(ptr)
2501             ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2502         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2503     }
2504
2505     if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2506                                  0, &size, unicode)) {
2507         *pcbNeeded += size;
2508         if(*pcbNeeded <= cbBuf)
2509             WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2510                                       size, &tmp, unicode);
2511         if(ptr)
2512             ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2513         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2514     }
2515
2516     if(Level == 2 ) {
2517         RegCloseKey(hkeyDriver);
2518         TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2519         return TRUE;
2520     }
2521
2522     if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2523                                  unicode)) {
2524         *pcbNeeded += size;
2525         if(*pcbNeeded <= cbBuf)
2526             WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2527                                       size, &tmp, unicode);
2528         if(ptr)
2529             ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2530         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2531     }
2532
2533     if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2534                              &size, unicode)) {
2535         *pcbNeeded += size;
2536         if(*pcbNeeded <= cbBuf)
2537             WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2538                                       size, &tmp, unicode);
2539         if(ptr)
2540             ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2541         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2542     }
2543
2544     if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2545                                  unicode)) {
2546         *pcbNeeded += size;
2547         if(*pcbNeeded <= cbBuf)
2548             WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2549                                       size, &tmp, unicode);
2550         if(ptr)
2551             ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2552         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2553     }
2554
2555     if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2556                                  unicode)) {
2557         *pcbNeeded += size;
2558         if(*pcbNeeded <= cbBuf)
2559             WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2560                                       size, &tmp, unicode);
2561         if(ptr)
2562             ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2563         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2564     }
2565
2566     TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2567     RegCloseKey(hkeyDriver);
2568     return TRUE;
2569 }
2570
2571 /*****************************************************************************
2572  *          WINSPOOL_GetPrinterDriver
2573  */
2574 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2575                                       DWORD Level, LPBYTE pDriverInfo,
2576                                       DWORD cbBuf, LPDWORD pcbNeeded,
2577                                       BOOL unicode)
2578 {
2579     LPCWSTR name;
2580     WCHAR DriverName[100];
2581     DWORD ret, type, size, needed = 0;
2582     LPBYTE ptr = NULL;
2583     HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2584
2585     TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2586           Level,pDriverInfo,cbBuf, pcbNeeded);
2587
2588     ZeroMemory(pDriverInfo, cbBuf);
2589
2590     if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2591
2592     if(Level < 1 || Level > 3) {
2593         SetLastError(ERROR_INVALID_LEVEL);
2594         return FALSE;
2595     }
2596     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2597        ERROR_SUCCESS) {
2598         ERR("Can't create Printers key\n");
2599         return FALSE;
2600     }
2601     if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2602        != ERROR_SUCCESS) {
2603         ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2604         RegCloseKey(hkeyPrinters);
2605         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2606         return FALSE;
2607     }
2608     size = sizeof(DriverName);
2609     DriverName[0] = 0;
2610     ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2611                            (LPBYTE)DriverName, &size);
2612     RegCloseKey(hkeyPrinter);
2613     RegCloseKey(hkeyPrinters);
2614     if(ret != ERROR_SUCCESS) {
2615         ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2616         return FALSE;
2617     }
2618
2619     hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2620     if(!hkeyDrivers) {
2621         ERR("Can't create Drivers key\n");
2622         return FALSE;
2623     }
2624
2625     switch(Level) {
2626     case 1:
2627         size = sizeof(DRIVER_INFO_1W);
2628         break;
2629     case 2:
2630         size = sizeof(DRIVER_INFO_2W);
2631         break;
2632     case 3:
2633         size = sizeof(DRIVER_INFO_3W);
2634         break;
2635     default:
2636         ERR("Invalid level\n");
2637         return FALSE;
2638     }
2639
2640     if(size <= cbBuf)
2641         ptr = pDriverInfo + size;
2642
2643     if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2644                          pEnvironment, Level, pDriverInfo,
2645                          (cbBuf < size) ? NULL : ptr,
2646                          (cbBuf < size) ? 0 : cbBuf - size,
2647                          &needed, unicode)) {
2648             RegCloseKey(hkeyDrivers);
2649             return FALSE;
2650     }
2651
2652     RegCloseKey(hkeyDrivers);
2653
2654     if(pcbNeeded) *pcbNeeded = size + needed;
2655     TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2656     if(cbBuf >= needed) return TRUE;
2657     SetLastError(ERROR_INSUFFICIENT_BUFFER);
2658     return FALSE;
2659 }
2660
2661 /*****************************************************************************
2662  *          GetPrinterDriverA  [WINSPOOL.@]
2663  */
2664 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2665                               DWORD Level, LPBYTE pDriverInfo,
2666                               DWORD cbBuf, LPDWORD pcbNeeded)
2667 {
2668     BOOL ret;
2669     UNICODE_STRING pEnvW;
2670     PWSTR pwstrEnvW;
2671     
2672     pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2673     ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2674                                     cbBuf, pcbNeeded, FALSE);
2675     RtlFreeUnicodeString(&pEnvW);
2676     return ret;
2677 }
2678 /*****************************************************************************
2679  *          GetPrinterDriverW  [WINSPOOL.@]
2680  */
2681 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2682                                   DWORD Level, LPBYTE pDriverInfo,
2683                                   DWORD cbBuf, LPDWORD pcbNeeded)
2684 {
2685     return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2686                                      pDriverInfo, cbBuf, pcbNeeded, TRUE);
2687 }
2688
2689 /*****************************************************************************
2690  *       GetPrinterDriverDirectoryW  [WINSPOOL.@]
2691  */
2692 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2693                                        DWORD Level, LPBYTE pDriverDirectory,
2694                                        DWORD cbBuf, LPDWORD pcbNeeded)
2695 {
2696     DWORD needed;
2697
2698     TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName), 
2699           debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2700     if(pName != NULL) {
2701         FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2702         SetLastError(ERROR_INVALID_PARAMETER);
2703         return FALSE;
2704     }
2705     if(pEnvironment != NULL) {
2706         FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2707         SetLastError(ERROR_INVALID_ENVIRONMENT);
2708         return FALSE;
2709     }
2710     if(Level != 1)  /* win95 ignores this so we just carry on */
2711         WARN("Level = %ld - assuming 1\n", Level);
2712
2713     /* FIXME should read from registry */
2714     needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2715     /* GetSystemDirectoryW returns number of TCHAR without '\0' 
2716      * adjust this now
2717      */
2718     needed++;
2719     needed*=sizeof(WCHAR);
2720
2721     if(pcbNeeded)
2722         *pcbNeeded = needed;
2723     TRACE("required <%08lx>\n", *pcbNeeded);
2724     if(needed > cbBuf) {
2725         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2726         return FALSE;
2727     }
2728     return TRUE;
2729 }
2730
2731
2732 /*****************************************************************************
2733  *       GetPrinterDriverDirectoryA  [WINSPOOL.@]
2734  */
2735 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2736                                        DWORD Level, LPBYTE pDriverDirectory,
2737                                        DWORD cbBuf, LPDWORD pcbNeeded)
2738 {
2739     UNICODE_STRING nameW, environmentW;
2740     BOOL ret;
2741     DWORD pcbNeededW;
2742     INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2743     WCHAR *driverDirectoryW = NULL;
2744
2745     if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2746
2747     if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2748     else nameW.Buffer = NULL;
2749     if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2750     else environmentW.Buffer = NULL;
2751
2752     ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2753                                       (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2754     if (ret) {
2755         DWORD needed;
2756         needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1, 
2757                                    pDriverDirectory, cbBuf, NULL, NULL);
2758         if(pcbNeeded)
2759             *pcbNeeded = needed;
2760         ret = (needed <= cbBuf) ? TRUE : FALSE;
2761     } else 
2762         if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2763
2764     TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2765
2766     HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2767     RtlFreeUnicodeString(&environmentW);
2768     RtlFreeUnicodeString(&nameW);
2769
2770     return ret;
2771 }
2772
2773 /*****************************************************************************
2774  *          AddPrinterDriverA  [WINSPOOL.@]
2775  */
2776 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2777 {
2778     DRIVER_INFO_3A di3;
2779     HKEY hkeyDrivers, hkeyName;
2780
2781     TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2782
2783     if(level != 2 && level != 3) {
2784         SetLastError(ERROR_INVALID_LEVEL);
2785         return FALSE;
2786     }
2787     if(pName != NULL) {
2788         FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2789         SetLastError(ERROR_INVALID_PARAMETER);
2790         return FALSE;
2791     }
2792     if(!pDriverInfo) {
2793         WARN("pDriverInfo == NULL\n");
2794         SetLastError(ERROR_INVALID_PARAMETER);
2795         return FALSE;
2796     }
2797
2798     if(level == 3)
2799         di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2800     else {
2801         memset(&di3, 0, sizeof(di3));
2802         memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
2803     }
2804
2805     if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2806        !di3.pDataFile) {
2807         SetLastError(ERROR_INVALID_PARAMETER);
2808         return FALSE;
2809     }
2810     if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2811     if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2812     if(!di3.pHelpFile) di3.pHelpFile = "";
2813     if(!di3.pMonitorName) di3.pMonitorName = "";
2814
2815     hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2816
2817     if(!hkeyDrivers) {
2818         ERR("Can't create Drivers key\n");
2819         return FALSE;
2820     }
2821
2822     if(level == 2) { /* apparently can't overwrite with level2 */
2823         if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2824             RegCloseKey(hkeyName);
2825             RegCloseKey(hkeyDrivers);
2826             WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2827             SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2828             return FALSE;
2829         }
2830     }
2831     if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2832         RegCloseKey(hkeyDrivers);
2833         ERR("Can't create Name key\n");
2834         return FALSE;
2835     }
2836     RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2837                    0);
2838     RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2839     RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2840     RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2841                    sizeof(DWORD));
2842     RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2843     RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2844                    di3.pDependentFiles, 0);
2845     RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2846     RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2847     RegCloseKey(hkeyName);
2848     RegCloseKey(hkeyDrivers);
2849
2850     return TRUE;
2851 }
2852
2853 /*****************************************************************************
2854  *          AddPrinterDriverW  [WINSPOOL.@]
2855  */
2856 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2857                                    LPBYTE pDriverInfo)
2858 {
2859     FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2860           level,pDriverInfo);
2861     return FALSE;
2862 }
2863
2864 /*****************************************************************************
2865  *          AddPrintProcessorA  [WINSPOOL.@]
2866  */
2867 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
2868                                LPSTR pPrintProcessorName)
2869 {
2870     FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
2871           debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
2872     return FALSE;
2873 }
2874
2875 /*****************************************************************************
2876  *          AddPrintProcessorW  [WINSPOOL.@]
2877  */
2878 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
2879                                LPWSTR pPrintProcessorName)
2880 {
2881     FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
2882           debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
2883     return FALSE;
2884 }
2885
2886 /*****************************************************************************
2887  *          AddPrintProvidorA  [WINSPOOL.@]
2888  */
2889 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
2890 {
2891     FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
2892     return FALSE;
2893 }
2894
2895 /*****************************************************************************
2896  *          AddPrintProvidorW  [WINSPOOL.@]
2897  */
2898 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
2899 {
2900     FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
2901     return FALSE;
2902 }
2903
2904 /*****************************************************************************
2905  *          AdvancedDocumentPropertiesA  [WINSPOOL.@]
2906  */
2907 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
2908                                         PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
2909 {
2910     FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
2911           pDevModeOutput, pDevModeInput);
2912     return 0;
2913 }
2914
2915 /*****************************************************************************
2916  *          AdvancedDocumentPropertiesW  [WINSPOOL.@]
2917  */
2918 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
2919                                         PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
2920 {
2921     FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
2922           pDevModeOutput, pDevModeInput);
2923     return 0;
2924 }
2925
2926 /*****************************************************************************
2927  *          PrinterProperties  [WINSPOOL.@]
2928  *
2929  *     Displays a dialog to set the properties of the printer.
2930  *
2931  * RETURNS
2932  *     nonzero on success or zero on failure
2933  *
2934  * BUGS
2935  *         implemented as stub only
2936  */
2937 BOOL WINAPI PrinterProperties(HWND hWnd,      /* [in] handle to parent window */
2938                               HANDLE hPrinter /* [in] handle to printer object */
2939 ){
2940     FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2941     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2942     return FALSE;
2943 }
2944
2945 /*****************************************************************************
2946  *          EnumJobsA [WINSPOOL.@]
2947  *
2948  */
2949 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2950                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2951                       LPDWORD pcReturned)
2952 {
2953     FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2954         hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2955     );
2956     if(pcbNeeded) *pcbNeeded = 0;
2957     if(pcReturned) *pcReturned = 0;
2958     return FALSE;
2959 }
2960
2961
2962 /*****************************************************************************
2963  *          EnumJobsW [WINSPOOL.@]
2964  *
2965  */
2966 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2967                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2968                       LPDWORD pcReturned)
2969 {
2970     FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2971         hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2972     );
2973     if(pcbNeeded) *pcbNeeded = 0;
2974     if(pcReturned) *pcReturned = 0;
2975     return FALSE;
2976 }
2977
2978 /*****************************************************************************
2979  *          WINSPOOL_EnumPrinterDrivers [internal]
2980  *
2981  *    Delivers information about all printer drivers installed on the
2982  *    localhost or a given server
2983  *
2984  * RETURNS
2985  *    nonzero on success or zero on failure. If the buffer for the returned
2986  *    information is too small the function will return an error
2987  *
2988  * BUGS
2989  *    - only implemented for localhost, foreign hosts will return an error
2990  */
2991 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2992                                         DWORD Level, LPBYTE pDriverInfo,
2993                                         DWORD cbBuf, LPDWORD pcbNeeded,
2994                                         LPDWORD pcReturned, BOOL unicode)
2995
2996 {   HKEY  hkeyDrivers;
2997     DWORD i, needed, number = 0, size = 0;
2998     WCHAR DriverNameW[255];
2999     PBYTE ptr;
3000
3001     TRACE("%s,%s,%ld,%p,%ld,%d\n",
3002           debugstr_w(pName), debugstr_w(pEnvironment),
3003           Level, pDriverInfo, cbBuf, unicode);
3004
3005     /* check for local drivers */
3006     if(pName) {
3007         ERR("remote drivers unsupported! Current remote host is %s\n",
3008              debugstr_w(pName));
3009         return FALSE;
3010     }
3011
3012     /* check input parameter */
3013     if((Level < 1) || (Level > 3)) {
3014         ERR("unsupported level %ld\n", Level);
3015         SetLastError(ERROR_INVALID_LEVEL);
3016         return FALSE;
3017     }
3018
3019     /* initialize return values */
3020     if(pDriverInfo)
3021         memset( pDriverInfo, 0, cbBuf);
3022     *pcbNeeded  = 0;
3023     *pcReturned = 0;
3024
3025     hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3026     if(!hkeyDrivers) {
3027         ERR("Can't open Drivers key\n");
3028         return FALSE;
3029     }
3030
3031     if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3032                         NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3033         RegCloseKey(hkeyDrivers);
3034         ERR("Can't query Drivers key\n");
3035         return FALSE;
3036     }
3037     TRACE("Found %ld Drivers\n", number);
3038
3039     /* get size of single struct
3040      * unicode and ascii structure have the same size
3041      */
3042     switch (Level) {
3043         case 1:
3044             size = sizeof(DRIVER_INFO_1A);
3045             break;
3046         case 2:
3047             size = sizeof(DRIVER_INFO_2A);
3048             break;
3049         case 3:
3050             size = sizeof(DRIVER_INFO_3A);
3051             break;
3052     }
3053
3054     /* calculate required buffer size */
3055     *pcbNeeded = size * number;
3056
3057     for( i = 0,  ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3058          i < number;
3059          i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3060         if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3061                        != ERROR_SUCCESS) {
3062             ERR("Can't enum key number %ld\n", i);
3063             RegCloseKey(hkeyDrivers);
3064             return FALSE;
3065         }
3066         if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3067                          pEnvironment, Level, ptr,
3068                          (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3069                          (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3070                          &needed, unicode)) {
3071             RegCloseKey(hkeyDrivers);
3072             return FALSE;
3073         }
3074         (*pcbNeeded) += needed;
3075     }
3076
3077     RegCloseKey(hkeyDrivers);
3078
3079     if(cbBuf < *pcbNeeded){
3080         SetLastError(ERROR_INSUFFICIENT_BUFFER);
3081         return FALSE;
3082     }
3083
3084     return TRUE;
3085 }
3086
3087 /*****************************************************************************
3088  *          EnumPrinterDriversW  [WINSPOOL.@]
3089  *
3090  *    see function EnumPrinterDrivers for RETURNS, BUGS
3091  */
3092 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3093                                 LPBYTE pDriverInfo, DWORD cbBuf,
3094                                 LPDWORD pcbNeeded, LPDWORD pcReturned)
3095 {
3096     return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3097                                        cbBuf, pcbNeeded, pcReturned, TRUE);
3098 }
3099
3100 /*****************************************************************************
3101  *          EnumPrinterDriversA  [WINSPOOL.@]
3102  *
3103  *    see function EnumPrinterDrivers for RETURNS, BUGS
3104  */
3105 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3106                                 LPBYTE pDriverInfo, DWORD cbBuf,
3107                                 LPDWORD pcbNeeded, LPDWORD pcReturned)
3108 {   BOOL ret;
3109     UNICODE_STRING pNameW, pEnvironmentW;
3110     PWSTR pwstrNameW, pwstrEnvironmentW;
3111
3112     pwstrNameW = asciitounicode(&pNameW, pName);
3113     pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3114
3115     ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3116                                       Level, pDriverInfo, cbBuf, pcbNeeded,
3117                                       pcReturned, FALSE);
3118     RtlFreeUnicodeString(&pNameW);
3119     RtlFreeUnicodeString(&pEnvironmentW);
3120
3121     return ret;
3122 }
3123
3124 static CHAR PortMonitor[] = "Wine Port Monitor";
3125 static CHAR PortDescription[] = "Wine Port";
3126
3127 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3128 {
3129     HANDLE handle;
3130
3131     handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3132                          NULL, OPEN_EXISTING, 0, NULL );
3133     if (handle == INVALID_HANDLE_VALUE)
3134         return FALSE;
3135     TRACE("Checking %s exists\n", name );
3136     CloseHandle( handle );
3137     return TRUE;
3138 }
3139
3140 static DWORD WINSPOOL_CountSerialPorts()
3141 {
3142     CHAR name[6];
3143     DWORD n = 0, i;
3144
3145     for (i=0; i<4; i++)
3146     {
3147         strcpy( name, "COMx:" );
3148         name[3] = '1' + i;
3149         if (WINSPOOL_ComPortExists( name ))
3150             n++;
3151     }
3152
3153     return n;
3154 }
3155
3156 /******************************************************************************
3157  *              EnumPortsA   (WINSPOOL.@)
3158  */
3159 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3160                        LPDWORD bufneeded,LPDWORD bufreturned)
3161 {
3162     CHAR portname[10];
3163     DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3164     const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3165     HKEY hkey_printer;
3166     BOOL retval = TRUE;
3167
3168     TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3169           debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3170
3171     switch( level )
3172     {
3173     case 1:
3174         info_size = sizeof (PORT_INFO_1A);
3175         break;
3176     case 2:
3177         info_size = sizeof (PORT_INFO_2A);
3178         break;
3179     default:
3180         SetLastError(ERROR_INVALID_LEVEL);
3181         return FALSE;
3182     }
3183     
3184     /* see how many exist */
3185
3186     hkey_printer = 0;
3187     serial_count = WINSPOOL_CountSerialPorts();
3188     printer_count = 0;
3189
3190     r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3191     if ( r == ERROR_SUCCESS )
3192     {
3193         RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3194             &printer_count, NULL, NULL, NULL, NULL);
3195     }
3196     count = serial_count + printer_count;
3197
3198     /* then fill in the structure info structure once
3199        we know the offset to the first string */
3200
3201     memset( buffer, 0, bufsize );
3202     n = 0;
3203     ofs = info_size*count; 
3204     for ( i=0; i<count; i++)
3205     {
3206         DWORD vallen = sizeof(portname) - 1;
3207
3208         /* get the serial port values, then the printer values */
3209         if ( i < serial_count )
3210         {
3211             strcpy( portname, "COMx:" );
3212             portname[3] = '1' + i;
3213             if (!WINSPOOL_ComPortExists( portname ))
3214                 continue;
3215
3216             TRACE("Found %s\n", portname );
3217             vallen = strlen( portname );
3218         }
3219         else
3220         {
3221             r = RegEnumValueA( hkey_printer, i-serial_count, 
3222                      portname, &vallen, NULL, NULL, NULL, 0 );
3223             if ( r )
3224                 continue;
3225         }
3226
3227         /* add a colon if necessary, and make it upper case */
3228         CharUpperBuffA(portname,vallen);
3229         if (strcasecmp(portname,"nul")!=0)
3230             if (vallen && (portname[vallen-1] != ':') )
3231                 lstrcatA(portname,":");
3232
3233         /* add the port info structure if we can fit it */
3234         if ( info_size*(n+1) < bufsize )
3235         {
3236             if ( level == 1)
3237             {
3238                 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3239                 info->pName = (LPSTR) &buffer[ofs];
3240             }
3241             else if ( level == 2)
3242             {
3243                 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3244                 info->pPortName = (LPSTR) &buffer[ofs];
3245                 /* FIXME: fill in more stuff here */
3246                 info->pMonitorName = PortMonitor;
3247                 info->pDescription = PortDescription;
3248                 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3249             }
3250
3251             /* add the name of the port if we can fit it */
3252             if ( ofs < bufsize )
3253                 lstrcpynA(&buffer[ofs],portname,bufsize - ofs);
3254
3255             n++;
3256         }
3257         else
3258             retval = FALSE;
3259         ofs += lstrlenA(portname)+1;
3260     }
3261
3262     RegCloseKey(hkey_printer);
3263
3264     if(bufneeded)
3265         *bufneeded = ofs;
3266
3267     if(bufreturned)
3268         *bufreturned = n;
3269
3270     return retval;
3271 }
3272
3273 /******************************************************************************
3274  *      EnumPortsW   (WINSPOOL.@)
3275  */
3276 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3277                        LPDWORD bufneeded,LPDWORD bufreturned)
3278 {
3279     FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3280           debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
3281     return FALSE;
3282 }
3283
3284 /******************************************************************************
3285  *              GetDefaultPrinterW   (WINSPOOL.@)
3286  *
3287  * FIXME
3288  *      This function must read the value from data 'device' of key
3289  *      HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3290  */
3291 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3292 {
3293     BOOL  retval = TRUE;
3294     DWORD insize, len;
3295     WCHAR *buffer, *ptr;
3296
3297     if (!namesize)
3298     {
3299         SetLastError(ERROR_INVALID_PARAMETER);
3300         return FALSE;
3301     }
3302
3303     /* make the buffer big enough for the stuff from the profile/registry,
3304      * the content must fit into the local buffer to compute the correct
3305      * size even if the extern buffer is to small or not given.
3306      * (20 for ,driver,port) */
3307     insize = *namesize;
3308     len = max(100, (insize + 20));
3309     buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3310
3311     if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3312     {
3313         SetLastError (ERROR_FILE_NOT_FOUND);
3314         retval = FALSE;
3315         goto end;
3316     }
3317     TRACE("%s\n", debugstr_w(buffer));
3318
3319     if ((ptr = strchrW(buffer, ',')) == NULL)
3320     {
3321         SetLastError(ERROR_INVALID_NAME);
3322         retval = FALSE;
3323         goto end;
3324     }
3325
3326     *ptr = 0;
3327     *namesize = strlenW(buffer) + 1;
3328     if(!name || (*namesize > insize))
3329     {
3330         SetLastError(ERROR_INSUFFICIENT_BUFFER);
3331         retval = FALSE;
3332         goto end;
3333     }
3334     strcpyW(name, buffer);
3335
3336 end:
3337     HeapFree( GetProcessHeap(), 0, buffer);
3338     return retval;
3339 }
3340
3341
3342 /******************************************************************************
3343  *              GetDefaultPrinterA   (WINSPOOL.@)
3344  */
3345 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3346 {
3347     BOOL  retval = TRUE;
3348     DWORD insize = 0;
3349     WCHAR *bufferW = NULL;
3350
3351     if (!namesize)
3352     {
3353         SetLastError(ERROR_INVALID_PARAMETER);
3354         return FALSE;
3355     }
3356
3357     if(name && *namesize) {
3358         insize = *namesize;
3359         bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
3360     }
3361
3362     if(!GetDefaultPrinterW( bufferW, namesize)) {
3363         retval = FALSE;
3364         goto end;
3365     }
3366
3367     *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
3368                                     NULL, NULL);
3369     if (!*namesize)
3370     {
3371         *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
3372         retval = FALSE;
3373     }
3374     TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
3375
3376 end:
3377     HeapFree( GetProcessHeap(), 0, bufferW);
3378     return retval;
3379 }
3380
3381
3382 /******************************************************************************
3383  *              SetPrinterDataExA   (WINSPOOL.@)
3384  */
3385 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3386                                LPCSTR pValueName, DWORD Type,
3387                                LPBYTE pData, DWORD cbData)
3388 {
3389     HKEY hkeyPrinter, hkeySubkey;
3390     DWORD ret;
3391
3392     TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3393           debugstr_a(pValueName), Type, pData, cbData);
3394
3395     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3396        != ERROR_SUCCESS)
3397         return ret;
3398
3399     if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3400        != ERROR_SUCCESS) {
3401         ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3402         RegCloseKey(hkeyPrinter);
3403         return ret;
3404     }
3405     ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3406     RegCloseKey(hkeySubkey);
3407     RegCloseKey(hkeyPrinter);
3408     return ret;
3409 }
3410
3411 /******************************************************************************
3412  *              SetPrinterDataExW   (WINSPOOL.@)
3413  */
3414 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3415                                LPCWSTR pValueName, DWORD Type,
3416                                LPBYTE pData, DWORD cbData)
3417 {
3418     HKEY hkeyPrinter, hkeySubkey;
3419     DWORD ret;
3420
3421     TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3422           debugstr_w(pValueName), Type, pData, cbData);
3423
3424     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3425        != ERROR_SUCCESS)
3426         return ret;
3427
3428     if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3429        != ERROR_SUCCESS) {
3430         ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3431         RegCloseKey(hkeyPrinter);
3432         return ret;
3433     }
3434     ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3435     RegCloseKey(hkeySubkey);
3436     RegCloseKey(hkeyPrinter);
3437     return ret;
3438 }
3439
3440 /******************************************************************************
3441  *              SetPrinterDataA   (WINSPOOL.@)
3442  */
3443 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3444                                LPBYTE pData, DWORD cbData)
3445 {
3446     return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3447                              pData, cbData);
3448 }
3449
3450 /******************************************************************************
3451  *              SetPrinterDataW   (WINSPOOL.@)
3452  */
3453 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3454                              LPBYTE pData, DWORD cbData)
3455 {
3456     return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3457                              pData, cbData);
3458 }
3459
3460 /******************************************************************************
3461  *              GetPrinterDataExA   (WINSPOOL.@)
3462  */
3463 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3464                                LPCSTR pValueName, LPDWORD pType,
3465                                LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3466 {
3467     HKEY hkeyPrinter, hkeySubkey;
3468     DWORD ret;
3469
3470     TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3471           debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3472           pcbNeeded);
3473
3474     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3475        != ERROR_SUCCESS)
3476         return ret;
3477
3478     if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3479        != ERROR_SUCCESS) {
3480         WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3481         RegCloseKey(hkeyPrinter);
3482         return ret;
3483     }
3484     *pcbNeeded = nSize;
3485     ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3486     RegCloseKey(hkeySubkey);
3487     RegCloseKey(hkeyPrinter);
3488     return ret;
3489 }
3490
3491 /******************************************************************************
3492  *              GetPrinterDataExW   (WINSPOOL.@)
3493  */
3494 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3495                                LPCWSTR pValueName, LPDWORD pType,
3496                                LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3497 {
3498     HKEY hkeyPrinter, hkeySubkey;
3499     DWORD ret;
3500
3501     TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3502           debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3503           pcbNeeded);
3504
3505     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3506        != ERROR_SUCCESS)
3507         return ret;
3508
3509     if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3510        != ERROR_SUCCESS) {
3511         WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3512         RegCloseKey(hkeyPrinter);
3513         return ret;
3514     }
3515     *pcbNeeded = nSize;
3516     ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3517     RegCloseKey(hkeySubkey);
3518     RegCloseKey(hkeyPrinter);
3519     return ret;
3520 }
3521
3522 /******************************************************************************
3523  *              GetPrinterDataA   (WINSPOOL.@)
3524  */
3525 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3526                              LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3527 {
3528     return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3529                              pData, nSize, pcbNeeded);
3530 }
3531
3532 /******************************************************************************
3533  *              GetPrinterDataW   (WINSPOOL.@)
3534  */
3535 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3536                              LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3537 {
3538     return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3539                              pData, nSize, pcbNeeded);
3540 }
3541
3542 /*******************************************************************************
3543  *              EnumPrinterDataExW      [WINSPOOL.@]
3544  */
3545 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3546                                 LPBYTE pEnumValues, DWORD cbEnumValues,
3547                                 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3548 {
3549     HKEY                    hkPrinter, hkSubKey;
3550     DWORD                   r, ret, dwIndex, cValues, cbMaxValueNameLen,
3551                             cbValueNameLen, cbMaxValueLen, cbValueLen,
3552                             cbBufSize, dwType;
3553     LPWSTR                  lpValueName;
3554     HANDLE                  hHeap;
3555     PBYTE                   lpValue;
3556     PPRINTER_ENUM_VALUESW   ppev;
3557
3558     TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3559
3560     if (pKeyName == NULL || *pKeyName == 0)
3561         return ERROR_INVALID_PARAMETER;
3562
3563     ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3564     if (ret != ERROR_SUCCESS)
3565     {
3566         TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3567                 hPrinter, ret);
3568         return ret;
3569     }
3570
3571     ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3572     if (ret != ERROR_SUCCESS)
3573     {
3574         r = RegCloseKey (hkPrinter);
3575         if (r != ERROR_SUCCESS)
3576             WARN ("RegCloseKey returned %li\n", r);
3577         TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3578                 debugstr_w (pKeyName), ret);
3579         return ret;
3580     }
3581
3582     ret = RegCloseKey (hkPrinter);
3583     if (ret != ERROR_SUCCESS)
3584     {
3585         ERR ("RegCloseKey returned %li\n", ret);
3586         r = RegCloseKey (hkSubKey);
3587         if (r != ERROR_SUCCESS)
3588             WARN ("RegCloseKey returned %li\n", r);
3589         return ret;
3590     }
3591
3592     ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3593             &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3594     if (ret != ERROR_SUCCESS)
3595     {
3596         r = RegCloseKey (hkSubKey);
3597         if (r != ERROR_SUCCESS)
3598             WARN ("RegCloseKey returned %li\n", r);
3599         TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3600         return ret;
3601     }
3602
3603     TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3604             "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3605
3606     if (cValues == 0)                   /* empty key */
3607     {
3608         r = RegCloseKey (hkSubKey);
3609         if (r != ERROR_SUCCESS)
3610             WARN ("RegCloseKey returned %li\n", r);
3611         *pcbEnumValues = *pnEnumValues = 0;
3612         return ERROR_SUCCESS;
3613     }
3614
3615     ++cbMaxValueNameLen;                        /* allow for trailing '\0' */
3616
3617     hHeap = GetProcessHeap ();
3618     if (hHeap == NULL)
3619     {
3620         ERR ("GetProcessHeap failed\n");
3621         r = RegCloseKey (hkSubKey);
3622         if (r != ERROR_SUCCESS)
3623             WARN ("RegCloseKey returned %li\n", r);
3624         return ERROR_OUTOFMEMORY;
3625     }
3626
3627     lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3628     if (lpValueName == NULL)
3629     {
3630         ERR ("Failed to allocate %li bytes from process heap\n",
3631                 cbMaxValueNameLen * sizeof (WCHAR));
3632         r = RegCloseKey (hkSubKey);
3633         if (r != ERROR_SUCCESS)
3634             WARN ("RegCloseKey returned %li\n", r);
3635         return ERROR_OUTOFMEMORY;
3636     }
3637
3638     lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3639     if (lpValue == NULL)
3640     {
3641         ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3642         if (HeapFree (hHeap, 0, lpValueName) == 0)
3643             WARN ("HeapFree failed with code %li\n", GetLastError ());
3644         r = RegCloseKey (hkSubKey);
3645         if (r != ERROR_SUCCESS)
3646             WARN ("RegCloseKey returned %li\n", r);
3647         return ERROR_OUTOFMEMORY;
3648     }
3649
3650     TRACE ("pass 1: calculating buffer required for all names and values\n");
3651
3652     cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3653
3654     TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3655
3656     for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3657     {
3658         cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3659         ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3660                 NULL, NULL, lpValue, &cbValueLen);
3661         if (ret != ERROR_SUCCESS)
3662         {
3663             if (HeapFree (hHeap, 0, lpValue) == 0)
3664                 WARN ("HeapFree failed with code %li\n", GetLastError ());
3665             if (HeapFree (hHeap, 0, lpValueName) == 0)
3666                 WARN ("HeapFree failed with code %li\n", GetLastError ());
3667             r = RegCloseKey (hkSubKey);
3668             if (r != ERROR_SUCCESS)
3669                 WARN ("RegCloseKey returned %li\n", r);
3670             TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3671             return ret;
3672         }
3673
3674         TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3675                 debugstr_w (lpValueName), dwIndex,
3676                 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3677
3678         cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3679         cbBufSize += cbValueLen;
3680     }
3681
3682     TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3683
3684     *pcbEnumValues = cbBufSize;
3685     *pnEnumValues = cValues;
3686
3687     if (cbEnumValues < cbBufSize)       /* buffer too small */
3688     {
3689         if (HeapFree (hHeap, 0, lpValue) == 0)
3690             WARN ("HeapFree failed with code %li\n", GetLastError ());
3691         if (HeapFree (hHeap, 0, lpValueName) == 0)
3692             WARN ("HeapFree failed with code %li\n", GetLastError ());
3693         r = RegCloseKey (hkSubKey);
3694         if (r != ERROR_SUCCESS)
3695             WARN ("RegCloseKey returned %li\n", r);
3696         TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3697         return ERROR_MORE_DATA;
3698     }
3699
3700     TRACE ("pass 2: copying all names and values to buffer\n");
3701
3702     ppev = (PPRINTER_ENUM_VALUESW) pEnumValues;         /* array of structs */
3703     pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3704
3705     for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3706     {
3707         cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3708         ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3709                 NULL, &dwType, lpValue, &cbValueLen);
3710         if (ret != ERROR_SUCCESS)
3711         {
3712             if (HeapFree (hHeap, 0, lpValue) == 0)
3713                 WARN ("HeapFree failed with code %li\n", GetLastError ());
3714             if (HeapFree (hHeap, 0, lpValueName) == 0)
3715                 WARN ("HeapFree failed with code %li\n", GetLastError ());
3716             r = RegCloseKey (hkSubKey);
3717             if (r != ERROR_SUCCESS)
3718                 WARN ("RegCloseKey returned %li\n", r);
3719             TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3720             return ret;
3721         }
3722
3723         cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3724         memcpy (pEnumValues, lpValueName, cbValueNameLen);
3725         ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3726         pEnumValues += cbValueNameLen;
3727
3728         /* return # of *bytes* (including trailing \0), not # of chars */
3729         ppev[dwIndex].cbValueName = cbValueNameLen;
3730
3731         ppev[dwIndex].dwType = dwType;
3732
3733         memcpy (pEnumValues, lpValue, cbValueLen);
3734         ppev[dwIndex].pData = pEnumValues;
3735         pEnumValues += cbValueLen;
3736
3737         ppev[dwIndex].cbData = cbValueLen;
3738
3739         TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3740                 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3741     }
3742
3743     if (HeapFree (hHeap, 0, lpValue) == 0)
3744     {
3745         ret = GetLastError ();
3746         ERR ("HeapFree failed with code %li\n", ret);
3747         if (HeapFree (hHeap, 0, lpValueName) == 0)
3748             WARN ("HeapFree failed with code %li\n", GetLastError ());
3749         r = RegCloseKey (hkSubKey);
3750         if (r != ERROR_SUCCESS)
3751             WARN ("RegCloseKey returned %li\n", r);
3752         return ret;
3753     }
3754
3755     if (HeapFree (hHeap, 0, lpValueName) == 0)
3756     {
3757         ret = GetLastError ();
3758         ERR ("HeapFree failed with code %li\n", ret);
3759         r = RegCloseKey (hkSubKey);
3760         if (r != ERROR_SUCCESS)
3761             WARN ("RegCloseKey returned %li\n", r);
3762         return ret;
3763     }
3764
3765     ret = RegCloseKey (hkSubKey);
3766     if (ret != ERROR_SUCCESS)
3767     {
3768         ERR ("RegCloseKey returned %li\n", ret);
3769         return ret;
3770     }
3771
3772     return ERROR_SUCCESS;
3773 }
3774
3775 /*******************************************************************************
3776  *              EnumPrinterDataExA      [WINSPOOL.@]
3777  *
3778  * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3779  * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers.  This is
3780  * what Windows 2000 SP1 does.
3781  *
3782  */
3783 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3784                                 LPBYTE pEnumValues, DWORD cbEnumValues,
3785                                 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3786 {
3787     INT     len;
3788     LPWSTR  pKeyNameW;
3789     DWORD   ret, dwIndex, dwBufSize;
3790     HANDLE  hHeap;
3791     LPSTR   pBuffer;
3792
3793     TRACE ("%p %s\n", hPrinter, pKeyName);
3794
3795     if (pKeyName == NULL || *pKeyName == 0)
3796         return ERROR_INVALID_PARAMETER;
3797
3798     len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3799     if (len == 0)
3800     {
3801         ret = GetLastError ();
3802         ERR ("MultiByteToWideChar failed with code %li\n", ret);
3803         return ret;
3804     }
3805
3806     hHeap = GetProcessHeap ();
3807     if (hHeap == NULL)
3808     {
3809         ERR ("GetProcessHeap failed\n");
3810         return ERROR_OUTOFMEMORY;
3811     }
3812
3813     pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3814     if (pKeyNameW == NULL)
3815     {
3816         ERR ("Failed to allocate %li bytes from process heap\n",
3817                 (LONG) len * sizeof (WCHAR));
3818         return ERROR_OUTOFMEMORY;
3819     }
3820
3821     if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3822     {
3823         ret = GetLastError ();
3824         ERR ("MultiByteToWideChar failed with code %li\n", ret);
3825         if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3826             WARN ("HeapFree failed with code %li\n", GetLastError ());
3827         return ret;
3828     }
3829
3830     ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3831             pcbEnumValues, pnEnumValues);
3832     if (ret != ERROR_SUCCESS)
3833     {
3834         if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3835             WARN ("HeapFree failed with code %li\n", GetLastError ());
3836         TRACE ("EnumPrinterDataExW returned %li\n", ret);
3837         return ret;
3838     }
3839
3840     if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3841     {
3842         ret = GetLastError ();
3843         ERR ("HeapFree failed with code %li\n", ret);
3844         return ret;
3845     }
3846
3847     if (*pnEnumValues == 0)     /* empty key */
3848         return ERROR_SUCCESS;
3849
3850     dwBufSize = 0;
3851     for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3852     {
3853         PPRINTER_ENUM_VALUESW ppev =
3854                 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3855
3856         if (dwBufSize < ppev->cbValueName)
3857             dwBufSize = ppev->cbValueName;
3858
3859         if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3860                 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3861             dwBufSize = ppev->cbData;
3862     }
3863
3864     TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3865
3866     pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3867     if (pBuffer == NULL)
3868     {
3869         ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3870         return ERROR_OUTOFMEMORY;
3871     }
3872
3873     for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3874     {
3875         PPRINTER_ENUM_VALUESW ppev =
3876                 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3877
3878         len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3879                 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3880                 NULL);
3881         if (len == 0)
3882         {
3883             ret = GetLastError ();
3884             ERR ("WideCharToMultiByte failed with code %li\n", ret);
3885             if (HeapFree (hHeap, 0, pBuffer) == 0)
3886                 WARN ("HeapFree failed with code %li\n", GetLastError ());
3887             return ret;
3888         }
3889
3890         memcpy (ppev->pValueName, pBuffer, len);
3891
3892         TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3893
3894         if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3895                 ppev->dwType != REG_MULTI_SZ)
3896             continue;
3897
3898         len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3899                 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3900         if (len == 0)
3901         {
3902             ret = GetLastError ();
3903             ERR ("WideCharToMultiByte failed with code %li\n", ret);
3904             if (HeapFree (hHeap, 0, pBuffer) == 0)
3905                 WARN ("HeapFree failed with code %li\n", GetLastError ());
3906             return ret;
3907         }
3908
3909         memcpy (ppev->pData, pBuffer, len);
3910
3911         TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3912         TRACE ("  (only first string of REG_MULTI_SZ printed)\n");
3913     }
3914
3915     if (HeapFree (hHeap, 0, pBuffer) == 0)
3916     {
3917         ret = GetLastError ();
3918         ERR ("HeapFree failed with code %li\n", ret);
3919         return ret;
3920     }
3921
3922     return ERROR_SUCCESS;
3923 }
3924
3925 /******************************************************************************
3926  *      AbortPrinter (WINSPOOL.@)
3927  */
3928 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
3929 {
3930     FIXME("(%p), stub!\n", hPrinter);
3931     return TRUE;
3932 }
3933
3934 /******************************************************************************
3935  *              AddPortA (WINSPOOL.@)
3936  */
3937 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
3938 {
3939     FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
3940     return FALSE;
3941 }
3942
3943 /******************************************************************************
3944  *      AddPortW (WINSPOOL.@)
3945  */
3946 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
3947 {
3948     FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
3949     return FALSE;
3950 }
3951
3952 /******************************************************************************
3953  *             AddPortExA (WINSPOOL.@)
3954  *
3955  * Adds a print spooler port without presenting a user interface.
3956  */
3957 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
3958 {
3959     FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
3960           lpBuffer, debugstr_a(lpMonitorName));
3961     return FALSE;
3962 }
3963
3964 /******************************************************************************
3965  *             AddPortExW (WINSPOOL.@)
3966  *
3967  * See AddPortExW.
3968  */
3969 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
3970 {
3971     FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
3972           lpBuffer, debugstr_w(lpMonitorName));
3973     return FALSE;
3974 }
3975
3976 /******************************************************************************
3977  *      AddPrinterConnectionA (WINSPOOL.@)
3978  */
3979 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
3980 {
3981     FIXME("%s\n", debugstr_a(pName));
3982     return FALSE;
3983 }
3984
3985 /******************************************************************************
3986  *      AddPrinterConnectionW (WINSPOOL.@)
3987  */
3988 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
3989 {
3990     FIXME("%s\n", debugstr_w(pName));
3991     return FALSE;
3992 }
3993
3994 /******************************************************************************
3995  *              AddPrinterDriverExW (WINSPOOL.@)
3996  */
3997 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
3998     LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
3999 {
4000     FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4001            Level, pDriverInfo, dwFileCopyFlags);
4002     SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4003     return FALSE;
4004 }
4005
4006 /******************************************************************************
4007  *              AddPrinterDriverExA (WINSPOOL.@)
4008  */
4009 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4010     LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4011 {
4012     FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4013            Level, pDriverInfo, dwFileCopyFlags);
4014     SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4015     return FALSE;
4016 }
4017
4018 /******************************************************************************
4019  *      ConfigurePortA (WINSPOOL.@)
4020  */
4021 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4022 {
4023     FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4024     return FALSE;
4025 }
4026
4027 /******************************************************************************
4028  *      ConfigurePortW (WINSPOOL.@)
4029  */
4030 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4031 {
4032     FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4033     return FALSE;
4034 }
4035
4036 /******************************************************************************
4037  *      ConnectToPrinterDlg (WINSPOOL.@)
4038  */
4039 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4040 {
4041     FIXME("%p %lx\n", hWnd, Flags);
4042     return NULL;
4043 }
4044
4045 /******************************************************************************
4046  *      DeletePrinterConnectionA (WINSPOOL.@)
4047  */
4048 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4049 {
4050     FIXME("%s\n", debugstr_a(pName));
4051     return TRUE;
4052 }
4053
4054 /******************************************************************************
4055  *      DeletePrinterConnectionW (WINSPOOL.@)
4056  */
4057 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4058 {
4059     FIXME("%s\n", debugstr_w(pName));
4060     return TRUE;
4061 }
4062
4063 /******************************************************************************
4064  *              DeletePrinterDriverExW (WINSPOOL.@)
4065  */
4066 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4067     LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4068 {
4069     FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4070           debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4071     return TRUE;
4072 }
4073
4074 /******************************************************************************
4075  *              DeletePrinterDriverExA (WINSPOOL.@)
4076  */
4077 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4078     LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4079 {
4080     FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4081           debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4082     return TRUE;
4083 }
4084
4085 /******************************************************************************
4086  *              DeletePrinterDataExW (WINSPOOL.@)
4087  */
4088 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4089                                   LPCWSTR pValueName)
4090 {
4091     FIXME("%p %s %s\n", hPrinter, 
4092           debugstr_w(pKeyName), debugstr_w(pValueName));
4093     return ERROR_INVALID_PARAMETER;
4094 }
4095
4096 /******************************************************************************
4097  *              DeletePrinterDataExA (WINSPOOL.@)
4098  */
4099 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4100                                   LPCSTR pValueName)
4101 {
4102     FIXME("%p %s %s\n", hPrinter, 
4103           debugstr_a(pKeyName), debugstr_a(pValueName));
4104     return ERROR_INVALID_PARAMETER;
4105 }
4106
4107 /******************************************************************************
4108  *      DeletePrintProcessorA (WINSPOOL.@)
4109  */
4110 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4111 {
4112     FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4113           debugstr_a(pPrintProcessorName));
4114     return TRUE;
4115 }
4116
4117 /******************************************************************************
4118  *      DeletePrintProcessorW (WINSPOOL.@)
4119  */
4120 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4121 {
4122     FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4123           debugstr_w(pPrintProcessorName));
4124     return TRUE;
4125 }
4126
4127 /******************************************************************************
4128  *      DeletePrintProvidorA (WINSPOOL.@)
4129  */
4130 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4131 {
4132     FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4133           debugstr_a(pPrintProviderName));
4134     return TRUE;
4135 }
4136
4137 /******************************************************************************
4138  *      DeletePrintProvidorW (WINSPOOL.@)
4139  */
4140 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4141 {
4142     FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4143           debugstr_w(pPrintProviderName));
4144     return TRUE;
4145 }
4146
4147 /******************************************************************************
4148  *      EnumFormsA (WINSPOOL.@)
4149  */
4150 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4151     DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4152 {
4153     FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4154     return FALSE;
4155 }
4156
4157 /******************************************************************************
4158  *      EnumFormsW (WINSPOOL.@)
4159  */
4160 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4161     DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4162 {
4163     FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4164     return FALSE;
4165 }
4166
4167 /*****************************************************************************
4168  *          EnumMonitorsA [WINSPOOL.@]
4169  *
4170  */
4171 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4172                           DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4173 {
4174     FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4175           cbBuf, pcbNeeded, pcReturned);
4176     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4177     return 0;
4178 }
4179
4180 /*****************************************************************************
4181  *          EnumMonitorsW [WINSPOOL.@]
4182  *
4183  */
4184 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
4185                           DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4186 {
4187     FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
4188           cbBuf, pcbNeeded, pcReturned);
4189     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4190     return 0;
4191 }
4192
4193 /******************************************************************************
4194  *              XcvDataW (WINSPOOL.@)
4195  *
4196  * Notes:
4197  *  There doesn't seem to be an A version...
4198  */
4199 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
4200     DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
4201     PDWORD pcbOutputNeeded, PDWORD pdwStatus)
4202 {
4203     FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName), 
4204           pInputData, cbInputData, pOutputData,
4205           cbOutputData, pcbOutputNeeded, pdwStatus);
4206     return FALSE;
4207 }
4208
4209 /*****************************************************************************
4210  *          EnumPrinterDataA [WINSPOOL.@]
4211  *
4212  */
4213 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
4214     DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4215     DWORD cbData, LPDWORD pcbData )
4216 {
4217     FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4218           cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4219     return ERROR_NO_MORE_ITEMS;
4220 }
4221
4222 /*****************************************************************************
4223  *          EnumPrinterDataW [WINSPOOL.@]
4224  *
4225  */
4226 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
4227     DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4228     DWORD cbData, LPDWORD pcbData )
4229 {
4230     FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4231           cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4232     return ERROR_NO_MORE_ITEMS;
4233 }
4234
4235 /*****************************************************************************
4236  *          EnumPrintProcessorDatatypesA [WINSPOOL.@]
4237  *
4238  */
4239 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
4240                                          DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4241                                          LPDWORD pcbNeeded, LPDWORD pcReturned)
4242 {
4243     FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
4244           debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
4245           pcbNeeded, pcReturned);
4246     return FALSE;
4247 }
4248
4249 /*****************************************************************************
4250  *          EnumPrintProcessorDatatypesW [WINSPOOL.@]
4251  *
4252  */
4253 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
4254                                          DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4255                                          LPDWORD pcbNeeded, LPDWORD pcReturned)
4256 {
4257     FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4258           debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
4259           pcbNeeded, pcReturned);
4260     return FALSE;
4261 }
4262
4263 /*****************************************************************************
4264  *          EnumPrintProcessorsA [WINSPOOL.@]
4265  *
4266  */
4267 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level, 
4268     LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4269 {
4270     FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
4271         pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
4272     return FALSE;
4273 }
4274
4275 /*****************************************************************************
4276  *          EnumPrintProcessorsW [WINSPOOL.@]
4277  *
4278  */
4279 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4280     LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4281 {
4282     FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4283         debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
4284         cbBuf, pcbNeeded, pcbReturned);
4285     return FALSE;
4286 }
4287
4288 /*****************************************************************************
4289  *          ExtDeviceMode [WINSPOOL.@]
4290  *
4291  */
4292 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
4293     LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
4294     DWORD fMode)
4295 {
4296     FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
4297           debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
4298           debugstr_a(pProfile), fMode);
4299     return -1;
4300 }
4301
4302 /*****************************************************************************
4303  *          FindClosePrinterChangeNotification [WINSPOOL.@]
4304  *
4305  */
4306 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
4307 {
4308     FIXME("Stub: %p\n", hChange);
4309     return TRUE;
4310 }
4311
4312 /*****************************************************************************
4313  *          FindFirstPrinterChangeNotification [WINSPOOL.@]
4314  *
4315  */
4316 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
4317     DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
4318 {
4319     FIXME("Stub: %p %lx %lx %p\n",
4320           hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
4321     return INVALID_HANDLE_VALUE;
4322 }
4323
4324 /*****************************************************************************
4325  *          FindNextPrinterChangeNotification [WINSPOOL.@]
4326  *
4327  */
4328 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
4329     LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
4330 {
4331     FIXME("Stub: %p %p %p %p\n",
4332           hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
4333     return FALSE;
4334 }
4335
4336 /*****************************************************************************
4337  *          FreePrinterNotifyInfo [WINSPOOL.@]
4338  *
4339  */
4340 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
4341 {
4342     FIXME("Stub: %p\n", pPrinterNotifyInfo);
4343     return TRUE;
4344 }
4345
4346 /*****************************************************************************
4347  *          GetJobA [WINSPOOL.@]
4348  *
4349  */
4350 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4351                            DWORD cbBuf, LPDWORD pcbNeeded)
4352 {
4353     FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob,
4354           cbBuf, pcbNeeded);
4355     return FALSE;
4356 }
4357
4358 /*****************************************************************************
4359  *          GetJobW [WINSPOOL.@]
4360  *
4361  */
4362 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4363                            DWORD cbBuf, LPDWORD pcbNeeded)
4364 {
4365     FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob,
4366           cbBuf, pcbNeeded);
4367     return FALSE;
4368 }
4369
4370 /*****************************************************************************
4371  *          ScheduleJob [WINSPOOL.@]
4372  *
4373  */
4374 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
4375 {
4376     FIXME("Stub: %p %lx\n", hPrinter, dwJobID);
4377     return FALSE;
4378 }