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