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