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