dbghelp: Add basic support for PVOID64.
[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     HKEY hkeyPrinter, hkeySubkey;
5358     DWORD ret;
5359
5360     TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5361           debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5362           pcbNeeded);
5363
5364     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5365        != ERROR_SUCCESS)
5366         return ret;
5367
5368     if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5369        != ERROR_SUCCESS) {
5370         WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5371         RegCloseKey(hkeyPrinter);
5372         return ret;
5373     }
5374     *pcbNeeded = nSize;
5375     ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5376     RegCloseKey(hkeySubkey);
5377     RegCloseKey(hkeyPrinter);
5378     return ret;
5379 }
5380
5381 /******************************************************************************
5382  *              GetPrinterDataExW   (WINSPOOL.@)
5383  */
5384 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5385                                LPCWSTR pValueName, LPDWORD pType,
5386                                LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5387 {
5388     HKEY hkeyPrinter, hkeySubkey;
5389     DWORD ret;
5390
5391     TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5392           debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5393           pcbNeeded);
5394
5395     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5396        != ERROR_SUCCESS)
5397         return ret;
5398
5399     if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5400        != ERROR_SUCCESS) {
5401         WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5402         RegCloseKey(hkeyPrinter);
5403         return ret;
5404     }
5405     *pcbNeeded = nSize;
5406     ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5407     RegCloseKey(hkeySubkey);
5408     RegCloseKey(hkeyPrinter);
5409     return ret;
5410 }
5411
5412 /******************************************************************************
5413  *              GetPrinterDataA   (WINSPOOL.@)
5414  */
5415 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5416                              LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5417 {
5418     return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5419                              pData, nSize, pcbNeeded);
5420 }
5421
5422 /******************************************************************************
5423  *              GetPrinterDataW   (WINSPOOL.@)
5424  */
5425 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5426                              LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5427 {
5428     return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5429                              pData, nSize, pcbNeeded);
5430 }
5431
5432 /*******************************************************************************
5433  *              EnumPrinterDataExW      [WINSPOOL.@]
5434  */
5435 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5436                                 LPBYTE pEnumValues, DWORD cbEnumValues,
5437                                 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5438 {
5439     HKEY                    hkPrinter, hkSubKey;
5440     DWORD                   r, ret, dwIndex, cValues, cbMaxValueNameLen,
5441                             cbValueNameLen, cbMaxValueLen, cbValueLen,
5442                             cbBufSize, dwType;
5443     LPWSTR                  lpValueName;
5444     HANDLE                  hHeap;
5445     PBYTE                   lpValue;
5446     PPRINTER_ENUM_VALUESW   ppev;
5447
5448     TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5449
5450     if (pKeyName == NULL || *pKeyName == 0)
5451         return ERROR_INVALID_PARAMETER;
5452
5453     ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5454     if (ret != ERROR_SUCCESS)
5455     {
5456         TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5457                 hPrinter, ret);
5458         return ret;
5459     }
5460
5461     ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5462     if (ret != ERROR_SUCCESS)
5463     {
5464         r = RegCloseKey (hkPrinter);
5465         if (r != ERROR_SUCCESS)
5466             WARN ("RegCloseKey returned %i\n", r);
5467         TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5468                 debugstr_w (pKeyName), ret);
5469         return ret;
5470     }
5471
5472     ret = RegCloseKey (hkPrinter);
5473     if (ret != ERROR_SUCCESS)
5474     {
5475         ERR ("RegCloseKey returned %i\n", ret);
5476         r = RegCloseKey (hkSubKey);
5477         if (r != ERROR_SUCCESS)
5478             WARN ("RegCloseKey returned %i\n", r);
5479         return ret;
5480     }
5481
5482     ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5483             &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5484     if (ret != ERROR_SUCCESS)
5485     {
5486         r = RegCloseKey (hkSubKey);
5487         if (r != ERROR_SUCCESS)
5488             WARN ("RegCloseKey returned %i\n", r);
5489         TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5490         return ret;
5491     }
5492
5493     TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5494             "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5495
5496     if (cValues == 0)                   /* empty key */
5497     {
5498         r = RegCloseKey (hkSubKey);
5499         if (r != ERROR_SUCCESS)
5500             WARN ("RegCloseKey returned %i\n", r);
5501         *pcbEnumValues = *pnEnumValues = 0;
5502         return ERROR_SUCCESS;
5503     }
5504
5505     ++cbMaxValueNameLen;                        /* allow for trailing '\0' */
5506
5507     hHeap = GetProcessHeap ();
5508     if (hHeap == NULL)
5509     {
5510         ERR ("GetProcessHeap failed\n");
5511         r = RegCloseKey (hkSubKey);
5512         if (r != ERROR_SUCCESS)
5513             WARN ("RegCloseKey returned %i\n", r);
5514         return ERROR_OUTOFMEMORY;
5515     }
5516
5517     lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5518     if (lpValueName == NULL)
5519     {
5520         ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5521         r = RegCloseKey (hkSubKey);
5522         if (r != ERROR_SUCCESS)
5523             WARN ("RegCloseKey returned %i\n", r);
5524         return ERROR_OUTOFMEMORY;
5525     }
5526
5527     lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5528     if (lpValue == NULL)
5529     {
5530         ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5531         if (HeapFree (hHeap, 0, lpValueName) == 0)
5532             WARN ("HeapFree failed with code %i\n", GetLastError ());
5533         r = RegCloseKey (hkSubKey);
5534         if (r != ERROR_SUCCESS)
5535             WARN ("RegCloseKey returned %i\n", r);
5536         return ERROR_OUTOFMEMORY;
5537     }
5538
5539     TRACE ("pass 1: calculating buffer required for all names and values\n");
5540
5541     cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5542
5543     TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5544
5545     for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5546     {
5547         cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5548         ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5549                 NULL, NULL, lpValue, &cbValueLen);
5550         if (ret != ERROR_SUCCESS)
5551         {
5552             if (HeapFree (hHeap, 0, lpValue) == 0)
5553                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5554             if (HeapFree (hHeap, 0, lpValueName) == 0)
5555                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5556             r = RegCloseKey (hkSubKey);
5557             if (r != ERROR_SUCCESS)
5558                 WARN ("RegCloseKey returned %i\n", r);
5559             TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5560             return ret;
5561         }
5562
5563         TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5564                 debugstr_w (lpValueName), dwIndex,
5565                 cbValueNameLen + 1, cbValueLen);
5566
5567         cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5568         cbBufSize += cbValueLen;
5569     }
5570
5571     TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5572
5573     *pcbEnumValues = cbBufSize;
5574     *pnEnumValues = cValues;
5575
5576     if (cbEnumValues < cbBufSize)       /* buffer too small */
5577     {
5578         if (HeapFree (hHeap, 0, lpValue) == 0)
5579             WARN ("HeapFree failed with code %i\n", GetLastError ());
5580         if (HeapFree (hHeap, 0, lpValueName) == 0)
5581             WARN ("HeapFree failed with code %i\n", GetLastError ());
5582         r = RegCloseKey (hkSubKey);
5583         if (r != ERROR_SUCCESS)
5584             WARN ("RegCloseKey returned %i\n", r);
5585         TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5586         return ERROR_MORE_DATA;
5587     }
5588
5589     TRACE ("pass 2: copying all names and values to buffer\n");
5590
5591     ppev = (PPRINTER_ENUM_VALUESW) pEnumValues;         /* array of structs */
5592     pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5593
5594     for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5595     {
5596         cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5597         ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5598                 NULL, &dwType, lpValue, &cbValueLen);
5599         if (ret != ERROR_SUCCESS)
5600         {
5601             if (HeapFree (hHeap, 0, lpValue) == 0)
5602                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5603             if (HeapFree (hHeap, 0, lpValueName) == 0)
5604                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5605             r = RegCloseKey (hkSubKey);
5606             if (r != ERROR_SUCCESS)
5607                 WARN ("RegCloseKey returned %i\n", r);
5608             TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5609             return ret;
5610         }
5611
5612         cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5613         memcpy (pEnumValues, lpValueName, cbValueNameLen);
5614         ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5615         pEnumValues += cbValueNameLen;
5616
5617         /* return # of *bytes* (including trailing \0), not # of chars */
5618         ppev[dwIndex].cbValueName = cbValueNameLen;
5619
5620         ppev[dwIndex].dwType = dwType;
5621
5622         memcpy (pEnumValues, lpValue, cbValueLen);
5623         ppev[dwIndex].pData = pEnumValues;
5624         pEnumValues += cbValueLen;
5625
5626         ppev[dwIndex].cbData = cbValueLen;
5627
5628         TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5629                 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5630     }
5631
5632     if (HeapFree (hHeap, 0, lpValue) == 0)
5633     {
5634         ret = GetLastError ();
5635         ERR ("HeapFree failed with code %i\n", ret);
5636         if (HeapFree (hHeap, 0, lpValueName) == 0)
5637             WARN ("HeapFree failed with code %i\n", GetLastError ());
5638         r = RegCloseKey (hkSubKey);
5639         if (r != ERROR_SUCCESS)
5640             WARN ("RegCloseKey returned %i\n", r);
5641         return ret;
5642     }
5643
5644     if (HeapFree (hHeap, 0, lpValueName) == 0)
5645     {
5646         ret = GetLastError ();
5647         ERR ("HeapFree failed with code %i\n", ret);
5648         r = RegCloseKey (hkSubKey);
5649         if (r != ERROR_SUCCESS)
5650             WARN ("RegCloseKey returned %i\n", r);
5651         return ret;
5652     }
5653
5654     ret = RegCloseKey (hkSubKey);
5655     if (ret != ERROR_SUCCESS)
5656     {
5657         ERR ("RegCloseKey returned %i\n", ret);
5658         return ret;
5659     }
5660
5661     return ERROR_SUCCESS;
5662 }
5663
5664 /*******************************************************************************
5665  *              EnumPrinterDataExA      [WINSPOOL.@]
5666  *
5667  * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5668  * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers.  This is
5669  * what Windows 2000 SP1 does.
5670  *
5671  */
5672 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5673                                 LPBYTE pEnumValues, DWORD cbEnumValues,
5674                                 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5675 {
5676     INT     len;
5677     LPWSTR  pKeyNameW;
5678     DWORD   ret, dwIndex, dwBufSize;
5679     HANDLE  hHeap;
5680     LPSTR   pBuffer;
5681
5682     TRACE ("%p %s\n", hPrinter, pKeyName);
5683
5684     if (pKeyName == NULL || *pKeyName == 0)
5685         return ERROR_INVALID_PARAMETER;
5686
5687     len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5688     if (len == 0)
5689     {
5690         ret = GetLastError ();
5691         ERR ("MultiByteToWideChar failed with code %i\n", ret);
5692         return ret;
5693     }
5694
5695     hHeap = GetProcessHeap ();
5696     if (hHeap == NULL)
5697     {
5698         ERR ("GetProcessHeap failed\n");
5699         return ERROR_OUTOFMEMORY;
5700     }
5701
5702     pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5703     if (pKeyNameW == NULL)
5704     {
5705         ERR ("Failed to allocate %i bytes from process heap\n",
5706              (LONG)(len * sizeof (WCHAR)));
5707         return ERROR_OUTOFMEMORY;
5708     }
5709
5710     if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5711     {
5712         ret = GetLastError ();
5713         ERR ("MultiByteToWideChar failed with code %i\n", ret);
5714         if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5715             WARN ("HeapFree failed with code %i\n", GetLastError ());
5716         return ret;
5717     }
5718
5719     ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5720             pcbEnumValues, pnEnumValues);
5721     if (ret != ERROR_SUCCESS)
5722     {
5723         if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5724             WARN ("HeapFree failed with code %i\n", GetLastError ());
5725         TRACE ("EnumPrinterDataExW returned %i\n", ret);
5726         return ret;
5727     }
5728
5729     if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5730     {
5731         ret = GetLastError ();
5732         ERR ("HeapFree failed with code %i\n", ret);
5733         return ret;
5734     }
5735
5736     if (*pnEnumValues == 0)     /* empty key */
5737         return ERROR_SUCCESS;
5738
5739     dwBufSize = 0;
5740     for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5741     {
5742         PPRINTER_ENUM_VALUESW ppev =
5743                 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5744
5745         if (dwBufSize < ppev->cbValueName)
5746             dwBufSize = ppev->cbValueName;
5747
5748         if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5749                 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5750             dwBufSize = ppev->cbData;
5751     }
5752
5753     TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5754
5755     pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5756     if (pBuffer == NULL)
5757     {
5758         ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5759         return ERROR_OUTOFMEMORY;
5760     }
5761
5762     for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5763     {
5764         PPRINTER_ENUM_VALUESW ppev =
5765                 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5766
5767         len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5768                 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5769                 NULL);
5770         if (len == 0)
5771         {
5772             ret = GetLastError ();
5773             ERR ("WideCharToMultiByte failed with code %i\n", ret);
5774             if (HeapFree (hHeap, 0, pBuffer) == 0)
5775                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5776             return ret;
5777         }
5778
5779         memcpy (ppev->pValueName, pBuffer, len);
5780
5781         TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5782
5783         if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5784                 ppev->dwType != REG_MULTI_SZ)
5785             continue;
5786
5787         len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5788                 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5789         if (len == 0)
5790         {
5791             ret = GetLastError ();
5792             ERR ("WideCharToMultiByte failed with code %i\n", ret);
5793             if (HeapFree (hHeap, 0, pBuffer) == 0)
5794                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5795             return ret;
5796         }
5797
5798         memcpy (ppev->pData, pBuffer, len);
5799
5800         TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5801         TRACE ("  (only first string of REG_MULTI_SZ printed)\n");
5802     }
5803
5804     if (HeapFree (hHeap, 0, pBuffer) == 0)
5805     {
5806         ret = GetLastError ();
5807         ERR ("HeapFree failed with code %i\n", ret);
5808         return ret;
5809     }
5810
5811     return ERROR_SUCCESS;
5812 }
5813
5814 /******************************************************************************
5815  *      AbortPrinter (WINSPOOL.@)
5816  */
5817 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5818 {
5819     FIXME("(%p), stub!\n", hPrinter);
5820     return TRUE;
5821 }
5822
5823 /******************************************************************************
5824  *              AddPortA (WINSPOOL.@)
5825  *
5826  * See AddPortW.
5827  *
5828  */
5829 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5830 {
5831     LPWSTR  nameW = NULL;
5832     LPWSTR  monitorW = NULL;
5833     DWORD   len;
5834     BOOL    res;
5835
5836     TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5837
5838     if (pName) {
5839         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5840         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5841         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5842     }
5843
5844     if (pMonitorName) {
5845         len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5846         monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5847         MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5848     }
5849     res = AddPortW(nameW, hWnd, monitorW);
5850     HeapFree(GetProcessHeap(), 0, nameW);
5851     HeapFree(GetProcessHeap(), 0, monitorW);
5852     return res;
5853 }
5854
5855 /******************************************************************************
5856  *      AddPortW (WINSPOOL.@)
5857  *
5858  * Add a Port for a specific Monitor
5859  *
5860  * PARAMS
5861  *  pName        [I] Servername or NULL (local Computer)
5862  *  hWnd         [I] Handle to parent Window for the Dialog-Box
5863  *  pMonitorName [I] Name of the Monitor that manage the Port
5864  *
5865  * RETURNS
5866  *  Success: TRUE
5867  *  Failure: FALSE
5868  *
5869  */
5870 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5871 {
5872     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5873
5874     if ((backend == NULL)  && !load_backend()) return FALSE;
5875
5876     if (!pMonitorName) {
5877         SetLastError(RPC_X_NULL_REF_POINTER);
5878         return FALSE;
5879     }
5880
5881     return backend->fpAddPort(pName, hWnd, pMonitorName);
5882 }
5883
5884 /******************************************************************************
5885  *             AddPortExA (WINSPOOL.@)
5886  *
5887  * See AddPortExW.
5888  *
5889  */
5890 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5891 {
5892     PORT_INFO_2W   pi2W;
5893     PORT_INFO_2A * pi2A;
5894     LPWSTR  nameW = NULL;
5895     LPWSTR  monitorW = NULL;
5896     DWORD   len;
5897     BOOL    res;
5898
5899     pi2A = (PORT_INFO_2A *) pBuffer;
5900
5901     TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5902             debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5903
5904     if ((level < 1) || (level > 2)) {
5905         SetLastError(ERROR_INVALID_LEVEL);
5906         return FALSE;
5907     }
5908
5909     if (!pi2A) {
5910         SetLastError(ERROR_INVALID_PARAMETER);
5911         return FALSE;
5912     }
5913
5914     if (pName) {
5915         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5916         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5917         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5918     }
5919
5920     if (pMonitorName) {
5921         len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5922         monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5923         MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5924     }
5925
5926     ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5927
5928     if (pi2A->pPortName) {
5929         len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5930         pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5931         MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
5932     }
5933
5934     if (level > 1) {
5935         if (pi2A->pMonitorName) {
5936             len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
5937             pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5938             MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
5939         }
5940
5941         if (pi2A->pDescription) {
5942             len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
5943             pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5944             MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
5945         }
5946         pi2W.fPortType = pi2A->fPortType;
5947         pi2W.Reserved = pi2A->Reserved;
5948     }
5949
5950     res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
5951
5952     HeapFree(GetProcessHeap(), 0, nameW);
5953     HeapFree(GetProcessHeap(), 0, monitorW);
5954     HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
5955     HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
5956     HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
5957     return res;
5958
5959 }
5960
5961 /******************************************************************************
5962  *             AddPortExW (WINSPOOL.@)
5963  *
5964  * Add a Port for a specific Monitor, without presenting a user interface
5965  *
5966  * PARAMS
5967  *  pName         [I] Servername or NULL (local Computer)
5968  *  level         [I] Structure-Level (1 or 2) for pBuffer
5969  *  pBuffer       [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5970  *  pMonitorName  [I] Name of the Monitor that manage the Port
5971  *
5972  * RETURNS
5973  *  Success: TRUE
5974  *  Failure: FALSE
5975  *
5976  */
5977 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
5978 {
5979     PORT_INFO_2W * pi2;
5980
5981     pi2 = (PORT_INFO_2W *) pBuffer;
5982
5983     TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
5984             debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
5985             debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
5986             debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
5987
5988     if ((backend == NULL)  && !load_backend()) return FALSE;
5989
5990     if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
5991         SetLastError(ERROR_INVALID_PARAMETER);
5992         return FALSE;
5993     }
5994
5995     return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
5996 }
5997
5998 /******************************************************************************
5999  *      AddPrinterConnectionA (WINSPOOL.@)
6000  */
6001 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6002 {
6003     FIXME("%s\n", debugstr_a(pName));
6004     return FALSE;
6005 }
6006
6007 /******************************************************************************
6008  *      AddPrinterConnectionW (WINSPOOL.@)
6009  */
6010 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6011 {
6012     FIXME("%s\n", debugstr_w(pName));
6013     return FALSE;
6014 }
6015
6016 /******************************************************************************
6017  *  AddPrinterDriverExW (WINSPOOL.@)
6018  *
6019  * Install a Printer Driver with the Option to upgrade / downgrade the Files
6020  *
6021  * PARAMS
6022  *  pName           [I] Servername or NULL (local Computer)
6023  *  level           [I] Level for the supplied DRIVER_INFO_*W struct
6024  *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6025  *  dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6026  *
6027  * RESULTS
6028  *  Success: TRUE
6029  *  Failure: FALSE
6030  *
6031  */
6032 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6033 {
6034     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6035
6036     if ((backend == NULL)  && !load_backend()) return FALSE;
6037
6038     if (level < 2 || level == 5 || level == 7 || level > 8) {
6039         SetLastError(ERROR_INVALID_LEVEL);
6040         return FALSE;
6041     }
6042
6043     if (!pDriverInfo) {
6044         SetLastError(ERROR_INVALID_PARAMETER);
6045         return FALSE;
6046     }
6047
6048     return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6049 }
6050
6051 /******************************************************************************
6052  *  AddPrinterDriverExA (WINSPOOL.@)
6053  *
6054  * See AddPrinterDriverExW.
6055  *
6056  */
6057 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6058 {
6059     DRIVER_INFO_8A  *diA;
6060     DRIVER_INFO_8W   diW;
6061     LPWSTR  nameW = NULL;
6062     DWORD   lenA;
6063     DWORD   len;
6064     DWORD   res = FALSE;
6065
6066     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6067
6068     diA = (DRIVER_INFO_8A  *) pDriverInfo;
6069     ZeroMemory(&diW, sizeof(diW));
6070
6071     if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6072         SetLastError(ERROR_INVALID_LEVEL);
6073         return FALSE;
6074     }
6075
6076     if (diA == NULL) {
6077         SetLastError(ERROR_INVALID_PARAMETER);
6078         return FALSE;
6079     }
6080
6081     /* convert servername to unicode */
6082     if (pName) {
6083         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6084         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6085         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6086     }
6087
6088     /* common fields */
6089     diW.cVersion = diA->cVersion;
6090
6091     if (diA->pName) {
6092         len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6093         diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6094         MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6095     }
6096
6097     if (diA->pEnvironment) {
6098         len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6099         diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6100         MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6101     }
6102
6103     if (diA->pDriverPath) {
6104         len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6105         diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6106         MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6107     }
6108
6109     if (diA->pDataFile) {
6110         len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6111         diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6112         MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6113     }
6114
6115     if (diA->pConfigFile) {
6116         len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6117         diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6118         MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6119     }
6120
6121     if ((Level > 2) && diA->pDependentFiles) {
6122         lenA = multi_sz_lenA(diA->pDependentFiles);
6123         len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6124         diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6125         MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6126     }
6127
6128     if ((Level > 2) && diA->pMonitorName) {
6129         len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6130         diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6131         MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6132     }
6133
6134     if ((Level > 3) && diA->pDefaultDataType) {
6135         len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6136         diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6137         MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6138     }
6139
6140     if ((Level > 3) && diA->pszzPreviousNames) {
6141         lenA = multi_sz_lenA(diA->pszzPreviousNames);
6142         len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6143         diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6144         MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6145     }
6146
6147     if ((Level > 5) && diA->pszMfgName) {
6148         len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6149         diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6150         MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6151     }
6152
6153     if ((Level > 5) && diA->pszOEMUrl) {
6154         len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6155         diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6156         MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6157     }
6158
6159     if ((Level > 5) && diA->pszHardwareID) {
6160         len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6161         diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6162         MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6163     }
6164
6165     if ((Level > 5) && diA->pszProvider) {
6166         len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6167         diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6168         MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6169     }
6170
6171     if (Level > 7) {
6172         FIXME("level %u is incomplete\n", Level);
6173     }
6174
6175     res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6176     TRACE("got %u with %u\n", res, GetLastError());
6177     HeapFree(GetProcessHeap(), 0, nameW);
6178     HeapFree(GetProcessHeap(), 0, diW.pName);
6179     HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6180     HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6181     HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6182     HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6183     HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6184     HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6185     HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6186     HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6187     HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6188     HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6189     HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6190     HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6191
6192     TRACE("=> %u with %u\n", res, GetLastError());
6193     return res;
6194 }
6195
6196 /******************************************************************************
6197  *      ConfigurePortA (WINSPOOL.@)
6198  *
6199  * See ConfigurePortW.
6200  *
6201  */
6202 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6203 {
6204     LPWSTR  nameW = NULL;
6205     LPWSTR  portW = NULL;
6206     INT     len;
6207     DWORD   res;
6208
6209     TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6210
6211     /* convert servername to unicode */
6212     if (pName) {
6213         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6214         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6215         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6216     }
6217
6218     /* convert portname to unicode */
6219     if (pPortName) {
6220         len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6221         portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6222         MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6223     }
6224
6225     res = ConfigurePortW(nameW, hWnd, portW);
6226     HeapFree(GetProcessHeap(), 0, nameW);
6227     HeapFree(GetProcessHeap(), 0, portW);
6228     return res;
6229 }
6230
6231 /******************************************************************************
6232  *      ConfigurePortW (WINSPOOL.@)
6233  *
6234  * Display the Configuration-Dialog for a specific Port
6235  *
6236  * PARAMS
6237  *  pName     [I] Servername or NULL (local Computer)
6238  *  hWnd      [I] Handle to parent Window for the Dialog-Box
6239  *  pPortName [I] Name of the Port, that should be configured
6240  *
6241  * RETURNS
6242  *  Success: TRUE
6243  *  Failure: FALSE
6244  *
6245  */
6246 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6247 {
6248
6249     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6250
6251     if ((backend == NULL)  && !load_backend()) return FALSE;
6252
6253     if (!pPortName) {
6254         SetLastError(RPC_X_NULL_REF_POINTER);
6255         return FALSE;
6256     }
6257
6258     return backend->fpConfigurePort(pName, hWnd, pPortName);
6259 }
6260
6261 /******************************************************************************
6262  *      ConnectToPrinterDlg (WINSPOOL.@)
6263  */
6264 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6265 {
6266     FIXME("%p %x\n", hWnd, Flags);
6267     return NULL;
6268 }
6269
6270 /******************************************************************************
6271  *      DeletePrinterConnectionA (WINSPOOL.@)
6272  */
6273 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6274 {
6275     FIXME("%s\n", debugstr_a(pName));
6276     return TRUE;
6277 }
6278
6279 /******************************************************************************
6280  *      DeletePrinterConnectionW (WINSPOOL.@)
6281  */
6282 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6283 {
6284     FIXME("%s\n", debugstr_w(pName));
6285     return TRUE;
6286 }
6287
6288 /******************************************************************************
6289  *              DeletePrinterDriverExW (WINSPOOL.@)
6290  */
6291 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6292     LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6293 {
6294     HKEY hkey_drivers;
6295     BOOL ret = FALSE;
6296
6297     TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6298           debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6299
6300     if(pName && pName[0])
6301     {
6302         FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6303         SetLastError(ERROR_INVALID_PARAMETER);
6304         return FALSE;
6305     }
6306
6307     if(dwDeleteFlag)
6308     {
6309         FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6310         SetLastError(ERROR_INVALID_PARAMETER);
6311         return FALSE;
6312     }
6313
6314     hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6315
6316     if(!hkey_drivers)
6317     {
6318         ERR("Can't open drivers key\n");
6319         return FALSE;
6320     }
6321
6322     if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6323         ret = TRUE;
6324
6325     RegCloseKey(hkey_drivers);
6326
6327     return ret;
6328 }
6329
6330 /******************************************************************************
6331  *              DeletePrinterDriverExA (WINSPOOL.@)
6332  */
6333 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6334     LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6335 {
6336     UNICODE_STRING NameW, EnvW, DriverW;
6337     BOOL ret;
6338
6339     asciitounicode(&NameW, pName);
6340     asciitounicode(&EnvW, pEnvironment);
6341     asciitounicode(&DriverW, pDriverName);
6342
6343     ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6344
6345     RtlFreeUnicodeString(&DriverW);
6346     RtlFreeUnicodeString(&EnvW);
6347     RtlFreeUnicodeString(&NameW);
6348
6349     return ret;
6350 }
6351
6352 /******************************************************************************
6353  *              DeletePrinterDataExW (WINSPOOL.@)
6354  */
6355 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6356                                   LPCWSTR pValueName)
6357 {
6358     FIXME("%p %s %s\n", hPrinter, 
6359           debugstr_w(pKeyName), debugstr_w(pValueName));
6360     return ERROR_INVALID_PARAMETER;
6361 }
6362
6363 /******************************************************************************
6364  *              DeletePrinterDataExA (WINSPOOL.@)
6365  */
6366 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6367                                   LPCSTR pValueName)
6368 {
6369     FIXME("%p %s %s\n", hPrinter, 
6370           debugstr_a(pKeyName), debugstr_a(pValueName));
6371     return ERROR_INVALID_PARAMETER;
6372 }
6373
6374 /******************************************************************************
6375  *      DeletePrintProcessorA (WINSPOOL.@)
6376  */
6377 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6378 {
6379     FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6380           debugstr_a(pPrintProcessorName));
6381     return TRUE;
6382 }
6383
6384 /******************************************************************************
6385  *      DeletePrintProcessorW (WINSPOOL.@)
6386  */
6387 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6388 {
6389     FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6390           debugstr_w(pPrintProcessorName));
6391     return TRUE;
6392 }
6393
6394 /******************************************************************************
6395  *      DeletePrintProvidorA (WINSPOOL.@)
6396  */
6397 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6398 {
6399     FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6400           debugstr_a(pPrintProviderName));
6401     return TRUE;
6402 }
6403
6404 /******************************************************************************
6405  *      DeletePrintProvidorW (WINSPOOL.@)
6406  */
6407 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6408 {
6409     FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6410           debugstr_w(pPrintProviderName));
6411     return TRUE;
6412 }
6413
6414 /******************************************************************************
6415  *      EnumFormsA (WINSPOOL.@)
6416  */
6417 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6418     DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6419 {
6420     FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6421     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6422     return FALSE;
6423 }
6424
6425 /******************************************************************************
6426  *      EnumFormsW (WINSPOOL.@)
6427  */
6428 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6429     DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6430 {
6431     FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6432     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6433     return FALSE;
6434 }
6435
6436 /*****************************************************************************
6437  *          EnumMonitorsA [WINSPOOL.@]
6438  *
6439  * See EnumMonitorsW.
6440  *
6441  */
6442 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6443                           DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6444 {
6445     BOOL    res;
6446     LPBYTE  bufferW = NULL;
6447     LPWSTR  nameW = NULL;
6448     DWORD   needed = 0;
6449     DWORD   numentries = 0;
6450     INT     len;
6451
6452     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6453           cbBuf, pcbNeeded, pcReturned);
6454
6455     /* convert servername to unicode */
6456     if (pName) {
6457         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6458         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6459         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6460     }
6461     /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6462     needed = cbBuf * sizeof(WCHAR);    
6463     if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6464     res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6465
6466     if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6467         if (pcbNeeded) needed = *pcbNeeded;
6468         /* HeapReAlloc return NULL, when bufferW was NULL */
6469         bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6470                               HeapAlloc(GetProcessHeap(), 0, needed);
6471
6472         /* Try again with the large Buffer */
6473         res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6474     }
6475     numentries = pcReturned ? *pcReturned : 0;
6476     needed = 0;
6477     /*
6478        W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6479        We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6480      */
6481     if (res) {
6482         /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6483         DWORD   entrysize = 0;
6484         DWORD   index;
6485         LPSTR   ptr;
6486         LPMONITOR_INFO_2W mi2w;
6487         LPMONITOR_INFO_2A mi2a;
6488
6489         /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6490         entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6491
6492         /* First pass: calculate the size for all Entries */
6493         mi2w = (LPMONITOR_INFO_2W) bufferW;
6494         mi2a = (LPMONITOR_INFO_2A) pMonitors;
6495         index = 0;
6496         while (index < numentries) {
6497             index++;
6498             needed += entrysize;    /* MONITOR_INFO_?A */
6499             TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6500
6501             needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6502                                             NULL, 0, NULL, NULL);
6503             if (Level > 1) {
6504                 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6505                                                 NULL, 0, NULL, NULL);
6506                 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6507                                                 NULL, 0, NULL, NULL);
6508             }
6509             /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6510             mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6511             mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6512         }
6513
6514         /* check for errors and quit on failure */
6515         if (cbBuf < needed) {
6516             SetLastError(ERROR_INSUFFICIENT_BUFFER);
6517             res = FALSE;
6518             goto emA_cleanup;
6519         }
6520         len = entrysize * numentries;       /* room for all MONITOR_INFO_?A */
6521         ptr = (LPSTR) &pMonitors[len];      /* room for strings */
6522         cbBuf -= len ;                      /* free Bytes in the user-Buffer */
6523         mi2w = (LPMONITOR_INFO_2W) bufferW;
6524         mi2a = (LPMONITOR_INFO_2A) pMonitors;
6525         index = 0;
6526         /* Second Pass: Fill the User Buffer (if we have one) */
6527         while ((index < numentries) && pMonitors) {
6528             index++;
6529             TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6530             mi2a->pName = ptr;
6531             len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6532                                             ptr, cbBuf , NULL, NULL);
6533             ptr += len;
6534             cbBuf -= len;
6535             if (Level > 1) {
6536                 mi2a->pEnvironment = ptr;
6537                 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6538                                             ptr, cbBuf, NULL, NULL);
6539                 ptr += len;
6540                 cbBuf -= len;
6541
6542                 mi2a->pDLLName = ptr;
6543                 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6544                                             ptr, cbBuf, NULL, NULL);
6545                 ptr += len;
6546                 cbBuf -= len;
6547             }
6548             /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6549             mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6550             mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6551         }
6552     }
6553 emA_cleanup:
6554     if (pcbNeeded)  *pcbNeeded = needed;
6555     if (pcReturned) *pcReturned = (res) ? numentries : 0;
6556
6557     HeapFree(GetProcessHeap(), 0, nameW);
6558     HeapFree(GetProcessHeap(), 0, bufferW);
6559
6560     TRACE("returning %d with %d (%d byte for %d entries)\n", 
6561             (res), GetLastError(), needed, numentries);
6562
6563     return (res);
6564
6565 }
6566
6567 /*****************************************************************************
6568  *          EnumMonitorsW [WINSPOOL.@]
6569  *
6570  * Enumerate available Port-Monitors
6571  *
6572  * PARAMS
6573  *  pName       [I] Servername or NULL (local Computer)
6574  *  Level       [I] Structure-Level (1:Win9x+NT or 2:NT only)
6575  *  pMonitors   [O] PTR to Buffer that receives the Result
6576  *  cbBuf       [I] Size of Buffer at pMonitors
6577  *  pcbNeeded   [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6578  *  pcReturned  [O] PTR to DWORD that receives the number of Monitors in pMonitors
6579  *
6580  * RETURNS
6581  *  Success: TRUE
6582  *  Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6583  *
6584  */
6585 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6586                           DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6587 {
6588
6589     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6590           cbBuf, pcbNeeded, pcReturned);
6591
6592     if ((backend == NULL)  && !load_backend()) return FALSE;
6593
6594     if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6595         SetLastError(RPC_X_NULL_REF_POINTER);
6596         return FALSE;
6597     }
6598
6599     return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6600 }
6601
6602 /******************************************************************************
6603  * SpoolerInit (WINSPOOL.@)
6604  *
6605  * Initialize the Spooler
6606  *
6607  * RETURNS
6608  *  Success: TRUE
6609  *  Failure: FALSE
6610  *
6611  * NOTES
6612  *  The function fails on windows, when the spooler service is not running
6613  *
6614  */
6615 BOOL WINAPI SpoolerInit(void)
6616 {
6617
6618     if ((backend == NULL)  && !load_backend()) return FALSE;
6619     return TRUE;
6620 }
6621
6622 /******************************************************************************
6623  *              XcvDataW (WINSPOOL.@)
6624  *
6625  * Execute commands in the Printmonitor DLL
6626  *
6627  * PARAMS
6628  *  hXcv            [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6629  *  pszDataName     [i] Name of the command to execute
6630  *  pInputData      [i] Buffer for extra Input Data (needed only for some commands)
6631  *  cbInputData     [i] Size in Bytes of Buffer at pInputData
6632  *  pOutputData     [o] Buffer to receive additional Data (needed only for some commands)
6633  *  cbOutputData    [i] Size in Bytes of Buffer at pOutputData
6634  *  pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6635  *  pdwStatus       [o] PTR to receive the win32 error code from the Printmonitor DLL
6636  *
6637  * RETURNS
6638  *  Success: TRUE
6639  *  Failure: FALSE
6640  *
6641  * NOTES
6642  *  Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6643  *  The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6644  *
6645  *  Minimal List of commands, that a Printmonitor DLL should support:
6646  *
6647  *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6648  *| "AddPort"   : Add a Port
6649  *| "DeletePort": Delete a Port
6650  *
6651  *  Many Printmonitors support additional commands. Examples for localspl.dll:
6652  *  "GetDefaultCommConfig", "SetDefaultCommConfig",
6653  *  "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6654  *
6655  */
6656 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6657     DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6658     PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6659 {
6660     opened_printer_t *printer;
6661
6662     TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6663           pInputData, cbInputData, pOutputData,
6664           cbOutputData, pcbOutputNeeded, pdwStatus);
6665
6666     if ((backend == NULL)  && !load_backend()) return FALSE;
6667
6668     printer = get_opened_printer(hXcv);
6669     if (!printer || (!printer->backend_printer)) {
6670         SetLastError(ERROR_INVALID_HANDLE);
6671         return FALSE;
6672     }
6673
6674     if (!pcbOutputNeeded) {
6675         SetLastError(ERROR_INVALID_PARAMETER);
6676         return FALSE;
6677     }
6678
6679     if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6680         SetLastError(RPC_X_NULL_REF_POINTER);
6681         return FALSE;
6682     }
6683
6684     *pcbOutputNeeded = 0;
6685
6686     return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6687                     cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6688
6689 }
6690
6691 /*****************************************************************************
6692  *          EnumPrinterDataA [WINSPOOL.@]
6693  *
6694  */
6695 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6696     DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6697     DWORD cbData, LPDWORD pcbData )
6698 {
6699     FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6700           cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6701     return ERROR_NO_MORE_ITEMS;
6702 }
6703
6704 /*****************************************************************************
6705  *          EnumPrinterDataW [WINSPOOL.@]
6706  *
6707  */
6708 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6709     DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6710     DWORD cbData, LPDWORD pcbData )
6711 {
6712     FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6713           cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6714     return ERROR_NO_MORE_ITEMS;
6715 }
6716
6717 /*****************************************************************************
6718  *          EnumPrintProcessorDatatypesA [WINSPOOL.@]
6719  *
6720  */
6721 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6722                                          DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6723                                          LPDWORD pcbNeeded, LPDWORD pcReturned)
6724 {
6725     FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6726           debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6727           pcbNeeded, pcReturned);
6728     return FALSE;
6729 }
6730
6731 /*****************************************************************************
6732  *          EnumPrintProcessorDatatypesW [WINSPOOL.@]
6733  *
6734  */
6735 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6736                                          DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6737                                          LPDWORD pcbNeeded, LPDWORD pcReturned)
6738 {
6739     FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6740           debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6741           pcbNeeded, pcReturned);
6742     return FALSE;
6743 }
6744
6745 /*****************************************************************************
6746  *          EnumPrintProcessorsA [WINSPOOL.@]
6747  *
6748  * See EnumPrintProcessorsW.
6749  *
6750  */
6751 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level, 
6752                             LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6753 {
6754     BOOL    res;
6755     LPBYTE  bufferW = NULL;
6756     LPWSTR  nameW = NULL;
6757     LPWSTR  envW = NULL;
6758     DWORD   needed = 0;
6759     DWORD   numentries = 0;
6760     INT     len;
6761
6762     TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6763                 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6764
6765     /* convert names to unicode */
6766     if (pName) {
6767         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6768         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6769         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6770     }
6771     if (pEnvironment) {
6772         len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6773         envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6774         MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6775     }
6776
6777     /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6778     needed = cbBuf * sizeof(WCHAR);
6779     if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6780     res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6781
6782     if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6783         if (pcbNeeded) needed = *pcbNeeded;
6784         /* HeapReAlloc return NULL, when bufferW was NULL */
6785         bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6786                               HeapAlloc(GetProcessHeap(), 0, needed);
6787
6788         /* Try again with the large Buffer */
6789         res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6790     }
6791     numentries = pcReturned ? *pcReturned : 0;
6792     needed = 0;
6793
6794     if (res) {
6795         /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6796         DWORD   index;
6797         LPSTR   ptr;
6798         PPRINTPROCESSOR_INFO_1W ppiw;
6799         PPRINTPROCESSOR_INFO_1A ppia;
6800
6801         /* First pass: calculate the size for all Entries */
6802         ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6803         ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6804         index = 0;
6805         while (index < numentries) {
6806             index++;
6807             needed += sizeof(PRINTPROCESSOR_INFO_1A);
6808             TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6809
6810             needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6811                                             NULL, 0, NULL, NULL);
6812
6813             ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6814             ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6815         }
6816
6817         /* check for errors and quit on failure */
6818         if (cbBuf < needed) {
6819             SetLastError(ERROR_INSUFFICIENT_BUFFER);
6820             res = FALSE;
6821             goto epp_cleanup;
6822         }
6823
6824         len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6825         ptr = (LPSTR) &pPPInfo[len];        /* start of strings */
6826         cbBuf -= len ;                      /* free Bytes in the user-Buffer */
6827         ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6828         ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6829         index = 0;
6830         /* Second Pass: Fill the User Buffer (if we have one) */
6831         while ((index < numentries) && pPPInfo) {
6832             index++;
6833             TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6834             ppia->pName = ptr;
6835             len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6836                                             ptr, cbBuf , NULL, NULL);
6837             ptr += len;
6838             cbBuf -= len;
6839
6840             ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6841             ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6842
6843         }
6844     }
6845 epp_cleanup:
6846     if (pcbNeeded)  *pcbNeeded = needed;
6847     if (pcReturned) *pcReturned = (res) ? numentries : 0;
6848
6849     HeapFree(GetProcessHeap(), 0, nameW);
6850     HeapFree(GetProcessHeap(), 0, envW);
6851     HeapFree(GetProcessHeap(), 0, bufferW);
6852
6853     TRACE("returning %d with %d (%d byte for %d entries)\n",
6854             (res), GetLastError(), needed, numentries);
6855
6856     return (res);
6857 }
6858
6859 /*****************************************************************************
6860  *          EnumPrintProcessorsW [WINSPOOL.@]
6861  *
6862  * Enumerate available Print Processors
6863  *
6864  * PARAMS
6865  *  pName        [I] Servername or NULL (local Computer)
6866  *  pEnvironment [I] Printing-Environment or NULL (Default)
6867  *  Level        [I] Structure-Level (Only 1 is allowed)
6868  *  pPPInfo      [O] PTR to Buffer that receives the Result
6869  *  cbBuf        [I] Size of Buffer at pPPInfo
6870  *  pcbNeeded    [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6871  *  pcReturned   [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6872  *
6873  * RETURNS
6874  *  Success: TRUE
6875  *  Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6876  *
6877  */
6878 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6879                             LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6880 {
6881
6882     TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
6883                                 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6884
6885     if ((backend == NULL)  && !load_backend()) return FALSE;
6886
6887     if (!pcbNeeded || !pcReturned) {
6888         SetLastError(RPC_X_NULL_REF_POINTER);
6889         return FALSE;
6890     }
6891
6892     if (!pPPInfo && (cbBuf > 0)) {
6893         SetLastError(ERROR_INVALID_USER_BUFFER);
6894         return FALSE;
6895     }
6896
6897     return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
6898                                           cbBuf, pcbNeeded, pcReturned);
6899 }
6900
6901 /*****************************************************************************
6902  *          ExtDeviceMode [WINSPOOL.@]
6903  *
6904  */
6905 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6906     LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6907     DWORD fMode)
6908 {
6909     FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6910           debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6911           debugstr_a(pProfile), fMode);
6912     return -1;
6913 }
6914
6915 /*****************************************************************************
6916  *          FindClosePrinterChangeNotification [WINSPOOL.@]
6917  *
6918  */
6919 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6920 {
6921     FIXME("Stub: %p\n", hChange);
6922     return TRUE;
6923 }
6924
6925 /*****************************************************************************
6926  *          FindFirstPrinterChangeNotification [WINSPOOL.@]
6927  *
6928  */
6929 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6930     DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6931 {
6932     FIXME("Stub: %p %x %x %p\n",
6933           hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6934     return INVALID_HANDLE_VALUE;
6935 }
6936
6937 /*****************************************************************************
6938  *          FindNextPrinterChangeNotification [WINSPOOL.@]
6939  *
6940  */
6941 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6942     LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6943 {
6944     FIXME("Stub: %p %p %p %p\n",
6945           hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6946     return FALSE;
6947 }
6948
6949 /*****************************************************************************
6950  *          FreePrinterNotifyInfo [WINSPOOL.@]
6951  *
6952  */
6953 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6954 {
6955     FIXME("Stub: %p\n", pPrinterNotifyInfo);
6956     return TRUE;
6957 }
6958
6959 /*****************************************************************************
6960  *          string_to_buf
6961  *
6962  * Copies a unicode string into a buffer.  The buffer will either contain unicode or
6963  * ansi depending on the unicode parameter.
6964  */
6965 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6966 {
6967     if(!str)
6968     {
6969         *size = 0;
6970         return TRUE;
6971     }
6972
6973     if(unicode)
6974     {
6975         *size = (strlenW(str) + 1) * sizeof(WCHAR);
6976         if(*size <= cb)
6977         {
6978             memcpy(ptr, str, *size);
6979             return TRUE;
6980         }
6981         return FALSE;
6982     }
6983     else
6984     {
6985         *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6986         if(*size <= cb)
6987         {
6988             WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6989             return TRUE;
6990         }
6991         return FALSE;
6992     }
6993 }
6994
6995 /*****************************************************************************
6996  *          get_job_info_1
6997  */
6998 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6999                            LPDWORD pcbNeeded, BOOL unicode)
7000 {
7001     DWORD size, left = cbBuf;
7002     BOOL space = (cbBuf > 0);
7003     LPBYTE ptr = buf;
7004
7005     *pcbNeeded = 0;
7006
7007     if(space)
7008     {
7009         ji1->JobId = job->job_id;
7010     }
7011
7012     string_to_buf(job->document_title, ptr, left, &size, unicode);
7013     if(space && size <= left)
7014     {
7015         ji1->pDocument = (LPWSTR)ptr;
7016         ptr += size;
7017         left -= size;
7018     }
7019     else
7020         space = FALSE;
7021     *pcbNeeded += size;
7022
7023     return space;
7024 }
7025
7026 /*****************************************************************************
7027  *          get_job_info_2
7028  */
7029 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7030                            LPDWORD pcbNeeded, BOOL unicode)
7031 {
7032     DWORD size, left = cbBuf;
7033     BOOL space = (cbBuf > 0);
7034     LPBYTE ptr = buf;
7035
7036     *pcbNeeded = 0;
7037
7038     if(space)
7039     {
7040         ji2->JobId = job->job_id;
7041     }
7042
7043     string_to_buf(job->document_title, ptr, left, &size, unicode);
7044     if(space && size <= left)
7045     {
7046         ji2->pDocument = (LPWSTR)ptr;
7047         ptr += size;
7048         left -= size;
7049     }
7050     else
7051         space = FALSE;
7052     *pcbNeeded += size;
7053
7054     return space;
7055 }
7056
7057 /*****************************************************************************
7058  *          get_job_info
7059  */
7060 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7061                          DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7062 {
7063     BOOL ret = FALSE;
7064     DWORD needed = 0, size;
7065     job_t *job;
7066     LPBYTE ptr = pJob;
7067
7068     TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7069
7070     EnterCriticalSection(&printer_handles_cs);
7071     job = get_job(hPrinter, JobId);
7072     if(!job)
7073         goto end;
7074
7075     switch(Level)
7076     {
7077     case 1:
7078         size = sizeof(JOB_INFO_1W);
7079         if(cbBuf >= size)
7080         {
7081             cbBuf -= size;
7082             ptr += size;
7083             memset(pJob, 0, size);
7084         }
7085         else
7086             cbBuf = 0;
7087         ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7088         needed += size;
7089         break;
7090
7091     case 2:
7092         size = sizeof(JOB_INFO_2W);
7093         if(cbBuf >= size)
7094         {
7095             cbBuf -= size;
7096             ptr += size;
7097             memset(pJob, 0, size);
7098         }
7099         else
7100             cbBuf = 0;
7101         ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7102         needed += size;
7103         break;
7104
7105     case 3:
7106         size = sizeof(JOB_INFO_3);
7107         if(cbBuf >= size)
7108         {
7109             cbBuf -= size;
7110             memset(pJob, 0, size);
7111             ret = TRUE;
7112         }
7113         else
7114             cbBuf = 0;
7115         needed = size;
7116         break;
7117
7118     default:
7119         SetLastError(ERROR_INVALID_LEVEL);
7120         goto end;
7121     }
7122     if(pcbNeeded)
7123         *pcbNeeded = needed;
7124 end:
7125     LeaveCriticalSection(&printer_handles_cs);
7126     return ret;
7127 }
7128
7129 /*****************************************************************************
7130  *          GetJobA [WINSPOOL.@]
7131  *
7132  */
7133 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7134                     DWORD cbBuf, LPDWORD pcbNeeded)
7135 {
7136     return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7137 }
7138
7139 /*****************************************************************************
7140  *          GetJobW [WINSPOOL.@]
7141  *
7142  */
7143 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7144                     DWORD cbBuf, LPDWORD pcbNeeded)
7145 {
7146     return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7147 }
7148
7149 /*****************************************************************************
7150  *          schedule_lpr
7151  */
7152 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7153 {
7154     char *unixname, *queue, *cmd;
7155     char fmt[] = "lpr -P%s %s";
7156     DWORD len;
7157     int r;
7158
7159     if(!(unixname = wine_get_unix_file_name(filename)))
7160         return FALSE;
7161
7162     len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7163     queue = HeapAlloc(GetProcessHeap(), 0, len);
7164     WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7165
7166     cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7167     sprintf(cmd, fmt, queue, unixname);
7168
7169     TRACE("printing with: %s\n", cmd);
7170     r = system(cmd);
7171
7172     HeapFree(GetProcessHeap(), 0, cmd);
7173     HeapFree(GetProcessHeap(), 0, queue);
7174     HeapFree(GetProcessHeap(), 0, unixname);
7175     return (r == 0);
7176 }
7177
7178 /*****************************************************************************
7179  *          schedule_cups
7180  */
7181 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7182 {
7183 #ifdef SONAME_LIBCUPS
7184     if(pcupsPrintFile)
7185     {
7186         char *unixname, *queue, *unix_doc_title;
7187         DWORD len;
7188         BOOL ret;
7189
7190         if(!(unixname = wine_get_unix_file_name(filename)))
7191             return FALSE;
7192
7193         len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7194         queue = HeapAlloc(GetProcessHeap(), 0, len);
7195         WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7196
7197         len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7198         unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7199         WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7200
7201         TRACE("printing via cups\n");
7202         ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7203         HeapFree(GetProcessHeap(), 0, unix_doc_title);
7204         HeapFree(GetProcessHeap(), 0, queue);
7205         HeapFree(GetProcessHeap(), 0, unixname);
7206         return ret;
7207     }
7208     else
7209 #endif
7210     {
7211         return schedule_lpr(printer_name, filename);
7212     }
7213 }
7214
7215 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7216 {
7217     LPWSTR filename;
7218
7219     switch(msg)
7220     {
7221     case WM_INITDIALOG:
7222         SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7223         return TRUE;
7224
7225     case WM_COMMAND:
7226         if(HIWORD(wparam) == BN_CLICKED)
7227         {
7228             if(LOWORD(wparam) == IDOK)
7229             {
7230                 HANDLE hf;
7231                 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7232                 LPWSTR *output;
7233
7234                 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7235                 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7236
7237                 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7238                 {
7239                     WCHAR caption[200], message[200];
7240                     int mb_ret;
7241
7242                     LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7243                     LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7244                     mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7245                     if(mb_ret == IDCANCEL)
7246                     {
7247                         HeapFree(GetProcessHeap(), 0, filename);
7248                         return TRUE;
7249                     }
7250                 }
7251                 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7252                 if(hf == INVALID_HANDLE_VALUE)
7253                 {
7254                     WCHAR caption[200], message[200];
7255
7256                     LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7257                     LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7258                     MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7259                     HeapFree(GetProcessHeap(), 0, filename);
7260                     return TRUE;
7261                 }
7262                 CloseHandle(hf);
7263                 DeleteFileW(filename);
7264                 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7265                 *output = filename;
7266                 EndDialog(hwnd, IDOK);
7267                 return TRUE;
7268             }
7269             if(LOWORD(wparam) == IDCANCEL)
7270             {
7271                 EndDialog(hwnd, IDCANCEL);
7272                 return TRUE;
7273             }
7274         }
7275         return FALSE;
7276     }
7277     return FALSE;
7278 }
7279
7280 /*****************************************************************************
7281  *          get_filename
7282  */
7283 static BOOL get_filename(LPWSTR *filename)
7284 {
7285     return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7286                            file_dlg_proc, (LPARAM)filename) == IDOK;
7287 }
7288
7289 /*****************************************************************************
7290  *          schedule_file
7291  */
7292 static BOOL schedule_file(LPCWSTR filename)
7293 {
7294     LPWSTR output = NULL;
7295
7296     if(get_filename(&output))
7297     {
7298         BOOL r;
7299         TRACE("copy to %s\n", debugstr_w(output));
7300         r = CopyFileW(filename, output, FALSE);
7301         HeapFree(GetProcessHeap(), 0, output);
7302         return r;
7303     }
7304     return FALSE;
7305 }
7306
7307 /*****************************************************************************
7308  *          schedule_pipe
7309  */
7310 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7311 {
7312 #ifdef HAVE_FORK
7313     char *unixname, *cmdA;
7314     DWORD len;
7315     int fds[2] = {-1, -1}, file_fd = -1, no_read;
7316     BOOL ret = FALSE;
7317     char buf[1024];
7318
7319     if(!(unixname = wine_get_unix_file_name(filename)))
7320         return FALSE;
7321
7322     len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7323     cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7324     WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7325
7326     TRACE("printing with: %s\n", cmdA);
7327
7328     if((file_fd = open(unixname, O_RDONLY)) == -1)
7329         goto end;
7330
7331     if (pipe(fds))
7332     {
7333         ERR("pipe() failed!\n"); 
7334         goto end;
7335     }
7336
7337     if (fork() == 0)
7338     {
7339         close(0);
7340         dup2(fds[0], 0);
7341         close(fds[1]);
7342
7343         /* reset signals that we previously set to SIG_IGN */
7344         signal(SIGPIPE, SIG_DFL);
7345         signal(SIGCHLD, SIG_DFL);
7346
7347         execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7348         _exit(1);
7349     }
7350
7351     while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7352         write(fds[1], buf, no_read);
7353
7354     ret = TRUE;
7355
7356 end:
7357     if(file_fd != -1) close(file_fd);
7358     if(fds[0] != -1) close(fds[0]);
7359     if(fds[1] != -1) close(fds[1]);
7360
7361     HeapFree(GetProcessHeap(), 0, cmdA);
7362     HeapFree(GetProcessHeap(), 0, unixname);
7363     return ret;
7364 #else
7365     return FALSE;
7366 #endif
7367 }
7368
7369 /*****************************************************************************
7370  *          schedule_unixfile
7371  */
7372 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7373 {
7374     int in_fd, out_fd, no_read;
7375     char buf[1024];
7376     BOOL ret = FALSE;
7377     char *unixname, *outputA;
7378     DWORD len;
7379
7380     if(!(unixname = wine_get_unix_file_name(filename)))
7381         return FALSE;
7382
7383     len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7384     outputA = HeapAlloc(GetProcessHeap(), 0, len);
7385     WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7386     
7387     out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7388     in_fd = open(unixname, O_RDONLY);
7389     if(out_fd == -1 || in_fd == -1)
7390         goto end;
7391
7392     while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7393         write(out_fd, buf, no_read);
7394
7395     ret = TRUE;
7396 end:
7397     if(in_fd != -1) close(in_fd);
7398     if(out_fd != -1) close(out_fd);
7399     HeapFree(GetProcessHeap(), 0, outputA);
7400     HeapFree(GetProcessHeap(), 0, unixname);
7401     return ret;
7402 }
7403
7404 /*****************************************************************************
7405  *          ScheduleJob [WINSPOOL.@]
7406  *
7407  */
7408 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7409 {
7410     opened_printer_t *printer;
7411     BOOL ret = FALSE;
7412     struct list *cursor, *cursor2;
7413
7414     TRACE("(%p, %x)\n", hPrinter, dwJobID);
7415     EnterCriticalSection(&printer_handles_cs);
7416     printer = get_opened_printer(hPrinter);
7417     if(!printer)
7418         goto end;
7419
7420     LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7421     {
7422         job_t *job = LIST_ENTRY(cursor, job_t, entry);
7423         HANDLE hf;
7424
7425         if(job->job_id != dwJobID) continue;
7426
7427         hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7428         if(hf != INVALID_HANDLE_VALUE)
7429         {
7430             PRINTER_INFO_5W *pi5;
7431             DWORD needed;
7432             HKEY hkey;
7433             WCHAR output[1024];
7434             static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7435                                                 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7436
7437             GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7438             pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7439             GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7440             TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7441                   debugstr_w(pi5->pPortName));
7442             
7443             output[0] = 0;
7444
7445             /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7446             if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7447             {
7448                 DWORD type, count = sizeof(output);
7449                 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7450                 RegCloseKey(hkey);
7451             }
7452             if(output[0] == '|')
7453             {
7454                 ret = schedule_pipe(output + 1, job->filename);
7455             }
7456             else if(output[0])
7457             {
7458                 ret = schedule_unixfile(output, job->filename);
7459             }
7460             else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7461             {
7462                 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7463             }
7464             else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7465             {
7466                 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7467             }
7468             else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7469             {
7470                 ret = schedule_file(job->filename);
7471             }
7472             else
7473             {
7474                 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7475             }
7476             HeapFree(GetProcessHeap(), 0, pi5);
7477             CloseHandle(hf);
7478             DeleteFileW(job->filename);
7479         }
7480         list_remove(cursor);
7481         HeapFree(GetProcessHeap(), 0, job->document_title);
7482         HeapFree(GetProcessHeap(), 0, job->filename);
7483         HeapFree(GetProcessHeap(), 0, job);
7484         break;
7485     }
7486 end:
7487     LeaveCriticalSection(&printer_handles_cs);
7488     return ret;
7489 }
7490
7491 /*****************************************************************************
7492  *          StartDocDlgA [WINSPOOL.@]
7493  */
7494 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7495 {
7496     UNICODE_STRING usBuffer;
7497     DOCINFOW docW;
7498     LPWSTR retW;
7499     LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7500     LPSTR ret = NULL;
7501
7502     docW.cbSize = sizeof(docW);
7503     if (doc->lpszDocName)
7504     {
7505         docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7506         if (!(docW.lpszDocName = docnameW)) return NULL;
7507     }
7508     if (doc->lpszOutput)
7509     {
7510         outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7511         if (!(docW.lpszOutput = outputW)) return NULL;
7512     }
7513     if (doc->lpszDatatype)
7514     {
7515         datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7516         if (!(docW.lpszDatatype = datatypeW)) return NULL;
7517     }
7518     docW.fwType = doc->fwType;
7519
7520     retW = StartDocDlgW(hPrinter, &docW);
7521
7522     if(retW)
7523     {
7524         DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7525         ret = HeapAlloc(GetProcessHeap(), 0, len);
7526         WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7527         HeapFree(GetProcessHeap(), 0, retW);
7528     }
7529
7530     HeapFree(GetProcessHeap(), 0, datatypeW);
7531     HeapFree(GetProcessHeap(), 0, outputW);
7532     HeapFree(GetProcessHeap(), 0, docnameW);
7533
7534     return ret;
7535 }
7536
7537 /*****************************************************************************
7538  *          StartDocDlgW [WINSPOOL.@]
7539  *
7540  * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7541  * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7542  * port is "FILE:". Also returns the full path if passed a relative path.
7543  *
7544  * The caller should free the returned string from the process heap.
7545  */
7546 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7547 {
7548     LPWSTR ret = NULL;
7549     DWORD len, attr;
7550
7551     if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7552     {
7553         PRINTER_INFO_5W *pi5;
7554         GetPrinterW(hPrinter, 5, NULL, 0, &len);
7555         if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7556             return NULL;
7557         pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7558         GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7559         if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7560         {
7561             HeapFree(GetProcessHeap(), 0, pi5);
7562             return NULL;
7563         }
7564         HeapFree(GetProcessHeap(), 0, pi5);
7565     }
7566
7567     if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7568     {
7569         LPWSTR name;
7570
7571         if (get_filename(&name))
7572         {
7573             if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7574             {
7575                 HeapFree(GetProcessHeap(), 0, name);
7576                 return NULL;
7577             }
7578             ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7579             GetFullPathNameW(name, len, ret, NULL);
7580             HeapFree(GetProcessHeap(), 0, name);
7581         }
7582         return ret;
7583     }
7584
7585     if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7586         return NULL;
7587
7588     ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7589     GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7590         
7591     attr = GetFileAttributesW(ret);
7592     if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7593     {
7594         HeapFree(GetProcessHeap(), 0, ret);
7595         ret = NULL;
7596     }
7597     return ret;
7598 }