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