winspool: Use the backend for GetPrintProcessorDirectory and update the tests.
[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             *lpdwNeeded = 0;
3770             *lpdwReturned = 0;
3771             return TRUE;
3772         }
3773
3774     }
3775
3776     if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3777         FIXME("dwType = %08x\n", dwType);
3778         SetLastError(ERROR_INVALID_FLAGS);
3779         return FALSE;
3780     }
3781
3782     if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3783        ERROR_SUCCESS) {
3784         ERR("Can't create Printers key\n");
3785         return FALSE;
3786     }
3787
3788     if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3789                         NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3790         RegCloseKey(hkeyPrinters);
3791         ERR("Can't query Printers key\n");
3792         return FALSE;
3793     }
3794     TRACE("Found %d printers\n", number);
3795
3796     switch(dwLevel) {
3797     case 1:
3798         used = number * sizeof(PRINTER_INFO_1W);
3799         break;
3800     case 2:
3801         used = number * sizeof(PRINTER_INFO_2W);
3802         break;
3803     case 4:
3804         used = number * sizeof(PRINTER_INFO_4W);
3805         break;
3806     case 5:
3807         used = number * sizeof(PRINTER_INFO_5W);
3808         break;
3809
3810     default:
3811         SetLastError(ERROR_INVALID_LEVEL);
3812         RegCloseKey(hkeyPrinters);
3813         return FALSE;
3814     }
3815     pi = (used <= cbBuf) ? lpbPrinters : NULL;
3816
3817     for(i = 0; i < number; i++) {
3818         if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3819            ERROR_SUCCESS) {
3820             ERR("Can't enum key number %d\n", i);
3821             RegCloseKey(hkeyPrinters);
3822             return FALSE;
3823         }
3824         TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3825         if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3826            ERROR_SUCCESS) {
3827             ERR("Can't open key %s\n", debugstr_w(PrinterName));
3828             RegCloseKey(hkeyPrinters);
3829             return FALSE;
3830         }
3831
3832         if(cbBuf > used) {
3833             buf = lpbPrinters + used;
3834             left = cbBuf - used;
3835         } else {
3836             buf = NULL;
3837             left = 0;
3838         }
3839
3840         switch(dwLevel) {
3841         case 1:
3842             WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
3843                                   left, &needed, unicode);
3844             used += needed;
3845             if(pi) pi += sizeof(PRINTER_INFO_1W);
3846             break;
3847         case 2:
3848             WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3849                                   left, &needed, unicode);
3850             used += needed;
3851             if(pi) pi += sizeof(PRINTER_INFO_2W);
3852             break;
3853         case 4:
3854             WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3855                                   left, &needed, unicode);
3856             used += needed;
3857             if(pi) pi += sizeof(PRINTER_INFO_4W);
3858             break;
3859         case 5:
3860             WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3861                                   left, &needed, unicode);
3862             used += needed;
3863             if(pi) pi += sizeof(PRINTER_INFO_5W);
3864             break;
3865         default:
3866             ERR("Shouldn't be here!\n");
3867             RegCloseKey(hkeyPrinter);
3868             RegCloseKey(hkeyPrinters);
3869             return FALSE;
3870         }
3871         RegCloseKey(hkeyPrinter);
3872     }
3873     RegCloseKey(hkeyPrinters);
3874
3875     if(lpdwNeeded)
3876         *lpdwNeeded = used;
3877
3878     if(used > cbBuf) {
3879         if(lpbPrinters)
3880             memset(lpbPrinters, 0, cbBuf);
3881         SetLastError(ERROR_INSUFFICIENT_BUFFER);
3882         return FALSE;
3883     }
3884     if(lpdwReturned)
3885         *lpdwReturned = number;
3886     SetLastError(ERROR_SUCCESS);
3887     return TRUE;
3888 }
3889
3890
3891 /******************************************************************
3892  *              EnumPrintersW        [WINSPOOL.@]
3893  *
3894  *    Enumerates the available printers, print servers and print
3895  *    providers, depending on the specified flags, name and level.
3896  *
3897  * RETURNS:
3898  *
3899  *    If level is set to 1:
3900  *      Returns an array of PRINTER_INFO_1 data structures in the
3901  *      lpbPrinters buffer.
3902  *
3903  *    If level is set to 2:
3904  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3905  *      Returns an array of PRINTER_INFO_2 data structures in the
3906  *      lpbPrinters buffer. Note that according to MSDN also an
3907  *      OpenPrinter should be performed on every remote printer.
3908  *
3909  *    If level is set to 4 (officially WinNT only):
3910  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3911  *      Fast: Only the registry is queried to retrieve printer names,
3912  *      no connection to the driver is made.
3913  *      Returns an array of PRINTER_INFO_4 data structures in the
3914  *      lpbPrinters buffer.
3915  *
3916  *    If level is set to 5 (officially WinNT4/Win9x only):
3917  *      Fast: Only the registry is queried to retrieve printer names,
3918  *      no connection to the driver is made.
3919  *      Returns an array of PRINTER_INFO_5 data structures in the
3920  *      lpbPrinters buffer.
3921  *
3922  *    If level set to 3 or 6+:
3923  *          returns zero (failure!)
3924  *
3925  *    Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3926  *    for information.
3927  *
3928  * BUGS:
3929  *    - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3930  *    - Only levels 2, 4 and 5 are implemented at the moment.
3931  *    - 16-bit printer drivers are not enumerated.
3932  *    - Returned amount of bytes used/needed does not match the real Windoze
3933  *      implementation (as in this implementation, all strings are part
3934  *      of the buffer, whereas Win32 keeps them somewhere else)
3935  *    - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3936  *
3937  * NOTE:
3938  *    - In a regular Wine installation, no registry settings for printers
3939  *      exist, which makes this function return an empty list.
3940  */
3941 BOOL  WINAPI EnumPrintersW(
3942                 DWORD dwType,        /* [in] Types of print objects to enumerate */
3943                 LPWSTR lpszName,     /* [in] name of objects to enumerate */
3944                 DWORD dwLevel,       /* [in] type of printer info structure */
3945                 LPBYTE lpbPrinters,  /* [out] buffer which receives info */
3946                 DWORD cbBuf,         /* [in] max size of buffer in bytes */
3947                 LPDWORD lpdwNeeded,  /* [out] pointer to var: # bytes used/needed */
3948                 LPDWORD lpdwReturned /* [out] number of entries returned */
3949                 )
3950 {
3951     return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3952                                  lpdwNeeded, lpdwReturned, TRUE);
3953 }
3954
3955 /******************************************************************
3956  * EnumPrintersA    [WINSPOOL.@]
3957  *
3958  * See EnumPrintersW
3959  *
3960  */
3961 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
3962                           DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
3963 {
3964     BOOL ret;
3965     UNICODE_STRING pNameU;
3966     LPWSTR pNameW;
3967     LPBYTE pPrintersW;
3968
3969     TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
3970                                               pPrinters, cbBuf, pcbNeeded, pcReturned);
3971
3972     pNameW = asciitounicode(&pNameU, pName);
3973
3974     /* Request a buffer with a size, that is big enough for EnumPrintersW.
3975        MS Office need this */
3976     pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
3977
3978     ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
3979
3980     RtlFreeUnicodeString(&pNameU);
3981     if (ret) {
3982         convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
3983     }
3984     HeapFree(GetProcessHeap(), 0, pPrintersW);
3985     return ret;
3986 }
3987
3988 /*****************************************************************************
3989  *          WINSPOOL_GetDriverInfoFromReg [internal]
3990  *
3991  *    Enters the information from the registry into the DRIVER_INFO struct
3992  *
3993  * RETURNS
3994  *    zero if the printer driver does not exist in the registry
3995  *    (only if Level > 1) otherwise nonzero
3996  */
3997 static BOOL WINSPOOL_GetDriverInfoFromReg(
3998                             HKEY    hkeyDrivers,
3999                             LPWSTR  DriverName,
4000                             const printenv_t * env,
4001                             DWORD   Level,
4002                             LPBYTE  ptr,            /* DRIVER_INFO */
4003                             LPBYTE  pDriverStrings, /* strings buffer */
4004                             DWORD   cbBuf,          /* size of string buffer */
4005                             LPDWORD pcbNeeded,      /* space needed for str. */
4006                             BOOL    unicode)        /* type of strings */
4007 {
4008     DWORD  size, tmp;
4009     HKEY   hkeyDriver;
4010     WCHAR  driverdir[MAX_PATH];
4011     DWORD  dirlen;
4012     LPBYTE strPtr = pDriverStrings;
4013     LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4014
4015     TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4016           debugstr_w(DriverName), env,
4017           Level, di, pDriverStrings, cbBuf, unicode);
4018
4019     if (di) ZeroMemory(di, di_sizeof[Level]);
4020
4021     if (unicode) {
4022         *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4023         if (*pcbNeeded <= cbBuf)
4024            strcpyW((LPWSTR)strPtr, DriverName);
4025     }
4026     else
4027     {
4028         *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4029         if (*pcbNeeded <= cbBuf)
4030             WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4031     }
4032
4033     /* pName for level 1 has a different offset! */
4034     if (Level == 1) {
4035        if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4036        return TRUE;
4037     }
4038
4039     /* .cVersion and .pName for level > 1 */
4040     if (di) {
4041         di->cVersion = env->driverversion;
4042         di->pName = (LPWSTR) strPtr;
4043         strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4044     }
4045
4046     /* Reserve Space for the largest subdir and a Backslash*/
4047     size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4048     if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4049         /* Should never Fail */
4050         return FALSE;
4051     }
4052     lstrcatW(driverdir, env->versionsubdir);
4053     lstrcatW(driverdir, backslashW);
4054
4055     /* dirlen must not include the terminating zero */
4056     dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4057              WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4058
4059     if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4060         ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4061         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4062         return FALSE;
4063     }
4064
4065     /* pEnvironment */
4066     if (unicode)
4067         size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4068     else
4069         size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4070
4071     *pcbNeeded += size;
4072     if (*pcbNeeded <= cbBuf) {
4073         if (unicode) {
4074             lstrcpyW((LPWSTR)strPtr, env->envname);
4075         }
4076         else
4077         {
4078             WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4079         }
4080         if (di) di->pEnvironment = (LPWSTR)strPtr;
4081         strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4082     }
4083
4084     /* .pDriverPath is the Graphics rendering engine.
4085         The full Path is required to avoid a crash in some apps */
4086     if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4087         *pcbNeeded += size;
4088         if (*pcbNeeded <= cbBuf)
4089             get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4090
4091         if (di) di->pDriverPath = (LPWSTR)strPtr;
4092         strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4093     }
4094
4095     /* .pDataFile: For postscript-drivers, this is the ppd-file */
4096     if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4097         *pcbNeeded += size;
4098         if (*pcbNeeded <= cbBuf)
4099             get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4100
4101         if (di) di->pDataFile = (LPWSTR)strPtr;
4102         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4103     }
4104
4105     /* .pConfigFile is the Driver user Interface */
4106     if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4107         *pcbNeeded += size;
4108         if (*pcbNeeded <= cbBuf)
4109             get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4110
4111         if (di) di->pConfigFile = (LPWSTR)strPtr;
4112         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4113     }
4114
4115     if (Level == 2 ) {
4116         RegCloseKey(hkeyDriver);
4117         TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4118         return TRUE;
4119     }
4120
4121     if (Level == 5 ) {
4122         RegCloseKey(hkeyDriver);
4123         FIXME("level 5: incomplete\n");
4124         return TRUE;
4125     }
4126
4127     /* .pHelpFile */
4128     if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4129         *pcbNeeded += size;
4130         if (*pcbNeeded <= cbBuf)
4131             get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4132
4133         if (di) di->pHelpFile = (LPWSTR)strPtr;
4134         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4135     }
4136
4137     /* .pDependentFiles */
4138     if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4139         *pcbNeeded += size;
4140         if (*pcbNeeded <= cbBuf)
4141             get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4142
4143         if (di) di->pDependentFiles = (LPWSTR)strPtr;
4144         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4145     }
4146     else if (GetVersion() & 0x80000000) {
4147         /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4148         size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4149         *pcbNeeded += size;
4150         if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4151
4152         if (di) di->pDependentFiles = (LPWSTR)strPtr;
4153         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4154     }
4155
4156     /* .pMonitorName is the optional Language Monitor */
4157     if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4158         *pcbNeeded += size;
4159         if (*pcbNeeded <= cbBuf)
4160             WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4161
4162         if (di) di->pMonitorName = (LPWSTR)strPtr;
4163         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4164     }
4165
4166     /* .pDefaultDataType */
4167     if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4168         *pcbNeeded += size;
4169         if(*pcbNeeded <= cbBuf)
4170             WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4171
4172         if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4173         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4174     }
4175
4176     if (Level == 3 ) {
4177         RegCloseKey(hkeyDriver);
4178         TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4179         return TRUE;
4180     }
4181
4182     /* .pszzPreviousNames */
4183     if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4184         *pcbNeeded += size;
4185         if(*pcbNeeded <= cbBuf)
4186             WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4187
4188         if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4189         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4190     }
4191
4192     if (Level == 4 ) {
4193         RegCloseKey(hkeyDriver);
4194         TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4195         return TRUE;
4196     }
4197
4198     /* support is missing, but not important enough for a FIXME */
4199     TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4200
4201     /* .pszMfgName */
4202     if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4203         *pcbNeeded += size;
4204         if(*pcbNeeded <= cbBuf)
4205             WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4206
4207         if (di) di->pszMfgName = (LPWSTR)strPtr;
4208         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4209     }
4210
4211     /* .pszOEMUrl */
4212     if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4213         *pcbNeeded += size;
4214         if(*pcbNeeded <= cbBuf)
4215             WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4216
4217         if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4218         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4219     }
4220
4221     /* .pszHardwareID */
4222     if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4223         *pcbNeeded += size;
4224         if(*pcbNeeded <= cbBuf)
4225             WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4226
4227         if (di) di->pszHardwareID = (LPWSTR)strPtr;
4228         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4229     }
4230
4231     /* .pszProvider */
4232     if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4233         *pcbNeeded += size;
4234         if(*pcbNeeded <= cbBuf)
4235             WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4236
4237         if (di) di->pszProvider = (LPWSTR)strPtr;
4238         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4239     }
4240
4241     if (Level == 6 ) {
4242         RegCloseKey(hkeyDriver);
4243         return TRUE;
4244     }
4245
4246     /* support is missing, but not important enough for a FIXME */
4247     TRACE("level 8: incomplete\n");
4248
4249     TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4250     RegCloseKey(hkeyDriver);
4251     return TRUE;
4252 }
4253
4254 /*****************************************************************************
4255  *          WINSPOOL_GetPrinterDriver
4256  */
4257 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4258                                       DWORD Level, LPBYTE pDriverInfo,
4259                                       DWORD cbBuf, LPDWORD pcbNeeded,
4260                                       BOOL unicode)
4261 {
4262     LPCWSTR name;
4263     WCHAR DriverName[100];
4264     DWORD ret, type, size, needed = 0;
4265     LPBYTE ptr = NULL;
4266     HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4267     const printenv_t * env;
4268
4269     TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4270           Level,pDriverInfo,cbBuf, pcbNeeded);
4271
4272
4273     if (!(name = get_opened_printer_name(hPrinter))) {
4274         SetLastError(ERROR_INVALID_HANDLE);
4275         return FALSE;
4276     }
4277
4278     if (Level < 1 || Level == 7 || Level > 8) {
4279         SetLastError(ERROR_INVALID_LEVEL);
4280         return FALSE;
4281     }
4282
4283     env = validate_envW(pEnvironment);
4284     if (!env) return FALSE;     /* SetLastError() is in validate_envW */
4285
4286     if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4287        ERROR_SUCCESS) {
4288         ERR("Can't create Printers key\n");
4289         return FALSE;
4290     }
4291     if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4292        != ERROR_SUCCESS) {
4293         ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4294         RegCloseKey(hkeyPrinters);
4295         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4296         return FALSE;
4297     }
4298     size = sizeof(DriverName);
4299     DriverName[0] = 0;
4300     ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4301                            (LPBYTE)DriverName, &size);
4302     RegCloseKey(hkeyPrinter);
4303     RegCloseKey(hkeyPrinters);
4304     if(ret != ERROR_SUCCESS) {
4305         ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4306         return FALSE;
4307     }
4308
4309     hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4310     if(!hkeyDrivers) {
4311         ERR("Can't create Drivers key\n");
4312         return FALSE;
4313     }
4314
4315     size = di_sizeof[Level];
4316     if ((size <= cbBuf) && pDriverInfo)
4317         ptr = pDriverInfo + size;
4318
4319     if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4320                          env, Level, pDriverInfo, ptr,
4321                          (cbBuf < size) ? 0 : cbBuf - size,
4322                          &needed, unicode)) {
4323             RegCloseKey(hkeyDrivers);
4324             return FALSE;
4325     }
4326
4327     RegCloseKey(hkeyDrivers);
4328
4329     if(pcbNeeded) *pcbNeeded = size + needed;
4330     TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4331     if(cbBuf >= needed) return TRUE;
4332     SetLastError(ERROR_INSUFFICIENT_BUFFER);
4333     return FALSE;
4334 }
4335
4336 /*****************************************************************************
4337  *          GetPrinterDriverA  [WINSPOOL.@]
4338  */
4339 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4340                               DWORD Level, LPBYTE pDriverInfo,
4341                               DWORD cbBuf, LPDWORD pcbNeeded)
4342 {
4343     BOOL ret;
4344     UNICODE_STRING pEnvW;
4345     PWSTR pwstrEnvW;
4346     
4347     pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4348     ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4349                                     cbBuf, pcbNeeded, FALSE);
4350     RtlFreeUnicodeString(&pEnvW);
4351     return ret;
4352 }
4353 /*****************************************************************************
4354  *          GetPrinterDriverW  [WINSPOOL.@]
4355  */
4356 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4357                                   DWORD Level, LPBYTE pDriverInfo,
4358                                   DWORD cbBuf, LPDWORD pcbNeeded)
4359 {
4360     return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4361                                      pDriverInfo, cbBuf, pcbNeeded, TRUE);
4362 }
4363
4364 /*****************************************************************************
4365  *       GetPrinterDriverDirectoryW  [WINSPOOL.@]
4366  *
4367  * Return the PATH for the Printer-Drivers (UNICODE)
4368  *
4369  * PARAMS
4370  *   pName            [I] Servername (NT only) or NULL (local Computer)
4371  *   pEnvironment     [I] Printing-Environment (see below) or NULL (Default)
4372  *   Level            [I] Structure-Level (must be 1)
4373  *   pDriverDirectory [O] PTR to Buffer that receives the Result
4374  *   cbBuf            [I] Size of Buffer at pDriverDirectory
4375  *   pcbNeeded        [O] PTR to DWORD that receives the size in Bytes used / 
4376  *                        required for pDriverDirectory
4377  *
4378  * RETURNS
4379  *   Success: TRUE  and in pcbNeeded the Bytes used in pDriverDirectory
4380  *   Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4381  *   if cbBuf is too small
4382  * 
4383  *   Native Values returned in pDriverDirectory on Success:
4384  *|  NT(Windows NT x86):  "%winsysdir%\\spool\\DRIVERS\\w32x86" 
4385  *|  NT(Windows 4.0):     "%winsysdir%\\spool\\DRIVERS\\win40" 
4386  *|  win9x(Windows 4.0):  "%winsysdir%" 
4387  *
4388  *   "%winsysdir%" is the Value from GetSystemDirectoryW()
4389  *
4390  * FIXME
4391  *-  Only NULL or "" is supported for pName
4392  *
4393  */
4394 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4395                                        DWORD Level, LPBYTE pDriverDirectory,
4396                                        DWORD cbBuf, LPDWORD pcbNeeded)
4397 {
4398     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName), 
4399           debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4400
4401     if ((backend == NULL)  && !load_backend()) return FALSE;
4402
4403     if (Level != 1) {
4404         /* (Level != 1) is ignored in win9x */
4405         SetLastError(ERROR_INVALID_LEVEL);
4406         return FALSE;
4407     }
4408     if (pcbNeeded == NULL) {
4409         /* (pcbNeeded == NULL) is ignored in win9x */
4410         SetLastError(RPC_X_NULL_REF_POINTER);
4411         return FALSE;
4412     }
4413
4414     return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4415                                                 pDriverDirectory, cbBuf, pcbNeeded);
4416
4417 }
4418
4419
4420 /*****************************************************************************
4421  *       GetPrinterDriverDirectoryA  [WINSPOOL.@]
4422  *
4423  * Return the PATH for the Printer-Drivers (ANSI)
4424  *
4425  * See GetPrinterDriverDirectoryW.
4426  *
4427  * NOTES
4428  * On NT, pDriverDirectory need the same Size as the Unicode-Version
4429  *
4430  */
4431 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4432                                        DWORD Level, LPBYTE pDriverDirectory,
4433                                        DWORD cbBuf, LPDWORD pcbNeeded)
4434 {
4435     UNICODE_STRING nameW, environmentW;
4436     BOOL ret;
4437     DWORD pcbNeededW;
4438     INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4439     WCHAR *driverDirectoryW = NULL;
4440
4441     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName), 
4442           debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4443  
4444     if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4445
4446     if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4447     else nameW.Buffer = NULL;
4448     if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4449     else environmentW.Buffer = NULL;
4450
4451     ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4452                                       (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4453     if (ret) {
4454         DWORD needed;
4455         needed =  WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1, 
4456                                    (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4457         if(pcbNeeded)
4458             *pcbNeeded = needed;
4459         ret = (needed <= cbBuf) ? TRUE : FALSE;
4460     } else 
4461         if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4462
4463     TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4464
4465     HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4466     RtlFreeUnicodeString(&environmentW);
4467     RtlFreeUnicodeString(&nameW);
4468
4469     return ret;
4470 }
4471
4472 /*****************************************************************************
4473  *          AddPrinterDriverA  [WINSPOOL.@]
4474  *
4475  * See AddPrinterDriverW.
4476  *
4477  */
4478 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4479 {
4480     TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4481     return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4482 }
4483
4484 /******************************************************************************
4485  *  AddPrinterDriverW (WINSPOOL.@)
4486  *
4487  * Install a Printer Driver
4488  *
4489  * PARAMS
4490  *  pName           [I] Servername or NULL (local Computer)
4491  *  level           [I] Level for the supplied DRIVER_INFO_*W struct
4492  *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4493  *
4494  * RESULTS
4495  *  Success: TRUE
4496  *  Failure: FALSE
4497  *
4498  */
4499 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4500 {
4501     TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4502     return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4503 }
4504
4505 /*****************************************************************************
4506  *          AddPrintProcessorA  [WINSPOOL.@]
4507  */
4508 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4509                                LPSTR pPrintProcessorName)
4510 {
4511     FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4512           debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4513     return FALSE;
4514 }
4515
4516 /*****************************************************************************
4517  *          AddPrintProcessorW  [WINSPOOL.@]
4518  */
4519 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4520                                LPWSTR pPrintProcessorName)
4521 {
4522     FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4523           debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4524     return FALSE;
4525 }
4526
4527 /*****************************************************************************
4528  *          AddPrintProvidorA  [WINSPOOL.@]
4529  */
4530 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4531 {
4532     FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4533     return FALSE;
4534 }
4535
4536 /*****************************************************************************
4537  *          AddPrintProvidorW  [WINSPOOL.@]
4538  */
4539 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4540 {
4541     FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4542     return FALSE;
4543 }
4544
4545 /*****************************************************************************
4546  *          AdvancedDocumentPropertiesA  [WINSPOOL.@]
4547  */
4548 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4549                                         PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4550 {
4551     FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4552           pDevModeOutput, pDevModeInput);
4553     return 0;
4554 }
4555
4556 /*****************************************************************************
4557  *          AdvancedDocumentPropertiesW  [WINSPOOL.@]
4558  */
4559 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4560                                         PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4561 {
4562     FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4563           pDevModeOutput, pDevModeInput);
4564     return 0;
4565 }
4566
4567 /*****************************************************************************
4568  *          PrinterProperties  [WINSPOOL.@]
4569  *
4570  *     Displays a dialog to set the properties of the printer.
4571  *
4572  * RETURNS
4573  *     nonzero on success or zero on failure
4574  *
4575  * BUGS
4576  *         implemented as stub only
4577  */
4578 BOOL WINAPI PrinterProperties(HWND hWnd,      /* [in] handle to parent window */
4579                               HANDLE hPrinter /* [in] handle to printer object */
4580 ){
4581     FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4582     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4583     return FALSE;
4584 }
4585
4586 /*****************************************************************************
4587  *          EnumJobsA [WINSPOOL.@]
4588  *
4589  */
4590 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4591                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4592                       LPDWORD pcReturned)
4593 {
4594     FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4595         hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4596     );
4597     if(pcbNeeded) *pcbNeeded = 0;
4598     if(pcReturned) *pcReturned = 0;
4599     return FALSE;
4600 }
4601
4602
4603 /*****************************************************************************
4604  *          EnumJobsW [WINSPOOL.@]
4605  *
4606  */
4607 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4608                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4609                       LPDWORD pcReturned)
4610 {
4611     FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4612         hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4613     );
4614     if(pcbNeeded) *pcbNeeded = 0;
4615     if(pcReturned) *pcReturned = 0;
4616     return FALSE;
4617 }
4618
4619 /*****************************************************************************
4620  *          WINSPOOL_EnumPrinterDrivers [internal]
4621  *
4622  *    Delivers information about all printer drivers installed on the
4623  *    localhost or a given server
4624  *
4625  * RETURNS
4626  *    nonzero on success or zero on failure. If the buffer for the returned
4627  *    information is too small the function will return an error
4628  *
4629  * BUGS
4630  *    - only implemented for localhost, foreign hosts will return an error
4631  */
4632 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4633                                         DWORD Level, LPBYTE pDriverInfo,
4634                                         DWORD cbBuf, LPDWORD pcbNeeded,
4635                                         LPDWORD pcReturned, BOOL unicode)
4636
4637 {   HKEY  hkeyDrivers;
4638     DWORD i, needed, number = 0, size = 0;
4639     WCHAR DriverNameW[255];
4640     PBYTE ptr;
4641     const printenv_t * env;
4642
4643     TRACE("%s,%s,%d,%p,%d,%d\n",
4644           debugstr_w(pName), debugstr_w(pEnvironment),
4645           Level, pDriverInfo, cbBuf, unicode);
4646
4647     /* check for local drivers */
4648     if((pName) && (pName[0])) {
4649         FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4650         SetLastError(ERROR_ACCESS_DENIED);
4651         return FALSE;
4652     }
4653
4654     env = validate_envW(pEnvironment);
4655     if (!env) return FALSE;     /* SetLastError() is in validate_envW */
4656
4657     /* check input parameter */
4658     if ((Level < 1) || (Level == 7) || (Level > 8)) {
4659         SetLastError(ERROR_INVALID_LEVEL);
4660         return FALSE;
4661     }
4662
4663     if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
4664         SetLastError(RPC_X_NULL_REF_POINTER);
4665         return FALSE;
4666     }
4667
4668     /* initialize return values */
4669     if(pDriverInfo)
4670         memset( pDriverInfo, 0, cbBuf);
4671     *pcbNeeded  = 0;
4672     *pcReturned = 0;
4673
4674     hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4675     if(!hkeyDrivers) {
4676         ERR("Can't open Drivers key\n");
4677         return FALSE;
4678     }
4679
4680     if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4681                         NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4682         RegCloseKey(hkeyDrivers);
4683         ERR("Can't query Drivers key\n");
4684         return FALSE;
4685     }
4686     TRACE("Found %d Drivers\n", number);
4687
4688     /* get size of single struct
4689      * unicode and ascii structure have the same size
4690      */
4691     size = di_sizeof[Level];
4692
4693     /* calculate required buffer size */
4694     *pcbNeeded = size * number;
4695
4696     for( i = 0,  ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4697          i < number;
4698          i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4699         if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4700                        != ERROR_SUCCESS) {
4701             ERR("Can't enum key number %d\n", i);
4702             RegCloseKey(hkeyDrivers);
4703             return FALSE;
4704         }
4705         if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4706                          env, Level, ptr,
4707                          (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4708                          (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4709                          &needed, unicode)) {
4710             RegCloseKey(hkeyDrivers);
4711             return FALSE;
4712         }
4713         *pcbNeeded += needed;
4714     }
4715
4716     RegCloseKey(hkeyDrivers);
4717
4718     if(cbBuf < *pcbNeeded){
4719         SetLastError(ERROR_INSUFFICIENT_BUFFER);
4720         return FALSE;
4721     }
4722
4723     *pcReturned = number;
4724     return TRUE;
4725 }
4726
4727 /*****************************************************************************
4728  *          EnumPrinterDriversW  [WINSPOOL.@]
4729  *
4730  *    see function EnumPrinterDrivers for RETURNS, BUGS
4731  */
4732 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4733                                 LPBYTE pDriverInfo, DWORD cbBuf,
4734                                 LPDWORD pcbNeeded, LPDWORD pcReturned)
4735 {
4736     static const WCHAR allW[] = {'a','l','l',0};
4737
4738     if (pEnvironment && !strcmpW(pEnvironment, allW))
4739     {
4740         BOOL ret;
4741         DWORD i, needed, returned, bufsize = cbBuf;
4742
4743         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4744         {
4745             needed = returned = 0;
4746             ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4747                                               pDriverInfo, bufsize, &needed, &returned, TRUE);
4748             if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4749             else if (ret)
4750             {
4751                 bufsize -= needed;
4752                 if (pDriverInfo) pDriverInfo += needed;
4753                 if (pcReturned) *pcReturned += returned;
4754             }
4755             if (pcbNeeded) *pcbNeeded += needed;
4756         }
4757         return ret;
4758     }
4759     return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4760                                        cbBuf, pcbNeeded, pcReturned, TRUE);
4761 }
4762
4763 /*****************************************************************************
4764  *          EnumPrinterDriversA  [WINSPOOL.@]
4765  *
4766  *    see function EnumPrinterDrivers for RETURNS, BUGS
4767  */
4768 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4769                                 LPBYTE pDriverInfo, DWORD cbBuf,
4770                                 LPDWORD pcbNeeded, LPDWORD pcReturned)
4771 {
4772     BOOL ret;
4773     UNICODE_STRING pNameW, pEnvironmentW;
4774     PWSTR pwstrNameW, pwstrEnvironmentW;
4775
4776     pwstrNameW = asciitounicode(&pNameW, pName);
4777     pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4778
4779     if (pEnvironment && !strcmp(pEnvironment, "all"))
4780     {
4781         DWORD i, needed, returned, bufsize = cbBuf;
4782
4783         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4784         {
4785             needed = returned = 0;
4786             ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, all_printenv[i]->envname, Level,
4787                                               pDriverInfo, bufsize, &needed, &returned, FALSE);
4788             if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
4789             else if (ret)
4790             {
4791                 bufsize -= needed;
4792                 if (pDriverInfo) pDriverInfo += needed;
4793                 if (pcReturned) *pcReturned += returned;
4794             }
4795             if (pcbNeeded) *pcbNeeded += needed;
4796         }
4797     }
4798     else ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4799                                            Level, pDriverInfo, cbBuf, pcbNeeded,
4800                                            pcReturned, FALSE);
4801     RtlFreeUnicodeString(&pNameW);
4802     RtlFreeUnicodeString(&pEnvironmentW);
4803
4804     return ret;
4805 }
4806
4807 /******************************************************************************
4808  *              EnumPortsA   (WINSPOOL.@)
4809  *
4810  * See EnumPortsW.
4811  *
4812  */
4813 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4814                         LPDWORD pcbNeeded, LPDWORD pcReturned)
4815 {
4816     BOOL    res;
4817     LPBYTE  bufferW = NULL;
4818     LPWSTR  nameW = NULL;
4819     DWORD   needed = 0;
4820     DWORD   numentries = 0;
4821     INT     len;
4822
4823     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4824           cbBuf, pcbNeeded, pcReturned);
4825
4826     /* convert servername to unicode */
4827     if (pName) {
4828         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4829         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4830         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4831     }
4832     /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4833     needed = cbBuf * sizeof(WCHAR);    
4834     if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4835     res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4836
4837     if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4838         if (pcbNeeded) needed = *pcbNeeded;
4839         /* HeapReAlloc return NULL, when bufferW was NULL */
4840         bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4841                               HeapAlloc(GetProcessHeap(), 0, needed);
4842
4843         /* Try again with the large Buffer */
4844         res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4845     }
4846     needed = pcbNeeded ? *pcbNeeded : 0;
4847     numentries = pcReturned ? *pcReturned : 0;
4848
4849     /*
4850        W2k require the buffersize from EnumPortsW also for EnumPortsA.
4851        We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
4852      */
4853     if (res) {
4854         /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
4855         DWORD   entrysize = 0;
4856         DWORD   index;
4857         LPSTR   ptr;
4858         LPPORT_INFO_2W pi2w;
4859         LPPORT_INFO_2A pi2a;
4860
4861         needed = 0;
4862         entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
4863
4864         /* First pass: calculate the size for all Entries */
4865         pi2w = (LPPORT_INFO_2W) bufferW;
4866         pi2a = (LPPORT_INFO_2A) pPorts;
4867         index = 0;
4868         while (index < numentries) {
4869             index++;
4870             needed += entrysize;    /* PORT_INFO_?A */
4871             TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
4872
4873             needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4874                                             NULL, 0, NULL, NULL);
4875             if (Level > 1) {
4876                 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4877                                                 NULL, 0, NULL, NULL);
4878                 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4879                                                 NULL, 0, NULL, NULL);
4880             }
4881             /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4882             pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4883             pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4884         }
4885
4886         /* check for errors and quit on failure */
4887         if (cbBuf < needed) {
4888             SetLastError(ERROR_INSUFFICIENT_BUFFER);
4889             res = FALSE;
4890             goto cleanup;
4891         }
4892         len = entrysize * numentries;       /* room for all PORT_INFO_?A */
4893         ptr = (LPSTR) &pPorts[len];         /* room for strings */
4894         cbBuf -= len ;                      /* free Bytes in the user-Buffer */
4895         pi2w = (LPPORT_INFO_2W) bufferW;
4896         pi2a = (LPPORT_INFO_2A) pPorts;
4897         index = 0;
4898         /* Second Pass: Fill the User Buffer (if we have one) */
4899         while ((index < numentries) && pPorts) {
4900             index++;
4901             TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
4902             pi2a->pPortName = ptr;
4903             len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4904                                             ptr, cbBuf , NULL, NULL);
4905             ptr += len;
4906             cbBuf -= len;
4907             if (Level > 1) {
4908                 pi2a->pMonitorName = ptr;
4909                 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4910                                             ptr, cbBuf, NULL, NULL);
4911                 ptr += len;
4912                 cbBuf -= len;
4913
4914                 pi2a->pDescription = ptr;
4915                 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4916                                             ptr, cbBuf, NULL, NULL);
4917                 ptr += len;
4918                 cbBuf -= len;
4919
4920                 pi2a->fPortType = pi2w->fPortType;
4921                 pi2a->Reserved = 0;              /* documented: "must be zero" */
4922                 
4923             }
4924             /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4925             pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4926             pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4927         }
4928     }
4929
4930 cleanup:
4931     if (pcbNeeded)  *pcbNeeded = needed;
4932     if (pcReturned) *pcReturned = (res) ? numentries : 0;
4933
4934     HeapFree(GetProcessHeap(), 0, nameW);
4935     HeapFree(GetProcessHeap(), 0, bufferW);
4936
4937     TRACE("returning %d with %d (%d byte for %d of %d entries)\n", 
4938             (res), GetLastError(), needed, (res)? numentries : 0, numentries);
4939
4940     return (res);
4941
4942 }
4943
4944 /******************************************************************************
4945  *      EnumPortsW   (WINSPOOL.@)
4946  *
4947  * Enumerate available Ports
4948  *
4949  * PARAMS
4950  *  pName      [I] Servername or NULL (local Computer)
4951  *  Level      [I] Structure-Level (1 or 2)
4952  *  pPorts     [O] PTR to Buffer that receives the Result
4953  *  cbBuf      [I] Size of Buffer at pPorts
4954  *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
4955  *  pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
4956  *
4957  * RETURNS
4958  *  Success: TRUE
4959  *  Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
4960  *
4961  */
4962 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4963 {
4964
4965     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
4966           cbBuf, pcbNeeded, pcReturned);
4967
4968     if ((backend == NULL)  && !load_backend()) return FALSE;
4969
4970     /* Level is not checked in win9x */
4971     if (!Level || (Level > 2)) {
4972         WARN("level (%d) is ignored in win9x\n", Level);
4973         SetLastError(ERROR_INVALID_LEVEL);
4974         return FALSE;
4975     }
4976     if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
4977         SetLastError(RPC_X_NULL_REF_POINTER);
4978         return FALSE;
4979     }
4980
4981     return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
4982 }
4983
4984 /******************************************************************************
4985  *              GetDefaultPrinterW   (WINSPOOL.@)
4986  *
4987  * FIXME
4988  *      This function must read the value from data 'device' of key
4989  *      HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4990  */
4991 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4992 {
4993     BOOL  retval = TRUE;
4994     DWORD insize, len;
4995     WCHAR *buffer, *ptr;
4996
4997     if (!namesize)
4998     {
4999         SetLastError(ERROR_INVALID_PARAMETER);
5000         return FALSE;
5001     }
5002
5003     /* make the buffer big enough for the stuff from the profile/registry,
5004      * the content must fit into the local buffer to compute the correct
5005      * size even if the extern buffer is too small or not given.
5006      * (20 for ,driver,port) */
5007     insize = *namesize;
5008     len = max(100, (insize + 20));
5009     buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5010
5011     if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5012     {
5013         SetLastError (ERROR_FILE_NOT_FOUND);
5014         retval = FALSE;
5015         goto end;
5016     }
5017     TRACE("%s\n", debugstr_w(buffer));
5018
5019     if ((ptr = strchrW(buffer, ',')) == NULL)
5020     {
5021         SetLastError(ERROR_INVALID_NAME);
5022         retval = FALSE;
5023         goto end;
5024     }
5025
5026     *ptr = 0;
5027     *namesize = strlenW(buffer) + 1;
5028     if(!name || (*namesize > insize))
5029     {
5030         SetLastError(ERROR_INSUFFICIENT_BUFFER);
5031         retval = FALSE;
5032         goto end;
5033     }
5034     strcpyW(name, buffer);
5035
5036 end:
5037     HeapFree( GetProcessHeap(), 0, buffer);
5038     return retval;
5039 }
5040
5041
5042 /******************************************************************************
5043  *              GetDefaultPrinterA   (WINSPOOL.@)
5044  */
5045 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5046 {
5047     BOOL  retval = TRUE;
5048     DWORD insize = 0;
5049     WCHAR *bufferW = NULL;
5050
5051     if (!namesize)
5052     {
5053         SetLastError(ERROR_INVALID_PARAMETER);
5054         return FALSE;
5055     }
5056
5057     if(name && *namesize) {
5058         insize = *namesize;
5059         bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5060     }
5061
5062     if(!GetDefaultPrinterW( bufferW, namesize)) {
5063         retval = FALSE;
5064         goto end;
5065     }
5066
5067     *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5068                                     NULL, NULL);
5069     if (!*namesize)
5070     {
5071         *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5072         retval = FALSE;
5073     }
5074     TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5075
5076 end:
5077     HeapFree( GetProcessHeap(), 0, bufferW);
5078     return retval;
5079 }
5080
5081
5082 /******************************************************************************
5083  *              SetDefaultPrinterW   (WINSPOOL.204)
5084  *
5085  * Set the Name of the Default Printer
5086  *
5087  * PARAMS
5088  *  pszPrinter [I] Name of the Printer or NULL
5089  *
5090  * RETURNS
5091  *  Success:    True
5092  *  Failure:    FALSE
5093  *
5094  * NOTES
5095  *  When the Parameter is NULL or points to an Empty String and
5096  *  a Default Printer was already present, then this Function changes nothing.
5097  *  Without a Default Printer and NULL (or an Empty String) as Parameter,
5098  *  the First enumerated local Printer is used.
5099  *
5100  */
5101 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5102 {
5103
5104     TRACE("(%s)\n", debugstr_w(pszPrinter));
5105
5106     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5107     return FALSE;
5108 }
5109
5110 /******************************************************************************
5111  *              SetDefaultPrinterA   (WINSPOOL.202)
5112  *
5113  * See SetDefaultPrinterW.
5114  *
5115  */
5116 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5117 {
5118
5119     TRACE("(%s)\n", debugstr_a(pszPrinter));
5120
5121     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5122     return FALSE;
5123 }
5124
5125
5126 /******************************************************************************
5127  *              SetPrinterDataExA   (WINSPOOL.@)
5128  */
5129 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5130                                LPCSTR pValueName, DWORD Type,
5131                                LPBYTE pData, DWORD cbData)
5132 {
5133     HKEY hkeyPrinter, hkeySubkey;
5134     DWORD ret;
5135
5136     TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5137           debugstr_a(pValueName), Type, pData, cbData);
5138
5139     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5140        != ERROR_SUCCESS)
5141         return ret;
5142
5143     if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5144        != ERROR_SUCCESS) {
5145         ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5146         RegCloseKey(hkeyPrinter);
5147         return ret;
5148     }
5149     ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5150     RegCloseKey(hkeySubkey);
5151     RegCloseKey(hkeyPrinter);
5152     return ret;
5153 }
5154
5155 /******************************************************************************
5156  *              SetPrinterDataExW   (WINSPOOL.@)
5157  */
5158 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5159                                LPCWSTR pValueName, DWORD Type,
5160                                LPBYTE pData, DWORD cbData)
5161 {
5162     HKEY hkeyPrinter, hkeySubkey;
5163     DWORD ret;
5164
5165     TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5166           debugstr_w(pValueName), Type, pData, cbData);
5167
5168     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5169        != ERROR_SUCCESS)
5170         return ret;
5171
5172     if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5173        != ERROR_SUCCESS) {
5174         ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5175         RegCloseKey(hkeyPrinter);
5176         return ret;
5177     }
5178     ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5179     RegCloseKey(hkeySubkey);
5180     RegCloseKey(hkeyPrinter);
5181     return ret;
5182 }
5183
5184 /******************************************************************************
5185  *              SetPrinterDataA   (WINSPOOL.@)
5186  */
5187 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5188                                LPBYTE pData, DWORD cbData)
5189 {
5190     return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5191                              pData, cbData);
5192 }
5193
5194 /******************************************************************************
5195  *              SetPrinterDataW   (WINSPOOL.@)
5196  */
5197 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5198                              LPBYTE pData, DWORD cbData)
5199 {
5200     return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5201                              pData, cbData);
5202 }
5203
5204 /******************************************************************************
5205  *              GetPrinterDataExA   (WINSPOOL.@)
5206  */
5207 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5208                                LPCSTR pValueName, LPDWORD pType,
5209                                LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5210 {
5211     HKEY hkeyPrinter, hkeySubkey;
5212     DWORD ret;
5213
5214     TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5215           debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5216           pcbNeeded);
5217
5218     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5219        != ERROR_SUCCESS)
5220         return ret;
5221
5222     if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5223        != ERROR_SUCCESS) {
5224         WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5225         RegCloseKey(hkeyPrinter);
5226         return ret;
5227     }
5228     *pcbNeeded = nSize;
5229     ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5230     RegCloseKey(hkeySubkey);
5231     RegCloseKey(hkeyPrinter);
5232     return ret;
5233 }
5234
5235 /******************************************************************************
5236  *              GetPrinterDataExW   (WINSPOOL.@)
5237  */
5238 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5239                                LPCWSTR pValueName, LPDWORD pType,
5240                                LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5241 {
5242     HKEY hkeyPrinter, hkeySubkey;
5243     DWORD ret;
5244
5245     TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5246           debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5247           pcbNeeded);
5248
5249     if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5250        != ERROR_SUCCESS)
5251         return ret;
5252
5253     if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5254        != ERROR_SUCCESS) {
5255         WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5256         RegCloseKey(hkeyPrinter);
5257         return ret;
5258     }
5259     *pcbNeeded = nSize;
5260     ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5261     RegCloseKey(hkeySubkey);
5262     RegCloseKey(hkeyPrinter);
5263     return ret;
5264 }
5265
5266 /******************************************************************************
5267  *              GetPrinterDataA   (WINSPOOL.@)
5268  */
5269 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5270                              LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5271 {
5272     return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5273                              pData, nSize, pcbNeeded);
5274 }
5275
5276 /******************************************************************************
5277  *              GetPrinterDataW   (WINSPOOL.@)
5278  */
5279 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5280                              LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5281 {
5282     return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5283                              pData, nSize, pcbNeeded);
5284 }
5285
5286 /*******************************************************************************
5287  *              EnumPrinterDataExW      [WINSPOOL.@]
5288  */
5289 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5290                                 LPBYTE pEnumValues, DWORD cbEnumValues,
5291                                 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5292 {
5293     HKEY                    hkPrinter, hkSubKey;
5294     DWORD                   r, ret, dwIndex, cValues, cbMaxValueNameLen,
5295                             cbValueNameLen, cbMaxValueLen, cbValueLen,
5296                             cbBufSize, dwType;
5297     LPWSTR                  lpValueName;
5298     HANDLE                  hHeap;
5299     PBYTE                   lpValue;
5300     PPRINTER_ENUM_VALUESW   ppev;
5301
5302     TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5303
5304     if (pKeyName == NULL || *pKeyName == 0)
5305         return ERROR_INVALID_PARAMETER;
5306
5307     ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5308     if (ret != ERROR_SUCCESS)
5309     {
5310         TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5311                 hPrinter, ret);
5312         return ret;
5313     }
5314
5315     ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5316     if (ret != ERROR_SUCCESS)
5317     {
5318         r = RegCloseKey (hkPrinter);
5319         if (r != ERROR_SUCCESS)
5320             WARN ("RegCloseKey returned %i\n", r);
5321         TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5322                 debugstr_w (pKeyName), ret);
5323         return ret;
5324     }
5325
5326     ret = RegCloseKey (hkPrinter);
5327     if (ret != ERROR_SUCCESS)
5328     {
5329         ERR ("RegCloseKey returned %i\n", ret);
5330         r = RegCloseKey (hkSubKey);
5331         if (r != ERROR_SUCCESS)
5332             WARN ("RegCloseKey returned %i\n", r);
5333         return ret;
5334     }
5335
5336     ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5337             &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5338     if (ret != ERROR_SUCCESS)
5339     {
5340         r = RegCloseKey (hkSubKey);
5341         if (r != ERROR_SUCCESS)
5342             WARN ("RegCloseKey returned %i\n", r);
5343         TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5344         return ret;
5345     }
5346
5347     TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5348             "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5349
5350     if (cValues == 0)                   /* empty key */
5351     {
5352         r = RegCloseKey (hkSubKey);
5353         if (r != ERROR_SUCCESS)
5354             WARN ("RegCloseKey returned %i\n", r);
5355         *pcbEnumValues = *pnEnumValues = 0;
5356         return ERROR_SUCCESS;
5357     }
5358
5359     ++cbMaxValueNameLen;                        /* allow for trailing '\0' */
5360
5361     hHeap = GetProcessHeap ();
5362     if (hHeap == NULL)
5363     {
5364         ERR ("GetProcessHeap failed\n");
5365         r = RegCloseKey (hkSubKey);
5366         if (r != ERROR_SUCCESS)
5367             WARN ("RegCloseKey returned %i\n", r);
5368         return ERROR_OUTOFMEMORY;
5369     }
5370
5371     lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5372     if (lpValueName == NULL)
5373     {
5374         ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5375         r = RegCloseKey (hkSubKey);
5376         if (r != ERROR_SUCCESS)
5377             WARN ("RegCloseKey returned %i\n", r);
5378         return ERROR_OUTOFMEMORY;
5379     }
5380
5381     lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5382     if (lpValue == NULL)
5383     {
5384         ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5385         if (HeapFree (hHeap, 0, lpValueName) == 0)
5386             WARN ("HeapFree failed with code %i\n", GetLastError ());
5387         r = RegCloseKey (hkSubKey);
5388         if (r != ERROR_SUCCESS)
5389             WARN ("RegCloseKey returned %i\n", r);
5390         return ERROR_OUTOFMEMORY;
5391     }
5392
5393     TRACE ("pass 1: calculating buffer required for all names and values\n");
5394
5395     cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5396
5397     TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5398
5399     for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5400     {
5401         cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5402         ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5403                 NULL, NULL, lpValue, &cbValueLen);
5404         if (ret != ERROR_SUCCESS)
5405         {
5406             if (HeapFree (hHeap, 0, lpValue) == 0)
5407                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5408             if (HeapFree (hHeap, 0, lpValueName) == 0)
5409                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5410             r = RegCloseKey (hkSubKey);
5411             if (r != ERROR_SUCCESS)
5412                 WARN ("RegCloseKey returned %i\n", r);
5413             TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5414             return ret;
5415         }
5416
5417         TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5418                 debugstr_w (lpValueName), dwIndex,
5419                 cbValueNameLen + 1, cbValueLen);
5420
5421         cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5422         cbBufSize += cbValueLen;
5423     }
5424
5425     TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5426
5427     *pcbEnumValues = cbBufSize;
5428     *pnEnumValues = cValues;
5429
5430     if (cbEnumValues < cbBufSize)       /* buffer too small */
5431     {
5432         if (HeapFree (hHeap, 0, lpValue) == 0)
5433             WARN ("HeapFree failed with code %i\n", GetLastError ());
5434         if (HeapFree (hHeap, 0, lpValueName) == 0)
5435             WARN ("HeapFree failed with code %i\n", GetLastError ());
5436         r = RegCloseKey (hkSubKey);
5437         if (r != ERROR_SUCCESS)
5438             WARN ("RegCloseKey returned %i\n", r);
5439         TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5440         return ERROR_MORE_DATA;
5441     }
5442
5443     TRACE ("pass 2: copying all names and values to buffer\n");
5444
5445     ppev = (PPRINTER_ENUM_VALUESW) pEnumValues;         /* array of structs */
5446     pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5447
5448     for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5449     {
5450         cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5451         ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5452                 NULL, &dwType, lpValue, &cbValueLen);
5453         if (ret != ERROR_SUCCESS)
5454         {
5455             if (HeapFree (hHeap, 0, lpValue) == 0)
5456                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5457             if (HeapFree (hHeap, 0, lpValueName) == 0)
5458                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5459             r = RegCloseKey (hkSubKey);
5460             if (r != ERROR_SUCCESS)
5461                 WARN ("RegCloseKey returned %i\n", r);
5462             TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5463             return ret;
5464         }
5465
5466         cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5467         memcpy (pEnumValues, lpValueName, cbValueNameLen);
5468         ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5469         pEnumValues += cbValueNameLen;
5470
5471         /* return # of *bytes* (including trailing \0), not # of chars */
5472         ppev[dwIndex].cbValueName = cbValueNameLen;
5473
5474         ppev[dwIndex].dwType = dwType;
5475
5476         memcpy (pEnumValues, lpValue, cbValueLen);
5477         ppev[dwIndex].pData = pEnumValues;
5478         pEnumValues += cbValueLen;
5479
5480         ppev[dwIndex].cbData = cbValueLen;
5481
5482         TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5483                 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5484     }
5485
5486     if (HeapFree (hHeap, 0, lpValue) == 0)
5487     {
5488         ret = GetLastError ();
5489         ERR ("HeapFree failed with code %i\n", ret);
5490         if (HeapFree (hHeap, 0, lpValueName) == 0)
5491             WARN ("HeapFree failed with code %i\n", GetLastError ());
5492         r = RegCloseKey (hkSubKey);
5493         if (r != ERROR_SUCCESS)
5494             WARN ("RegCloseKey returned %i\n", r);
5495         return ret;
5496     }
5497
5498     if (HeapFree (hHeap, 0, lpValueName) == 0)
5499     {
5500         ret = GetLastError ();
5501         ERR ("HeapFree failed with code %i\n", ret);
5502         r = RegCloseKey (hkSubKey);
5503         if (r != ERROR_SUCCESS)
5504             WARN ("RegCloseKey returned %i\n", r);
5505         return ret;
5506     }
5507
5508     ret = RegCloseKey (hkSubKey);
5509     if (ret != ERROR_SUCCESS)
5510     {
5511         ERR ("RegCloseKey returned %i\n", ret);
5512         return ret;
5513     }
5514
5515     return ERROR_SUCCESS;
5516 }
5517
5518 /*******************************************************************************
5519  *              EnumPrinterDataExA      [WINSPOOL.@]
5520  *
5521  * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5522  * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers.  This is
5523  * what Windows 2000 SP1 does.
5524  *
5525  */
5526 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5527                                 LPBYTE pEnumValues, DWORD cbEnumValues,
5528                                 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5529 {
5530     INT     len;
5531     LPWSTR  pKeyNameW;
5532     DWORD   ret, dwIndex, dwBufSize;
5533     HANDLE  hHeap;
5534     LPSTR   pBuffer;
5535
5536     TRACE ("%p %s\n", hPrinter, pKeyName);
5537
5538     if (pKeyName == NULL || *pKeyName == 0)
5539         return ERROR_INVALID_PARAMETER;
5540
5541     len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5542     if (len == 0)
5543     {
5544         ret = GetLastError ();
5545         ERR ("MultiByteToWideChar failed with code %i\n", ret);
5546         return ret;
5547     }
5548
5549     hHeap = GetProcessHeap ();
5550     if (hHeap == NULL)
5551     {
5552         ERR ("GetProcessHeap failed\n");
5553         return ERROR_OUTOFMEMORY;
5554     }
5555
5556     pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5557     if (pKeyNameW == NULL)
5558     {
5559         ERR ("Failed to allocate %i bytes from process heap\n",
5560              (LONG)(len * sizeof (WCHAR)));
5561         return ERROR_OUTOFMEMORY;
5562     }
5563
5564     if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5565     {
5566         ret = GetLastError ();
5567         ERR ("MultiByteToWideChar failed with code %i\n", ret);
5568         if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5569             WARN ("HeapFree failed with code %i\n", GetLastError ());
5570         return ret;
5571     }
5572
5573     ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5574             pcbEnumValues, pnEnumValues);
5575     if (ret != ERROR_SUCCESS)
5576     {
5577         if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5578             WARN ("HeapFree failed with code %i\n", GetLastError ());
5579         TRACE ("EnumPrinterDataExW returned %i\n", ret);
5580         return ret;
5581     }
5582
5583     if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5584     {
5585         ret = GetLastError ();
5586         ERR ("HeapFree failed with code %i\n", ret);
5587         return ret;
5588     }
5589
5590     if (*pnEnumValues == 0)     /* empty key */
5591         return ERROR_SUCCESS;
5592
5593     dwBufSize = 0;
5594     for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5595     {
5596         PPRINTER_ENUM_VALUESW ppev =
5597                 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5598
5599         if (dwBufSize < ppev->cbValueName)
5600             dwBufSize = ppev->cbValueName;
5601
5602         if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5603                 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5604             dwBufSize = ppev->cbData;
5605     }
5606
5607     TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5608
5609     pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5610     if (pBuffer == NULL)
5611     {
5612         ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5613         return ERROR_OUTOFMEMORY;
5614     }
5615
5616     for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5617     {
5618         PPRINTER_ENUM_VALUESW ppev =
5619                 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5620
5621         len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5622                 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5623                 NULL);
5624         if (len == 0)
5625         {
5626             ret = GetLastError ();
5627             ERR ("WideCharToMultiByte failed with code %i\n", ret);
5628             if (HeapFree (hHeap, 0, pBuffer) == 0)
5629                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5630             return ret;
5631         }
5632
5633         memcpy (ppev->pValueName, pBuffer, len);
5634
5635         TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5636
5637         if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5638                 ppev->dwType != REG_MULTI_SZ)
5639             continue;
5640
5641         len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5642                 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5643         if (len == 0)
5644         {
5645             ret = GetLastError ();
5646             ERR ("WideCharToMultiByte failed with code %i\n", ret);
5647             if (HeapFree (hHeap, 0, pBuffer) == 0)
5648                 WARN ("HeapFree failed with code %i\n", GetLastError ());
5649             return ret;
5650         }
5651
5652         memcpy (ppev->pData, pBuffer, len);
5653
5654         TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5655         TRACE ("  (only first string of REG_MULTI_SZ printed)\n");
5656     }
5657
5658     if (HeapFree (hHeap, 0, pBuffer) == 0)
5659     {
5660         ret = GetLastError ();
5661         ERR ("HeapFree failed with code %i\n", ret);
5662         return ret;
5663     }
5664
5665     return ERROR_SUCCESS;
5666 }
5667
5668 /******************************************************************************
5669  *      AbortPrinter (WINSPOOL.@)
5670  */
5671 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5672 {
5673     FIXME("(%p), stub!\n", hPrinter);
5674     return TRUE;
5675 }
5676
5677 /******************************************************************************
5678  *              AddPortA (WINSPOOL.@)
5679  *
5680  * See AddPortW.
5681  *
5682  */
5683 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5684 {
5685     LPWSTR  nameW = NULL;
5686     LPWSTR  monitorW = NULL;
5687     DWORD   len;
5688     BOOL    res;
5689
5690     TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5691
5692     if (pName) {
5693         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5694         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5695         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5696     }
5697
5698     if (pMonitorName) {
5699         len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5700         monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5701         MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5702     }
5703     res = AddPortW(nameW, hWnd, monitorW);
5704     HeapFree(GetProcessHeap(), 0, nameW);
5705     HeapFree(GetProcessHeap(), 0, monitorW);
5706     return res;
5707 }
5708
5709 /******************************************************************************
5710  *      AddPortW (WINSPOOL.@)
5711  *
5712  * Add a Port for a specific Monitor
5713  *
5714  * PARAMS
5715  *  pName        [I] Servername or NULL (local Computer)
5716  *  hWnd         [I] Handle to parent Window for the Dialog-Box
5717  *  pMonitorName [I] Name of the Monitor that manage the Port
5718  *
5719  * RETURNS
5720  *  Success: TRUE
5721  *  Failure: FALSE
5722  *
5723  */
5724 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5725 {
5726     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5727
5728     if ((backend == NULL)  && !load_backend()) return FALSE;
5729
5730     if (!pMonitorName) {
5731         SetLastError(RPC_X_NULL_REF_POINTER);
5732         return FALSE;
5733     }
5734
5735     return backend->fpAddPort(pName, hWnd, pMonitorName);
5736 }
5737
5738 /******************************************************************************
5739  *             AddPortExA (WINSPOOL.@)
5740  *
5741  * See AddPortExW.
5742  *
5743  */
5744 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5745 {
5746     PORT_INFO_2W   pi2W;
5747     PORT_INFO_2A * pi2A;
5748     LPWSTR  nameW = NULL;
5749     LPWSTR  monitorW = NULL;
5750     DWORD   len;
5751     BOOL    res;
5752
5753     pi2A = (PORT_INFO_2A *) pBuffer;
5754
5755     TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5756             debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5757
5758     if ((level < 1) || (level > 2)) {
5759         SetLastError(ERROR_INVALID_LEVEL);
5760         return FALSE;
5761     }
5762
5763     if (!pi2A) {
5764         SetLastError(ERROR_INVALID_PARAMETER);
5765         return FALSE;
5766     }
5767
5768     if (pName) {
5769         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5770         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5771         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5772     }
5773
5774     if (pMonitorName) {
5775         len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5776         monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5777         MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5778     }
5779
5780     ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5781
5782     if (pi2A->pPortName) {
5783         len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5784         pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5785         MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
5786     }
5787
5788     if (level > 1) {
5789         if (pi2A->pMonitorName) {
5790             len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
5791             pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5792             MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
5793         }
5794
5795         if (pi2A->pDescription) {
5796             len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
5797             pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5798             MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
5799         }
5800         pi2W.fPortType = pi2A->fPortType;
5801         pi2W.Reserved = pi2A->Reserved;
5802     }
5803
5804     res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
5805
5806     HeapFree(GetProcessHeap(), 0, nameW);
5807     HeapFree(GetProcessHeap(), 0, monitorW);
5808     HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
5809     HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
5810     HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
5811     return res;
5812
5813 }
5814
5815 /******************************************************************************
5816  *             AddPortExW (WINSPOOL.@)
5817  *
5818  * Add a Port for a specific Monitor, without presenting a user interface
5819  *
5820  * PARAMS
5821  *  pName         [I] Servername or NULL (local Computer)
5822  *  level         [I] Structure-Level (1 or 2) for pBuffer
5823  *  pBuffer       [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5824  *  pMonitorName  [I] Name of the Monitor that manage the Port
5825  *
5826  * RETURNS
5827  *  Success: TRUE
5828  *  Failure: FALSE
5829  *
5830  */
5831 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
5832 {
5833     PORT_INFO_2W * pi2;
5834
5835     pi2 = (PORT_INFO_2W *) pBuffer;
5836
5837     TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
5838             debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
5839             debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
5840             debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
5841
5842     if ((backend == NULL)  && !load_backend()) return FALSE;
5843
5844     if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
5845         SetLastError(ERROR_INVALID_PARAMETER);
5846         return FALSE;
5847     }
5848
5849     return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
5850 }
5851
5852 /******************************************************************************
5853  *      AddPrinterConnectionA (WINSPOOL.@)
5854  */
5855 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5856 {
5857     FIXME("%s\n", debugstr_a(pName));
5858     return FALSE;
5859 }
5860
5861 /******************************************************************************
5862  *      AddPrinterConnectionW (WINSPOOL.@)
5863  */
5864 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5865 {
5866     FIXME("%s\n", debugstr_w(pName));
5867     return FALSE;
5868 }
5869
5870 /******************************************************************************
5871  *  AddPrinterDriverExW (WINSPOOL.@)
5872  *
5873  * Install a Printer Driver with the Option to upgrade / downgrade the Files
5874  *
5875  * PARAMS
5876  *  pName           [I] Servername or NULL (local Computer)
5877  *  level           [I] Level for the supplied DRIVER_INFO_*W struct
5878  *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5879  *  dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
5880  *
5881  * RESULTS
5882  *  Success: TRUE
5883  *  Failure: FALSE
5884  *
5885  */
5886 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5887 {
5888     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
5889
5890     if ((backend == NULL)  && !load_backend()) return FALSE;
5891
5892     if (level < 2 || level == 5 || level == 7 || level > 8) {
5893         SetLastError(ERROR_INVALID_LEVEL);
5894         return FALSE;
5895     }
5896
5897     if (!pDriverInfo) {
5898         SetLastError(ERROR_INVALID_PARAMETER);
5899         return FALSE;
5900     }
5901
5902     return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
5903 }
5904
5905 /******************************************************************************
5906  *  AddPrinterDriverExA (WINSPOOL.@)
5907  *
5908  * See AddPrinterDriverExW.
5909  *
5910  */
5911 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5912 {
5913     DRIVER_INFO_8A  *diA;
5914     DRIVER_INFO_8W   diW;
5915     LPWSTR  nameW = NULL;
5916     DWORD   lenA;
5917     DWORD   len;
5918     DWORD   res = FALSE;
5919
5920     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
5921
5922     diA = (DRIVER_INFO_8A  *) pDriverInfo;
5923     ZeroMemory(&diW, sizeof(diW));
5924
5925     if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
5926         SetLastError(ERROR_INVALID_LEVEL);
5927         return FALSE;
5928     }
5929
5930     if (diA == NULL) {
5931         SetLastError(ERROR_INVALID_PARAMETER);
5932         return FALSE;
5933     }
5934
5935     /* convert servername to unicode */
5936     if (pName) {
5937         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5938         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5939         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5940     }
5941
5942     /* common fields */
5943     diW.cVersion = diA->cVersion;
5944
5945     if (diA->pName) {
5946         len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
5947         diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5948         MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
5949     }
5950
5951     if (diA->pEnvironment) {
5952         len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
5953         diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5954         MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
5955     }
5956
5957     if (diA->pDriverPath) {
5958         len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
5959         diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5960         MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
5961     }
5962
5963     if (diA->pDataFile) {
5964         len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
5965         diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5966         MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
5967     }
5968
5969     if (diA->pConfigFile) {
5970         len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
5971         diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5972         MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
5973     }
5974
5975     if ((Level > 2) && diA->pDependentFiles) {
5976         lenA = multi_sz_lenA(diA->pDependentFiles);
5977         len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
5978         diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5979         MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
5980     }
5981
5982     if ((Level > 2) && diA->pMonitorName) {
5983         len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
5984         diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5985         MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
5986     }
5987
5988     if ((Level > 3) && diA->pDefaultDataType) {
5989         len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
5990         diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5991         MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
5992     }
5993
5994     if ((Level > 3) && diA->pszzPreviousNames) {
5995         lenA = multi_sz_lenA(diA->pszzPreviousNames);
5996         len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
5997         diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5998         MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
5999     }
6000
6001     if ((Level > 5) && diA->pszMfgName) {
6002         len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6003         diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6004         MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6005     }
6006
6007     if ((Level > 5) && diA->pszOEMUrl) {
6008         len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6009         diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6010         MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6011     }
6012
6013     if ((Level > 5) && diA->pszHardwareID) {
6014         len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6015         diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6016         MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6017     }
6018
6019     if ((Level > 5) && diA->pszProvider) {
6020         len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6021         diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6022         MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6023     }
6024
6025     if (Level > 7) {
6026         FIXME("level %u is incomplete\n", Level);
6027     }
6028
6029     res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6030     TRACE("got %u with %u\n", res, GetLastError());
6031     HeapFree(GetProcessHeap(), 0, nameW);
6032     HeapFree(GetProcessHeap(), 0, diW.pName);
6033     HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6034     HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6035     HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6036     HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6037     HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6038     HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6039     HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6040     HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6041     HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6042     HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6043     HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6044     HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6045
6046     TRACE("=> %u with %u\n", res, GetLastError());
6047     return res;
6048 }
6049
6050 /******************************************************************************
6051  *      ConfigurePortA (WINSPOOL.@)
6052  *
6053  * See ConfigurePortW.
6054  *
6055  */
6056 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6057 {
6058     LPWSTR  nameW = NULL;
6059     LPWSTR  portW = NULL;
6060     INT     len;
6061     DWORD   res;
6062
6063     TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6064
6065     /* convert servername to unicode */
6066     if (pName) {
6067         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6068         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6069         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6070     }
6071
6072     /* convert portname to unicode */
6073     if (pPortName) {
6074         len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6075         portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6076         MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6077     }
6078
6079     res = ConfigurePortW(nameW, hWnd, portW);
6080     HeapFree(GetProcessHeap(), 0, nameW);
6081     HeapFree(GetProcessHeap(), 0, portW);
6082     return res;
6083 }
6084
6085 /******************************************************************************
6086  *      ConfigurePortW (WINSPOOL.@)
6087  *
6088  * Display the Configuration-Dialog for a specific Port
6089  *
6090  * PARAMS
6091  *  pName     [I] Servername or NULL (local Computer)
6092  *  hWnd      [I] Handle to parent Window for the Dialog-Box
6093  *  pPortName [I] Name of the Port, that should be configured
6094  *
6095  * RETURNS
6096  *  Success: TRUE
6097  *  Failure: FALSE
6098  *
6099  */
6100 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6101 {
6102
6103     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6104
6105     if ((backend == NULL)  && !load_backend()) return FALSE;
6106
6107     if (!pPortName) {
6108         SetLastError(RPC_X_NULL_REF_POINTER);
6109         return FALSE;
6110     }
6111
6112     return backend->fpConfigurePort(pName, hWnd, pPortName);
6113 }
6114
6115 /******************************************************************************
6116  *      ConnectToPrinterDlg (WINSPOOL.@)
6117  */
6118 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6119 {
6120     FIXME("%p %x\n", hWnd, Flags);
6121     return NULL;
6122 }
6123
6124 /******************************************************************************
6125  *      DeletePrinterConnectionA (WINSPOOL.@)
6126  */
6127 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6128 {
6129     FIXME("%s\n", debugstr_a(pName));
6130     return TRUE;
6131 }
6132
6133 /******************************************************************************
6134  *      DeletePrinterConnectionW (WINSPOOL.@)
6135  */
6136 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6137 {
6138     FIXME("%s\n", debugstr_w(pName));
6139     return TRUE;
6140 }
6141
6142 /******************************************************************************
6143  *              DeletePrinterDriverExW (WINSPOOL.@)
6144  */
6145 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6146     LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6147 {
6148     HKEY hkey_drivers;
6149     BOOL ret = FALSE;
6150
6151     TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6152           debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6153
6154     if(pName && pName[0])
6155     {
6156         FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6157         SetLastError(ERROR_INVALID_PARAMETER);
6158         return FALSE;
6159     }
6160
6161     if(dwDeleteFlag)
6162     {
6163         FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6164         SetLastError(ERROR_INVALID_PARAMETER);
6165         return FALSE;
6166     }
6167
6168     hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6169
6170     if(!hkey_drivers)
6171     {
6172         ERR("Can't open drivers key\n");
6173         return FALSE;
6174     }
6175
6176     if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6177         ret = TRUE;
6178
6179     RegCloseKey(hkey_drivers);
6180
6181     return ret;
6182 }
6183
6184 /******************************************************************************
6185  *              DeletePrinterDriverExA (WINSPOOL.@)
6186  */
6187 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6188     LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6189 {
6190     UNICODE_STRING NameW, EnvW, DriverW;
6191     BOOL ret;
6192
6193     asciitounicode(&NameW, pName);
6194     asciitounicode(&EnvW, pEnvironment);
6195     asciitounicode(&DriverW, pDriverName);
6196
6197     ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6198
6199     RtlFreeUnicodeString(&DriverW);
6200     RtlFreeUnicodeString(&EnvW);
6201     RtlFreeUnicodeString(&NameW);
6202
6203     return ret;
6204 }
6205
6206 /******************************************************************************
6207  *              DeletePrinterDataExW (WINSPOOL.@)
6208  */
6209 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6210                                   LPCWSTR pValueName)
6211 {
6212     FIXME("%p %s %s\n", hPrinter, 
6213           debugstr_w(pKeyName), debugstr_w(pValueName));
6214     return ERROR_INVALID_PARAMETER;
6215 }
6216
6217 /******************************************************************************
6218  *              DeletePrinterDataExA (WINSPOOL.@)
6219  */
6220 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6221                                   LPCSTR pValueName)
6222 {
6223     FIXME("%p %s %s\n", hPrinter, 
6224           debugstr_a(pKeyName), debugstr_a(pValueName));
6225     return ERROR_INVALID_PARAMETER;
6226 }
6227
6228 /******************************************************************************
6229  *      DeletePrintProcessorA (WINSPOOL.@)
6230  */
6231 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6232 {
6233     FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6234           debugstr_a(pPrintProcessorName));
6235     return TRUE;
6236 }
6237
6238 /******************************************************************************
6239  *      DeletePrintProcessorW (WINSPOOL.@)
6240  */
6241 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6242 {
6243     FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6244           debugstr_w(pPrintProcessorName));
6245     return TRUE;
6246 }
6247
6248 /******************************************************************************
6249  *      DeletePrintProvidorA (WINSPOOL.@)
6250  */
6251 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6252 {
6253     FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6254           debugstr_a(pPrintProviderName));
6255     return TRUE;
6256 }
6257
6258 /******************************************************************************
6259  *      DeletePrintProvidorW (WINSPOOL.@)
6260  */
6261 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6262 {
6263     FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6264           debugstr_w(pPrintProviderName));
6265     return TRUE;
6266 }
6267
6268 /******************************************************************************
6269  *      EnumFormsA (WINSPOOL.@)
6270  */
6271 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6272     DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6273 {
6274     FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6275     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6276     return FALSE;
6277 }
6278
6279 /******************************************************************************
6280  *      EnumFormsW (WINSPOOL.@)
6281  */
6282 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6283     DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6284 {
6285     FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6286     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6287     return FALSE;
6288 }
6289
6290 /*****************************************************************************
6291  *          EnumMonitorsA [WINSPOOL.@]
6292  *
6293  * See EnumMonitorsW.
6294  *
6295  */
6296 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6297                           DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6298 {
6299     BOOL    res;
6300     LPBYTE  bufferW = NULL;
6301     LPWSTR  nameW = NULL;
6302     DWORD   needed = 0;
6303     DWORD   numentries = 0;
6304     INT     len;
6305
6306     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6307           cbBuf, pcbNeeded, pcReturned);
6308
6309     /* convert servername to unicode */
6310     if (pName) {
6311         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6312         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6313         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6314     }
6315     /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6316     needed = cbBuf * sizeof(WCHAR);    
6317     if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6318     res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6319
6320     if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6321         if (pcbNeeded) needed = *pcbNeeded;
6322         /* HeapReAlloc return NULL, when bufferW was NULL */
6323         bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6324                               HeapAlloc(GetProcessHeap(), 0, needed);
6325
6326         /* Try again with the large Buffer */
6327         res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6328     }
6329     numentries = pcReturned ? *pcReturned : 0;
6330     needed = 0;
6331     /*
6332        W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6333        We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6334      */
6335     if (res) {
6336         /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6337         DWORD   entrysize = 0;
6338         DWORD   index;
6339         LPSTR   ptr;
6340         LPMONITOR_INFO_2W mi2w;
6341         LPMONITOR_INFO_2A mi2a;
6342
6343         /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6344         entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6345
6346         /* First pass: calculate the size for all Entries */
6347         mi2w = (LPMONITOR_INFO_2W) bufferW;
6348         mi2a = (LPMONITOR_INFO_2A) pMonitors;
6349         index = 0;
6350         while (index < numentries) {
6351             index++;
6352             needed += entrysize;    /* MONITOR_INFO_?A */
6353             TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6354
6355             needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6356                                             NULL, 0, NULL, NULL);
6357             if (Level > 1) {
6358                 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6359                                                 NULL, 0, NULL, NULL);
6360                 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6361                                                 NULL, 0, NULL, NULL);
6362             }
6363             /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6364             mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6365             mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6366         }
6367
6368         /* check for errors and quit on failure */
6369         if (cbBuf < needed) {
6370             SetLastError(ERROR_INSUFFICIENT_BUFFER);
6371             res = FALSE;
6372             goto emA_cleanup;
6373         }
6374         len = entrysize * numentries;       /* room for all MONITOR_INFO_?A */
6375         ptr = (LPSTR) &pMonitors[len];      /* room for strings */
6376         cbBuf -= len ;                      /* free Bytes in the user-Buffer */
6377         mi2w = (LPMONITOR_INFO_2W) bufferW;
6378         mi2a = (LPMONITOR_INFO_2A) pMonitors;
6379         index = 0;
6380         /* Second Pass: Fill the User Buffer (if we have one) */
6381         while ((index < numentries) && pMonitors) {
6382             index++;
6383             TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6384             mi2a->pName = ptr;
6385             len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6386                                             ptr, cbBuf , NULL, NULL);
6387             ptr += len;
6388             cbBuf -= len;
6389             if (Level > 1) {
6390                 mi2a->pEnvironment = ptr;
6391                 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6392                                             ptr, cbBuf, NULL, NULL);
6393                 ptr += len;
6394                 cbBuf -= len;
6395
6396                 mi2a->pDLLName = ptr;
6397                 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6398                                             ptr, cbBuf, NULL, NULL);
6399                 ptr += len;
6400                 cbBuf -= len;
6401             }
6402             /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6403             mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6404             mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6405         }
6406     }
6407 emA_cleanup:
6408     if (pcbNeeded)  *pcbNeeded = needed;
6409     if (pcReturned) *pcReturned = (res) ? numentries : 0;
6410
6411     HeapFree(GetProcessHeap(), 0, nameW);
6412     HeapFree(GetProcessHeap(), 0, bufferW);
6413
6414     TRACE("returning %d with %d (%d byte for %d entries)\n", 
6415             (res), GetLastError(), needed, numentries);
6416
6417     return (res);
6418
6419 }
6420
6421 /*****************************************************************************
6422  *          EnumMonitorsW [WINSPOOL.@]
6423  *
6424  * Enumerate available Port-Monitors
6425  *
6426  * PARAMS
6427  *  pName       [I] Servername or NULL (local Computer)
6428  *  Level       [I] Structure-Level (1:Win9x+NT or 2:NT only)
6429  *  pMonitors   [O] PTR to Buffer that receives the Result
6430  *  cbBuf       [I] Size of Buffer at pMonitors
6431  *  pcbNeeded   [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6432  *  pcReturned  [O] PTR to DWORD that receives the number of Monitors in pMonitors
6433  *
6434  * RETURNS
6435  *  Success: TRUE
6436  *  Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6437  *
6438  */
6439 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6440                           DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6441 {
6442
6443     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6444           cbBuf, pcbNeeded, pcReturned);
6445
6446     if ((backend == NULL)  && !load_backend()) return FALSE;
6447
6448     if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6449         SetLastError(RPC_X_NULL_REF_POINTER);
6450         return FALSE;
6451     }
6452
6453     return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6454 }
6455
6456 /******************************************************************************
6457  * SpoolerInit (WINSPOOL.@)
6458  *
6459  * Initialize the Spooler
6460  *
6461  * RETURNS
6462  *  Success: TRUE
6463  *  Failure: FALSE
6464  *
6465  * NOTES
6466  *  The function fails on windows, when the spooler service is not running
6467  *
6468  */
6469 BOOL WINAPI SpoolerInit(void)
6470 {
6471
6472     if ((backend == NULL)  && !load_backend()) return FALSE;
6473     return TRUE;
6474 }
6475
6476 /******************************************************************************
6477  *              XcvDataW (WINSPOOL.@)
6478  *
6479  * Execute commands in the Printmonitor DLL
6480  *
6481  * PARAMS
6482  *  hXcv            [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6483  *  pszDataName     [i] Name of the command to execute
6484  *  pInputData      [i] Buffer for extra Input Data (needed only for some commands)
6485  *  cbInputData     [i] Size in Bytes of Buffer at pInputData
6486  *  pOutputData     [o] Buffer to receive additional Data (needed only for some commands)
6487  *  cbOutputData    [i] Size in Bytes of Buffer at pOutputData
6488  *  pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6489  *  pdwStatus       [o] PTR to receive the win32 error code from the Printmonitor DLL
6490  *
6491  * RETURNS
6492  *  Success: TRUE
6493  *  Failure: FALSE
6494  *
6495  * NOTES
6496  *  Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6497  *  The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6498  *
6499  *  Minimal List of commands, that a Printmonitor DLL should support:
6500  *
6501  *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6502  *| "AddPort"   : Add a Port
6503  *| "DeletePort": Delete a Port
6504  *
6505  *  Many Printmonitors support additional commands. Examples for localspl.dll:
6506  *  "GetDefaultCommConfig", "SetDefaultCommConfig",
6507  *  "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6508  *
6509  */
6510 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6511     DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6512     PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6513 {
6514     opened_printer_t *printer;
6515
6516     TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6517           pInputData, cbInputData, pOutputData,
6518           cbOutputData, pcbOutputNeeded, pdwStatus);
6519
6520     if ((backend == NULL)  && !load_backend()) return FALSE;
6521
6522     printer = get_opened_printer(hXcv);
6523     if (!printer || (!printer->backend_printer)) {
6524         SetLastError(ERROR_INVALID_HANDLE);
6525         return FALSE;
6526     }
6527
6528     if (!pcbOutputNeeded) {
6529         SetLastError(ERROR_INVALID_PARAMETER);
6530         return FALSE;
6531     }
6532
6533     if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6534         SetLastError(RPC_X_NULL_REF_POINTER);
6535         return FALSE;
6536     }
6537
6538     *pcbOutputNeeded = 0;
6539
6540     return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6541                     cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6542
6543 }
6544
6545 /*****************************************************************************
6546  *          EnumPrinterDataA [WINSPOOL.@]
6547  *
6548  */
6549 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6550     DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6551     DWORD cbData, LPDWORD pcbData )
6552 {
6553     FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6554           cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6555     return ERROR_NO_MORE_ITEMS;
6556 }
6557
6558 /*****************************************************************************
6559  *          EnumPrinterDataW [WINSPOOL.@]
6560  *
6561  */
6562 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6563     DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6564     DWORD cbData, LPDWORD pcbData )
6565 {
6566     FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6567           cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6568     return ERROR_NO_MORE_ITEMS;
6569 }
6570
6571 /*****************************************************************************
6572  *          EnumPrintProcessorDatatypesA [WINSPOOL.@]
6573  *
6574  */
6575 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6576                                          DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6577                                          LPDWORD pcbNeeded, LPDWORD pcReturned)
6578 {
6579     FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6580           debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6581           pcbNeeded, pcReturned);
6582     return FALSE;
6583 }
6584
6585 /*****************************************************************************
6586  *          EnumPrintProcessorDatatypesW [WINSPOOL.@]
6587  *
6588  */
6589 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6590                                          DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6591                                          LPDWORD pcbNeeded, LPDWORD pcReturned)
6592 {
6593     FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6594           debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6595           pcbNeeded, pcReturned);
6596     return FALSE;
6597 }
6598
6599 /*****************************************************************************
6600  *          EnumPrintProcessorsA [WINSPOOL.@]
6601  *
6602  * See EnumPrintProcessorsW.
6603  *
6604  */
6605 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level, 
6606                             LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6607 {
6608     BOOL    res;
6609     LPBYTE  bufferW = NULL;
6610     LPWSTR  nameW = NULL;
6611     LPWSTR  envW = NULL;
6612     DWORD   needed = 0;
6613     DWORD   numentries = 0;
6614     INT     len;
6615
6616     TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6617                 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6618
6619     /* convert names to unicode */
6620     if (pName) {
6621         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6622         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6623         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6624     }
6625     if (pEnvironment) {
6626         len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6627         envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6628         MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6629     }
6630
6631     /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6632     needed = cbBuf * sizeof(WCHAR);
6633     if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6634     res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6635
6636     if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6637         if (pcbNeeded) needed = *pcbNeeded;
6638         /* HeapReAlloc return NULL, when bufferW was NULL */
6639         bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6640                               HeapAlloc(GetProcessHeap(), 0, needed);
6641
6642         /* Try again with the large Buffer */
6643         res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6644     }
6645     numentries = pcReturned ? *pcReturned : 0;
6646     needed = 0;
6647
6648     if (res) {
6649         /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6650         DWORD   index;
6651         LPSTR   ptr;
6652         PPRINTPROCESSOR_INFO_1W ppiw;
6653         PPRINTPROCESSOR_INFO_1A ppia;
6654
6655         /* First pass: calculate the size for all Entries */
6656         ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6657         ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6658         index = 0;
6659         while (index < numentries) {
6660             index++;
6661             needed += sizeof(PRINTPROCESSOR_INFO_1A);
6662             TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6663
6664             needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6665                                             NULL, 0, NULL, NULL);
6666
6667             ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6668             ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6669         }
6670
6671         /* check for errors and quit on failure */
6672         if (cbBuf < needed) {
6673             SetLastError(ERROR_INSUFFICIENT_BUFFER);
6674             res = FALSE;
6675             goto epp_cleanup;
6676         }
6677
6678         len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6679         ptr = (LPSTR) &pPPInfo[len];        /* start of strings */
6680         cbBuf -= len ;                      /* free Bytes in the user-Buffer */
6681         ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6682         ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6683         index = 0;
6684         /* Second Pass: Fill the User Buffer (if we have one) */
6685         while ((index < numentries) && pPPInfo) {
6686             index++;
6687             TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6688             ppia->pName = ptr;
6689             len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6690                                             ptr, cbBuf , NULL, NULL);
6691             ptr += len;
6692             cbBuf -= len;
6693
6694             ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6695             ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6696
6697         }
6698     }
6699 epp_cleanup:
6700     if (pcbNeeded)  *pcbNeeded = needed;
6701     if (pcReturned) *pcReturned = (res) ? numentries : 0;
6702
6703     HeapFree(GetProcessHeap(), 0, nameW);
6704     HeapFree(GetProcessHeap(), 0, envW);
6705     HeapFree(GetProcessHeap(), 0, bufferW);
6706
6707     TRACE("returning %d with %d (%d byte for %d entries)\n",
6708             (res), GetLastError(), needed, numentries);
6709
6710     return (res);
6711 }
6712
6713 /*****************************************************************************
6714  *          EnumPrintProcessorsW [WINSPOOL.@]
6715  *
6716  * Enumerate available Print Processors
6717  *
6718  * PARAMS
6719  *  pName        [I] Servername or NULL (local Computer)
6720  *  pEnvironment [I] Printing-Environment or NULL (Default)
6721  *  Level        [I] Structure-Level (Only 1 is allowed)
6722  *  pPPInfo      [O] PTR to Buffer that receives the Result
6723  *  cbBuf        [I] Size of Buffer at pPPInfo
6724  *  pcbNeeded    [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6725  *  pcReturned   [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6726  *
6727  * RETURNS
6728  *  Success: TRUE
6729  *  Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6730  *
6731  */
6732 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6733                             LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6734 {
6735
6736     TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
6737                                 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6738
6739     if ((backend == NULL)  && !load_backend()) return FALSE;
6740
6741     if (!pcbNeeded || !pcReturned) {
6742         SetLastError(RPC_X_NULL_REF_POINTER);
6743         return FALSE;
6744     }
6745
6746     if (!pPPInfo && (cbBuf > 0)) {
6747         SetLastError(ERROR_INVALID_USER_BUFFER);
6748         return FALSE;
6749     }
6750
6751     return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
6752                                           cbBuf, pcbNeeded, pcReturned);
6753 }
6754
6755 /*****************************************************************************
6756  *          ExtDeviceMode [WINSPOOL.@]
6757  *
6758  */
6759 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6760     LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6761     DWORD fMode)
6762 {
6763     FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6764           debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6765           debugstr_a(pProfile), fMode);
6766     return -1;
6767 }
6768
6769 /*****************************************************************************
6770  *          FindClosePrinterChangeNotification [WINSPOOL.@]
6771  *
6772  */
6773 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6774 {
6775     FIXME("Stub: %p\n", hChange);
6776     return TRUE;
6777 }
6778
6779 /*****************************************************************************
6780  *          FindFirstPrinterChangeNotification [WINSPOOL.@]
6781  *
6782  */
6783 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6784     DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6785 {
6786     FIXME("Stub: %p %x %x %p\n",
6787           hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6788     return INVALID_HANDLE_VALUE;
6789 }
6790
6791 /*****************************************************************************
6792  *          FindNextPrinterChangeNotification [WINSPOOL.@]
6793  *
6794  */
6795 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6796     LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6797 {
6798     FIXME("Stub: %p %p %p %p\n",
6799           hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6800     return FALSE;
6801 }
6802
6803 /*****************************************************************************
6804  *          FreePrinterNotifyInfo [WINSPOOL.@]
6805  *
6806  */
6807 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6808 {
6809     FIXME("Stub: %p\n", pPrinterNotifyInfo);
6810     return TRUE;
6811 }
6812
6813 /*****************************************************************************
6814  *          string_to_buf
6815  *
6816  * Copies a unicode string into a buffer.  The buffer will either contain unicode or
6817  * ansi depending on the unicode parameter.
6818  */
6819 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6820 {
6821     if(!str)
6822     {
6823         *size = 0;
6824         return TRUE;
6825     }
6826
6827     if(unicode)
6828     {
6829         *size = (strlenW(str) + 1) * sizeof(WCHAR);
6830         if(*size <= cb)
6831         {
6832             memcpy(ptr, str, *size);
6833             return TRUE;
6834         }
6835         return FALSE;
6836     }
6837     else
6838     {
6839         *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6840         if(*size <= cb)
6841         {
6842             WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6843             return TRUE;
6844         }
6845         return FALSE;
6846     }
6847 }
6848
6849 /*****************************************************************************
6850  *          get_job_info_1
6851  */
6852 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6853                            LPDWORD pcbNeeded, BOOL unicode)
6854 {
6855     DWORD size, left = cbBuf;
6856     BOOL space = (cbBuf > 0);
6857     LPBYTE ptr = buf;
6858
6859     *pcbNeeded = 0;
6860
6861     if(space)
6862     {
6863         ji1->JobId = job->job_id;
6864     }
6865
6866     string_to_buf(job->document_title, ptr, left, &size, unicode);
6867     if(space && size <= left)
6868     {
6869         ji1->pDocument = (LPWSTR)ptr;
6870         ptr += size;
6871         left -= size;
6872     }
6873     else
6874         space = FALSE;
6875     *pcbNeeded += size;
6876
6877     return space;
6878 }
6879
6880 /*****************************************************************************
6881  *          get_job_info_2
6882  */
6883 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6884                            LPDWORD pcbNeeded, BOOL unicode)
6885 {
6886     DWORD size, left = cbBuf;
6887     BOOL space = (cbBuf > 0);
6888     LPBYTE ptr = buf;
6889
6890     *pcbNeeded = 0;
6891
6892     if(space)
6893     {
6894         ji2->JobId = job->job_id;
6895     }
6896
6897     string_to_buf(job->document_title, ptr, left, &size, unicode);
6898     if(space && size <= left)
6899     {
6900         ji2->pDocument = (LPWSTR)ptr;
6901         ptr += size;
6902         left -= size;
6903     }
6904     else
6905         space = FALSE;
6906     *pcbNeeded += size;
6907
6908     return space;
6909 }
6910
6911 /*****************************************************************************
6912  *          get_job_info
6913  */
6914 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6915                          DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6916 {
6917     BOOL ret = FALSE;
6918     DWORD needed = 0, size;
6919     job_t *job;
6920     LPBYTE ptr = pJob;
6921
6922     TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6923
6924     EnterCriticalSection(&printer_handles_cs);
6925     job = get_job(hPrinter, JobId);
6926     if(!job)
6927         goto end;
6928
6929     switch(Level)
6930     {
6931     case 1:
6932         size = sizeof(JOB_INFO_1W);
6933         if(cbBuf >= size)
6934         {
6935             cbBuf -= size;
6936             ptr += size;
6937             memset(pJob, 0, size);
6938         }
6939         else
6940             cbBuf = 0;
6941         ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6942         needed += size;
6943         break;
6944
6945     case 2:
6946         size = sizeof(JOB_INFO_2W);
6947         if(cbBuf >= size)
6948         {
6949             cbBuf -= size;
6950             ptr += size;
6951             memset(pJob, 0, size);
6952         }
6953         else
6954             cbBuf = 0;
6955         ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6956         needed += size;
6957         break;
6958
6959     case 3:
6960         size = sizeof(JOB_INFO_3);
6961         if(cbBuf >= size)
6962         {
6963             cbBuf -= size;
6964             memset(pJob, 0, size);
6965             ret = TRUE;
6966         }
6967         else
6968             cbBuf = 0;
6969         needed = size;
6970         break;
6971
6972     default:
6973         SetLastError(ERROR_INVALID_LEVEL);
6974         goto end;
6975     }
6976     if(pcbNeeded)
6977         *pcbNeeded = needed;
6978 end:
6979     LeaveCriticalSection(&printer_handles_cs);
6980     return ret;
6981 }
6982
6983 /*****************************************************************************
6984  *          GetJobA [WINSPOOL.@]
6985  *
6986  */
6987 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6988                     DWORD cbBuf, LPDWORD pcbNeeded)
6989 {
6990     return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6991 }
6992
6993 /*****************************************************************************
6994  *          GetJobW [WINSPOOL.@]
6995  *
6996  */
6997 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6998                     DWORD cbBuf, LPDWORD pcbNeeded)
6999 {
7000     return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7001 }
7002
7003 /*****************************************************************************
7004  *          schedule_lpr
7005  */
7006 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7007 {
7008     char *unixname, *queue, *cmd;
7009     char fmt[] = "lpr -P%s %s";
7010     DWORD len;
7011     int r;
7012
7013     if(!(unixname = wine_get_unix_file_name(filename)))
7014         return FALSE;
7015
7016     len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7017     queue = HeapAlloc(GetProcessHeap(), 0, len);
7018     WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7019
7020     cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7021     sprintf(cmd, fmt, queue, unixname);
7022
7023     TRACE("printing with: %s\n", cmd);
7024     r = system(cmd);
7025
7026     HeapFree(GetProcessHeap(), 0, cmd);
7027     HeapFree(GetProcessHeap(), 0, queue);
7028     HeapFree(GetProcessHeap(), 0, unixname);
7029     return (r == 0);
7030 }
7031
7032 /*****************************************************************************
7033  *          schedule_cups
7034  */
7035 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7036 {
7037 #ifdef SONAME_LIBCUPS
7038     if(pcupsPrintFile)
7039     {
7040         char *unixname, *queue, *unix_doc_title;
7041         DWORD len;
7042         BOOL ret;
7043
7044         if(!(unixname = wine_get_unix_file_name(filename)))
7045             return FALSE;
7046
7047         len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7048         queue = HeapAlloc(GetProcessHeap(), 0, len);
7049         WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7050
7051         len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7052         unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7053         WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7054
7055         TRACE("printing via cups\n");
7056         ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7057         HeapFree(GetProcessHeap(), 0, unix_doc_title);
7058         HeapFree(GetProcessHeap(), 0, queue);
7059         HeapFree(GetProcessHeap(), 0, unixname);
7060         return ret;
7061     }
7062     else
7063 #endif
7064     {
7065         return schedule_lpr(printer_name, filename);
7066     }
7067 }
7068
7069 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7070 {
7071     LPWSTR filename;
7072
7073     switch(msg)
7074     {
7075     case WM_INITDIALOG:
7076         SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7077         return TRUE;
7078
7079     case WM_COMMAND:
7080         if(HIWORD(wparam) == BN_CLICKED)
7081         {
7082             if(LOWORD(wparam) == IDOK)
7083             {
7084                 HANDLE hf;
7085                 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7086                 LPWSTR *output;
7087
7088                 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7089                 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7090
7091                 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7092                 {
7093                     WCHAR caption[200], message[200];
7094                     int mb_ret;
7095
7096                     LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7097                     LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7098                     mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7099                     if(mb_ret == IDCANCEL)
7100                     {
7101                         HeapFree(GetProcessHeap(), 0, filename);
7102                         return TRUE;
7103                     }
7104                 }
7105                 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7106                 if(hf == INVALID_HANDLE_VALUE)
7107                 {
7108                     WCHAR caption[200], message[200];
7109
7110                     LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7111                     LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7112                     MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7113                     HeapFree(GetProcessHeap(), 0, filename);
7114                     return TRUE;
7115                 }
7116                 CloseHandle(hf);
7117                 DeleteFileW(filename);
7118                 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7119                 *output = filename;
7120                 EndDialog(hwnd, IDOK);
7121                 return TRUE;
7122             }
7123             if(LOWORD(wparam) == IDCANCEL)
7124             {
7125                 EndDialog(hwnd, IDCANCEL);
7126                 return TRUE;
7127             }
7128         }
7129         return FALSE;
7130     }
7131     return FALSE;
7132 }
7133
7134 /*****************************************************************************
7135  *          get_filename
7136  */
7137 static BOOL get_filename(LPWSTR *filename)
7138 {
7139     return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7140                            file_dlg_proc, (LPARAM)filename) == IDOK;
7141 }
7142
7143 /*****************************************************************************
7144  *          schedule_file
7145  */
7146 static BOOL schedule_file(LPCWSTR filename)
7147 {
7148     LPWSTR output = NULL;
7149
7150     if(get_filename(&output))
7151     {
7152         BOOL r;
7153         TRACE("copy to %s\n", debugstr_w(output));
7154         r = CopyFileW(filename, output, FALSE);
7155         HeapFree(GetProcessHeap(), 0, output);
7156         return r;
7157     }
7158     return FALSE;
7159 }
7160
7161 /*****************************************************************************
7162  *          schedule_pipe
7163  */
7164 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7165 {
7166 #ifdef HAVE_FORK
7167     char *unixname, *cmdA;
7168     DWORD len;
7169     int fds[2] = {-1, -1}, file_fd = -1, no_read;
7170     BOOL ret = FALSE;
7171     char buf[1024];
7172
7173     if(!(unixname = wine_get_unix_file_name(filename)))
7174         return FALSE;
7175
7176     len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7177     cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7178     WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7179
7180     TRACE("printing with: %s\n", cmdA);
7181
7182     if((file_fd = open(unixname, O_RDONLY)) == -1)
7183         goto end;
7184
7185     if (pipe(fds))
7186     {
7187         ERR("pipe() failed!\n"); 
7188         goto end;
7189     }
7190
7191     if (fork() == 0)
7192     {
7193         close(0);
7194         dup2(fds[0], 0);
7195         close(fds[1]);
7196
7197         /* reset signals that we previously set to SIG_IGN */
7198         signal(SIGPIPE, SIG_DFL);
7199         signal(SIGCHLD, SIG_DFL);
7200
7201         execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7202         _exit(1);
7203     }
7204
7205     while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7206         write(fds[1], buf, no_read);
7207
7208     ret = TRUE;
7209
7210 end:
7211     if(file_fd != -1) close(file_fd);
7212     if(fds[0] != -1) close(fds[0]);
7213     if(fds[1] != -1) close(fds[1]);
7214
7215     HeapFree(GetProcessHeap(), 0, cmdA);
7216     HeapFree(GetProcessHeap(), 0, unixname);
7217     return ret;
7218 #else
7219     return FALSE;
7220 #endif
7221 }
7222
7223 /*****************************************************************************
7224  *          schedule_unixfile
7225  */
7226 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7227 {
7228     int in_fd, out_fd, no_read;
7229     char buf[1024];
7230     BOOL ret = FALSE;
7231     char *unixname, *outputA;
7232     DWORD len;
7233
7234     if(!(unixname = wine_get_unix_file_name(filename)))
7235         return FALSE;
7236
7237     len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7238     outputA = HeapAlloc(GetProcessHeap(), 0, len);
7239     WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7240     
7241     out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7242     in_fd = open(unixname, O_RDONLY);
7243     if(out_fd == -1 || in_fd == -1)
7244         goto end;
7245
7246     while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7247         write(out_fd, buf, no_read);
7248
7249     ret = TRUE;
7250 end:
7251     if(in_fd != -1) close(in_fd);
7252     if(out_fd != -1) close(out_fd);
7253     HeapFree(GetProcessHeap(), 0, outputA);
7254     HeapFree(GetProcessHeap(), 0, unixname);
7255     return ret;
7256 }
7257
7258 /*****************************************************************************
7259  *          ScheduleJob [WINSPOOL.@]
7260  *
7261  */
7262 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7263 {
7264     opened_printer_t *printer;
7265     BOOL ret = FALSE;
7266     struct list *cursor, *cursor2;
7267
7268     TRACE("(%p, %x)\n", hPrinter, dwJobID);
7269     EnterCriticalSection(&printer_handles_cs);
7270     printer = get_opened_printer(hPrinter);
7271     if(!printer)
7272         goto end;
7273
7274     LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7275     {
7276         job_t *job = LIST_ENTRY(cursor, job_t, entry);
7277         HANDLE hf;
7278
7279         if(job->job_id != dwJobID) continue;
7280
7281         hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7282         if(hf != INVALID_HANDLE_VALUE)
7283         {
7284             PRINTER_INFO_5W *pi5;
7285             DWORD needed;
7286             HKEY hkey;
7287             WCHAR output[1024];
7288             static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7289                                                 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7290
7291             GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7292             pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7293             GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7294             TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7295                   debugstr_w(pi5->pPortName));
7296             
7297             output[0] = 0;
7298
7299             /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7300             if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7301             {
7302                 DWORD type, count = sizeof(output);
7303                 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7304                 RegCloseKey(hkey);
7305             }
7306             if(output[0] == '|')
7307             {
7308                 ret = schedule_pipe(output + 1, job->filename);
7309             }
7310             else if(output[0])
7311             {
7312                 ret = schedule_unixfile(output, job->filename);
7313             }
7314             else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7315             {
7316                 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7317             }
7318             else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7319             {
7320                 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7321             }
7322             else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7323             {
7324                 ret = schedule_file(job->filename);
7325             }
7326             else
7327             {
7328                 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7329             }
7330             HeapFree(GetProcessHeap(), 0, pi5);
7331             CloseHandle(hf);
7332             DeleteFileW(job->filename);
7333         }
7334         list_remove(cursor);
7335         HeapFree(GetProcessHeap(), 0, job->document_title);
7336         HeapFree(GetProcessHeap(), 0, job->filename);
7337         HeapFree(GetProcessHeap(), 0, job);
7338         break;
7339     }
7340 end:
7341     LeaveCriticalSection(&printer_handles_cs);
7342     return ret;
7343 }
7344
7345 /*****************************************************************************
7346  *          StartDocDlgA [WINSPOOL.@]
7347  */
7348 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7349 {
7350     UNICODE_STRING usBuffer;
7351     DOCINFOW docW;
7352     LPWSTR retW;
7353     LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7354     LPSTR ret = NULL;
7355
7356     docW.cbSize = sizeof(docW);
7357     if (doc->lpszDocName)
7358     {
7359         docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7360         if (!(docW.lpszDocName = docnameW)) return NULL;
7361     }
7362     if (doc->lpszOutput)
7363     {
7364         outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7365         if (!(docW.lpszOutput = outputW)) return NULL;
7366     }
7367     if (doc->lpszDatatype)
7368     {
7369         datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7370         if (!(docW.lpszDatatype = datatypeW)) return NULL;
7371     }
7372     docW.fwType = doc->fwType;
7373
7374     retW = StartDocDlgW(hPrinter, &docW);
7375
7376     if(retW)
7377     {
7378         DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7379         ret = HeapAlloc(GetProcessHeap(), 0, len);
7380         WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7381         HeapFree(GetProcessHeap(), 0, retW);
7382     }
7383
7384     HeapFree(GetProcessHeap(), 0, datatypeW);
7385     HeapFree(GetProcessHeap(), 0, outputW);
7386     HeapFree(GetProcessHeap(), 0, docnameW);
7387
7388     return ret;
7389 }
7390
7391 /*****************************************************************************
7392  *          StartDocDlgW [WINSPOOL.@]
7393  *
7394  * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7395  * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7396  * port is "FILE:". Also returns the full path if passed a relative path.
7397  *
7398  * The caller should free the returned string from the process heap.
7399  */
7400 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7401 {
7402     LPWSTR ret = NULL;
7403     DWORD len, attr;
7404
7405     if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7406     {
7407         PRINTER_INFO_5W *pi5;
7408         GetPrinterW(hPrinter, 5, NULL, 0, &len);
7409         if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7410             return NULL;
7411         pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7412         GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7413         if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7414         {
7415             HeapFree(GetProcessHeap(), 0, pi5);
7416             return NULL;
7417         }
7418         HeapFree(GetProcessHeap(), 0, pi5);
7419     }
7420
7421     if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7422     {
7423         LPWSTR name;
7424
7425         if (get_filename(&name))
7426         {
7427             if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7428             {
7429                 HeapFree(GetProcessHeap(), 0, name);
7430                 return NULL;
7431             }
7432             ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7433             GetFullPathNameW(name, len, ret, NULL);
7434             HeapFree(GetProcessHeap(), 0, name);
7435         }
7436         return ret;
7437     }
7438
7439     if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7440         return NULL;
7441
7442     ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7443     GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7444         
7445     attr = GetFileAttributesW(ret);
7446     if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7447     {
7448         HeapFree(GetProcessHeap(), 0, ret);
7449         ret = NULL;
7450     }
7451     return ret;
7452 }