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