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