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