mapi32: Add Lithunian translation.
[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
4392     if (!(name = get_opened_printer_name(hPrinter))) {
4393         SetLastError(ERROR_INVALID_HANDLE);
4394         return FALSE;
4395     }
4396
4397     if (Level < 1 || Level == 7 || Level > 8) {
4398         SetLastError(ERROR_INVALID_LEVEL);
4399         return FALSE;
4400     }
4401
4402     env = validate_envW(pEnvironment);
4403     if (!env) return FALSE;     /* SetLastError() is in validate_envW */
4404
4405     if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4406        ERROR_SUCCESS) {
4407         ERR("Can't create Printers key\n");
4408         return FALSE;
4409     }
4410     if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4411        != ERROR_SUCCESS) {
4412         ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4413         RegCloseKey(hkeyPrinters);
4414         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4415         return FALSE;
4416     }
4417     size = sizeof(DriverName);
4418     DriverName[0] = 0;
4419     ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4420                            (LPBYTE)DriverName, &size);
4421     RegCloseKey(hkeyPrinter);
4422     RegCloseKey(hkeyPrinters);
4423     if(ret != ERROR_SUCCESS) {
4424         ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4425         return FALSE;
4426     }
4427
4428     hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4429     if(!hkeyDrivers) {
4430         ERR("Can't create Drivers key\n");
4431         return FALSE;
4432     }
4433
4434     size = di_sizeof[Level];
4435     if ((size <= cbBuf) && pDriverInfo)
4436         ptr = pDriverInfo + size;
4437
4438     if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4439                          env, Level, pDriverInfo, ptr,
4440                          (cbBuf < size) ? 0 : cbBuf - size,
4441                          &needed)) {
4442             RegCloseKey(hkeyDrivers);
4443             return FALSE;
4444     }
4445
4446     RegCloseKey(hkeyDrivers);
4447
4448     if(pcbNeeded) *pcbNeeded = size + needed;
4449     TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4450     if(cbBuf >= needed) return TRUE;
4451     SetLastError(ERROR_INSUFFICIENT_BUFFER);
4452     return FALSE;
4453 }
4454
4455 /*****************************************************************************
4456  *          GetPrinterDriverA  [WINSPOOL.@]
4457  */
4458 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4459                               DWORD Level, LPBYTE pDriverInfo,
4460                               DWORD cbBuf, LPDWORD pcbNeeded)
4461 {
4462     BOOL ret;
4463     UNICODE_STRING pEnvW;
4464     PWSTR pwstrEnvW;
4465     LPBYTE buf = NULL;
4466
4467     if (cbBuf)
4468         buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4469     
4470     pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4471     ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4472                                     cbBuf, pcbNeeded);
4473     if (ret)
4474         convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4475
4476     HeapFree(GetProcessHeap(), 0, buf);
4477
4478     RtlFreeUnicodeString(&pEnvW);
4479     return ret;
4480 }
4481
4482 /*****************************************************************************
4483  *       GetPrinterDriverDirectoryW  [WINSPOOL.@]
4484  *
4485  * Return the PATH for the Printer-Drivers (UNICODE)
4486  *
4487  * PARAMS
4488  *   pName            [I] Servername (NT only) or NULL (local Computer)
4489  *   pEnvironment     [I] Printing-Environment (see below) or NULL (Default)
4490  *   Level            [I] Structure-Level (must be 1)
4491  *   pDriverDirectory [O] PTR to Buffer that receives the Result
4492  *   cbBuf            [I] Size of Buffer at pDriverDirectory
4493  *   pcbNeeded        [O] PTR to DWORD that receives the size in Bytes used / 
4494  *                        required for pDriverDirectory
4495  *
4496  * RETURNS
4497  *   Success: TRUE  and in pcbNeeded the Bytes used in pDriverDirectory
4498  *   Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4499  *   if cbBuf is too small
4500  * 
4501  *   Native Values returned in pDriverDirectory on Success:
4502  *|  NT(Windows NT x86):  "%winsysdir%\\spool\\DRIVERS\\w32x86" 
4503  *|  NT(Windows 4.0):     "%winsysdir%\\spool\\DRIVERS\\win40" 
4504  *|  win9x(Windows 4.0):  "%winsysdir%" 
4505  *
4506  *   "%winsysdir%" is the Value from GetSystemDirectoryW()
4507  *
4508  * FIXME
4509  *-  Only NULL or "" is supported for pName
4510  *
4511  */
4512 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4513                                        DWORD Level, LPBYTE pDriverDirectory,
4514                                        DWORD cbBuf, LPDWORD pcbNeeded)
4515 {
4516     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName), 
4517           debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4518
4519     if ((backend == NULL)  && !load_backend()) return FALSE;
4520
4521     if (Level != 1) {
4522         /* (Level != 1) is ignored in win9x */
4523         SetLastError(ERROR_INVALID_LEVEL);
4524         return FALSE;
4525     }
4526     if (pcbNeeded == NULL) {
4527         /* (pcbNeeded == NULL) is ignored in win9x */
4528         SetLastError(RPC_X_NULL_REF_POINTER);
4529         return FALSE;
4530     }
4531
4532     return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4533                                                 pDriverDirectory, cbBuf, pcbNeeded);
4534
4535 }
4536
4537
4538 /*****************************************************************************
4539  *       GetPrinterDriverDirectoryA  [WINSPOOL.@]
4540  *
4541  * Return the PATH for the Printer-Drivers (ANSI)
4542  *
4543  * See GetPrinterDriverDirectoryW.
4544  *
4545  * NOTES
4546  * On NT, pDriverDirectory need the same Size as the Unicode-Version
4547  *
4548  */
4549 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4550                                        DWORD Level, LPBYTE pDriverDirectory,
4551                                        DWORD cbBuf, LPDWORD pcbNeeded)
4552 {
4553     UNICODE_STRING nameW, environmentW;
4554     BOOL ret;
4555     DWORD pcbNeededW;
4556     INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4557     WCHAR *driverDirectoryW = NULL;
4558
4559     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName), 
4560           debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4561  
4562     if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4563
4564     if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4565     else nameW.Buffer = NULL;
4566     if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4567     else environmentW.Buffer = NULL;
4568
4569     ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4570                                       (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4571     if (ret) {
4572         DWORD needed;
4573         needed =  WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1, 
4574                                    (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4575         if(pcbNeeded)
4576             *pcbNeeded = needed;
4577         ret = (needed <= cbBuf) ? TRUE : FALSE;
4578     } else 
4579         if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4580
4581     TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4582
4583     HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4584     RtlFreeUnicodeString(&environmentW);
4585     RtlFreeUnicodeString(&nameW);
4586
4587     return ret;
4588 }
4589
4590 /*****************************************************************************
4591  *          AddPrinterDriverA  [WINSPOOL.@]
4592  *
4593  * See AddPrinterDriverW.
4594  *
4595  */
4596 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4597 {
4598     TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4599     return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4600 }
4601
4602 /******************************************************************************
4603  *  AddPrinterDriverW (WINSPOOL.@)
4604  *
4605  * Install a Printer Driver
4606  *
4607  * PARAMS
4608  *  pName           [I] Servername or NULL (local Computer)
4609  *  level           [I] Level for the supplied DRIVER_INFO_*W struct
4610  *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4611  *
4612  * RESULTS
4613  *  Success: TRUE
4614  *  Failure: FALSE
4615  *
4616  */
4617 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4618 {
4619     TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4620     return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4621 }
4622
4623 /*****************************************************************************
4624  *          AddPrintProcessorA  [WINSPOOL.@]
4625  */
4626 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4627                                LPSTR pPrintProcessorName)
4628 {
4629     FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4630           debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4631     return FALSE;
4632 }
4633
4634 /*****************************************************************************
4635  *          AddPrintProcessorW  [WINSPOOL.@]
4636  */
4637 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4638                                LPWSTR pPrintProcessorName)
4639 {
4640     FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4641           debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4642     return FALSE;
4643 }
4644
4645 /*****************************************************************************
4646  *          AddPrintProvidorA  [WINSPOOL.@]
4647  */
4648 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4649 {
4650     FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4651     return FALSE;
4652 }
4653
4654 /*****************************************************************************
4655  *          AddPrintProvidorW  [WINSPOOL.@]
4656  */
4657 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4658 {
4659     FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4660     return FALSE;
4661 }
4662
4663 /*****************************************************************************
4664  *          AdvancedDocumentPropertiesA  [WINSPOOL.@]
4665  */
4666 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4667                                         PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4668 {
4669     FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4670           pDevModeOutput, pDevModeInput);
4671     return 0;
4672 }
4673
4674 /*****************************************************************************
4675  *          AdvancedDocumentPropertiesW  [WINSPOOL.@]
4676  */
4677 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4678                                         PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4679 {
4680     FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4681           pDevModeOutput, pDevModeInput);
4682     return 0;
4683 }
4684
4685 /*****************************************************************************
4686  *          PrinterProperties  [WINSPOOL.@]
4687  *
4688  *     Displays a dialog to set the properties of the printer.
4689  *
4690  * RETURNS
4691  *     nonzero on success or zero on failure
4692  *
4693  * BUGS
4694  *         implemented as stub only
4695  */
4696 BOOL WINAPI PrinterProperties(HWND hWnd,      /* [in] handle to parent window */
4697                               HANDLE hPrinter /* [in] handle to printer object */
4698 ){
4699     FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4700     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4701     return FALSE;
4702 }
4703
4704 /*****************************************************************************
4705  *          EnumJobsA [WINSPOOL.@]
4706  *
4707  */
4708 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4709                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4710                       LPDWORD pcReturned)
4711 {
4712     FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4713         hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4714     );
4715     if(pcbNeeded) *pcbNeeded = 0;
4716     if(pcReturned) *pcReturned = 0;
4717     return FALSE;
4718 }
4719
4720
4721 /*****************************************************************************
4722  *          EnumJobsW [WINSPOOL.@]
4723  *
4724  */
4725 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4726                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4727                       LPDWORD pcReturned)
4728 {
4729     FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4730         hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4731     );
4732     if(pcbNeeded) *pcbNeeded = 0;
4733     if(pcReturned) *pcReturned = 0;
4734     return FALSE;
4735 }
4736
4737 /*****************************************************************************
4738  *          WINSPOOL_EnumPrinterDrivers [internal]
4739  *
4740  *    Delivers information about all printer drivers installed on the
4741  *    localhost or a given server
4742  *
4743  * RETURNS
4744  *    nonzero on success or zero on failure. If the buffer for the returned
4745  *    information is too small the function will return an error
4746  *
4747  * BUGS
4748  *    - only implemented for localhost, foreign hosts will return an error
4749  */
4750 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4751                                         DWORD Level, LPBYTE pDriverInfo,
4752                                         DWORD driver_index,
4753                                         DWORD cbBuf, LPDWORD pcbNeeded,
4754                                         LPDWORD pcFound, DWORD data_offset)
4755
4756 {   HKEY  hkeyDrivers;
4757     DWORD i, size = 0;
4758     const printenv_t * env;
4759
4760     TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4761           debugstr_w(pName), debugstr_w(pEnvironment),
4762           Level, pDriverInfo, driver_index, cbBuf, data_offset);
4763
4764     env = validate_envW(pEnvironment);
4765     if (!env) return FALSE;     /* SetLastError() is in validate_envW */
4766
4767     *pcFound = 0;
4768
4769     hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4770     if(!hkeyDrivers) {
4771         ERR("Can't open Drivers key\n");
4772         return FALSE;
4773     }
4774
4775     if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4776                         NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4777         RegCloseKey(hkeyDrivers);
4778         ERR("Can't query Drivers key\n");
4779         return FALSE;
4780     }
4781     TRACE("Found %d Drivers\n", *pcFound);
4782
4783     /* get size of single struct
4784      * unicode and ascii structure have the same size
4785      */
4786     size = di_sizeof[Level];
4787
4788     if (data_offset == 0)
4789         data_offset = size * (*pcFound);
4790     *pcbNeeded = data_offset;
4791
4792     for( i = 0; i < *pcFound; i++) {
4793         WCHAR DriverNameW[255];
4794         PBYTE table_ptr = NULL;
4795         PBYTE data_ptr = NULL;
4796         DWORD needed = 0;
4797
4798         if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4799                        != ERROR_SUCCESS) {
4800             ERR("Can't enum key number %d\n", i);
4801             RegCloseKey(hkeyDrivers);
4802             return FALSE;
4803         }
4804
4805         if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4806             table_ptr = pDriverInfo + (driver_index + i) * size;
4807         if (pDriverInfo && *pcbNeeded <= cbBuf)
4808             data_ptr = pDriverInfo + *pcbNeeded;
4809
4810         if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4811                          env, Level, table_ptr, data_ptr,
4812                          (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4813                          &needed)) {
4814             RegCloseKey(hkeyDrivers);
4815             return FALSE;
4816         }
4817
4818         *pcbNeeded += needed;
4819     }
4820
4821     RegCloseKey(hkeyDrivers);
4822
4823     if(cbBuf < *pcbNeeded){
4824         SetLastError(ERROR_INSUFFICIENT_BUFFER);
4825         return FALSE;
4826     }
4827
4828     return TRUE;
4829 }
4830
4831 /*****************************************************************************
4832  *          EnumPrinterDriversW  [WINSPOOL.@]
4833  *
4834  *    see function EnumPrinterDrivers for RETURNS, BUGS
4835  */
4836 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4837                                 LPBYTE pDriverInfo, DWORD cbBuf,
4838                                 LPDWORD pcbNeeded, LPDWORD pcReturned)
4839 {
4840     static const WCHAR allW[] = {'a','l','l',0};
4841     BOOL ret;
4842     DWORD found;
4843
4844     if ((pcbNeeded == NULL) || (pcReturned == NULL))
4845     {
4846         SetLastError(RPC_X_NULL_REF_POINTER);
4847         return FALSE;
4848     }
4849
4850     /* check for local drivers */
4851     if((pName) && (pName[0])) {
4852         FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4853         SetLastError(ERROR_ACCESS_DENIED);
4854         return FALSE;
4855     }
4856
4857     /* check input parameter */
4858     if ((Level < 1) || (Level == 7) || (Level > 8)) {
4859         SetLastError(ERROR_INVALID_LEVEL);
4860         return FALSE;
4861     }
4862
4863     if(pDriverInfo && cbBuf > 0)
4864         memset( pDriverInfo, 0, cbBuf);
4865
4866     /* Exception:  pull all printers */
4867     if (pEnvironment && !strcmpW(pEnvironment, allW))
4868     {
4869         DWORD i, needed, bufsize = cbBuf;
4870         DWORD total_needed = 0;
4871         DWORD total_found = 0;
4872         DWORD data_offset;
4873
4874         /* Precompute the overall total; we need this to know
4875            where pointers end and data begins (i.e. data_offset) */
4876         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4877         {
4878             needed = found = 0;
4879             ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4880                                               NULL, 0, 0, &needed, &found, 0);
4881             if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4882             total_needed += needed;
4883             total_found += found;
4884         }
4885
4886         data_offset = di_sizeof[Level] * total_found;
4887
4888         *pcReturned = 0;
4889         *pcbNeeded = 0;
4890         total_found = 0;
4891         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4892         {
4893             needed = found = 0;
4894             ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4895                                               pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4896             if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4897             else if (ret)
4898                 *pcReturned += found;
4899             *pcbNeeded = needed;
4900             data_offset = needed;
4901             total_found += found;
4902         }
4903         return ret;
4904     }
4905
4906     /* Normal behavior */
4907     ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4908                                        0, cbBuf, pcbNeeded, &found, 0);
4909     if (ret)
4910         *pcReturned = found;
4911
4912     return ret;
4913 }
4914
4915 /*****************************************************************************
4916  *          EnumPrinterDriversA  [WINSPOOL.@]
4917  *
4918  *    see function EnumPrinterDrivers for RETURNS, BUGS
4919  */
4920 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4921                                 LPBYTE pDriverInfo, DWORD cbBuf,
4922                                 LPDWORD pcbNeeded, LPDWORD pcReturned)
4923 {
4924     BOOL ret;
4925     UNICODE_STRING pNameW, pEnvironmentW;
4926     PWSTR pwstrNameW, pwstrEnvironmentW;
4927     LPBYTE buf = NULL;
4928
4929     if (cbBuf)
4930         buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4931
4932     pwstrNameW = asciitounicode(&pNameW, pName);
4933     pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4934
4935     ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4936                                 buf, cbBuf, pcbNeeded, pcReturned);
4937     if (ret)
4938         convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4939
4940     HeapFree(GetProcessHeap(), 0, buf);
4941
4942     RtlFreeUnicodeString(&pNameW);
4943     RtlFreeUnicodeString(&pEnvironmentW);
4944
4945     return ret;
4946 }
4947
4948 /******************************************************************************
4949  *              EnumPortsA   (WINSPOOL.@)
4950  *
4951  * See EnumPortsW.
4952  *
4953  */
4954 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4955                         LPDWORD pcbNeeded, LPDWORD pcReturned)
4956 {
4957     BOOL    res;
4958     LPBYTE  bufferW = NULL;
4959     LPWSTR  nameW = NULL;
4960     DWORD   needed = 0;
4961     DWORD   numentries = 0;
4962     INT     len;
4963
4964     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4965           cbBuf, pcbNeeded, pcReturned);
4966
4967     /* convert servername to unicode */
4968     if (pName) {
4969         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4970         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4971         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4972     }
4973     /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4974     needed = cbBuf * sizeof(WCHAR);    
4975     if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4976     res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4977
4978     if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4979         if (pcbNeeded) needed = *pcbNeeded;
4980         /* HeapReAlloc return NULL, when bufferW was NULL */
4981         bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4982                               HeapAlloc(GetProcessHeap(), 0, needed);
4983
4984         /* Try again with the large Buffer */
4985         res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4986     }
4987     needed = pcbNeeded ? *pcbNeeded : 0;
4988     numentries = pcReturned ? *pcReturned : 0;
4989
4990     /*
4991        W2k require the buffersize from EnumPortsW also for EnumPortsA.
4992        We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
4993      */
4994     if (res) {
4995         /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
4996         DWORD   entrysize = 0;
4997         DWORD   index;
4998         LPSTR   ptr;
4999         LPPORT_INFO_2W pi2w;
5000         LPPORT_INFO_2A pi2a;
5001
5002         needed = 0;
5003         entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5004
5005         /* First pass: calculate the size for all Entries */
5006         pi2w = (LPPORT_INFO_2W) bufferW;
5007         pi2a = (LPPORT_INFO_2A) pPorts;
5008         index = 0;
5009         while (index < numentries) {
5010             index++;
5011             needed += entrysize;    /* PORT_INFO_?A */
5012             TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5013
5014             needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5015                                             NULL, 0, NULL, NULL);
5016             if (Level > 1) {
5017                 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5018                                                 NULL, 0, NULL, NULL);
5019                 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5020                                                 NULL, 0, NULL, NULL);
5021             }
5022             /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5023             pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5024             pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5025         }
5026
5027         /* check for errors and quit on failure */
5028         if (cbBuf < needed) {
5029             SetLastError(ERROR_INSUFFICIENT_BUFFER);
5030             res = FALSE;
5031             goto cleanup;
5032         }
5033         len = entrysize * numentries;       /* room for all PORT_INFO_?A */
5034         ptr = (LPSTR) &pPorts[len];         /* room for strings */
5035         cbBuf -= len ;                      /* free Bytes in the user-Buffer */
5036         pi2w = (LPPORT_INFO_2W) bufferW;
5037         pi2a = (LPPORT_INFO_2A) pPorts;
5038         index = 0;
5039         /* Second Pass: Fill the User Buffer (if we have one) */
5040         while ((index < numentries) && pPorts) {
5041             index++;
5042             TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5043             pi2a->pPortName = ptr;
5044             len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5045                                             ptr, cbBuf , NULL, NULL);
5046             ptr += len;
5047             cbBuf -= len;
5048             if (Level > 1) {
5049                 pi2a->pMonitorName = ptr;
5050                 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5051                                             ptr, cbBuf, NULL, NULL);
5052                 ptr += len;
5053                 cbBuf -= len;
5054
5055                 pi2a->pDescription = ptr;
5056                 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5057                                             ptr, cbBuf, NULL, NULL);
5058                 ptr += len;
5059                 cbBuf -= len;
5060
5061                 pi2a->fPortType = pi2w->fPortType;
5062                 pi2a->Reserved = 0;              /* documented: "must be zero" */
5063                 
5064             }
5065             /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5066             pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5067             pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5068         }
5069     }
5070
5071 cleanup:
5072     if (pcbNeeded)  *pcbNeeded = needed;
5073     if (pcReturned) *pcReturned = (res) ? numentries : 0;
5074
5075     HeapFree(GetProcessHeap(), 0, nameW);
5076     HeapFree(GetProcessHeap(), 0, bufferW);
5077
5078     TRACE("returning %d with %d (%d byte for %d of %d entries)\n", 
5079             (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5080
5081     return (res);
5082
5083 }
5084
5085 /******************************************************************************
5086  *      EnumPortsW   (WINSPOOL.@)
5087  *
5088  * Enumerate available Ports
5089  *
5090  * PARAMS
5091  *  pName      [I] Servername or NULL (local Computer)
5092  *  Level      [I] Structure-Level (1 or 2)
5093  *  pPorts     [O] PTR to Buffer that receives the Result
5094  *  cbBuf      [I] Size of Buffer at pPorts
5095  *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5096  *  pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5097  *
5098  * RETURNS
5099  *  Success: TRUE
5100  *  Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5101  *
5102  */
5103 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5104 {
5105
5106     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5107           cbBuf, pcbNeeded, pcReturned);
5108
5109     if ((backend == NULL)  && !load_backend()) return FALSE;
5110
5111     /* Level is not checked in win9x */
5112     if (!Level || (Level > 2)) {
5113         WARN("level (%d) is ignored in win9x\n", Level);
5114         SetLastError(ERROR_INVALID_LEVEL);
5115         return FALSE;
5116     }
5117     if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5118         SetLastError(RPC_X_NULL_REF_POINTER);
5119         return FALSE;
5120     }
5121
5122     return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5123 }
5124
5125 /******************************************************************************
5126  *              GetDefaultPrinterW   (WINSPOOL.@)
5127  *
5128  * FIXME
5129  *      This function must read the value from data 'device' of key
5130  *      HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5131  */
5132 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5133 {
5134     BOOL  retval = TRUE;
5135     DWORD insize, len;
5136     WCHAR *buffer, *ptr;
5137
5138     if (!namesize)
5139     {
5140         SetLastError(ERROR_INVALID_PARAMETER);
5141         return FALSE;
5142     }
5143
5144     /* make the buffer big enough for the stuff from the profile/registry,
5145      * the content must fit into the local buffer to compute the correct
5146      * size even if the extern buffer is too small or not given.
5147      * (20 for ,driver,port) */
5148     insize = *namesize;
5149     len = max(100, (insize + 20));
5150     buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5151
5152     if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5153     {
5154         SetLastError (ERROR_FILE_NOT_FOUND);
5155         retval = FALSE;
5156         goto end;
5157     }
5158     TRACE("%s\n", debugstr_w(buffer));
5159
5160     if ((ptr = strchrW(buffer, ',')) == NULL)
5161     {
5162         SetLastError(ERROR_INVALID_NAME);
5163         retval = FALSE;
5164         goto end;
5165     }
5166
5167     *ptr = 0;
5168     *namesize = strlenW(buffer) + 1;
5169     if(!name || (*namesize > insize))
5170     {
5171         SetLastError(ERROR_INSUFFICIENT_BUFFER);
5172         retval = FALSE;
5173         goto end;
5174     }
5175     strcpyW(name, buffer);
5176
5177 end:
5178     HeapFree( GetProcessHeap(), 0, buffer);
5179     return retval;
5180 }
5181
5182
5183 /******************************************************************************
5184  *              GetDefaultPrinterA   (WINSPOOL.@)
5185  */
5186 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5187 {
5188     BOOL  retval = TRUE;
5189     DWORD insize = 0;
5190     WCHAR *bufferW = NULL;
5191
5192     if (!namesize)
5193     {
5194         SetLastError(ERROR_INVALID_PARAMETER);
5195         return FALSE;
5196     }
5197
5198     if(name && *namesize) {
5199         insize = *namesize;
5200         bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5201     }
5202
5203     if(!GetDefaultPrinterW( bufferW, namesize)) {
5204         retval = FALSE;
5205         goto end;
5206     }
5207
5208     *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5209                                     NULL, NULL);
5210     if (!*namesize)
5211     {
5212         *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5213         retval = FALSE;
5214     }
5215     TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5216
5217 end:
5218     HeapFree( GetProcessHeap(), 0, bufferW);
5219     return retval;
5220 }
5221
5222
5223 /******************************************************************************
5224  *              SetDefaultPrinterW   (WINSPOOL.204)
5225  *
5226  * Set the Name of the Default Printer
5227  *
5228  * PARAMS
5229  *  pszPrinter [I] Name of the Printer or NULL
5230  *
5231  * RETURNS
5232  *  Success:    True
5233  *  Failure:    FALSE
5234  *
5235  * NOTES
5236  *  When the Parameter is NULL or points to an Empty String and
5237  *  a Default Printer was already present, then this Function changes nothing.
5238  *  Without a Default Printer and NULL (or an Empty String) as Parameter,
5239  *  the First enumerated local Printer is used.
5240  *
5241  */
5242 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5243 {
5244
5245     TRACE("(%s)\n", debugstr_w(pszPrinter));
5246
5247     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5248     return FALSE;
5249 }
5250
5251 /******************************************************************************
5252  *              SetDefaultPrinterA   (WINSPOOL.202)
5253  *
5254  * See SetDefaultPrinterW.
5255  *
5256  */
5257 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5258 {
5259
5260     TRACE("(%s)\n", debugstr_a(pszPrinter));
5261
5262     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5263     return FALSE;
5264 }
5265
5266
5267 /******************************************************************************
5268  *              SetPrinterDataExA   (WINSPOOL.@)
5269  */
5270 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5271                                LPCSTR pValueName, DWORD Type,
5272                                LPBYTE pData, DWORD cbData)
5273 {
5274     HKEY hkeyPrinter, hkeySubkey;
5275     DWORD ret;
5276
5277     TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5278           debugstr_a(pValueName), Type, pData, cbData);
5279
5280     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5281        != ERROR_SUCCESS)
5282         return ret;
5283
5284     if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5285        != ERROR_SUCCESS) {
5286         ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5287         RegCloseKey(hkeyPrinter);
5288         return ret;
5289     }
5290     ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5291     RegCloseKey(hkeySubkey);
5292     RegCloseKey(hkeyPrinter);
5293     return ret;
5294 }
5295
5296 /******************************************************************************
5297  *              SetPrinterDataExW   (WINSPOOL.@)
5298  */
5299 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5300                                LPCWSTR pValueName, DWORD Type,
5301                                LPBYTE pData, DWORD cbData)
5302 {
5303     HKEY hkeyPrinter, hkeySubkey;
5304     DWORD ret;
5305
5306     TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5307           debugstr_w(pValueName), Type, pData, cbData);
5308
5309     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5310        != ERROR_SUCCESS)
5311         return ret;
5312
5313     if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5314        != ERROR_SUCCESS) {
5315         ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5316         RegCloseKey(hkeyPrinter);
5317         return ret;
5318     }
5319     ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5320     RegCloseKey(hkeySubkey);
5321     RegCloseKey(hkeyPrinter);
5322     return ret;
5323 }
5324
5325 /******************************************************************************
5326  *              SetPrinterDataA   (WINSPOOL.@)
5327  */
5328 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5329                                LPBYTE pData, DWORD cbData)
5330 {
5331     return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5332                              pData, cbData);
5333 }
5334
5335 /******************************************************************************
5336  *              SetPrinterDataW   (WINSPOOL.@)
5337  */
5338 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5339                              LPBYTE pData, DWORD cbData)
5340 {
5341     return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5342                              pData, cbData);
5343 }
5344
5345 /******************************************************************************
5346  *              GetPrinterDataExA   (WINSPOOL.@)
5347  */
5348 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5349                                LPCSTR pValueName, LPDWORD pType,
5350                                LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5351 {
5352     HKEY hkeyPrinter, hkeySubkey;
5353     DWORD ret;
5354
5355     TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5356           debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5357           pcbNeeded);
5358
5359     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5360        != ERROR_SUCCESS)
5361         return ret;
5362
5363     if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5364        != ERROR_SUCCESS) {
5365         WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5366         RegCloseKey(hkeyPrinter);
5367         return ret;
5368     }
5369     *pcbNeeded = nSize;
5370     ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5371     RegCloseKey(hkeySubkey);
5372     RegCloseKey(hkeyPrinter);
5373     return ret;
5374 }
5375
5376 /******************************************************************************
5377  *              GetPrinterDataExW   (WINSPOOL.@)
5378  */
5379 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5380                                LPCWSTR pValueName, LPDWORD pType,
5381                                LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5382 {
5383     HKEY hkeyPrinter, hkeySubkey;
5384     DWORD ret;
5385
5386     TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5387           debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5388           pcbNeeded);
5389
5390     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5391        != ERROR_SUCCESS)
5392         return ret;
5393
5394     if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5395        != ERROR_SUCCESS) {
5396         WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5397         RegCloseKey(hkeyPrinter);
5398         return ret;
5399     }
5400     *pcbNeeded = nSize;
5401     ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5402     RegCloseKey(hkeySubkey);
5403     RegCloseKey(hkeyPrinter);
5404     return ret;
5405 }
5406
5407 /******************************************************************************
5408  *              GetPrinterDataA   (WINSPOOL.@)
5409  */
5410 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5411                              LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5412 {
5413     return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5414                              pData, nSize, pcbNeeded);
5415 }
5416
5417 /******************************************************************************
5418  *              GetPrinterDataW   (WINSPOOL.@)
5419  */
5420 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5421                              LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5422 {
5423     return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5424                              pData, nSize, pcbNeeded);
5425 }
5426
5427 /*******************************************************************************
5428  *              EnumPrinterDataExW      [WINSPOOL.@]
5429  */
5430 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5431                                 LPBYTE pEnumValues, DWORD cbEnumValues,
5432                                 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5433 {
5434     HKEY                    hkPrinter, hkSubKey;
5435     DWORD                   r, ret, dwIndex, cValues, cbMaxValueNameLen,
5436                             cbValueNameLen, cbMaxValueLen, cbValueLen,
5437                             cbBufSize, dwType;
5438     LPWSTR                  lpValueName;
5439     HANDLE                  hHeap;
5440     PBYTE                   lpValue;
5441     PPRINTER_ENUM_VALUESW   ppev;
5442
5443     TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5444
5445     if (pKeyName == NULL || *pKeyName == 0)
5446         return ERROR_INVALID_PARAMETER;
5447
5448     ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5449     if (ret != ERROR_SUCCESS)
5450     {
5451         TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5452                 hPrinter, ret);
5453         return ret;
5454     }
5455
5456     ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5457     if (ret != ERROR_SUCCESS)
5458     {
5459         r = RegCloseKey (hkPrinter);
5460         if (r != ERROR_SUCCESS)
5461             WARN ("RegCloseKey returned %i\n", r);
5462         TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5463                 debugstr_w (pKeyName), ret);
5464         return ret;
5465     }
5466
5467     ret = RegCloseKey (hkPrinter);
5468     if (ret != ERROR_SUCCESS)
5469     {
5470         ERR ("RegCloseKey returned %i\n", ret);
5471         r = RegCloseKey (hkSubKey);
5472         if (r != ERROR_SUCCESS)
5473             WARN ("RegCloseKey returned %i\n", r);
5474         return ret;
5475     }
5476
5477     ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5478             &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5479     if (ret != ERROR_SUCCESS)
5480     {
5481         r = RegCloseKey (hkSubKey);
5482         if (r != ERROR_SUCCESS)
5483             WARN ("RegCloseKey returned %i\n", r);
5484         TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5485         return ret;
5486     }
5487
5488     TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5489             "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5490
5491     if (cValues == 0)                   /* empty key */
5492     {
5493         r = RegCloseKey (hkSubKey);
5494         if (r != ERROR_SUCCESS)
5495             WARN ("RegCloseKey returned %i\n", r);
5496         *pcbEnumValues = *pnEnumValues = 0;
5497         return ERROR_SUCCESS;
5498     }
5499
5500     ++cbMaxValueNameLen;                        /* allow for trailing '\0' */
5501
5502     hHeap = GetProcessHeap ();
5503     if (hHeap == NULL)
5504     {
5505         ERR ("GetProcessHeap failed\n");
5506         r = RegCloseKey (hkSubKey);
5507         if (r != ERROR_SUCCESS)
5508             WARN ("RegCloseKey returned %i\n", r);
5509         return ERROR_OUTOFMEMORY;
5510     }
5511
5512     lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5513     if (lpValueName == NULL)
5514     {
5515         ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5516         r = RegCloseKey (hkSubKey);
5517         if (r != ERROR_SUCCESS)
5518             WARN ("RegCloseKey returned %i\n", r);
5519         return ERROR_OUTOFMEMORY;
5520     }
5521
5522     lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5523     if (lpValue == NULL)
5524     {
5525         ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5526         if (HeapFree (hHeap, 0, lpValueName) == 0)
5527             WARN ("HeapFree failed with code %i\n", GetLastError ());
5528         r = RegCloseKey (hkSubKey);
5529         if (r != ERROR_SUCCESS)
5530             WARN ("RegCloseKey returned %i\n", r);
5531         return ERROR_OUTOFMEMORY;
5532     }
5533
5534     TRACE ("pass 1: calculating buffer required for all names and values\n");
5535
5536     cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5537
5538     TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5539
5540     for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5541     {
5542         cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5543         ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5544                 NULL, NULL, lpValue, &cbValueLen);
5545         if (ret != ERROR_SUCCESS)
5546         {
5547             if (HeapFree (hHeap, 0, lpValue) == 0)
5548                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5549             if (HeapFree (hHeap, 0, lpValueName) == 0)
5550                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5551             r = RegCloseKey (hkSubKey);
5552             if (r != ERROR_SUCCESS)
5553                 WARN ("RegCloseKey returned %i\n", r);
5554             TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5555             return ret;
5556         }
5557
5558         TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5559                 debugstr_w (lpValueName), dwIndex,
5560                 cbValueNameLen + 1, cbValueLen);
5561
5562         cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5563         cbBufSize += cbValueLen;
5564     }
5565
5566     TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5567
5568     *pcbEnumValues = cbBufSize;
5569     *pnEnumValues = cValues;
5570
5571     if (cbEnumValues < cbBufSize)       /* buffer too small */
5572     {
5573         if (HeapFree (hHeap, 0, lpValue) == 0)
5574             WARN ("HeapFree failed with code %i\n", GetLastError ());
5575         if (HeapFree (hHeap, 0, lpValueName) == 0)
5576             WARN ("HeapFree failed with code %i\n", GetLastError ());
5577         r = RegCloseKey (hkSubKey);
5578         if (r != ERROR_SUCCESS)
5579             WARN ("RegCloseKey returned %i\n", r);
5580         TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5581         return ERROR_MORE_DATA;
5582     }
5583
5584     TRACE ("pass 2: copying all names and values to buffer\n");
5585
5586     ppev = (PPRINTER_ENUM_VALUESW) pEnumValues;         /* array of structs */
5587     pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5588
5589     for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5590     {
5591         cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5592         ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5593                 NULL, &dwType, lpValue, &cbValueLen);
5594         if (ret != ERROR_SUCCESS)
5595         {
5596             if (HeapFree (hHeap, 0, lpValue) == 0)
5597                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5598             if (HeapFree (hHeap, 0, lpValueName) == 0)
5599                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5600             r = RegCloseKey (hkSubKey);
5601             if (r != ERROR_SUCCESS)
5602                 WARN ("RegCloseKey returned %i\n", r);
5603             TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5604             return ret;
5605         }
5606
5607         cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5608         memcpy (pEnumValues, lpValueName, cbValueNameLen);
5609         ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5610         pEnumValues += cbValueNameLen;
5611
5612         /* return # of *bytes* (including trailing \0), not # of chars */
5613         ppev[dwIndex].cbValueName = cbValueNameLen;
5614
5615         ppev[dwIndex].dwType = dwType;
5616
5617         memcpy (pEnumValues, lpValue, cbValueLen);
5618         ppev[dwIndex].pData = pEnumValues;
5619         pEnumValues += cbValueLen;
5620
5621         ppev[dwIndex].cbData = cbValueLen;
5622
5623         TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5624                 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5625     }
5626
5627     if (HeapFree (hHeap, 0, lpValue) == 0)
5628     {
5629         ret = GetLastError ();
5630         ERR ("HeapFree failed with code %i\n", ret);
5631         if (HeapFree (hHeap, 0, lpValueName) == 0)
5632             WARN ("HeapFree failed with code %i\n", GetLastError ());
5633         r = RegCloseKey (hkSubKey);
5634         if (r != ERROR_SUCCESS)
5635             WARN ("RegCloseKey returned %i\n", r);
5636         return ret;
5637     }
5638
5639     if (HeapFree (hHeap, 0, lpValueName) == 0)
5640     {
5641         ret = GetLastError ();
5642         ERR ("HeapFree failed with code %i\n", ret);
5643         r = RegCloseKey (hkSubKey);
5644         if (r != ERROR_SUCCESS)
5645             WARN ("RegCloseKey returned %i\n", r);
5646         return ret;
5647     }
5648
5649     ret = RegCloseKey (hkSubKey);
5650     if (ret != ERROR_SUCCESS)
5651     {
5652         ERR ("RegCloseKey returned %i\n", ret);
5653         return ret;
5654     }
5655
5656     return ERROR_SUCCESS;
5657 }
5658
5659 /*******************************************************************************
5660  *              EnumPrinterDataExA      [WINSPOOL.@]
5661  *
5662  * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5663  * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers.  This is
5664  * what Windows 2000 SP1 does.
5665  *
5666  */
5667 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5668                                 LPBYTE pEnumValues, DWORD cbEnumValues,
5669                                 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5670 {
5671     INT     len;
5672     LPWSTR  pKeyNameW;
5673     DWORD   ret, dwIndex, dwBufSize;
5674     HANDLE  hHeap;
5675     LPSTR   pBuffer;
5676
5677     TRACE ("%p %s\n", hPrinter, pKeyName);
5678
5679     if (pKeyName == NULL || *pKeyName == 0)
5680         return ERROR_INVALID_PARAMETER;
5681
5682     len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5683     if (len == 0)
5684     {
5685         ret = GetLastError ();
5686         ERR ("MultiByteToWideChar failed with code %i\n", ret);
5687         return ret;
5688     }
5689
5690     hHeap = GetProcessHeap ();
5691     if (hHeap == NULL)
5692     {
5693         ERR ("GetProcessHeap failed\n");
5694         return ERROR_OUTOFMEMORY;
5695     }
5696
5697     pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5698     if (pKeyNameW == NULL)
5699     {
5700         ERR ("Failed to allocate %i bytes from process heap\n",
5701              (LONG)(len * sizeof (WCHAR)));
5702         return ERROR_OUTOFMEMORY;
5703     }
5704
5705     if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5706     {
5707         ret = GetLastError ();
5708         ERR ("MultiByteToWideChar failed with code %i\n", ret);
5709         if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5710             WARN ("HeapFree failed with code %i\n", GetLastError ());
5711         return ret;
5712     }
5713
5714     ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5715             pcbEnumValues, pnEnumValues);
5716     if (ret != ERROR_SUCCESS)
5717     {
5718         if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5719             WARN ("HeapFree failed with code %i\n", GetLastError ());
5720         TRACE ("EnumPrinterDataExW returned %i\n", ret);
5721         return ret;
5722     }
5723
5724     if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5725     {
5726         ret = GetLastError ();
5727         ERR ("HeapFree failed with code %i\n", ret);
5728         return ret;
5729     }
5730
5731     if (*pnEnumValues == 0)     /* empty key */
5732         return ERROR_SUCCESS;
5733
5734     dwBufSize = 0;
5735     for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5736     {
5737         PPRINTER_ENUM_VALUESW ppev =
5738                 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5739
5740         if (dwBufSize < ppev->cbValueName)
5741             dwBufSize = ppev->cbValueName;
5742
5743         if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5744                 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5745             dwBufSize = ppev->cbData;
5746     }
5747
5748     TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5749
5750     pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5751     if (pBuffer == NULL)
5752     {
5753         ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5754         return ERROR_OUTOFMEMORY;
5755     }
5756
5757     for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5758     {
5759         PPRINTER_ENUM_VALUESW ppev =
5760                 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5761
5762         len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5763                 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5764                 NULL);
5765         if (len == 0)
5766         {
5767             ret = GetLastError ();
5768             ERR ("WideCharToMultiByte failed with code %i\n", ret);
5769             if (HeapFree (hHeap, 0, pBuffer) == 0)
5770                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5771             return ret;
5772         }
5773
5774         memcpy (ppev->pValueName, pBuffer, len);
5775
5776         TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5777
5778         if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5779                 ppev->dwType != REG_MULTI_SZ)
5780             continue;
5781
5782         len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5783                 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5784         if (len == 0)
5785         {
5786             ret = GetLastError ();
5787             ERR ("WideCharToMultiByte failed with code %i\n", ret);
5788             if (HeapFree (hHeap, 0, pBuffer) == 0)
5789                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5790             return ret;
5791         }
5792
5793         memcpy (ppev->pData, pBuffer, len);
5794
5795         TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5796         TRACE ("  (only first string of REG_MULTI_SZ printed)\n");
5797     }
5798
5799     if (HeapFree (hHeap, 0, pBuffer) == 0)
5800     {
5801         ret = GetLastError ();
5802         ERR ("HeapFree failed with code %i\n", ret);
5803         return ret;
5804     }
5805
5806     return ERROR_SUCCESS;
5807 }
5808
5809 /******************************************************************************
5810  *      AbortPrinter (WINSPOOL.@)
5811  */
5812 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5813 {
5814     FIXME("(%p), stub!\n", hPrinter);
5815     return TRUE;
5816 }
5817
5818 /******************************************************************************
5819  *              AddPortA (WINSPOOL.@)
5820  *
5821  * See AddPortW.
5822  *
5823  */
5824 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5825 {
5826     LPWSTR  nameW = NULL;
5827     LPWSTR  monitorW = NULL;
5828     DWORD   len;
5829     BOOL    res;
5830
5831     TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5832
5833     if (pName) {
5834         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5835         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5836         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5837     }
5838
5839     if (pMonitorName) {
5840         len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5841         monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5842         MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5843     }
5844     res = AddPortW(nameW, hWnd, monitorW);
5845     HeapFree(GetProcessHeap(), 0, nameW);
5846     HeapFree(GetProcessHeap(), 0, monitorW);
5847     return res;
5848 }
5849
5850 /******************************************************************************
5851  *      AddPortW (WINSPOOL.@)
5852  *
5853  * Add a Port for a specific Monitor
5854  *
5855  * PARAMS
5856  *  pName        [I] Servername or NULL (local Computer)
5857  *  hWnd         [I] Handle to parent Window for the Dialog-Box
5858  *  pMonitorName [I] Name of the Monitor that manage the Port
5859  *
5860  * RETURNS
5861  *  Success: TRUE
5862  *  Failure: FALSE
5863  *
5864  */
5865 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5866 {
5867     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5868
5869     if ((backend == NULL)  && !load_backend()) return FALSE;
5870
5871     if (!pMonitorName) {
5872         SetLastError(RPC_X_NULL_REF_POINTER);
5873         return FALSE;
5874     }
5875
5876     return backend->fpAddPort(pName, hWnd, pMonitorName);
5877 }
5878
5879 /******************************************************************************
5880  *             AddPortExA (WINSPOOL.@)
5881  *
5882  * See AddPortExW.
5883  *
5884  */
5885 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5886 {
5887     PORT_INFO_2W   pi2W;
5888     PORT_INFO_2A * pi2A;
5889     LPWSTR  nameW = NULL;
5890     LPWSTR  monitorW = NULL;
5891     DWORD   len;
5892     BOOL    res;
5893
5894     pi2A = (PORT_INFO_2A *) pBuffer;
5895
5896     TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5897             debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5898
5899     if ((level < 1) || (level > 2)) {
5900         SetLastError(ERROR_INVALID_LEVEL);
5901         return FALSE;
5902     }
5903
5904     if (!pi2A) {
5905         SetLastError(ERROR_INVALID_PARAMETER);
5906         return FALSE;
5907     }
5908
5909     if (pName) {
5910         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5911         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5912         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5913     }
5914
5915     if (pMonitorName) {
5916         len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5917         monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5918         MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5919     }
5920
5921     ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5922
5923     if (pi2A->pPortName) {
5924         len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5925         pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5926         MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
5927     }
5928
5929     if (level > 1) {
5930         if (pi2A->pMonitorName) {
5931             len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
5932             pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5933             MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
5934         }
5935
5936         if (pi2A->pDescription) {
5937             len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
5938             pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5939             MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
5940         }
5941         pi2W.fPortType = pi2A->fPortType;
5942         pi2W.Reserved = pi2A->Reserved;
5943     }
5944
5945     res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
5946
5947     HeapFree(GetProcessHeap(), 0, nameW);
5948     HeapFree(GetProcessHeap(), 0, monitorW);
5949     HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
5950     HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
5951     HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
5952     return res;
5953
5954 }
5955
5956 /******************************************************************************
5957  *             AddPortExW (WINSPOOL.@)
5958  *
5959  * Add a Port for a specific Monitor, without presenting a user interface
5960  *
5961  * PARAMS
5962  *  pName         [I] Servername or NULL (local Computer)
5963  *  level         [I] Structure-Level (1 or 2) for pBuffer
5964  *  pBuffer       [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5965  *  pMonitorName  [I] Name of the Monitor that manage the Port
5966  *
5967  * RETURNS
5968  *  Success: TRUE
5969  *  Failure: FALSE
5970  *
5971  */
5972 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
5973 {
5974     PORT_INFO_2W * pi2;
5975
5976     pi2 = (PORT_INFO_2W *) pBuffer;
5977
5978     TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
5979             debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
5980             debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
5981             debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
5982
5983     if ((backend == NULL)  && !load_backend()) return FALSE;
5984
5985     if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
5986         SetLastError(ERROR_INVALID_PARAMETER);
5987         return FALSE;
5988     }
5989
5990     return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
5991 }
5992
5993 /******************************************************************************
5994  *      AddPrinterConnectionA (WINSPOOL.@)
5995  */
5996 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5997 {
5998     FIXME("%s\n", debugstr_a(pName));
5999     return FALSE;
6000 }
6001
6002 /******************************************************************************
6003  *      AddPrinterConnectionW (WINSPOOL.@)
6004  */
6005 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6006 {
6007     FIXME("%s\n", debugstr_w(pName));
6008     return FALSE;
6009 }
6010
6011 /******************************************************************************
6012  *  AddPrinterDriverExW (WINSPOOL.@)
6013  *
6014  * Install a Printer Driver with the Option to upgrade / downgrade the Files
6015  *
6016  * PARAMS
6017  *  pName           [I] Servername or NULL (local Computer)
6018  *  level           [I] Level for the supplied DRIVER_INFO_*W struct
6019  *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6020  *  dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6021  *
6022  * RESULTS
6023  *  Success: TRUE
6024  *  Failure: FALSE
6025  *
6026  */
6027 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6028 {
6029     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6030
6031     if ((backend == NULL)  && !load_backend()) return FALSE;
6032
6033     if (level < 2 || level == 5 || level == 7 || level > 8) {
6034         SetLastError(ERROR_INVALID_LEVEL);
6035         return FALSE;
6036     }
6037
6038     if (!pDriverInfo) {
6039         SetLastError(ERROR_INVALID_PARAMETER);
6040         return FALSE;
6041     }
6042
6043     return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6044 }
6045
6046 /******************************************************************************
6047  *  AddPrinterDriverExA (WINSPOOL.@)
6048  *
6049  * See AddPrinterDriverExW.
6050  *
6051  */
6052 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6053 {
6054     DRIVER_INFO_8A  *diA;
6055     DRIVER_INFO_8W   diW;
6056     LPWSTR  nameW = NULL;
6057     DWORD   lenA;
6058     DWORD   len;
6059     DWORD   res = FALSE;
6060
6061     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6062
6063     diA = (DRIVER_INFO_8A  *) pDriverInfo;
6064     ZeroMemory(&diW, sizeof(diW));
6065
6066     if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6067         SetLastError(ERROR_INVALID_LEVEL);
6068         return FALSE;
6069     }
6070
6071     if (diA == NULL) {
6072         SetLastError(ERROR_INVALID_PARAMETER);
6073         return FALSE;
6074     }
6075
6076     /* convert servername to unicode */
6077     if (pName) {
6078         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6079         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6080         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6081     }
6082
6083     /* common fields */
6084     diW.cVersion = diA->cVersion;
6085
6086     if (diA->pName) {
6087         len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6088         diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6089         MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6090     }
6091
6092     if (diA->pEnvironment) {
6093         len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6094         diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6095         MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6096     }
6097
6098     if (diA->pDriverPath) {
6099         len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6100         diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6101         MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6102     }
6103
6104     if (diA->pDataFile) {
6105         len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6106         diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6107         MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6108     }
6109
6110     if (diA->pConfigFile) {
6111         len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6112         diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6113         MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6114     }
6115
6116     if ((Level > 2) && diA->pDependentFiles) {
6117         lenA = multi_sz_lenA(diA->pDependentFiles);
6118         len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6119         diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6120         MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6121     }
6122
6123     if ((Level > 2) && diA->pMonitorName) {
6124         len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6125         diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6126         MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6127     }
6128
6129     if ((Level > 3) && diA->pDefaultDataType) {
6130         len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6131         diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6132         MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6133     }
6134
6135     if ((Level > 3) && diA->pszzPreviousNames) {
6136         lenA = multi_sz_lenA(diA->pszzPreviousNames);
6137         len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6138         diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6139         MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6140     }
6141
6142     if ((Level > 5) && diA->pszMfgName) {
6143         len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6144         diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6145         MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6146     }
6147
6148     if ((Level > 5) && diA->pszOEMUrl) {
6149         len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6150         diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6151         MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6152     }
6153
6154     if ((Level > 5) && diA->pszHardwareID) {
6155         len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6156         diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6157         MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6158     }
6159
6160     if ((Level > 5) && diA->pszProvider) {
6161         len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6162         diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6163         MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6164     }
6165
6166     if (Level > 7) {
6167         FIXME("level %u is incomplete\n", Level);
6168     }
6169
6170     res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6171     TRACE("got %u with %u\n", res, GetLastError());
6172     HeapFree(GetProcessHeap(), 0, nameW);
6173     HeapFree(GetProcessHeap(), 0, diW.pName);
6174     HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6175     HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6176     HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6177     HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6178     HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6179     HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6180     HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6181     HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6182     HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6183     HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6184     HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6185     HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6186
6187     TRACE("=> %u with %u\n", res, GetLastError());
6188     return res;
6189 }
6190
6191 /******************************************************************************
6192  *      ConfigurePortA (WINSPOOL.@)
6193  *
6194  * See ConfigurePortW.
6195  *
6196  */
6197 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6198 {
6199     LPWSTR  nameW = NULL;
6200     LPWSTR  portW = NULL;
6201     INT     len;
6202     DWORD   res;
6203
6204     TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6205
6206     /* convert servername to unicode */
6207     if (pName) {
6208         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6209         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6210         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6211     }
6212
6213     /* convert portname to unicode */
6214     if (pPortName) {
6215         len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6216         portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6217         MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6218     }
6219
6220     res = ConfigurePortW(nameW, hWnd, portW);
6221     HeapFree(GetProcessHeap(), 0, nameW);
6222     HeapFree(GetProcessHeap(), 0, portW);
6223     return res;
6224 }
6225
6226 /******************************************************************************
6227  *      ConfigurePortW (WINSPOOL.@)
6228  *
6229  * Display the Configuration-Dialog for a specific Port
6230  *
6231  * PARAMS
6232  *  pName     [I] Servername or NULL (local Computer)
6233  *  hWnd      [I] Handle to parent Window for the Dialog-Box
6234  *  pPortName [I] Name of the Port, that should be configured
6235  *
6236  * RETURNS
6237  *  Success: TRUE
6238  *  Failure: FALSE
6239  *
6240  */
6241 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6242 {
6243
6244     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6245
6246     if ((backend == NULL)  && !load_backend()) return FALSE;
6247
6248     if (!pPortName) {
6249         SetLastError(RPC_X_NULL_REF_POINTER);
6250         return FALSE;
6251     }
6252
6253     return backend->fpConfigurePort(pName, hWnd, pPortName);
6254 }
6255
6256 /******************************************************************************
6257  *      ConnectToPrinterDlg (WINSPOOL.@)
6258  */
6259 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6260 {
6261     FIXME("%p %x\n", hWnd, Flags);
6262     return NULL;
6263 }
6264
6265 /******************************************************************************
6266  *      DeletePrinterConnectionA (WINSPOOL.@)
6267  */
6268 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6269 {
6270     FIXME("%s\n", debugstr_a(pName));
6271     return TRUE;
6272 }
6273
6274 /******************************************************************************
6275  *      DeletePrinterConnectionW (WINSPOOL.@)
6276  */
6277 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6278 {
6279     FIXME("%s\n", debugstr_w(pName));
6280     return TRUE;
6281 }
6282
6283 /******************************************************************************
6284  *              DeletePrinterDriverExW (WINSPOOL.@)
6285  */
6286 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6287     LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6288 {
6289     HKEY hkey_drivers;
6290     BOOL ret = FALSE;
6291
6292     TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6293           debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6294
6295     if(pName && pName[0])
6296     {
6297         FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6298         SetLastError(ERROR_INVALID_PARAMETER);
6299         return FALSE;
6300     }
6301
6302     if(dwDeleteFlag)
6303     {
6304         FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6305         SetLastError(ERROR_INVALID_PARAMETER);
6306         return FALSE;
6307     }
6308
6309     hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6310
6311     if(!hkey_drivers)
6312     {
6313         ERR("Can't open drivers key\n");
6314         return FALSE;
6315     }
6316
6317     if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6318         ret = TRUE;
6319
6320     RegCloseKey(hkey_drivers);
6321
6322     return ret;
6323 }
6324
6325 /******************************************************************************
6326  *              DeletePrinterDriverExA (WINSPOOL.@)
6327  */
6328 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6329     LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6330 {
6331     UNICODE_STRING NameW, EnvW, DriverW;
6332     BOOL ret;
6333
6334     asciitounicode(&NameW, pName);
6335     asciitounicode(&EnvW, pEnvironment);
6336     asciitounicode(&DriverW, pDriverName);
6337
6338     ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6339
6340     RtlFreeUnicodeString(&DriverW);
6341     RtlFreeUnicodeString(&EnvW);
6342     RtlFreeUnicodeString(&NameW);
6343
6344     return ret;
6345 }
6346
6347 /******************************************************************************
6348  *              DeletePrinterDataExW (WINSPOOL.@)
6349  */
6350 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6351                                   LPCWSTR pValueName)
6352 {
6353     FIXME("%p %s %s\n", hPrinter, 
6354           debugstr_w(pKeyName), debugstr_w(pValueName));
6355     return ERROR_INVALID_PARAMETER;
6356 }
6357
6358 /******************************************************************************
6359  *              DeletePrinterDataExA (WINSPOOL.@)
6360  */
6361 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6362                                   LPCSTR pValueName)
6363 {
6364     FIXME("%p %s %s\n", hPrinter, 
6365           debugstr_a(pKeyName), debugstr_a(pValueName));
6366     return ERROR_INVALID_PARAMETER;
6367 }
6368
6369 /******************************************************************************
6370  *      DeletePrintProcessorA (WINSPOOL.@)
6371  */
6372 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6373 {
6374     FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6375           debugstr_a(pPrintProcessorName));
6376     return TRUE;
6377 }
6378
6379 /******************************************************************************
6380  *      DeletePrintProcessorW (WINSPOOL.@)
6381  */
6382 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6383 {
6384     FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6385           debugstr_w(pPrintProcessorName));
6386     return TRUE;
6387 }
6388
6389 /******************************************************************************
6390  *      DeletePrintProvidorA (WINSPOOL.@)
6391  */
6392 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6393 {
6394     FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6395           debugstr_a(pPrintProviderName));
6396     return TRUE;
6397 }
6398
6399 /******************************************************************************
6400  *      DeletePrintProvidorW (WINSPOOL.@)
6401  */
6402 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6403 {
6404     FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6405           debugstr_w(pPrintProviderName));
6406     return TRUE;
6407 }
6408
6409 /******************************************************************************
6410  *      EnumFormsA (WINSPOOL.@)
6411  */
6412 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6413     DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6414 {
6415     FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6416     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6417     return FALSE;
6418 }
6419
6420 /******************************************************************************
6421  *      EnumFormsW (WINSPOOL.@)
6422  */
6423 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6424     DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6425 {
6426     FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6427     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6428     return FALSE;
6429 }
6430
6431 /*****************************************************************************
6432  *          EnumMonitorsA [WINSPOOL.@]
6433  *
6434  * See EnumMonitorsW.
6435  *
6436  */
6437 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6438                           DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6439 {
6440     BOOL    res;
6441     LPBYTE  bufferW = NULL;
6442     LPWSTR  nameW = NULL;
6443     DWORD   needed = 0;
6444     DWORD   numentries = 0;
6445     INT     len;
6446
6447     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6448           cbBuf, pcbNeeded, pcReturned);
6449
6450     /* convert servername to unicode */
6451     if (pName) {
6452         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6453         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6454         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6455     }
6456     /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6457     needed = cbBuf * sizeof(WCHAR);    
6458     if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6459     res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6460
6461     if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6462         if (pcbNeeded) needed = *pcbNeeded;
6463         /* HeapReAlloc return NULL, when bufferW was NULL */
6464         bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6465                               HeapAlloc(GetProcessHeap(), 0, needed);
6466
6467         /* Try again with the large Buffer */
6468         res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6469     }
6470     numentries = pcReturned ? *pcReturned : 0;
6471     needed = 0;
6472     /*
6473        W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6474        We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6475      */
6476     if (res) {
6477         /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6478         DWORD   entrysize = 0;
6479         DWORD   index;
6480         LPSTR   ptr;
6481         LPMONITOR_INFO_2W mi2w;
6482         LPMONITOR_INFO_2A mi2a;
6483
6484         /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6485         entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6486
6487         /* First pass: calculate the size for all Entries */
6488         mi2w = (LPMONITOR_INFO_2W) bufferW;
6489         mi2a = (LPMONITOR_INFO_2A) pMonitors;
6490         index = 0;
6491         while (index < numentries) {
6492             index++;
6493             needed += entrysize;    /* MONITOR_INFO_?A */
6494             TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6495
6496             needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6497                                             NULL, 0, NULL, NULL);
6498             if (Level > 1) {
6499                 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6500                                                 NULL, 0, NULL, NULL);
6501                 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6502                                                 NULL, 0, NULL, NULL);
6503             }
6504             /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6505             mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6506             mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6507         }
6508
6509         /* check for errors and quit on failure */
6510         if (cbBuf < needed) {
6511             SetLastError(ERROR_INSUFFICIENT_BUFFER);
6512             res = FALSE;
6513             goto emA_cleanup;
6514         }
6515         len = entrysize * numentries;       /* room for all MONITOR_INFO_?A */
6516         ptr = (LPSTR) &pMonitors[len];      /* room for strings */
6517         cbBuf -= len ;                      /* free Bytes in the user-Buffer */
6518         mi2w = (LPMONITOR_INFO_2W) bufferW;
6519         mi2a = (LPMONITOR_INFO_2A) pMonitors;
6520         index = 0;
6521         /* Second Pass: Fill the User Buffer (if we have one) */
6522         while ((index < numentries) && pMonitors) {
6523             index++;
6524             TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6525             mi2a->pName = ptr;
6526             len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6527                                             ptr, cbBuf , NULL, NULL);
6528             ptr += len;
6529             cbBuf -= len;
6530             if (Level > 1) {
6531                 mi2a->pEnvironment = ptr;
6532                 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6533                                             ptr, cbBuf, NULL, NULL);
6534                 ptr += len;
6535                 cbBuf -= len;
6536
6537                 mi2a->pDLLName = ptr;
6538                 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6539                                             ptr, cbBuf, NULL, NULL);
6540                 ptr += len;
6541                 cbBuf -= len;
6542             }
6543             /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6544             mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6545             mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6546         }
6547     }
6548 emA_cleanup:
6549     if (pcbNeeded)  *pcbNeeded = needed;
6550     if (pcReturned) *pcReturned = (res) ? numentries : 0;
6551
6552     HeapFree(GetProcessHeap(), 0, nameW);
6553     HeapFree(GetProcessHeap(), 0, bufferW);
6554
6555     TRACE("returning %d with %d (%d byte for %d entries)\n", 
6556             (res), GetLastError(), needed, numentries);
6557
6558     return (res);
6559
6560 }
6561
6562 /*****************************************************************************
6563  *          EnumMonitorsW [WINSPOOL.@]
6564  *
6565  * Enumerate available Port-Monitors
6566  *
6567  * PARAMS
6568  *  pName       [I] Servername or NULL (local Computer)
6569  *  Level       [I] Structure-Level (1:Win9x+NT or 2:NT only)
6570  *  pMonitors   [O] PTR to Buffer that receives the Result
6571  *  cbBuf       [I] Size of Buffer at pMonitors
6572  *  pcbNeeded   [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6573  *  pcReturned  [O] PTR to DWORD that receives the number of Monitors in pMonitors
6574  *
6575  * RETURNS
6576  *  Success: TRUE
6577  *  Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6578  *
6579  */
6580 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6581                           DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6582 {
6583
6584     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6585           cbBuf, pcbNeeded, pcReturned);
6586
6587     if ((backend == NULL)  && !load_backend()) return FALSE;
6588
6589     if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6590         SetLastError(RPC_X_NULL_REF_POINTER);
6591         return FALSE;
6592     }
6593
6594     return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6595 }
6596
6597 /******************************************************************************
6598  * SpoolerInit (WINSPOOL.@)
6599  *
6600  * Initialize the Spooler
6601  *
6602  * RETURNS
6603  *  Success: TRUE
6604  *  Failure: FALSE
6605  *
6606  * NOTES
6607  *  The function fails on windows, when the spooler service is not running
6608  *
6609  */
6610 BOOL WINAPI SpoolerInit(void)
6611 {
6612
6613     if ((backend == NULL)  && !load_backend()) return FALSE;
6614     return TRUE;
6615 }
6616
6617 /******************************************************************************
6618  *              XcvDataW (WINSPOOL.@)
6619  *
6620  * Execute commands in the Printmonitor DLL
6621  *
6622  * PARAMS
6623  *  hXcv            [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6624  *  pszDataName     [i] Name of the command to execute
6625  *  pInputData      [i] Buffer for extra Input Data (needed only for some commands)
6626  *  cbInputData     [i] Size in Bytes of Buffer at pInputData
6627  *  pOutputData     [o] Buffer to receive additional Data (needed only for some commands)
6628  *  cbOutputData    [i] Size in Bytes of Buffer at pOutputData
6629  *  pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6630  *  pdwStatus       [o] PTR to receive the win32 error code from the Printmonitor DLL
6631  *
6632  * RETURNS
6633  *  Success: TRUE
6634  *  Failure: FALSE
6635  *
6636  * NOTES
6637  *  Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6638  *  The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6639  *
6640  *  Minimal List of commands, that a Printmonitor DLL should support:
6641  *
6642  *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6643  *| "AddPort"   : Add a Port
6644  *| "DeletePort": Delete a Port
6645  *
6646  *  Many Printmonitors support additional commands. Examples for localspl.dll:
6647  *  "GetDefaultCommConfig", "SetDefaultCommConfig",
6648  *  "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6649  *
6650  */
6651 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6652     DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6653     PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6654 {
6655     opened_printer_t *printer;
6656
6657     TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6658           pInputData, cbInputData, pOutputData,
6659           cbOutputData, pcbOutputNeeded, pdwStatus);
6660
6661     if ((backend == NULL)  && !load_backend()) return FALSE;
6662
6663     printer = get_opened_printer(hXcv);
6664     if (!printer || (!printer->backend_printer)) {
6665         SetLastError(ERROR_INVALID_HANDLE);
6666         return FALSE;
6667     }
6668
6669     if (!pcbOutputNeeded) {
6670         SetLastError(ERROR_INVALID_PARAMETER);
6671         return FALSE;
6672     }
6673
6674     if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6675         SetLastError(RPC_X_NULL_REF_POINTER);
6676         return FALSE;
6677     }
6678
6679     *pcbOutputNeeded = 0;
6680
6681     return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6682                     cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6683
6684 }
6685
6686 /*****************************************************************************
6687  *          EnumPrinterDataA [WINSPOOL.@]
6688  *
6689  */
6690 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6691     DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6692     DWORD cbData, LPDWORD pcbData )
6693 {
6694     FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6695           cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6696     return ERROR_NO_MORE_ITEMS;
6697 }
6698
6699 /*****************************************************************************
6700  *          EnumPrinterDataW [WINSPOOL.@]
6701  *
6702  */
6703 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6704     DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6705     DWORD cbData, LPDWORD pcbData )
6706 {
6707     FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6708           cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6709     return ERROR_NO_MORE_ITEMS;
6710 }
6711
6712 /*****************************************************************************
6713  *          EnumPrintProcessorDatatypesA [WINSPOOL.@]
6714  *
6715  */
6716 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6717                                          DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6718                                          LPDWORD pcbNeeded, LPDWORD pcReturned)
6719 {
6720     FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6721           debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6722           pcbNeeded, pcReturned);
6723     return FALSE;
6724 }
6725
6726 /*****************************************************************************
6727  *          EnumPrintProcessorDatatypesW [WINSPOOL.@]
6728  *
6729  */
6730 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6731                                          DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6732                                          LPDWORD pcbNeeded, LPDWORD pcReturned)
6733 {
6734     FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6735           debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6736           pcbNeeded, pcReturned);
6737     return FALSE;
6738 }
6739
6740 /*****************************************************************************
6741  *          EnumPrintProcessorsA [WINSPOOL.@]
6742  *
6743  * See EnumPrintProcessorsW.
6744  *
6745  */
6746 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level, 
6747                             LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6748 {
6749     BOOL    res;
6750     LPBYTE  bufferW = NULL;
6751     LPWSTR  nameW = NULL;
6752     LPWSTR  envW = NULL;
6753     DWORD   needed = 0;
6754     DWORD   numentries = 0;
6755     INT     len;
6756
6757     TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6758                 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6759
6760     /* convert names to unicode */
6761     if (pName) {
6762         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6763         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6764         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6765     }
6766     if (pEnvironment) {
6767         len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6768         envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6769         MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6770     }
6771
6772     /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6773     needed = cbBuf * sizeof(WCHAR);
6774     if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6775     res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6776
6777     if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6778         if (pcbNeeded) needed = *pcbNeeded;
6779         /* HeapReAlloc return NULL, when bufferW was NULL */
6780         bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6781                               HeapAlloc(GetProcessHeap(), 0, needed);
6782
6783         /* Try again with the large Buffer */
6784         res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6785     }
6786     numentries = pcReturned ? *pcReturned : 0;
6787     needed = 0;
6788
6789     if (res) {
6790         /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6791         DWORD   index;
6792         LPSTR   ptr;
6793         PPRINTPROCESSOR_INFO_1W ppiw;
6794         PPRINTPROCESSOR_INFO_1A ppia;
6795
6796         /* First pass: calculate the size for all Entries */
6797         ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6798         ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6799         index = 0;
6800         while (index < numentries) {
6801             index++;
6802             needed += sizeof(PRINTPROCESSOR_INFO_1A);
6803             TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6804
6805             needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6806                                             NULL, 0, NULL, NULL);
6807
6808             ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6809             ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6810         }
6811
6812         /* check for errors and quit on failure */
6813         if (cbBuf < needed) {
6814             SetLastError(ERROR_INSUFFICIENT_BUFFER);
6815             res = FALSE;
6816             goto epp_cleanup;
6817         }
6818
6819         len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6820         ptr = (LPSTR) &pPPInfo[len];        /* start of strings */
6821         cbBuf -= len ;                      /* free Bytes in the user-Buffer */
6822         ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6823         ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6824         index = 0;
6825         /* Second Pass: Fill the User Buffer (if we have one) */
6826         while ((index < numentries) && pPPInfo) {
6827             index++;
6828             TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6829             ppia->pName = ptr;
6830             len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6831                                             ptr, cbBuf , NULL, NULL);
6832             ptr += len;
6833             cbBuf -= len;
6834
6835             ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6836             ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6837
6838         }
6839     }
6840 epp_cleanup:
6841     if (pcbNeeded)  *pcbNeeded = needed;
6842     if (pcReturned) *pcReturned = (res) ? numentries : 0;
6843
6844     HeapFree(GetProcessHeap(), 0, nameW);
6845     HeapFree(GetProcessHeap(), 0, envW);
6846     HeapFree(GetProcessHeap(), 0, bufferW);
6847
6848     TRACE("returning %d with %d (%d byte for %d entries)\n",
6849             (res), GetLastError(), needed, numentries);
6850
6851     return (res);
6852 }
6853
6854 /*****************************************************************************
6855  *          EnumPrintProcessorsW [WINSPOOL.@]
6856  *
6857  * Enumerate available Print Processors
6858  *
6859  * PARAMS
6860  *  pName        [I] Servername or NULL (local Computer)
6861  *  pEnvironment [I] Printing-Environment or NULL (Default)
6862  *  Level        [I] Structure-Level (Only 1 is allowed)
6863  *  pPPInfo      [O] PTR to Buffer that receives the Result
6864  *  cbBuf        [I] Size of Buffer at pPPInfo
6865  *  pcbNeeded    [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6866  *  pcReturned   [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6867  *
6868  * RETURNS
6869  *  Success: TRUE
6870  *  Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6871  *
6872  */
6873 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6874                             LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6875 {
6876
6877     TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
6878                                 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6879
6880     if ((backend == NULL)  && !load_backend()) return FALSE;
6881
6882     if (!pcbNeeded || !pcReturned) {
6883         SetLastError(RPC_X_NULL_REF_POINTER);
6884         return FALSE;
6885     }
6886
6887     if (!pPPInfo && (cbBuf > 0)) {
6888         SetLastError(ERROR_INVALID_USER_BUFFER);
6889         return FALSE;
6890     }
6891
6892     return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
6893                                           cbBuf, pcbNeeded, pcReturned);
6894 }
6895
6896 /*****************************************************************************
6897  *          ExtDeviceMode [WINSPOOL.@]
6898  *
6899  */
6900 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6901     LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6902     DWORD fMode)
6903 {
6904     FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6905           debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6906           debugstr_a(pProfile), fMode);
6907     return -1;
6908 }
6909
6910 /*****************************************************************************
6911  *          FindClosePrinterChangeNotification [WINSPOOL.@]
6912  *
6913  */
6914 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6915 {
6916     FIXME("Stub: %p\n", hChange);
6917     return TRUE;
6918 }
6919
6920 /*****************************************************************************
6921  *          FindFirstPrinterChangeNotification [WINSPOOL.@]
6922  *
6923  */
6924 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6925     DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6926 {
6927     FIXME("Stub: %p %x %x %p\n",
6928           hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6929     return INVALID_HANDLE_VALUE;
6930 }
6931
6932 /*****************************************************************************
6933  *          FindNextPrinterChangeNotification [WINSPOOL.@]
6934  *
6935  */
6936 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6937     LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6938 {
6939     FIXME("Stub: %p %p %p %p\n",
6940           hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6941     return FALSE;
6942 }
6943
6944 /*****************************************************************************
6945  *          FreePrinterNotifyInfo [WINSPOOL.@]
6946  *
6947  */
6948 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6949 {
6950     FIXME("Stub: %p\n", pPrinterNotifyInfo);
6951     return TRUE;
6952 }
6953
6954 /*****************************************************************************
6955  *          string_to_buf
6956  *
6957  * Copies a unicode string into a buffer.  The buffer will either contain unicode or
6958  * ansi depending on the unicode parameter.
6959  */
6960 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6961 {
6962     if(!str)
6963     {
6964         *size = 0;
6965         return TRUE;
6966     }
6967
6968     if(unicode)
6969     {
6970         *size = (strlenW(str) + 1) * sizeof(WCHAR);
6971         if(*size <= cb)
6972         {
6973             memcpy(ptr, str, *size);
6974             return TRUE;
6975         }
6976         return FALSE;
6977     }
6978     else
6979     {
6980         *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6981         if(*size <= cb)
6982         {
6983             WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6984             return TRUE;
6985         }
6986         return FALSE;
6987     }
6988 }
6989
6990 /*****************************************************************************
6991  *          get_job_info_1
6992  */
6993 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6994                            LPDWORD pcbNeeded, BOOL unicode)
6995 {
6996     DWORD size, left = cbBuf;
6997     BOOL space = (cbBuf > 0);
6998     LPBYTE ptr = buf;
6999
7000     *pcbNeeded = 0;
7001
7002     if(space)
7003     {
7004         ji1->JobId = job->job_id;
7005     }
7006
7007     string_to_buf(job->document_title, ptr, left, &size, unicode);
7008     if(space && size <= left)
7009     {
7010         ji1->pDocument = (LPWSTR)ptr;
7011         ptr += size;
7012         left -= size;
7013     }
7014     else
7015         space = FALSE;
7016     *pcbNeeded += size;
7017
7018     return space;
7019 }
7020
7021 /*****************************************************************************
7022  *          get_job_info_2
7023  */
7024 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7025                            LPDWORD pcbNeeded, BOOL unicode)
7026 {
7027     DWORD size, left = cbBuf;
7028     BOOL space = (cbBuf > 0);
7029     LPBYTE ptr = buf;
7030
7031     *pcbNeeded = 0;
7032
7033     if(space)
7034     {
7035         ji2->JobId = job->job_id;
7036     }
7037
7038     string_to_buf(job->document_title, ptr, left, &size, unicode);
7039     if(space && size <= left)
7040     {
7041         ji2->pDocument = (LPWSTR)ptr;
7042         ptr += size;
7043         left -= size;
7044     }
7045     else
7046         space = FALSE;
7047     *pcbNeeded += size;
7048
7049     return space;
7050 }
7051
7052 /*****************************************************************************
7053  *          get_job_info
7054  */
7055 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7056                          DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7057 {
7058     BOOL ret = FALSE;
7059     DWORD needed = 0, size;
7060     job_t *job;
7061     LPBYTE ptr = pJob;
7062
7063     TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7064
7065     EnterCriticalSection(&printer_handles_cs);
7066     job = get_job(hPrinter, JobId);
7067     if(!job)
7068         goto end;
7069
7070     switch(Level)
7071     {
7072     case 1:
7073         size = sizeof(JOB_INFO_1W);
7074         if(cbBuf >= size)
7075         {
7076             cbBuf -= size;
7077             ptr += size;
7078             memset(pJob, 0, size);
7079         }
7080         else
7081             cbBuf = 0;
7082         ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7083         needed += size;
7084         break;
7085
7086     case 2:
7087         size = sizeof(JOB_INFO_2W);
7088         if(cbBuf >= size)
7089         {
7090             cbBuf -= size;
7091             ptr += size;
7092             memset(pJob, 0, size);
7093         }
7094         else
7095             cbBuf = 0;
7096         ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7097         needed += size;
7098         break;
7099
7100     case 3:
7101         size = sizeof(JOB_INFO_3);
7102         if(cbBuf >= size)
7103         {
7104             cbBuf -= size;
7105             memset(pJob, 0, size);
7106             ret = TRUE;
7107         }
7108         else
7109             cbBuf = 0;
7110         needed = size;
7111         break;
7112
7113     default:
7114         SetLastError(ERROR_INVALID_LEVEL);
7115         goto end;
7116     }
7117     if(pcbNeeded)
7118         *pcbNeeded = needed;
7119 end:
7120     LeaveCriticalSection(&printer_handles_cs);
7121     return ret;
7122 }
7123
7124 /*****************************************************************************
7125  *          GetJobA [WINSPOOL.@]
7126  *
7127  */
7128 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7129                     DWORD cbBuf, LPDWORD pcbNeeded)
7130 {
7131     return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7132 }
7133
7134 /*****************************************************************************
7135  *          GetJobW [WINSPOOL.@]
7136  *
7137  */
7138 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7139                     DWORD cbBuf, LPDWORD pcbNeeded)
7140 {
7141     return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7142 }
7143
7144 /*****************************************************************************
7145  *          schedule_lpr
7146  */
7147 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7148 {
7149     char *unixname, *queue, *cmd;
7150     char fmt[] = "lpr -P%s %s";
7151     DWORD len;
7152     int r;
7153
7154     if(!(unixname = wine_get_unix_file_name(filename)))
7155         return FALSE;
7156
7157     len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7158     queue = HeapAlloc(GetProcessHeap(), 0, len);
7159     WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7160
7161     cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7162     sprintf(cmd, fmt, queue, unixname);
7163
7164     TRACE("printing with: %s\n", cmd);
7165     r = system(cmd);
7166
7167     HeapFree(GetProcessHeap(), 0, cmd);
7168     HeapFree(GetProcessHeap(), 0, queue);
7169     HeapFree(GetProcessHeap(), 0, unixname);
7170     return (r == 0);
7171 }
7172
7173 /*****************************************************************************
7174  *          schedule_cups
7175  */
7176 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7177 {
7178 #ifdef SONAME_LIBCUPS
7179     if(pcupsPrintFile)
7180     {
7181         char *unixname, *queue, *unix_doc_title;
7182         DWORD len;
7183         BOOL ret;
7184
7185         if(!(unixname = wine_get_unix_file_name(filename)))
7186             return FALSE;
7187
7188         len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7189         queue = HeapAlloc(GetProcessHeap(), 0, len);
7190         WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7191
7192         len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7193         unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7194         WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7195
7196         TRACE("printing via cups\n");
7197         ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7198         HeapFree(GetProcessHeap(), 0, unix_doc_title);
7199         HeapFree(GetProcessHeap(), 0, queue);
7200         HeapFree(GetProcessHeap(), 0, unixname);
7201         return ret;
7202     }
7203     else
7204 #endif
7205     {
7206         return schedule_lpr(printer_name, filename);
7207     }
7208 }
7209
7210 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7211 {
7212     LPWSTR filename;
7213
7214     switch(msg)
7215     {
7216     case WM_INITDIALOG:
7217         SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7218         return TRUE;
7219
7220     case WM_COMMAND:
7221         if(HIWORD(wparam) == BN_CLICKED)
7222         {
7223             if(LOWORD(wparam) == IDOK)
7224             {
7225                 HANDLE hf;
7226                 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7227                 LPWSTR *output;
7228
7229                 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7230                 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7231
7232                 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7233                 {
7234                     WCHAR caption[200], message[200];
7235                     int mb_ret;
7236
7237                     LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7238                     LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7239                     mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7240                     if(mb_ret == IDCANCEL)
7241                     {
7242                         HeapFree(GetProcessHeap(), 0, filename);
7243                         return TRUE;
7244                     }
7245                 }
7246                 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7247                 if(hf == INVALID_HANDLE_VALUE)
7248                 {
7249                     WCHAR caption[200], message[200];
7250
7251                     LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7252                     LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7253                     MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7254                     HeapFree(GetProcessHeap(), 0, filename);
7255                     return TRUE;
7256                 }
7257                 CloseHandle(hf);
7258                 DeleteFileW(filename);
7259                 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7260                 *output = filename;
7261                 EndDialog(hwnd, IDOK);
7262                 return TRUE;
7263             }
7264             if(LOWORD(wparam) == IDCANCEL)
7265             {
7266                 EndDialog(hwnd, IDCANCEL);
7267                 return TRUE;
7268             }
7269         }
7270         return FALSE;
7271     }
7272     return FALSE;
7273 }
7274
7275 /*****************************************************************************
7276  *          get_filename
7277  */
7278 static BOOL get_filename(LPWSTR *filename)
7279 {
7280     return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7281                            file_dlg_proc, (LPARAM)filename) == IDOK;
7282 }
7283
7284 /*****************************************************************************
7285  *          schedule_file
7286  */
7287 static BOOL schedule_file(LPCWSTR filename)
7288 {
7289     LPWSTR output = NULL;
7290
7291     if(get_filename(&output))
7292     {
7293         BOOL r;
7294         TRACE("copy to %s\n", debugstr_w(output));
7295         r = CopyFileW(filename, output, FALSE);
7296         HeapFree(GetProcessHeap(), 0, output);
7297         return r;
7298     }
7299     return FALSE;
7300 }
7301
7302 /*****************************************************************************
7303  *          schedule_pipe
7304  */
7305 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7306 {
7307 #ifdef HAVE_FORK
7308     char *unixname, *cmdA;
7309     DWORD len;
7310     int fds[2] = {-1, -1}, file_fd = -1, no_read;
7311     BOOL ret = FALSE;
7312     char buf[1024];
7313
7314     if(!(unixname = wine_get_unix_file_name(filename)))
7315         return FALSE;
7316
7317     len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7318     cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7319     WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7320
7321     TRACE("printing with: %s\n", cmdA);
7322
7323     if((file_fd = open(unixname, O_RDONLY)) == -1)
7324         goto end;
7325
7326     if (pipe(fds))
7327     {
7328         ERR("pipe() failed!\n"); 
7329         goto end;
7330     }
7331
7332     if (fork() == 0)
7333     {
7334         close(0);
7335         dup2(fds[0], 0);
7336         close(fds[1]);
7337
7338         /* reset signals that we previously set to SIG_IGN */
7339         signal(SIGPIPE, SIG_DFL);
7340         signal(SIGCHLD, SIG_DFL);
7341
7342         execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7343         _exit(1);
7344     }
7345
7346     while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7347         write(fds[1], buf, no_read);
7348
7349     ret = TRUE;
7350
7351 end:
7352     if(file_fd != -1) close(file_fd);
7353     if(fds[0] != -1) close(fds[0]);
7354     if(fds[1] != -1) close(fds[1]);
7355
7356     HeapFree(GetProcessHeap(), 0, cmdA);
7357     HeapFree(GetProcessHeap(), 0, unixname);
7358     return ret;
7359 #else
7360     return FALSE;
7361 #endif
7362 }
7363
7364 /*****************************************************************************
7365  *          schedule_unixfile
7366  */
7367 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7368 {
7369     int in_fd, out_fd, no_read;
7370     char buf[1024];
7371     BOOL ret = FALSE;
7372     char *unixname, *outputA;
7373     DWORD len;
7374
7375     if(!(unixname = wine_get_unix_file_name(filename)))
7376         return FALSE;
7377
7378     len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7379     outputA = HeapAlloc(GetProcessHeap(), 0, len);
7380     WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7381     
7382     out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7383     in_fd = open(unixname, O_RDONLY);
7384     if(out_fd == -1 || in_fd == -1)
7385         goto end;
7386
7387     while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7388         write(out_fd, buf, no_read);
7389
7390     ret = TRUE;
7391 end:
7392     if(in_fd != -1) close(in_fd);
7393     if(out_fd != -1) close(out_fd);
7394     HeapFree(GetProcessHeap(), 0, outputA);
7395     HeapFree(GetProcessHeap(), 0, unixname);
7396     return ret;
7397 }
7398
7399 /*****************************************************************************
7400  *          ScheduleJob [WINSPOOL.@]
7401  *
7402  */
7403 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7404 {
7405     opened_printer_t *printer;
7406     BOOL ret = FALSE;
7407     struct list *cursor, *cursor2;
7408
7409     TRACE("(%p, %x)\n", hPrinter, dwJobID);
7410     EnterCriticalSection(&printer_handles_cs);
7411     printer = get_opened_printer(hPrinter);
7412     if(!printer)
7413         goto end;
7414
7415     LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7416     {
7417         job_t *job = LIST_ENTRY(cursor, job_t, entry);
7418         HANDLE hf;
7419
7420         if(job->job_id != dwJobID) continue;
7421
7422         hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7423         if(hf != INVALID_HANDLE_VALUE)
7424         {
7425             PRINTER_INFO_5W *pi5;
7426             DWORD needed;
7427             HKEY hkey;
7428             WCHAR output[1024];
7429             static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7430                                                 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7431
7432             GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7433             pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7434             GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7435             TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7436                   debugstr_w(pi5->pPortName));
7437             
7438             output[0] = 0;
7439
7440             /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7441             if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7442             {
7443                 DWORD type, count = sizeof(output);
7444                 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7445                 RegCloseKey(hkey);
7446             }
7447             if(output[0] == '|')
7448             {
7449                 ret = schedule_pipe(output + 1, job->filename);
7450             }
7451             else if(output[0])
7452             {
7453                 ret = schedule_unixfile(output, job->filename);
7454             }
7455             else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7456             {
7457                 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7458             }
7459             else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7460             {
7461                 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7462             }
7463             else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7464             {
7465                 ret = schedule_file(job->filename);
7466             }
7467             else
7468             {
7469                 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7470             }
7471             HeapFree(GetProcessHeap(), 0, pi5);
7472             CloseHandle(hf);
7473             DeleteFileW(job->filename);
7474         }
7475         list_remove(cursor);
7476         HeapFree(GetProcessHeap(), 0, job->document_title);
7477         HeapFree(GetProcessHeap(), 0, job->filename);
7478         HeapFree(GetProcessHeap(), 0, job);
7479         break;
7480     }
7481 end:
7482     LeaveCriticalSection(&printer_handles_cs);
7483     return ret;
7484 }
7485
7486 /*****************************************************************************
7487  *          StartDocDlgA [WINSPOOL.@]
7488  */
7489 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7490 {
7491     UNICODE_STRING usBuffer;
7492     DOCINFOW docW;
7493     LPWSTR retW;
7494     LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7495     LPSTR ret = NULL;
7496
7497     docW.cbSize = sizeof(docW);
7498     if (doc->lpszDocName)
7499     {
7500         docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7501         if (!(docW.lpszDocName = docnameW)) return NULL;
7502     }
7503     if (doc->lpszOutput)
7504     {
7505         outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7506         if (!(docW.lpszOutput = outputW)) return NULL;
7507     }
7508     if (doc->lpszDatatype)
7509     {
7510         datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7511         if (!(docW.lpszDatatype = datatypeW)) return NULL;
7512     }
7513     docW.fwType = doc->fwType;
7514
7515     retW = StartDocDlgW(hPrinter, &docW);
7516
7517     if(retW)
7518     {
7519         DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7520         ret = HeapAlloc(GetProcessHeap(), 0, len);
7521         WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7522         HeapFree(GetProcessHeap(), 0, retW);
7523     }
7524
7525     HeapFree(GetProcessHeap(), 0, datatypeW);
7526     HeapFree(GetProcessHeap(), 0, outputW);
7527     HeapFree(GetProcessHeap(), 0, docnameW);
7528
7529     return ret;
7530 }
7531
7532 /*****************************************************************************
7533  *          StartDocDlgW [WINSPOOL.@]
7534  *
7535  * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7536  * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7537  * port is "FILE:". Also returns the full path if passed a relative path.
7538  *
7539  * The caller should free the returned string from the process heap.
7540  */
7541 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7542 {
7543     LPWSTR ret = NULL;
7544     DWORD len, attr;
7545
7546     if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7547     {
7548         PRINTER_INFO_5W *pi5;
7549         GetPrinterW(hPrinter, 5, NULL, 0, &len);
7550         if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7551             return NULL;
7552         pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7553         GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7554         if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7555         {
7556             HeapFree(GetProcessHeap(), 0, pi5);
7557             return NULL;
7558         }
7559         HeapFree(GetProcessHeap(), 0, pi5);
7560     }
7561
7562     if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7563     {
7564         LPWSTR name;
7565
7566         if (get_filename(&name))
7567         {
7568             if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7569             {
7570                 HeapFree(GetProcessHeap(), 0, name);
7571                 return NULL;
7572             }
7573             ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7574             GetFullPathNameW(name, len, ret, NULL);
7575             HeapFree(GetProcessHeap(), 0, name);
7576         }
7577         return ret;
7578     }
7579
7580     if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7581         return NULL;
7582
7583     ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7584     GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7585         
7586     attr = GetFileAttributesW(ret);
7587     if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7588     {
7589         HeapFree(GetProcessHeap(), 0, ret);
7590         ret = NULL;
7591     }
7592     return ret;
7593 }