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