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