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