~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/winspool.drv/info.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  * WINSPOOL functions
  3  *
  4  * Copyright 1996 John Harvey
  5  * Copyright 1998 Andreas Mohr
  6  * Copyright 1999 Klaas van Gend
  7  * Copyright 1999, 2000 Huw D M Davies
  8  * Copyright 2001 Marcus Meissner
  9  * Copyright 2005-2009 Detlef Riekenberg
 10  *
 11  * This library is free software; you can redistribute it and/or
 12  * modify it under the terms of the GNU Lesser General Public
 13  * License as published by the Free Software Foundation; either
 14  * version 2.1 of the License, or (at your option) any later version.
 15  *
 16  * This library is distributed in the hope that it will be useful,
 17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19  * Lesser General Public License for more details.
 20  *
 21  * You should have received a copy of the GNU Lesser General Public
 22  * License along with this library; if not, write to the Free Software
 23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 24  */
 25 
 26 #include "config.h"
 27 #include "wine/port.h"
 28 
 29 #include <stdarg.h>
 30 #include <stdio.h>
 31 #include <stdlib.h>
 32 #include <string.h>
 33 #include <ctype.h>
 34 #include <stddef.h>
 35 #ifdef HAVE_UNISTD_H
 36 # include <unistd.h>
 37 #endif
 38 #include <signal.h>
 39 #ifdef HAVE_CUPS_CUPS_H
 40 # include <cups/cups.h>
 41 #endif
 42 
 43 #define NONAMELESSUNION
 44 #define NONAMELESSSTRUCT
 45 #include "wine/library.h"
 46 #include "windef.h"
 47 #include "winbase.h"
 48 #include "winuser.h"
 49 #include "winerror.h"
 50 #include "winreg.h"
 51 #include "wingdi.h"
 52 #include "winspool.h"
 53 #include "winternl.h"
 54 #include "wine/windef16.h"
 55 #include "wine/unicode.h"
 56 #include "wine/debug.h"
 57 #include "wine/list.h"
 58 #include "winnls.h"
 59 
 60 #include "ddk/winsplp.h"
 61 #include "wspool.h"
 62 
 63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
 64 
 65 /* ############################### */
 66 
 67 static CRITICAL_SECTION monitor_handles_cs;
 68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug = 
 69 {
 70     0, 0, &monitor_handles_cs,
 71     { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
 72       0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
 73 };
 74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
 75 
 76 
 77 static CRITICAL_SECTION printer_handles_cs;
 78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug = 
 79 {
 80     0, 0, &printer_handles_cs,
 81     { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
 82       0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
 83 };
 84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
 85 
 86 /* ############################### */
 87 
 88 typedef struct {
 89     struct list     entry;
 90     LPWSTR          name;
 91     LPWSTR          dllname;
 92     PMONITORUI      monitorUI;
 93     LPMONITOR       monitor;
 94     HMODULE         hdll;
 95     DWORD           refcount;
 96     DWORD           dwMonitorSize;
 97 } monitor_t;
 98 
 99 typedef struct {
100     DWORD job_id;
101     HANDLE hf;
102 } started_doc_t;
103 
104 typedef struct {
105     struct list jobs;
106     LONG ref;
107 } jobqueue_t;
108 
109 typedef struct {
110     LPWSTR name;
111     LPWSTR printername;
112     HANDLE backend_printer;
113     jobqueue_t *queue;
114     started_doc_t *doc;
115 } opened_printer_t;
116 
117 typedef struct {
118     struct list entry;
119     DWORD job_id;
120     WCHAR *filename;
121     WCHAR *document_title;
122 } job_t;
123 
124 
125 typedef struct {
126     LPCWSTR  envname;
127     LPCWSTR  subdir;
128     DWORD    driverversion;
129     LPCWSTR  versionregpath;
130     LPCWSTR  versionsubdir;
131 } printenv_t;
132 
133 /* ############################### */
134 
135 static struct list monitor_handles = LIST_INIT( monitor_handles );
136 static monitor_t * pm_localport;
137 
138 static opened_printer_t **printer_handles;
139 static UINT nb_printer_handles;
140 static LONG next_job_id = 1;
141 
142 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
143                                                      WORD fwCapability, LPSTR lpszOutput,
144                                                      LPDEVMODEA lpdm );
145 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
146                                               LPSTR lpszDevice, LPSTR lpszPort,
147                                               LPDEVMODEA lpdmInput, LPSTR lpszProfile,
148                                               DWORD fwMode );
149 
150 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
151                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
152                                   'c','o','n','t','r','o','l','\\',
153                                   'P','r','i','n','t','\\',
154                                   'E','n','v','i','r','o','n','m','e','n','t','s','\\',
155                                   '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
156 
157 static const WCHAR MonitorsW[] =  { 'S','y','s','t','e','m','\\',
158                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
159                                   'C','o','n','t','r','o','l','\\',
160                                   'P','r','i','n','t','\\',
161                                   'M','o','n','i','t','o','r','s','\\',0};
162 
163 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
164                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
165                                   'C','o','n','t','r','o','l','\\',
166                                   'P','r','i','n','t','\\',
167                                   'P','r','i','n','t','e','r','s',0};
168 
169 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
170 
171 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
172                                               'M','i','c','r','o','s','o','f','t','\\',
173                                               'W','i','n','d','o','w','s',' ','N','T','\\',
174                                               'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
175                                               'W','i','n','d','o','w','s',0};
176 
177 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
178                                                'M','i','c','r','o','s','o','f','t','\\',
179                                                'W','i','n','d','o','w','s',' ','N','T','\\',
180                                                'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
181                                                'D','e','v','i','c','e','s',0};
182 
183 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
184                                         'M','i','c','r','o','s','o','f','t','\\',
185                                         'W','i','n','d','o','w','s',' ','N','T','\\',
186                                         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
187                                         'P','o','r','t','s',0};
188 
189 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
190                                                 'M','i','c','r','o','s','o','f','t','\\',
191                                                 'W','i','n','d','o','w','s',' ','N','T','\\',
192                                                 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
193                                                 'P','r','i','n','t','e','r','P','o','r','t','s',0};
194 
195 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
196 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','',0};
197 static const WCHAR envname_x64W[] =   {'W','i','n','d','o','w','s',' ','x','6','4',0};
198 static const WCHAR envname_x86W[] =   {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
199 static const WCHAR subdir_win40W[] = {'w','i','n','4','',0};
200 static const WCHAR subdir_x64W[] =   {'x','6','4',0};
201 static const WCHAR subdir_x86W[] =   {'w','3','2','x','8','6',0};
202 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','',0};
203 static const WCHAR Version0_SubdirW[] = {'\\','',0};
204 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
205 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
206 
207 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
208 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
209 
210 static const WCHAR backslashW[] = {'\\',0};
211 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
212                                       'i','o','n',' ','F','i','l','e',0};
213 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
214 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
215 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
216 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
217 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
218 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
219 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
220 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
221 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
222 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
223 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
224 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
225 static const WCHAR NameW[] = {'N','a','m','e',0};
226 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
227 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
228 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
229 static const WCHAR PortW[] = {'P','o','r','t',0};
230 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
231 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
232 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
233 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
234 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
235 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
236 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
237 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
238 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
239 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
240 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
241 static const WCHAR deviceW[]  = {'d','e','v','i','c','e',0};
242 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
243 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
244 static const WCHAR emptyStringW[] = {0};
245 
246 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
247 
248 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
249 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
250 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
251 
252 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
253                                           'D','o','c','u','m','e','n','t',0};
254 
255 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
256                                      sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
257                                      sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
258                                   0, sizeof(DRIVER_INFO_8W)};
259 
260 
261 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
262                                      sizeof(PRINTER_INFO_3),  sizeof(PRINTER_INFO_4W),
263                                      sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
264                                      sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
265                                      sizeof(PRINTER_INFO_9W)};
266 
267 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
268 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
269 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
270 
271 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
272 
273 /******************************************************************
274  *  validate the user-supplied printing-environment [internal]
275  *
276  * PARAMS
277  *  env  [I] PTR to Environment-String or NULL
278  *
279  * RETURNS
280  *  Failure:  NULL
281  *  Success:  PTR to printenv_t
282  *
283  * NOTES
284  *  An empty string is handled the same way as NULL.
285  *  SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
286  *  
287  */
288 
289 static const  printenv_t * validate_envW(LPCWSTR env)
290 {
291     const printenv_t *result = NULL;
292     unsigned int i;
293 
294     TRACE("testing %s\n", debugstr_w(env));
295     if (env && env[0])
296     {
297         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
298         {
299             if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
300             {
301                 result = all_printenv[i];
302                 break;
303             }
304         }
305 
306         if (result == NULL) {
307             FIXME("unsupported Environment: %s\n", debugstr_w(env));
308             SetLastError(ERROR_INVALID_ENVIRONMENT);
309         }
310         /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
311     }
312     else
313     {
314         result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
315     }
316     TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
317 
318     return result;
319 }
320 
321 
322 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
323    if passed a NULL string. This returns NULLs to the result. 
324 */
325 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
326 {
327     if ( (src) )
328     {
329         RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
330         return usBufferPtr->Buffer;
331     }
332     usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
333     return NULL;
334 }
335             
336 static LPWSTR strdupW(LPCWSTR p)
337 {
338     LPWSTR ret;
339     DWORD len;
340 
341     if(!p) return NULL;
342     len = (strlenW(p) + 1) * sizeof(WCHAR);
343     ret = HeapAlloc(GetProcessHeap(), 0, len);
344     memcpy(ret, p, len);
345     return ret;
346 }
347 
348 static LPSTR strdupWtoA( LPCWSTR str )
349 {
350     LPSTR ret;
351     INT len;
352 
353     if (!str) return NULL;
354     len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
355     ret = HeapAlloc( GetProcessHeap(), 0, len );
356     if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
357     return ret;
358 }
359 
360 /******************************************************************
361  * Return the number of bytes for an multi_sz string.
362  * The result includes all \0s
363  * (specifically the extra \0, that is needed as multi_sz terminator).
364  */
365 #if 0
366 static int multi_sz_lenW(const WCHAR *str)
367 {
368     const WCHAR *ptr = str;
369     if(!str) return 0;
370     do
371     {
372         ptr += lstrlenW(ptr) + 1;
373     } while(*ptr);
374 
375     return (ptr - str + 1) * sizeof(WCHAR);
376 }
377 #endif
378 /* ################################ */
379 
380 static int multi_sz_lenA(const char *str)
381 {
382     const char *ptr = str;
383     if(!str) return 0;
384     do
385     {
386         ptr += lstrlenA(ptr) + 1;
387     } while(*ptr);
388 
389     return ptr - str + 1;
390 }
391 
392 static void
393 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
394     char qbuf[200];
395 
396     /* If forcing, or no profile string entry for device yet, set the entry
397      *
398      * The always change entry if not WINEPS yet is discussable.
399      */
400     if (force                                                           ||
401         !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf))    ||
402         !strcmp(qbuf,"*")                                               ||
403         !strstr(qbuf,"WINEPS.DRV")
404     ) {
405         char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
406         HKEY hkey;
407 
408         sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
409         WriteProfileStringA("windows","device",buf);
410         if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
411             RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
412             RegCloseKey(hkey);
413         }
414         HeapFree(GetProcessHeap(),0,buf);
415     }
416 }
417 
418 static BOOL add_printer_driver(const char *name)
419 {
420     DRIVER_INFO_3A di3a;
421 
422     static char driver_9x[]         = "wineps16.drv",
423                 driver_nt[]         = "wineps.drv",
424                 env_9x[]            = "Windows 4.0",
425                 env_nt[]            = "Windows NT x86",
426                 data_file[]         = "generic.ppd",
427                 default_data_type[] = "RAW";
428 
429     ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
430     di3a.cVersion         = 3;
431     di3a.pName            = (char *)name;
432     di3a.pEnvironment     = env_nt;
433     di3a.pDriverPath      = driver_nt;
434     di3a.pDataFile        = data_file;
435     di3a.pConfigFile      = driver_nt;
436     di3a.pDefaultDataType = default_data_type;
437 
438     if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
439         (GetLastError() ==  ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
440     {
441         di3a.cVersion     = 0;
442         di3a.pEnvironment = env_9x;
443         di3a.pDriverPath  = driver_9x;
444         di3a.pConfigFile  = driver_9x;
445         if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
446             (GetLastError() ==  ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
447         {
448             return TRUE;
449         }
450     }
451     ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
452         debugstr_a(di3a.pEnvironment), GetLastError());
453     return FALSE;
454 }
455 
456 #ifdef SONAME_LIBCUPS
457 static typeof(cupsFreeDests) *pcupsFreeDests;
458 static typeof(cupsGetDests)  *pcupsGetDests;
459 static typeof(cupsGetPPD)    *pcupsGetPPD;
460 static typeof(cupsPrintFile) *pcupsPrintFile;
461 static void *cupshandle;
462 
463 static BOOL CUPS_LoadPrinters(void)
464 {
465     int                   i, nrofdests;
466     BOOL                  hadprinter = FALSE, haddefault = FALSE;
467     cups_dest_t          *dests;
468     PRINTER_INFO_2A       pinfo2a;
469     char   *port,*devline;
470     HKEY hkeyPrinter, hkeyPrinters, hkey;
471     char    loaderror[256];
472 
473     cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
474     if (!cupshandle) {
475         TRACE("%s\n", loaderror);
476         return FALSE;
477     }
478     TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
479 
480 #define DYNCUPS(x)                                      \
481         p##x = wine_dlsym(cupshandle, #x, NULL,0);      \
482         if (!p##x) return FALSE;
483 
484     DYNCUPS(cupsFreeDests);
485     DYNCUPS(cupsGetPPD);
486     DYNCUPS(cupsGetDests);
487     DYNCUPS(cupsPrintFile);
488 #undef DYNCUPS
489 
490     if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
491        ERROR_SUCCESS) {
492         ERR("Can't create Printers key\n");
493         return FALSE;
494     }
495 
496     nrofdests = pcupsGetDests(&dests);
497     TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
498     for (i=0;i<nrofdests;i++) {
499         /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
500         port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
501         sprintf(port,"LPR:%s", dests[i].name);
502         /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
503         devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
504         sprintf(devline, "WINEPS.DRV,%s", port);
505         WriteProfileStringA("devices", dests[i].name, devline);
506         if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
507             RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
508             RegCloseKey(hkey);
509         }
510 
511         lstrcatA(devline, ",15,45");
512         WriteProfileStringA("PrinterPorts", dests[i].name, devline);
513         if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
514             RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
515             RegCloseKey(hkey);
516         }
517 
518         HeapFree(GetProcessHeap(), 0, devline);
519 
520         TRACE("Printer %d: %s\n", i, dests[i].name);
521         if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
522             /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
523                and continue */
524             TRACE("Printer already exists\n");
525             RegDeleteValueW(hkeyPrinter, May_Delete_Value);
526             RegCloseKey(hkeyPrinter);
527         } else {
528             static CHAR data_type[] = "RAW",
529                     print_proc[]    = "WinPrint",
530                     comment[]       = "WINEPS Printer using CUPS",
531                     location[]      = "<physical location of printer>",
532                     params[]        = "<parameters?>",
533                     share_name[]    = "<share name?>",
534                     sep_file[]      = "<sep file?>";
535 
536             add_printer_driver(dests[i].name);
537 
538             memset(&pinfo2a,0,sizeof(pinfo2a));
539             pinfo2a.pPrinterName    = dests[i].name;
540             pinfo2a.pDatatype       = data_type;
541             pinfo2a.pPrintProcessor = print_proc;
542             pinfo2a.pDriverName     = dests[i].name;
543             pinfo2a.pComment        = comment;
544             pinfo2a.pLocation       = location;
545             pinfo2a.pPortName       = port;
546             pinfo2a.pParameters     = params;
547             pinfo2a.pShareName      = share_name;
548             pinfo2a.pSepFile        = sep_file;
549 
550             if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
551                 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
552                     ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
553             }
554         }
555         HeapFree(GetProcessHeap(),0,port);
556 
557         hadprinter = TRUE;
558         if (dests[i].is_default) {
559             WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
560             haddefault = TRUE;
561         }
562     }
563     if (hadprinter & !haddefault)
564         WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
565     pcupsFreeDests(nrofdests, dests);
566     RegCloseKey(hkeyPrinters);
567     return hadprinter;
568 }
569 #endif
570 
571 static BOOL
572 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
573     PRINTER_INFO_2A     pinfo2a;
574     char                *e,*s,*name,*prettyname,*devname;
575     BOOL                ret = FALSE, set_default = FALSE;
576     char                *port = NULL, *devline,*env_default;
577     HKEY                hkeyPrinter, hkeyPrinters, hkey;
578 
579     while (isspace(*pent)) pent++;
580     s = strchr(pent,':');
581     if(s) *s='\0';
582     name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
583     strcpy(name,pent);
584     if(s) {
585         *s=':';
586         pent = s;
587     } else
588         pent = "";
589 
590     TRACE("name=%s entry=%s\n",name, pent);
591 
592     if(ispunct(*name)) { /* a tc entry, not a real printer */
593         TRACE("skipping tc entry\n");
594         goto end;
595     }
596 
597     if(strstr(pent,":server")) { /* server only version so skip */
598         TRACE("skipping server entry\n");
599         goto end;
600     }
601 
602     /* Determine whether this is a postscript printer. */
603 
604     ret = TRUE;
605     env_default = getenv("PRINTER");
606     prettyname = name;
607     /* Get longest name, usually the one at the right for later display. */
608     while((s=strchr(prettyname,'|'))) {
609         *s = '\0';
610         e = s;
611         while(isspace(*--e)) *e = '\0';
612         TRACE("\t%s\n", debugstr_a(prettyname));
613         if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
614         for(prettyname = s+1; isspace(*prettyname); prettyname++)
615             ;
616     }
617     e = prettyname + strlen(prettyname);
618     while(isspace(*--e)) *e = '\0';
619     TRACE("\t%s\n", debugstr_a(prettyname));
620     if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
621 
622     /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
623      * if it is too long, we use it as comment below. */
624     devname = prettyname;
625     if (strlen(devname)>=CCHDEVICENAME-1)
626          devname = name;
627     if (strlen(devname)>=CCHDEVICENAME-1) {
628         ret = FALSE;
629         goto end;
630     }
631 
632     port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
633     sprintf(port,"LPR:%s",name);
634 
635     /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
636     devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
637     sprintf(devline, "WINEPS.DRV,%s", port);
638     WriteProfileStringA("devices", devname, devline);
639     if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
640         RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
641         RegCloseKey(hkey);
642     }
643 
644     lstrcatA(devline, ",15,45");
645     WriteProfileStringA("PrinterPorts", devname, devline);
646     if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
647         RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
648         RegCloseKey(hkey);
649     }
650 
651     HeapFree(GetProcessHeap(),0,devline);
652     
653     if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
654        ERROR_SUCCESS) {
655         ERR("Can't create Printers key\n");
656         ret = FALSE;
657         goto end;
658     }
659     if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
660         /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
661            and continue */
662         TRACE("Printer already exists\n");
663         RegDeleteValueW(hkeyPrinter, May_Delete_Value);
664         RegCloseKey(hkeyPrinter);
665     } else {
666         static CHAR data_type[]   = "RAW",
667                     print_proc[]  = "WinPrint",
668                     comment[]     = "WINEPS Printer using LPR",
669                     params[]      = "<parameters?>",
670                     share_name[]  = "<share name?>",
671                     sep_file[]    = "<sep file?>";
672 
673         add_printer_driver(devname);
674 
675         memset(&pinfo2a,0,sizeof(pinfo2a));
676         pinfo2a.pPrinterName    = devname;
677         pinfo2a.pDatatype       = data_type;
678         pinfo2a.pPrintProcessor = print_proc;
679         pinfo2a.pDriverName     = devname;
680         pinfo2a.pComment        = comment;
681         pinfo2a.pLocation       = prettyname;
682         pinfo2a.pPortName       = port;
683         pinfo2a.pParameters     = params;
684         pinfo2a.pShareName      = share_name;
685         pinfo2a.pSepFile        = sep_file;
686 
687         if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
688             if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
689                 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
690         }
691     }
692     RegCloseKey(hkeyPrinters);
693 
694     if (isfirst || set_default)
695         WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
696 
697  end:
698     HeapFree(GetProcessHeap(), 0, port);
699     HeapFree(GetProcessHeap(), 0, name);
700     return ret;
701 }
702 
703 static BOOL
704 PRINTCAP_LoadPrinters(void) {
705     BOOL                hadprinter = FALSE;
706     char                buf[200];
707     FILE                *f;
708     char *pent = NULL;
709     BOOL had_bash = FALSE;
710 
711     f = fopen("/etc/printcap","r");
712     if (!f)
713         return FALSE;
714 
715     while(fgets(buf,sizeof(buf),f)) {
716         char *start, *end;
717 
718         end=strchr(buf,'\n');
719         if (end) *end='\0';
720     
721         start = buf;
722         while(isspace(*start)) start++;
723         if(*start == '#' || *start == '\0')
724             continue;
725 
726         if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
727             hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
728             HeapFree(GetProcessHeap(),0,pent);
729             pent = NULL;
730         }
731 
732         if (end && *--end == '\\') {
733             *end = '\0';
734             had_bash = TRUE;
735         } else
736             had_bash = FALSE;
737 
738         if (pent) {
739             pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
740             strcat(pent,start);
741         } else {
742             pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
743             strcpy(pent,start);
744         }
745 
746     }
747     if(pent) {
748         hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
749         HeapFree(GetProcessHeap(),0,pent);
750     }
751     fclose(f);
752     return hadprinter;
753 }
754 
755 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
756 {
757     if (value)
758         return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
759                               (lstrlenW(value) + 1) * sizeof(WCHAR));
760     else
761         return ERROR_FILE_NOT_FOUND;
762 }
763 
764 /******************************************************************
765  * monitor_unload [internal]
766  *
767  * release a printmonitor and unload it from memory, when needed
768  *
769  */
770 static void monitor_unload(monitor_t * pm)
771 {
772     if (pm == NULL) return;
773     TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
774 
775     EnterCriticalSection(&monitor_handles_cs);
776 
777     if (pm->refcount) pm->refcount--;
778 
779     if (pm->refcount == 0) {
780         list_remove(&pm->entry);
781         FreeLibrary(pm->hdll);
782         HeapFree(GetProcessHeap(), 0, pm->name);
783         HeapFree(GetProcessHeap(), 0, pm->dllname);
784         HeapFree(GetProcessHeap(), 0, pm);
785     }
786     LeaveCriticalSection(&monitor_handles_cs);
787 }
788 
789 /******************************************************************
790  * monitor_load [internal]
791  *
792  * load a printmonitor, get the dllname from the registry, when needed 
793  * initialize the monitor and dump found function-pointers
794  *
795  * On failure, SetLastError() is called and NULL is returned
796  */
797 
798 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
799 {
800     LPMONITOR2  (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
801     PMONITORUI  (WINAPI *pInitializePrintMonitorUI)(VOID);
802     LPMONITOREX (WINAPI *pInitializePrintMonitor)  (LPWSTR);
803     DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
804     DWORD (WINAPI *pInitializeMonitor)  (LPWSTR);
805 
806     monitor_t * pm = NULL;
807     monitor_t * cursor;
808     LPWSTR  regroot = NULL;
809     LPWSTR  driver = dllname;
810 
811     TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
812     /* Is the Monitor already loaded? */
813     EnterCriticalSection(&monitor_handles_cs);
814 
815     if (name) {
816         LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
817         {
818             if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
819                 pm = cursor;
820                 break;
821             }
822         }
823     }
824 
825     if (pm == NULL) {
826         pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
827         if (pm == NULL) goto cleanup;
828         list_add_tail(&monitor_handles, &pm->entry);
829     }
830     pm->refcount++;
831 
832     if (pm->name == NULL) {
833         /* Load the monitor */
834         LPMONITOREX pmonitorEx;
835         DWORD   len;
836 
837         if (name) {
838             len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
839             regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
840         }
841 
842         if (regroot) {
843             lstrcpyW(regroot, MonitorsW);
844             lstrcatW(regroot, name);
845             /* Get the Driver from the Registry */
846             if (driver == NULL) {
847                 HKEY    hroot;
848                 DWORD   namesize;
849                 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
850                     if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
851                                         &namesize) == ERROR_SUCCESS) {
852                         driver = HeapAlloc(GetProcessHeap(), 0, namesize);
853                         RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
854                     }
855                     RegCloseKey(hroot);
856                 }
857             }
858         }
859 
860         pm->name = strdupW(name);
861         pm->dllname = strdupW(driver);
862 
863         if ((name && (!regroot || !pm->name)) || !pm->dllname) {
864             monitor_unload(pm);
865             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
866             pm = NULL;
867             goto cleanup;
868         }
869 
870         pm->hdll = LoadLibraryW(driver);
871         TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
872 
873         if (pm->hdll == NULL) {
874             monitor_unload(pm);
875             SetLastError(ERROR_MOD_NOT_FOUND);
876             pm = NULL;
877             goto cleanup;
878         }
879 
880         pInitializePrintMonitor2  = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
881         pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
882         pInitializePrintMonitor   = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
883         pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
884         pInitializeMonitor   = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
885 
886 
887         TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
888         TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
889         TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
890         TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
891         TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
892 
893         if (pInitializePrintMonitorUI  != NULL) {
894             pm->monitorUI = pInitializePrintMonitorUI();
895             TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver)); 
896             if (pm->monitorUI) {
897                 TRACE(  "0x%08x: dwMonitorSize (%d)\n",
898                         pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
899 
900             }
901         }
902 
903         if (pInitializePrintMonitor && regroot) {
904             pmonitorEx = pInitializePrintMonitor(regroot);
905             TRACE(  "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
906                     pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
907 
908             if (pmonitorEx) {
909                 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
910                 pm->monitor = &(pmonitorEx->Monitor);
911             }
912         }
913 
914         if (pm->monitor) {
915             TRACE(  "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
916 
917         }
918 
919         if (!pm->monitor && regroot) {
920             if (pInitializePrintMonitor2 != NULL) {
921                 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
922             }
923             if (pInitializeMonitorEx != NULL) {
924                 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
925             }
926             if (pInitializeMonitor != NULL) {
927                 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
928             }
929         }
930         if (!pm->monitor && !pm->monitorUI) {
931             monitor_unload(pm);
932             SetLastError(ERROR_PROC_NOT_FOUND);
933             pm = NULL;
934         }
935     }
936 cleanup:
937     if ((pm_localport ==  NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
938         pm->refcount++;
939         pm_localport = pm;
940     }
941     LeaveCriticalSection(&monitor_handles_cs);
942     if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
943     HeapFree(GetProcessHeap(), 0, regroot);
944     TRACE("=> %p\n", pm);
945     return pm;
946 }
947 
948 /******************************************************************
949  * monitor_loadui [internal]
950  *
951  * load the userinterface-dll for a given portmonitor
952  *
953  * On failure, NULL is returned
954  */
955 
956 static monitor_t * monitor_loadui(monitor_t * pm)
957 {
958     monitor_t * pui = NULL;
959     LPWSTR  buffer[MAX_PATH];
960     HANDLE  hXcv;
961     DWORD   len;
962     DWORD   res;
963 
964     if (pm == NULL) return NULL;
965     TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
966 
967     /* Try the Portmonitor first; works for many monitors */
968     if (pm->monitorUI) {
969         EnterCriticalSection(&monitor_handles_cs);
970         pm->refcount++;
971         LeaveCriticalSection(&monitor_handles_cs);
972         return pm;
973     }
974 
975     /* query the userinterface-dllname from the Portmonitor */
976     if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
977         /* building (",XcvMonitor %s",pm->name) not needed yet */
978         res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
979         TRACE("got %u with %p\n", res, hXcv);
980         if (res) {
981             res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
982             TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
983             if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
984             pm->monitor->pfnXcvClosePort(hXcv);
985         }
986     }
987     return pui;
988 }
989 
990 
991 /******************************************************************
992  * monitor_load_by_port [internal]
993  *
994  * load a printmonitor for a given port
995  *
996  * On failure, NULL is returned
997  */
998 
999 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1000 {
1001     HKEY    hroot;
1002     HKEY    hport;
1003     LPWSTR  buffer;
1004     monitor_t * pm = NULL;
1005     DWORD   registered = 0;
1006     DWORD   id = 0;
1007     DWORD   len;
1008 
1009     TRACE("(%s)\n", debugstr_w(portname));
1010 
1011     /* Try the Local Monitor first */
1012     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1013         if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1014             /* found the portname */
1015             RegCloseKey(hroot);
1016             return monitor_load(LocalPortW, NULL);
1017         }
1018         RegCloseKey(hroot);
1019     }
1020 
1021     len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1022     buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1023     if (buffer == NULL) return NULL;
1024 
1025     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1026         EnterCriticalSection(&monitor_handles_cs);
1027         RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1028 
1029         while ((pm == NULL) && (id < registered)) {
1030             buffer[0] = '\0';
1031             RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1032             TRACE("testing %s\n", debugstr_w(buffer));
1033             len = lstrlenW(buffer);
1034             lstrcatW(buffer, bs_Ports_bsW);
1035             lstrcatW(buffer, portname);
1036             if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1037                 RegCloseKey(hport);
1038                 buffer[len] = '\0';             /* use only the Monitor-Name */
1039                 pm = monitor_load(buffer, NULL);
1040             }
1041             id++;
1042         }
1043         LeaveCriticalSection(&monitor_handles_cs);
1044         RegCloseKey(hroot);
1045     }
1046     HeapFree(GetProcessHeap(), 0, buffer);
1047     return pm;
1048 }
1049 
1050 /******************************************************************
1051  * get_servername_from_name  (internal)
1052  *
1053  * for an external server, a copy of the serverpart from the full name is returned
1054  *
1055  */
1056 static LPWSTR get_servername_from_name(LPCWSTR name)
1057 {
1058     LPWSTR  server;
1059     LPWSTR  ptr;
1060     WCHAR   buffer[MAX_PATH];
1061     DWORD   len;
1062 
1063     if (name == NULL) return NULL;
1064     if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1065 
1066     server = strdupW(&name[2]);     /* skip over both backslash */
1067     if (server == NULL) return NULL;
1068 
1069     /* strip '\' and the printername */
1070     ptr = strchrW(server, '\\');
1071     if (ptr) ptr[0] = '\0';
1072 
1073     TRACE("found %s\n", debugstr_w(server));
1074 
1075     len = sizeof(buffer)/sizeof(buffer[0]);
1076     if (GetComputerNameW(buffer, &len)) {
1077         if (lstrcmpW(buffer, server) == 0) {
1078             /* The requested Servername is our computername */
1079             HeapFree(GetProcessHeap(), 0, server);
1080             return NULL;
1081         }
1082     }
1083     return server;
1084 }
1085 
1086 /******************************************************************
1087  * get_basename_from_name  (internal)
1088  *
1089  * skip over the serverpart from the full name
1090  *
1091  */
1092 static LPCWSTR get_basename_from_name(LPCWSTR name)
1093 {
1094     if (name == NULL)  return NULL;
1095     if ((name[0] == '\\') && (name[1] == '\\')) {
1096         /* skip over the servername and search for the following '\'  */
1097         name = strchrW(&name[2], '\\');
1098         if ((name) && (name[1])) {
1099             /* found a separator ('\') followed by a name:
1100                skip over the separator and return the rest */
1101             name++;
1102         }
1103         else
1104         {
1105             /* no basename present (we found only a servername) */
1106             return NULL;
1107         }
1108     }
1109     return name;
1110 }
1111 
1112 /******************************************************************
1113  *  get_opened_printer_entry
1114  *  Get the first place empty in the opened printer table
1115  *
1116  * ToDo:
1117  *  - pDefault is ignored
1118  */
1119 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1120 {
1121     UINT_PTR handle = nb_printer_handles, i;
1122     jobqueue_t *queue = NULL;
1123     opened_printer_t *printer = NULL;
1124     LPWSTR  servername;
1125     LPCWSTR printername;
1126 
1127     if ((backend == NULL)  && !load_backend()) return NULL;
1128 
1129     servername = get_servername_from_name(name);
1130     if (servername) {
1131         FIXME("server %s not supported\n", debugstr_w(servername));
1132         HeapFree(GetProcessHeap(), 0, servername);
1133         SetLastError(ERROR_INVALID_PRINTER_NAME);
1134         return NULL;
1135     }
1136 
1137     printername = get_basename_from_name(name);
1138     if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1139 
1140     /* an empty printername is invalid */
1141     if (printername && (!printername[0])) {
1142         SetLastError(ERROR_INVALID_PARAMETER);
1143         return NULL;
1144     }
1145 
1146     EnterCriticalSection(&printer_handles_cs);
1147 
1148     for (i = 0; i < nb_printer_handles; i++)
1149     {
1150         if (!printer_handles[i])
1151         {
1152             if(handle == nb_printer_handles)
1153                 handle = i;
1154         }
1155         else
1156         {
1157             if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1158                 queue = printer_handles[i]->queue;
1159         }
1160     }
1161 
1162     if (handle >= nb_printer_handles)
1163     {
1164         opened_printer_t **new_array;
1165         if (printer_handles)
1166             new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1167                                      (nb_printer_handles + 16) * sizeof(*new_array) );
1168         else
1169             new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1170                                    (nb_printer_handles + 16) * sizeof(*new_array) );
1171 
1172         if (!new_array)
1173         {
1174             handle = 0;
1175             goto end;
1176         }
1177         printer_handles = new_array;
1178         nb_printer_handles += 16;
1179     }
1180 
1181     if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1182     {
1183         handle = 0;
1184         goto end;
1185     }
1186 
1187     /* get a printer handle from the backend */
1188     if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1189         handle = 0;
1190         goto end;
1191     }
1192 
1193     /* clone the base name. This is NULL for the printserver */
1194     printer->printername = strdupW(printername);
1195 
1196     /* clone the full name */
1197     printer->name = strdupW(name);
1198     if (name && (!printer->name)) {
1199         handle = 0;
1200         goto end;
1201     }
1202 
1203     if(queue)
1204         printer->queue = queue;
1205     else
1206     {
1207         printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1208         if (!printer->queue) {
1209             handle = 0;
1210             goto end;
1211         }
1212         list_init(&printer->queue->jobs);
1213         printer->queue->ref = 0;
1214     }
1215     InterlockedIncrement(&printer->queue->ref);
1216 
1217     printer_handles[handle] = printer;
1218     handle++;
1219 end:
1220     LeaveCriticalSection(&printer_handles_cs);
1221     if (!handle && printer) {
1222         /* Something failed: Free all resources */
1223         HeapFree(GetProcessHeap(), 0, printer->printername);
1224         HeapFree(GetProcessHeap(), 0, printer->name);
1225         if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1226         HeapFree(GetProcessHeap(), 0, printer);
1227     }
1228 
1229     return (HANDLE)handle;
1230 }
1231 
1232 /******************************************************************
1233  *  get_opened_printer
1234  *  Get the pointer to the opened printer referred by the handle
1235  */
1236 static opened_printer_t *get_opened_printer(HANDLE hprn)
1237 {
1238     UINT_PTR idx = (UINT_PTR)hprn;
1239     opened_printer_t *ret = NULL;
1240 
1241     EnterCriticalSection(&printer_handles_cs);
1242 
1243     if ((idx > 0) && (idx <= nb_printer_handles)) {
1244         ret = printer_handles[idx - 1];
1245     }
1246     LeaveCriticalSection(&printer_handles_cs);
1247     return ret;
1248 }
1249 
1250 /******************************************************************
1251  *  get_opened_printer_name
1252  *  Get the pointer to the opened printer name referred by the handle
1253  */
1254 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1255 {
1256     opened_printer_t *printer = get_opened_printer(hprn);
1257     if(!printer) return NULL;
1258     return printer->name;
1259 }
1260 
1261 /******************************************************************
1262  *  WINSPOOL_GetOpenedPrinterRegKey
1263  *
1264  */
1265 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1266 {
1267     LPCWSTR name = get_opened_printer_name(hPrinter);
1268     DWORD ret;
1269     HKEY hkeyPrinters;
1270 
1271     if(!name) return ERROR_INVALID_HANDLE;
1272 
1273     if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1274        ERROR_SUCCESS)
1275         return ret;
1276 
1277     if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1278     {
1279         ERR("Can't find opened printer %s in registry\n",
1280             debugstr_w(name));
1281         RegCloseKey(hkeyPrinters);
1282         return ERROR_INVALID_PRINTER_NAME; /* ? */
1283     }
1284     RegCloseKey(hkeyPrinters);
1285     return ERROR_SUCCESS;
1286 }
1287 
1288 void WINSPOOL_LoadSystemPrinters(void)
1289 {
1290     HKEY                hkey, hkeyPrinters;
1291     HANDLE              hprn;
1292     DWORD               needed, num, i;
1293     WCHAR               PrinterName[256];
1294     BOOL                done = FALSE;
1295 
1296     /* This ensures that all printer entries have a valid Name value.  If causes
1297        problems later if they don't.  If one is found to be missed we create one
1298        and set it equal to the name of the key */
1299     if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1300         if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1301                             NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1302             for(i = 0; i < num; i++) {
1303                 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1304                     if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1305                         if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1306                             set_reg_szW(hkey, NameW, PrinterName);
1307                         }
1308                         RegCloseKey(hkey);
1309                     }
1310                 }
1311             }
1312         }
1313         RegCloseKey(hkeyPrinters);
1314     }
1315 
1316     /* We want to avoid calling AddPrinter on printers as much as
1317        possible, because on cups printers this will (eventually) lead
1318        to a call to cupsGetPPD which takes forever, even with non-cups
1319        printers AddPrinter takes a while.  So we'll tag all printers that
1320        were automatically added last time around, if they still exist
1321        we'll leave them be otherwise we'll delete them. */
1322     EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1323     if(needed) {
1324         PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1325         if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1326             for(i = 0; i < num; i++) {
1327                 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1328                     if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1329                         if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1330                             DWORD dw = 1;
1331                             RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1332                             RegCloseKey(hkey);
1333                         }
1334                         ClosePrinter(hprn);
1335                     }
1336                 }
1337             }
1338         }
1339         HeapFree(GetProcessHeap(), 0, pi);
1340     }
1341 
1342 
1343 #ifdef SONAME_LIBCUPS
1344     done = CUPS_LoadPrinters();
1345 #endif
1346 
1347     if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1348         PRINTCAP_LoadPrinters();
1349 
1350     /* Now enumerate the list again and delete any printers that are still tagged */
1351     EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1352     if(needed) {
1353         PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1354         if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1355             for(i = 0; i < num; i++) {
1356                 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1357                     if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1358                         BOOL delete_driver = FALSE;
1359                         if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1360                             DWORD dw, type, size = sizeof(dw);
1361                             if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1362                                 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1363                                 DeletePrinter(hprn);
1364                                 delete_driver = TRUE;
1365                             }
1366                             RegCloseKey(hkey);
1367                         }
1368                         ClosePrinter(hprn);
1369                         if(delete_driver)
1370                             DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1371                     }
1372                 }
1373             }
1374         }
1375         HeapFree(GetProcessHeap(), 0, pi);
1376     }
1377 
1378     return;
1379 
1380 }
1381 
1382 /******************************************************************
1383  *                  get_job
1384  *
1385  *  Get the pointer to the specified job.
1386  *  Should hold the printer_handles_cs before calling.
1387  */
1388 static job_t *get_job(HANDLE hprn, DWORD JobId)
1389 {
1390     opened_printer_t *printer = get_opened_printer(hprn);
1391     job_t *job;
1392 
1393     if(!printer) return NULL;
1394     LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1395     {
1396         if(job->job_id == JobId)
1397             return job;
1398     }
1399     return NULL;
1400 }
1401 
1402 /***********************************************************
1403  *      DEVMODEcpyAtoW
1404  */
1405 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1406 {
1407     BOOL Formname;
1408     ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1409     DWORD size;
1410 
1411     Formname = (dmA->dmSize > off_formname);
1412     size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1413     MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1414                         dmW->dmDeviceName, CCHDEVICENAME);
1415     if(!Formname) {
1416       memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1417              dmA->dmSize - CCHDEVICENAME);
1418     } else {
1419       memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1420              off_formname - CCHDEVICENAME);
1421       MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1422                           dmW->dmFormName, CCHFORMNAME);
1423       memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1424              (off_formname + CCHFORMNAME));
1425     }
1426     dmW->dmSize = size;
1427     memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1428            dmA->dmDriverExtra);
1429     return dmW;
1430 }
1431 
1432 /***********************************************************
1433  * DEVMODEdupWtoA
1434  * Creates an ansi copy of supplied devmode
1435  */
1436 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1437 {
1438     LPDEVMODEA dmA;
1439     DWORD size;
1440 
1441     if (!dmW) return NULL;
1442     size = dmW->dmSize - CCHDEVICENAME -
1443                         ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1444 
1445     dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1446     if (!dmA) return NULL;
1447 
1448     WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1449                         (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1450 
1451     if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1452         memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1453                dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1454     }
1455     else
1456     {
1457         memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1458                FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1459         WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1460                             (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1461 
1462         memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1463     }
1464 
1465     dmA->dmSize = size;
1466     memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1467     return dmA;
1468 }
1469 
1470 /******************************************************************
1471  * convert_printerinfo_W_to_A [internal]
1472  *
1473  */
1474 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1475                                        DWORD level, DWORD outlen, DWORD numentries)
1476 {
1477     DWORD id = 0;
1478     LPSTR ptr;
1479     INT len;
1480 
1481     TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1482 
1483     len = pi_sizeof[level] * numentries;
1484     ptr = (LPSTR) out + len;
1485     outlen -= len;
1486 
1487     /* copy the numbers of all PRINTER_INFO_* first */
1488     memcpy(out, pPrintersW, len);
1489 
1490     while (id < numentries) {
1491         switch (level) {
1492             case 1:
1493                 {
1494                     PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1495                     PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1496 
1497                     TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1498                     if (piW->pDescription) {
1499                         piA->pDescription = ptr;
1500                         len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1501                                                   ptr, outlen, NULL, NULL);
1502                         ptr += len;
1503                         outlen -= len;
1504                     }
1505                     if (piW->pName) {
1506                         piA->pName = ptr;
1507                         len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1508                                                   ptr, outlen, NULL, NULL);
1509                         ptr += len;
1510                         outlen -= len;
1511                     }
1512                     if (piW->pComment) {
1513                         piA->pComment = ptr;
1514                         len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1515                                                   ptr, outlen, NULL, NULL);
1516                         ptr += len;
1517                         outlen -= len;
1518                     }
1519                     break;
1520                 }
1521 
1522             case 2:
1523                 {
1524                     PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1525                     PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1526                     LPDEVMODEA dmA;
1527 
1528                     TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1529                     if (piW->pServerName) {
1530                         piA->pServerName = ptr;
1531                         len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1532                                                   ptr, outlen, NULL, NULL);
1533                         ptr += len;
1534                         outlen -= len;
1535                     }
1536                     if (piW->pPrinterName) {
1537                         piA->pPrinterName = ptr;
1538                         len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1539                                                   ptr, outlen, NULL, NULL);
1540                         ptr += len;
1541                         outlen -= len;
1542                     }
1543                     if (piW->pShareName) {
1544                         piA->pShareName = ptr;
1545                         len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1546                                                   ptr, outlen, NULL, NULL);
1547                         ptr += len;
1548                         outlen -= len;
1549                     }
1550                     if (piW->pPortName) {
1551                         piA->pPortName = ptr;
1552                         len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1553                                                   ptr, outlen, NULL, NULL);
1554                         ptr += len;
1555                         outlen -= len;
1556                     }
1557                     if (piW->pDriverName) {
1558                         piA->pDriverName = ptr;
1559                         len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1560                                                   ptr, outlen, NULL, NULL);
1561                         ptr += len;
1562                         outlen -= len;
1563                     }
1564                     if (piW->pComment) {
1565                         piA->pComment = ptr;
1566                         len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1567                                                   ptr, outlen, NULL, NULL);
1568                         ptr += len;
1569                         outlen -= len;
1570                     }
1571                     if (piW->pLocation) {
1572                         piA->pLocation = ptr;
1573                         len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1574                                                   ptr, outlen, NULL, NULL);
1575                         ptr += len;
1576                         outlen -= len;
1577                     }
1578 
1579                     dmA = DEVMODEdupWtoA(piW->pDevMode);
1580                     if (dmA) {
1581                         /* align DEVMODEA to a DWORD boundary */
1582                         len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1583                         ptr += len;
1584                         outlen -= len;
1585 
1586                         piA->pDevMode = (LPDEVMODEA) ptr;
1587                         len = dmA->dmSize + dmA->dmDriverExtra;
1588                         memcpy(ptr, dmA, len);
1589                         HeapFree(GetProcessHeap(), 0, dmA);
1590 
1591                         ptr += len;
1592                         outlen -= len;
1593                     }
1594 
1595                     if (piW->pSepFile) {
1596                         piA->pSepFile = ptr;
1597                         len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1598                                                   ptr, outlen, NULL, NULL);
1599                         ptr += len;
1600                         outlen -= len;
1601                     }
1602                     if (piW->pPrintProcessor) {
1603                         piA->pPrintProcessor = ptr;
1604                         len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1605                                                   ptr, outlen, NULL, NULL);
1606                         ptr += len;
1607                         outlen -= len;
1608                     }
1609                     if (piW->pDatatype) {
1610                         piA->pDatatype = ptr;
1611                         len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1612                                                   ptr, outlen, NULL, NULL);
1613                         ptr += len;
1614                         outlen -= len;
1615                     }
1616                     if (piW->pParameters) {
1617                         piA->pParameters = ptr;
1618                         len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1619                                                   ptr, outlen, NULL, NULL);
1620                         ptr += len;
1621                         outlen -= len;
1622                     }
1623                     if (piW->pSecurityDescriptor) {
1624                         piA->pSecurityDescriptor = NULL;
1625                         FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1626                     }
1627                     break;
1628                 }
1629 
1630             case 4:
1631                 {
1632                     PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1633                     PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1634 
1635                     TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1636 
1637                     if (piW->pPrinterName) {
1638                         piA->pPrinterName = ptr;
1639                         len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1640                                                   ptr, outlen, NULL, NULL);
1641                         ptr += len;
1642                         outlen -= len;
1643                     }
1644                     if (piW->pServerName) {
1645                         piA->pServerName = ptr;
1646                         len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1647                                                   ptr, outlen, NULL, NULL);
1648                         ptr += len;
1649                         outlen -= len;
1650                     }
1651                     break;
1652                 }
1653 
1654             case 5:
1655                 {
1656                     PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1657                     PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1658 
1659                     TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1660 
1661                     if (piW->pPrinterName) {
1662                         piA->pPrinterName = ptr;
1663                         len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1664                                                   ptr, outlen, NULL, NULL);
1665                         ptr += len;
1666                         outlen -= len;
1667                     }
1668                     if (piW->pPortName) {
1669                         piA->pPortName = ptr;
1670                         len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1671                                                   ptr, outlen, NULL, NULL);
1672                         ptr += len;
1673                         outlen -= len;
1674                     }
1675                     break;
1676                 }
1677 
1678             default:
1679                 FIXME("for level %u\n", level);
1680         }
1681         pPrintersW += pi_sizeof[level];
1682         out += pi_sizeof[level];
1683         id++;
1684     }
1685 }
1686 
1687 /***********************************************************
1688  *             PRINTER_INFO_2AtoW
1689  * Creates a unicode copy of PRINTER_INFO_2A on heap
1690  */
1691 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1692 {
1693     LPPRINTER_INFO_2W piW;
1694     UNICODE_STRING usBuffer;
1695 
1696     if(!piA) return NULL;
1697     piW = HeapAlloc(heap, 0, sizeof(*piW));
1698     memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1699     
1700     piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1701     piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1702     piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1703     piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1704     piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1705     piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1706     piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1707     piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1708     piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1709     piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1710     piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1711     piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1712     return piW;
1713 }
1714 
1715 /***********************************************************
1716  *       FREE_PRINTER_INFO_2W
1717  * Free PRINTER_INFO_2W and all strings
1718  */
1719 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1720 {
1721     if(!piW) return;
1722 
1723     HeapFree(heap,0,piW->pServerName);
1724     HeapFree(heap,0,piW->pPrinterName);
1725     HeapFree(heap,0,piW->pShareName);
1726     HeapFree(heap,0,piW->pPortName);
1727     HeapFree(heap,0,piW->pDriverName);
1728     HeapFree(heap,0,piW->pComment);
1729     HeapFree(heap,0,piW->pLocation);
1730     HeapFree(heap,0,piW->pDevMode);
1731     HeapFree(heap,0,piW->pSepFile);
1732     HeapFree(heap,0,piW->pPrintProcessor);
1733     HeapFree(heap,0,piW->pDatatype);
1734     HeapFree(heap,0,piW->pParameters);
1735     HeapFree(heap,0,piW);
1736     return;
1737 }
1738 
1739 /******************************************************************
1740  *              DeviceCapabilities     [WINSPOOL.@]
1741  *              DeviceCapabilitiesA    [WINSPOOL.@]
1742  *
1743  */
1744 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1745                                LPSTR pOutput, LPDEVMODEA lpdm)
1746 {
1747     INT ret;
1748 
1749     if (!GDI_CallDeviceCapabilities16)
1750     {
1751         GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1752                                                               (LPCSTR)104 );
1753         if (!GDI_CallDeviceCapabilities16) return -1;
1754     }
1755     ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1756 
1757     /* If DC_PAPERSIZE map POINT16s to POINTs */
1758     if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1759         POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1760         POINT *pt = (POINT *)pOutput;
1761         INT i;
1762         memcpy(tmp, pOutput, ret * sizeof(POINT16));
1763         for(i = 0; i < ret; i++, pt++)
1764         {
1765             pt->x = tmp[i].x;
1766             pt->y = tmp[i].y;
1767         }
1768         HeapFree( GetProcessHeap(), 0, tmp );
1769     }
1770     return ret;
1771 }
1772 
1773 
1774 /*****************************************************************************
1775  *          DeviceCapabilitiesW        [WINSPOOL.@]
1776  *
1777  * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1778  *
1779  */
1780 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1781                                WORD fwCapability, LPWSTR pOutput,
1782                                const DEVMODEW *pDevMode)
1783 {
1784     LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1785     LPSTR pDeviceA = strdupWtoA(pDevice);
1786     LPSTR pPortA = strdupWtoA(pPort);
1787     INT ret;
1788 
1789     if(pOutput && (fwCapability == DC_BINNAMES ||
1790                    fwCapability == DC_FILEDEPENDENCIES ||
1791                    fwCapability == DC_PAPERNAMES)) {
1792       /* These need A -> W translation */
1793         INT size = 0, i;
1794         LPSTR pOutputA;
1795         ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1796                                   dmA);
1797         if(ret == -1)
1798             return ret;
1799         switch(fwCapability) {
1800         case DC_BINNAMES:
1801             size = 24;
1802             break;
1803         case DC_PAPERNAMES:
1804         case DC_FILEDEPENDENCIES:
1805             size = 64;
1806             break;
1807         }
1808         pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1809         ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1810                                   dmA);
1811         for(i = 0; i < ret; i++)
1812             MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1813                                 pOutput + (i * size), size);
1814         HeapFree(GetProcessHeap(), 0, pOutputA);
1815     } else {
1816         ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1817                                   (LPSTR)pOutput, dmA);
1818     }
1819     HeapFree(GetProcessHeap(),0,pPortA);
1820     HeapFree(GetProcessHeap(),0,pDeviceA);
1821     HeapFree(GetProcessHeap(),0,dmA);
1822     return ret;
1823 }
1824 
1825 /******************************************************************
1826  *              DocumentPropertiesA   [WINSPOOL.@]
1827  *
1828  * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1829  */
1830 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1831                                 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1832                                 LPDEVMODEA pDevModeInput,DWORD fMode )
1833 {
1834     LPSTR lpName = pDeviceName;
1835     static CHAR port[] = "LPT1:";
1836     LONG ret;
1837 
1838     TRACE("(%p,%p,%s,%p,%p,%d)\n",
1839         hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1840     );
1841 
1842     if(!pDeviceName) {
1843         LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1844         if(!lpNameW) {
1845                 ERR("no name from hPrinter?\n");
1846                 SetLastError(ERROR_INVALID_HANDLE);
1847                 return -1;
1848         }
1849         lpName = strdupWtoA(lpNameW);
1850     }
1851 
1852     if (!GDI_CallExtDeviceMode16)
1853     {
1854         GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1855                                                          (LPCSTR)102 );
1856         if (!GDI_CallExtDeviceMode16) {
1857                 ERR("No CallExtDeviceMode16?\n");
1858                 return -1;
1859         }
1860     }
1861     ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1862                                   pDevModeInput, NULL, fMode);
1863 
1864     if(!pDeviceName)
1865         HeapFree(GetProcessHeap(),0,lpName);
1866     return ret;
1867 }
1868 
1869 
1870 /*****************************************************************************
1871  *          DocumentPropertiesW (WINSPOOL.@)
1872  *
1873  * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1874  */
1875 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1876                                 LPWSTR pDeviceName,
1877                                 LPDEVMODEW pDevModeOutput,
1878                                 LPDEVMODEW pDevModeInput, DWORD fMode)
1879 {
1880 
1881     LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1882     LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1883     LPDEVMODEA pDevModeOutputA = NULL;
1884     LONG ret;
1885 
1886     TRACE("(%p,%p,%s,%p,%p,%d)\n",
1887           hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1888           fMode);
1889     if(pDevModeOutput) {
1890         ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1891         if(ret < 0) return ret;
1892         pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1893     }
1894     ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1895                               pDevModeInputA, fMode);
1896     if(pDevModeOutput) {
1897         DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1898         HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1899     }
1900     if(fMode == 0 && ret > 0)
1901         ret += (CCHDEVICENAME + CCHFORMNAME);
1902     HeapFree(GetProcessHeap(),0,pDevModeInputA);
1903     HeapFree(GetProcessHeap(),0,pDeviceNameA);
1904     return ret;
1905 }
1906 
1907 /******************************************************************
1908  *              OpenPrinterA        [WINSPOOL.@]
1909  *
1910  * See OpenPrinterW.
1911  *
1912  */
1913 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1914                          LPPRINTER_DEFAULTSA pDefault)
1915 {
1916     UNICODE_STRING lpPrinterNameW;
1917     UNICODE_STRING usBuffer;
1918     PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1919     PWSTR pwstrPrinterNameW;
1920     BOOL ret;
1921 
1922     pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1923 
1924     if(pDefault) {
1925         DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1926         DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1927         DefaultW.DesiredAccess = pDefault->DesiredAccess;
1928         pDefaultW = &DefaultW;
1929     }
1930     ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1931     if(pDefault) {
1932         RtlFreeUnicodeString(&usBuffer);
1933         HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1934     }
1935     RtlFreeUnicodeString(&lpPrinterNameW);
1936     return ret;
1937 }
1938 
1939 /******************************************************************
1940  *              OpenPrinterW        [WINSPOOL.@]
1941  *
1942  * Open a Printer / Printserver or a Printer-Object
1943  *
1944  * PARAMS
1945  *  lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1946  *  phPrinter     [O] The resulting Handle is stored here
1947  *  pDefault      [I] PTR to Default Printer Settings or NULL
1948  *
1949  * RETURNS
1950  *  Success: TRUE
1951  *  Failure: FALSE
1952  *
1953  * NOTES
1954  *  lpPrinterName is one of:
1955  *|  Printserver (NT only): "Servername" or NULL for the local Printserver
1956  *|  Printer: "PrinterName"
1957  *|  Printer-Object: "PrinterName,Job xxx"
1958  *|  XcvMonitor: "Servername,XcvMonitor MonitorName"
1959  *|  XcvPort: "Servername,XcvPort PortName"
1960  *
1961  * BUGS
1962  *|  Printer-Object not supported
1963  *|  pDefaults is ignored
1964  *
1965  */
1966 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1967 {
1968 
1969     TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1970     if (pDefault) {
1971         FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1972         debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1973     }
1974 
1975     if(!phPrinter) {
1976         /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1977         SetLastError(ERROR_INVALID_PARAMETER);
1978         return FALSE;
1979     }
1980 
1981     /* Get the unique handle of the printer or Printserver */
1982     *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1983     TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1984     return (*phPrinter != 0);
1985 }
1986 
1987 /******************************************************************
1988  *              AddMonitorA        [WINSPOOL.@]
1989  *
1990  * See AddMonitorW.
1991  *
1992  */
1993 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1994 {
1995     LPWSTR  nameW = NULL;
1996     INT     len;
1997     BOOL    res;
1998     LPMONITOR_INFO_2A mi2a;
1999     MONITOR_INFO_2W mi2w;
2000 
2001     mi2a = (LPMONITOR_INFO_2A) pMonitors;
2002     TRACE("(%s, %d, %p) :  %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2003           debugstr_a(mi2a ? mi2a->pName : NULL),
2004           debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2005           debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2006 
2007     if  (Level != 2) {
2008         SetLastError(ERROR_INVALID_LEVEL);
2009         return FALSE;
2010     }
2011 
2012     /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2013     if (mi2a == NULL) {
2014         return FALSE;
2015     }
2016 
2017     if (pName) {
2018         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2019         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2020         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2021     }
2022 
2023     memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2024     if (mi2a->pName) {
2025         len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2026         mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2027         MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2028     }
2029     if (mi2a->pEnvironment) {
2030         len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2031         mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2032         MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2033     }
2034     if (mi2a->pDLLName) {
2035         len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2036         mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2037         MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2038     }
2039 
2040     res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2041 
2042     HeapFree(GetProcessHeap(), 0, mi2w.pName); 
2043     HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment); 
2044     HeapFree(GetProcessHeap(), 0, mi2w.pDLLName); 
2045 
2046     HeapFree(GetProcessHeap(), 0, nameW); 
2047     return (res);
2048 }
2049 
2050 /******************************************************************************
2051  *              AddMonitorW        [WINSPOOL.@]
2052  *
2053  * Install a Printmonitor
2054  *
2055  * PARAMS
2056  *  pName       [I] Servername or NULL (local Computer)
2057  *  Level       [I] Structure-Level (Must be 2)
2058  *  pMonitors   [I] PTR to MONITOR_INFO_2
2059  *
2060  * RETURNS
2061  *  Success: TRUE
2062  *  Failure: FALSE
2063  *
2064  * NOTES
2065  *  All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2066  *
2067  */
2068 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2069 {
2070     LPMONITOR_INFO_2W mi2w;
2071 
2072     mi2w = (LPMONITOR_INFO_2W) pMonitors;
2073     TRACE("(%s, %d, %p) :  %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2074           debugstr_w(mi2w ? mi2w->pName : NULL),
2075           debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2076           debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2077 
2078     if ((backend == NULL)  && !load_backend()) return FALSE;
2079 
2080     if (Level != 2) {
2081         SetLastError(ERROR_INVALID_LEVEL);
2082         return FALSE;
2083     }
2084 
2085     /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2086     if (mi2w == NULL) {
2087         return FALSE;
2088     }
2089 
2090     return backend->fpAddMonitor(pName, Level, pMonitors);
2091 }
2092 
2093 /******************************************************************
2094  *              DeletePrinterDriverA        [WINSPOOL.@]
2095  *
2096  */
2097 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2098 {
2099     return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2100 }
2101 
2102 /******************************************************************
2103  *              DeletePrinterDriverW        [WINSPOOL.@]
2104  *
2105  */
2106 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2107 {
2108     return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2109 }
2110 
2111 /******************************************************************
2112  *              DeleteMonitorA        [WINSPOOL.@]
2113  *
2114  * See DeleteMonitorW.
2115  *
2116  */
2117 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2118 {
2119     LPWSTR  nameW = NULL;
2120     LPWSTR  EnvironmentW = NULL;
2121     LPWSTR  MonitorNameW = NULL;
2122     BOOL    res;
2123     INT     len;
2124 
2125     if (pName) {
2126         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2127         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2128         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2129     }
2130 
2131     if (pEnvironment) {
2132         len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2133         EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2134         MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2135     }
2136     if (pMonitorName) {
2137         len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2138         MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2139         MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2140     }
2141 
2142     res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2143 
2144     HeapFree(GetProcessHeap(), 0, MonitorNameW); 
2145     HeapFree(GetProcessHeap(), 0, EnvironmentW);
2146     HeapFree(GetProcessHeap(), 0, nameW); 
2147     return (res);
2148 }
2149 
2150 /******************************************************************
2151  *              DeleteMonitorW        [WINSPOOL.@]
2152  *
2153  * Delete a specific Printmonitor from a Printing-Environment
2154  *
2155  * PARAMS
2156  *  pName        [I] Servername or NULL (local Computer)
2157  *  pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2158  *  pMonitorName [I] Name of the Monitor, that should be deleted
2159  *
2160  * RETURNS
2161  *  Success: TRUE
2162  *  Failure: FALSE
2163  *
2164  * NOTES
2165  *  pEnvironment is ignored in Windows for the local Computer.
2166  *
2167  */
2168 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2169 {
2170 
2171     TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2172            debugstr_w(pMonitorName));
2173 
2174     if ((backend == NULL)  && !load_backend()) return FALSE;
2175 
2176     return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2177 }
2178 
2179 
2180 /******************************************************************
2181  *              DeletePortA        [WINSPOOL.@]
2182  *
2183  * See DeletePortW.
2184  *
2185  */
2186 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2187 {
2188     LPWSTR  nameW = NULL;
2189     LPWSTR  portW = NULL;
2190     INT     len;
2191     DWORD   res;
2192 
2193     TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2194 
2195     /* convert servername to unicode */
2196     if (pName) {
2197         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2198         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2199         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2200     }
2201 
2202     /* convert portname to unicode */
2203     if (pPortName) {
2204         len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2205         portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2206         MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2207     }
2208 
2209     res = DeletePortW(nameW, hWnd, portW);
2210     HeapFree(GetProcessHeap(), 0, nameW);
2211     HeapFree(GetProcessHeap(), 0, portW);
2212     return res;
2213 }
2214 
2215 /******************************************************************
2216  *              DeletePortW        [WINSPOOL.@]
2217  *
2218  * Delete a specific Port
2219  *
2220  * PARAMS
2221  *  pName     [I] Servername or NULL (local Computer)
2222  *  hWnd      [I] Handle to parent Window for the Dialog-Box
2223  *  pPortName [I] Name of the Port, that should be deleted
2224  *
2225  * RETURNS
2226  *  Success: TRUE
2227  *  Failure: FALSE
2228  *
2229  */
2230 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2231 {
2232     monitor_t * pm;
2233     monitor_t * pui;
2234     DWORD       res;
2235 
2236     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2237 
2238     if (pName && pName[0]) {
2239         SetLastError(ERROR_INVALID_PARAMETER);
2240         return FALSE;
2241     }
2242 
2243     if (!pPortName) {
2244         SetLastError(RPC_X_NULL_REF_POINTER);
2245         return FALSE;
2246     }
2247 
2248     /* an empty Portname is Invalid */
2249     if (!pPortName[0]) {
2250         SetLastError(ERROR_NOT_SUPPORTED);
2251         return FALSE;
2252     }
2253 
2254     pm = monitor_load_by_port(pPortName);
2255     if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2256         TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2257         res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2258         TRACE("got %d with %u\n", res, GetLastError());
2259     }
2260     else
2261     {
2262         pui = monitor_loadui(pm);
2263         if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2264             TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2265             res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2266             TRACE("got %d with %u\n", res, GetLastError());
2267         }
2268         else
2269         {
2270             FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2271                   pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2272 
2273             /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2274             SetLastError(ERROR_NOT_SUPPORTED);
2275             res = FALSE;
2276         }
2277         monitor_unload(pui);
2278     }
2279     monitor_unload(pm);
2280 
2281     TRACE("returning %d with %u\n", res, GetLastError());
2282     return res;
2283 }
2284 
2285 /******************************************************************************
2286  *    SetPrinterW  [WINSPOOL.@]
2287  */
2288 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2289 {
2290     FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2291     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2292     return FALSE;
2293 }
2294 
2295 /******************************************************************************
2296  *    WritePrinter  [WINSPOOL.@]
2297  */
2298 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2299 {
2300     opened_printer_t *printer;
2301     BOOL ret = FALSE;
2302 
2303     TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2304 
2305     EnterCriticalSection(&printer_handles_cs);
2306     printer = get_opened_printer(hPrinter);
2307     if(!printer)
2308     {
2309         SetLastError(ERROR_INVALID_HANDLE);
2310         goto end;
2311     }
2312 
2313     if(!printer->doc)
2314     {
2315         SetLastError(ERROR_SPL_NO_STARTDOC);
2316         goto end;
2317     }
2318 
2319     ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2320 end:
2321     LeaveCriticalSection(&printer_handles_cs);
2322     return ret;
2323 }
2324 
2325 /*****************************************************************************
2326  *          AddFormA  [WINSPOOL.@]
2327  */
2328 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2329 {
2330     FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2331     return 1;
2332 }
2333 
2334 /*****************************************************************************
2335  *          AddFormW  [WINSPOOL.@]
2336  */
2337 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2338 {
2339     FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2340     return 1;
2341 }
2342 
2343 /*****************************************************************************
2344  *          AddJobA  [WINSPOOL.@]
2345  */
2346 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2347 {
2348     BOOL ret;
2349     BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2350     DWORD needed;
2351 
2352     if(Level != 1) {
2353         SetLastError(ERROR_INVALID_LEVEL);
2354         return FALSE;
2355     }
2356 
2357     ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2358 
2359     if(ret) {
2360         ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2361         DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2362         *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2363         if(*pcbNeeded > cbBuf) {
2364             SetLastError(ERROR_INSUFFICIENT_BUFFER);
2365             ret = FALSE;
2366         } else {
2367             ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2368             addjobA->JobId = addjobW->JobId;
2369             addjobA->Path = (char *)(addjobA + 1);
2370             WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2371         }
2372     }
2373     return ret;
2374 }
2375 
2376 /*****************************************************************************
2377  *          AddJobW  [WINSPOOL.@]
2378  */
2379 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2380 {
2381     opened_printer_t *printer;
2382     job_t *job;
2383     BOOL ret = FALSE;
2384     static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2385     static const WCHAR fmtW[] = {'%','s','%','','5','d','.','S','P','L',0};
2386     WCHAR path[MAX_PATH], filename[MAX_PATH];
2387     DWORD len;
2388     ADDJOB_INFO_1W *addjob;
2389 
2390     TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2391     
2392     EnterCriticalSection(&printer_handles_cs);
2393 
2394     printer = get_opened_printer(hPrinter);
2395 
2396     if(!printer) {
2397         SetLastError(ERROR_INVALID_HANDLE);
2398         goto end;
2399     }
2400 
2401     if(Level != 1) {
2402         SetLastError(ERROR_INVALID_LEVEL);
2403         goto end;
2404     }
2405 
2406     job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2407     if(!job)
2408         goto end;
2409 
2410     job->job_id = InterlockedIncrement(&next_job_id);
2411 
2412     len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2413     if(path[len - 1] != '\\')
2414         path[len++] = '\\';
2415     memcpy(path + len, spool_path, sizeof(spool_path));    
2416     sprintfW(filename, fmtW, path, job->job_id);
2417 
2418     len = strlenW(filename);
2419     job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2420     memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2421     job->document_title = strdupW(default_doc_title);
2422     list_add_tail(&printer->queue->jobs, &job->entry);
2423 
2424     *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2425     if(*pcbNeeded <= cbBuf) {
2426         addjob = (ADDJOB_INFO_1W*)pData;
2427         addjob->JobId = job->job_id;
2428         addjob->Path = (WCHAR *)(addjob + 1);
2429         memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2430         ret = TRUE;
2431     } else 
2432         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2433 
2434 end:
2435     LeaveCriticalSection(&printer_handles_cs);
2436     return ret;
2437 }
2438 
2439 /*****************************************************************************
2440  *          GetPrintProcessorDirectoryA  [WINSPOOL.@]
2441  *
2442  * Return the PATH for the Print-Processors
2443  *
2444  * See GetPrintProcessorDirectoryW.
2445  *
2446  *
2447  */
2448 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2449                                         DWORD level,  LPBYTE Info,
2450                                         DWORD cbBuf,  LPDWORD pcbNeeded)
2451 {
2452     LPWSTR  serverW = NULL;
2453     LPWSTR  envW = NULL;
2454     BOOL    ret;
2455     INT     len;
2456 
2457     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server), 
2458           debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2459  
2460 
2461     if (server) {
2462         len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2463         serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2464         MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2465     }
2466 
2467     if (env) {
2468         len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2469         envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2470         MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2471     }
2472 
2473     /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2474        for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2475      */
2476     ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info, 
2477                                       cbBuf, pcbNeeded);
2478 
2479     if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2480                                        cbBuf, NULL, NULL) > 0;
2481 
2482 
2483     TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2484     HeapFree(GetProcessHeap(), 0, envW);
2485     HeapFree(GetProcessHeap(), 0, serverW);
2486     return ret;
2487 }
2488 
2489 /*****************************************************************************
2490  *          GetPrintProcessorDirectoryW  [WINSPOOL.@]
2491  *
2492  * Return the PATH for the Print-Processors
2493  *
2494  * PARAMS
2495  *   server     [I] Servername (NT only) or NULL (local Computer)
2496  *   env        [I] Printing-Environment (see below) or NULL (Default)
2497  *   level      [I] Structure-Level (must be 1)
2498  *   Info       [O] PTR to Buffer that receives the Result
2499  *   cbBuf      [I] Size of Buffer at "Info"
2500  *   pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / 
2501  *                  required for the Buffer at "Info"
2502  *
2503  * RETURNS
2504  *   Success: TRUE  and in pcbNeeded the Bytes used in Info
2505  *   Failure: FALSE and in pcbNeeded the Bytes required for Info,
2506  *   if cbBuf is too small
2507  * 
2508  *   Native Values returned in Info on Success:
2509  *|  NT(Windows NT x86):  "%winsysdir%\\spool\\PRTPROCS\\w32x86" 
2510  *|  NT(Windows 4.0):     "%winsysdir%\\spool\\PRTPROCS\\win40" 
2511  *|  win9x(Windows 4.0):  "%winsysdir%" 
2512  *
2513  *   "%winsysdir%" is the Value from GetSystemDirectoryW()
2514  *
2515  * BUGS
2516  *  Only NULL or "" is supported for server
2517  *
2518  */
2519 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2520                                         DWORD level,  LPBYTE Info,
2521                                         DWORD cbBuf,  LPDWORD pcbNeeded)
2522 {
2523     DWORD needed;
2524     const printenv_t * env_t;
2525 
2526     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2527             debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2528 
2529     if(server != NULL && server[0]) {
2530         FIXME("server not supported: %s\n", debugstr_w(server));
2531         SetLastError(ERROR_INVALID_PARAMETER);
2532         return FALSE;
2533     }
2534 
2535     env_t = validate_envW(env);
2536     if(!env_t) return FALSE;  /* environment invalid or unsupported */
2537 
2538     if(level != 1) {
2539         WARN("(Level: %d) is ignored in win9x\n", level);
2540         SetLastError(ERROR_INVALID_LEVEL);
2541         return FALSE;
2542     }
2543 
2544     /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2545     needed = GetSystemDirectoryW(NULL, 0);
2546     /* add the Size for the Subdirectories */
2547     needed += lstrlenW(spoolprtprocsW);
2548     needed += lstrlenW(env_t->subdir);
2549     needed *= sizeof(WCHAR);  /* return-value is size in Bytes */
2550 
2551     if(pcbNeeded) *pcbNeeded = needed;
2552     TRACE ("required: 0x%x/%d\n", needed, needed);
2553     if (needed > cbBuf) {
2554         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2555         return FALSE;
2556     }
2557     if(pcbNeeded == NULL) {
2558         /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2559         WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2560         SetLastError(RPC_X_NULL_REF_POINTER);
2561         return FALSE;
2562     }
2563     if(Info == NULL) {
2564         /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2565         SetLastError(RPC_X_NULL_REF_POINTER);
2566         return FALSE;
2567     }
2568     
2569     GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2570     /* add the Subdirectories */
2571     lstrcatW((LPWSTR) Info, spoolprtprocsW);
2572     lstrcatW((LPWSTR) Info, env_t->subdir);
2573     TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2574     return TRUE;
2575 }
2576 
2577 /*****************************************************************************
2578  *          WINSPOOL_OpenDriverReg [internal]
2579  *
2580  * opens the registry for the printer drivers depending on the given input
2581  * variable pEnvironment
2582  *
2583  * RETURNS:
2584  *    the opened hkey on success
2585  *    NULL on error
2586  */
2587 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2588 {   
2589     HKEY  retval = NULL;
2590     LPWSTR buffer;
2591     const printenv_t * env;
2592 
2593     TRACE("(%s, %d)\n",
2594           (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2595 
2596     if (!pEnvironment || unicode) {
2597         /* pEnvironment was NULL or a Unicode-String: use it direct */
2598         env = validate_envW(pEnvironment);
2599     }
2600     else
2601     {
2602         /* pEnvironment was an ANSI-String: convert to unicode first */
2603         LPWSTR  buffer;
2604         INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2605         buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2606         if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2607         env = validate_envW(buffer);
2608         HeapFree(GetProcessHeap(), 0, buffer);
2609     }
2610     if (!env) return NULL;
2611 
2612     buffer = HeapAlloc( GetProcessHeap(), 0,
2613                 (strlenW(DriversW) + strlenW(env->envname) + 
2614                  strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2615     if(buffer) {
2616         wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2617         RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2618         HeapFree(GetProcessHeap(), 0, buffer);
2619     }
2620     return retval;
2621 }
2622 
2623 /*****************************************************************************
2624  *          AddPrinterW  [WINSPOOL.@]
2625  */
2626 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2627 {
2628     PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2629     LPDEVMODEA dmA;
2630     LPDEVMODEW dmW;
2631     HANDLE retval;
2632     HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2633     LONG size;
2634     static const WCHAR attributesW[]      = {'A','t','t','r','i','b','u','t','e','s',0},
2635                        default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2636                        priorityW[]        = {'P','r','i','o','r','i','t','y',0},
2637                        start_timeW[]      = {'S','t','a','r','t','T','i','m','e',0},
2638                        statusW[]          = {'S','t','a','t','u','s',0},
2639                        until_timeW[]      = {'U','n','t','i','l','T','i','m','e',0};
2640 
2641     TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2642 
2643     if(pName != NULL) {
2644         ERR("pName = %s - unsupported\n", debugstr_w(pName));
2645         SetLastError(ERROR_INVALID_PARAMETER);
2646         return 0;
2647     }
2648     if(Level != 2) {
2649         ERR("Level = %d, unsupported!\n", Level);
2650         SetLastError(ERROR_INVALID_LEVEL);
2651         return 0;
2652     }
2653     if(!pPrinter) {
2654         SetLastError(ERROR_INVALID_PARAMETER);
2655         return 0;
2656     }
2657     if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2658        ERROR_SUCCESS) {
2659         ERR("Can't create Printers key\n");
2660         return 0;
2661     }
2662     if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2663         if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2664             SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2665             RegCloseKey(hkeyPrinter);
2666             RegCloseKey(hkeyPrinters);
2667             return 0;
2668         }
2669         RegCloseKey(hkeyPrinter);
2670     }
2671     hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2672     if(!hkeyDrivers) {
2673         ERR("Can't create Drivers key\n");
2674         RegCloseKey(hkeyPrinters);
2675         return 0;
2676     }
2677     if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2678        ERROR_SUCCESS) {
2679         WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2680         RegCloseKey(hkeyPrinters);
2681         RegCloseKey(hkeyDrivers);
2682         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2683         return 0;
2684     }
2685     RegCloseKey(hkeyDriver);
2686     RegCloseKey(hkeyDrivers);
2687 
2688     if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) {  /* FIXME */
2689         FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2690         SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2691         RegCloseKey(hkeyPrinters);
2692         return 0;
2693     }
2694 
2695     if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2696        ERROR_SUCCESS) {
2697         FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2698         SetLastError(ERROR_INVALID_PRINTER_NAME);
2699         RegCloseKey(hkeyPrinters);
2700         return 0;
2701     }
2702     RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2703                    (LPBYTE)&pi->Attributes, sizeof(DWORD));
2704     set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2705 
2706     /* See if we can load the driver.  We may need the devmode structure anyway
2707      *
2708      * FIXME:
2709      * Note that DocumentPropertiesW will briefly try to open the printer we
2710      * just create to find a DEVMODEA struct (it will use the WINEPS default
2711      * one in case it is not there, so we are ok).
2712      */
2713     size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2714 
2715     if(size < 0) {
2716         FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2717         size = sizeof(DEVMODEW);
2718     }
2719     if(pi->pDevMode)
2720         dmW = pi->pDevMode;
2721     else
2722     {
2723         dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2724         dmW->dmSize = size;
2725         if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2726         {
2727             WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2728             HeapFree(GetProcessHeap(),0,dmW);
2729             dmW=NULL;
2730         }
2731         else
2732         {
2733             /* set devmode to printer name */
2734             lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2735         }
2736     }
2737 
2738     /* Write DEVMODEA not DEVMODEW into reg.  This is what win9x does
2739        and we support these drivers.  NT writes DEVMODEW so somehow
2740        we'll need to distinguish between these when we support NT
2741        drivers */
2742     if (dmW)
2743     {
2744         dmA = DEVMODEdupWtoA(dmW);
2745         RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2746                        (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2747         HeapFree(GetProcessHeap(), 0, dmA);
2748         if(!pi->pDevMode)
2749             HeapFree(GetProcessHeap(), 0, dmW);
2750     }
2751     set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2752     set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2753     set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2754     set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2755 
2756     set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2757     set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2758     set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2759     RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2760                    (LPBYTE)&pi->Priority, sizeof(DWORD));
2761     set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2762     set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2763     RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2764                    (LPBYTE)&pi->StartTime, sizeof(DWORD));
2765     RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2766                    (LPBYTE)&pi->Status, sizeof(DWORD));
2767     RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2768                    (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2769 
2770     RegCloseKey(hkeyPrinter);
2771     RegCloseKey(hkeyPrinters);
2772     if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2773         ERR("OpenPrinter failing\n");
2774         return 0;
2775     }
2776     return retval;
2777 }
2778 
2779 /*****************************************************************************
2780  *          AddPrinterA  [WINSPOOL.@]
2781  */
2782 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2783 {
2784     UNICODE_STRING pNameW;
2785     PWSTR pwstrNameW;
2786     PRINTER_INFO_2W *piW;
2787     PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2788     HANDLE ret;
2789 
2790     TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2791     if(Level != 2) {
2792         ERR("Level = %d, unsupported!\n", Level);
2793         SetLastError(ERROR_INVALID_LEVEL);
2794         return 0;
2795     }
2796     pwstrNameW = asciitounicode(&pNameW,pName);
2797     piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2798 
2799     ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2800 
2801     FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2802     RtlFreeUnicodeString(&pNameW);
2803     return ret;
2804 }
2805 
2806 
2807 /*****************************************************************************
2808  *          ClosePrinter  [WINSPOOL.@]
2809  */
2810 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2811 {
2812     UINT_PTR i = (UINT_PTR)hPrinter;
2813     opened_printer_t *printer = NULL;
2814     BOOL ret = FALSE;
2815 
2816     TRACE("(%p)\n", hPrinter);
2817 
2818     EnterCriticalSection(&printer_handles_cs);
2819 
2820     if ((i > 0) && (i <= nb_printer_handles))
2821         printer = printer_handles[i - 1];
2822 
2823 
2824     if(printer)
2825     {
2826         struct list *cursor, *cursor2;
2827 
2828         TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2829 
2830         if (printer->backend_printer) {
2831             backend->fpClosePrinter(printer->backend_printer);
2832         }
2833 
2834         if(printer->doc)
2835             EndDocPrinter(hPrinter);
2836 
2837         if(InterlockedDecrement(&printer->queue->ref) == 0)
2838         {
2839             LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2840             {
2841                 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2842                 ScheduleJob(hPrinter, job->job_id);
2843             }
2844             HeapFree(GetProcessHeap(), 0, printer->queue);
2845         }
2846 
2847         HeapFree(GetProcessHeap(), 0, printer->printername);
2848         HeapFree(GetProcessHeap(), 0, printer->name);
2849         HeapFree(GetProcessHeap(), 0, printer);
2850         printer_handles[i - 1] = NULL;
2851         ret = TRUE;
2852     }
2853     LeaveCriticalSection(&printer_handles_cs);
2854     return ret;
2855 }
2856 
2857 /*****************************************************************************
2858  *          DeleteFormA  [WINSPOOL.@]
2859  */
2860 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2861 {
2862     FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2863     return 1;
2864 }
2865 
2866 /*****************************************************************************
2867  *          DeleteFormW  [WINSPOOL.@]
2868  */
2869 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2870 {
2871     FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2872     return 1;
2873 }
2874 
2875 /*****************************************************************************
2876  *          DeletePrinter  [WINSPOOL.@]
2877  */
2878 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2879 {
2880     LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2881     HKEY hkeyPrinters, hkey;
2882 
2883     if(!lpNameW) {
2884         SetLastError(ERROR_INVALID_HANDLE);
2885         return FALSE;
2886     }
2887     if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2888         RegDeleteTreeW(hkeyPrinters, lpNameW);
2889         RegCloseKey(hkeyPrinters);
2890     }
2891     WriteProfileStringW(devicesW, lpNameW, NULL);
2892     WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2893 
2894     if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2895         RegDeleteValueW(hkey, lpNameW);
2896         RegCloseKey(hkey);
2897     }
2898 
2899     if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2900         RegDeleteValueW(hkey, lpNameW);
2901         RegCloseKey(hkey);
2902     }
2903     return TRUE;
2904 }
2905 
2906 /*****************************************************************************
2907  *          SetPrinterA  [WINSPOOL.@]
2908  */
2909 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2910                            DWORD Command)
2911 {
2912     FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2913     return FALSE;
2914 }
2915 
2916 /*****************************************************************************
2917  *          SetJobA  [WINSPOOL.@]
2918  */
2919 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2920                     LPBYTE pJob, DWORD Command)
2921 {
2922     BOOL ret;
2923     LPBYTE JobW;
2924     UNICODE_STRING usBuffer;
2925 
2926     TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2927 
2928     /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2929        are all ignored by SetJob, so we don't bother copying them */
2930     switch(Level)
2931     {
2932     case 0:
2933         JobW = NULL;
2934         break;
2935     case 1:
2936       {
2937         JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2938         JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2939 
2940         JobW = (LPBYTE)info1W;
2941         info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2942         info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2943         info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2944         info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2945         info1W->Status = info1A->Status;
2946         info1W->Priority = info1A->Priority;
2947         info1W->Position = info1A->Position;
2948         info1W->PagesPrinted = info1A->PagesPrinted;
2949         break;
2950       }
2951     case 2:
2952       {
2953         JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2954         JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2955 
2956         JobW = (LPBYTE)info2W;
2957         info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2958         info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2959         info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2960         info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2961         info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2962         info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2963         info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2964         info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2965         info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2966         info2W->Status = info2A->Status;
2967         info2W->Priority = info2A->Priority;
2968         info2W->Position = info2A->Position;
2969         info2W->StartTime = info2A->StartTime;
2970         info2W->UntilTime = info2A->UntilTime;
2971         info2W->PagesPrinted = info2A->PagesPrinted;
2972         break;
2973       }
2974     case 3:
2975         JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2976         memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2977         break;
2978     default:
2979         SetLastError(ERROR_INVALID_LEVEL);
2980         return FALSE;
2981     }
2982 
2983     ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2984 
2985     switch(Level)
2986     {
2987     case 1:
2988       {
2989         JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2990         HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2991         HeapFree(GetProcessHeap(), 0, info1W->pDocument); 
2992         HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2993         HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2994         break;
2995       }
2996     case 2:
2997       {
2998         JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2999         HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3000         HeapFree(GetProcessHeap(), 0, info2W->pDocument); 
3001         HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3002         HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3003         HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3004         HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3005         HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3006         HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3007         break;
3008       }
3009     }
3010     HeapFree(GetProcessHeap(), 0, JobW);
3011 
3012     return ret;
3013 }
3014 
3015 /*****************************************************************************
3016  *          SetJobW  [WINSPOOL.@]
3017  */
3018 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3019                     LPBYTE pJob, DWORD Command)
3020 {
3021     BOOL ret = FALSE;
3022     job_t *job;
3023 
3024     TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3025     FIXME("Ignoring everything other than document title\n");
3026 
3027     EnterCriticalSection(&printer_handles_cs);
3028     job = get_job(hPrinter, JobId);
3029     if(!job)
3030         goto end;
3031 
3032     switch(Level)
3033     {
3034     case 0:
3035         break;
3036     case 1:
3037       {
3038         JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3039         HeapFree(GetProcessHeap(), 0, job->document_title);
3040         job->document_title = strdupW(info1->pDocument);
3041         break;
3042       }
3043     case 2:
3044       {
3045         JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3046         HeapFree(GetProcessHeap(), 0, job->document_title);
3047         job->document_title = strdupW(info2->pDocument);
3048         break;
3049       }
3050     case 3:
3051         break;
3052     default:
3053         SetLastError(ERROR_INVALID_LEVEL);
3054         goto end;
3055     }
3056     ret = TRUE;
3057 end:
3058     LeaveCriticalSection(&printer_handles_cs);
3059     return ret;
3060 }
3061 
3062 /*****************************************************************************
3063  *          EndDocPrinter  [WINSPOOL.@]
3064  */
3065 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3066 {
3067     opened_printer_t *printer;
3068     BOOL ret = FALSE;
3069     TRACE("(%p)\n", hPrinter);
3070 
3071     EnterCriticalSection(&printer_handles_cs);
3072 
3073     printer = get_opened_printer(hPrinter);
3074     if(!printer)
3075     {
3076         SetLastError(ERROR_INVALID_HANDLE);
3077         goto end;
3078     }
3079 
3080     if(!printer->doc)    
3081     {
3082         SetLastError(ERROR_SPL_NO_STARTDOC);
3083         goto end;
3084     }
3085 
3086     CloseHandle(printer->doc->hf);
3087     ScheduleJob(hPrinter, printer->doc->job_id);
3088     HeapFree(GetProcessHeap(), 0, printer->doc);
3089     printer->doc = NULL;
3090     ret = TRUE;
3091 end:
3092     LeaveCriticalSection(&printer_handles_cs);
3093     return ret;
3094 }
3095 
3096 /*****************************************************************************
3097  *          EndPagePrinter  [WINSPOOL.@]
3098  */
3099 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3100 {
3101     FIXME("(%p): stub\n", hPrinter);
3102     return TRUE;
3103 }
3104 
3105 /*****************************************************************************
3106  *          StartDocPrinterA  [WINSPOOL.@]
3107  */
3108 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3109 {
3110     UNICODE_STRING usBuffer;
3111     DOC_INFO_2W doc2W;
3112     DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3113     DWORD ret;
3114 
3115     /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3116        or one (DOC_INFO_3) extra DWORDs */
3117 
3118     switch(Level) {
3119     case 2:
3120         doc2W.JobId = doc2->JobId;
3121         /* fall through */
3122     case 3:
3123         doc2W.dwMode = doc2->dwMode;
3124         /* fall through */
3125     case 1:
3126         doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3127         doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3128         doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3129         break;
3130 
3131     default:
3132         SetLastError(ERROR_INVALID_LEVEL);
3133         return FALSE;
3134     }
3135 
3136     ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3137 
3138     HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3139     HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3140     HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3141 
3142     return ret;
3143 }
3144 
3145 /*****************************************************************************
3146  *          StartDocPrinterW  [WINSPOOL.@]
3147  */
3148 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3149 {
3150     DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3151     opened_printer_t *printer;
3152     BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3153     ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3154     JOB_INFO_1W job_info;
3155     DWORD needed, ret = 0;
3156     HANDLE hf;
3157     WCHAR *filename;
3158 
3159     TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3160           hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3161           debugstr_w(doc->pDatatype));
3162 
3163     if(Level < 1 || Level > 3)