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