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