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