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