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