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