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