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