winspool: Don't fail on empty server name in AddPrinterW.
[wine.git] / dlls / winspool.drv / info.c
blob45490346a6c9be3ddede55af2da26cd375fafd59
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include "wine/port.h"
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stddef.h>
36 #include <errno.h>
37 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/wait.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 #include <signal.h>
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
46 #endif
48 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
49 #define GetCurrentProcess GetCurrentProcess_Mac
50 #define GetCurrentThread GetCurrentThread_Mac
51 #define LoadResource LoadResource_Mac
52 #define AnimatePalette AnimatePalette_Mac
53 #define EqualRgn EqualRgn_Mac
54 #define FillRgn FillRgn_Mac
55 #define FrameRgn FrameRgn_Mac
56 #define GetPixel GetPixel_Mac
57 #define InvertRgn InvertRgn_Mac
58 #define LineTo LineTo_Mac
59 #define OffsetRgn OffsetRgn_Mac
60 #define PaintRgn PaintRgn_Mac
61 #define Polygon Polygon_Mac
62 #define ResizePalette ResizePalette_Mac
63 #define SetRectRgn SetRectRgn_Mac
64 #define EqualRect EqualRect_Mac
65 #define FillRect FillRect_Mac
66 #define FrameRect FrameRect_Mac
67 #define GetCursor GetCursor_Mac
68 #define InvertRect InvertRect_Mac
69 #define OffsetRect OffsetRect_Mac
70 #define PtInRect PtInRect_Mac
71 #define SetCursor SetCursor_Mac
72 #define SetRect SetRect_Mac
73 #define ShowCursor ShowCursor_Mac
74 #define UnionRect UnionRect_Mac
75 #include <ApplicationServices/ApplicationServices.h>
76 #undef GetCurrentProcess
77 #undef GetCurrentThread
78 #undef LoadResource
79 #undef AnimatePalette
80 #undef EqualRgn
81 #undef FillRgn
82 #undef FrameRgn
83 #undef GetPixel
84 #undef InvertRgn
85 #undef LineTo
86 #undef OffsetRgn
87 #undef PaintRgn
88 #undef Polygon
89 #undef ResizePalette
90 #undef SetRectRgn
91 #undef EqualRect
92 #undef FillRect
93 #undef FrameRect
94 #undef GetCursor
95 #undef InvertRect
96 #undef OffsetRect
97 #undef PtInRect
98 #undef SetCursor
99 #undef SetRect
100 #undef ShowCursor
101 #undef UnionRect
102 #undef DPRINTF
103 #endif
105 #include "wine/library.h"
106 #include "windef.h"
107 #include "winbase.h"
108 #include "winuser.h"
109 #include "winerror.h"
110 #include "winreg.h"
111 #include "wingdi.h"
112 #include "winspool.h"
113 #include "winternl.h"
114 #include "wine/windef16.h"
115 #include "wine/unicode.h"
116 #include "wine/debug.h"
117 #include "wine/list.h"
118 #include "winnls.h"
120 #include "ddk/winsplp.h"
121 #include "wspool.h"
123 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
125 /* ############################### */
127 static CRITICAL_SECTION printer_handles_cs;
128 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
130 0, 0, &printer_handles_cs,
131 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
132 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
134 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
136 /* ############################### */
138 typedef struct {
139 DWORD job_id;
140 HANDLE hf;
141 } started_doc_t;
143 typedef struct {
144 struct list jobs;
145 LONG ref;
146 } jobqueue_t;
148 typedef struct {
149 LPWSTR name;
150 LPWSTR printername;
151 HANDLE backend_printer;
152 jobqueue_t *queue;
153 started_doc_t *doc;
154 DEVMODEW *devmode;
155 } opened_printer_t;
157 typedef struct {
158 struct list entry;
159 DWORD job_id;
160 WCHAR *filename;
161 WCHAR *portname;
162 WCHAR *document_title;
163 WCHAR *printer_name;
164 LPDEVMODEW devmode;
165 } job_t;
168 typedef struct {
169 LPCWSTR envname;
170 LPCWSTR subdir;
171 DWORD driverversion;
172 LPCWSTR versionregpath;
173 LPCWSTR versionsubdir;
174 } printenv_t;
176 /* ############################### */
178 static opened_printer_t **printer_handles;
179 static UINT nb_printer_handles;
180 static LONG next_job_id = 1;
182 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
183 WORD fwCapability, LPSTR lpszOutput,
184 LPDEVMODEA lpdm );
185 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
186 LPSTR lpszDevice, LPSTR lpszPort,
187 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
188 DWORD fwMode );
190 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
191 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
192 'c','o','n','t','r','o','l','\\',
193 'P','r','i','n','t','\\',
194 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
195 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
197 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
198 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
199 'C','o','n','t','r','o','l','\\',
200 'P','r','i','n','t','\\',
201 'P','r','i','n','t','e','r','s',0};
203 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
204 'M','i','c','r','o','s','o','f','t','\\',
205 'W','i','n','d','o','w','s',' ','N','T','\\',
206 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
207 'W','i','n','d','o','w','s',0};
209 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
210 'M','i','c','r','o','s','o','f','t','\\',
211 'W','i','n','d','o','w','s',' ','N','T','\\',
212 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
213 'D','e','v','i','c','e','s',0};
215 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
216 'M','i','c','r','o','s','o','f','t','\\',
217 'W','i','n','d','o','w','s',' ','N','T','\\',
218 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
219 'P','r','i','n','t','e','r','P','o','r','t','s',0};
221 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
222 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
223 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
224 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
225 static const WCHAR subdir_x64W[] = {'x','6','4',0};
226 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
227 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
228 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
229 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
230 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
232 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
233 static const WCHAR backslashW[] = {'\\',0};
234 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
235 'i','o','n',' ','F','i','l','e',0};
236 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
237 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
238 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
239 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
240 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
241 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
242 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
243 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
244 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
245 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
246 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
247 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
248 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
249 static const WCHAR NameW[] = {'N','a','m','e',0};
250 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
251 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
252 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
253 static const WCHAR PortW[] = {'P','o','r','t',0};
254 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
255 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
256 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
257 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
258 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
259 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
260 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
261 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
262 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
263 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
264 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
265 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
266 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
267 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
268 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
269 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
270 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
271 static WCHAR rawW[] = {'R','A','W',0};
272 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
273 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
274 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
275 static const WCHAR commaW[] = {',',0};
276 static WCHAR emptyStringW[] = {0};
278 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
280 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
281 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
282 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
284 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
285 'D','o','c','u','m','e','n','t',0};
287 static const WCHAR PPD_Overrides[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
288 static const WCHAR DefaultPageSize[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
290 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
291 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
292 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
293 0, sizeof(DRIVER_INFO_8W)};
296 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
297 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
298 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
299 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
300 sizeof(PRINTER_INFO_9W)};
302 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
303 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
304 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
306 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
308 /******************************************************************
309 * validate the user-supplied printing-environment [internal]
311 * PARAMS
312 * env [I] PTR to Environment-String or NULL
314 * RETURNS
315 * Failure: NULL
316 * Success: PTR to printenv_t
318 * NOTES
319 * An empty string is handled the same way as NULL.
320 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
324 static const printenv_t * validate_envW(LPCWSTR env)
326 const printenv_t *result = NULL;
327 unsigned int i;
329 TRACE("testing %s\n", debugstr_w(env));
330 if (env && env[0])
332 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
334 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
336 result = all_printenv[i];
337 break;
341 if (result == NULL) {
342 FIXME("unsupported Environment: %s\n", debugstr_w(env));
343 SetLastError(ERROR_INVALID_ENVIRONMENT);
345 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
347 else
349 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
351 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
353 return result;
357 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
358 if passed a NULL string. This returns NULLs to the result.
360 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
362 if ( (src) )
364 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
365 return usBufferPtr->Buffer;
367 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
368 return NULL;
371 static LPWSTR strdupW(LPCWSTR p)
373 LPWSTR ret;
374 DWORD len;
376 if(!p) return NULL;
377 len = (strlenW(p) + 1) * sizeof(WCHAR);
378 ret = HeapAlloc(GetProcessHeap(), 0, len);
379 memcpy(ret, p, len);
380 return ret;
383 static LPSTR strdupWtoA( LPCWSTR str )
385 LPSTR ret;
386 INT len;
388 if (!str) return NULL;
389 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
390 ret = HeapAlloc( GetProcessHeap(), 0, len );
391 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
392 return ret;
395 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
397 DEVMODEW *ret;
399 if (!dm) return NULL;
400 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
401 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
402 return ret;
405 /***********************************************************
406 * DEVMODEdupWtoA
407 * Creates an ansi copy of supplied devmode
409 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
411 LPDEVMODEA dmA;
412 DWORD size;
414 if (!dmW) return NULL;
415 size = dmW->dmSize - CCHDEVICENAME -
416 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
418 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
419 if (!dmA) return NULL;
421 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
422 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
424 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
426 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
427 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
429 else
431 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
432 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
433 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
434 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
436 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
439 dmA->dmSize = size;
440 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
441 return dmA;
445 /******************************************************************
446 * verify, that the filename is a local file
449 static inline BOOL is_local_file(LPWSTR name)
451 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
454 /* ################################ */
456 static int multi_sz_lenA(const char *str)
458 const char *ptr = str;
459 if(!str) return 0;
462 ptr += lstrlenA(ptr) + 1;
463 } while(*ptr);
465 return ptr - str + 1;
468 /*****************************************************************************
469 * get_dword_from_reg
471 * Return DWORD associated with name from hkey.
473 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
475 DWORD sz = sizeof(DWORD), type, value = 0;
476 LONG ret;
478 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
480 if (ret != ERROR_SUCCESS)
482 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
483 return 0;
485 if (type != REG_DWORD)
487 ERR( "Got type %d\n", type );
488 return 0;
490 return value;
493 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
495 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
498 /******************************************************************
499 * get_opened_printer
500 * Get the pointer to the opened printer referred by the handle
502 static opened_printer_t *get_opened_printer(HANDLE hprn)
504 UINT_PTR idx = (UINT_PTR)hprn;
505 opened_printer_t *ret = NULL;
507 EnterCriticalSection(&printer_handles_cs);
509 if ((idx > 0) && (idx <= nb_printer_handles)) {
510 ret = printer_handles[idx - 1];
512 LeaveCriticalSection(&printer_handles_cs);
513 return ret;
516 /******************************************************************
517 * get_opened_printer_name
518 * Get the pointer to the opened printer name referred by the handle
520 static LPCWSTR get_opened_printer_name(HANDLE hprn)
522 opened_printer_t *printer = get_opened_printer(hprn);
523 if(!printer) return NULL;
524 return printer->name;
527 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
529 HKEY printers;
530 DWORD err;
532 *key = NULL;
533 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
534 if (err) return err;
536 err = RegOpenKeyW( printers, name, key );
537 if (err) err = ERROR_INVALID_PRINTER_NAME;
538 RegCloseKey( printers );
539 return err;
542 /******************************************************************
543 * WINSPOOL_GetOpenedPrinterRegKey
546 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
548 LPCWSTR name = get_opened_printer_name(hPrinter);
550 if(!name) return ERROR_INVALID_HANDLE;
551 return open_printer_reg_key( name, phkey );
554 static void
555 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
556 char qbuf[200];
558 /* If forcing, or no profile string entry for device yet, set the entry
560 * The always change entry if not WINEPS yet is discussable.
562 if (force ||
563 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
564 !strcmp(qbuf,"*") ||
565 !strstr(qbuf,"WINEPS.DRV")
567 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
568 HKEY hkey;
570 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
571 WriteProfileStringA("windows","device",buf);
572 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
573 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
574 RegCloseKey(hkey);
576 HeapFree(GetProcessHeap(),0,buf);
580 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
582 DRIVER_INFO_3W di3;
584 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
585 di3.cVersion = 3;
586 di3.pName = (WCHAR*)name;
587 di3.pEnvironment = envname_x86W;
588 di3.pDriverPath = driver_nt;
589 di3.pDataFile = ppd;
590 di3.pConfigFile = driver_nt;
591 di3.pDefaultDataType = rawW;
593 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
594 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
596 di3.cVersion = 0;
597 di3.pEnvironment = envname_win40W;
598 di3.pDriverPath = driver_9x;
599 di3.pConfigFile = driver_9x;
600 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
601 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
603 return TRUE;
606 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
607 return FALSE;
610 static inline char *expand_env_string( char *str, DWORD type )
612 if (type == REG_EXPAND_SZ)
614 char *tmp;
615 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
616 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
617 if (tmp)
619 ExpandEnvironmentStringsA( str, tmp, needed );
620 HeapFree( GetProcessHeap(), 0, str );
621 return tmp;
624 return str;
627 static char *get_fallback_ppd_name( const char *printer_name )
629 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
630 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
631 HKEY hkey;
632 DWORD needed, type;
633 char *ret = NULL;
635 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
637 const char *value_name = NULL;
639 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
640 value_name = printer_name;
641 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
642 value_name = "generic";
644 if (value_name)
646 ret = HeapAlloc( GetProcessHeap(), 0, needed );
647 if (!ret) return NULL;
648 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
650 RegCloseKey( hkey );
651 if (ret) return expand_env_string( ret, type );
653 return NULL;
656 static BOOL copy_file( const char *src, const char *dst )
658 int fds[2] = {-1, -1}, num;
659 char buf[1024];
660 BOOL ret = FALSE;
662 fds[0] = open( src, O_RDONLY );
663 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
664 if (fds[0] == -1 || fds[1] == -1) goto fail;
666 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
668 if (num == -1) goto fail;
669 if (write( fds[1], buf, num ) != num) goto fail;
671 ret = TRUE;
673 fail:
674 if (fds[1] != -1) close( fds[1] );
675 if (fds[0] != -1) close( fds[0] );
676 return ret;
679 static BOOL get_internal_fallback_ppd( const WCHAR *ppd )
681 static const WCHAR typeW[] = {'P','P','D','F','I','L','E',0};
683 char *ptr, *end;
684 DWORD size, written;
685 HANDLE file;
686 BOOL ret;
687 HRSRC res = FindResourceW( WINSPOOL_hInstance, MAKEINTRESOURCEW(1), typeW );
689 if (!res || !(ptr = LoadResource( WINSPOOL_hInstance, res ))) return FALSE;
690 size = SizeofResource( WINSPOOL_hInstance, res );
691 end = memchr( ptr, 0, size ); /* resource file may contain additional nulls */
692 if (end) size = end - ptr;
693 file = CreateFileW( ppd, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
694 if (file == INVALID_HANDLE_VALUE) return FALSE;
695 ret = WriteFile( file, ptr, size, &written, NULL ) && written == size;
696 CloseHandle( file );
697 if (ret) TRACE( "using internal fallback for %s\n", debugstr_w( ppd ));
698 else DeleteFileW( ppd );
699 return ret;
702 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
704 char *dst, *src = get_fallback_ppd_name( printer_name );
705 BOOL ret = FALSE;
707 if (!src) return get_internal_fallback_ppd( ppd );
709 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
711 if (!(dst = wine_get_unix_file_name( ppd ))) goto fail;
713 if (symlink( src, dst ) == -1)
714 if (errno != ENOSYS || !copy_file( src, dst ))
715 goto fail;
717 ret = TRUE;
718 fail:
719 HeapFree( GetProcessHeap(), 0, dst );
720 HeapFree( GetProcessHeap(), 0, src );
721 return ret;
724 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
726 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
727 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
728 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
730 if (!ppd) return NULL;
731 strcpyW( ppd, dir );
732 strcatW( ppd, file_name );
733 strcatW( ppd, dot_ppd );
735 return ppd;
738 static WCHAR *get_ppd_dir( void )
740 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
741 DWORD len;
742 WCHAR *dir, tmp_path[MAX_PATH];
743 BOOL res;
745 len = GetTempPathW( sizeof(tmp_path) / sizeof(tmp_path[0]), tmp_path );
746 if (!len) return NULL;
747 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
748 if (!dir) return NULL;
750 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
751 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
752 res = CreateDirectoryW( dir, NULL );
753 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
755 HeapFree( GetProcessHeap(), 0, dir );
756 dir = NULL;
758 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
759 return dir;
762 static void unlink_ppd( const WCHAR *ppd )
764 char *unix_name = wine_get_unix_file_name( ppd );
765 unlink( unix_name );
766 HeapFree( GetProcessHeap(), 0, unix_name );
769 #ifdef SONAME_LIBCUPS
771 static void *cupshandle;
773 #define CUPS_FUNCS \
774 DO_FUNC(cupsAddOption); \
775 DO_FUNC(cupsFreeDests); \
776 DO_FUNC(cupsFreeOptions); \
777 DO_FUNC(cupsGetDests); \
778 DO_FUNC(cupsGetOption); \
779 DO_FUNC(cupsGetPPD); \
780 DO_FUNC(cupsParseOptions); \
781 DO_FUNC(cupsPrintFile)
782 #define CUPS_OPT_FUNCS \
783 DO_FUNC(cupsGetNamedDest); \
784 DO_FUNC(cupsGetPPD3)
786 #define DO_FUNC(f) static typeof(f) *p##f
787 CUPS_FUNCS;
788 #undef DO_FUNC
789 static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
790 static http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t);
792 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
793 time_t *modtime, char *buffer,
794 size_t bufsize )
796 const char *ppd;
798 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
800 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
802 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
804 *modtime = 0;
805 ppd = pcupsGetPPD( name );
807 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
809 if (!ppd) return HTTP_NOT_FOUND;
811 if (rename( ppd, buffer ) == -1)
813 BOOL res = copy_file( ppd, buffer );
814 unlink( ppd );
815 if (!res) return HTTP_NOT_FOUND;
817 return HTTP_OK;
820 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
822 time_t modtime = 0;
823 http_status_t http_status;
824 char *unix_name = wine_get_unix_file_name( ppd );
826 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
828 if (!unix_name) return FALSE;
830 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
831 unix_name, strlen( unix_name ) + 1 );
833 if (http_status != HTTP_OK) unlink( unix_name );
834 HeapFree( GetProcessHeap(), 0, unix_name );
836 if (http_status == HTTP_OK) return TRUE;
838 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
839 debugstr_a(printer_name), http_status );
840 return get_fallback_ppd( printer_name, ppd );
843 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
845 const char *value;
846 WCHAR *ret;
847 int len;
849 value = pcupsGetOption( name, num_options, options );
850 if (!value) return NULL;
852 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
853 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
854 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
856 return ret;
859 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
861 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
862 cups_ptype_t ret = 0;
864 if (type && *type)
866 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
867 if (*end) ret = 0;
869 HeapFree( GetProcessHeap(), 0, type );
870 return ret;
873 static void load_cups(void)
875 cupshandle = wine_dlopen( SONAME_LIBCUPS, RTLD_NOW, NULL, 0 );
876 if (!cupshandle) return;
878 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
880 #define DO_FUNC(x) \
881 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
882 if (!p##x) \
884 ERR("failed to load symbol %s\n", #x); \
885 cupshandle = NULL; \
886 return; \
888 CUPS_FUNCS;
889 #undef DO_FUNC
890 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
891 CUPS_OPT_FUNCS;
892 #undef DO_FUNC
895 static BOOL CUPS_LoadPrinters(void)
897 int i, nrofdests;
898 BOOL hadprinter = FALSE, haddefault = FALSE;
899 cups_dest_t *dests;
900 PRINTER_INFO_2W pi2;
901 WCHAR *port, *ppd_dir = NULL, *ppd;
902 HKEY hkeyPrinter, hkeyPrinters;
903 WCHAR nameW[MAX_PATH];
904 HANDLE added_printer;
905 cups_ptype_t printer_type;
907 if (!cupshandle) return FALSE;
909 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
910 ERROR_SUCCESS) {
911 ERR("Can't create Printers key\n");
912 return FALSE;
915 nrofdests = pcupsGetDests(&dests);
916 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
917 for (i=0;i<nrofdests;i++) {
918 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
919 printer_type = get_cups_printer_type( dests + i );
921 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
923 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
925 TRACE( "skipping scanner-only device\n" );
926 continue;
929 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
930 lstrcpyW(port, CUPS_Port);
931 lstrcatW(port, nameW);
933 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
934 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
935 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
936 and continue */
937 TRACE("Printer already exists\n");
938 /* overwrite old LPR:* port */
939 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
940 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
941 /* flag that the PPD file should be checked for an update */
942 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
943 RegCloseKey(hkeyPrinter);
944 } else {
945 BOOL added_driver = FALSE;
947 if (!ppd_dir && !(ppd_dir = get_ppd_dir()))
949 HeapFree( GetProcessHeap(), 0, port );
950 break;
952 ppd = get_ppd_filename( ppd_dir, nameW );
953 if (get_cups_ppd( dests[i].name, ppd ))
955 added_driver = add_printer_driver( nameW, ppd );
956 unlink_ppd( ppd );
958 HeapFree( GetProcessHeap(), 0, ppd );
959 if (!added_driver)
961 HeapFree( GetProcessHeap(), 0, port );
962 continue;
965 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
966 pi2.pPrinterName = nameW;
967 pi2.pDatatype = rawW;
968 pi2.pPrintProcessor = WinPrintW;
969 pi2.pDriverName = nameW;
970 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
971 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
972 pi2.pPortName = port;
973 pi2.pParameters = emptyStringW;
974 pi2.pShareName = emptyStringW;
975 pi2.pSepFile = emptyStringW;
977 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
978 if (added_printer) ClosePrinter( added_printer );
979 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
980 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
982 HeapFree( GetProcessHeap(), 0, pi2.pComment );
983 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
985 HeapFree( GetProcessHeap(), 0, port );
987 hadprinter = TRUE;
988 if (dests[i].is_default) {
989 SetDefaultPrinterW(nameW);
990 haddefault = TRUE;
994 if (ppd_dir)
996 RemoveDirectoryW( ppd_dir );
997 HeapFree( GetProcessHeap(), 0, ppd_dir );
1000 if (hadprinter && !haddefault) {
1001 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
1002 SetDefaultPrinterW(nameW);
1004 pcupsFreeDests(nrofdests, dests);
1005 RegCloseKey(hkeyPrinters);
1006 return TRUE;
1009 #endif
1011 static char *get_queue_name( HANDLE printer, BOOL *cups )
1013 WCHAR *port, *name = NULL;
1014 DWORD err, needed, type;
1015 char *ret = NULL;
1016 HKEY key;
1018 *cups = FALSE;
1020 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1021 if (err) return NULL;
1022 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1023 if (err) goto end;
1024 port = HeapAlloc( GetProcessHeap(), 0, needed );
1025 if (!port) goto end;
1026 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1028 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1030 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1031 *cups = TRUE;
1033 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1034 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1035 if (name)
1037 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1038 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1039 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1041 HeapFree( GetProcessHeap(), 0, port );
1042 end:
1043 RegCloseKey( key );
1044 return ret;
1048 static void set_ppd_overrides( HANDLE printer )
1050 WCHAR *wstr = NULL;
1051 int size = 0;
1052 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1053 OSStatus status;
1054 PMPrintSession session = NULL;
1055 PMPageFormat format = NULL;
1056 PMPaper paper;
1057 CFStringRef paper_name;
1058 CFRange range;
1060 status = PMCreateSession( &session );
1061 if (status) goto end;
1063 status = PMCreatePageFormat( &format );
1064 if (status) goto end;
1066 status = PMSessionDefaultPageFormat( session, format );
1067 if (status) goto end;
1069 status = PMGetPageFormatPaper( format, &paper );
1070 if (status) goto end;
1072 status = PMPaperGetPPDPaperName( paper, &paper_name );
1073 if (status) goto end;
1075 range.location = 0;
1076 range.length = CFStringGetLength( paper_name );
1077 size = (range.length + 1) * sizeof(WCHAR);
1079 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1080 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1081 wstr[range.length] = 0;
1083 end:
1084 if (format) PMRelease( format );
1085 if (session) PMRelease( session );
1086 #endif
1088 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1089 HeapFree( GetProcessHeap(), 0, wstr );
1092 static BOOL update_driver( HANDLE printer )
1094 BOOL ret, is_cups;
1095 const WCHAR *name = get_opened_printer_name( printer );
1096 WCHAR *ppd_dir, *ppd;
1097 char *queue_name;
1099 if (!name) return FALSE;
1100 queue_name = get_queue_name( printer, &is_cups );
1101 if (!queue_name) return FALSE;
1103 if (!(ppd_dir = get_ppd_dir()))
1105 HeapFree( GetProcessHeap(), 0, queue_name );
1106 return FALSE;
1108 ppd = get_ppd_filename( ppd_dir, name );
1110 #ifdef SONAME_LIBCUPS
1111 if (is_cups)
1112 ret = get_cups_ppd( queue_name, ppd );
1113 else
1114 #endif
1115 ret = get_fallback_ppd( queue_name, ppd );
1117 if (ret)
1119 TRACE( "updating driver %s\n", debugstr_w( name ) );
1120 ret = add_printer_driver( name, ppd );
1121 unlink_ppd( ppd );
1123 HeapFree( GetProcessHeap(), 0, ppd_dir );
1124 HeapFree( GetProcessHeap(), 0, ppd );
1125 HeapFree( GetProcessHeap(), 0, queue_name );
1127 set_ppd_overrides( printer );
1129 /* call into the driver to update the devmode */
1130 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1132 return ret;
1135 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1137 PRINTER_INFO_2A pinfo2a;
1138 const char *r;
1139 size_t name_len;
1140 char *e,*s,*name,*prettyname,*devname;
1141 BOOL ret = FALSE, set_default = FALSE;
1142 char *port = NULL, *env_default;
1143 HKEY hkeyPrinter, hkeyPrinters = NULL;
1144 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1145 HANDLE added_printer;
1147 while (isspace(*pent)) pent++;
1148 r = strchr(pent,':');
1149 if (r)
1150 name_len = r - pent;
1151 else
1152 name_len = strlen(pent);
1153 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1154 memcpy(name, pent, name_len);
1155 name[name_len] = '\0';
1156 if (r)
1157 pent = r;
1158 else
1159 pent = "";
1161 TRACE("name=%s entry=%s\n",name, pent);
1163 if(ispunct(*name)) { /* a tc entry, not a real printer */
1164 TRACE("skipping tc entry\n");
1165 goto end;
1168 if(strstr(pent,":server")) { /* server only version so skip */
1169 TRACE("skipping server entry\n");
1170 goto end;
1173 /* Determine whether this is a postscript printer. */
1175 ret = TRUE;
1176 env_default = getenv("PRINTER");
1177 prettyname = name;
1178 /* Get longest name, usually the one at the right for later display. */
1179 while((s=strchr(prettyname,'|'))) {
1180 *s = '\0';
1181 e = s;
1182 while(isspace(*--e)) *e = '\0';
1183 TRACE("\t%s\n", debugstr_a(prettyname));
1184 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1185 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1188 e = prettyname + strlen(prettyname);
1189 while(isspace(*--e)) *e = '\0';
1190 TRACE("\t%s\n", debugstr_a(prettyname));
1191 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1193 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1194 * if it is too long, we use it as comment below. */
1195 devname = prettyname;
1196 if (strlen(devname)>=CCHDEVICENAME-1)
1197 devname = name;
1198 if (strlen(devname)>=CCHDEVICENAME-1) {
1199 ret = FALSE;
1200 goto end;
1203 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1204 sprintf(port,"LPR:%s",name);
1206 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1207 ERROR_SUCCESS) {
1208 ERR("Can't create Printers key\n");
1209 ret = FALSE;
1210 goto end;
1213 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1215 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1216 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1217 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1218 and continue */
1219 TRACE("Printer already exists\n");
1220 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1221 /* flag that the PPD file should be checked for an update */
1222 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1223 RegCloseKey(hkeyPrinter);
1224 } else {
1225 static CHAR data_type[] = "RAW",
1226 print_proc[] = "WinPrint",
1227 comment[] = "WINEPS Printer using LPR",
1228 params[] = "<parameters?>",
1229 share_name[] = "<share name?>",
1230 sep_file[] = "<sep file?>";
1231 BOOL added_driver = FALSE;
1233 if (!ppd_dir && !(ppd_dir = get_ppd_dir())) goto end;
1234 ppd = get_ppd_filename( ppd_dir, devnameW );
1235 if (get_fallback_ppd( devname, ppd ))
1237 added_driver = add_printer_driver( devnameW, ppd );
1238 unlink_ppd( ppd );
1240 HeapFree( GetProcessHeap(), 0, ppd );
1241 if (!added_driver) goto end;
1243 memset(&pinfo2a,0,sizeof(pinfo2a));
1244 pinfo2a.pPrinterName = devname;
1245 pinfo2a.pDatatype = data_type;
1246 pinfo2a.pPrintProcessor = print_proc;
1247 pinfo2a.pDriverName = devname;
1248 pinfo2a.pComment = comment;
1249 pinfo2a.pLocation = prettyname;
1250 pinfo2a.pPortName = port;
1251 pinfo2a.pParameters = params;
1252 pinfo2a.pShareName = share_name;
1253 pinfo2a.pSepFile = sep_file;
1255 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1256 if (added_printer) ClosePrinter( added_printer );
1257 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1258 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1261 if (isfirst || set_default)
1262 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1264 end:
1265 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1266 if (ppd_dir)
1268 RemoveDirectoryW( ppd_dir );
1269 HeapFree( GetProcessHeap(), 0, ppd_dir );
1271 HeapFree(GetProcessHeap(), 0, port);
1272 HeapFree(GetProcessHeap(), 0, name);
1273 return ret;
1276 static BOOL
1277 PRINTCAP_LoadPrinters(void) {
1278 BOOL hadprinter = FALSE;
1279 char buf[200];
1280 FILE *f;
1281 char *pent = NULL;
1282 BOOL had_bash = FALSE;
1284 f = fopen("/etc/printcap","r");
1285 if (!f)
1286 return FALSE;
1288 while(fgets(buf,sizeof(buf),f)) {
1289 char *start, *end;
1291 end=strchr(buf,'\n');
1292 if (end) *end='\0';
1294 start = buf;
1295 while(isspace(*start)) start++;
1296 if(*start == '#' || *start == '\0')
1297 continue;
1299 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1300 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1301 HeapFree(GetProcessHeap(),0,pent);
1302 pent = NULL;
1305 if (end && *--end == '\\') {
1306 *end = '\0';
1307 had_bash = TRUE;
1308 } else
1309 had_bash = FALSE;
1311 if (pent) {
1312 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1313 strcat(pent,start);
1314 } else {
1315 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1316 strcpy(pent,start);
1320 if(pent) {
1321 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1322 HeapFree(GetProcessHeap(),0,pent);
1324 fclose(f);
1325 return hadprinter;
1328 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1330 if (value)
1331 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1332 (lstrlenW(value) + 1) * sizeof(WCHAR));
1333 else
1334 return ERROR_FILE_NOT_FOUND;
1337 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1339 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1340 DWORD ret = ERROR_FILE_NOT_FOUND;
1342 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1343 and we support these drivers. NT writes DEVMODEW so somehow
1344 we'll need to distinguish between these when we support NT
1345 drivers */
1347 if (dmA)
1349 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1350 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1351 HeapFree( GetProcessHeap(), 0, dmA );
1354 return ret;
1357 /******************************************************************
1358 * get_servername_from_name (internal)
1360 * for an external server, a copy of the serverpart from the full name is returned
1363 static LPWSTR get_servername_from_name(LPCWSTR name)
1365 LPWSTR server;
1366 LPWSTR ptr;
1367 WCHAR buffer[MAX_PATH];
1368 DWORD len;
1370 if (name == NULL) return NULL;
1371 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1373 server = strdupW(&name[2]); /* skip over both backslash */
1374 if (server == NULL) return NULL;
1376 /* strip '\' and the printername */
1377 ptr = strchrW(server, '\\');
1378 if (ptr) ptr[0] = '\0';
1380 TRACE("found %s\n", debugstr_w(server));
1382 len = sizeof(buffer)/sizeof(buffer[0]);
1383 if (GetComputerNameW(buffer, &len)) {
1384 if (lstrcmpW(buffer, server) == 0) {
1385 /* The requested Servername is our computername */
1386 HeapFree(GetProcessHeap(), 0, server);
1387 return NULL;
1390 return server;
1393 /******************************************************************
1394 * get_basename_from_name (internal)
1396 * skip over the serverpart from the full name
1399 static LPCWSTR get_basename_from_name(LPCWSTR name)
1401 if (name == NULL) return NULL;
1402 if ((name[0] == '\\') && (name[1] == '\\')) {
1403 /* skip over the servername and search for the following '\' */
1404 name = strchrW(&name[2], '\\');
1405 if ((name) && (name[1])) {
1406 /* found a separator ('\') followed by a name:
1407 skip over the separator and return the rest */
1408 name++;
1410 else
1412 /* no basename present (we found only a servername) */
1413 return NULL;
1416 return name;
1419 static void free_printer_entry( opened_printer_t *printer )
1421 /* the queue is shared, so don't free that here */
1422 HeapFree( GetProcessHeap(), 0, printer->printername );
1423 HeapFree( GetProcessHeap(), 0, printer->name );
1424 HeapFree( GetProcessHeap(), 0, printer->devmode );
1425 HeapFree( GetProcessHeap(), 0, printer );
1428 /******************************************************************
1429 * get_opened_printer_entry
1430 * Get the first place empty in the opened printer table
1432 * ToDo:
1433 * - pDefault is ignored
1435 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1437 UINT_PTR handle = nb_printer_handles, i;
1438 jobqueue_t *queue = NULL;
1439 opened_printer_t *printer = NULL;
1440 LPWSTR servername;
1441 LPCWSTR printername;
1443 if ((backend == NULL) && !load_backend()) return NULL;
1445 servername = get_servername_from_name(name);
1446 if (servername) {
1447 FIXME("server %s not supported\n", debugstr_w(servername));
1448 HeapFree(GetProcessHeap(), 0, servername);
1449 SetLastError(ERROR_INVALID_PRINTER_NAME);
1450 return NULL;
1453 printername = get_basename_from_name(name);
1454 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1456 /* an empty printername is invalid */
1457 if (printername && (!printername[0])) {
1458 SetLastError(ERROR_INVALID_PARAMETER);
1459 return NULL;
1462 EnterCriticalSection(&printer_handles_cs);
1464 for (i = 0; i < nb_printer_handles; i++)
1466 if (!printer_handles[i])
1468 if(handle == nb_printer_handles)
1469 handle = i;
1471 else
1473 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1474 queue = printer_handles[i]->queue;
1478 if (handle >= nb_printer_handles)
1480 opened_printer_t **new_array;
1481 if (printer_handles)
1482 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1483 (nb_printer_handles + 16) * sizeof(*new_array) );
1484 else
1485 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1486 (nb_printer_handles + 16) * sizeof(*new_array) );
1488 if (!new_array)
1490 handle = 0;
1491 goto end;
1493 printer_handles = new_array;
1494 nb_printer_handles += 16;
1497 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1499 handle = 0;
1500 goto end;
1503 /* get a printer handle from the backend */
1504 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1505 handle = 0;
1506 goto end;
1509 /* clone the base name. This is NULL for the printserver */
1510 printer->printername = strdupW(printername);
1512 /* clone the full name */
1513 printer->name = strdupW(name);
1514 if (name && (!printer->name)) {
1515 handle = 0;
1516 goto end;
1519 if (pDefault && pDefault->pDevMode)
1520 printer->devmode = dup_devmode( pDefault->pDevMode );
1522 if(queue)
1523 printer->queue = queue;
1524 else
1526 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1527 if (!printer->queue) {
1528 handle = 0;
1529 goto end;
1531 list_init(&printer->queue->jobs);
1532 printer->queue->ref = 0;
1534 InterlockedIncrement(&printer->queue->ref);
1536 printer_handles[handle] = printer;
1537 handle++;
1538 end:
1539 LeaveCriticalSection(&printer_handles_cs);
1540 if (!handle && printer) {
1541 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1542 free_printer_entry( printer );
1545 return (HANDLE)handle;
1548 static void old_printer_check( BOOL delete_phase )
1550 PRINTER_INFO_5W* pi;
1551 DWORD needed, type, num, delete, i, size;
1552 const DWORD one = 1;
1553 HKEY key;
1554 HANDLE hprn;
1556 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1557 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1559 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1560 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1561 for (i = 0; i < num; i++)
1563 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1564 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1565 continue;
1567 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1569 if (!delete_phase)
1571 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1572 RegCloseKey( key );
1574 else
1576 delete = 0;
1577 size = sizeof( delete );
1578 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1579 RegCloseKey( key );
1580 if (delete)
1582 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1583 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1585 DeletePrinter( hprn );
1586 ClosePrinter( hprn );
1588 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1592 HeapFree(GetProcessHeap(), 0, pi);
1595 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1596 'M','U','T','E','X','_','_','\0'};
1597 static HANDLE init_mutex;
1599 void WINSPOOL_LoadSystemPrinters(void)
1601 HKEY hkey, hkeyPrinters;
1602 DWORD needed, num, i;
1603 WCHAR PrinterName[256];
1604 BOOL done = FALSE;
1606 #ifdef SONAME_LIBCUPS
1607 load_cups();
1608 #endif
1610 /* FIXME: The init code should be moved to spoolsv.exe */
1611 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1612 if (!init_mutex)
1614 ERR( "Failed to create mutex\n" );
1615 return;
1617 if (GetLastError() == ERROR_ALREADY_EXISTS)
1619 WaitForSingleObject( init_mutex, INFINITE );
1620 ReleaseMutex( init_mutex );
1621 TRACE( "Init already done\n" );
1622 return;
1625 /* This ensures that all printer entries have a valid Name value. If causes
1626 problems later if they don't. If one is found to be missed we create one
1627 and set it equal to the name of the key */
1628 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1629 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1630 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1631 for(i = 0; i < num; i++) {
1632 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1633 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1634 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1635 set_reg_szW(hkey, NameW, PrinterName);
1637 RegCloseKey(hkey);
1642 RegCloseKey(hkeyPrinters);
1645 old_printer_check( FALSE );
1647 #ifdef SONAME_LIBCUPS
1648 done = CUPS_LoadPrinters();
1649 #endif
1651 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1652 PRINTCAP_LoadPrinters();
1654 old_printer_check( TRUE );
1656 ReleaseMutex( init_mutex );
1657 return;
1660 /******************************************************************
1661 * get_job
1663 * Get the pointer to the specified job.
1664 * Should hold the printer_handles_cs before calling.
1666 static job_t *get_job(HANDLE hprn, DWORD JobId)
1668 opened_printer_t *printer = get_opened_printer(hprn);
1669 job_t *job;
1671 if(!printer) return NULL;
1672 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1674 if(job->job_id == JobId)
1675 return job;
1677 return NULL;
1680 /***********************************************************
1681 * DEVMODEcpyAtoW
1683 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1685 BOOL Formname;
1686 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1687 DWORD size;
1689 Formname = (dmA->dmSize > off_formname);
1690 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1691 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1692 dmW->dmDeviceName, CCHDEVICENAME);
1693 if(!Formname) {
1694 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1695 dmA->dmSize - CCHDEVICENAME);
1696 } else {
1697 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1698 off_formname - CCHDEVICENAME);
1699 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1700 dmW->dmFormName, CCHFORMNAME);
1701 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1702 (off_formname + CCHFORMNAME));
1704 dmW->dmSize = size;
1705 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1706 dmA->dmDriverExtra);
1707 return dmW;
1710 /******************************************************************
1711 * convert_printerinfo_W_to_A [internal]
1714 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1715 DWORD level, DWORD outlen, DWORD numentries)
1717 DWORD id = 0;
1718 LPSTR ptr;
1719 INT len;
1721 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1723 len = pi_sizeof[level] * numentries;
1724 ptr = (LPSTR) out + len;
1725 outlen -= len;
1727 /* copy the numbers of all PRINTER_INFO_* first */
1728 memcpy(out, pPrintersW, len);
1730 while (id < numentries) {
1731 switch (level) {
1732 case 1:
1734 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1735 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1737 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1738 if (piW->pDescription) {
1739 piA->pDescription = ptr;
1740 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1741 ptr, outlen, NULL, NULL);
1742 ptr += len;
1743 outlen -= len;
1745 if (piW->pName) {
1746 piA->pName = ptr;
1747 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1748 ptr, outlen, NULL, NULL);
1749 ptr += len;
1750 outlen -= len;
1752 if (piW->pComment) {
1753 piA->pComment = ptr;
1754 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1755 ptr, outlen, NULL, NULL);
1756 ptr += len;
1757 outlen -= len;
1759 break;
1762 case 2:
1764 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1765 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1766 LPDEVMODEA dmA;
1768 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1769 if (piW->pServerName) {
1770 piA->pServerName = ptr;
1771 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1772 ptr, outlen, NULL, NULL);
1773 ptr += len;
1774 outlen -= len;
1776 if (piW->pPrinterName) {
1777 piA->pPrinterName = ptr;
1778 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1779 ptr, outlen, NULL, NULL);
1780 ptr += len;
1781 outlen -= len;
1783 if (piW->pShareName) {
1784 piA->pShareName = ptr;
1785 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1786 ptr, outlen, NULL, NULL);
1787 ptr += len;
1788 outlen -= len;
1790 if (piW->pPortName) {
1791 piA->pPortName = ptr;
1792 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1793 ptr, outlen, NULL, NULL);
1794 ptr += len;
1795 outlen -= len;
1797 if (piW->pDriverName) {
1798 piA->pDriverName = ptr;
1799 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1800 ptr, outlen, NULL, NULL);
1801 ptr += len;
1802 outlen -= len;
1804 if (piW->pComment) {
1805 piA->pComment = ptr;
1806 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1807 ptr, outlen, NULL, NULL);
1808 ptr += len;
1809 outlen -= len;
1811 if (piW->pLocation) {
1812 piA->pLocation = ptr;
1813 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1814 ptr, outlen, NULL, NULL);
1815 ptr += len;
1816 outlen -= len;
1819 dmA = DEVMODEdupWtoA(piW->pDevMode);
1820 if (dmA) {
1821 /* align DEVMODEA to a DWORD boundary */
1822 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1823 ptr += len;
1824 outlen -= len;
1826 piA->pDevMode = (LPDEVMODEA) ptr;
1827 len = dmA->dmSize + dmA->dmDriverExtra;
1828 memcpy(ptr, dmA, len);
1829 HeapFree(GetProcessHeap(), 0, dmA);
1831 ptr += len;
1832 outlen -= len;
1835 if (piW->pSepFile) {
1836 piA->pSepFile = ptr;
1837 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1838 ptr, outlen, NULL, NULL);
1839 ptr += len;
1840 outlen -= len;
1842 if (piW->pPrintProcessor) {
1843 piA->pPrintProcessor = ptr;
1844 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1845 ptr, outlen, NULL, NULL);
1846 ptr += len;
1847 outlen -= len;
1849 if (piW->pDatatype) {
1850 piA->pDatatype = ptr;
1851 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1852 ptr, outlen, NULL, NULL);
1853 ptr += len;
1854 outlen -= len;
1856 if (piW->pParameters) {
1857 piA->pParameters = ptr;
1858 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1859 ptr, outlen, NULL, NULL);
1860 ptr += len;
1861 outlen -= len;
1863 if (piW->pSecurityDescriptor) {
1864 piA->pSecurityDescriptor = NULL;
1865 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1867 break;
1870 case 4:
1872 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1873 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1875 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1877 if (piW->pPrinterName) {
1878 piA->pPrinterName = ptr;
1879 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1880 ptr, outlen, NULL, NULL);
1881 ptr += len;
1882 outlen -= len;
1884 if (piW->pServerName) {
1885 piA->pServerName = ptr;
1886 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1887 ptr, outlen, NULL, NULL);
1888 ptr += len;
1889 outlen -= len;
1891 break;
1894 case 5:
1896 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1897 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1899 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1901 if (piW->pPrinterName) {
1902 piA->pPrinterName = ptr;
1903 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1904 ptr, outlen, NULL, NULL);
1905 ptr += len;
1906 outlen -= len;
1908 if (piW->pPortName) {
1909 piA->pPortName = ptr;
1910 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1911 ptr, outlen, NULL, NULL);
1912 ptr += len;
1913 outlen -= len;
1915 break;
1918 case 6: /* 6A and 6W are the same structure */
1919 break;
1921 case 7:
1923 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1924 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1926 TRACE("(%u) #%u\n", level, id);
1927 if (piW->pszObjectGUID) {
1928 piA->pszObjectGUID = ptr;
1929 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1930 ptr, outlen, NULL, NULL);
1931 ptr += len;
1932 outlen -= len;
1934 break;
1937 case 8:
1938 case 9:
1940 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1941 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1942 LPDEVMODEA dmA;
1944 TRACE("(%u) #%u\n", level, id);
1945 dmA = DEVMODEdupWtoA(piW->pDevMode);
1946 if (dmA) {
1947 /* align DEVMODEA to a DWORD boundary */
1948 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1949 ptr += len;
1950 outlen -= len;
1952 piA->pDevMode = (LPDEVMODEA) ptr;
1953 len = dmA->dmSize + dmA->dmDriverExtra;
1954 memcpy(ptr, dmA, len);
1955 HeapFree(GetProcessHeap(), 0, dmA);
1957 ptr += len;
1958 outlen -= len;
1961 break;
1964 default:
1965 FIXME("for level %u\n", level);
1967 pPrintersW += pi_sizeof[level];
1968 out += pi_sizeof[level];
1969 id++;
1973 /******************************************************************
1974 * convert_driverinfo_W_to_A [internal]
1977 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1978 DWORD level, DWORD outlen, DWORD numentries)
1980 DWORD id = 0;
1981 LPSTR ptr;
1982 INT len;
1984 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1986 len = di_sizeof[level] * numentries;
1987 ptr = (LPSTR) out + len;
1988 outlen -= len;
1990 /* copy the numbers of all PRINTER_INFO_* first */
1991 memcpy(out, pDriversW, len);
1993 #define COPY_STRING(fld) \
1994 { if (diW->fld){ \
1995 diA->fld = ptr; \
1996 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1997 ptr += len; outlen -= len;\
1999 #define COPY_MULTIZ_STRING(fld) \
2000 { LPWSTR p = diW->fld; if (p){ \
2001 diA->fld = ptr; \
2002 do {\
2003 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2004 ptr += len; outlen -= len; p += len;\
2006 while(len > 1 && outlen > 0); \
2009 while (id < numentries)
2011 switch (level)
2013 case 1:
2015 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2016 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2018 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2020 COPY_STRING(pName);
2021 break;
2023 case 2:
2025 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2026 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2028 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2030 COPY_STRING(pName);
2031 COPY_STRING(pEnvironment);
2032 COPY_STRING(pDriverPath);
2033 COPY_STRING(pDataFile);
2034 COPY_STRING(pConfigFile);
2035 break;
2037 case 3:
2039 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2040 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2042 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2044 COPY_STRING(pName);
2045 COPY_STRING(pEnvironment);
2046 COPY_STRING(pDriverPath);
2047 COPY_STRING(pDataFile);
2048 COPY_STRING(pConfigFile);
2049 COPY_STRING(pHelpFile);
2050 COPY_MULTIZ_STRING(pDependentFiles);
2051 COPY_STRING(pMonitorName);
2052 COPY_STRING(pDefaultDataType);
2053 break;
2055 case 4:
2057 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2058 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2060 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2062 COPY_STRING(pName);
2063 COPY_STRING(pEnvironment);
2064 COPY_STRING(pDriverPath);
2065 COPY_STRING(pDataFile);
2066 COPY_STRING(pConfigFile);
2067 COPY_STRING(pHelpFile);
2068 COPY_MULTIZ_STRING(pDependentFiles);
2069 COPY_STRING(pMonitorName);
2070 COPY_STRING(pDefaultDataType);
2071 COPY_MULTIZ_STRING(pszzPreviousNames);
2072 break;
2074 case 5:
2076 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2077 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2079 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2081 COPY_STRING(pName);
2082 COPY_STRING(pEnvironment);
2083 COPY_STRING(pDriverPath);
2084 COPY_STRING(pDataFile);
2085 COPY_STRING(pConfigFile);
2086 break;
2088 case 6:
2090 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2091 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2093 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2095 COPY_STRING(pName);
2096 COPY_STRING(pEnvironment);
2097 COPY_STRING(pDriverPath);
2098 COPY_STRING(pDataFile);
2099 COPY_STRING(pConfigFile);
2100 COPY_STRING(pHelpFile);
2101 COPY_MULTIZ_STRING(pDependentFiles);
2102 COPY_STRING(pMonitorName);
2103 COPY_STRING(pDefaultDataType);
2104 COPY_MULTIZ_STRING(pszzPreviousNames);
2105 COPY_STRING(pszMfgName);
2106 COPY_STRING(pszOEMUrl);
2107 COPY_STRING(pszHardwareID);
2108 COPY_STRING(pszProvider);
2109 break;
2111 case 8:
2113 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2114 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2116 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2118 COPY_STRING(pName);
2119 COPY_STRING(pEnvironment);
2120 COPY_STRING(pDriverPath);
2121 COPY_STRING(pDataFile);
2122 COPY_STRING(pConfigFile);
2123 COPY_STRING(pHelpFile);
2124 COPY_MULTIZ_STRING(pDependentFiles);
2125 COPY_STRING(pMonitorName);
2126 COPY_STRING(pDefaultDataType);
2127 COPY_MULTIZ_STRING(pszzPreviousNames);
2128 COPY_STRING(pszMfgName);
2129 COPY_STRING(pszOEMUrl);
2130 COPY_STRING(pszHardwareID);
2131 COPY_STRING(pszProvider);
2132 COPY_STRING(pszPrintProcessor);
2133 COPY_STRING(pszVendorSetup);
2134 COPY_MULTIZ_STRING(pszzColorProfiles);
2135 COPY_STRING(pszInfPath);
2136 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2137 break;
2141 default:
2142 FIXME("for level %u\n", level);
2145 pDriversW += di_sizeof[level];
2146 out += di_sizeof[level];
2147 id++;
2150 #undef COPY_STRING
2151 #undef COPY_MULTIZ_STRING
2155 /***********************************************************
2156 * printer_info_AtoW
2158 static void *printer_info_AtoW( const void *data, DWORD level )
2160 void *ret;
2161 UNICODE_STRING usBuffer;
2163 if (!data) return NULL;
2165 if (level < 1 || level > 9) return NULL;
2167 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2168 if (!ret) return NULL;
2170 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2172 switch (level)
2174 case 2:
2176 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2177 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2179 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2180 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2181 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2182 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2183 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2184 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2185 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2186 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2187 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2188 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2189 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2190 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2191 break;
2194 case 8:
2195 case 9:
2197 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2198 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2200 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2201 break;
2204 default:
2205 FIXME( "Unhandled level %d\n", level );
2206 HeapFree( GetProcessHeap(), 0, ret );
2207 return NULL;
2210 return ret;
2213 /***********************************************************
2214 * free_printer_info
2216 static void free_printer_info( void *data, DWORD level )
2218 if (!data) return;
2220 switch (level)
2222 case 2:
2224 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2226 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2227 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2228 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2229 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2230 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2231 HeapFree( GetProcessHeap(), 0, piW->pComment );
2232 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2233 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2234 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2235 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2236 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2237 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2238 break;
2241 case 8:
2242 case 9:
2244 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2246 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2247 break;
2250 default:
2251 FIXME( "Unhandled level %d\n", level );
2254 HeapFree( GetProcessHeap(), 0, data );
2255 return;
2258 /******************************************************************
2259 * DeviceCapabilities [WINSPOOL.@]
2260 * DeviceCapabilitiesA [WINSPOOL.@]
2263 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2264 LPSTR pOutput, LPDEVMODEA lpdm)
2266 INT ret;
2268 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2270 if (!GDI_CallDeviceCapabilities16)
2272 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2273 (LPCSTR)104 );
2274 if (!GDI_CallDeviceCapabilities16) return -1;
2276 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2278 /* If DC_PAPERSIZE map POINT16s to POINTs */
2279 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2280 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2281 POINT *pt = (POINT *)pOutput;
2282 INT i;
2283 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2284 for(i = 0; i < ret; i++, pt++)
2286 pt->x = tmp[i].x;
2287 pt->y = tmp[i].y;
2289 HeapFree( GetProcessHeap(), 0, tmp );
2291 return ret;
2295 /*****************************************************************************
2296 * DeviceCapabilitiesW [WINSPOOL.@]
2298 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2301 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2302 WORD fwCapability, LPWSTR pOutput,
2303 const DEVMODEW *pDevMode)
2305 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2306 LPSTR pDeviceA = strdupWtoA(pDevice);
2307 LPSTR pPortA = strdupWtoA(pPort);
2308 INT ret;
2310 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2312 if(pOutput && (fwCapability == DC_BINNAMES ||
2313 fwCapability == DC_FILEDEPENDENCIES ||
2314 fwCapability == DC_PAPERNAMES)) {
2315 /* These need A -> W translation */
2316 INT size = 0, i;
2317 LPSTR pOutputA;
2318 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2319 dmA);
2320 if(ret == -1)
2321 return ret;
2322 switch(fwCapability) {
2323 case DC_BINNAMES:
2324 size = 24;
2325 break;
2326 case DC_PAPERNAMES:
2327 case DC_FILEDEPENDENCIES:
2328 size = 64;
2329 break;
2331 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2332 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2333 dmA);
2334 for(i = 0; i < ret; i++)
2335 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2336 pOutput + (i * size), size);
2337 HeapFree(GetProcessHeap(), 0, pOutputA);
2338 } else {
2339 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2340 (LPSTR)pOutput, dmA);
2342 HeapFree(GetProcessHeap(),0,pPortA);
2343 HeapFree(GetProcessHeap(),0,pDeviceA);
2344 HeapFree(GetProcessHeap(),0,dmA);
2345 return ret;
2348 /******************************************************************
2349 * DocumentPropertiesA [WINSPOOL.@]
2351 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2353 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2354 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2355 LPDEVMODEA pDevModeInput,DWORD fMode )
2357 LPSTR lpName = pDeviceName, dupname = NULL;
2358 static CHAR port[] = "LPT1:";
2359 LONG ret;
2361 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2362 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2365 if(!pDeviceName || !*pDeviceName) {
2366 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2367 if(!lpNameW) {
2368 ERR("no name from hPrinter?\n");
2369 SetLastError(ERROR_INVALID_HANDLE);
2370 return -1;
2372 lpName = dupname = strdupWtoA(lpNameW);
2375 if (!GDI_CallExtDeviceMode16)
2377 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2378 (LPCSTR)102 );
2379 if (!GDI_CallExtDeviceMode16) {
2380 ERR("No CallExtDeviceMode16?\n");
2381 ret = -1;
2382 goto end;
2385 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2386 pDevModeInput, NULL, fMode);
2388 end:
2389 HeapFree(GetProcessHeap(), 0, dupname);
2390 return ret;
2394 /*****************************************************************************
2395 * DocumentPropertiesW (WINSPOOL.@)
2397 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2399 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2400 LPWSTR pDeviceName,
2401 LPDEVMODEW pDevModeOutput,
2402 LPDEVMODEW pDevModeInput, DWORD fMode)
2405 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2406 LPDEVMODEA pDevModeInputA;
2407 LPDEVMODEA pDevModeOutputA = NULL;
2408 LONG ret;
2410 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2411 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2412 fMode);
2413 if(pDevModeOutput) {
2414 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2415 if(ret < 0) return ret;
2416 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2418 pDevModeInputA = (fMode & DM_IN_BUFFER) ? DEVMODEdupWtoA(pDevModeInput) : NULL;
2419 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2420 pDevModeInputA, fMode);
2421 if(pDevModeOutput) {
2422 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2423 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2425 if(fMode == 0 && ret > 0)
2426 ret += (CCHDEVICENAME + CCHFORMNAME);
2427 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2428 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2429 return ret;
2432 /*****************************************************************************
2433 * IsValidDevmodeA [WINSPOOL.@]
2435 * Validate a DEVMODE structure and fix errors if possible.
2438 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2440 FIXME("(%p,%ld): stub\n", pDevMode, size);
2442 if(!pDevMode)
2443 return FALSE;
2445 return TRUE;
2448 /*****************************************************************************
2449 * IsValidDevmodeW [WINSPOOL.@]
2451 * Validate a DEVMODE structure and fix errors if possible.
2454 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2456 FIXME("(%p,%ld): stub\n", pDevMode, size);
2458 if(!pDevMode)
2459 return FALSE;
2461 return TRUE;
2464 /******************************************************************
2465 * OpenPrinterA [WINSPOOL.@]
2467 * See OpenPrinterW.
2470 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2471 LPPRINTER_DEFAULTSA pDefault)
2473 UNICODE_STRING lpPrinterNameW;
2474 UNICODE_STRING usBuffer;
2475 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2476 PWSTR pwstrPrinterNameW;
2477 BOOL ret;
2479 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2481 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2483 if(pDefault) {
2484 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2485 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2486 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2487 pDefaultW = &DefaultW;
2489 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2490 if(pDefault) {
2491 RtlFreeUnicodeString(&usBuffer);
2492 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2494 RtlFreeUnicodeString(&lpPrinterNameW);
2495 return ret;
2498 /******************************************************************
2499 * OpenPrinterW [WINSPOOL.@]
2501 * Open a Printer / Printserver or a Printer-Object
2503 * PARAMS
2504 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2505 * phPrinter [O] The resulting Handle is stored here
2506 * pDefault [I] PTR to Default Printer Settings or NULL
2508 * RETURNS
2509 * Success: TRUE
2510 * Failure: FALSE
2512 * NOTES
2513 * lpPrinterName is one of:
2514 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2515 *| Printer: "PrinterName"
2516 *| Printer-Object: "PrinterName,Job xxx"
2517 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2518 *| XcvPort: "Servername,XcvPort PortName"
2520 * BUGS
2521 *| Printer-Object not supported
2522 *| pDefaults is ignored
2525 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2527 HKEY key;
2529 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2531 if(!phPrinter) {
2532 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2533 SetLastError(ERROR_INVALID_PARAMETER);
2534 return FALSE;
2537 /* Get the unique handle of the printer or Printserver */
2538 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2540 if (*phPrinter && WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key ) == ERROR_SUCCESS)
2542 DWORD deleting = 0, size = sizeof( deleting ), type;
2543 DWORD status;
2544 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2545 WaitForSingleObject( init_mutex, INFINITE );
2546 status = get_dword_from_reg( key, StatusW );
2547 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2548 ReleaseMutex( init_mutex );
2549 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2550 update_driver( *phPrinter );
2551 RegCloseKey( key );
2554 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2555 return (*phPrinter != 0);
2558 /******************************************************************
2559 * AddMonitorA [WINSPOOL.@]
2561 * See AddMonitorW.
2564 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2566 LPWSTR nameW = NULL;
2567 INT len;
2568 BOOL res;
2569 LPMONITOR_INFO_2A mi2a;
2570 MONITOR_INFO_2W mi2w;
2572 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2573 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2574 debugstr_a(mi2a ? mi2a->pName : NULL),
2575 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2576 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2578 if (Level != 2) {
2579 SetLastError(ERROR_INVALID_LEVEL);
2580 return FALSE;
2583 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2584 if (mi2a == NULL) {
2585 return FALSE;
2588 if (pName) {
2589 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2590 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2591 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2594 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2595 if (mi2a->pName) {
2596 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2597 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2598 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2600 if (mi2a->pEnvironment) {
2601 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2602 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2603 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2605 if (mi2a->pDLLName) {
2606 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2607 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2608 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2611 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2613 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2614 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2615 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2617 HeapFree(GetProcessHeap(), 0, nameW);
2618 return (res);
2621 /******************************************************************************
2622 * AddMonitorW [WINSPOOL.@]
2624 * Install a Printmonitor
2626 * PARAMS
2627 * pName [I] Servername or NULL (local Computer)
2628 * Level [I] Structure-Level (Must be 2)
2629 * pMonitors [I] PTR to MONITOR_INFO_2
2631 * RETURNS
2632 * Success: TRUE
2633 * Failure: FALSE
2635 * NOTES
2636 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2639 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2641 LPMONITOR_INFO_2W mi2w;
2643 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2644 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2645 debugstr_w(mi2w ? mi2w->pName : NULL),
2646 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2647 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2649 if ((backend == NULL) && !load_backend()) return FALSE;
2651 if (Level != 2) {
2652 SetLastError(ERROR_INVALID_LEVEL);
2653 return FALSE;
2656 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2657 if (mi2w == NULL) {
2658 return FALSE;
2661 return backend->fpAddMonitor(pName, Level, pMonitors);
2664 /******************************************************************
2665 * DeletePrinterDriverA [WINSPOOL.@]
2668 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2670 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2673 /******************************************************************
2674 * DeletePrinterDriverW [WINSPOOL.@]
2677 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2679 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2682 /******************************************************************
2683 * DeleteMonitorA [WINSPOOL.@]
2685 * See DeleteMonitorW.
2688 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2690 LPWSTR nameW = NULL;
2691 LPWSTR EnvironmentW = NULL;
2692 LPWSTR MonitorNameW = NULL;
2693 BOOL res;
2694 INT len;
2696 if (pName) {
2697 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2698 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2699 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2702 if (pEnvironment) {
2703 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2704 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2705 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2707 if (pMonitorName) {
2708 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2709 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2710 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2713 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2715 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2716 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2717 HeapFree(GetProcessHeap(), 0, nameW);
2718 return (res);
2721 /******************************************************************
2722 * DeleteMonitorW [WINSPOOL.@]
2724 * Delete a specific Printmonitor from a Printing-Environment
2726 * PARAMS
2727 * pName [I] Servername or NULL (local Computer)
2728 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2729 * pMonitorName [I] Name of the Monitor, that should be deleted
2731 * RETURNS
2732 * Success: TRUE
2733 * Failure: FALSE
2735 * NOTES
2736 * pEnvironment is ignored in Windows for the local Computer.
2739 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2742 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2743 debugstr_w(pMonitorName));
2745 if ((backend == NULL) && !load_backend()) return FALSE;
2747 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2751 /******************************************************************
2752 * DeletePortA [WINSPOOL.@]
2754 * See DeletePortW.
2757 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2759 LPWSTR nameW = NULL;
2760 LPWSTR portW = NULL;
2761 INT len;
2762 DWORD res;
2764 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2766 /* convert servername to unicode */
2767 if (pName) {
2768 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2769 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2770 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2773 /* convert portname to unicode */
2774 if (pPortName) {
2775 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2776 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2777 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2780 res = DeletePortW(nameW, hWnd, portW);
2781 HeapFree(GetProcessHeap(), 0, nameW);
2782 HeapFree(GetProcessHeap(), 0, portW);
2783 return res;
2786 /******************************************************************
2787 * DeletePortW [WINSPOOL.@]
2789 * Delete a specific Port
2791 * PARAMS
2792 * pName [I] Servername or NULL (local Computer)
2793 * hWnd [I] Handle to parent Window for the Dialog-Box
2794 * pPortName [I] Name of the Port, that should be deleted
2796 * RETURNS
2797 * Success: TRUE
2798 * Failure: FALSE
2801 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2803 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2805 if ((backend == NULL) && !load_backend()) return FALSE;
2807 if (!pPortName) {
2808 SetLastError(RPC_X_NULL_REF_POINTER);
2809 return FALSE;
2812 return backend->fpDeletePort(pName, hWnd, pPortName);
2815 /******************************************************************************
2816 * WritePrinter [WINSPOOL.@]
2818 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2820 opened_printer_t *printer;
2821 BOOL ret = FALSE;
2823 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2825 EnterCriticalSection(&printer_handles_cs);
2826 printer = get_opened_printer(hPrinter);
2827 if(!printer)
2829 SetLastError(ERROR_INVALID_HANDLE);
2830 goto end;
2833 if(!printer->doc)
2835 SetLastError(ERROR_SPL_NO_STARTDOC);
2836 goto end;
2839 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2840 end:
2841 LeaveCriticalSection(&printer_handles_cs);
2842 return ret;
2845 /*****************************************************************************
2846 * AddFormA [WINSPOOL.@]
2848 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2850 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2851 return TRUE;
2854 /*****************************************************************************
2855 * AddFormW [WINSPOOL.@]
2857 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2859 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2860 return TRUE;
2863 /*****************************************************************************
2864 * AddJobA [WINSPOOL.@]
2866 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2868 BOOL ret;
2869 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2870 DWORD needed;
2872 if(Level != 1) {
2873 SetLastError(ERROR_INVALID_LEVEL);
2874 return FALSE;
2877 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2879 if(ret) {
2880 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2881 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2882 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2883 if(*pcbNeeded > cbBuf) {
2884 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2885 ret = FALSE;
2886 } else {
2887 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2888 addjobA->JobId = addjobW->JobId;
2889 addjobA->Path = (char *)(addjobA + 1);
2890 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2893 return ret;
2896 /*****************************************************************************
2897 * AddJobW [WINSPOOL.@]
2899 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2901 opened_printer_t *printer;
2902 job_t *job;
2903 BOOL ret = FALSE;
2904 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2905 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2906 WCHAR path[MAX_PATH], filename[MAX_PATH];
2907 DWORD len;
2908 ADDJOB_INFO_1W *addjob;
2910 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2912 EnterCriticalSection(&printer_handles_cs);
2914 printer = get_opened_printer(hPrinter);
2916 if(!printer) {
2917 SetLastError(ERROR_INVALID_HANDLE);
2918 goto end;
2921 if(Level != 1) {
2922 SetLastError(ERROR_INVALID_LEVEL);
2923 goto end;
2926 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2927 if(!job)
2928 goto end;
2930 job->job_id = InterlockedIncrement(&next_job_id);
2932 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2933 if(path[len - 1] != '\\')
2934 path[len++] = '\\';
2935 memcpy(path + len, spool_path, sizeof(spool_path));
2936 sprintfW(filename, fmtW, path, job->job_id);
2938 len = strlenW(filename);
2939 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2940 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2941 job->portname = NULL;
2942 job->document_title = strdupW(default_doc_title);
2943 job->printer_name = strdupW(printer->name);
2944 job->devmode = dup_devmode( printer->devmode );
2945 list_add_tail(&printer->queue->jobs, &job->entry);
2947 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2948 if(*pcbNeeded <= cbBuf) {
2949 addjob = (ADDJOB_INFO_1W*)pData;
2950 addjob->JobId = job->job_id;
2951 addjob->Path = (WCHAR *)(addjob + 1);
2952 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2953 ret = TRUE;
2954 } else
2955 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2957 end:
2958 LeaveCriticalSection(&printer_handles_cs);
2959 return ret;
2962 /*****************************************************************************
2963 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2965 * Return the PATH for the Print-Processors
2967 * See GetPrintProcessorDirectoryW.
2971 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2972 DWORD level, LPBYTE Info,
2973 DWORD cbBuf, LPDWORD pcbNeeded)
2975 LPWSTR serverW = NULL;
2976 LPWSTR envW = NULL;
2977 BOOL ret;
2978 INT len;
2980 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2981 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2984 if (server) {
2985 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2986 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2987 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2990 if (env) {
2991 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2992 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2993 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2996 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2997 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2999 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
3000 cbBuf, pcbNeeded);
3002 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
3003 cbBuf, NULL, NULL) > 0;
3006 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3007 HeapFree(GetProcessHeap(), 0, envW);
3008 HeapFree(GetProcessHeap(), 0, serverW);
3009 return ret;
3012 /*****************************************************************************
3013 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3015 * Return the PATH for the Print-Processors
3017 * PARAMS
3018 * server [I] Servername (NT only) or NULL (local Computer)
3019 * env [I] Printing-Environment (see below) or NULL (Default)
3020 * level [I] Structure-Level (must be 1)
3021 * Info [O] PTR to Buffer that receives the Result
3022 * cbBuf [I] Size of Buffer at "Info"
3023 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3024 * required for the Buffer at "Info"
3026 * RETURNS
3027 * Success: TRUE and in pcbNeeded the Bytes used in Info
3028 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3029 * if cbBuf is too small
3031 * Native Values returned in Info on Success:
3032 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3033 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3034 *| win9x(Windows 4.0): "%winsysdir%"
3036 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3038 * BUGS
3039 * Only NULL or "" is supported for server
3042 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3043 DWORD level, LPBYTE Info,
3044 DWORD cbBuf, LPDWORD pcbNeeded)
3047 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3048 Info, cbBuf, pcbNeeded);
3050 if ((backend == NULL) && !load_backend()) return FALSE;
3052 if (level != 1) {
3053 /* (Level != 1) is ignored in win9x */
3054 SetLastError(ERROR_INVALID_LEVEL);
3055 return FALSE;
3058 if (pcbNeeded == NULL) {
3059 /* (pcbNeeded == NULL) is ignored in win9x */
3060 SetLastError(RPC_X_NULL_REF_POINTER);
3061 return FALSE;
3064 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3067 /*****************************************************************************
3068 * WINSPOOL_OpenDriverReg [internal]
3070 * opens the registry for the printer drivers depending on the given input
3071 * variable pEnvironment
3073 * RETURNS:
3074 * the opened hkey on success
3075 * NULL on error
3077 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3079 HKEY retval = NULL;
3080 LPWSTR buffer;
3081 const printenv_t * env;
3083 TRACE("(%s)\n", debugstr_w(pEnvironment));
3085 env = validate_envW(pEnvironment);
3086 if (!env) return NULL;
3088 buffer = HeapAlloc( GetProcessHeap(), 0,
3089 (strlenW(DriversW) + strlenW(env->envname) +
3090 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3091 if(buffer) {
3092 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3093 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3094 HeapFree(GetProcessHeap(), 0, buffer);
3096 return retval;
3099 /*****************************************************************************
3100 * set_devices_and_printerports [internal]
3102 * set the [Devices] and [PrinterPorts] entries for a printer.
3105 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3107 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3108 WCHAR *devline;
3109 HKEY hkey;
3111 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3113 /* FIXME: the driver must change to "winspool" */
3114 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3115 if (devline) {
3116 lstrcpyW(devline, driver_nt);
3117 lstrcatW(devline, commaW);
3118 lstrcatW(devline, pi->pPortName);
3120 TRACE("using %s\n", debugstr_w(devline));
3121 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3122 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3123 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3124 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3125 RegCloseKey(hkey);
3128 lstrcatW(devline, timeout_15_45);
3129 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3130 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3131 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3132 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3133 RegCloseKey(hkey);
3135 HeapFree(GetProcessHeap(), 0, devline);
3139 /*****************************************************************************
3140 * AddPrinterW [WINSPOOL.@]
3142 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3144 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3145 LPDEVMODEW dm;
3146 HANDLE retval;
3147 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3148 LONG size;
3150 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3152 if(pName && *pName) {
3153 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3154 SetLastError(ERROR_INVALID_PARAMETER);
3155 return 0;
3157 if(Level != 2) {
3158 ERR("Level = %d, unsupported!\n", Level);
3159 SetLastError(ERROR_INVALID_LEVEL);
3160 return 0;
3162 if(!pPrinter) {
3163 SetLastError(ERROR_INVALID_PARAMETER);
3164 return 0;
3166 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3167 ERROR_SUCCESS) {
3168 ERR("Can't create Printers key\n");
3169 return 0;
3171 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3172 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3173 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3174 RegCloseKey(hkeyPrinter);
3175 RegCloseKey(hkeyPrinters);
3176 return 0;
3178 RegCloseKey(hkeyPrinter);
3180 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3181 if(!hkeyDrivers) {
3182 ERR("Can't create Drivers key\n");
3183 RegCloseKey(hkeyPrinters);
3184 return 0;
3186 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3187 ERROR_SUCCESS) {
3188 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3189 RegCloseKey(hkeyPrinters);
3190 RegCloseKey(hkeyDrivers);
3191 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3192 return 0;
3194 RegCloseKey(hkeyDriver);
3195 RegCloseKey(hkeyDrivers);
3197 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3198 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3199 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3200 RegCloseKey(hkeyPrinters);
3201 return 0;
3204 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3205 ERROR_SUCCESS) {
3206 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3207 SetLastError(ERROR_INVALID_PRINTER_NAME);
3208 RegCloseKey(hkeyPrinters);
3209 return 0;
3212 set_devices_and_printerports(pi);
3214 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3215 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3216 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3217 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3218 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3219 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3220 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3221 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3222 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3223 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3224 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3225 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3226 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3227 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3228 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3229 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3230 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3231 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3233 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3235 if (size < 0)
3237 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3238 size = sizeof(DEVMODEW);
3240 if(pi->pDevMode)
3241 dm = pi->pDevMode;
3242 else
3244 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3245 dm->dmSize = size;
3246 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3248 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3249 HeapFree( GetProcessHeap(), 0, dm );
3250 dm = NULL;
3252 else
3254 /* set devmode to printer name */
3255 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3259 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3260 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3262 RegCloseKey(hkeyPrinter);
3263 RegCloseKey(hkeyPrinters);
3264 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3265 ERR("OpenPrinter failing\n");
3266 return 0;
3268 return retval;
3271 /*****************************************************************************
3272 * AddPrinterA [WINSPOOL.@]
3274 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3276 UNICODE_STRING pNameW;
3277 PWSTR pwstrNameW;
3278 PRINTER_INFO_2W *piW;
3279 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3280 HANDLE ret;
3282 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3283 if(Level != 2) {
3284 ERR("Level = %d, unsupported!\n", Level);
3285 SetLastError(ERROR_INVALID_LEVEL);
3286 return 0;
3288 pwstrNameW = asciitounicode(&pNameW,pName);
3289 piW = printer_info_AtoW( piA, Level );
3291 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3293 free_printer_info( piW, Level );
3294 RtlFreeUnicodeString(&pNameW);
3295 return ret;
3299 /*****************************************************************************
3300 * ClosePrinter [WINSPOOL.@]
3302 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3304 UINT_PTR i = (UINT_PTR)hPrinter;
3305 opened_printer_t *printer = NULL;
3306 BOOL ret = FALSE;
3308 TRACE("(%p)\n", hPrinter);
3310 EnterCriticalSection(&printer_handles_cs);
3312 if ((i > 0) && (i <= nb_printer_handles))
3313 printer = printer_handles[i - 1];
3316 if(printer)
3318 struct list *cursor, *cursor2;
3320 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3322 if (printer->backend_printer) {
3323 backend->fpClosePrinter(printer->backend_printer);
3326 if(printer->doc)
3327 EndDocPrinter(hPrinter);
3329 if(InterlockedDecrement(&printer->queue->ref) == 0)
3331 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3333 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3334 ScheduleJob(hPrinter, job->job_id);
3336 HeapFree(GetProcessHeap(), 0, printer->queue);
3339 free_printer_entry( printer );
3340 printer_handles[i - 1] = NULL;
3341 ret = TRUE;
3343 LeaveCriticalSection(&printer_handles_cs);
3344 return ret;
3347 /*****************************************************************************
3348 * DeleteFormA [WINSPOOL.@]
3350 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3352 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3353 return TRUE;
3356 /*****************************************************************************
3357 * DeleteFormW [WINSPOOL.@]
3359 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3361 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3362 return TRUE;
3365 /*****************************************************************************
3366 * DeletePrinter [WINSPOOL.@]
3368 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3370 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3371 HKEY hkeyPrinters, hkey;
3372 WCHAR def[MAX_PATH];
3373 DWORD size = sizeof( def ) / sizeof( def[0] );
3375 if(!lpNameW) {
3376 SetLastError(ERROR_INVALID_HANDLE);
3377 return FALSE;
3379 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3380 RegDeleteTreeW(hkeyPrinters, lpNameW);
3381 RegCloseKey(hkeyPrinters);
3383 WriteProfileStringW(devicesW, lpNameW, NULL);
3384 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3386 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3387 RegDeleteValueW(hkey, lpNameW);
3388 RegCloseKey(hkey);
3391 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3392 RegDeleteValueW(hkey, lpNameW);
3393 RegCloseKey(hkey);
3396 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3398 WriteProfileStringW( windowsW, deviceW, NULL );
3399 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3401 RegDeleteValueW( hkey, deviceW );
3402 RegCloseKey( hkey );
3404 SetDefaultPrinterW( NULL );
3407 return TRUE;
3410 /*****************************************************************************
3411 * SetPrinterA [WINSPOOL.@]
3413 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3415 BYTE *dataW = data;
3416 BOOL ret;
3418 if (level != 0)
3420 dataW = printer_info_AtoW( data, level );
3421 if (!dataW) return FALSE;
3424 ret = SetPrinterW( printer, level, dataW, command );
3426 if (dataW != data) free_printer_info( dataW, level );
3428 return ret;
3431 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3433 set_reg_szW( key, NameW, pi->pPrinterName );
3434 set_reg_szW( key, Share_NameW, pi->pShareName );
3435 set_reg_szW( key, PortW, pi->pPortName );
3436 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3437 set_reg_szW( key, DescriptionW, pi->pComment );
3438 set_reg_szW( key, LocationW, pi->pLocation );
3440 if (pi->pDevMode)
3441 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3443 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3444 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3445 set_reg_szW( key, DatatypeW, pi->pDatatype );
3446 set_reg_szW( key, ParametersW, pi->pParameters );
3448 set_reg_DWORD( key, AttributesW, pi->Attributes );
3449 set_reg_DWORD( key, PriorityW, pi->Priority );
3450 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3451 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3452 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3455 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3457 if (!pi->pDevMode) return FALSE;
3459 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3460 return TRUE;
3463 /******************************************************************************
3464 * SetPrinterW [WINSPOOL.@]
3466 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3468 HKEY key;
3469 BOOL ret = FALSE;
3471 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3473 if (command != 0) FIXME( "Ignoring command %d\n", command );
3475 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3476 return FALSE;
3478 switch (level)
3480 case 2:
3482 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3483 set_printer_2( key, pi2 );
3484 ret = TRUE;
3485 break;
3488 case 9:
3490 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3491 ret = set_printer_9( key, pi );
3492 break;
3495 default:
3496 FIXME( "Unimplemented level %d\n", level );
3497 SetLastError( ERROR_INVALID_LEVEL );
3500 RegCloseKey( key );
3501 return ret;
3504 /*****************************************************************************
3505 * SetJobA [WINSPOOL.@]
3507 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3508 LPBYTE pJob, DWORD Command)
3510 BOOL ret;
3511 LPBYTE JobW;
3512 UNICODE_STRING usBuffer;
3514 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3516 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3517 are all ignored by SetJob, so we don't bother copying them */
3518 switch(Level)
3520 case 0:
3521 JobW = NULL;
3522 break;
3523 case 1:
3525 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3526 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3528 JobW = (LPBYTE)info1W;
3529 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3530 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3531 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3532 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3533 info1W->Status = info1A->Status;
3534 info1W->Priority = info1A->Priority;
3535 info1W->Position = info1A->Position;
3536 info1W->PagesPrinted = info1A->PagesPrinted;
3537 break;
3539 case 2:
3541 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3542 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3544 JobW = (LPBYTE)info2W;
3545 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3546 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3547 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3548 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3549 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3550 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3551 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3552 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3553 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3554 info2W->Status = info2A->Status;
3555 info2W->Priority = info2A->Priority;
3556 info2W->Position = info2A->Position;
3557 info2W->StartTime = info2A->StartTime;
3558 info2W->UntilTime = info2A->UntilTime;
3559 info2W->PagesPrinted = info2A->PagesPrinted;
3560 break;
3562 case 3:
3563 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3564 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3565 break;
3566 default:
3567 SetLastError(ERROR_INVALID_LEVEL);
3568 return FALSE;
3571 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3573 switch(Level)
3575 case 1:
3577 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3578 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3579 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3580 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3581 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3582 break;
3584 case 2:
3586 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3587 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3588 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3589 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3590 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3591 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3592 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3593 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3594 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3595 break;
3598 HeapFree(GetProcessHeap(), 0, JobW);
3600 return ret;
3603 /*****************************************************************************
3604 * SetJobW [WINSPOOL.@]
3606 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3607 LPBYTE pJob, DWORD Command)
3609 BOOL ret = FALSE;
3610 job_t *job;
3612 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3613 FIXME("Ignoring everything other than document title\n");
3615 EnterCriticalSection(&printer_handles_cs);
3616 job = get_job(hPrinter, JobId);
3617 if(!job)
3618 goto end;
3620 switch(Level)
3622 case 0:
3623 break;
3624 case 1:
3626 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3627 HeapFree(GetProcessHeap(), 0, job->document_title);
3628 job->document_title = strdupW(info1->pDocument);
3629 break;
3631 case 2:
3633 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3634 HeapFree(GetProcessHeap(), 0, job->document_title);
3635 job->document_title = strdupW(info2->pDocument);
3636 HeapFree(GetProcessHeap(), 0, job->devmode);
3637 job->devmode = dup_devmode( info2->pDevMode );
3638 break;
3640 case 3:
3641 break;
3642 default:
3643 SetLastError(ERROR_INVALID_LEVEL);
3644 goto end;
3646 ret = TRUE;
3647 end:
3648 LeaveCriticalSection(&printer_handles_cs);
3649 return ret;
3652 /*****************************************************************************
3653 * EndDocPrinter [WINSPOOL.@]
3655 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3657 opened_printer_t *printer;
3658 BOOL ret = FALSE;
3659 TRACE("(%p)\n", hPrinter);
3661 EnterCriticalSection(&printer_handles_cs);
3663 printer = get_opened_printer(hPrinter);
3664 if(!printer)
3666 SetLastError(ERROR_INVALID_HANDLE);
3667 goto end;
3670 if(!printer->doc)
3672 SetLastError(ERROR_SPL_NO_STARTDOC);
3673 goto end;
3676 CloseHandle(printer->doc->hf);
3677 ScheduleJob(hPrinter, printer->doc->job_id);
3678 HeapFree(GetProcessHeap(), 0, printer->doc);
3679 printer->doc = NULL;
3680 ret = TRUE;
3681 end:
3682 LeaveCriticalSection(&printer_handles_cs);
3683 return ret;
3686 /*****************************************************************************
3687 * EndPagePrinter [WINSPOOL.@]
3689 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3691 FIXME("(%p): stub\n", hPrinter);
3692 return TRUE;
3695 /*****************************************************************************
3696 * StartDocPrinterA [WINSPOOL.@]
3698 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3700 UNICODE_STRING usBuffer;
3701 DOC_INFO_2W doc2W;
3702 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3703 DWORD ret;
3705 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3706 or one (DOC_INFO_3) extra DWORDs */
3708 switch(Level) {
3709 case 2:
3710 doc2W.JobId = doc2->JobId;
3711 /* fall through */
3712 case 3:
3713 doc2W.dwMode = doc2->dwMode;
3714 /* fall through */
3715 case 1:
3716 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3717 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3718 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3719 break;
3721 default:
3722 SetLastError(ERROR_INVALID_LEVEL);
3723 return FALSE;
3726 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3728 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3729 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3730 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3732 return ret;
3735 /*****************************************************************************
3736 * StartDocPrinterW [WINSPOOL.@]
3738 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3740 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3741 opened_printer_t *printer;
3742 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3743 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3744 JOB_INFO_1W job_info;
3745 DWORD needed, ret = 0;
3746 HANDLE hf;
3747 WCHAR *filename;
3748 job_t *job;
3750 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3751 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3752 debugstr_w(doc->pDatatype));
3754 if(Level < 1 || Level > 3)
3756 SetLastError(ERROR_INVALID_LEVEL);
3757 return 0;
3760 EnterCriticalSection(&printer_handles_cs);
3761 printer = get_opened_printer(hPrinter);
3762 if(!printer)
3764 SetLastError(ERROR_INVALID_HANDLE);
3765 goto end;
3768 if(printer->doc)
3770 SetLastError(ERROR_INVALID_PRINTER_STATE);
3771 goto end;
3774 /* Even if we're printing to a file we still add a print job, we'll
3775 just ignore the spool file name */
3777 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3779 ERR("AddJob failed gle %u\n", GetLastError());
3780 goto end;
3783 /* use pOutputFile only, when it is a real filename */
3784 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3785 filename = doc->pOutputFile;
3786 else
3787 filename = addjob->Path;
3789 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3790 if(hf == INVALID_HANDLE_VALUE)
3791 goto end;
3793 memset(&job_info, 0, sizeof(job_info));
3794 job_info.pDocument = doc->pDocName;
3795 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3797 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3798 printer->doc->hf = hf;
3799 ret = printer->doc->job_id = addjob->JobId;
3800 job = get_job(hPrinter, ret);
3801 job->portname = strdupW(doc->pOutputFile);
3803 end:
3804 LeaveCriticalSection(&printer_handles_cs);
3806 return ret;
3809 /*****************************************************************************
3810 * StartPagePrinter [WINSPOOL.@]
3812 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3814 FIXME("(%p): stub\n", hPrinter);
3815 return TRUE;
3818 /*****************************************************************************
3819 * GetFormA [WINSPOOL.@]
3821 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3822 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3824 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3825 Level,pForm,cbBuf,pcbNeeded);
3826 return FALSE;
3829 /*****************************************************************************
3830 * GetFormW [WINSPOOL.@]
3832 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3833 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3835 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3836 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3837 return FALSE;
3840 /*****************************************************************************
3841 * SetFormA [WINSPOOL.@]
3843 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3844 LPBYTE pForm)
3846 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3847 return FALSE;
3850 /*****************************************************************************
3851 * SetFormW [WINSPOOL.@]
3853 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3854 LPBYTE pForm)
3856 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3857 return FALSE;
3860 /*****************************************************************************
3861 * ReadPrinter [WINSPOOL.@]
3863 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3864 LPDWORD pNoBytesRead)
3866 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3867 return FALSE;
3870 /*****************************************************************************
3871 * ResetPrinterA [WINSPOOL.@]
3873 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3875 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3876 return FALSE;
3879 /*****************************************************************************
3880 * ResetPrinterW [WINSPOOL.@]
3882 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3884 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3885 return FALSE;
3888 /*****************************************************************************
3889 * get_filename_from_reg [internal]
3891 * Get ValueName from hkey storing result in out
3892 * when the Value in the registry has only a filename, use driverdir as prefix
3893 * outlen is space left in out
3894 * String is stored either as unicode or ascii
3898 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3899 LPBYTE out, DWORD outlen, LPDWORD needed)
3901 WCHAR filename[MAX_PATH];
3902 DWORD size;
3903 DWORD type;
3904 LONG ret;
3905 LPWSTR buffer = filename;
3906 LPWSTR ptr;
3908 *needed = 0;
3909 size = sizeof(filename);
3910 buffer[0] = '\0';
3911 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3912 if (ret == ERROR_MORE_DATA) {
3913 TRACE("need dynamic buffer: %u\n", size);
3914 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3915 if (!buffer) {
3916 /* No Memory is bad */
3917 return FALSE;
3919 buffer[0] = '\0';
3920 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3923 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3924 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3925 return FALSE;
3928 ptr = buffer;
3929 while (ptr) {
3930 /* do we have a full path ? */
3931 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3932 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3934 if (!ret) {
3935 /* we must build the full Path */
3936 *needed += dirlen;
3937 if ((out) && (outlen > dirlen)) {
3938 lstrcpyW((LPWSTR)out, driverdir);
3939 out += dirlen;
3940 outlen -= dirlen;
3942 else
3943 out = NULL;
3946 /* write the filename */
3947 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3948 if ((out) && (outlen >= size)) {
3949 lstrcpyW((LPWSTR)out, ptr);
3950 out += size;
3951 outlen -= size;
3953 else
3954 out = NULL;
3955 *needed += size;
3956 ptr += lstrlenW(ptr)+1;
3957 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3960 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3962 /* write the multisz-termination */
3963 if (type == REG_MULTI_SZ) {
3964 size = sizeof(WCHAR);
3966 *needed += size;
3967 if (out && (outlen >= size)) {
3968 memset (out, 0, size);
3971 return TRUE;
3974 /*****************************************************************************
3975 * WINSPOOL_GetStringFromReg
3977 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3978 * String is stored as unicode.
3980 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3981 DWORD buflen, DWORD *needed)
3983 DWORD sz = buflen, type;
3984 LONG ret;
3986 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3987 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3988 WARN("Got ret = %d\n", ret);
3989 *needed = 0;
3990 return FALSE;
3992 /* add space for terminating '\0' */
3993 sz += sizeof(WCHAR);
3994 *needed = sz;
3996 if (ptr)
3997 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3999 return TRUE;
4002 /*****************************************************************************
4003 * WINSPOOL_GetDefaultDevMode
4005 * Get a default DevMode values for wineps.
4007 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4009 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4011 if (buflen >= sizeof(DEVMODEW))
4013 DEVMODEW *dm = (DEVMODEW *)ptr;
4015 /* the driver will update registry with real values */
4016 memset(dm, 0, sizeof(*dm));
4017 dm->dmSize = sizeof(*dm);
4018 lstrcpyW(dm->dmDeviceName, winepsW);
4020 *needed = sizeof(DEVMODEW);
4023 /*****************************************************************************
4024 * WINSPOOL_GetDevModeFromReg
4026 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4027 * DevMode is stored either as unicode or ascii.
4029 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4030 LPBYTE ptr,
4031 DWORD buflen, DWORD *needed)
4033 DWORD sz = buflen, type;
4034 LONG ret;
4036 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4037 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4038 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4039 if (sz < sizeof(DEVMODEA))
4041 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4042 return FALSE;
4044 /* ensures that dmSize is not erratically bogus if registry is invalid */
4045 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4046 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4047 sz += (CCHDEVICENAME + CCHFORMNAME);
4048 if (ptr && (buflen >= sz)) {
4049 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4050 memcpy(ptr, dmW, sz);
4051 HeapFree(GetProcessHeap(),0,dmW);
4053 *needed = sz;
4054 return TRUE;
4057 /*********************************************************************
4058 * WINSPOOL_GetPrinter_1
4060 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4062 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4063 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4065 DWORD size, left = cbBuf;
4066 BOOL space = (cbBuf > 0);
4067 LPBYTE ptr = buf;
4069 *pcbNeeded = 0;
4071 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4072 if(space && size <= left) {
4073 pi1->pName = (LPWSTR)ptr;
4074 ptr += size;
4075 left -= size;
4076 } else
4077 space = FALSE;
4078 *pcbNeeded += size;
4081 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4082 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4083 if(space && size <= left) {
4084 pi1->pDescription = (LPWSTR)ptr;
4085 ptr += size;
4086 left -= size;
4087 } else
4088 space = FALSE;
4089 *pcbNeeded += size;
4092 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4093 if(space && size <= left) {
4094 pi1->pComment = (LPWSTR)ptr;
4095 ptr += size;
4096 left -= size;
4097 } else
4098 space = FALSE;
4099 *pcbNeeded += size;
4102 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4104 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4105 memset(pi1, 0, sizeof(*pi1));
4107 return space;
4109 /*********************************************************************
4110 * WINSPOOL_GetPrinter_2
4112 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4114 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4115 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4117 DWORD size, left = cbBuf;
4118 BOOL space = (cbBuf > 0);
4119 LPBYTE ptr = buf;
4121 *pcbNeeded = 0;
4123 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4124 if(space && size <= left) {
4125 pi2->pPrinterName = (LPWSTR)ptr;
4126 ptr += size;
4127 left -= size;
4128 } else
4129 space = FALSE;
4130 *pcbNeeded += size;
4132 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4133 if(space && size <= left) {
4134 pi2->pShareName = (LPWSTR)ptr;
4135 ptr += size;
4136 left -= size;
4137 } else
4138 space = FALSE;
4139 *pcbNeeded += size;
4141 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4142 if(space && size <= left) {
4143 pi2->pPortName = (LPWSTR)ptr;
4144 ptr += size;
4145 left -= size;
4146 } else
4147 space = FALSE;
4148 *pcbNeeded += size;
4150 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4151 if(space && size <= left) {
4152 pi2->pDriverName = (LPWSTR)ptr;
4153 ptr += size;
4154 left -= size;
4155 } else
4156 space = FALSE;
4157 *pcbNeeded += size;
4159 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4160 if(space && size <= left) {
4161 pi2->pComment = (LPWSTR)ptr;
4162 ptr += size;
4163 left -= size;
4164 } else
4165 space = FALSE;
4166 *pcbNeeded += size;
4168 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4169 if(space && size <= left) {
4170 pi2->pLocation = (LPWSTR)ptr;
4171 ptr += size;
4172 left -= size;
4173 } else
4174 space = FALSE;
4175 *pcbNeeded += size;
4177 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4178 if(space && size <= left) {
4179 pi2->pDevMode = (LPDEVMODEW)ptr;
4180 ptr += size;
4181 left -= size;
4182 } else
4183 space = FALSE;
4184 *pcbNeeded += size;
4186 else
4188 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4189 if(space && size <= left) {
4190 pi2->pDevMode = (LPDEVMODEW)ptr;
4191 ptr += size;
4192 left -= size;
4193 } else
4194 space = FALSE;
4195 *pcbNeeded += size;
4197 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4198 if(space && size <= left) {
4199 pi2->pSepFile = (LPWSTR)ptr;
4200 ptr += size;
4201 left -= size;
4202 } else
4203 space = FALSE;
4204 *pcbNeeded += size;
4206 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4207 if(space && size <= left) {
4208 pi2->pPrintProcessor = (LPWSTR)ptr;
4209 ptr += size;
4210 left -= size;
4211 } else
4212 space = FALSE;
4213 *pcbNeeded += size;
4215 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4216 if(space && size <= left) {
4217 pi2->pDatatype = (LPWSTR)ptr;
4218 ptr += size;
4219 left -= size;
4220 } else
4221 space = FALSE;
4222 *pcbNeeded += size;
4224 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4225 if(space && size <= left) {
4226 pi2->pParameters = (LPWSTR)ptr;
4227 ptr += size;
4228 left -= size;
4229 } else
4230 space = FALSE;
4231 *pcbNeeded += size;
4233 if(pi2) {
4234 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4235 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4236 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4237 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4238 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4241 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4242 memset(pi2, 0, sizeof(*pi2));
4244 return space;
4247 /*********************************************************************
4248 * WINSPOOL_GetPrinter_4
4250 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4252 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4253 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4255 DWORD size, left = cbBuf;
4256 BOOL space = (cbBuf > 0);
4257 LPBYTE ptr = buf;
4259 *pcbNeeded = 0;
4261 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4262 if(space && size <= left) {
4263 pi4->pPrinterName = (LPWSTR)ptr;
4264 ptr += size;
4265 left -= size;
4266 } else
4267 space = FALSE;
4268 *pcbNeeded += size;
4270 if(pi4) {
4271 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4274 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4275 memset(pi4, 0, sizeof(*pi4));
4277 return space;
4280 /*********************************************************************
4281 * WINSPOOL_GetPrinter_5
4283 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4285 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4286 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4288 DWORD size, left = cbBuf;
4289 BOOL space = (cbBuf > 0);
4290 LPBYTE ptr = buf;
4292 *pcbNeeded = 0;
4294 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4295 if(space && size <= left) {
4296 pi5->pPrinterName = (LPWSTR)ptr;
4297 ptr += size;
4298 left -= size;
4299 } else
4300 space = FALSE;
4301 *pcbNeeded += size;
4303 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4304 if(space && size <= left) {
4305 pi5->pPortName = (LPWSTR)ptr;
4306 ptr += size;
4307 left -= size;
4308 } else
4309 space = FALSE;
4310 *pcbNeeded += size;
4312 if(pi5) {
4313 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4314 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4315 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4318 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4319 memset(pi5, 0, sizeof(*pi5));
4321 return space;
4324 /*********************************************************************
4325 * WINSPOOL_GetPrinter_7
4327 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4329 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4330 DWORD cbBuf, LPDWORD pcbNeeded)
4332 DWORD size, left = cbBuf;
4333 BOOL space = (cbBuf > 0);
4334 LPBYTE ptr = buf;
4336 *pcbNeeded = 0;
4338 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4340 ptr = NULL;
4341 size = sizeof(pi7->pszObjectGUID);
4343 if (space && size <= left) {
4344 pi7->pszObjectGUID = (LPWSTR)ptr;
4345 ptr += size;
4346 left -= size;
4347 } else
4348 space = FALSE;
4349 *pcbNeeded += size;
4350 if (pi7) {
4351 /* We do not have a Directory Service */
4352 pi7->dwAction = DSPRINT_UNPUBLISH;
4355 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4356 memset(pi7, 0, sizeof(*pi7));
4358 return space;
4361 /*********************************************************************
4362 * WINSPOOL_GetPrinter_9
4364 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4366 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4367 DWORD cbBuf, LPDWORD pcbNeeded)
4369 DWORD size;
4370 BOOL space = (cbBuf > 0);
4372 *pcbNeeded = 0;
4374 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4375 if(space && size <= cbBuf) {
4376 pi9->pDevMode = (LPDEVMODEW)buf;
4377 } else
4378 space = FALSE;
4379 *pcbNeeded += size;
4381 else
4383 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4384 if(space && size <= cbBuf) {
4385 pi9->pDevMode = (LPDEVMODEW)buf;
4386 } else
4387 space = FALSE;
4388 *pcbNeeded += size;
4391 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4392 memset(pi9, 0, sizeof(*pi9));
4394 return space;
4397 /*****************************************************************************
4398 * GetPrinterW [WINSPOOL.@]
4400 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4401 DWORD cbBuf, LPDWORD pcbNeeded)
4403 DWORD size, needed = 0, err;
4404 LPBYTE ptr = NULL;
4405 HKEY hkeyPrinter;
4406 BOOL ret;
4408 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4410 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4411 if (err)
4413 SetLastError( err );
4414 return FALSE;
4417 switch(Level) {
4418 case 2:
4420 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4422 size = sizeof(PRINTER_INFO_2W);
4423 if(size <= cbBuf) {
4424 ptr = pPrinter + size;
4425 cbBuf -= size;
4426 memset(pPrinter, 0, size);
4427 } else {
4428 pi2 = NULL;
4429 cbBuf = 0;
4431 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4432 needed += size;
4433 break;
4436 case 4:
4438 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4440 size = sizeof(PRINTER_INFO_4W);
4441 if(size <= cbBuf) {
4442 ptr = pPrinter + size;
4443 cbBuf -= size;
4444 memset(pPrinter, 0, size);
4445 } else {
4446 pi4 = NULL;
4447 cbBuf = 0;
4449 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4450 needed += size;
4451 break;
4455 case 5:
4457 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4459 size = sizeof(PRINTER_INFO_5W);
4460 if(size <= cbBuf) {
4461 ptr = pPrinter + size;
4462 cbBuf -= size;
4463 memset(pPrinter, 0, size);
4464 } else {
4465 pi5 = NULL;
4466 cbBuf = 0;
4469 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4470 needed += size;
4471 break;
4475 case 6:
4477 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4479 size = sizeof(PRINTER_INFO_6);
4480 if (size <= cbBuf) {
4481 /* FIXME: We do not update the status yet */
4482 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4483 ret = TRUE;
4484 } else {
4485 ret = FALSE;
4488 needed += size;
4489 break;
4492 case 7:
4494 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4496 size = sizeof(PRINTER_INFO_7W);
4497 if (size <= cbBuf) {
4498 ptr = pPrinter + size;
4499 cbBuf -= size;
4500 memset(pPrinter, 0, size);
4501 } else {
4502 pi7 = NULL;
4503 cbBuf = 0;
4506 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4507 needed += size;
4508 break;
4512 case 8:
4513 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4514 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4515 /* fall through */
4516 case 9:
4518 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4520 size = sizeof(PRINTER_INFO_9W);
4521 if(size <= cbBuf) {
4522 ptr = pPrinter + size;
4523 cbBuf -= size;
4524 memset(pPrinter, 0, size);
4525 } else {
4526 pi9 = NULL;
4527 cbBuf = 0;
4530 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4531 needed += size;
4532 break;
4536 default:
4537 FIXME("Unimplemented level %d\n", Level);
4538 SetLastError(ERROR_INVALID_LEVEL);
4539 RegCloseKey(hkeyPrinter);
4540 return FALSE;
4543 RegCloseKey(hkeyPrinter);
4545 TRACE("returning %d needed = %d\n", ret, needed);
4546 if(pcbNeeded) *pcbNeeded = needed;
4547 if(!ret)
4548 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4549 return ret;
4552 /*****************************************************************************
4553 * GetPrinterA [WINSPOOL.@]
4555 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4556 DWORD cbBuf, LPDWORD pcbNeeded)
4558 BOOL ret;
4559 LPBYTE buf = NULL;
4561 if (cbBuf)
4562 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4564 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4565 if (ret)
4566 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4567 HeapFree(GetProcessHeap(), 0, buf);
4569 return ret;
4572 /*****************************************************************************
4573 * WINSPOOL_EnumPrintersW
4575 * Implementation of EnumPrintersW
4577 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4578 DWORD dwLevel, LPBYTE lpbPrinters,
4579 DWORD cbBuf, LPDWORD lpdwNeeded,
4580 LPDWORD lpdwReturned)
4583 HKEY hkeyPrinters, hkeyPrinter;
4584 WCHAR PrinterName[255];
4585 DWORD needed = 0, number = 0;
4586 DWORD used, i, left;
4587 PBYTE pi, buf;
4589 if(lpbPrinters)
4590 memset(lpbPrinters, 0, cbBuf);
4591 if(lpdwReturned)
4592 *lpdwReturned = 0;
4593 if(lpdwNeeded)
4594 *lpdwNeeded = 0;
4596 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4597 if(dwType == PRINTER_ENUM_DEFAULT)
4598 return TRUE;
4600 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4601 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4602 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4603 if (!dwType) {
4604 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4605 return TRUE;
4610 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4611 FIXME("dwType = %08x\n", dwType);
4612 SetLastError(ERROR_INVALID_FLAGS);
4613 return FALSE;
4616 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4617 ERROR_SUCCESS) {
4618 ERR("Can't create Printers key\n");
4619 return FALSE;
4622 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4623 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4624 RegCloseKey(hkeyPrinters);
4625 ERR("Can't query Printers key\n");
4626 return FALSE;
4628 TRACE("Found %d printers\n", number);
4630 switch(dwLevel) {
4631 case 1:
4632 used = number * sizeof(PRINTER_INFO_1W);
4633 break;
4634 case 2:
4635 used = number * sizeof(PRINTER_INFO_2W);
4636 break;
4637 case 4:
4638 used = number * sizeof(PRINTER_INFO_4W);
4639 break;
4640 case 5:
4641 used = number * sizeof(PRINTER_INFO_5W);
4642 break;
4644 default:
4645 SetLastError(ERROR_INVALID_LEVEL);
4646 RegCloseKey(hkeyPrinters);
4647 return FALSE;
4649 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4651 for(i = 0; i < number; i++) {
4652 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4653 ERROR_SUCCESS) {
4654 ERR("Can't enum key number %d\n", i);
4655 RegCloseKey(hkeyPrinters);
4656 return FALSE;
4658 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4659 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4660 ERROR_SUCCESS) {
4661 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4662 RegCloseKey(hkeyPrinters);
4663 return FALSE;
4666 if(cbBuf > used) {
4667 buf = lpbPrinters + used;
4668 left = cbBuf - used;
4669 } else {
4670 buf = NULL;
4671 left = 0;
4674 switch(dwLevel) {
4675 case 1:
4676 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4677 left, &needed);
4678 used += needed;
4679 if(pi) pi += sizeof(PRINTER_INFO_1W);
4680 break;
4681 case 2:
4682 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4683 left, &needed);
4684 used += needed;
4685 if(pi) pi += sizeof(PRINTER_INFO_2W);
4686 break;
4687 case 4:
4688 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4689 left, &needed);
4690 used += needed;
4691 if(pi) pi += sizeof(PRINTER_INFO_4W);
4692 break;
4693 case 5:
4694 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4695 left, &needed);
4696 used += needed;
4697 if(pi) pi += sizeof(PRINTER_INFO_5W);
4698 break;
4699 default:
4700 ERR("Shouldn't be here!\n");
4701 RegCloseKey(hkeyPrinter);
4702 RegCloseKey(hkeyPrinters);
4703 return FALSE;
4705 RegCloseKey(hkeyPrinter);
4707 RegCloseKey(hkeyPrinters);
4709 if(lpdwNeeded)
4710 *lpdwNeeded = used;
4712 if(used > cbBuf) {
4713 if(lpbPrinters)
4714 memset(lpbPrinters, 0, cbBuf);
4715 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4716 return FALSE;
4718 if(lpdwReturned)
4719 *lpdwReturned = number;
4720 SetLastError(ERROR_SUCCESS);
4721 return TRUE;
4725 /******************************************************************
4726 * EnumPrintersW [WINSPOOL.@]
4728 * Enumerates the available printers, print servers and print
4729 * providers, depending on the specified flags, name and level.
4731 * RETURNS:
4733 * If level is set to 1:
4734 * Returns an array of PRINTER_INFO_1 data structures in the
4735 * lpbPrinters buffer.
4737 * If level is set to 2:
4738 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4739 * Returns an array of PRINTER_INFO_2 data structures in the
4740 * lpbPrinters buffer. Note that according to MSDN also an
4741 * OpenPrinter should be performed on every remote printer.
4743 * If level is set to 4 (officially WinNT only):
4744 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4745 * Fast: Only the registry is queried to retrieve printer names,
4746 * no connection to the driver is made.
4747 * Returns an array of PRINTER_INFO_4 data structures in the
4748 * lpbPrinters buffer.
4750 * If level is set to 5 (officially WinNT4/Win9x only):
4751 * Fast: Only the registry is queried to retrieve printer names,
4752 * no connection to the driver is made.
4753 * Returns an array of PRINTER_INFO_5 data structures in the
4754 * lpbPrinters buffer.
4756 * If level set to 3 or 6+:
4757 * returns zero (failure!)
4759 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4760 * for information.
4762 * BUGS:
4763 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4764 * - Only levels 2, 4 and 5 are implemented at the moment.
4765 * - 16-bit printer drivers are not enumerated.
4766 * - Returned amount of bytes used/needed does not match the real Windoze
4767 * implementation (as in this implementation, all strings are part
4768 * of the buffer, whereas Win32 keeps them somewhere else)
4769 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4771 * NOTE:
4772 * - In a regular Wine installation, no registry settings for printers
4773 * exist, which makes this function return an empty list.
4775 BOOL WINAPI EnumPrintersW(
4776 DWORD dwType, /* [in] Types of print objects to enumerate */
4777 LPWSTR lpszName, /* [in] name of objects to enumerate */
4778 DWORD dwLevel, /* [in] type of printer info structure */
4779 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4780 DWORD cbBuf, /* [in] max size of buffer in bytes */
4781 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4782 LPDWORD lpdwReturned /* [out] number of entries returned */
4785 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4786 lpdwNeeded, lpdwReturned);
4789 /******************************************************************
4790 * EnumPrintersA [WINSPOOL.@]
4792 * See EnumPrintersW
4795 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4796 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4798 BOOL ret;
4799 UNICODE_STRING pNameU;
4800 LPWSTR pNameW;
4801 LPBYTE pPrintersW;
4803 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4804 pPrinters, cbBuf, pcbNeeded, pcReturned);
4806 pNameW = asciitounicode(&pNameU, pName);
4808 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4809 MS Office need this */
4810 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4812 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4814 RtlFreeUnicodeString(&pNameU);
4815 if (ret) {
4816 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4818 HeapFree(GetProcessHeap(), 0, pPrintersW);
4819 return ret;
4822 /*****************************************************************************
4823 * WINSPOOL_GetDriverInfoFromReg [internal]
4825 * Enters the information from the registry into the DRIVER_INFO struct
4827 * RETURNS
4828 * zero if the printer driver does not exist in the registry
4829 * (only if Level > 1) otherwise nonzero
4831 static BOOL WINSPOOL_GetDriverInfoFromReg(
4832 HKEY hkeyDrivers,
4833 LPWSTR DriverName,
4834 const printenv_t * env,
4835 DWORD Level,
4836 LPBYTE ptr, /* DRIVER_INFO */
4837 LPBYTE pDriverStrings, /* strings buffer */
4838 DWORD cbBuf, /* size of string buffer */
4839 LPDWORD pcbNeeded) /* space needed for str. */
4841 DWORD size, tmp;
4842 HKEY hkeyDriver;
4843 WCHAR driverdir[MAX_PATH];
4844 DWORD dirlen;
4845 LPBYTE strPtr = pDriverStrings;
4846 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4848 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4849 debugstr_w(DriverName), env,
4850 Level, di, pDriverStrings, cbBuf);
4852 if (di) ZeroMemory(di, di_sizeof[Level]);
4854 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4855 if (*pcbNeeded <= cbBuf)
4856 strcpyW((LPWSTR)strPtr, DriverName);
4858 /* pName for level 1 has a different offset! */
4859 if (Level == 1) {
4860 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4861 return TRUE;
4864 /* .cVersion and .pName for level > 1 */
4865 if (di) {
4866 di->cVersion = env->driverversion;
4867 di->pName = (LPWSTR) strPtr;
4868 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4871 /* Reserve Space for the largest subdir and a Backslash*/
4872 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4873 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4874 /* Should never Fail */
4875 return FALSE;
4877 lstrcatW(driverdir, env->versionsubdir);
4878 lstrcatW(driverdir, backslashW);
4880 /* dirlen must not include the terminating zero */
4881 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4883 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4884 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4885 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4886 return FALSE;
4889 /* pEnvironment */
4890 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4892 *pcbNeeded += size;
4893 if (*pcbNeeded <= cbBuf) {
4894 lstrcpyW((LPWSTR)strPtr, env->envname);
4895 if (di) di->pEnvironment = (LPWSTR)strPtr;
4896 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4899 /* .pDriverPath is the Graphics rendering engine.
4900 The full Path is required to avoid a crash in some apps */
4901 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4902 *pcbNeeded += size;
4903 if (*pcbNeeded <= cbBuf)
4904 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4906 if (di) di->pDriverPath = (LPWSTR)strPtr;
4907 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4910 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4911 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4912 *pcbNeeded += size;
4913 if (*pcbNeeded <= cbBuf)
4914 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4916 if (di) di->pDataFile = (LPWSTR)strPtr;
4917 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4920 /* .pConfigFile is the Driver user Interface */
4921 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4922 *pcbNeeded += size;
4923 if (*pcbNeeded <= cbBuf)
4924 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4926 if (di) di->pConfigFile = (LPWSTR)strPtr;
4927 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4930 if (Level == 2 ) {
4931 RegCloseKey(hkeyDriver);
4932 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4933 return TRUE;
4936 if (Level == 5 ) {
4937 RegCloseKey(hkeyDriver);
4938 FIXME("level 5: incomplete\n");
4939 return TRUE;
4942 /* .pHelpFile */
4943 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4944 *pcbNeeded += size;
4945 if (*pcbNeeded <= cbBuf)
4946 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4948 if (di) di->pHelpFile = (LPWSTR)strPtr;
4949 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4952 /* .pDependentFiles */
4953 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4954 *pcbNeeded += size;
4955 if (*pcbNeeded <= cbBuf)
4956 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4958 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4959 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4961 else if (GetVersion() & 0x80000000) {
4962 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4963 size = 2 * sizeof(WCHAR);
4964 *pcbNeeded += size;
4965 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4967 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4968 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4971 /* .pMonitorName is the optional Language Monitor */
4972 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4973 *pcbNeeded += size;
4974 if (*pcbNeeded <= cbBuf)
4975 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4977 if (di) di->pMonitorName = (LPWSTR)strPtr;
4978 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4981 /* .pDefaultDataType */
4982 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4983 *pcbNeeded += size;
4984 if(*pcbNeeded <= cbBuf)
4985 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4987 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4988 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4991 if (Level == 3 ) {
4992 RegCloseKey(hkeyDriver);
4993 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4994 return TRUE;
4997 /* .pszzPreviousNames */
4998 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4999 *pcbNeeded += size;
5000 if(*pcbNeeded <= cbBuf)
5001 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5003 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5004 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5007 if (Level == 4 ) {
5008 RegCloseKey(hkeyDriver);
5009 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5010 return TRUE;
5013 /* support is missing, but not important enough for a FIXME */
5014 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5016 /* .pszMfgName */
5017 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5018 *pcbNeeded += size;
5019 if(*pcbNeeded <= cbBuf)
5020 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5022 if (di) di->pszMfgName = (LPWSTR)strPtr;
5023 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5026 /* .pszOEMUrl */
5027 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5028 *pcbNeeded += size;
5029 if(*pcbNeeded <= cbBuf)
5030 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5032 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5033 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5036 /* .pszHardwareID */
5037 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5038 *pcbNeeded += size;
5039 if(*pcbNeeded <= cbBuf)
5040 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5042 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5043 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5046 /* .pszProvider */
5047 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5048 *pcbNeeded += size;
5049 if(*pcbNeeded <= cbBuf)
5050 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5052 if (di) di->pszProvider = (LPWSTR)strPtr;
5053 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5056 if (Level == 6 ) {
5057 RegCloseKey(hkeyDriver);
5058 return TRUE;
5061 /* support is missing, but not important enough for a FIXME */
5062 TRACE("level 8: incomplete\n");
5064 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5065 RegCloseKey(hkeyDriver);
5066 return TRUE;
5069 /*****************************************************************************
5070 * GetPrinterDriverW [WINSPOOL.@]
5072 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5073 DWORD Level, LPBYTE pDriverInfo,
5074 DWORD cbBuf, LPDWORD pcbNeeded)
5076 LPCWSTR name;
5077 WCHAR DriverName[100];
5078 DWORD ret, type, size, needed = 0;
5079 LPBYTE ptr = NULL;
5080 HKEY hkeyPrinter, hkeyDrivers;
5081 const printenv_t * env;
5083 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5084 Level,pDriverInfo,cbBuf, pcbNeeded);
5086 if (cbBuf > 0)
5087 ZeroMemory(pDriverInfo, cbBuf);
5089 if (!(name = get_opened_printer_name(hPrinter))) {
5090 SetLastError(ERROR_INVALID_HANDLE);
5091 return FALSE;
5094 if (Level < 1 || Level == 7 || Level > 8) {
5095 SetLastError(ERROR_INVALID_LEVEL);
5096 return FALSE;
5099 env = validate_envW(pEnvironment);
5100 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5102 ret = open_printer_reg_key( name, &hkeyPrinter );
5103 if (ret)
5105 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5106 SetLastError( ret );
5107 return FALSE;
5110 size = sizeof(DriverName);
5111 DriverName[0] = 0;
5112 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5113 (LPBYTE)DriverName, &size);
5114 RegCloseKey(hkeyPrinter);
5115 if(ret != ERROR_SUCCESS) {
5116 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5117 return FALSE;
5120 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5121 if(!hkeyDrivers) {
5122 ERR("Can't create Drivers key\n");
5123 return FALSE;
5126 size = di_sizeof[Level];
5127 if ((size <= cbBuf) && pDriverInfo)
5128 ptr = pDriverInfo + size;
5130 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5131 env, Level, pDriverInfo, ptr,
5132 (cbBuf < size) ? 0 : cbBuf - size,
5133 &needed)) {
5134 RegCloseKey(hkeyDrivers);
5135 return FALSE;
5138 RegCloseKey(hkeyDrivers);
5140 if(pcbNeeded) *pcbNeeded = size + needed;
5141 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5142 if(cbBuf >= size + needed) return TRUE;
5143 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5144 return FALSE;
5147 /*****************************************************************************
5148 * GetPrinterDriverA [WINSPOOL.@]
5150 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5151 DWORD Level, LPBYTE pDriverInfo,
5152 DWORD cbBuf, LPDWORD pcbNeeded)
5154 BOOL ret;
5155 UNICODE_STRING pEnvW;
5156 PWSTR pwstrEnvW;
5157 LPBYTE buf = NULL;
5159 if (cbBuf)
5161 ZeroMemory(pDriverInfo, cbBuf);
5162 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5165 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5166 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5167 cbBuf, pcbNeeded);
5168 if (ret)
5169 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5171 HeapFree(GetProcessHeap(), 0, buf);
5173 RtlFreeUnicodeString(&pEnvW);
5174 return ret;
5177 /*****************************************************************************
5178 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5180 * Return the PATH for the Printer-Drivers (UNICODE)
5182 * PARAMS
5183 * pName [I] Servername (NT only) or NULL (local Computer)
5184 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5185 * Level [I] Structure-Level (must be 1)
5186 * pDriverDirectory [O] PTR to Buffer that receives the Result
5187 * cbBuf [I] Size of Buffer at pDriverDirectory
5188 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5189 * required for pDriverDirectory
5191 * RETURNS
5192 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5193 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5194 * if cbBuf is too small
5196 * Native Values returned in pDriverDirectory on Success:
5197 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5198 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5199 *| win9x(Windows 4.0): "%winsysdir%"
5201 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5203 * FIXME
5204 *- Only NULL or "" is supported for pName
5207 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5208 DWORD Level, LPBYTE pDriverDirectory,
5209 DWORD cbBuf, LPDWORD pcbNeeded)
5211 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5212 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5214 if ((backend == NULL) && !load_backend()) return FALSE;
5216 if (Level != 1) {
5217 /* (Level != 1) is ignored in win9x */
5218 SetLastError(ERROR_INVALID_LEVEL);
5219 return FALSE;
5221 if (pcbNeeded == NULL) {
5222 /* (pcbNeeded == NULL) is ignored in win9x */
5223 SetLastError(RPC_X_NULL_REF_POINTER);
5224 return FALSE;
5227 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5228 pDriverDirectory, cbBuf, pcbNeeded);
5233 /*****************************************************************************
5234 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5236 * Return the PATH for the Printer-Drivers (ANSI)
5238 * See GetPrinterDriverDirectoryW.
5240 * NOTES
5241 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5244 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5245 DWORD Level, LPBYTE pDriverDirectory,
5246 DWORD cbBuf, LPDWORD pcbNeeded)
5248 UNICODE_STRING nameW, environmentW;
5249 BOOL ret;
5250 DWORD pcbNeededW;
5251 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5252 WCHAR *driverDirectoryW = NULL;
5254 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5255 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5257 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5259 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5260 else nameW.Buffer = NULL;
5261 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5262 else environmentW.Buffer = NULL;
5264 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5265 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5266 if (ret) {
5267 DWORD needed;
5268 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5269 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5270 if(pcbNeeded)
5271 *pcbNeeded = needed;
5272 ret = needed <= cbBuf;
5273 } else
5274 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5276 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5278 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5279 RtlFreeUnicodeString(&environmentW);
5280 RtlFreeUnicodeString(&nameW);
5282 return ret;
5285 /*****************************************************************************
5286 * AddPrinterDriverA [WINSPOOL.@]
5288 * See AddPrinterDriverW.
5291 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5293 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5294 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5297 /******************************************************************************
5298 * AddPrinterDriverW (WINSPOOL.@)
5300 * Install a Printer Driver
5302 * PARAMS
5303 * pName [I] Servername or NULL (local Computer)
5304 * level [I] Level for the supplied DRIVER_INFO_*W struct
5305 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5307 * RESULTS
5308 * Success: TRUE
5309 * Failure: FALSE
5312 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5314 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5315 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5318 /*****************************************************************************
5319 * AddPrintProcessorA [WINSPOOL.@]
5321 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5322 LPSTR pPrintProcessorName)
5324 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5325 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5326 return FALSE;
5329 /*****************************************************************************
5330 * AddPrintProcessorW [WINSPOOL.@]
5332 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5333 LPWSTR pPrintProcessorName)
5335 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5336 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5337 return TRUE;
5340 /*****************************************************************************
5341 * AddPrintProvidorA [WINSPOOL.@]
5343 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5345 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5346 return FALSE;
5349 /*****************************************************************************
5350 * AddPrintProvidorW [WINSPOOL.@]
5352 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5354 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5355 return FALSE;
5358 /*****************************************************************************
5359 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5361 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5362 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5364 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5365 pDevModeOutput, pDevModeInput);
5366 return 0;
5369 /*****************************************************************************
5370 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5372 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5373 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5375 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5376 pDevModeOutput, pDevModeInput);
5377 return 0;
5380 /*****************************************************************************
5381 * PrinterProperties [WINSPOOL.@]
5383 * Displays a dialog to set the properties of the printer.
5385 * RETURNS
5386 * nonzero on success or zero on failure
5388 * BUGS
5389 * implemented as stub only
5391 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5392 HANDLE hPrinter /* [in] handle to printer object */
5394 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5395 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5396 return FALSE;
5399 /*****************************************************************************
5400 * EnumJobsA [WINSPOOL.@]
5403 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5404 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5405 LPDWORD pcReturned)
5407 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5408 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5410 if(pcbNeeded) *pcbNeeded = 0;
5411 if(pcReturned) *pcReturned = 0;
5412 return FALSE;
5416 /*****************************************************************************
5417 * EnumJobsW [WINSPOOL.@]
5420 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5421 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5422 LPDWORD pcReturned)
5424 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5425 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5427 if(pcbNeeded) *pcbNeeded = 0;
5428 if(pcReturned) *pcReturned = 0;
5429 return FALSE;
5432 /*****************************************************************************
5433 * WINSPOOL_EnumPrinterDrivers [internal]
5435 * Delivers information about all printer drivers installed on the
5436 * localhost or a given server
5438 * RETURNS
5439 * nonzero on success or zero on failure. If the buffer for the returned
5440 * information is too small the function will return an error
5442 * BUGS
5443 * - only implemented for localhost, foreign hosts will return an error
5445 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5446 DWORD Level, LPBYTE pDriverInfo,
5447 DWORD driver_index,
5448 DWORD cbBuf, LPDWORD pcbNeeded,
5449 LPDWORD pcFound, DWORD data_offset)
5451 { HKEY hkeyDrivers;
5452 DWORD i, size = 0;
5453 const printenv_t * env;
5455 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5456 debugstr_w(pName), debugstr_w(pEnvironment),
5457 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5459 env = validate_envW(pEnvironment);
5460 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5462 *pcFound = 0;
5464 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5465 if(!hkeyDrivers) {
5466 ERR("Can't open Drivers key\n");
5467 return FALSE;
5470 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5471 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5472 RegCloseKey(hkeyDrivers);
5473 ERR("Can't query Drivers key\n");
5474 return FALSE;
5476 TRACE("Found %d Drivers\n", *pcFound);
5478 /* get size of single struct
5479 * unicode and ascii structure have the same size
5481 size = di_sizeof[Level];
5483 if (data_offset == 0)
5484 data_offset = size * (*pcFound);
5485 *pcbNeeded = data_offset;
5487 for( i = 0; i < *pcFound; i++) {
5488 WCHAR DriverNameW[255];
5489 PBYTE table_ptr = NULL;
5490 PBYTE data_ptr = NULL;
5491 DWORD needed = 0;
5493 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5494 != ERROR_SUCCESS) {
5495 ERR("Can't enum key number %d\n", i);
5496 RegCloseKey(hkeyDrivers);
5497 return FALSE;
5500 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5501 table_ptr = pDriverInfo + (driver_index + i) * size;
5502 if (pDriverInfo && *pcbNeeded <= cbBuf)
5503 data_ptr = pDriverInfo + *pcbNeeded;
5505 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5506 env, Level, table_ptr, data_ptr,
5507 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5508 &needed)) {
5509 RegCloseKey(hkeyDrivers);
5510 return FALSE;
5513 *pcbNeeded += needed;
5516 RegCloseKey(hkeyDrivers);
5518 if(cbBuf < *pcbNeeded){
5519 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5520 return FALSE;
5523 return TRUE;
5526 /*****************************************************************************
5527 * EnumPrinterDriversW [WINSPOOL.@]
5529 * see function EnumPrinterDrivers for RETURNS, BUGS
5531 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5532 LPBYTE pDriverInfo, DWORD cbBuf,
5533 LPDWORD pcbNeeded, LPDWORD pcReturned)
5535 static const WCHAR allW[] = {'a','l','l',0};
5536 BOOL ret;
5537 DWORD found;
5539 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5541 SetLastError(RPC_X_NULL_REF_POINTER);
5542 return FALSE;
5545 /* check for local drivers */
5546 if((pName) && (pName[0])) {
5547 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5548 SetLastError(ERROR_ACCESS_DENIED);
5549 return FALSE;
5552 /* check input parameter */
5553 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5554 SetLastError(ERROR_INVALID_LEVEL);
5555 return FALSE;
5558 if(pDriverInfo && cbBuf > 0)
5559 memset( pDriverInfo, 0, cbBuf);
5561 /* Exception: pull all printers */
5562 if (pEnvironment && !strcmpW(pEnvironment, allW))
5564 DWORD i, needed, bufsize = cbBuf;
5565 DWORD total_found = 0;
5566 DWORD data_offset;
5568 /* Precompute the overall total; we need this to know
5569 where pointers end and data begins (i.e. data_offset) */
5570 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5572 needed = found = 0;
5573 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5574 NULL, 0, 0, &needed, &found, 0);
5575 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5576 total_found += found;
5579 data_offset = di_sizeof[Level] * total_found;
5581 *pcReturned = 0;
5582 *pcbNeeded = 0;
5583 total_found = 0;
5584 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5586 needed = found = 0;
5587 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5588 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5589 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5590 else if (ret)
5591 *pcReturned += found;
5592 *pcbNeeded = needed;
5593 data_offset = needed;
5594 total_found += found;
5596 return ret;
5599 /* Normal behavior */
5600 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5601 0, cbBuf, pcbNeeded, &found, 0);
5602 if (ret)
5603 *pcReturned = found;
5605 return ret;
5608 /*****************************************************************************
5609 * EnumPrinterDriversA [WINSPOOL.@]
5611 * see function EnumPrinterDrivers for RETURNS, BUGS
5613 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5614 LPBYTE pDriverInfo, DWORD cbBuf,
5615 LPDWORD pcbNeeded, LPDWORD pcReturned)
5617 BOOL ret;
5618 UNICODE_STRING pNameW, pEnvironmentW;
5619 PWSTR pwstrNameW, pwstrEnvironmentW;
5620 LPBYTE buf = NULL;
5622 if (cbBuf)
5623 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5625 pwstrNameW = asciitounicode(&pNameW, pName);
5626 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5628 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5629 buf, cbBuf, pcbNeeded, pcReturned);
5630 if (ret)
5631 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5633 HeapFree(GetProcessHeap(), 0, buf);
5635 RtlFreeUnicodeString(&pNameW);
5636 RtlFreeUnicodeString(&pEnvironmentW);
5638 return ret;
5641 /******************************************************************************
5642 * EnumPortsA (WINSPOOL.@)
5644 * See EnumPortsW.
5647 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5648 LPDWORD pcbNeeded, LPDWORD pcReturned)
5650 BOOL res;
5651 LPBYTE bufferW = NULL;
5652 LPWSTR nameW = NULL;
5653 DWORD needed = 0;
5654 DWORD numentries = 0;
5655 INT len;
5657 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5658 cbBuf, pcbNeeded, pcReturned);
5660 /* convert servername to unicode */
5661 if (pName) {
5662 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5663 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5664 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5666 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5667 needed = cbBuf * sizeof(WCHAR);
5668 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5669 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5671 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5672 if (pcbNeeded) needed = *pcbNeeded;
5673 /* HeapReAlloc return NULL, when bufferW was NULL */
5674 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5675 HeapAlloc(GetProcessHeap(), 0, needed);
5677 /* Try again with the large Buffer */
5678 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5680 needed = pcbNeeded ? *pcbNeeded : 0;
5681 numentries = pcReturned ? *pcReturned : 0;
5684 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5685 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5687 if (res) {
5688 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5689 DWORD entrysize = 0;
5690 DWORD index;
5691 LPSTR ptr;
5692 LPPORT_INFO_2W pi2w;
5693 LPPORT_INFO_2A pi2a;
5695 needed = 0;
5696 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5698 /* First pass: calculate the size for all Entries */
5699 pi2w = (LPPORT_INFO_2W) bufferW;
5700 pi2a = (LPPORT_INFO_2A) pPorts;
5701 index = 0;
5702 while (index < numentries) {
5703 index++;
5704 needed += entrysize; /* PORT_INFO_?A */
5705 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5707 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5708 NULL, 0, NULL, NULL);
5709 if (Level > 1) {
5710 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5711 NULL, 0, NULL, NULL);
5712 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5713 NULL, 0, NULL, NULL);
5715 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5716 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5717 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5720 /* check for errors and quit on failure */
5721 if (cbBuf < needed) {
5722 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5723 res = FALSE;
5724 goto cleanup;
5726 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5727 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5728 cbBuf -= len ; /* free Bytes in the user-Buffer */
5729 pi2w = (LPPORT_INFO_2W) bufferW;
5730 pi2a = (LPPORT_INFO_2A) pPorts;
5731 index = 0;
5732 /* Second Pass: Fill the User Buffer (if we have one) */
5733 while ((index < numentries) && pPorts) {
5734 index++;
5735 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5736 pi2a->pPortName = ptr;
5737 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5738 ptr, cbBuf , NULL, NULL);
5739 ptr += len;
5740 cbBuf -= len;
5741 if (Level > 1) {
5742 pi2a->pMonitorName = ptr;
5743 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5744 ptr, cbBuf, NULL, NULL);
5745 ptr += len;
5746 cbBuf -= len;
5748 pi2a->pDescription = ptr;
5749 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5750 ptr, cbBuf, NULL, NULL);
5751 ptr += len;
5752 cbBuf -= len;
5754 pi2a->fPortType = pi2w->fPortType;
5755 pi2a->Reserved = 0; /* documented: "must be zero" */
5758 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5759 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5760 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5764 cleanup:
5765 if (pcbNeeded) *pcbNeeded = needed;
5766 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5768 HeapFree(GetProcessHeap(), 0, nameW);
5769 HeapFree(GetProcessHeap(), 0, bufferW);
5771 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5772 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5774 return (res);
5778 /******************************************************************************
5779 * EnumPortsW (WINSPOOL.@)
5781 * Enumerate available Ports
5783 * PARAMS
5784 * pName [I] Servername or NULL (local Computer)
5785 * Level [I] Structure-Level (1 or 2)
5786 * pPorts [O] PTR to Buffer that receives the Result
5787 * cbBuf [I] Size of Buffer at pPorts
5788 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5789 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5791 * RETURNS
5792 * Success: TRUE
5793 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5796 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5799 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5800 cbBuf, pcbNeeded, pcReturned);
5802 if ((backend == NULL) && !load_backend()) return FALSE;
5804 /* Level is not checked in win9x */
5805 if (!Level || (Level > 2)) {
5806 WARN("level (%d) is ignored in win9x\n", Level);
5807 SetLastError(ERROR_INVALID_LEVEL);
5808 return FALSE;
5810 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5811 SetLastError(RPC_X_NULL_REF_POINTER);
5812 return FALSE;
5815 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5818 /******************************************************************************
5819 * GetDefaultPrinterW (WINSPOOL.@)
5821 * FIXME
5822 * This function must read the value from data 'device' of key
5823 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5825 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5827 BOOL retval = TRUE;
5828 DWORD insize, len;
5829 WCHAR *buffer, *ptr;
5831 if (!namesize)
5833 SetLastError(ERROR_INVALID_PARAMETER);
5834 return FALSE;
5837 /* make the buffer big enough for the stuff from the profile/registry,
5838 * the content must fit into the local buffer to compute the correct
5839 * size even if the extern buffer is too small or not given.
5840 * (20 for ,driver,port) */
5841 insize = *namesize;
5842 len = max(100, (insize + 20));
5843 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5845 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5847 SetLastError (ERROR_FILE_NOT_FOUND);
5848 retval = FALSE;
5849 goto end;
5851 TRACE("%s\n", debugstr_w(buffer));
5853 if ((ptr = strchrW(buffer, ',')) == NULL)
5855 SetLastError(ERROR_INVALID_NAME);
5856 retval = FALSE;
5857 goto end;
5860 *ptr = 0;
5861 *namesize = strlenW(buffer) + 1;
5862 if(!name || (*namesize > insize))
5864 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5865 retval = FALSE;
5866 goto end;
5868 strcpyW(name, buffer);
5870 end:
5871 HeapFree( GetProcessHeap(), 0, buffer);
5872 return retval;
5876 /******************************************************************************
5877 * GetDefaultPrinterA (WINSPOOL.@)
5879 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5881 BOOL retval = TRUE;
5882 DWORD insize = 0;
5883 WCHAR *bufferW = NULL;
5885 if (!namesize)
5887 SetLastError(ERROR_INVALID_PARAMETER);
5888 return FALSE;
5891 if(name && *namesize) {
5892 insize = *namesize;
5893 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5896 if(!GetDefaultPrinterW( bufferW, namesize)) {
5897 retval = FALSE;
5898 goto end;
5901 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5902 NULL, NULL);
5903 if (!*namesize)
5905 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5906 retval = FALSE;
5908 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5910 end:
5911 HeapFree( GetProcessHeap(), 0, bufferW);
5912 return retval;
5916 /******************************************************************************
5917 * SetDefaultPrinterW (WINSPOOL.204)
5919 * Set the Name of the Default Printer
5921 * PARAMS
5922 * pszPrinter [I] Name of the Printer or NULL
5924 * RETURNS
5925 * Success: True
5926 * Failure: FALSE
5928 * NOTES
5929 * When the Parameter is NULL or points to an Empty String and
5930 * a Default Printer was already present, then this Function changes nothing.
5931 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5932 * the First enumerated local Printer is used.
5935 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5937 WCHAR default_printer[MAX_PATH];
5938 LPWSTR buffer = NULL;
5939 HKEY hreg;
5940 DWORD size;
5941 DWORD namelen;
5942 LONG lres;
5944 TRACE("(%s)\n", debugstr_w(pszPrinter));
5945 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5947 default_printer[0] = '\0';
5948 size = sizeof(default_printer)/sizeof(WCHAR);
5950 /* if we have a default Printer, do nothing. */
5951 if (GetDefaultPrinterW(default_printer, &size))
5952 return TRUE;
5954 pszPrinter = NULL;
5955 /* we have no default Printer: search local Printers and use the first */
5956 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5958 default_printer[0] = '\0';
5959 size = sizeof(default_printer)/sizeof(WCHAR);
5960 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5962 pszPrinter = default_printer;
5963 TRACE("using %s\n", debugstr_w(pszPrinter));
5965 RegCloseKey(hreg);
5968 if (pszPrinter == NULL) {
5969 TRACE("no local printer found\n");
5970 SetLastError(ERROR_FILE_NOT_FOUND);
5971 return FALSE;
5975 /* "pszPrinter" is never empty or NULL here. */
5976 namelen = lstrlenW(pszPrinter);
5977 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5978 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5979 if (!buffer ||
5980 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5981 HeapFree(GetProcessHeap(), 0, buffer);
5982 SetLastError(ERROR_FILE_NOT_FOUND);
5983 return FALSE;
5986 /* read the devices entry for the printer (driver,port) to build the string for the
5987 default device entry (printer,driver,port) */
5988 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5989 buffer[namelen] = ',';
5990 namelen++; /* move index to the start of the driver */
5992 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5993 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5994 if (!lres) {
5995 TRACE("set device to %s\n", debugstr_w(buffer));
5997 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5998 TRACE("failed to set the device entry: %d\n", GetLastError());
5999 lres = ERROR_INVALID_PRINTER_NAME;
6002 /* remove the next section, when INIFileMapping is implemented */
6004 HKEY hdev;
6005 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6006 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6007 RegCloseKey(hdev);
6011 else
6013 if (lres != ERROR_FILE_NOT_FOUND)
6014 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6016 SetLastError(ERROR_INVALID_PRINTER_NAME);
6019 RegCloseKey(hreg);
6020 HeapFree(GetProcessHeap(), 0, buffer);
6021 return (lres == ERROR_SUCCESS);
6024 /******************************************************************************
6025 * SetDefaultPrinterA (WINSPOOL.202)
6027 * See SetDefaultPrinterW.
6030 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6032 LPWSTR bufferW = NULL;
6033 BOOL res;
6035 TRACE("(%s)\n", debugstr_a(pszPrinter));
6036 if(pszPrinter) {
6037 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6038 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6039 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6041 res = SetDefaultPrinterW(bufferW);
6042 HeapFree(GetProcessHeap(), 0, bufferW);
6043 return res;
6046 /******************************************************************************
6047 * SetPrinterDataExA (WINSPOOL.@)
6049 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6050 LPCSTR pValueName, DWORD Type,
6051 LPBYTE pData, DWORD cbData)
6053 HKEY hkeyPrinter, hkeySubkey;
6054 DWORD ret;
6056 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6057 debugstr_a(pValueName), Type, pData, cbData);
6059 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6060 != ERROR_SUCCESS)
6061 return ret;
6063 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6064 != ERROR_SUCCESS) {
6065 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6066 RegCloseKey(hkeyPrinter);
6067 return ret;
6069 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6070 RegCloseKey(hkeySubkey);
6071 RegCloseKey(hkeyPrinter);
6072 return ret;
6075 /******************************************************************************
6076 * SetPrinterDataExW (WINSPOOL.@)
6078 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6079 LPCWSTR pValueName, DWORD Type,
6080 LPBYTE pData, DWORD cbData)
6082 HKEY hkeyPrinter, hkeySubkey;
6083 DWORD ret;
6085 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6086 debugstr_w(pValueName), Type, pData, cbData);
6088 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6089 != ERROR_SUCCESS)
6090 return ret;
6092 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6093 != ERROR_SUCCESS) {
6094 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6095 RegCloseKey(hkeyPrinter);
6096 return ret;
6098 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6099 RegCloseKey(hkeySubkey);
6100 RegCloseKey(hkeyPrinter);
6101 return ret;
6104 /******************************************************************************
6105 * SetPrinterDataA (WINSPOOL.@)
6107 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6108 LPBYTE pData, DWORD cbData)
6110 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6111 pData, cbData);
6114 /******************************************************************************
6115 * SetPrinterDataW (WINSPOOL.@)
6117 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6118 LPBYTE pData, DWORD cbData)
6120 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6121 pData, cbData);
6124 /******************************************************************************
6125 * GetPrinterDataExA (WINSPOOL.@)
6127 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6128 LPCSTR pValueName, LPDWORD pType,
6129 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6131 opened_printer_t *printer;
6132 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6133 DWORD ret;
6135 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6136 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6138 printer = get_opened_printer(hPrinter);
6139 if(!printer) return ERROR_INVALID_HANDLE;
6141 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6142 if (ret) return ret;
6144 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6146 if (printer->name) {
6148 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6149 if (ret) {
6150 RegCloseKey(hkeyPrinters);
6151 return ret;
6153 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6154 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6155 RegCloseKey(hkeyPrinter);
6156 RegCloseKey(hkeyPrinters);
6157 return ret;
6160 *pcbNeeded = nSize;
6161 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6162 0, pType, pData, pcbNeeded);
6164 if (!ret && !pData) ret = ERROR_MORE_DATA;
6166 RegCloseKey(hkeySubkey);
6167 RegCloseKey(hkeyPrinter);
6168 RegCloseKey(hkeyPrinters);
6170 TRACE("--> %d\n", ret);
6171 return ret;
6174 /******************************************************************************
6175 * GetPrinterDataExW (WINSPOOL.@)
6177 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6178 LPCWSTR pValueName, LPDWORD pType,
6179 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6181 opened_printer_t *printer;
6182 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6183 DWORD ret;
6185 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6186 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6188 printer = get_opened_printer(hPrinter);
6189 if(!printer) return ERROR_INVALID_HANDLE;
6191 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6192 if (ret) return ret;
6194 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6196 if (printer->name) {
6198 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6199 if (ret) {
6200 RegCloseKey(hkeyPrinters);
6201 return ret;
6203 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6204 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6205 RegCloseKey(hkeyPrinter);
6206 RegCloseKey(hkeyPrinters);
6207 return ret;
6210 *pcbNeeded = nSize;
6211 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6212 0, pType, pData, pcbNeeded);
6214 if (!ret && !pData) ret = ERROR_MORE_DATA;
6216 RegCloseKey(hkeySubkey);
6217 RegCloseKey(hkeyPrinter);
6218 RegCloseKey(hkeyPrinters);
6220 TRACE("--> %d\n", ret);
6221 return ret;
6224 /******************************************************************************
6225 * GetPrinterDataA (WINSPOOL.@)
6227 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6228 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6230 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6231 pData, nSize, pcbNeeded);
6234 /******************************************************************************
6235 * GetPrinterDataW (WINSPOOL.@)
6237 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6238 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6240 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6241 pData, nSize, pcbNeeded);
6244 /*******************************************************************************
6245 * EnumPrinterDataExW [WINSPOOL.@]
6247 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6248 LPBYTE pEnumValues, DWORD cbEnumValues,
6249 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6251 HKEY hkPrinter, hkSubKey;
6252 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6253 cbValueNameLen, cbMaxValueLen, cbValueLen,
6254 cbBufSize, dwType;
6255 LPWSTR lpValueName;
6256 HANDLE hHeap;
6257 PBYTE lpValue;
6258 PPRINTER_ENUM_VALUESW ppev;
6260 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6262 if (pKeyName == NULL || *pKeyName == 0)
6263 return ERROR_INVALID_PARAMETER;
6265 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6266 if (ret != ERROR_SUCCESS)
6268 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6269 hPrinter, ret);
6270 return ret;
6273 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6274 if (ret != ERROR_SUCCESS)
6276 r = RegCloseKey (hkPrinter);
6277 if (r != ERROR_SUCCESS)
6278 WARN ("RegCloseKey returned %i\n", r);
6279 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6280 debugstr_w (pKeyName), ret);
6281 return ret;
6284 ret = RegCloseKey (hkPrinter);
6285 if (ret != ERROR_SUCCESS)
6287 ERR ("RegCloseKey returned %i\n", ret);
6288 r = RegCloseKey (hkSubKey);
6289 if (r != ERROR_SUCCESS)
6290 WARN ("RegCloseKey returned %i\n", r);
6291 return ret;
6294 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6295 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6296 if (ret != ERROR_SUCCESS)
6298 r = RegCloseKey (hkSubKey);
6299 if (r != ERROR_SUCCESS)
6300 WARN ("RegCloseKey returned %i\n", r);
6301 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6302 return ret;
6305 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6306 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6308 if (cValues == 0) /* empty key */
6310 r = RegCloseKey (hkSubKey);
6311 if (r != ERROR_SUCCESS)
6312 WARN ("RegCloseKey returned %i\n", r);
6313 *pcbEnumValues = *pnEnumValues = 0;
6314 return ERROR_SUCCESS;
6317 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6319 hHeap = GetProcessHeap ();
6320 if (hHeap == NULL)
6322 ERR ("GetProcessHeap failed\n");
6323 r = RegCloseKey (hkSubKey);
6324 if (r != ERROR_SUCCESS)
6325 WARN ("RegCloseKey returned %i\n", r);
6326 return ERROR_OUTOFMEMORY;
6329 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6330 if (lpValueName == NULL)
6332 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6333 r = RegCloseKey (hkSubKey);
6334 if (r != ERROR_SUCCESS)
6335 WARN ("RegCloseKey returned %i\n", r);
6336 return ERROR_OUTOFMEMORY;
6339 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6340 if (lpValue == NULL)
6342 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6343 if (HeapFree (hHeap, 0, lpValueName) == 0)
6344 WARN ("HeapFree failed with code %i\n", GetLastError ());
6345 r = RegCloseKey (hkSubKey);
6346 if (r != ERROR_SUCCESS)
6347 WARN ("RegCloseKey returned %i\n", r);
6348 return ERROR_OUTOFMEMORY;
6351 TRACE ("pass 1: calculating buffer required for all names and values\n");
6353 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6355 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6357 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6359 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6360 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6361 NULL, NULL, lpValue, &cbValueLen);
6362 if (ret != ERROR_SUCCESS)
6364 if (HeapFree (hHeap, 0, lpValue) == 0)
6365 WARN ("HeapFree failed with code %i\n", GetLastError ());
6366 if (HeapFree (hHeap, 0, lpValueName) == 0)
6367 WARN ("HeapFree failed with code %i\n", GetLastError ());
6368 r = RegCloseKey (hkSubKey);
6369 if (r != ERROR_SUCCESS)
6370 WARN ("RegCloseKey returned %i\n", r);
6371 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6372 return ret;
6375 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6376 debugstr_w (lpValueName), dwIndex,
6377 cbValueNameLen + 1, cbValueLen);
6379 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6380 cbBufSize += cbValueLen;
6383 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6385 *pcbEnumValues = cbBufSize;
6386 *pnEnumValues = cValues;
6388 if (cbEnumValues < cbBufSize) /* buffer too small */
6390 if (HeapFree (hHeap, 0, lpValue) == 0)
6391 WARN ("HeapFree failed with code %i\n", GetLastError ());
6392 if (HeapFree (hHeap, 0, lpValueName) == 0)
6393 WARN ("HeapFree failed with code %i\n", GetLastError ());
6394 r = RegCloseKey (hkSubKey);
6395 if (r != ERROR_SUCCESS)
6396 WARN ("RegCloseKey returned %i\n", r);
6397 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6398 return ERROR_MORE_DATA;
6401 TRACE ("pass 2: copying all names and values to buffer\n");
6403 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6404 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6406 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6408 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6409 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6410 NULL, &dwType, lpValue, &cbValueLen);
6411 if (ret != ERROR_SUCCESS)
6413 if (HeapFree (hHeap, 0, lpValue) == 0)
6414 WARN ("HeapFree failed with code %i\n", GetLastError ());
6415 if (HeapFree (hHeap, 0, lpValueName) == 0)
6416 WARN ("HeapFree failed with code %i\n", GetLastError ());
6417 r = RegCloseKey (hkSubKey);
6418 if (r != ERROR_SUCCESS)
6419 WARN ("RegCloseKey returned %i\n", r);
6420 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6421 return ret;
6424 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6425 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6426 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6427 pEnumValues += cbValueNameLen;
6429 /* return # of *bytes* (including trailing \0), not # of chars */
6430 ppev[dwIndex].cbValueName = cbValueNameLen;
6432 ppev[dwIndex].dwType = dwType;
6434 memcpy (pEnumValues, lpValue, cbValueLen);
6435 ppev[dwIndex].pData = pEnumValues;
6436 pEnumValues += cbValueLen;
6438 ppev[dwIndex].cbData = cbValueLen;
6440 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6441 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6444 if (HeapFree (hHeap, 0, lpValue) == 0)
6446 ret = GetLastError ();
6447 ERR ("HeapFree failed with code %i\n", ret);
6448 if (HeapFree (hHeap, 0, lpValueName) == 0)
6449 WARN ("HeapFree failed with code %i\n", GetLastError ());
6450 r = RegCloseKey (hkSubKey);
6451 if (r != ERROR_SUCCESS)
6452 WARN ("RegCloseKey returned %i\n", r);
6453 return ret;
6456 if (HeapFree (hHeap, 0, lpValueName) == 0)
6458 ret = GetLastError ();
6459 ERR ("HeapFree failed with code %i\n", ret);
6460 r = RegCloseKey (hkSubKey);
6461 if (r != ERROR_SUCCESS)
6462 WARN ("RegCloseKey returned %i\n", r);
6463 return ret;
6466 ret = RegCloseKey (hkSubKey);
6467 if (ret != ERROR_SUCCESS)
6469 ERR ("RegCloseKey returned %i\n", ret);
6470 return ret;
6473 return ERROR_SUCCESS;
6476 /*******************************************************************************
6477 * EnumPrinterDataExA [WINSPOOL.@]
6479 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6480 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6481 * what Windows 2000 SP1 does.
6484 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6485 LPBYTE pEnumValues, DWORD cbEnumValues,
6486 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6488 INT len;
6489 LPWSTR pKeyNameW;
6490 DWORD ret, dwIndex, dwBufSize;
6491 HANDLE hHeap;
6492 LPSTR pBuffer;
6494 TRACE ("%p %s\n", hPrinter, pKeyName);
6496 if (pKeyName == NULL || *pKeyName == 0)
6497 return ERROR_INVALID_PARAMETER;
6499 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6500 if (len == 0)
6502 ret = GetLastError ();
6503 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6504 return ret;
6507 hHeap = GetProcessHeap ();
6508 if (hHeap == NULL)
6510 ERR ("GetProcessHeap failed\n");
6511 return ERROR_OUTOFMEMORY;
6514 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6515 if (pKeyNameW == NULL)
6517 ERR ("Failed to allocate %i bytes from process heap\n",
6518 (LONG)(len * sizeof (WCHAR)));
6519 return ERROR_OUTOFMEMORY;
6522 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6524 ret = GetLastError ();
6525 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6526 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6527 WARN ("HeapFree failed with code %i\n", GetLastError ());
6528 return ret;
6531 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6532 pcbEnumValues, pnEnumValues);
6533 if (ret != ERROR_SUCCESS)
6535 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6536 WARN ("HeapFree failed with code %i\n", GetLastError ());
6537 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6538 return ret;
6541 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6543 ret = GetLastError ();
6544 ERR ("HeapFree failed with code %i\n", ret);
6545 return ret;
6548 if (*pnEnumValues == 0) /* empty key */
6549 return ERROR_SUCCESS;
6551 dwBufSize = 0;
6552 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6554 PPRINTER_ENUM_VALUESW ppev =
6555 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6557 if (dwBufSize < ppev->cbValueName)
6558 dwBufSize = ppev->cbValueName;
6560 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6561 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6562 dwBufSize = ppev->cbData;
6565 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6567 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6568 if (pBuffer == NULL)
6570 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6571 return ERROR_OUTOFMEMORY;
6574 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6576 PPRINTER_ENUM_VALUESW ppev =
6577 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6579 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6580 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6581 NULL);
6582 if (len == 0)
6584 ret = GetLastError ();
6585 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6586 if (HeapFree (hHeap, 0, pBuffer) == 0)
6587 WARN ("HeapFree failed with code %i\n", GetLastError ());
6588 return ret;
6591 memcpy (ppev->pValueName, pBuffer, len);
6593 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6595 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6596 ppev->dwType != REG_MULTI_SZ)
6597 continue;
6599 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6600 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6601 if (len == 0)
6603 ret = GetLastError ();
6604 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6605 if (HeapFree (hHeap, 0, pBuffer) == 0)
6606 WARN ("HeapFree failed with code %i\n", GetLastError ());
6607 return ret;
6610 memcpy (ppev->pData, pBuffer, len);
6612 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6613 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6616 if (HeapFree (hHeap, 0, pBuffer) == 0)
6618 ret = GetLastError ();
6619 ERR ("HeapFree failed with code %i\n", ret);
6620 return ret;
6623 return ERROR_SUCCESS;
6626 /******************************************************************************
6627 * AbortPrinter (WINSPOOL.@)
6629 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6631 FIXME("(%p), stub!\n", hPrinter);
6632 return TRUE;
6635 /******************************************************************************
6636 * AddPortA (WINSPOOL.@)
6638 * See AddPortW.
6641 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6643 LPWSTR nameW = NULL;
6644 LPWSTR monitorW = NULL;
6645 DWORD len;
6646 BOOL res;
6648 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6650 if (pName) {
6651 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6652 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6653 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6656 if (pMonitorName) {
6657 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6658 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6659 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6661 res = AddPortW(nameW, hWnd, monitorW);
6662 HeapFree(GetProcessHeap(), 0, nameW);
6663 HeapFree(GetProcessHeap(), 0, monitorW);
6664 return res;
6667 /******************************************************************************
6668 * AddPortW (WINSPOOL.@)
6670 * Add a Port for a specific Monitor
6672 * PARAMS
6673 * pName [I] Servername or NULL (local Computer)
6674 * hWnd [I] Handle to parent Window for the Dialog-Box
6675 * pMonitorName [I] Name of the Monitor that manage the Port
6677 * RETURNS
6678 * Success: TRUE
6679 * Failure: FALSE
6682 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6684 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6686 if ((backend == NULL) && !load_backend()) return FALSE;
6688 if (!pMonitorName) {
6689 SetLastError(RPC_X_NULL_REF_POINTER);
6690 return FALSE;
6693 return backend->fpAddPort(pName, hWnd, pMonitorName);
6696 /******************************************************************************
6697 * AddPortExA (WINSPOOL.@)
6699 * See AddPortExW.
6702 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6704 PORT_INFO_2W pi2W;
6705 PORT_INFO_2A * pi2A;
6706 LPWSTR nameW = NULL;
6707 LPWSTR monitorW = NULL;
6708 DWORD len;
6709 BOOL res;
6711 pi2A = (PORT_INFO_2A *) pBuffer;
6713 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6714 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6716 if ((level < 1) || (level > 2)) {
6717 SetLastError(ERROR_INVALID_LEVEL);
6718 return FALSE;
6721 if (!pi2A) {
6722 SetLastError(ERROR_INVALID_PARAMETER);
6723 return FALSE;
6726 if (pName) {
6727 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6728 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6729 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6732 if (pMonitorName) {
6733 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6734 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6735 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6738 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6740 if (pi2A->pPortName) {
6741 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6742 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6743 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6746 if (level > 1) {
6747 if (pi2A->pMonitorName) {
6748 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6749 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6750 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6753 if (pi2A->pDescription) {
6754 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6755 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6756 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6758 pi2W.fPortType = pi2A->fPortType;
6759 pi2W.Reserved = pi2A->Reserved;
6762 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6764 HeapFree(GetProcessHeap(), 0, nameW);
6765 HeapFree(GetProcessHeap(), 0, monitorW);
6766 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6767 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6768 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6769 return res;
6773 /******************************************************************************
6774 * AddPortExW (WINSPOOL.@)
6776 * Add a Port for a specific Monitor, without presenting a user interface
6778 * PARAMS
6779 * pName [I] Servername or NULL (local Computer)
6780 * level [I] Structure-Level (1 or 2) for pBuffer
6781 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6782 * pMonitorName [I] Name of the Monitor that manage the Port
6784 * RETURNS
6785 * Success: TRUE
6786 * Failure: FALSE
6789 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6791 PORT_INFO_2W * pi2;
6793 pi2 = (PORT_INFO_2W *) pBuffer;
6795 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6796 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6797 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6798 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6800 if ((backend == NULL) && !load_backend()) return FALSE;
6802 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6803 SetLastError(ERROR_INVALID_PARAMETER);
6804 return FALSE;
6807 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6810 /******************************************************************************
6811 * AddPrinterConnectionA (WINSPOOL.@)
6813 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6815 FIXME("%s\n", debugstr_a(pName));
6816 return FALSE;
6819 /******************************************************************************
6820 * AddPrinterConnectionW (WINSPOOL.@)
6822 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6824 FIXME("%s\n", debugstr_w(pName));
6825 return FALSE;
6828 /******************************************************************************
6829 * AddPrinterDriverExW (WINSPOOL.@)
6831 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6833 * PARAMS
6834 * pName [I] Servername or NULL (local Computer)
6835 * level [I] Level for the supplied DRIVER_INFO_*W struct
6836 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6837 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6839 * RESULTS
6840 * Success: TRUE
6841 * Failure: FALSE
6844 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6846 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6848 if ((backend == NULL) && !load_backend()) return FALSE;
6850 if (level < 2 || level == 5 || level == 7 || level > 8) {
6851 SetLastError(ERROR_INVALID_LEVEL);
6852 return FALSE;
6855 if (!pDriverInfo) {
6856 SetLastError(ERROR_INVALID_PARAMETER);
6857 return FALSE;
6860 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6863 /******************************************************************************
6864 * AddPrinterDriverExA (WINSPOOL.@)
6866 * See AddPrinterDriverExW.
6869 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6871 DRIVER_INFO_8A *diA;
6872 DRIVER_INFO_8W diW;
6873 LPWSTR nameW = NULL;
6874 DWORD lenA;
6875 DWORD len;
6876 BOOL res = FALSE;
6878 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6880 diA = (DRIVER_INFO_8A *) pDriverInfo;
6881 ZeroMemory(&diW, sizeof(diW));
6883 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6884 SetLastError(ERROR_INVALID_LEVEL);
6885 return FALSE;
6888 if (diA == NULL) {
6889 SetLastError(ERROR_INVALID_PARAMETER);
6890 return FALSE;
6893 /* convert servername to unicode */
6894 if (pName) {
6895 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6896 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6897 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6900 /* common fields */
6901 diW.cVersion = diA->cVersion;
6903 if (diA->pName) {
6904 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6905 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6906 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6909 if (diA->pEnvironment) {
6910 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6911 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6912 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6915 if (diA->pDriverPath) {
6916 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6917 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6918 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6921 if (diA->pDataFile) {
6922 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6923 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6924 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6927 if (diA->pConfigFile) {
6928 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6929 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6930 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6933 if ((Level > 2) && diA->pDependentFiles) {
6934 lenA = multi_sz_lenA(diA->pDependentFiles);
6935 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6936 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6937 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6940 if ((Level > 2) && diA->pMonitorName) {
6941 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6942 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6943 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6946 if ((Level > 3) && diA->pDefaultDataType) {
6947 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6948 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6949 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6952 if ((Level > 3) && diA->pszzPreviousNames) {
6953 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6954 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6955 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6956 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6959 if ((Level > 5) && diA->pszMfgName) {
6960 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6961 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6962 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6965 if ((Level > 5) && diA->pszOEMUrl) {
6966 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6967 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6968 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6971 if ((Level > 5) && diA->pszHardwareID) {
6972 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6973 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6974 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6977 if ((Level > 5) && diA->pszProvider) {
6978 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6979 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6980 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6983 if (Level > 7) {
6984 FIXME("level %u is incomplete\n", Level);
6987 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6988 TRACE("got %u with %u\n", res, GetLastError());
6989 HeapFree(GetProcessHeap(), 0, nameW);
6990 HeapFree(GetProcessHeap(), 0, diW.pName);
6991 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6992 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6993 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6994 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6995 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6996 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6997 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6998 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6999 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7000 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7001 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7002 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7004 TRACE("=> %u with %u\n", res, GetLastError());
7005 return res;
7008 /******************************************************************************
7009 * ConfigurePortA (WINSPOOL.@)
7011 * See ConfigurePortW.
7014 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7016 LPWSTR nameW = NULL;
7017 LPWSTR portW = NULL;
7018 INT len;
7019 DWORD res;
7021 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7023 /* convert servername to unicode */
7024 if (pName) {
7025 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7026 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7027 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7030 /* convert portname to unicode */
7031 if (pPortName) {
7032 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7033 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7034 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7037 res = ConfigurePortW(nameW, hWnd, portW);
7038 HeapFree(GetProcessHeap(), 0, nameW);
7039 HeapFree(GetProcessHeap(), 0, portW);
7040 return res;
7043 /******************************************************************************
7044 * ConfigurePortW (WINSPOOL.@)
7046 * Display the Configuration-Dialog for a specific Port
7048 * PARAMS
7049 * pName [I] Servername or NULL (local Computer)
7050 * hWnd [I] Handle to parent Window for the Dialog-Box
7051 * pPortName [I] Name of the Port, that should be configured
7053 * RETURNS
7054 * Success: TRUE
7055 * Failure: FALSE
7058 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7061 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7063 if ((backend == NULL) && !load_backend()) return FALSE;
7065 if (!pPortName) {
7066 SetLastError(RPC_X_NULL_REF_POINTER);
7067 return FALSE;
7070 return backend->fpConfigurePort(pName, hWnd, pPortName);
7073 /******************************************************************************
7074 * ConnectToPrinterDlg (WINSPOOL.@)
7076 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7078 FIXME("%p %x\n", hWnd, Flags);
7079 return NULL;
7082 /******************************************************************************
7083 * DeletePrinterConnectionA (WINSPOOL.@)
7085 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7087 FIXME("%s\n", debugstr_a(pName));
7088 return TRUE;
7091 /******************************************************************************
7092 * DeletePrinterConnectionW (WINSPOOL.@)
7094 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7096 FIXME("%s\n", debugstr_w(pName));
7097 return TRUE;
7100 /******************************************************************************
7101 * DeletePrinterDriverExW (WINSPOOL.@)
7103 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7104 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7106 HKEY hkey_drivers;
7107 BOOL ret = FALSE;
7109 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7110 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7112 if(pName && pName[0])
7114 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7115 SetLastError(ERROR_INVALID_PARAMETER);
7116 return FALSE;
7119 if(dwDeleteFlag)
7121 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7122 SetLastError(ERROR_INVALID_PARAMETER);
7123 return FALSE;
7126 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7128 if(!hkey_drivers)
7130 ERR("Can't open drivers key\n");
7131 return FALSE;
7134 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7135 ret = TRUE;
7137 RegCloseKey(hkey_drivers);
7139 return ret;
7142 /******************************************************************************
7143 * DeletePrinterDriverExA (WINSPOOL.@)
7145 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7146 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7148 UNICODE_STRING NameW, EnvW, DriverW;
7149 BOOL ret;
7151 asciitounicode(&NameW, pName);
7152 asciitounicode(&EnvW, pEnvironment);
7153 asciitounicode(&DriverW, pDriverName);
7155 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7157 RtlFreeUnicodeString(&DriverW);
7158 RtlFreeUnicodeString(&EnvW);
7159 RtlFreeUnicodeString(&NameW);
7161 return ret;
7164 /******************************************************************************
7165 * DeletePrinterDataExW (WINSPOOL.@)
7167 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7168 LPCWSTR pValueName)
7170 FIXME("%p %s %s\n", hPrinter,
7171 debugstr_w(pKeyName), debugstr_w(pValueName));
7172 return ERROR_INVALID_PARAMETER;
7175 /******************************************************************************
7176 * DeletePrinterDataExA (WINSPOOL.@)
7178 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7179 LPCSTR pValueName)
7181 FIXME("%p %s %s\n", hPrinter,
7182 debugstr_a(pKeyName), debugstr_a(pValueName));
7183 return ERROR_INVALID_PARAMETER;
7186 /******************************************************************************
7187 * DeletePrintProcessorA (WINSPOOL.@)
7189 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7191 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7192 debugstr_a(pPrintProcessorName));
7193 return TRUE;
7196 /******************************************************************************
7197 * DeletePrintProcessorW (WINSPOOL.@)
7199 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7201 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7202 debugstr_w(pPrintProcessorName));
7203 return TRUE;
7206 /******************************************************************************
7207 * DeletePrintProvidorA (WINSPOOL.@)
7209 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7211 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7212 debugstr_a(pPrintProviderName));
7213 return TRUE;
7216 /******************************************************************************
7217 * DeletePrintProvidorW (WINSPOOL.@)
7219 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7221 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7222 debugstr_w(pPrintProviderName));
7223 return TRUE;
7226 /******************************************************************************
7227 * EnumFormsA (WINSPOOL.@)
7229 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7230 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7232 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7233 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7234 return FALSE;
7237 /******************************************************************************
7238 * EnumFormsW (WINSPOOL.@)
7240 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7241 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7243 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7244 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7245 return FALSE;
7248 /*****************************************************************************
7249 * EnumMonitorsA [WINSPOOL.@]
7251 * See EnumMonitorsW.
7254 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7255 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7257 BOOL res;
7258 LPBYTE bufferW = NULL;
7259 LPWSTR nameW = NULL;
7260 DWORD needed = 0;
7261 DWORD numentries = 0;
7262 INT len;
7264 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7265 cbBuf, pcbNeeded, pcReturned);
7267 /* convert servername to unicode */
7268 if (pName) {
7269 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7270 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7271 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7273 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7274 needed = cbBuf * sizeof(WCHAR);
7275 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7276 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7278 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7279 if (pcbNeeded) needed = *pcbNeeded;
7280 /* HeapReAlloc return NULL, when bufferW was NULL */
7281 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7282 HeapAlloc(GetProcessHeap(), 0, needed);
7284 /* Try again with the large Buffer */
7285 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7287 numentries = pcReturned ? *pcReturned : 0;
7288 needed = 0;
7290 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7291 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7293 if (res) {
7294 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7295 DWORD entrysize = 0;
7296 DWORD index;
7297 LPSTR ptr;
7298 LPMONITOR_INFO_2W mi2w;
7299 LPMONITOR_INFO_2A mi2a;
7301 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7302 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7304 /* First pass: calculate the size for all Entries */
7305 mi2w = (LPMONITOR_INFO_2W) bufferW;
7306 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7307 index = 0;
7308 while (index < numentries) {
7309 index++;
7310 needed += entrysize; /* MONITOR_INFO_?A */
7311 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7313 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7314 NULL, 0, NULL, NULL);
7315 if (Level > 1) {
7316 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7317 NULL, 0, NULL, NULL);
7318 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7319 NULL, 0, NULL, NULL);
7321 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7322 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7323 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7326 /* check for errors and quit on failure */
7327 if (cbBuf < needed) {
7328 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7329 res = FALSE;
7330 goto emA_cleanup;
7332 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7333 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7334 cbBuf -= len ; /* free Bytes in the user-Buffer */
7335 mi2w = (LPMONITOR_INFO_2W) bufferW;
7336 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7337 index = 0;
7338 /* Second Pass: Fill the User Buffer (if we have one) */
7339 while ((index < numentries) && pMonitors) {
7340 index++;
7341 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7342 mi2a->pName = ptr;
7343 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7344 ptr, cbBuf , NULL, NULL);
7345 ptr += len;
7346 cbBuf -= len;
7347 if (Level > 1) {
7348 mi2a->pEnvironment = ptr;
7349 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7350 ptr, cbBuf, NULL, NULL);
7351 ptr += len;
7352 cbBuf -= len;
7354 mi2a->pDLLName = ptr;
7355 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7356 ptr, cbBuf, NULL, NULL);
7357 ptr += len;
7358 cbBuf -= len;
7360 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7361 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7362 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7365 emA_cleanup:
7366 if (pcbNeeded) *pcbNeeded = needed;
7367 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7369 HeapFree(GetProcessHeap(), 0, nameW);
7370 HeapFree(GetProcessHeap(), 0, bufferW);
7372 TRACE("returning %d with %d (%d byte for %d entries)\n",
7373 (res), GetLastError(), needed, numentries);
7375 return (res);
7379 /*****************************************************************************
7380 * EnumMonitorsW [WINSPOOL.@]
7382 * Enumerate available Port-Monitors
7384 * PARAMS
7385 * pName [I] Servername or NULL (local Computer)
7386 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7387 * pMonitors [O] PTR to Buffer that receives the Result
7388 * cbBuf [I] Size of Buffer at pMonitors
7389 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7390 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7392 * RETURNS
7393 * Success: TRUE
7394 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7397 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7398 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7401 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7402 cbBuf, pcbNeeded, pcReturned);
7404 if ((backend == NULL) && !load_backend()) return FALSE;
7406 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7407 SetLastError(RPC_X_NULL_REF_POINTER);
7408 return FALSE;
7411 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7414 /******************************************************************************
7415 * SpoolerInit (WINSPOOL.@)
7417 * Initialize the Spooler
7419 * RETURNS
7420 * Success: TRUE
7421 * Failure: FALSE
7423 * NOTES
7424 * The function fails on windows, when the spooler service is not running
7427 BOOL WINAPI SpoolerInit(void)
7430 if ((backend == NULL) && !load_backend()) return FALSE;
7431 return TRUE;
7434 /******************************************************************************
7435 * XcvDataW (WINSPOOL.@)
7437 * Execute commands in the Printmonitor DLL
7439 * PARAMS
7440 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7441 * pszDataName [i] Name of the command to execute
7442 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7443 * cbInputData [i] Size in Bytes of Buffer at pInputData
7444 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7445 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7446 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7447 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7449 * RETURNS
7450 * Success: TRUE
7451 * Failure: FALSE
7453 * NOTES
7454 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7455 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7457 * Minimal List of commands, that a Printmonitor DLL should support:
7459 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7460 *| "AddPort" : Add a Port
7461 *| "DeletePort": Delete a Port
7463 * Many Printmonitors support additional commands. Examples for localspl.dll:
7464 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7465 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7468 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7469 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7470 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7472 opened_printer_t *printer;
7474 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7475 pInputData, cbInputData, pOutputData,
7476 cbOutputData, pcbOutputNeeded, pdwStatus);
7478 if ((backend == NULL) && !load_backend()) return FALSE;
7480 printer = get_opened_printer(hXcv);
7481 if (!printer || (!printer->backend_printer)) {
7482 SetLastError(ERROR_INVALID_HANDLE);
7483 return FALSE;
7486 if (!pcbOutputNeeded) {
7487 SetLastError(ERROR_INVALID_PARAMETER);
7488 return FALSE;
7491 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7492 SetLastError(RPC_X_NULL_REF_POINTER);
7493 return FALSE;
7496 *pcbOutputNeeded = 0;
7498 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7499 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7503 /*****************************************************************************
7504 * EnumPrinterDataA [WINSPOOL.@]
7507 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7508 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7509 DWORD cbData, LPDWORD pcbData )
7511 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7512 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7513 return ERROR_NO_MORE_ITEMS;
7516 /*****************************************************************************
7517 * EnumPrinterDataW [WINSPOOL.@]
7520 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7521 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7522 DWORD cbData, LPDWORD pcbData )
7524 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7525 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7526 return ERROR_NO_MORE_ITEMS;
7529 /*****************************************************************************
7530 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7533 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7534 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7535 LPDWORD pcbNeeded, LPDWORD pcReturned)
7537 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7538 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7539 pcbNeeded, pcReturned);
7540 return FALSE;
7543 /*****************************************************************************
7544 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7547 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7548 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7549 LPDWORD pcbNeeded, LPDWORD pcReturned)
7551 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7552 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7553 pcbNeeded, pcReturned);
7554 return FALSE;
7557 /*****************************************************************************
7558 * EnumPrintProcessorsA [WINSPOOL.@]
7560 * See EnumPrintProcessorsW.
7563 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7564 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7566 BOOL res;
7567 LPBYTE bufferW = NULL;
7568 LPWSTR nameW = NULL;
7569 LPWSTR envW = NULL;
7570 DWORD needed = 0;
7571 DWORD numentries = 0;
7572 INT len;
7574 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7575 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7577 /* convert names to unicode */
7578 if (pName) {
7579 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7580 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7581 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7583 if (pEnvironment) {
7584 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7585 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7586 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7589 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7590 needed = cbBuf * sizeof(WCHAR);
7591 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7592 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7594 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7595 if (pcbNeeded) needed = *pcbNeeded;
7596 /* HeapReAlloc return NULL, when bufferW was NULL */
7597 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7598 HeapAlloc(GetProcessHeap(), 0, needed);
7600 /* Try again with the large Buffer */
7601 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7603 numentries = pcReturned ? *pcReturned : 0;
7604 needed = 0;
7606 if (res) {
7607 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7608 DWORD index;
7609 LPSTR ptr;
7610 PPRINTPROCESSOR_INFO_1W ppiw;
7611 PPRINTPROCESSOR_INFO_1A ppia;
7613 /* First pass: calculate the size for all Entries */
7614 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7615 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7616 index = 0;
7617 while (index < numentries) {
7618 index++;
7619 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7620 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7622 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7623 NULL, 0, NULL, NULL);
7625 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7626 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7629 /* check for errors and quit on failure */
7630 if (cbBuf < needed) {
7631 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7632 res = FALSE;
7633 goto epp_cleanup;
7636 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7637 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7638 cbBuf -= len ; /* free Bytes in the user-Buffer */
7639 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7640 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7641 index = 0;
7642 /* Second Pass: Fill the User Buffer (if we have one) */
7643 while ((index < numentries) && pPPInfo) {
7644 index++;
7645 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7646 ppia->pName = ptr;
7647 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7648 ptr, cbBuf , NULL, NULL);
7649 ptr += len;
7650 cbBuf -= len;
7652 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7653 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7657 epp_cleanup:
7658 if (pcbNeeded) *pcbNeeded = needed;
7659 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7661 HeapFree(GetProcessHeap(), 0, nameW);
7662 HeapFree(GetProcessHeap(), 0, envW);
7663 HeapFree(GetProcessHeap(), 0, bufferW);
7665 TRACE("returning %d with %d (%d byte for %d entries)\n",
7666 (res), GetLastError(), needed, numentries);
7668 return (res);
7671 /*****************************************************************************
7672 * EnumPrintProcessorsW [WINSPOOL.@]
7674 * Enumerate available Print Processors
7676 * PARAMS
7677 * pName [I] Servername or NULL (local Computer)
7678 * pEnvironment [I] Printing-Environment or NULL (Default)
7679 * Level [I] Structure-Level (Only 1 is allowed)
7680 * pPPInfo [O] PTR to Buffer that receives the Result
7681 * cbBuf [I] Size of Buffer at pPPInfo
7682 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7683 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7685 * RETURNS
7686 * Success: TRUE
7687 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7690 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7691 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7694 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7695 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7697 if ((backend == NULL) && !load_backend()) return FALSE;
7699 if (!pcbNeeded || !pcReturned) {
7700 SetLastError(RPC_X_NULL_REF_POINTER);
7701 return FALSE;
7704 if (!pPPInfo && (cbBuf > 0)) {
7705 SetLastError(ERROR_INVALID_USER_BUFFER);
7706 return FALSE;
7709 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7710 cbBuf, pcbNeeded, pcReturned);
7713 /*****************************************************************************
7714 * ExtDeviceMode [WINSPOOL.@]
7717 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7718 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7719 DWORD fMode)
7721 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7722 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7723 debugstr_a(pProfile), fMode);
7724 return -1;
7727 /*****************************************************************************
7728 * FindClosePrinterChangeNotification [WINSPOOL.@]
7731 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7733 FIXME("Stub: %p\n", hChange);
7734 return TRUE;
7737 /*****************************************************************************
7738 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7741 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7742 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7744 FIXME("Stub: %p %x %x %p\n",
7745 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7746 return INVALID_HANDLE_VALUE;
7749 /*****************************************************************************
7750 * FindNextPrinterChangeNotification [WINSPOOL.@]
7753 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7754 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7756 FIXME("Stub: %p %p %p %p\n",
7757 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7758 return FALSE;
7761 /*****************************************************************************
7762 * FreePrinterNotifyInfo [WINSPOOL.@]
7765 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7767 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7768 return TRUE;
7771 /*****************************************************************************
7772 * string_to_buf
7774 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7775 * ansi depending on the unicode parameter.
7777 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7779 if(!str)
7781 *size = 0;
7782 return TRUE;
7785 if(unicode)
7787 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7788 if(*size <= cb)
7790 memcpy(ptr, str, *size);
7791 return TRUE;
7793 return FALSE;
7795 else
7797 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7798 if(*size <= cb)
7800 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7801 return TRUE;
7803 return FALSE;
7807 /*****************************************************************************
7808 * get_job_info_1
7810 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7811 LPDWORD pcbNeeded, BOOL unicode)
7813 DWORD size, left = cbBuf;
7814 BOOL space = (cbBuf > 0);
7815 LPBYTE ptr = buf;
7817 *pcbNeeded = 0;
7819 if(space)
7821 ji1->JobId = job->job_id;
7824 string_to_buf(job->document_title, ptr, left, &size, unicode);
7825 if(space && size <= left)
7827 ji1->pDocument = (LPWSTR)ptr;
7828 ptr += size;
7829 left -= size;
7831 else
7832 space = FALSE;
7833 *pcbNeeded += size;
7835 if (job->printer_name)
7837 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7838 if(space && size <= left)
7840 ji1->pPrinterName = (LPWSTR)ptr;
7841 ptr += size;
7842 left -= size;
7844 else
7845 space = FALSE;
7846 *pcbNeeded += size;
7849 return space;
7852 /*****************************************************************************
7853 * get_job_info_2
7855 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7856 LPDWORD pcbNeeded, BOOL unicode)
7858 DWORD size, left = cbBuf;
7859 DWORD shift;
7860 BOOL space = (cbBuf > 0);
7861 LPBYTE ptr = buf;
7862 LPDEVMODEA dmA = NULL;
7863 LPDEVMODEW devmode;
7865 *pcbNeeded = 0;
7867 if(space)
7869 ji2->JobId = job->job_id;
7872 string_to_buf(job->document_title, ptr, left, &size, unicode);
7873 if(space && size <= left)
7875 ji2->pDocument = (LPWSTR)ptr;
7876 ptr += size;
7877 left -= size;
7879 else
7880 space = FALSE;
7881 *pcbNeeded += size;
7883 if (job->printer_name)
7885 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7886 if(space && size <= left)
7888 ji2->pPrinterName = (LPWSTR)ptr;
7889 ptr += size;
7890 left -= size;
7892 else
7893 space = FALSE;
7894 *pcbNeeded += size;
7897 if (job->devmode)
7899 if (!unicode)
7901 dmA = DEVMODEdupWtoA(job->devmode);
7902 devmode = (LPDEVMODEW) dmA;
7903 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7905 else
7907 devmode = job->devmode;
7908 size = devmode->dmSize + devmode->dmDriverExtra;
7911 if (!devmode)
7912 FIXME("Can't convert DEVMODE W to A\n");
7913 else
7915 /* align DEVMODE to a DWORD boundary */
7916 shift = (4 - (*pcbNeeded & 3)) & 3;
7917 size += shift;
7919 if (size <= left)
7921 ptr += shift;
7922 memcpy(ptr, devmode, size-shift);
7923 ji2->pDevMode = (LPDEVMODEW)ptr;
7924 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7925 ptr += size-shift;
7926 left -= size;
7928 else
7929 space = FALSE;
7930 *pcbNeeded +=size;
7934 return space;
7937 /*****************************************************************************
7938 * get_job_info
7940 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7941 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7943 BOOL ret = FALSE;
7944 DWORD needed = 0, size;
7945 job_t *job;
7946 LPBYTE ptr = pJob;
7948 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7950 EnterCriticalSection(&printer_handles_cs);
7951 job = get_job(hPrinter, JobId);
7952 if(!job)
7953 goto end;
7955 switch(Level)
7957 case 1:
7958 size = sizeof(JOB_INFO_1W);
7959 if(cbBuf >= size)
7961 cbBuf -= size;
7962 ptr += size;
7963 memset(pJob, 0, size);
7965 else
7966 cbBuf = 0;
7967 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7968 needed += size;
7969 break;
7971 case 2:
7972 size = sizeof(JOB_INFO_2W);
7973 if(cbBuf >= size)
7975 cbBuf -= size;
7976 ptr += size;
7977 memset(pJob, 0, size);
7979 else
7980 cbBuf = 0;
7981 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7982 needed += size;
7983 break;
7985 case 3:
7986 size = sizeof(JOB_INFO_3);
7987 if(cbBuf >= size)
7989 cbBuf -= size;
7990 memset(pJob, 0, size);
7991 ret = TRUE;
7993 else
7994 cbBuf = 0;
7995 needed = size;
7996 break;
7998 default:
7999 SetLastError(ERROR_INVALID_LEVEL);
8000 goto end;
8002 if(pcbNeeded)
8003 *pcbNeeded = needed;
8004 end:
8005 LeaveCriticalSection(&printer_handles_cs);
8006 return ret;
8009 /*****************************************************************************
8010 * GetJobA [WINSPOOL.@]
8013 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8014 DWORD cbBuf, LPDWORD pcbNeeded)
8016 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8019 /*****************************************************************************
8020 * GetJobW [WINSPOOL.@]
8023 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8024 DWORD cbBuf, LPDWORD pcbNeeded)
8026 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8029 /*****************************************************************************
8030 * schedule_pipe
8032 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8034 #ifdef HAVE_FORK
8035 char *unixname, *cmdA;
8036 DWORD len;
8037 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8038 BOOL ret = FALSE;
8039 char buf[1024];
8040 pid_t pid, wret;
8041 int status;
8043 if(!(unixname = wine_get_unix_file_name(filename)))
8044 return FALSE;
8046 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8047 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8048 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8050 TRACE("printing with: %s\n", cmdA);
8052 if((file_fd = open(unixname, O_RDONLY)) == -1)
8053 goto end;
8055 if (pipe(fds))
8057 ERR("pipe() failed!\n");
8058 goto end;
8061 if ((pid = fork()) == 0)
8063 close(0);
8064 dup2(fds[0], 0);
8065 close(fds[1]);
8067 /* reset signals that we previously set to SIG_IGN */
8068 signal(SIGPIPE, SIG_DFL);
8070 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8071 _exit(1);
8073 else if (pid == -1)
8075 ERR("fork() failed!\n");
8076 goto end;
8079 close(fds[0]);
8080 fds[0] = -1;
8081 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8082 write(fds[1], buf, no_read);
8084 close(fds[1]);
8085 fds[1] = -1;
8087 /* reap child */
8088 do {
8089 wret = waitpid(pid, &status, 0);
8090 } while (wret < 0 && errno == EINTR);
8091 if (wret < 0)
8093 ERR("waitpid() failed!\n");
8094 goto end;
8096 if (!WIFEXITED(status) || WEXITSTATUS(status))
8098 ERR("child process failed! %d\n", status);
8099 goto end;
8102 ret = TRUE;
8104 end:
8105 if(file_fd != -1) close(file_fd);
8106 if(fds[0] != -1) close(fds[0]);
8107 if(fds[1] != -1) close(fds[1]);
8109 HeapFree(GetProcessHeap(), 0, cmdA);
8110 HeapFree(GetProcessHeap(), 0, unixname);
8111 return ret;
8112 #else
8113 return FALSE;
8114 #endif
8117 /*****************************************************************************
8118 * schedule_lpr
8120 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8122 WCHAR *cmd;
8123 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8124 BOOL r;
8126 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8127 sprintfW(cmd, fmtW, printer_name);
8129 r = schedule_pipe(cmd, filename);
8131 HeapFree(GetProcessHeap(), 0, cmd);
8132 return r;
8135 #ifdef SONAME_LIBCUPS
8136 /*****************************************************************************
8137 * get_cups_jobs_ticket_options
8139 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8140 * The CUPS scheduler only looks for these in Print-File requests, and since
8141 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8142 * parsed.
8144 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8146 FILE *fp = fopen( file, "r" );
8147 char buf[257]; /* DSC max of 256 + '\0' */
8148 const char *ps_adobe = "%!PS-Adobe-";
8149 const char *cups_job = "%cupsJobTicket:";
8151 if (!fp) return num_options;
8152 if (!fgets( buf, sizeof(buf), fp )) goto end;
8153 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8154 while (fgets( buf, sizeof(buf), fp ))
8156 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8157 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8160 end:
8161 fclose( fp );
8162 return num_options;
8165 static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
8167 cups_dest_t *dest;
8168 int i;
8170 if (!pcupsGetNamedDest) return num_options;
8172 dest = pcupsGetNamedDest( NULL, printer, NULL );
8173 if (!dest) return num_options;
8175 for (i = 0; i < dest->num_options; i++)
8177 if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
8178 num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
8179 num_options, options );
8182 pcupsFreeDests( 1, dest );
8183 return num_options;
8185 #endif
8187 /*****************************************************************************
8188 * schedule_cups
8190 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8192 #ifdef SONAME_LIBCUPS
8193 if(pcupsPrintFile)
8195 char *unixname, *queue, *unix_doc_title;
8196 DWORD len;
8197 BOOL ret;
8198 int num_options = 0, i;
8199 cups_option_t *options = NULL;
8201 if(!(unixname = wine_get_unix_file_name(filename)))
8202 return FALSE;
8204 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8205 queue = HeapAlloc(GetProcessHeap(), 0, len);
8206 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8208 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8209 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8210 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8212 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8213 num_options = get_cups_default_options( queue, num_options, &options );
8215 TRACE( "printing via cups with options:\n" );
8216 for (i = 0; i < num_options; i++)
8217 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8219 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8221 pcupsFreeOptions( num_options, options );
8223 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8224 HeapFree(GetProcessHeap(), 0, queue);
8225 HeapFree(GetProcessHeap(), 0, unixname);
8226 return ret;
8228 else
8229 #endif
8231 return schedule_lpr(printer_name, filename);
8235 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8237 LPWSTR filename;
8239 switch(msg)
8241 case WM_INITDIALOG:
8242 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8243 return TRUE;
8245 case WM_COMMAND:
8246 if(HIWORD(wparam) == BN_CLICKED)
8248 if(LOWORD(wparam) == IDOK)
8250 HANDLE hf;
8251 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8252 LPWSTR *output;
8254 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8255 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8257 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8259 WCHAR caption[200], message[200];
8260 int mb_ret;
8262 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8263 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8264 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8265 if(mb_ret == IDCANCEL)
8267 HeapFree(GetProcessHeap(), 0, filename);
8268 return TRUE;
8271 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8272 if(hf == INVALID_HANDLE_VALUE)
8274 WCHAR caption[200], message[200];
8276 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8277 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8278 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8279 HeapFree(GetProcessHeap(), 0, filename);
8280 return TRUE;
8282 CloseHandle(hf);
8283 DeleteFileW(filename);
8284 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8285 *output = filename;
8286 EndDialog(hwnd, IDOK);
8287 return TRUE;
8289 if(LOWORD(wparam) == IDCANCEL)
8291 EndDialog(hwnd, IDCANCEL);
8292 return TRUE;
8295 return FALSE;
8297 return FALSE;
8300 /*****************************************************************************
8301 * get_filename
8303 static BOOL get_filename(LPWSTR *filename)
8305 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8306 file_dlg_proc, (LPARAM)filename) == IDOK;
8309 /*****************************************************************************
8310 * schedule_file
8312 static BOOL schedule_file(LPCWSTR filename)
8314 LPWSTR output = NULL;
8316 if(get_filename(&output))
8318 BOOL r;
8319 TRACE("copy to %s\n", debugstr_w(output));
8320 r = CopyFileW(filename, output, FALSE);
8321 HeapFree(GetProcessHeap(), 0, output);
8322 return r;
8324 return FALSE;
8327 /*****************************************************************************
8328 * schedule_unixfile
8330 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8332 int in_fd, out_fd, no_read;
8333 char buf[1024];
8334 BOOL ret = FALSE;
8335 char *unixname, *outputA;
8336 DWORD len;
8338 if(!(unixname = wine_get_unix_file_name(filename)))
8339 return FALSE;
8341 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8342 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8343 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8345 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8346 in_fd = open(unixname, O_RDONLY);
8347 if(out_fd == -1 || in_fd == -1)
8348 goto end;
8350 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8351 write(out_fd, buf, no_read);
8353 ret = TRUE;
8354 end:
8355 if(in_fd != -1) close(in_fd);
8356 if(out_fd != -1) close(out_fd);
8357 HeapFree(GetProcessHeap(), 0, outputA);
8358 HeapFree(GetProcessHeap(), 0, unixname);
8359 return ret;
8362 /*****************************************************************************
8363 * ScheduleJob [WINSPOOL.@]
8366 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8368 opened_printer_t *printer;
8369 BOOL ret = FALSE;
8370 struct list *cursor, *cursor2;
8372 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8373 EnterCriticalSection(&printer_handles_cs);
8374 printer = get_opened_printer(hPrinter);
8375 if(!printer)
8376 goto end;
8378 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8380 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8381 HANDLE hf;
8383 if(job->job_id != dwJobID) continue;
8385 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8386 if(hf != INVALID_HANDLE_VALUE)
8388 PRINTER_INFO_5W *pi5 = NULL;
8389 LPWSTR portname = job->portname;
8390 DWORD needed;
8391 HKEY hkey;
8392 WCHAR output[1024];
8393 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8394 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8396 if (!portname)
8398 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8399 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8400 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8401 portname = pi5->pPortName;
8403 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8404 debugstr_w(portname));
8406 output[0] = 0;
8408 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8409 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8411 DWORD type, count = sizeof(output);
8412 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8413 RegCloseKey(hkey);
8415 if(output[0] == '|')
8417 ret = schedule_pipe(output + 1, job->filename);
8419 else if(output[0])
8421 ret = schedule_unixfile(output, job->filename);
8423 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8425 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8427 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8429 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8431 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8433 ret = schedule_file(job->filename);
8435 else
8437 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8439 HeapFree(GetProcessHeap(), 0, pi5);
8440 CloseHandle(hf);
8441 DeleteFileW(job->filename);
8443 list_remove(cursor);
8444 HeapFree(GetProcessHeap(), 0, job->document_title);
8445 HeapFree(GetProcessHeap(), 0, job->printer_name);
8446 HeapFree(GetProcessHeap(), 0, job->portname);
8447 HeapFree(GetProcessHeap(), 0, job->filename);
8448 HeapFree(GetProcessHeap(), 0, job->devmode);
8449 HeapFree(GetProcessHeap(), 0, job);
8450 break;
8452 end:
8453 LeaveCriticalSection(&printer_handles_cs);
8454 return ret;
8457 /*****************************************************************************
8458 * StartDocDlgA [WINSPOOL.@]
8460 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8462 UNICODE_STRING usBuffer;
8463 DOCINFOW docW;
8464 LPWSTR retW;
8465 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8466 LPSTR ret = NULL;
8468 docW.cbSize = sizeof(docW);
8469 if (doc->lpszDocName)
8471 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8472 if (!(docW.lpszDocName = docnameW)) return NULL;
8474 if (doc->lpszOutput)
8476 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8477 if (!(docW.lpszOutput = outputW)) return NULL;
8479 if (doc->lpszDatatype)
8481 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8482 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8484 docW.fwType = doc->fwType;
8486 retW = StartDocDlgW(hPrinter, &docW);
8488 if(retW)
8490 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8491 ret = HeapAlloc(GetProcessHeap(), 0, len);
8492 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8493 HeapFree(GetProcessHeap(), 0, retW);
8496 HeapFree(GetProcessHeap(), 0, datatypeW);
8497 HeapFree(GetProcessHeap(), 0, outputW);
8498 HeapFree(GetProcessHeap(), 0, docnameW);
8500 return ret;
8503 /*****************************************************************************
8504 * StartDocDlgW [WINSPOOL.@]
8506 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8507 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8508 * port is "FILE:". Also returns the full path if passed a relative path.
8510 * The caller should free the returned string from the process heap.
8512 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8514 LPWSTR ret = NULL;
8515 DWORD len, attr;
8517 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8519 PRINTER_INFO_5W *pi5;
8520 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8521 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8522 return NULL;
8523 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8524 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8525 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8527 HeapFree(GetProcessHeap(), 0, pi5);
8528 return NULL;
8530 HeapFree(GetProcessHeap(), 0, pi5);
8533 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8535 LPWSTR name;
8537 if (get_filename(&name))
8539 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8541 HeapFree(GetProcessHeap(), 0, name);
8542 return NULL;
8544 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8545 GetFullPathNameW(name, len, ret, NULL);
8546 HeapFree(GetProcessHeap(), 0, name);
8548 return ret;
8551 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8552 return NULL;
8554 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8555 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8557 attr = GetFileAttributesW(ret);
8558 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8560 HeapFree(GetProcessHeap(), 0, ret);
8561 ret = NULL;
8563 return ret;
8566 /*****************************************************************************
8567 * UploadPrinterDriverPackageA [WINSPOOL.@]
8569 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
8570 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
8572 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
8573 flags, hwnd, dst, dstlen);
8574 return E_NOTIMPL;
8577 /*****************************************************************************
8578 * UploadPrinterDriverPackageW [WINSPOOL.@]
8580 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
8581 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
8583 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
8584 flags, hwnd, dst, dstlen);
8585 return E_NOTIMPL;