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