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