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