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