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