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