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