include/windows.foundation: Add double reference.
[wine.git] / dlls / winspool.drv / info.c
blobb82df25082c87ef1d2ed406a6770c1d9d8d00b7d
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
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <stddef.h>
33 #define NONAMELESSSTRUCT
34 #define NONAMELESSUNION
36 #include "ntstatus.h"
37 #define WIN32_NO_STATUS
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "winerror.h"
42 #include "winreg.h"
43 #include "wingdi.h"
44 #include "winspool.h"
45 #include "winternl.h"
46 #include "winnls.h"
47 #include "wine/windef16.h"
48 #include "wine/debug.h"
49 #include "wine/list.h"
50 #include "wine/rbtree.h"
51 #include "wine/heap.h"
52 #include <wine/unixlib.h>
54 #include "ddk/compstui.h"
55 #include "ddk/winsplp.h"
56 #include "wspool.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
60 /* ############################### */
62 static CRITICAL_SECTION printer_handles_cs;
63 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
65 0, 0, &printer_handles_cs,
66 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
67 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
69 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
71 /* ############################### */
73 typedef struct {
74 LPWSTR name;
75 HANDLE backend_printer;
76 } opened_printer_t;
78 typedef struct {
79 LPCWSTR envname;
80 LPCWSTR subdir;
81 DWORD driverversion;
82 LPCWSTR versionregpath;
83 LPCWSTR versionsubdir;
84 } printenv_t;
86 typedef struct
88 struct wine_rb_entry entry;
89 HMODULE module;
90 LONG ref;
92 /* entry points */
93 DWORD (WINAPI *pDrvDeviceCapabilities)(HANDLE, const WCHAR *, WORD, void *, const DEVMODEW *);
94 LONG (WINAPI *pDrvDocumentPropertySheets)(PROPSHEETUI_INFO*, LPARAM);
96 WCHAR name[1];
97 } config_module_t;
99 typedef struct {
100 WORD cbSize;
101 WORD Reserved;
102 HANDLE hPrinter;
103 LPCWSTR pszPrinterName;
104 PDEVMODEW pdmIn;
105 PDEVMODEW pdmOut;
106 DWORD cbOut;
107 DWORD fMode;
108 } DOCUMENTPROPERTYHEADERW;
110 typedef struct {
111 DOCUMENTPROPERTYHEADERW dph;
112 config_module_t *config;
113 } document_property_t;
115 /* ############################### */
117 static opened_printer_t **printer_handles;
118 static UINT nb_printer_handles;
120 static const WCHAR * const May_Delete_Value = L"WineMayDeleteMe";
122 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
123 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
124 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
125 0, sizeof(DRIVER_INFO_8W)};
128 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
129 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
130 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
131 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
132 sizeof(PRINTER_INFO_9W)};
134 static const printenv_t env_x64 = { L"Windows x64", L"x64", 3, L"\\Version-3", L"\\3" };
135 static const printenv_t env_x86 = { L"Windows NT x86", L"w32x86", 3, L"\\Version-3", L"\\3" };
136 static const printenv_t env_arm = { L"Windows ARM", L"arm", 3, L"\\Version-3", L"\\3" };
137 static const printenv_t env_arm64 = { L"Windows ARM64", L"arm64", 3, L"\\Version-3", L"\\3" };
138 static const printenv_t env_win40 = { L"Windows 4.0", L"win40", 0, L"\\Version-0", L"\\0" };
140 static const printenv_t * const all_printenv[] = { &env_x86, &env_x64, &env_arm, &env_arm64, &env_win40 };
142 #ifdef __i386__
143 #define env_arch env_x86
144 #elif defined __x86_64__
145 #define env_arch env_x64
146 #elif defined __arm__
147 #define env_arch env_arm
148 #elif defined __aarch64__
149 #define env_arch env_arm64
150 #else
151 #error not defined for this cpu
152 #endif
154 /******************************************************************
155 * validate the user-supplied printing-environment [internal]
157 * PARAMS
158 * env [I] PTR to Environment-String or NULL
160 * RETURNS
161 * Failure: NULL
162 * Success: PTR to printenv_t
164 * NOTES
165 * An empty string is handled the same way as NULL.
166 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
170 static const printenv_t * validate_envW(LPCWSTR env)
172 const printenv_t *result = NULL;
173 unsigned int i;
175 TRACE("testing %s\n", debugstr_w(env));
176 if (env && env[0])
178 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
180 if (!wcsicmp( env, all_printenv[i]->envname ))
182 result = all_printenv[i];
183 break;
187 if (result == NULL) {
188 FIXME("unsupported Environment: %s\n", debugstr_w(env));
189 SetLastError(ERROR_INVALID_ENVIRONMENT);
191 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
193 else
195 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_arch;
197 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
199 return result;
203 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
204 if passed a NULL string. This returns NULLs to the result.
206 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
208 if ( (src) )
210 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
211 return usBufferPtr->Buffer;
213 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
214 return NULL;
217 /* stringWtoA
218 * Converts Unicode string to Ansi (possibly in place).
220 static void stringWtoA( const WCHAR *strW, char *strA, size_t size )
222 DWORD ret;
223 char *str;
225 str = (char *)strW == strA ? malloc( size ) : strA;
226 ret = WideCharToMultiByte( CP_ACP, 0, strW, -1, str, size, NULL, NULL );
227 if (str != strA)
229 memcpy( strA, str, ret );
230 free( str );
232 memset( strA + ret, 0, size - ret );
235 /***********************************************************
236 * DEVMODEWtoA
237 * Converts DEVMODEW to DEVMODEA (possibly in place).
238 * Allocates DEVMODEA if needed.
240 static DEVMODEA *DEVMODEWtoA( const DEVMODEW *dmW, DEVMODEA *dmA )
242 DWORD size, sizeW;
244 if (!dmW) return NULL;
245 sizeW = dmW->dmSize;
246 size = sizeW - CCHDEVICENAME -
247 ((sizeW > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
249 if (!dmA)
250 dmA = calloc( 1, size + dmW->dmDriverExtra );
251 if (!dmA) return NULL;
253 stringWtoA( dmW->dmDeviceName, (char *)dmA->dmDeviceName, CCHDEVICENAME );
255 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= sizeW)
257 memmove( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
258 sizeW - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
260 else
262 memmove( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
263 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
264 stringWtoA( dmW->dmFormName, (char *)dmA->dmFormName, CCHFORMNAME );
265 memmove( &dmA->dmLogPixels, &dmW->dmLogPixels, sizeW - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
268 dmA->dmSize = size;
269 memmove( (char *)dmA + dmA->dmSize, (const char *)dmW + sizeW, dmW->dmDriverExtra );
270 return dmA;
273 /*********************************************************************
274 * packed_struct_WtoA
276 * Convert a packed struct from W to A overwriting the unicode strings
277 * with their ansi equivalents.
279 static void packed_struct_WtoA( BYTE *data, const DWORD *string_info )
281 WCHAR *strW;
283 string_info++; /* sizeof */
284 while (*string_info != ~0u)
286 strW = *(WCHAR **)(data + *string_info);
287 if (strW) stringWtoA( strW, (char *)strW, (wcslen(strW) + 1) * sizeof(WCHAR) );
288 string_info++;
292 static inline const DWORD *form_string_info( DWORD level )
294 static const DWORD info_1[] =
296 sizeof( FORM_INFO_1W ),
297 FIELD_OFFSET( FORM_INFO_1W, pName ),
300 static const DWORD info_2[] =
302 sizeof( FORM_INFO_2W ),
303 FIELD_OFFSET( FORM_INFO_2W, pName ),
304 FIELD_OFFSET( FORM_INFO_2W, pMuiDll ),
305 FIELD_OFFSET( FORM_INFO_2W, pDisplayName ),
309 if (level == 1) return info_1;
310 if (level == 2) return info_2;
312 SetLastError( ERROR_INVALID_LEVEL );
313 return NULL;
316 /*****************************************************************************
317 * WINSPOOL_OpenDriverReg [internal]
319 * opens the registry for the printer drivers depending on the given input
320 * variable pEnvironment
322 * RETURNS:
323 * the opened hkey on success
324 * NULL on error
326 static HKEY WINSPOOL_OpenDriverReg(const void *pEnvironment)
328 HKEY retval = NULL;
329 LPWSTR buffer;
330 const printenv_t *env;
331 unsigned int len;
332 static const WCHAR driver_fmt[] = L"System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers%s";
334 TRACE("(%s)\n", debugstr_w(pEnvironment));
336 env = validate_envW(pEnvironment);
337 if (!env) return NULL;
339 len = ARRAY_SIZE( driver_fmt ) + wcslen( env->envname ) + wcslen( env->versionregpath );
340 buffer = malloc( len * sizeof(WCHAR) );
341 if (buffer)
343 swprintf( buffer, len, driver_fmt, env->envname, env->versionregpath );
344 RegCreateKeyW( HKEY_LOCAL_MACHINE, buffer, &retval );
345 free( buffer );
347 return retval;
350 enum printers_key
352 system_printers_key,
353 user_printers_key,
354 user_ports_key,
355 user_default_key,
358 static DWORD create_printers_reg_key( enum printers_key type, HKEY *key )
360 switch( type )
362 case system_printers_key:
363 return RegCreateKeyW( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Print\\Printers", key );
364 case user_printers_key:
365 return RegCreateKeyW( HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices", key );
366 case user_ports_key:
367 return RegCreateKeyW( HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\PrinterPorts", key );
368 case user_default_key:
369 return RegCreateKeyW( HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows", key );
371 return ERROR_PATH_NOT_FOUND;
374 static CRITICAL_SECTION config_modules_cs;
375 static CRITICAL_SECTION_DEBUG config_modules_cs_debug =
377 0, 0, &config_modules_cs,
378 { &config_modules_cs_debug.ProcessLocksList, &config_modules_cs_debug.ProcessLocksList },
379 0, 0, { (DWORD_PTR)(__FILE__ ": config_modules_cs") }
381 static CRITICAL_SECTION config_modules_cs = { &config_modules_cs_debug, -1, 0, 0, 0, 0 };
383 static int compare_config_modules(const void *key, const struct wine_rb_entry *entry)
385 config_module_t *module = WINE_RB_ENTRY_VALUE(entry, config_module_t, entry);
386 return wcsicmp( key, module->name );
389 static struct wine_rb_tree config_modules = { compare_config_modules };
391 static void release_config_module(config_module_t *config_module)
393 if (InterlockedDecrement(&config_module->ref)) return;
394 FreeLibrary(config_module->module);
395 free(config_module);
398 static config_module_t *get_config_module(const WCHAR *device, BOOL grab)
400 WCHAR driver_name[100], driver[MAX_PATH];
401 DWORD size, len;
402 HKEY printers_key, printer_key, drivers_key, driver_key;
403 HMODULE driver_module;
404 config_module_t *ret = NULL;
405 struct wine_rb_entry *entry;
406 DWORD r, type;
407 LSTATUS res;
409 EnterCriticalSection(&config_modules_cs);
410 entry = wine_rb_get(&config_modules, device);
411 if (entry) {
412 ret = WINE_RB_ENTRY_VALUE(entry, config_module_t, entry);
413 if (grab) InterlockedIncrement(&ret->ref);
414 goto ret;
416 if (!grab) goto ret;
418 if (create_printers_reg_key(system_printers_key, &printers_key))
420 ERR("Can't create Printers key\n");
421 goto ret;
424 r = RegOpenKeyW(printers_key, device, &printer_key);
425 RegCloseKey(printers_key);
426 if (r)
428 WARN("Device %s key not found\n", debugstr_w(device));
429 goto ret;
432 size = sizeof(driver_name);
433 r = RegQueryValueExW(printer_key, L"Printer Driver", 0, &type, (BYTE *)driver_name, &size);
434 RegCloseKey(printer_key);
435 if (r || type != REG_SZ)
437 WARN("Can't get Printer Driver name\n");
438 goto ret;
441 if (!(drivers_key = WINSPOOL_OpenDriverReg(NULL))) goto ret;
443 res = RegOpenKeyW(drivers_key, driver_name, &driver_key);
444 RegCloseKey(drivers_key);
445 if (res) {
446 WARN("Driver %s key not found\n", debugstr_w(driver_name));
447 goto ret;
450 size = sizeof(driver);
451 if (!GetPrinterDriverDirectoryW(NULL, NULL, 1, (LPBYTE)driver, size, &size)) goto ret;
453 len = size / sizeof(WCHAR) - 1;
454 driver[len++] = '\\';
455 driver[len++] = '3';
456 driver[len++] = '\\';
457 size = sizeof(driver) - len * sizeof(WCHAR);
458 res = RegQueryValueExW( driver_key, L"Configuration File", NULL, &type,
459 (BYTE *)(driver + len), &size );
460 RegCloseKey(driver_key);
461 if (res || type != REG_SZ) {
462 WARN("no configuration file: %lu\n", res);
463 goto ret;
466 if (!(driver_module = LoadLibraryW(driver))) {
467 WARN("Could not load %s\n", debugstr_w(driver));
468 goto ret;
471 len = wcslen( device );
472 if (!(ret = malloc(FIELD_OFFSET(config_module_t, name[len + 1]))))
473 goto ret;
475 ret->ref = 2; /* one for config_module and one for the caller */
476 ret->module = driver_module;
477 ret->pDrvDeviceCapabilities = (void *)GetProcAddress(driver_module, "DrvDeviceCapabilities");
478 ret->pDrvDocumentPropertySheets = (void *)GetProcAddress(driver_module, "DrvDocumentPropertySheets");
479 wcscpy( ret->name, device );
481 wine_rb_put(&config_modules, ret->name, &ret->entry);
482 ret:
483 LeaveCriticalSection(&config_modules_cs);
484 return ret;
487 /* ################################ */
489 static int multi_sz_lenA(const char *str)
491 const char *ptr = str;
492 if(!str) return 0;
495 ptr += strlen( ptr ) + 1;
496 } while(*ptr);
498 return ptr - str + 1;
501 /*****************************************************************************
502 * get_dword_from_reg
504 * Return DWORD associated with name from hkey.
506 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
508 DWORD sz = sizeof(DWORD), type, value = 0;
509 LONG ret;
511 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
513 if (ret != ERROR_SUCCESS)
515 WARN( "Got ret = %ld on name %s\n", ret, debugstr_w(name) );
516 return 0;
518 if (type != REG_DWORD)
520 ERR( "Got type %ld\n", type );
521 return 0;
523 return value;
526 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
528 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
531 /******************************************************************
532 * get_opened_printer
533 * Get the pointer to the opened printer referred by the handle
535 static opened_printer_t *get_opened_printer(HANDLE hprn)
537 UINT_PTR idx = (UINT_PTR)hprn;
538 opened_printer_t *ret = NULL;
540 EnterCriticalSection(&printer_handles_cs);
542 if ((idx > 0) && (idx <= nb_printer_handles)) {
543 ret = printer_handles[idx - 1];
545 LeaveCriticalSection(&printer_handles_cs);
546 return ret;
549 /******************************************************************
550 * get_opened_printer_name
551 * Get the pointer to the opened printer name referred by the handle
553 static LPCWSTR get_opened_printer_name(HANDLE hprn)
555 opened_printer_t *printer = get_opened_printer(hprn);
556 if(!printer) return NULL;
557 return printer->name;
560 static HANDLE get_backend_handle( HANDLE hprn )
562 opened_printer_t *printer = get_opened_printer( hprn );
563 if (!printer) return NULL;
564 return printer->backend_printer;
567 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
569 HKEY printers;
570 DWORD err;
572 *key = NULL;
573 err = create_printers_reg_key( system_printers_key, &printers );
574 if (err) return err;
576 err = RegOpenKeyW( printers, name, key );
577 if (err) err = ERROR_INVALID_PRINTER_NAME;
578 RegCloseKey( printers );
579 return err;
582 /******************************************************************
583 * WINSPOOL_GetOpenedPrinterRegKey
586 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
588 LPCWSTR name = get_opened_printer_name(hPrinter);
590 if(!name) return ERROR_INVALID_HANDLE;
591 return open_printer_reg_key( name, phkey );
594 static BOOL get_internal_fallback_ppd( const WCHAR *ppd )
596 char *ptr, *end;
597 DWORD size, written;
598 HANDLE file;
599 BOOL ret;
600 HRSRC res = FindResourceW( WINSPOOL_hInstance, MAKEINTRESOURCEW(1), L"PPDFILE" );
602 if (!res || !(ptr = LoadResource( WINSPOOL_hInstance, res ))) return FALSE;
603 size = SizeofResource( WINSPOOL_hInstance, res );
604 end = memchr( ptr, 0, size ); /* resource file may contain additional nulls */
605 if (end) size = end - ptr;
606 file = CreateFileW( ppd, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
607 if (file == INVALID_HANDLE_VALUE) return FALSE;
608 ret = WriteFile( file, ptr, size, &written, NULL ) && written == size;
609 CloseHandle( file );
610 if (ret) TRACE( "using internal fallback for %s\n", debugstr_w( ppd ));
611 else DeleteFileW( ppd );
612 return ret;
615 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
617 static const WCHAR dot_ppd[] = L".ppd";
618 static const WCHAR invalid_chars[] = L"*?<>|\"/\\";
619 int dir_len = wcslen( dir ), file_len = wcslen( file_name );
620 int len = (dir_len + file_len + ARRAY_SIZE( dot_ppd )) * sizeof(WCHAR);
621 WCHAR *ppd = malloc( len ), *p;
623 if (!ppd) return NULL;
624 memcpy( ppd, dir, dir_len * sizeof(WCHAR) );
625 memcpy( ppd + dir_len, file_name, file_len * sizeof(WCHAR) );
626 memcpy( ppd + dir_len + file_len, dot_ppd, sizeof(dot_ppd) );
628 p = ppd + dir_len;
629 while ((p = wcspbrk( p, invalid_chars ))) *p++ = '_';
631 return ppd;
634 static BOOL add_printer_driver( const WCHAR *name, const WCHAR *ppd_dir )
636 WCHAR *ppd = get_ppd_filename( ppd_dir, name );
637 struct get_ppd_params ppd_params;
638 UNICODE_STRING nt_ppd = { .Buffer = NULL };
639 DRIVER_INFO_3W di3;
640 unsigned int i;
641 BOOL res = FALSE;
642 WCHAR raw[] = L"RAW", driver_nt[] = L"wineps.drv";
644 if (!ppd) return FALSE;
645 if (!RtlDosPathNameToNtPathName_U( ppd, &nt_ppd, NULL, NULL )) goto end;
647 ppd_params.printer = name;
648 ppd_params.ppd = nt_ppd.Buffer;
649 res = !UNIX_CALL( get_ppd, &ppd_params ) || get_internal_fallback_ppd( ppd );
650 if (!res) goto end;
652 AddPrintProcessorW(NULL, NULL, driver_nt, (WCHAR *)L"wineps");
654 memset( &di3, 0, sizeof(DRIVER_INFO_3W) );
655 di3.cVersion = 3;
656 di3.pName = (WCHAR *)name;
657 di3.pDriverPath = driver_nt;
658 di3.pDataFile = ppd;
659 di3.pConfigFile = driver_nt;
660 di3.pDefaultDataType = raw;
662 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
664 di3.pEnvironment = (WCHAR *)all_printenv[i]->envname;
665 if (all_printenv[i]->driverversion == 0)
667 WCHAR driver_9x[] = L"wineps16.drv";
668 /* We use wineps16.drv as driver for 16 bit */
669 di3.pDriverPath = driver_9x;
670 di3.pConfigFile = driver_9x;
672 res = AddPrinterDriverExW( NULL, 3, (BYTE *)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY );
673 TRACE( "got %d and %ld for %s (%s)\n", res, GetLastError(), debugstr_w( name ), debugstr_w( di3.pEnvironment ) );
675 if (!res && (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED))
677 ERR( "failed with %lu for %s (%s) %s\n", GetLastError(), debugstr_w( name ),
678 debugstr_w( di3.pEnvironment ), debugstr_w( di3.pDriverPath ) );
679 break;
681 res = TRUE;
683 ppd_params.printer = NULL; /* unlink the ppd */
684 UNIX_CALL( get_ppd, &ppd_params );
686 end:
687 RtlFreeUnicodeString( &nt_ppd );
688 free( ppd );
689 return res;
692 static WCHAR *get_ppd_dir( void )
694 static const WCHAR wine_ppds[] = L"wine_ppds\\";
695 DWORD len;
696 WCHAR *dir, tmp_path[MAX_PATH];
697 BOOL res;
699 len = GetTempPathW( ARRAY_SIZE( tmp_path ), tmp_path );
700 if (!len) return NULL;
701 dir = malloc( len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
702 if (!dir) return NULL;
704 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
705 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
706 res = CreateDirectoryW( dir, NULL );
707 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
709 free( dir );
710 dir = NULL;
712 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
713 return dir;
716 static BOOL init_unix_printers( void )
718 WCHAR *port, *ppd_dir = NULL, *default_printer = NULL;
719 unsigned int size, num;
720 struct enum_printers_params enum_params = { NULL, &size, &num };
721 HKEY printer_key, printers_key;
722 HANDLE added_printer;
723 PRINTER_INFO_2W pi2;
724 NTSTATUS status;
725 WCHAR raw[] = L"RAW", wineps[] = L"wineps", empty[] = L"";
726 int i;
728 if (create_printers_reg_key( system_printers_key, &printers_key ))
730 ERR( "Can't create Printers key\n" );
731 return FALSE;
734 size = 10000;
737 size *= 2;
738 free( enum_params.printers );
739 enum_params.printers = malloc( size );
740 status = UNIX_CALL( enum_printers, &enum_params );
741 } while (status == STATUS_BUFFER_OVERFLOW);
742 if (status) goto end;
744 TRACE( "Found %d CUPS %s:\n", num, (num == 1) ? "printer" : "printers" );
745 for (i = 0; i < num; i++)
747 struct printer_info *printer = enum_params.printers + i;
749 if (RegOpenKeyW( printers_key, printer->name, &printer_key ) == ERROR_SUCCESS)
751 DWORD status = get_dword_from_reg( printer_key, L"Status" );
752 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
753 and continue */
754 TRACE("Printer already exists\n");
755 RegDeleteValueW( printer_key, May_Delete_Value );
756 /* flag that the PPD file should be checked for an update */
757 set_reg_DWORD( printer_key, L"Status", status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
758 RegSetValueExW( printer_key, L"Print Processor", 0, REG_SZ, (const BYTE*)wineps,
759 (wcslen( wineps ) + 1) * sizeof(WCHAR));
760 RegCloseKey( printer_key );
762 else
764 if (!ppd_dir && !(ppd_dir = get_ppd_dir())) break;
765 if (!add_printer_driver( printer->name, ppd_dir )) continue;
767 port = malloc( sizeof(L"CUPS:") + wcslen( printer->name ) * sizeof(WCHAR) );
768 wcscpy( port, L"CUPS:" );
769 wcscat( port, printer->name );
771 memset( &pi2, 0, sizeof(PRINTER_INFO_2W) );
772 pi2.pPrinterName = printer->name;
773 pi2.pDatatype = raw;
774 pi2.pPrintProcessor = wineps;
775 pi2.pDriverName = printer->name;
776 pi2.pComment = printer->comment;
777 pi2.pLocation = printer->location;
778 pi2.pPortName = port;
779 pi2.pParameters = empty;
780 pi2.pShareName = empty;
781 pi2.pSepFile = empty;
783 added_printer = AddPrinterW( NULL, 2, (BYTE *)&pi2 );
784 if (added_printer) ClosePrinter( added_printer );
785 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
786 ERR( "printer '%s' not added by AddPrinter (error %ld)\n", debugstr_w( printer->name ), GetLastError() );
788 free( port );
790 if (printer->is_default) default_printer = printer->name;
793 if (!default_printer && num) default_printer = enum_params.printers[0].name;
794 if (default_printer) SetDefaultPrinterW( default_printer );
796 if (ppd_dir)
798 RemoveDirectoryW( ppd_dir );
799 free( ppd_dir );
801 end:
802 free( enum_params.printers );
803 RegCloseKey( printers_key );
804 return TRUE;
807 static void set_ppd_overrides( HANDLE printer )
809 WCHAR buffer[256];
810 unsigned int name_size = sizeof(buffer);
811 struct get_default_page_size_params params = { .name = buffer, .name_size = &name_size };
812 NTSTATUS status;
814 while (1)
816 status = UNIX_CALL( get_default_page_size, &params );
817 if (status != STATUS_BUFFER_OVERFLOW) break;
818 if (params.name != buffer) free( params.name );
819 params.name = malloc( name_size );
820 if (!params.name) break;
822 if (!status) SetPrinterDataExW( printer, L"PPD Overrides", L"DefaultPageSize", REG_SZ, (BYTE*)params.name, name_size );
823 if (params.name != buffer) free( params.name );
826 static BOOL update_driver( HANDLE printer )
828 BOOL ret;
829 const WCHAR *name = get_opened_printer_name( printer );
830 WCHAR *ppd_dir;
832 if (!name) return FALSE;
833 if (!(ppd_dir = get_ppd_dir())) return FALSE;
835 TRACE( "updating driver %s\n", debugstr_w( name ) );
836 ret = add_printer_driver( name, ppd_dir );
838 free( ppd_dir );
840 set_ppd_overrides( printer );
842 /* call into the driver to update the devmode */
843 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
845 return ret;
848 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
850 if (value)
851 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
852 (wcslen( value ) + 1) * sizeof(WCHAR));
853 else
854 return ERROR_FILE_NOT_FOUND;
857 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
859 DEVMODEA *dmA = DEVMODEWtoA( dm, NULL );
860 DWORD ret = ERROR_FILE_NOT_FOUND;
862 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
863 and we support these drivers. NT writes DEVMODEW so somehow
864 we'll need to distinguish between these when we support NT
865 drivers */
867 if (dmA)
869 ret = RegSetValueExW( key, name, 0, REG_BINARY,
870 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
871 free( dmA );
874 return ret;
877 /******************************************************************
878 * get_servername_from_name (internal)
880 * for an external server, a copy of the serverpart from the full name is returned
883 static LPWSTR get_servername_from_name(LPCWSTR name)
885 LPWSTR server;
886 LPWSTR ptr;
887 WCHAR buffer[MAX_PATH];
888 DWORD len;
890 if (name == NULL) return NULL;
891 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
893 server = wcsdup(&name[2]); /* skip over both backslashes */
894 if (server == NULL) return NULL;
896 /* strip '\' and the printername */
897 ptr = wcschr( server, '\\' );
898 if (ptr) ptr[0] = '\0';
900 TRACE("found %s\n", debugstr_w(server));
902 len = ARRAY_SIZE(buffer);
903 if (GetComputerNameW(buffer, &len))
905 if (!wcscmp( buffer, server ))
907 /* The requested Servername is our computername */
908 free(server);
909 return NULL;
912 return server;
915 /******************************************************************
916 * get_basename_from_name (internal)
918 * skip over the serverpart from the full name
921 static LPCWSTR get_basename_from_name(LPCWSTR name)
923 if (name == NULL) return NULL;
924 if ((name[0] == '\\') && (name[1] == '\\'))
926 /* skip over the servername and search for the following '\' */
927 name = wcschr( &name[2], '\\' );
928 if ((name) && (name[1]))
930 /* found a separator ('\') followed by a name:
931 skip over the separator and return the rest */
932 name++;
934 else
936 /* no basename present (we found only a servername) */
937 return NULL;
940 return name;
943 static void free_printer_entry( opened_printer_t *printer )
945 /* the queue is shared, so don't free that here */
946 free( printer->name );
947 free( printer );
950 /******************************************************************
951 * get_opened_printer_entry
952 * Get the first place empty in the opened printer table
954 * ToDo:
955 * - pDefault is ignored
957 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
959 opened_printer_t *printer = NULL;
960 LPWSTR servername;
961 LPCWSTR printername;
962 UINT_PTR handle;
964 if ((backend == NULL) && !load_backend()) return NULL;
966 servername = get_servername_from_name(name);
967 if (servername) {
968 FIXME("server %s not supported\n", debugstr_w(servername));
969 free(servername);
970 SetLastError(ERROR_INVALID_PRINTER_NAME);
971 return NULL;
974 printername = get_basename_from_name(name);
975 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
977 /* an empty printername is invalid */
978 if (printername && (!printername[0])) {
979 SetLastError(ERROR_INVALID_PARAMETER);
980 return NULL;
983 EnterCriticalSection(&printer_handles_cs);
985 for (handle = 0; handle < nb_printer_handles; handle++)
987 if (!printer_handles[handle])
988 break;
991 if (handle >= nb_printer_handles)
993 opened_printer_t **new_array;
994 if (printer_handles)
996 new_array = realloc(printer_handles, (nb_printer_handles + 16) * sizeof(*new_array));
997 memset(new_array + nb_printer_handles, 0, 16 * sizeof(*new_array));
999 else
1001 new_array = calloc(nb_printer_handles + 16, sizeof(*new_array));
1004 if (!new_array)
1006 handle = 0;
1007 goto end;
1009 printer_handles = new_array;
1010 nb_printer_handles += 16;
1013 if (!(printer = calloc(1, sizeof(*printer))))
1015 handle = 0;
1016 goto end;
1019 /* get a printer handle from the backend */
1020 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1021 handle = 0;
1022 goto end;
1025 /* clone the full name */
1026 printer->name = wcsdup(name);
1027 if (name && (!printer->name)) {
1028 handle = 0;
1029 goto end;
1032 printer_handles[handle] = printer;
1033 handle++;
1034 end:
1035 LeaveCriticalSection(&printer_handles_cs);
1036 if (!handle && printer)
1037 free_printer_entry( printer );
1039 return (HANDLE)handle;
1042 static void old_printer_check( BOOL delete_phase )
1044 PRINTER_INFO_5W* pi;
1045 DWORD needed, type, num, delete, i, size;
1046 const DWORD one = 1;
1047 HKEY key;
1048 HANDLE hprn;
1050 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1051 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1053 pi = malloc( needed );
1054 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1055 for (i = 0; i < num; i++)
1057 if (!pi[i].pPortName) continue;
1059 if (wcsncmp( pi[i].pPortName, L"CUPS:", ARRAY_SIZE(L"CUPS:") - 1 ) &&
1060 wcsncmp( pi[i].pPortName, L"LPR:", ARRAY_SIZE(L"LPR:") - 1 ))
1061 continue;
1063 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1065 if (!delete_phase)
1067 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1068 RegCloseKey( key );
1070 else
1072 delete = 0;
1073 size = sizeof( delete );
1074 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1075 RegCloseKey( key );
1076 if (delete)
1078 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1079 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1081 DeletePrinter( hprn );
1082 ClosePrinter( hprn );
1084 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1088 free(pi);
1091 static HANDLE init_mutex;
1093 void WINSPOOL_LoadSystemPrinters(void)
1095 HKEY printers_key, printer_key;
1096 DWORD needed, num, i;
1097 WCHAR PrinterName[256];
1099 /* FIXME: The init code should be moved to spoolsv.exe */
1100 init_mutex = CreateMutexW( NULL, TRUE, L"__WINE_WINSPOOL_MUTEX__" );
1101 if (!init_mutex)
1103 ERR( "Failed to create mutex\n" );
1104 return;
1106 if (GetLastError() == ERROR_ALREADY_EXISTS)
1108 WaitForSingleObject( init_mutex, INFINITE );
1109 ReleaseMutex( init_mutex );
1110 TRACE( "Init already done\n" );
1111 return;
1114 /* This ensures that all printer entries have a valid Name value. If causes
1115 problems later if they don't. If one is found to be missed we create one
1116 and set it equal to the name of the key */
1117 if (!create_printers_reg_key( system_printers_key, &printers_key ))
1119 if (!RegQueryInfoKeyW( printers_key, NULL, NULL, NULL, &num, NULL, NULL, NULL, NULL, NULL, NULL, NULL ))
1120 for (i = 0; i < num; i++)
1121 if (!RegEnumKeyW( printers_key, i, PrinterName, ARRAY_SIZE(PrinterName) ))
1122 if (!RegOpenKeyW( printers_key, PrinterName, &printer_key ))
1124 if (RegQueryValueExW( printer_key, L"Name", 0, 0, 0, &needed ) == ERROR_FILE_NOT_FOUND)
1125 set_reg_szW( printer_key, L"Name", PrinterName );
1126 RegCloseKey( printer_key );
1128 RegCloseKey( printers_key );
1131 old_printer_check( FALSE );
1132 init_unix_printers();
1133 old_printer_check( TRUE );
1135 ReleaseMutex( init_mutex );
1136 return;
1139 /******************************************************************
1140 * convert_printerinfo_W_to_A [internal]
1143 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1144 DWORD level, DWORD outlen, DWORD numentries)
1146 DWORD id = 0;
1147 LPSTR ptr;
1148 INT len;
1150 TRACE("(%p, %p, %ld, %lu, %lu)\n", out, pPrintersW, level, outlen, numentries);
1152 len = pi_sizeof[level] * numentries;
1153 ptr = (LPSTR) out + len;
1154 outlen -= len;
1156 /* copy the numbers of all PRINTER_INFO_* first */
1157 memcpy(out, pPrintersW, len);
1159 while (id < numentries) {
1160 switch (level) {
1161 case 1:
1163 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1164 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1166 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(piW->pName));
1167 if (piW->pDescription) {
1168 piA->pDescription = ptr;
1169 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1170 ptr, outlen, NULL, NULL);
1171 ptr += len;
1172 outlen -= len;
1174 if (piW->pName) {
1175 piA->pName = ptr;
1176 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1177 ptr, outlen, NULL, NULL);
1178 ptr += len;
1179 outlen -= len;
1181 if (piW->pComment) {
1182 piA->pComment = ptr;
1183 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1184 ptr, outlen, NULL, NULL);
1185 ptr += len;
1186 outlen -= len;
1188 break;
1191 case 2:
1193 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1194 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1196 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(piW->pPrinterName));
1197 if (piW->pServerName) {
1198 piA->pServerName = ptr;
1199 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1200 ptr, outlen, NULL, NULL);
1201 ptr += len;
1202 outlen -= len;
1204 if (piW->pPrinterName) {
1205 piA->pPrinterName = ptr;
1206 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1207 ptr, outlen, NULL, NULL);
1208 ptr += len;
1209 outlen -= len;
1211 if (piW->pShareName) {
1212 piA->pShareName = ptr;
1213 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1214 ptr, outlen, NULL, NULL);
1215 ptr += len;
1216 outlen -= len;
1218 if (piW->pPortName) {
1219 piA->pPortName = ptr;
1220 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1221 ptr, outlen, NULL, NULL);
1222 ptr += len;
1223 outlen -= len;
1225 if (piW->pDriverName) {
1226 piA->pDriverName = ptr;
1227 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1228 ptr, outlen, NULL, NULL);
1229 ptr += len;
1230 outlen -= len;
1232 if (piW->pComment) {
1233 piA->pComment = ptr;
1234 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1235 ptr, outlen, NULL, NULL);
1236 ptr += len;
1237 outlen -= len;
1239 if (piW->pLocation) {
1240 piA->pLocation = ptr;
1241 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1242 ptr, outlen, NULL, NULL);
1243 ptr += len;
1244 outlen -= len;
1247 if (piW->pDevMode)
1249 /* align DEVMODEA to a DWORD boundary */
1250 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1251 ptr += len;
1252 outlen -= len;
1254 piA->pDevMode = (LPDEVMODEA) ptr;
1255 DEVMODEWtoA(piW->pDevMode, piA->pDevMode);
1256 len = piA->pDevMode->dmSize + piA->pDevMode->dmDriverExtra;
1258 ptr += len;
1259 outlen -= len;
1262 if (piW->pSepFile) {
1263 piA->pSepFile = ptr;
1264 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1265 ptr, outlen, NULL, NULL);
1266 ptr += len;
1267 outlen -= len;
1269 if (piW->pPrintProcessor) {
1270 piA->pPrintProcessor = ptr;
1271 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1272 ptr, outlen, NULL, NULL);
1273 ptr += len;
1274 outlen -= len;
1276 if (piW->pDatatype) {
1277 piA->pDatatype = ptr;
1278 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1279 ptr, outlen, NULL, NULL);
1280 ptr += len;
1281 outlen -= len;
1283 if (piW->pParameters) {
1284 piA->pParameters = ptr;
1285 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1286 ptr, outlen, NULL, NULL);
1287 ptr += len;
1288 outlen -= len;
1290 if (piW->pSecurityDescriptor) {
1291 piA->pSecurityDescriptor = NULL;
1292 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1294 break;
1297 case 4:
1299 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1300 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1302 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(piW->pPrinterName));
1304 if (piW->pPrinterName) {
1305 piA->pPrinterName = ptr;
1306 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1307 ptr, outlen, NULL, NULL);
1308 ptr += len;
1309 outlen -= len;
1311 if (piW->pServerName) {
1312 piA->pServerName = ptr;
1313 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1314 ptr, outlen, NULL, NULL);
1315 ptr += len;
1316 outlen -= len;
1318 break;
1321 case 5:
1323 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1324 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1326 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(piW->pPrinterName));
1328 if (piW->pPrinterName) {
1329 piA->pPrinterName = ptr;
1330 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1331 ptr, outlen, NULL, NULL);
1332 ptr += len;
1333 outlen -= len;
1335 if (piW->pPortName) {
1336 piA->pPortName = ptr;
1337 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1338 ptr, outlen, NULL, NULL);
1339 ptr += len;
1340 outlen -= len;
1342 break;
1345 case 6: /* 6A and 6W are the same structure */
1346 break;
1348 case 7:
1350 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1351 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1353 TRACE("(%lu) #%lu\n", level, id);
1354 if (piW->pszObjectGUID) {
1355 piA->pszObjectGUID = ptr;
1356 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1357 ptr, outlen, NULL, NULL);
1358 ptr += len;
1359 outlen -= len;
1361 break;
1364 case 8:
1365 case 9:
1367 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1368 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1370 TRACE("(%lu) #%lu\n", level, id);
1371 if (piW->pDevMode)
1373 /* align DEVMODEA to a DWORD boundary */
1374 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1375 ptr += len;
1376 outlen -= len;
1378 piA->pDevMode = (LPDEVMODEA) ptr;
1379 DEVMODEWtoA(piW->pDevMode, piA->pDevMode);
1380 len = piA->pDevMode->dmSize + piA->pDevMode->dmDriverExtra;
1382 ptr += len;
1383 outlen -= len;
1385 break;
1388 default:
1389 FIXME("for level %lu\n", level);
1391 pPrintersW += pi_sizeof[level];
1392 out += pi_sizeof[level];
1393 id++;
1397 /******************************************************************
1398 * convert_driverinfo_W_to_A [internal]
1401 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1402 DWORD level, DWORD outlen, DWORD numentries)
1404 DWORD id = 0;
1405 LPSTR ptr;
1406 INT len;
1408 TRACE("(%p, %p, %ld, %lu, %lu)\n", out, pDriversW, level, outlen, numentries);
1410 len = di_sizeof[level] * numentries;
1411 ptr = (LPSTR) out + len;
1412 outlen -= len;
1414 /* copy the numbers of all PRINTER_INFO_* first */
1415 memcpy(out, pDriversW, len);
1417 #define COPY_STRING(fld) \
1418 { if (diW->fld){ \
1419 diA->fld = ptr; \
1420 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1421 ptr += len; outlen -= len;\
1423 #define COPY_MULTIZ_STRING(fld) \
1424 { LPWSTR p = diW->fld; if (p){ \
1425 diA->fld = ptr; \
1426 do {\
1427 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1428 ptr += len; outlen -= len; p += len;\
1430 while(len > 1 && outlen > 0); \
1433 while (id < numentries)
1435 switch (level)
1437 case 1:
1439 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1440 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1442 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1444 COPY_STRING(pName);
1445 break;
1447 case 2:
1449 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1450 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1452 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1454 COPY_STRING(pName);
1455 COPY_STRING(pEnvironment);
1456 COPY_STRING(pDriverPath);
1457 COPY_STRING(pDataFile);
1458 COPY_STRING(pConfigFile);
1459 break;
1461 case 3:
1463 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1464 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1466 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1468 COPY_STRING(pName);
1469 COPY_STRING(pEnvironment);
1470 COPY_STRING(pDriverPath);
1471 COPY_STRING(pDataFile);
1472 COPY_STRING(pConfigFile);
1473 COPY_STRING(pHelpFile);
1474 COPY_MULTIZ_STRING(pDependentFiles);
1475 COPY_STRING(pMonitorName);
1476 COPY_STRING(pDefaultDataType);
1477 break;
1479 case 4:
1481 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1482 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1484 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1486 COPY_STRING(pName);
1487 COPY_STRING(pEnvironment);
1488 COPY_STRING(pDriverPath);
1489 COPY_STRING(pDataFile);
1490 COPY_STRING(pConfigFile);
1491 COPY_STRING(pHelpFile);
1492 COPY_MULTIZ_STRING(pDependentFiles);
1493 COPY_STRING(pMonitorName);
1494 COPY_STRING(pDefaultDataType);
1495 COPY_MULTIZ_STRING(pszzPreviousNames);
1496 break;
1498 case 5:
1500 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1501 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1503 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1505 COPY_STRING(pName);
1506 COPY_STRING(pEnvironment);
1507 COPY_STRING(pDriverPath);
1508 COPY_STRING(pDataFile);
1509 COPY_STRING(pConfigFile);
1510 break;
1512 case 6:
1514 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1515 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1517 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1519 COPY_STRING(pName);
1520 COPY_STRING(pEnvironment);
1521 COPY_STRING(pDriverPath);
1522 COPY_STRING(pDataFile);
1523 COPY_STRING(pConfigFile);
1524 COPY_STRING(pHelpFile);
1525 COPY_MULTIZ_STRING(pDependentFiles);
1526 COPY_STRING(pMonitorName);
1527 COPY_STRING(pDefaultDataType);
1528 COPY_MULTIZ_STRING(pszzPreviousNames);
1529 COPY_STRING(pszMfgName);
1530 COPY_STRING(pszOEMUrl);
1531 COPY_STRING(pszHardwareID);
1532 COPY_STRING(pszProvider);
1533 break;
1535 case 8:
1537 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1538 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1540 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1542 COPY_STRING(pName);
1543 COPY_STRING(pEnvironment);
1544 COPY_STRING(pDriverPath);
1545 COPY_STRING(pDataFile);
1546 COPY_STRING(pConfigFile);
1547 COPY_STRING(pHelpFile);
1548 COPY_MULTIZ_STRING(pDependentFiles);
1549 COPY_STRING(pMonitorName);
1550 COPY_STRING(pDefaultDataType);
1551 COPY_MULTIZ_STRING(pszzPreviousNames);
1552 COPY_STRING(pszMfgName);
1553 COPY_STRING(pszOEMUrl);
1554 COPY_STRING(pszHardwareID);
1555 COPY_STRING(pszProvider);
1556 COPY_STRING(pszPrintProcessor);
1557 COPY_STRING(pszVendorSetup);
1558 COPY_MULTIZ_STRING(pszzColorProfiles);
1559 COPY_STRING(pszInfPath);
1560 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1561 break;
1565 default:
1566 FIXME("for level %lu\n", level);
1569 pDriversW += di_sizeof[level];
1570 out += di_sizeof[level];
1571 id++;
1574 #undef COPY_STRING
1575 #undef COPY_MULTIZ_STRING
1579 /***********************************************************
1580 * printer_info_AtoW
1582 static void *printer_info_AtoW( const void *data, DWORD level )
1584 void *ret;
1585 UNICODE_STRING usBuffer;
1587 if (!data) return NULL;
1589 if (level < 1 || level > 9) return NULL;
1591 ret = malloc( pi_sizeof[level] );
1592 if (!ret) return NULL;
1594 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1596 switch (level)
1598 case 2:
1600 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1601 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1603 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1604 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1605 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1606 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1607 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1608 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1609 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1610 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1611 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1612 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1613 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1614 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1615 break;
1618 case 8:
1619 case 9:
1621 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1622 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1624 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1625 break;
1628 default:
1629 FIXME( "Unhandled level %ld\n", level );
1630 free( ret );
1631 return NULL;
1634 return ret;
1637 /***********************************************************
1638 * free_printer_info
1640 static void free_printer_info( void *data, DWORD level )
1642 if (!data) return;
1644 switch (level)
1646 case 2:
1648 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1650 free( piW->pServerName );
1651 free( piW->pPrinterName );
1652 free( piW->pShareName );
1653 free( piW->pPortName );
1654 free( piW->pDriverName );
1655 free( piW->pComment );
1656 free( piW->pLocation );
1657 heap_free( piW->pDevMode );
1658 free( piW->pSepFile );
1659 free( piW->pPrintProcessor );
1660 free( piW->pDatatype );
1661 free( piW->pParameters );
1662 break;
1665 case 8:
1666 case 9:
1668 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1670 heap_free( piW->pDevMode );
1671 break;
1674 default:
1675 FIXME( "Unhandled level %ld\n", level );
1678 free( data );
1679 return;
1682 /******************************************************************
1683 * DeviceCapabilities [WINSPOOL.@]
1684 * DeviceCapabilitiesA [WINSPOOL.@]
1687 INT WINAPI DeviceCapabilitiesA(const char *device, const char *portA, WORD cap,
1688 char *output, DEVMODEA *devmodeA)
1690 WCHAR *device_name = NULL, *port = NULL;
1691 DEVMODEW *devmode = NULL;
1692 DWORD ret, len;
1694 len = MultiByteToWideChar(CP_ACP, 0, device, -1, NULL, 0);
1695 if (len) {
1696 device_name = malloc(len * sizeof(WCHAR));
1697 MultiByteToWideChar(CP_ACP, 0, device, -1, device_name, len);
1700 len = MultiByteToWideChar(CP_ACP, 0, portA, -1, NULL, 0);
1701 if (len) {
1702 port = malloc(len * sizeof(WCHAR));
1703 MultiByteToWideChar(CP_ACP, 0, portA, -1, port, len);
1706 if (devmodeA) devmode = GdiConvertToDevmodeW( devmodeA );
1708 if (output && (cap == DC_BINNAMES || cap == DC_FILEDEPENDENCIES || cap == DC_PAPERNAMES)) {
1709 /* These need A -> W translation */
1710 unsigned int size = 0, i;
1711 WCHAR *outputW;
1713 ret = DeviceCapabilitiesW(device_name, port, cap, NULL, devmode);
1714 if (ret == -1) goto cleanup;
1716 switch (cap) {
1717 case DC_BINNAMES:
1718 size = 24;
1719 break;
1720 case DC_PAPERNAMES:
1721 case DC_FILEDEPENDENCIES:
1722 size = 64;
1723 break;
1725 outputW = malloc(size * ret * sizeof(WCHAR));
1726 ret = DeviceCapabilitiesW(device_name, port, cap, outputW, devmode);
1727 for (i = 0; i < ret; i++)
1728 WideCharToMultiByte(CP_ACP, 0, outputW + (i * size), -1,
1729 output + (i * size), size, NULL, NULL);
1730 free(outputW);
1731 } else {
1732 ret = DeviceCapabilitiesW(device_name, port, cap, (WCHAR *)output, devmode);
1734 cleanup:
1735 free(device_name);
1736 heap_free(devmode);
1737 free(port);
1738 return ret;
1741 /*****************************************************************************
1742 * DeviceCapabilitiesW [WINSPOOL.@]
1745 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1746 WORD fwCapability, LPWSTR pOutput,
1747 const DEVMODEW *pDevMode)
1749 config_module_t *config;
1750 int ret;
1752 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability,
1753 pOutput, pDevMode);
1755 if (!(config = get_config_module(pDevice, TRUE))) {
1756 WARN("Could not load config module for %s\n", debugstr_w(pDevice));
1757 return 0;
1760 ret = config->pDrvDeviceCapabilities(NULL /* FIXME */, pDevice, fwCapability,
1761 pOutput, pDevMode);
1762 release_config_module(config);
1763 return ret;
1766 /******************************************************************
1767 * DocumentPropertiesA [WINSPOOL.@]
1769 LONG WINAPI DocumentPropertiesA(HWND hwnd, HANDLE printer, char *device_name, DEVMODEA *output,
1770 DEVMODEA *input, DWORD mode)
1772 DEVMODEW *outputW = NULL, *inputW = NULL;
1773 WCHAR *device = NULL;
1774 unsigned int len;
1775 int ret;
1777 TRACE("(%p,%p,%s,%p,%p,%ld)\n", hwnd, printer, debugstr_a(device_name), output, input, mode);
1779 len = MultiByteToWideChar(CP_ACP, 0, device_name, -1, NULL, 0);
1780 if (len) {
1781 device = malloc(len * sizeof(WCHAR));
1782 MultiByteToWideChar(CP_ACP, 0, device_name, -1, device, len);
1785 if (output && (mode & (DM_COPY | DM_UPDATE))) {
1786 ret = DocumentPropertiesW(hwnd, printer, device, NULL, NULL, 0);
1787 if (ret <= 0) {
1788 free(device);
1789 return -1;
1791 outputW = malloc(ret);
1794 if (input && (mode & DM_IN_BUFFER)) inputW = GdiConvertToDevmodeW(input);
1796 ret = DocumentPropertiesW(hwnd, printer, device, outputW, inputW, mode);
1798 if (ret >= 0 && outputW && (mode & (DM_COPY | DM_UPDATE)))
1799 DEVMODEWtoA( outputW, output );
1801 free(device);
1802 heap_free(inputW);
1803 free(outputW);
1805 if (!mode && ret > 0) ret -= CCHDEVICENAME + CCHFORMNAME;
1806 return ret;
1809 static LONG WINAPI document_callback(PROPSHEETUI_INFO *info, LPARAM lparam)
1811 if (info->Reason == PROPSHEETUI_REASON_INIT)
1813 document_property_t *dp = (document_property_t *)info->lParamInit;
1815 if (!info->pfnComPropSheet(info->hComPropSheet, CPSFUNC_ADD_PFNPROPSHEETUIW,
1816 (LPARAM)dp->config->pDrvDocumentPropertySheets, (LPARAM)&dp->dph))
1817 return ERR_CPSUI_GETLASTERROR;
1819 return CPSUI_OK;
1822 /*****************************************************************************
1823 * DocumentPropertiesW (WINSPOOL.@)
1825 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1826 LPWSTR pDeviceName,
1827 LPDEVMODEW pDevModeOutput,
1828 LPDEVMODEW pDevModeInput, DWORD fMode)
1830 document_property_t dp;
1831 const WCHAR *device;
1832 LONG ret;
1834 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1835 hWnd, hPrinter, debugstr_w(pDeviceName), pDevModeOutput, pDevModeInput, fMode);
1837 device = hPrinter ? get_opened_printer_name(hPrinter) : pDeviceName;
1838 if (!device) {
1839 ERR("no device name\n");
1840 return -1;
1843 dp.dph.cbSize = sizeof(dp.dph);
1844 dp.dph.Reserved = 0;
1845 dp.dph.hPrinter = hPrinter;
1846 dp.dph.pszPrinterName = device;
1847 dp.dph.pdmIn = pDevModeInput;
1848 dp.dph.pdmOut = pDevModeOutput;
1849 dp.dph.cbOut = dp.dph.pdmOut ? dp.dph.pdmOut->dmSize : 0;
1850 dp.dph.fMode = fMode;
1851 dp.config = get_config_module(device, TRUE);
1852 if (!dp.config) {
1853 ERR("Could not load config module for %s\n", debugstr_w(device));
1854 return -1;
1857 if (!(fMode & ~(DM_IN_BUFFER | DM_OUT_BUFFER | DM_OUT_DEFAULT))) {
1858 ret = dp.config->pDrvDocumentPropertySheets(NULL, (LPARAM)&dp.dph);
1860 if ((!fMode || !pDevModeOutput) && dp.dph.cbOut != ret)
1861 FIXME("size mismatch: ret = %ld cbOut = %ld\n", ret, dp.dph.cbOut);
1862 } else {
1863 ret = CommonPropertySheetUIW(hWnd, document_callback, (LPARAM)&dp, NULL);
1866 release_config_module(dp.config);
1867 return ret;
1870 /*****************************************************************************
1871 * IsValidDevmodeA [WINSPOOL.@]
1873 * Validate a DEVMODE structure and fix errors if possible.
1876 BOOL WINAPI IsValidDevmodeA(PDEVMODEA pDevMode, SIZE_T size)
1878 FIXME("(%p,%Id): stub\n", pDevMode, size);
1880 if(!pDevMode)
1881 return FALSE;
1883 return TRUE;
1886 /*****************************************************************************
1887 * IsValidDevmodeW [WINSPOOL.@]
1889 * Validate a DEVMODE structure and fix errors if possible.
1892 BOOL WINAPI IsValidDevmodeW(PDEVMODEW dm, SIZE_T size)
1894 static const struct
1896 DWORD flag;
1897 SIZE_T size;
1898 } map[] =
1900 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
1901 { DM_ORIENTATION, F_SIZE(u1.s1.dmOrientation) },
1902 { DM_PAPERSIZE, F_SIZE(u1.s1.dmPaperSize) },
1903 { DM_PAPERLENGTH, F_SIZE(u1.s1.dmPaperLength) },
1904 { DM_PAPERWIDTH, F_SIZE(u1.s1.dmPaperWidth) },
1905 { DM_SCALE, F_SIZE(u1.s1.dmScale) },
1906 { DM_COPIES, F_SIZE(u1.s1.dmCopies) },
1907 { DM_DEFAULTSOURCE, F_SIZE(u1.s1.dmDefaultSource) },
1908 { DM_PRINTQUALITY, F_SIZE(u1.s1.dmPrintQuality) },
1909 { DM_POSITION, F_SIZE(u1.s2.dmPosition) },
1910 { DM_DISPLAYORIENTATION, F_SIZE(u1.s2.dmDisplayOrientation) },
1911 { DM_DISPLAYFIXEDOUTPUT, F_SIZE(u1.s2.dmDisplayFixedOutput) },
1912 { DM_COLOR, F_SIZE(dmColor) },
1913 { DM_DUPLEX, F_SIZE(dmDuplex) },
1914 { DM_YRESOLUTION, F_SIZE(dmYResolution) },
1915 { DM_TTOPTION, F_SIZE(dmTTOption) },
1916 { DM_COLLATE, F_SIZE(dmCollate) },
1917 { DM_FORMNAME, F_SIZE(dmFormName) },
1918 { DM_LOGPIXELS, F_SIZE(dmLogPixels) },
1919 { DM_BITSPERPEL, F_SIZE(dmBitsPerPel) },
1920 { DM_PELSWIDTH, F_SIZE(dmPelsWidth) },
1921 { DM_PELSHEIGHT, F_SIZE(dmPelsHeight) },
1922 { DM_DISPLAYFLAGS, F_SIZE(u2.dmDisplayFlags) },
1923 { DM_NUP, F_SIZE(u2.dmNup) },
1924 { DM_DISPLAYFREQUENCY, F_SIZE(dmDisplayFrequency) },
1925 { DM_ICMMETHOD, F_SIZE(dmICMMethod) },
1926 { DM_ICMINTENT, F_SIZE(dmICMIntent) },
1927 { DM_MEDIATYPE, F_SIZE(dmMediaType) },
1928 { DM_DITHERTYPE, F_SIZE(dmDitherType) },
1929 { DM_PANNINGWIDTH, F_SIZE(dmPanningWidth) },
1930 { DM_PANNINGHEIGHT, F_SIZE(dmPanningHeight) }
1931 #undef F_SIZE
1933 int i;
1934 const DWORD fields_off = FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(dm->dmFields);
1936 if (!dm) return FALSE;
1937 if (size < fields_off) return FALSE;
1938 if (dm->dmSize < fields_off || size < dm->dmSize + dm->dmDriverExtra) return FALSE;
1940 for (i = 0; i < ARRAY_SIZE(map); i++)
1941 if ((dm->dmFields & map[i].flag) && dm->dmSize < map[i].size)
1942 return FALSE;
1944 return TRUE;
1947 /******************************************************************
1948 * OpenPrinterA [WINSPOOL.@]
1950 * See OpenPrinterW.
1953 BOOL WINAPI OpenPrinterA(LPSTR name, HANDLE *printer, PRINTER_DEFAULTSA *defaults)
1955 return OpenPrinter2A(name, printer, defaults, NULL);
1958 /******************************************************************
1959 * OpenPrinterW [WINSPOOL.@]
1961 * Open a Printer / Printserver or a Printer-Object
1963 * PARAMS
1964 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1965 * phPrinter [O] The resulting Handle is stored here
1966 * pDefault [I] PTR to Default Printer Settings or NULL
1968 * RETURNS
1969 * Success: TRUE
1970 * Failure: FALSE
1972 * NOTES
1973 * lpPrinterName is one of:
1974 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1975 *| Printer: "PrinterName"
1976 *| Printer-Object: "PrinterName,Job xxx"
1977 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1978 *| XcvPort: "Servername,XcvPort PortName"
1980 * BUGS
1981 *| Printer-Object not supported
1982 *| pDefaults is ignored
1985 BOOL WINAPI OpenPrinterW(LPWSTR name, HANDLE *printer, PRINTER_DEFAULTSW *defaults)
1987 return OpenPrinter2W(name, printer, defaults, NULL);
1990 BOOL WINAPI OpenPrinter2A(LPSTR name, HANDLE *printer,
1991 PRINTER_DEFAULTSA *defaults, PRINTER_OPTIONSA *options)
1993 UNICODE_STRING nameU;
1994 UNICODE_STRING datatypeU;
1995 PRINTER_DEFAULTSW defaultsW, *p_defaultsW = NULL;
1996 PRINTER_OPTIONSW optionsW, *p_optionsW = NULL;
1997 WCHAR *nameW;
1998 BOOL ret;
2000 TRACE("(%s,%p,%p,%p)\n", debugstr_a(name), printer, defaults, options);
2002 nameW = asciitounicode(&nameU, name);
2004 if (options)
2006 optionsW.cbSize = sizeof(optionsW);
2007 optionsW.dwFlags = options->dwFlags;
2008 p_optionsW = &optionsW;
2011 if (defaults)
2013 defaultsW.pDatatype = asciitounicode(&datatypeU, defaults->pDatatype);
2014 defaultsW.pDevMode = defaults->pDevMode ? GdiConvertToDevmodeW(defaults->pDevMode) : NULL;
2015 defaultsW.DesiredAccess = defaults->DesiredAccess;
2016 p_defaultsW = &defaultsW;
2019 ret = OpenPrinter2W(nameW, printer, p_defaultsW, p_optionsW);
2021 if (p_defaultsW)
2023 RtlFreeUnicodeString(&datatypeU);
2024 heap_free(defaultsW.pDevMode);
2026 RtlFreeUnicodeString(&nameU);
2028 return ret;
2031 BOOL WINAPI OpenPrinter2W(LPWSTR name, HANDLE *printer,
2032 PRINTER_DEFAULTSW *defaults, PRINTER_OPTIONSW *options)
2034 HKEY key;
2036 TRACE("(%s,%p,%p,%p)\n", debugstr_w(name), printer, defaults, options);
2038 if (options)
2039 FIXME("flags %08lx ignored\n", options->dwFlags);
2041 if(!printer)
2043 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2044 SetLastError( ERROR_INVALID_PARAMETER );
2045 return FALSE;
2048 /* Get the unique handle of the printer or Printserver */
2049 *printer = get_opened_printer_entry( name, defaults );
2051 if (*printer && WINSPOOL_GetOpenedPrinterRegKey( *printer, &key ) == ERROR_SUCCESS)
2053 DWORD deleting = 0, size = sizeof( deleting ), type;
2054 DWORD status;
2055 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2056 WaitForSingleObject( init_mutex, INFINITE );
2057 status = get_dword_from_reg( key, L"Status" );
2058 set_reg_DWORD( key, L"Status", status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2059 ReleaseMutex( init_mutex );
2060 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2061 update_driver( *printer );
2062 RegCloseKey( key );
2065 TRACE("returning %d with %lu and %p\n", *printer != NULL, GetLastError(), *printer);
2066 return (*printer != NULL);
2069 /******************************************************************
2070 * AddMonitorA [WINSPOOL.@]
2072 * See AddMonitorW.
2075 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2077 LPWSTR nameW = NULL;
2078 INT len;
2079 BOOL res;
2080 LPMONITOR_INFO_2A mi2a;
2081 MONITOR_INFO_2W mi2w;
2083 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2084 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2085 debugstr_a(mi2a ? mi2a->pName : NULL),
2086 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2087 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2089 if (Level != 2) {
2090 SetLastError(ERROR_INVALID_LEVEL);
2091 return FALSE;
2094 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2095 if (mi2a == NULL) {
2096 return FALSE;
2099 if (pName) {
2100 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2101 nameW = malloc(len * sizeof(WCHAR));
2102 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2105 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2106 if (mi2a->pName) {
2107 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2108 mi2w.pName = malloc(len * sizeof(WCHAR));
2109 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2111 if (mi2a->pEnvironment) {
2112 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2113 mi2w.pEnvironment = malloc(len * sizeof(WCHAR));
2114 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2116 if (mi2a->pDLLName) {
2117 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2118 mi2w.pDLLName = malloc(len * sizeof(WCHAR));
2119 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2122 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2124 free(mi2w.pName);
2125 free(mi2w.pEnvironment);
2126 free(mi2w.pDLLName);
2128 free(nameW);
2129 return (res);
2132 /******************************************************************************
2133 * AddMonitorW [WINSPOOL.@]
2135 * Install a Printmonitor
2137 * PARAMS
2138 * pName [I] Servername or NULL (local Computer)
2139 * Level [I] Structure-Level (Must be 2)
2140 * pMonitors [I] PTR to MONITOR_INFO_2
2142 * RETURNS
2143 * Success: TRUE
2144 * Failure: FALSE
2146 * NOTES
2147 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2150 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2152 LPMONITOR_INFO_2W mi2w;
2154 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2155 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2156 debugstr_w(mi2w ? mi2w->pName : NULL),
2157 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2158 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2160 if ((backend == NULL) && !load_backend()) return FALSE;
2162 if (Level != 2) {
2163 SetLastError(ERROR_INVALID_LEVEL);
2164 return FALSE;
2167 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2168 if (mi2w == NULL) {
2169 return FALSE;
2172 return backend->fpAddMonitor(pName, Level, pMonitors);
2175 /******************************************************************
2176 * DeletePrinterDriverA [WINSPOOL.@]
2179 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2181 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2184 /******************************************************************
2185 * DeletePrinterDriverW [WINSPOOL.@]
2188 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2190 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2193 /******************************************************************
2194 * DeleteMonitorA [WINSPOOL.@]
2196 * See DeleteMonitorW.
2199 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2201 LPWSTR nameW = NULL;
2202 LPWSTR EnvironmentW = NULL;
2203 LPWSTR MonitorNameW = NULL;
2204 BOOL res;
2205 INT len;
2207 if (pName) {
2208 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2209 nameW = malloc(len * sizeof(WCHAR));
2210 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2213 if (pEnvironment) {
2214 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2215 EnvironmentW = malloc(len * sizeof(WCHAR));
2216 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2218 if (pMonitorName) {
2219 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2220 MonitorNameW = malloc(len * sizeof(WCHAR));
2221 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2224 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2226 free(MonitorNameW);
2227 free(EnvironmentW);
2228 free(nameW);
2229 return (res);
2232 /******************************************************************
2233 * DeleteMonitorW [WINSPOOL.@]
2235 * Delete a specific Printmonitor from a Printing-Environment
2237 * PARAMS
2238 * pName [I] Servername or NULL (local Computer)
2239 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2240 * pMonitorName [I] Name of the Monitor, that should be deleted
2242 * RETURNS
2243 * Success: TRUE
2244 * Failure: FALSE
2246 * NOTES
2247 * pEnvironment is ignored in Windows for the local Computer.
2250 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2253 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2254 debugstr_w(pMonitorName));
2256 if ((backend == NULL) && !load_backend()) return FALSE;
2258 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2262 /******************************************************************
2263 * DeletePortA [WINSPOOL.@]
2265 * See DeletePortW.
2268 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2270 LPWSTR nameW = NULL;
2271 LPWSTR portW = NULL;
2272 INT len;
2273 DWORD res;
2275 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2277 /* convert servername to unicode */
2278 if (pName) {
2279 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2280 nameW = malloc(len * sizeof(WCHAR));
2281 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2284 /* convert portname to unicode */
2285 if (pPortName) {
2286 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2287 portW = malloc(len * sizeof(WCHAR));
2288 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2291 res = DeletePortW(nameW, hWnd, portW);
2292 free(nameW);
2293 free(portW);
2294 return res;
2297 /******************************************************************
2298 * DeletePortW [WINSPOOL.@]
2300 * Delete a specific Port
2302 * PARAMS
2303 * pName [I] Servername or NULL (local Computer)
2304 * hWnd [I] Handle to parent Window for the Dialog-Box
2305 * pPortName [I] Name of the Port, that should be deleted
2307 * RETURNS
2308 * Success: TRUE
2309 * Failure: FALSE
2312 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2314 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2316 if ((backend == NULL) && !load_backend()) return FALSE;
2318 if (!pPortName) {
2319 SetLastError(RPC_X_NULL_REF_POINTER);
2320 return FALSE;
2323 return backend->fpDeletePort(pName, hWnd, pPortName);
2326 /******************************************************************************
2327 * WritePrinter [WINSPOOL.@]
2329 BOOL WINAPI WritePrinter(HANDLE printer, void *buf, DWORD size, DWORD *written)
2331 HANDLE handle = get_backend_handle(printer);
2333 TRACE("(%p, %p, %ld, %p)\n", printer, buf, size, written);
2335 if (!handle)
2337 SetLastError(ERROR_INVALID_HANDLE);
2338 return FALSE;
2341 return backend->fpWritePrinter(handle, buf, size, written);
2344 /*****************************************************************************
2345 * AddFormA [WINSPOOL.@]
2347 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2349 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
2350 return TRUE;
2353 /*****************************************************************************
2354 * AddFormW [WINSPOOL.@]
2356 BOOL WINAPI AddFormW( HANDLE printer, DWORD level, BYTE *form )
2358 HANDLE handle = get_backend_handle( printer );
2360 TRACE( "(%p, %ld, %p)\n", printer, level, form );
2362 if (!handle)
2364 SetLastError( ERROR_INVALID_HANDLE );
2365 return FALSE;
2368 return backend->fpAddForm( handle, level, form );
2371 /*****************************************************************************
2372 * AddJobA [WINSPOOL.@]
2374 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2376 BOOL ret;
2377 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2378 DWORD needed;
2380 if(Level != 1) {
2381 SetLastError(ERROR_INVALID_LEVEL);
2382 return FALSE;
2385 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2387 if(ret) {
2388 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2389 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2390 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2391 if(*pcbNeeded > cbBuf) {
2392 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2393 ret = FALSE;
2394 } else {
2395 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2396 addjobA->JobId = addjobW->JobId;
2397 addjobA->Path = (char *)(addjobA + 1);
2398 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2401 return ret;
2404 /*****************************************************************************
2405 * AddJobW [WINSPOOL.@]
2407 BOOL WINAPI AddJobW(HANDLE printer, DWORD level, LPBYTE data, DWORD size, DWORD *needed)
2409 HANDLE handle = get_backend_handle(printer);
2411 TRACE("(%p, %ld, %p, %ld, %p)\n", printer, level, data, size, needed);
2413 if (!handle)
2415 SetLastError(ERROR_INVALID_HANDLE);
2416 return FALSE;
2419 return backend->fpAddJob(handle, level, data, size, needed);
2422 /*****************************************************************************
2423 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2425 * Return the PATH for the Print-Processors
2427 * See GetPrintProcessorDirectoryW.
2431 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2432 DWORD level, LPBYTE Info,
2433 DWORD cbBuf, LPDWORD pcbNeeded)
2435 LPWSTR serverW = NULL;
2436 LPWSTR envW = NULL;
2437 BOOL ret;
2438 INT len;
2440 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server),
2441 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2444 if (server) {
2445 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2446 serverW = malloc(len * sizeof(WCHAR));
2447 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2450 if (env) {
2451 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2452 envW = malloc(len * sizeof(WCHAR));
2453 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2456 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2457 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2459 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2460 cbBuf, pcbNeeded);
2462 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2463 cbBuf, NULL, NULL) > 0;
2466 TRACE(" required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2467 free(envW);
2468 free(serverW);
2469 return ret;
2472 /*****************************************************************************
2473 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2475 * Return the PATH for the Print-Processors
2477 * PARAMS
2478 * server [I] Servername (NT only) or NULL (local Computer)
2479 * env [I] Printing-Environment (see below) or NULL (Default)
2480 * level [I] Structure-Level (must be 1)
2481 * Info [O] PTR to Buffer that receives the Result
2482 * cbBuf [I] Size of Buffer at "Info"
2483 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2484 * required for the Buffer at "Info"
2486 * RETURNS
2487 * Success: TRUE and in pcbNeeded the Bytes used in Info
2488 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2489 * if cbBuf is too small
2491 * Native Values returned in Info on Success:
2492 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2493 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2494 *| win9x(Windows 4.0): "%winsysdir%"
2496 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2498 * BUGS
2499 * Only NULL or "" is supported for server
2502 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2503 DWORD level, LPBYTE Info,
2504 DWORD cbBuf, LPDWORD pcbNeeded)
2507 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server), debugstr_w(env), level,
2508 Info, cbBuf, pcbNeeded);
2510 if ((backend == NULL) && !load_backend()) return FALSE;
2512 if (level != 1) {
2513 /* (Level != 1) is ignored in win9x */
2514 SetLastError(ERROR_INVALID_LEVEL);
2515 return FALSE;
2518 if (pcbNeeded == NULL) {
2519 /* (pcbNeeded == NULL) is ignored in win9x */
2520 SetLastError(RPC_X_NULL_REF_POINTER);
2521 return FALSE;
2524 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2527 /*****************************************************************************
2528 * set_devices_and_printerports [internal]
2530 * set the [Devices] and [PrinterPorts] entries for a printer.
2533 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2535 DWORD portlen = wcslen( pi->pPortName ) * sizeof(WCHAR);
2536 WCHAR *devline;
2537 HKEY key;
2539 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2541 /* FIXME: the driver must change to "winspool" */
2542 devline = malloc( sizeof(L"wineps.drv") + portlen + sizeof(L",15,45") );
2543 if (devline)
2545 wcscpy( devline, L"wineps.drv," );
2546 wcscat( devline, pi->pPortName );
2548 TRACE("using %s\n", debugstr_w(devline));
2549 if (!create_printers_reg_key( user_printers_key, &key ))
2551 RegSetValueExW( key, pi->pPrinterName, 0, REG_SZ, (BYTE *)devline,
2552 (wcslen( devline ) + 1) * sizeof(WCHAR) );
2553 RegCloseKey( key );
2556 wcscat( devline, L",15,45" );
2557 if (!create_printers_reg_key( user_ports_key, &key ))
2559 RegSetValueExW( key, pi->pPrinterName, 0, REG_SZ, (BYTE *)devline,
2560 (wcslen( devline ) + 1) * sizeof(WCHAR) );
2561 RegCloseKey( key );
2563 free(devline);
2567 static BOOL validate_print_proc(WCHAR *server, const WCHAR *name)
2569 PRINTPROCESSOR_INFO_1W *ppi;
2570 DWORD size, i, no;
2572 if (!EnumPrintProcessorsW(server, NULL, 1, NULL, 0, &size, &no)
2573 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2575 return FALSE;
2577 ppi = malloc(size);
2578 if (!ppi)
2580 SetLastError(ERROR_OUTOFMEMORY);
2581 return FALSE;
2583 if (!EnumPrintProcessorsW(server, NULL, 1, (BYTE*)ppi, size, &size, &no))
2585 free(ppi);
2586 return FALSE;
2589 for (i = 0; i < no; i++)
2591 if (!wcsicmp(ppi[i].pName, name))
2592 break;
2594 free(ppi);
2595 return i != no;
2598 /*****************************************************************************
2599 * AddPrinterW [WINSPOOL.@]
2601 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2603 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2604 LPDEVMODEW dm;
2605 HANDLE retval;
2606 HKEY printer_key, printers_key, hkeyDriver, hkeyDrivers;
2607 LONG size;
2609 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
2611 if(pName && *pName) {
2612 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2613 SetLastError(ERROR_INVALID_PARAMETER);
2614 return 0;
2616 if(Level != 2) {
2617 ERR("Level = %ld, unsupported!\n", Level);
2618 SetLastError(ERROR_INVALID_LEVEL);
2619 return 0;
2621 if(!pPrinter) {
2622 SetLastError(ERROR_INVALID_PARAMETER);
2623 return 0;
2625 if (create_printers_reg_key( system_printers_key, &printers_key ))
2627 ERR("Can't create Printers key\n");
2628 return 0;
2630 if (!RegOpenKeyW( printers_key, pi->pPrinterName, &printer_key ))
2632 if (!RegQueryValueW( printer_key, L"Attributes", NULL, NULL ))
2634 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2635 RegCloseKey( printer_key );
2636 RegCloseKey( printers_key );
2637 return 0;
2639 RegCloseKey( printer_key );
2641 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2642 if(!hkeyDrivers) {
2643 ERR("Can't create Drivers key\n");
2644 RegCloseKey( printers_key );
2645 return 0;
2647 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2648 ERROR_SUCCESS) {
2649 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2650 RegCloseKey( printers_key );
2651 RegCloseKey(hkeyDrivers);
2652 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2653 return 0;
2655 RegCloseKey(hkeyDriver);
2656 RegCloseKey(hkeyDrivers);
2658 if (!validate_print_proc(pName, pi->pPrintProcessor))
2660 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2661 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2662 RegCloseKey( printers_key );
2663 return 0;
2666 if (RegCreateKeyW( printers_key, pi->pPrinterName, &printer_key ))
2668 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2669 SetLastError(ERROR_INVALID_PRINTER_NAME);
2670 RegCloseKey( printers_key );
2671 return 0;
2674 set_devices_and_printerports(pi);
2676 set_reg_DWORD( printer_key, L"Attributes", pi->Attributes );
2677 set_reg_szW( printer_key, L"Datatype", pi->pDatatype );
2678 set_reg_DWORD( printer_key, L"Default Priority", pi->DefaultPriority );
2679 set_reg_szW( printer_key, L"Description", pi->pComment );
2680 set_reg_DWORD( printer_key, L"dnsTimeout", 0 );
2681 set_reg_szW( printer_key, L"Location", pi->pLocation );
2682 set_reg_szW( printer_key, L"Name", pi->pPrinterName );
2683 set_reg_szW( printer_key, L"Parameters", pi->pParameters );
2684 set_reg_szW( printer_key, L"Port", pi->pPortName );
2685 set_reg_szW( printer_key, L"Print Processor", pi->pPrintProcessor );
2686 set_reg_szW( printer_key, L"Printer Driver", pi->pDriverName );
2687 set_reg_DWORD( printer_key, L"Priority", pi->Priority );
2688 set_reg_szW( printer_key, L"Separator File", pi->pSepFile );
2689 set_reg_szW( printer_key, L"Share Name", pi->pShareName );
2690 set_reg_DWORD( printer_key, L"StartTime", pi->StartTime );
2691 set_reg_DWORD( printer_key, L"Status", pi->Status );
2692 set_reg_DWORD( printer_key, L"txTimeout", 0 );
2693 set_reg_DWORD( printer_key, L"UntilTime", pi->UntilTime );
2695 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2697 if (size < 0)
2699 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2700 size = sizeof(DEVMODEW);
2702 if(pi->pDevMode)
2703 dm = pi->pDevMode;
2704 else
2706 dm = calloc( 1, size );
2707 dm->dmSize = size;
2708 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2710 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2711 free( dm );
2712 dm = NULL;
2714 else
2716 unsigned int len = min( ARRAY_SIZE( dm->dmDeviceName ) - 1, wcslen( pi->pPrinterName ) );
2717 memcpy( dm->dmDeviceName, pi->pPrinterName, len * sizeof(WCHAR) );
2718 dm->dmDeviceName[len] = '\0';
2722 set_reg_devmode( printer_key, L"Default DevMode", dm );
2723 if (!pi->pDevMode) free( dm );
2725 RegCloseKey( printer_key );
2726 RegCloseKey( printers_key );
2727 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2728 ERR("OpenPrinter failing\n");
2729 return 0;
2731 return retval;
2734 /*****************************************************************************
2735 * AddPrinterA [WINSPOOL.@]
2737 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2739 UNICODE_STRING pNameW;
2740 PWSTR pwstrNameW;
2741 PRINTER_INFO_2W *piW;
2742 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2743 HANDLE ret;
2745 TRACE("(%s, %ld, %p)\n", debugstr_a(pName), Level, pPrinter);
2746 if(Level != 2) {
2747 ERR("Level = %ld, unsupported!\n", Level);
2748 SetLastError(ERROR_INVALID_LEVEL);
2749 return 0;
2751 pwstrNameW = asciitounicode(&pNameW,pName);
2752 piW = printer_info_AtoW( piA, Level );
2754 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2756 free_printer_info( piW, Level );
2757 RtlFreeUnicodeString(&pNameW);
2758 return ret;
2762 /*****************************************************************************
2763 * ClosePrinter [WINSPOOL.@]
2765 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2767 UINT_PTR i = (UINT_PTR)hPrinter;
2768 opened_printer_t *printer = NULL;
2770 TRACE("(%p)\n", hPrinter);
2772 EnterCriticalSection(&printer_handles_cs);
2774 if ((i > 0) && (i <= nb_printer_handles))
2775 printer = printer_handles[i - 1];
2778 if(printer)
2780 TRACE("closing %s\n", debugstr_w(printer->name));
2781 if (printer->backend_printer) {
2782 backend->fpClosePrinter(printer->backend_printer);
2785 free_printer_entry( printer );
2786 printer_handles[i - 1] = NULL;
2787 LeaveCriticalSection(&printer_handles_cs);
2788 return TRUE;
2791 LeaveCriticalSection(&printer_handles_cs);
2792 SetLastError(ERROR_INVALID_HANDLE);
2793 return FALSE;
2796 /*****************************************************************************
2797 * DeleteFormA [WINSPOOL.@]
2799 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2801 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2802 return TRUE;
2805 /*****************************************************************************
2806 * DeleteFormW [WINSPOOL.@]
2808 BOOL WINAPI DeleteFormW( HANDLE printer, WCHAR *name )
2810 HANDLE handle = get_backend_handle( printer );
2812 TRACE( "(%p, %s)\n", printer, debugstr_w( name ) );
2814 if (!handle)
2816 SetLastError( ERROR_INVALID_HANDLE );
2817 return FALSE;
2820 return backend->fpDeleteForm( handle, name );
2823 /*****************************************************************************
2824 * DeletePrinter [WINSPOOL.@]
2826 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2828 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2829 config_module_t *config_module;
2830 HKEY key;
2831 WCHAR def[MAX_PATH];
2832 DWORD size = ARRAY_SIZE(def);
2834 if(!lpNameW) {
2835 SetLastError(ERROR_INVALID_HANDLE);
2836 return FALSE;
2839 EnterCriticalSection(&config_modules_cs);
2840 if ((config_module = get_config_module(lpNameW, FALSE))) {
2841 wine_rb_remove(&config_modules, &config_module->entry);
2842 release_config_module(config_module);
2844 LeaveCriticalSection(&config_modules_cs);
2846 if (!create_printers_reg_key( system_printers_key, &key ))
2848 RegDeleteTreeW( key, lpNameW );
2849 RegCloseKey( key );
2852 if (!create_printers_reg_key( user_printers_key, &key ))
2854 RegDeleteValueW( key, lpNameW );
2855 RegCloseKey( key );
2858 if (!create_printers_reg_key( user_ports_key, &key ))
2860 RegDeleteValueW( key, lpNameW );
2861 RegCloseKey( key );
2864 if (GetDefaultPrinterW( def, &size ) && !wcscmp( def, lpNameW ))
2866 if (!create_printers_reg_key( user_default_key, &key ))
2868 RegDeleteValueW( key, L"device" );
2869 RegCloseKey( key );
2871 SetDefaultPrinterW( NULL );
2874 return TRUE;
2877 /*****************************************************************************
2878 * SetPrinterA [WINSPOOL.@]
2880 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2882 BYTE *dataW = data;
2883 BOOL ret;
2885 if (level != 0)
2887 dataW = printer_info_AtoW( data, level );
2888 if (!dataW) return FALSE;
2891 ret = SetPrinterW( printer, level, dataW, command );
2893 if (dataW != data) free_printer_info( dataW, level );
2895 return ret;
2898 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
2900 set_reg_szW( key, L"Name", pi->pPrinterName );
2901 set_reg_szW( key, L"Share Name", pi->pShareName );
2902 set_reg_szW( key, L"Port", pi->pPortName );
2903 set_reg_szW( key, L"Printer Driver", pi->pDriverName );
2904 set_reg_szW( key, L"Description", pi->pComment );
2905 set_reg_szW( key, L"Location", pi->pLocation );
2907 if (pi->pDevMode)
2908 set_reg_devmode( key, L"Default DevMode", pi->pDevMode );
2910 set_reg_szW( key, L"Separator File", pi->pSepFile );
2911 set_reg_szW( key, L"Print Processor", pi->pPrintProcessor );
2912 set_reg_szW( key, L"Datatype", pi->pDatatype );
2913 set_reg_szW( key, L"Parameters", pi->pParameters );
2915 set_reg_DWORD( key, L"Attributes", pi->Attributes );
2916 set_reg_DWORD( key, L"Priority", pi->Priority );
2917 set_reg_DWORD( key, L"Default Priority", pi->DefaultPriority );
2918 set_reg_DWORD( key, L"StartTime", pi->StartTime );
2919 set_reg_DWORD( key, L"UntilTime", pi->UntilTime );
2922 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
2924 if (!pi->pDevMode) return FALSE;
2926 set_reg_devmode( key, L"Default DevMode", pi->pDevMode );
2927 return TRUE;
2930 /******************************************************************************
2931 * SetPrinterW [WINSPOOL.@]
2933 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2935 HKEY key;
2936 BOOL ret = FALSE;
2938 TRACE( "(%p, %ld, %p, %ld)\n", printer, level, data, command );
2940 if (command != 0) FIXME( "Ignoring command %ld\n", command );
2942 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
2943 return FALSE;
2945 switch (level)
2947 case 2:
2949 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
2950 set_printer_2( key, pi2 );
2951 ret = TRUE;
2952 break;
2955 case 8:
2956 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
2957 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
2958 /* fall through */
2959 case 9:
2961 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
2962 ret = set_printer_9( key, pi );
2963 break;
2966 default:
2967 FIXME( "Unimplemented level %ld\n", level );
2968 SetLastError( ERROR_INVALID_LEVEL );
2971 RegCloseKey( key );
2972 return ret;
2975 /*****************************************************************************
2976 * SetJobA [WINSPOOL.@]
2978 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2979 LPBYTE pJob, DWORD Command)
2981 BOOL ret;
2982 void *JobW;
2983 UNICODE_STRING usBuffer;
2985 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2987 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2988 are all ignored by SetJob, so we don't bother copying them */
2989 switch(Level)
2991 case 0:
2992 JobW = NULL;
2993 break;
2994 case 1:
2996 JOB_INFO_1W *info1W = malloc(sizeof(*info1W));
2997 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2999 JobW = info1W;
3000 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3001 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3002 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3003 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3004 info1W->Status = info1A->Status;
3005 info1W->Priority = info1A->Priority;
3006 info1W->Position = info1A->Position;
3007 info1W->PagesPrinted = info1A->PagesPrinted;
3008 break;
3010 case 2:
3012 JOB_INFO_2W *info2W = malloc(sizeof(*info2W));
3013 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3015 JobW = info2W;
3016 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3017 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3018 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3019 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3020 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3021 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3022 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3023 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3024 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3025 info2W->Status = info2A->Status;
3026 info2W->Priority = info2A->Priority;
3027 info2W->Position = info2A->Position;
3028 info2W->StartTime = info2A->StartTime;
3029 info2W->UntilTime = info2A->UntilTime;
3030 info2W->PagesPrinted = info2A->PagesPrinted;
3031 break;
3033 case 3:
3034 JobW = malloc(sizeof(JOB_INFO_3));
3035 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3036 break;
3037 default:
3038 SetLastError(ERROR_INVALID_LEVEL);
3039 return FALSE;
3042 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3044 switch(Level)
3046 case 1:
3048 JOB_INFO_1W *info1W = JobW;
3049 free(info1W->pUserName);
3050 free(info1W->pDocument);
3051 free(info1W->pDatatype);
3052 free(info1W->pStatus);
3053 break;
3055 case 2:
3057 JOB_INFO_2W *info2W = JobW;
3058 free(info2W->pUserName);
3059 free(info2W->pDocument);
3060 free(info2W->pNotifyName);
3061 free(info2W->pDatatype);
3062 free(info2W->pPrintProcessor);
3063 free(info2W->pParameters);
3064 heap_free(info2W->pDevMode);
3065 free(info2W->pStatus);
3066 break;
3069 free(JobW);
3071 return ret;
3074 /*****************************************************************************
3075 * SetJobW [WINSPOOL.@]
3077 BOOL WINAPI SetJobW(HANDLE printer, DWORD job_id, DWORD level,
3078 LPBYTE data, DWORD command)
3080 HANDLE handle = get_backend_handle(printer);
3082 TRACE("(%p, %ld, %ld, %p, %ld)\n", printer, job_id, level, data, command);
3084 if (!handle)
3086 SetLastError(ERROR_INVALID_HANDLE);
3087 return FALSE;
3090 return backend->fpSetJob(handle, job_id, level, data, command);
3093 /*****************************************************************************
3094 * EndDocPrinter [WINSPOOL.@]
3096 BOOL WINAPI EndDocPrinter(HANDLE printer)
3098 HANDLE handle = get_backend_handle(printer);
3100 TRACE("(%p)\n", printer);
3102 if (!handle)
3104 SetLastError(ERROR_INVALID_HANDLE);
3105 return FALSE;
3108 return backend->fpEndDocPrinter(handle);
3111 /*****************************************************************************
3112 * EndPagePrinter [WINSPOOL.@]
3114 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3116 FIXME("(%p): stub\n", hPrinter);
3117 return TRUE;
3120 /*****************************************************************************
3121 * StartDocPrinterA [WINSPOOL.@]
3123 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3125 UNICODE_STRING usBuffer;
3126 DOC_INFO_2W doc2W;
3127 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3128 DWORD ret;
3130 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3131 or one (DOC_INFO_3) extra DWORDs */
3133 switch(Level) {
3134 case 2:
3135 doc2W.JobId = doc2->JobId;
3136 /* fall through */
3137 case 3:
3138 doc2W.dwMode = doc2->dwMode;
3139 /* fall through */
3140 case 1:
3141 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3142 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3143 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3144 break;
3146 default:
3147 SetLastError(ERROR_INVALID_LEVEL);
3148 return FALSE;
3151 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3153 free(doc2W.pDatatype);
3154 free(doc2W.pOutputFile);
3155 free(doc2W.pDocName);
3157 return ret;
3160 /*****************************************************************************
3161 * StartDocPrinterW [WINSPOOL.@]
3163 DWORD WINAPI StartDocPrinterW(HANDLE printer, DWORD level, BYTE *doc_info)
3165 HANDLE handle = get_backend_handle(printer);
3166 DOC_INFO_1W *info = (DOC_INFO_1W *)doc_info;
3168 TRACE("(%p, %ld, %p {%s, %s, %s})\n", printer, level, doc_info,
3169 debugstr_w(info->pDocName), debugstr_w(info->pOutputFile),
3170 debugstr_w(info->pDatatype));
3172 if (!handle)
3174 SetLastError(ERROR_INVALID_HANDLE);
3175 return 0;
3178 return backend->fpStartDocPrinter(handle, level, doc_info);
3181 /*****************************************************************************
3182 * StartPagePrinter [WINSPOOL.@]
3184 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3186 FIXME("(%p): stub\n", hPrinter);
3187 return TRUE;
3190 /*****************************************************************************
3191 * GetFormA [WINSPOOL.@]
3193 BOOL WINAPI GetFormA( HANDLE printer, char *name, DWORD level, BYTE *form, DWORD size, DWORD *needed )
3195 UNICODE_STRING nameW;
3196 const DWORD *string_info = form_string_info( level );
3197 BOOL ret;
3199 if (!string_info) return FALSE;
3201 asciitounicode( &nameW, name );
3203 ret = GetFormW( printer, nameW.Buffer, level, form, size, needed );
3204 if (ret) packed_struct_WtoA( form, string_info );
3206 RtlFreeUnicodeString( &nameW );
3207 return ret;
3210 /*****************************************************************************
3211 * GetFormW [WINSPOOL.@]
3213 BOOL WINAPI GetFormW( HANDLE printer, WCHAR *name, DWORD level, BYTE *form, DWORD size, DWORD *needed )
3215 HANDLE handle = get_backend_handle( printer );
3217 TRACE( "(%p, %s, %ld, %p, %ld, %p)\n", printer, debugstr_w( name ), level, form, size, needed );
3219 if (!handle)
3221 SetLastError( ERROR_INVALID_HANDLE );
3222 return FALSE;
3225 return backend->fpGetForm( handle, name, level, form, size, needed );
3228 /*****************************************************************************
3229 * SetFormA [WINSPOOL.@]
3231 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3232 LPBYTE pForm)
3234 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
3235 return FALSE;
3238 /*****************************************************************************
3239 * SetFormW [WINSPOOL.@]
3241 BOOL WINAPI SetFormW( HANDLE printer, WCHAR *name, DWORD level, BYTE *form )
3243 HANDLE handle = get_backend_handle( printer );
3245 TRACE( "(%p, %s, %ld, %p)\n", printer, debugstr_w( name ), level, form );
3247 if (!handle)
3249 SetLastError( ERROR_INVALID_HANDLE );
3250 return FALSE;
3253 return backend->fpSetForm( handle, name, level, form );
3256 /*****************************************************************************
3257 * ReadPrinter [WINSPOOL.@]
3259 BOOL WINAPI ReadPrinter(HANDLE printer, void *buf, DWORD size, DWORD *bytes_read)
3261 HANDLE handle = get_backend_handle(printer);
3263 TRACE("(%p,%p,%ld,%p)\n", printer, buf, size, bytes_read);
3265 if (!handle)
3267 SetLastError( ERROR_INVALID_HANDLE );
3268 return FALSE;
3271 return backend->fpReadPrinter(handle, buf, size, bytes_read);
3274 /*****************************************************************************
3275 * ResetPrinterA [WINSPOOL.@]
3277 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3279 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3280 return FALSE;
3283 /*****************************************************************************
3284 * ResetPrinterW [WINSPOOL.@]
3286 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3288 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3289 return FALSE;
3292 /*****************************************************************************
3293 * get_filename_from_reg [internal]
3295 * Get ValueName from hkey storing result in out
3296 * when the Value in the registry has only a filename, use driverdir as prefix
3297 * outlen is space left in out
3298 * String is stored either as unicode or ansi
3302 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3303 LPBYTE out, DWORD outlen, LPDWORD needed)
3305 WCHAR filename[MAX_PATH];
3306 DWORD size;
3307 DWORD type;
3308 LONG ret;
3309 LPWSTR buffer = filename;
3310 LPWSTR ptr;
3312 *needed = 0;
3313 size = sizeof(filename);
3314 buffer[0] = '\0';
3315 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3316 if (ret == ERROR_MORE_DATA) {
3317 TRACE("need dynamic buffer: %lu\n", size);
3318 buffer = malloc(size);
3319 if (!buffer) {
3320 /* No Memory is bad */
3321 return FALSE;
3323 buffer[0] = '\0';
3324 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3327 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3328 if (buffer != filename) free(buffer);
3329 return FALSE;
3332 ptr = buffer;
3333 while (ptr) {
3334 /* do we have a full path ? */
3335 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3336 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3338 if (!ret) {
3339 /* we must build the full Path */
3340 *needed += dirlen;
3341 if ((out) && (outlen > dirlen)) {
3342 wcscpy( (WCHAR *)out, driverdir );
3343 out += dirlen;
3344 outlen -= dirlen;
3346 else
3347 out = NULL;
3350 /* write the filename */
3351 size = (wcslen( ptr ) + 1) * sizeof(WCHAR);
3352 if ((out) && (outlen >= size)) {
3353 wcscpy( (WCHAR *)out, ptr );
3354 out += size;
3355 outlen -= size;
3357 else
3358 out = NULL;
3359 *needed += size;
3360 ptr += wcslen( ptr ) + 1;
3361 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3364 if (buffer != filename) free(buffer);
3366 /* write the multisz-termination */
3367 if (type == REG_MULTI_SZ) {
3368 size = sizeof(WCHAR);
3370 *needed += size;
3371 if (out && (outlen >= size)) {
3372 memset (out, 0, size);
3375 return TRUE;
3378 /*****************************************************************************
3379 * WINSPOOL_GetStringFromReg
3381 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3382 * String is stored as unicode.
3384 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3385 DWORD buflen, DWORD *needed)
3387 DWORD sz = buflen, type;
3388 LONG ret;
3390 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3391 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3392 WARN("Got ret = %ld\n", ret);
3393 *needed = 0;
3394 return FALSE;
3396 /* add space for terminating '\0' */
3397 sz += sizeof(WCHAR);
3398 *needed = sz;
3400 if (ptr)
3401 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3403 return TRUE;
3406 /*****************************************************************************
3407 * WINSPOOL_GetDefaultDevMode
3409 * Get a default DevMode values for wineps.
3411 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
3413 if (buflen >= sizeof(DEVMODEW))
3415 DEVMODEW *dm = (DEVMODEW *)ptr;
3417 /* the driver will update registry with real values */
3418 memset(dm, 0, sizeof(*dm));
3419 dm->dmSize = sizeof(*dm);
3420 wcscpy( dm->dmDeviceName, L"wineps.drv" );
3422 *needed = sizeof(DEVMODEW);
3425 /*****************************************************************************
3426 * WINSPOOL_GetDevModeFromReg
3428 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3429 * DevMode is stored either as unicode or ansi.
3431 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3432 LPBYTE ptr,
3433 DWORD buflen, DWORD *needed)
3435 DWORD sz = buflen, type;
3436 LONG ret;
3438 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3439 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3440 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3441 if (sz < sizeof(DEVMODEA))
3443 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
3444 return FALSE;
3446 /* ensures that dmSize is not erratically bogus if registry is invalid */
3447 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3448 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3449 sz += (CCHDEVICENAME + CCHFORMNAME);
3450 if (ptr && (buflen >= sz)) {
3451 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3452 memcpy(ptr, dmW, sz);
3453 heap_free(dmW);
3455 *needed = sz;
3456 return TRUE;
3459 /*********************************************************************
3460 * WINSPOOL_GetPrinter_1
3462 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3464 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3465 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3467 DWORD size, left = cbBuf;
3468 BOOL space = (cbBuf > 0);
3469 LPBYTE ptr = buf;
3471 *pcbNeeded = 0;
3473 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3475 if(space && size <= left) {
3476 pi1->pName = (LPWSTR)ptr;
3477 ptr += size;
3478 left -= size;
3479 } else
3480 space = FALSE;
3481 *pcbNeeded += size;
3484 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3485 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3487 if(space && size <= left) {
3488 pi1->pDescription = (LPWSTR)ptr;
3489 ptr += size;
3490 left -= size;
3491 } else
3492 space = FALSE;
3493 *pcbNeeded += size;
3496 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Description", ptr, left, &size ))
3498 if(space && size <= left) {
3499 pi1->pComment = (LPWSTR)ptr;
3500 ptr += size;
3501 left -= size;
3502 } else
3503 space = FALSE;
3504 *pcbNeeded += size;
3507 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3509 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3510 memset(pi1, 0, sizeof(*pi1));
3512 return space;
3514 /*********************************************************************
3515 * WINSPOOL_GetPrinter_2
3517 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3519 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3520 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3522 DWORD size, left = cbBuf;
3523 BOOL space = (cbBuf > 0);
3524 LPBYTE ptr = buf;
3526 *pcbNeeded = 0;
3528 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3530 if(space && size <= left) {
3531 pi2->pPrinterName = (LPWSTR)ptr;
3532 ptr += size;
3533 left -= size;
3534 } else
3535 space = FALSE;
3536 *pcbNeeded += size;
3538 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Share Name", ptr, left, &size))
3540 if(space && size <= left) {
3541 pi2->pShareName = (LPWSTR)ptr;
3542 ptr += size;
3543 left -= size;
3544 } else
3545 space = FALSE;
3546 *pcbNeeded += size;
3548 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Port", ptr, left, &size ))
3550 if(space && size <= left) {
3551 pi2->pPortName = (LPWSTR)ptr;
3552 ptr += size;
3553 left -= size;
3554 } else
3555 space = FALSE;
3556 *pcbNeeded += size;
3558 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Printer Driver", ptr, left, &size ))
3560 if(space && size <= left) {
3561 pi2->pDriverName = (LPWSTR)ptr;
3562 ptr += size;
3563 left -= size;
3564 } else
3565 space = FALSE;
3566 *pcbNeeded += size;
3568 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Description", ptr, left, &size ))
3570 if(space && size <= left) {
3571 pi2->pComment = (LPWSTR)ptr;
3572 ptr += size;
3573 left -= size;
3574 } else
3575 space = FALSE;
3576 *pcbNeeded += size;
3578 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Location", ptr, left, &size ))
3580 if(space && size <= left) {
3581 pi2->pLocation = (LPWSTR)ptr;
3582 ptr += size;
3583 left -= size;
3584 } else
3585 space = FALSE;
3586 *pcbNeeded += size;
3588 if (WINSPOOL_GetDevModeFromReg( hkeyPrinter, L"Default DevMode", ptr, left, &size ))
3590 if(space && size <= left) {
3591 pi2->pDevMode = (LPDEVMODEW)ptr;
3592 ptr += size;
3593 left -= size;
3594 } else
3595 space = FALSE;
3596 *pcbNeeded += size;
3598 else
3600 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3601 if(space && size <= left) {
3602 pi2->pDevMode = (LPDEVMODEW)ptr;
3603 ptr += size;
3604 left -= size;
3605 } else
3606 space = FALSE;
3607 *pcbNeeded += size;
3609 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Separator File", ptr, left, &size ))
3611 if(space && size <= left) {
3612 pi2->pSepFile = (LPWSTR)ptr;
3613 ptr += size;
3614 left -= size;
3615 } else
3616 space = FALSE;
3617 *pcbNeeded += size;
3619 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Print Processor", ptr, left, &size ))
3621 if(space && size <= left) {
3622 pi2->pPrintProcessor = (LPWSTR)ptr;
3623 ptr += size;
3624 left -= size;
3625 } else
3626 space = FALSE;
3627 *pcbNeeded += size;
3629 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Datatype", ptr, left, &size ))
3631 if(space && size <= left) {
3632 pi2->pDatatype = (LPWSTR)ptr;
3633 ptr += size;
3634 left -= size;
3635 } else
3636 space = FALSE;
3637 *pcbNeeded += size;
3639 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Parameters", ptr, left, &size ))
3641 if(space && size <= left) {
3642 pi2->pParameters = (LPWSTR)ptr;
3643 ptr += size;
3644 left -= size;
3645 } else
3646 space = FALSE;
3647 *pcbNeeded += size;
3649 if (pi2)
3651 pi2->Attributes = get_dword_from_reg( hkeyPrinter, L"Attributes" );
3652 pi2->Priority = get_dword_from_reg( hkeyPrinter, L"Priority" );
3653 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, L"Default Priority" );
3654 pi2->StartTime = get_dword_from_reg( hkeyPrinter, L"StartTime" );
3655 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, L"UntilTime" );
3658 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3659 memset(pi2, 0, sizeof(*pi2));
3661 return space;
3664 /*********************************************************************
3665 * WINSPOOL_GetPrinter_4
3667 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3669 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3670 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3672 DWORD size, left = cbBuf;
3673 BOOL space = (cbBuf > 0);
3674 LPBYTE ptr = buf;
3676 *pcbNeeded = 0;
3678 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3680 if(space && size <= left) {
3681 pi4->pPrinterName = (LPWSTR)ptr;
3682 ptr += size;
3683 left -= size;
3684 } else
3685 space = FALSE;
3686 *pcbNeeded += size;
3688 if(pi4) {
3689 pi4->Attributes = get_dword_from_reg( hkeyPrinter, L"Attributes" );
3692 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3693 memset(pi4, 0, sizeof(*pi4));
3695 return space;
3698 /*********************************************************************
3699 * WINSPOOL_GetPrinter_5
3701 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3703 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3704 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3706 DWORD size, left = cbBuf;
3707 BOOL space = (cbBuf > 0);
3708 LPBYTE ptr = buf;
3710 *pcbNeeded = 0;
3712 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3714 if(space && size <= left) {
3715 pi5->pPrinterName = (LPWSTR)ptr;
3716 ptr += size;
3717 left -= size;
3718 } else
3719 space = FALSE;
3720 *pcbNeeded += size;
3722 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Port", ptr, left, &size ))
3724 if(space && size <= left) {
3725 pi5->pPortName = (LPWSTR)ptr;
3726 ptr += size;
3727 left -= size;
3728 } else
3729 space = FALSE;
3730 *pcbNeeded += size;
3732 if(pi5) {
3733 pi5->Attributes = get_dword_from_reg( hkeyPrinter, L"Attributes" );
3734 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, L"dnsTimeout" );
3735 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, L"txTimeout" );
3738 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3739 memset(pi5, 0, sizeof(*pi5));
3741 return space;
3744 /*********************************************************************
3745 * WINSPOOL_GetPrinter_7
3747 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3749 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3750 DWORD cbBuf, LPDWORD pcbNeeded)
3752 DWORD size, left = cbBuf;
3753 BOOL space = (cbBuf > 0);
3754 LPBYTE ptr = buf;
3756 *pcbNeeded = 0;
3758 if (!WINSPOOL_GetStringFromReg( hkeyPrinter, L"ObjectGUID", ptr, left, &size ))
3760 ptr = NULL;
3761 size = sizeof(pi7->pszObjectGUID);
3763 if (space && size <= left) {
3764 pi7->pszObjectGUID = (LPWSTR)ptr;
3765 ptr += size;
3766 left -= size;
3767 } else
3768 space = FALSE;
3769 *pcbNeeded += size;
3770 if (pi7) {
3771 /* We do not have a Directory Service */
3772 pi7->dwAction = DSPRINT_UNPUBLISH;
3775 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3776 memset(pi7, 0, sizeof(*pi7));
3778 return space;
3781 /*********************************************************************
3782 * WINSPOOL_GetPrinter_9
3784 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3786 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3787 DWORD cbBuf, LPDWORD pcbNeeded)
3789 DWORD size;
3790 BOOL space = (cbBuf > 0);
3792 *pcbNeeded = 0;
3794 if (WINSPOOL_GetDevModeFromReg( hkeyPrinter, L"Default DevMode", buf, cbBuf, &size ))
3796 if(space && size <= cbBuf) {
3797 pi9->pDevMode = (LPDEVMODEW)buf;
3798 } else
3799 space = FALSE;
3800 *pcbNeeded += size;
3802 else
3804 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3805 if(space && size <= cbBuf) {
3806 pi9->pDevMode = (LPDEVMODEW)buf;
3807 } else
3808 space = FALSE;
3809 *pcbNeeded += size;
3812 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3813 memset(pi9, 0, sizeof(*pi9));
3815 return space;
3818 /*****************************************************************************
3819 * GetPrinterW [WINSPOOL.@]
3821 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3822 DWORD cbBuf, LPDWORD pcbNeeded)
3824 DWORD size, needed = 0, err;
3825 LPBYTE ptr = NULL;
3826 HKEY hkeyPrinter;
3827 BOOL ret;
3829 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3831 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
3832 if (err)
3834 SetLastError( err );
3835 return FALSE;
3838 switch(Level) {
3839 case 1:
3841 PRINTER_INFO_1W *pi1 = (PRINTER_INFO_1W *)pPrinter;
3843 size = sizeof(PRINTER_INFO_1W);
3844 if (size <= cbBuf) {
3845 ptr = pPrinter + size;
3846 cbBuf -= size;
3847 memset(pPrinter, 0, size);
3848 } else {
3849 pi1 = NULL;
3850 cbBuf = 0;
3852 ret = WINSPOOL_GetPrinter_1(hkeyPrinter, pi1, ptr, cbBuf, &needed);
3853 needed += size;
3854 break;
3857 case 2:
3859 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3861 size = sizeof(PRINTER_INFO_2W);
3862 if(size <= cbBuf) {
3863 ptr = pPrinter + size;
3864 cbBuf -= size;
3865 memset(pPrinter, 0, size);
3866 } else {
3867 pi2 = NULL;
3868 cbBuf = 0;
3870 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3871 needed += size;
3872 break;
3875 case 4:
3877 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3879 size = sizeof(PRINTER_INFO_4W);
3880 if(size <= cbBuf) {
3881 ptr = pPrinter + size;
3882 cbBuf -= size;
3883 memset(pPrinter, 0, size);
3884 } else {
3885 pi4 = NULL;
3886 cbBuf = 0;
3888 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3889 needed += size;
3890 break;
3894 case 5:
3896 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3898 size = sizeof(PRINTER_INFO_5W);
3899 if(size <= cbBuf) {
3900 ptr = pPrinter + size;
3901 cbBuf -= size;
3902 memset(pPrinter, 0, size);
3903 } else {
3904 pi5 = NULL;
3905 cbBuf = 0;
3908 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3909 needed += size;
3910 break;
3914 case 6:
3916 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3918 size = sizeof(PRINTER_INFO_6);
3919 if (size <= cbBuf) {
3920 /* FIXME: We do not update the status yet */
3921 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, L"Status" );
3922 ret = TRUE;
3923 } else {
3924 ret = FALSE;
3927 needed += size;
3928 break;
3931 case 7:
3933 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3935 size = sizeof(PRINTER_INFO_7W);
3936 if (size <= cbBuf) {
3937 ptr = pPrinter + size;
3938 cbBuf -= size;
3939 memset(pPrinter, 0, size);
3940 } else {
3941 pi7 = NULL;
3942 cbBuf = 0;
3945 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3946 needed += size;
3947 break;
3951 case 8:
3952 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
3953 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3954 /* fall through */
3955 case 9:
3957 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3959 size = sizeof(PRINTER_INFO_9W);
3960 if(size <= cbBuf) {
3961 ptr = pPrinter + size;
3962 cbBuf -= size;
3963 memset(pPrinter, 0, size);
3964 } else {
3965 pi9 = NULL;
3966 cbBuf = 0;
3969 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3970 needed += size;
3971 break;
3975 default:
3976 FIXME("Unimplemented level %ld\n", Level);
3977 SetLastError(ERROR_INVALID_LEVEL);
3978 RegCloseKey(hkeyPrinter);
3979 return FALSE;
3982 RegCloseKey(hkeyPrinter);
3984 TRACE("returning %d needed = %ld\n", ret, needed);
3985 if(pcbNeeded) *pcbNeeded = needed;
3986 if(!ret)
3987 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3988 return ret;
3991 /*****************************************************************************
3992 * GetPrinterA [WINSPOOL.@]
3994 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3995 DWORD cbBuf, LPDWORD pcbNeeded)
3997 BOOL ret;
3998 LPBYTE buf = NULL;
4000 if (cbBuf)
4001 buf = malloc(cbBuf);
4003 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4004 if (ret)
4005 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4006 free(buf);
4008 return ret;
4011 /*****************************************************************************
4012 * WINSPOOL_EnumPrintersW
4014 * Implementation of EnumPrintersW
4016 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4017 DWORD dwLevel, LPBYTE lpbPrinters,
4018 DWORD cbBuf, LPDWORD lpdwNeeded,
4019 LPDWORD lpdwReturned)
4022 HKEY printers_key, hkeyPrinter;
4023 WCHAR PrinterName[255];
4024 DWORD needed = 0, number = 0;
4025 DWORD used, i, left;
4026 PBYTE pi, buf;
4028 if(lpbPrinters)
4029 memset(lpbPrinters, 0, cbBuf);
4030 if(lpdwReturned)
4031 *lpdwReturned = 0;
4032 if(lpdwNeeded)
4033 *lpdwNeeded = 0;
4035 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4036 if(dwType == PRINTER_ENUM_DEFAULT)
4037 return TRUE;
4039 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4040 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4041 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4042 if (!dwType) {
4043 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4044 return TRUE;
4049 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4050 FIXME("dwType = %08lx\n", dwType);
4051 SetLastError(ERROR_INVALID_FLAGS);
4052 return FALSE;
4055 if (create_printers_reg_key( system_printers_key, &printers_key ))
4057 ERR("Can't create Printers key\n");
4058 return FALSE;
4061 if (RegQueryInfoKeyA( printers_key, NULL, NULL, NULL, &number, NULL, NULL, NULL, NULL, NULL, NULL, NULL ))
4063 RegCloseKey( printers_key );
4064 ERR("Can't query Printers key\n");
4065 return FALSE;
4067 TRACE("Found %ld printers\n", number);
4069 switch(dwLevel) {
4070 case 1:
4071 used = number * sizeof(PRINTER_INFO_1W);
4072 break;
4073 case 2:
4074 used = number * sizeof(PRINTER_INFO_2W);
4075 break;
4076 case 4:
4077 used = number * sizeof(PRINTER_INFO_4W);
4078 break;
4079 case 5:
4080 used = number * sizeof(PRINTER_INFO_5W);
4081 break;
4083 default:
4084 SetLastError(ERROR_INVALID_LEVEL);
4085 RegCloseKey( printers_key );
4086 return FALSE;
4088 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4090 for(i = 0; i < number; i++) {
4091 if (RegEnumKeyW( printers_key, i, PrinterName, ARRAY_SIZE(PrinterName) ))
4093 ERR("Can't enum key number %ld\n", i);
4094 RegCloseKey( printers_key );
4095 return FALSE;
4097 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
4098 if (RegOpenKeyW( printers_key, PrinterName, &hkeyPrinter ))
4100 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4101 RegCloseKey( printers_key );
4102 return FALSE;
4105 if(cbBuf > used) {
4106 buf = lpbPrinters + used;
4107 left = cbBuf - used;
4108 } else {
4109 buf = NULL;
4110 left = 0;
4113 switch(dwLevel) {
4114 case 1:
4115 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4116 left, &needed);
4117 used += needed;
4118 if(pi) pi += sizeof(PRINTER_INFO_1W);
4119 break;
4120 case 2:
4121 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4122 left, &needed);
4123 used += needed;
4124 if(pi) pi += sizeof(PRINTER_INFO_2W);
4125 break;
4126 case 4:
4127 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4128 left, &needed);
4129 used += needed;
4130 if(pi) pi += sizeof(PRINTER_INFO_4W);
4131 break;
4132 case 5:
4133 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4134 left, &needed);
4135 used += needed;
4136 if(pi) pi += sizeof(PRINTER_INFO_5W);
4137 break;
4138 default:
4139 ERR("Shouldn't be here!\n");
4140 RegCloseKey(hkeyPrinter);
4141 RegCloseKey( printers_key );
4142 return FALSE;
4144 RegCloseKey(hkeyPrinter);
4146 RegCloseKey( printers_key );
4148 if(lpdwNeeded)
4149 *lpdwNeeded = used;
4151 if(used > cbBuf) {
4152 if(lpbPrinters)
4153 memset(lpbPrinters, 0, cbBuf);
4154 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4155 return FALSE;
4157 if(lpdwReturned)
4158 *lpdwReturned = number;
4159 SetLastError(ERROR_SUCCESS);
4160 return TRUE;
4164 /******************************************************************
4165 * EnumPrintersW [WINSPOOL.@]
4167 * Enumerates the available printers, print servers and print
4168 * providers, depending on the specified flags, name and level.
4170 * RETURNS:
4172 * If level is set to 1:
4173 * Returns an array of PRINTER_INFO_1 data structures in the
4174 * lpbPrinters buffer.
4176 * If level is set to 2:
4177 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4178 * Returns an array of PRINTER_INFO_2 data structures in the
4179 * lpbPrinters buffer. Note that according to MSDN also an
4180 * OpenPrinter should be performed on every remote printer.
4182 * If level is set to 4 (officially WinNT only):
4183 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4184 * Fast: Only the registry is queried to retrieve printer names,
4185 * no connection to the driver is made.
4186 * Returns an array of PRINTER_INFO_4 data structures in the
4187 * lpbPrinters buffer.
4189 * If level is set to 5 (officially WinNT4/Win9x only):
4190 * Fast: Only the registry is queried to retrieve printer names,
4191 * no connection to the driver is made.
4192 * Returns an array of PRINTER_INFO_5 data structures in the
4193 * lpbPrinters buffer.
4195 * If level set to 3 or 6+:
4196 * returns zero (failure!)
4198 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4199 * for information.
4201 * BUGS:
4202 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4203 * - Only levels 2, 4 and 5 are implemented at the moment.
4204 * - 16-bit printer drivers are not enumerated.
4205 * - Returned amount of bytes used/needed does not match the real Windoze
4206 * implementation (as in this implementation, all strings are part
4207 * of the buffer, whereas Win32 keeps them somewhere else)
4208 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4210 * NOTE:
4211 * - In a regular Wine installation, no registry settings for printers
4212 * exist, which makes this function return an empty list.
4214 BOOL WINAPI EnumPrintersW(
4215 DWORD dwType, /* [in] Types of print objects to enumerate */
4216 LPWSTR lpszName, /* [in] name of objects to enumerate */
4217 DWORD dwLevel, /* [in] type of printer info structure */
4218 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4219 DWORD cbBuf, /* [in] max size of buffer in bytes */
4220 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4221 LPDWORD lpdwReturned /* [out] number of entries returned */
4224 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4225 lpdwNeeded, lpdwReturned);
4228 /******************************************************************
4229 * EnumPrintersA [WINSPOOL.@]
4231 * See EnumPrintersW
4234 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4235 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4237 BOOL ret;
4238 UNICODE_STRING pNameU;
4239 LPWSTR pNameW;
4240 LPBYTE pPrintersW;
4242 TRACE("(0x%lx, %s, %lu, %p, %ld, %p, %p)\n", flags, debugstr_a(pName), level,
4243 pPrinters, cbBuf, pcbNeeded, pcReturned);
4245 pNameW = asciitounicode(&pNameU, pName);
4247 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4248 MS Office need this */
4249 pPrintersW = (pPrinters && cbBuf) ? malloc(cbBuf) : NULL;
4251 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4253 RtlFreeUnicodeString(&pNameU);
4254 if (ret) {
4255 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4257 free(pPrintersW);
4258 return ret;
4261 /*****************************************************************************
4262 * WINSPOOL_GetDriverInfoFromReg [internal]
4264 * Enters the information from the registry into the DRIVER_INFO struct
4266 * RETURNS
4267 * zero if the printer driver does not exist in the registry
4268 * (only if Level > 1) otherwise nonzero
4270 static BOOL WINSPOOL_GetDriverInfoFromReg(
4271 HKEY hkeyDrivers,
4272 LPWSTR DriverName,
4273 const printenv_t * env,
4274 DWORD Level,
4275 LPBYTE ptr, /* DRIVER_INFO */
4276 LPBYTE pDriverStrings, /* strings buffer */
4277 DWORD cbBuf, /* size of string buffer */
4278 LPDWORD pcbNeeded) /* space needed for str. */
4280 DWORD size, tmp;
4281 HKEY hkeyDriver;
4282 WCHAR driverdir[MAX_PATH];
4283 DWORD dirlen;
4284 LPBYTE strPtr = pDriverStrings;
4285 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4287 TRACE("(%p, %s, %p, %ld, %p, %p, %ld)\n", hkeyDrivers,
4288 debugstr_w(DriverName), env,
4289 Level, di, pDriverStrings, cbBuf);
4291 if (di) ZeroMemory(di, di_sizeof[Level]);
4293 *pcbNeeded = (wcslen( DriverName ) + 1) * sizeof(WCHAR);
4294 if (*pcbNeeded <= cbBuf)
4295 wcscpy( (WCHAR *)strPtr, DriverName );
4297 /* pName for level 1 has a different offset! */
4298 if (Level == 1) {
4299 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4300 return TRUE;
4303 /* .cVersion and .pName for level > 1 */
4304 if (di) {
4305 di->cVersion = env->driverversion;
4306 di->pName = (LPWSTR) strPtr;
4307 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4310 /* Reserve Space for "\\3\\" + \0 */
4311 size = sizeof(driverdir) - 4 * sizeof(WCHAR);
4312 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4313 /* Should never Fail */
4314 return FALSE;
4316 wcscat( driverdir, env->versionsubdir );
4317 wcscat( driverdir, L"\\" );
4319 /* dirlen must not include the terminating zero */
4320 dirlen = wcslen( driverdir ) * sizeof(WCHAR);
4322 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4323 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4324 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4325 return FALSE;
4328 /* pEnvironment */
4329 size = (wcslen( env->envname ) + 1) * sizeof(WCHAR);
4331 *pcbNeeded += size;
4332 if (*pcbNeeded <= cbBuf) {
4333 wcscpy( (WCHAR *)strPtr, env->envname );
4334 if (di) di->pEnvironment = (LPWSTR)strPtr;
4335 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4338 /* .pDriverPath is the Graphics rendering engine.
4339 The full Path is required to avoid a crash in some apps */
4340 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Driver", strPtr, 0, &size ))
4342 *pcbNeeded += size;
4343 if (*pcbNeeded <= cbBuf)
4344 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Driver", strPtr, size, &tmp );
4346 if (di) di->pDriverPath = (LPWSTR)strPtr;
4347 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4350 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4351 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Data File", strPtr, 0, &size ))
4353 *pcbNeeded += size;
4354 if (*pcbNeeded <= cbBuf)
4355 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Data File", strPtr, size, &size );
4357 if (di) di->pDataFile = (LPWSTR)strPtr;
4358 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4361 /* .pConfigFile is the Driver user Interface */
4362 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Configuration File", strPtr, 0, &size ))
4364 *pcbNeeded += size;
4365 if (*pcbNeeded <= cbBuf)
4366 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Configuration File", strPtr, size, &size );
4368 if (di) di->pConfigFile = (LPWSTR)strPtr;
4369 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4372 if (Level == 2 ) {
4373 RegCloseKey(hkeyDriver);
4374 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
4375 return TRUE;
4378 if (Level == 5 ) {
4379 RegCloseKey(hkeyDriver);
4380 FIXME("level 5: incomplete\n");
4381 return TRUE;
4384 /* .pHelpFile */
4385 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Help File", strPtr, 0, &size ))
4387 *pcbNeeded += size;
4388 if (*pcbNeeded <= cbBuf)
4389 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Help File", strPtr, size, &size );
4391 if (di) di->pHelpFile = (LPWSTR)strPtr;
4392 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4395 /* .pDependentFiles */
4396 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Dependent Files", strPtr, 0, &size ))
4398 *pcbNeeded += size;
4399 if (*pcbNeeded <= cbBuf)
4400 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Dependent Files", strPtr, size, &size );
4402 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4403 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4405 else if (GetVersion() & 0x80000000) {
4406 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4407 size = 2 * sizeof(WCHAR);
4408 *pcbNeeded += size;
4409 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4411 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4412 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4415 /* .pMonitorName is the optional Language Monitor */
4416 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Monitor", strPtr, 0, &size ))
4418 *pcbNeeded += size;
4419 if (*pcbNeeded <= cbBuf)
4420 WINSPOOL_GetStringFromReg( hkeyDriver, L"Monitor", strPtr, size, &size );
4422 if (di) di->pMonitorName = (LPWSTR)strPtr;
4423 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4426 /* .pDefaultDataType */
4427 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Datatype", strPtr, 0, &size ))
4429 *pcbNeeded += size;
4430 if(*pcbNeeded <= cbBuf)
4431 WINSPOOL_GetStringFromReg( hkeyDriver, L"Datatype", strPtr, size, &size );
4433 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4434 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4437 if (Level == 3 ) {
4438 RegCloseKey(hkeyDriver);
4439 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
4440 return TRUE;
4443 /* .pszzPreviousNames */
4444 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Previous Names", strPtr, 0, &size ))
4446 *pcbNeeded += size;
4447 if(*pcbNeeded <= cbBuf)
4448 WINSPOOL_GetStringFromReg( hkeyDriver, L"Previous Names", strPtr, size, &size );
4450 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4451 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4454 if (Level == 4 ) {
4455 RegCloseKey(hkeyDriver);
4456 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
4457 return TRUE;
4460 /* support is missing, but not important enough for a FIXME */
4461 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4463 /* .pszMfgName */
4464 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Manufacturer", strPtr, 0, &size ))
4466 *pcbNeeded += size;
4467 if(*pcbNeeded <= cbBuf)
4468 WINSPOOL_GetStringFromReg( hkeyDriver, L"Manufacturer", strPtr, size, &size );
4470 if (di) di->pszMfgName = (LPWSTR)strPtr;
4471 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4474 /* .pszOEMUrl */
4475 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"OEM Url", strPtr, 0, &size ))
4477 *pcbNeeded += size;
4478 if(*pcbNeeded <= cbBuf)
4479 WINSPOOL_GetStringFromReg( hkeyDriver, L"OEM Url", strPtr, size, &size );
4481 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4482 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4485 /* .pszHardwareID */
4486 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"HardwareID", strPtr, 0, &size ))
4488 *pcbNeeded += size;
4489 if(*pcbNeeded <= cbBuf)
4490 WINSPOOL_GetStringFromReg( hkeyDriver, L"HardwareID", strPtr, size, &size );
4492 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4493 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4496 /* .pszProvider */
4497 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Provider", strPtr, 0, &size ))
4499 *pcbNeeded += size;
4500 if(*pcbNeeded <= cbBuf)
4501 WINSPOOL_GetStringFromReg( hkeyDriver, L"Provider", strPtr, size, &size );
4503 if (di) di->pszProvider = (LPWSTR)strPtr;
4504 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4507 if (Level == 6 ) {
4508 RegCloseKey(hkeyDriver);
4509 return TRUE;
4512 /* support is missing, but not important enough for a FIXME */
4513 TRACE("level 8: incomplete\n");
4515 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
4516 RegCloseKey(hkeyDriver);
4517 return TRUE;
4520 /*****************************************************************************
4521 * GetPrinterDriverW [WINSPOOL.@]
4523 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4524 DWORD Level, LPBYTE pDriverInfo,
4525 DWORD cbBuf, LPDWORD pcbNeeded)
4527 LPCWSTR name;
4528 WCHAR DriverName[100];
4529 DWORD ret, type, size, needed = 0;
4530 LPBYTE ptr = NULL;
4531 HKEY hkeyPrinter, hkeyDrivers;
4532 const printenv_t * env;
4534 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
4535 Level,pDriverInfo,cbBuf, pcbNeeded);
4537 if (cbBuf > 0)
4538 ZeroMemory(pDriverInfo, cbBuf);
4540 if (!(name = get_opened_printer_name(hPrinter))) {
4541 SetLastError(ERROR_INVALID_HANDLE);
4542 return FALSE;
4545 if (Level < 1 || Level == 7 || Level > 8) {
4546 SetLastError(ERROR_INVALID_LEVEL);
4547 return FALSE;
4550 env = validate_envW(pEnvironment);
4551 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4553 ret = open_printer_reg_key( name, &hkeyPrinter );
4554 if (ret)
4556 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4557 SetLastError( ret );
4558 return FALSE;
4561 size = sizeof(DriverName);
4562 DriverName[0] = 0;
4563 ret = RegQueryValueExW( hkeyPrinter, L"Printer Driver", 0, &type, (BYTE *)DriverName, &size );
4564 RegCloseKey(hkeyPrinter);
4565 if(ret != ERROR_SUCCESS) {
4566 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4567 return FALSE;
4570 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4571 if(!hkeyDrivers) {
4572 ERR("Can't create Drivers key\n");
4573 return FALSE;
4576 size = di_sizeof[Level];
4577 if ((size <= cbBuf) && pDriverInfo)
4578 ptr = pDriverInfo + size;
4580 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4581 env, Level, pDriverInfo, ptr,
4582 (cbBuf < size) ? 0 : cbBuf - size,
4583 &needed)) {
4584 RegCloseKey(hkeyDrivers);
4585 return FALSE;
4588 RegCloseKey(hkeyDrivers);
4590 if(pcbNeeded) *pcbNeeded = size + needed;
4591 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
4592 if(cbBuf >= size + needed) return TRUE;
4593 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4594 return FALSE;
4597 /*****************************************************************************
4598 * GetPrinterDriverA [WINSPOOL.@]
4600 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4601 DWORD Level, LPBYTE pDriverInfo,
4602 DWORD cbBuf, LPDWORD pcbNeeded)
4604 BOOL ret;
4605 UNICODE_STRING pEnvW;
4606 PWSTR pwstrEnvW;
4607 LPBYTE buf = NULL;
4609 if (cbBuf)
4611 ZeroMemory(pDriverInfo, cbBuf);
4612 buf = malloc(cbBuf);
4615 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4616 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4617 cbBuf, pcbNeeded);
4618 if (ret)
4619 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4621 free(buf);
4623 RtlFreeUnicodeString(&pEnvW);
4624 return ret;
4627 /*****************************************************************************
4628 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4630 * Return the PATH for the Printer-Drivers (UNICODE)
4632 * PARAMS
4633 * pName [I] Servername (NT only) or NULL (local Computer)
4634 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4635 * Level [I] Structure-Level (must be 1)
4636 * pDriverDirectory [O] PTR to Buffer that receives the Result
4637 * cbBuf [I] Size of Buffer at pDriverDirectory
4638 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4639 * required for pDriverDirectory
4641 * RETURNS
4642 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4643 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4644 * if cbBuf is too small
4646 * Native Values returned in pDriverDirectory on Success:
4647 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4648 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4649 *| win9x(Windows 4.0): "%winsysdir%"
4651 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4653 * FIXME
4654 *- Only NULL or "" is supported for pName
4657 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4658 DWORD Level, LPBYTE pDriverDirectory,
4659 DWORD cbBuf, LPDWORD pcbNeeded)
4661 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
4662 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4664 if ((backend == NULL) && !load_backend()) return FALSE;
4666 if (Level != 1) {
4667 /* (Level != 1) is ignored in win9x */
4668 SetLastError(ERROR_INVALID_LEVEL);
4669 return FALSE;
4671 if (pcbNeeded == NULL) {
4672 /* (pcbNeeded == NULL) is ignored in win9x */
4673 SetLastError(RPC_X_NULL_REF_POINTER);
4674 return FALSE;
4677 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4678 pDriverDirectory, cbBuf, pcbNeeded);
4683 /*****************************************************************************
4684 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4686 * Return the PATH for the Printer-Drivers (ANSI)
4688 * See GetPrinterDriverDirectoryW.
4690 * NOTES
4691 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4694 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4695 DWORD Level, LPBYTE pDriverDirectory,
4696 DWORD cbBuf, LPDWORD pcbNeeded)
4698 UNICODE_STRING nameW, environmentW;
4699 BOOL ret;
4700 DWORD pcbNeededW;
4701 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4702 WCHAR *driverDirectoryW = NULL;
4704 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
4705 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4707 if (len) driverDirectoryW = malloc( len );
4709 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4710 else nameW.Buffer = NULL;
4711 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4712 else environmentW.Buffer = NULL;
4714 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4715 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4716 if (ret) {
4717 DWORD needed;
4718 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4719 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4720 if(pcbNeeded)
4721 *pcbNeeded = needed;
4722 ret = needed <= cbBuf;
4723 } else
4724 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4726 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4728 free( driverDirectoryW );
4729 RtlFreeUnicodeString(&environmentW);
4730 RtlFreeUnicodeString(&nameW);
4732 return ret;
4735 /*****************************************************************************
4736 * AddPrinterDriverA [WINSPOOL.@]
4738 * See AddPrinterDriverW.
4741 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4743 TRACE("(%s, %ld, %p)\n", debugstr_a(pName), level, pDriverInfo);
4744 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4747 /******************************************************************************
4748 * AddPrinterDriverW (WINSPOOL.@)
4750 * Install a Printer Driver
4752 * PARAMS
4753 * pName [I] Servername or NULL (local Computer)
4754 * level [I] Level for the supplied DRIVER_INFO_*W struct
4755 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4757 * RESULTS
4758 * Success: TRUE
4759 * Failure: FALSE
4762 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4764 TRACE("(%s, %ld, %p)\n", debugstr_w(pName), level, pDriverInfo);
4765 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4768 /*****************************************************************************
4769 * AddPrintProcessorA [WINSPOOL.@]
4771 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4772 LPSTR pPrintProcessorName)
4774 UNICODE_STRING NameW, EnvW, PathW, ProcessorW;
4775 BOOL ret;
4777 TRACE("(%s,%s,%s,%s)\n", debugstr_a(pName), debugstr_a(pEnvironment),
4778 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4780 asciitounicode(&NameW, pName);
4781 asciitounicode(&EnvW, pEnvironment);
4782 asciitounicode(&PathW, pPathName);
4783 asciitounicode(&ProcessorW, pPrintProcessorName);
4785 ret = AddPrintProcessorW(NameW.Buffer, EnvW.Buffer, PathW.Buffer, ProcessorW.Buffer);
4787 RtlFreeUnicodeString(&ProcessorW);
4788 RtlFreeUnicodeString(&PathW);
4789 RtlFreeUnicodeString(&EnvW);
4790 RtlFreeUnicodeString(&NameW);
4792 return ret;
4795 /*****************************************************************************
4796 * AddPrintProcessorW [WINSPOOL.@]
4798 BOOL WINAPI AddPrintProcessorW(WCHAR *name, WCHAR *env, WCHAR *path, WCHAR *print_proc)
4800 TRACE("(%s,%s,%s,%s)\n", debugstr_w(name), debugstr_w(env),
4801 debugstr_w(path), debugstr_w(print_proc));
4803 if (!path || !print_proc)
4805 SetLastError(ERROR_INVALID_PARAMETER);
4806 return FALSE;
4809 if ((backend == NULL) && !load_backend()) return FALSE;
4810 return backend->fpAddPrintProcessor(name, env, path, print_proc);
4813 /*****************************************************************************
4814 * AddPrintProvidorA [WINSPOOL.@]
4816 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4818 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4819 return FALSE;
4822 /*****************************************************************************
4823 * AddPrintProvidorW [WINSPOOL.@]
4825 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4827 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4828 return FALSE;
4831 /*****************************************************************************
4832 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4834 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4835 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4837 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4838 pDevModeOutput, pDevModeInput);
4839 return 0;
4842 /*****************************************************************************
4843 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4845 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4846 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4848 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4849 pDevModeOutput, pDevModeInput);
4850 return 0;
4853 /*****************************************************************************
4854 * PrinterProperties [WINSPOOL.@]
4856 * Displays a dialog to set the properties of the printer.
4858 * RETURNS
4859 * nonzero on success or zero on failure
4861 * BUGS
4862 * implemented as stub only
4864 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4865 HANDLE hPrinter /* [in] handle to printer object */
4867 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4868 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4869 return FALSE;
4872 /*****************************************************************************
4873 * EnumJobsA [WINSPOOL.@]
4876 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4877 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4878 LPDWORD pcReturned)
4880 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4881 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4883 if(pcbNeeded) *pcbNeeded = 0;
4884 if(pcReturned) *pcReturned = 0;
4885 return FALSE;
4889 /*****************************************************************************
4890 * EnumJobsW [WINSPOOL.@]
4893 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4894 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4895 LPDWORD pcReturned)
4897 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4898 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4900 if(pcbNeeded) *pcbNeeded = 0;
4901 if(pcReturned) *pcReturned = 0;
4902 return FALSE;
4905 /*****************************************************************************
4906 * WINSPOOL_EnumPrinterDrivers [internal]
4908 * Delivers information about all printer drivers installed on the
4909 * localhost or a given server
4911 * RETURNS
4912 * nonzero on success or zero on failure. If the buffer for the returned
4913 * information is too small the function will return an error
4915 * BUGS
4916 * - only implemented for localhost, foreign hosts will return an error
4918 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4919 DWORD Level, LPBYTE pDriverInfo,
4920 DWORD driver_index,
4921 DWORD cbBuf, LPDWORD pcbNeeded,
4922 LPDWORD pcFound, DWORD data_offset)
4924 { HKEY hkeyDrivers;
4925 DWORD i, size = 0;
4926 const printenv_t * env;
4928 TRACE("%s,%s,%ld,%p,%ld,%ld,%ld\n",
4929 debugstr_w(pName), debugstr_w(pEnvironment),
4930 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4932 env = validate_envW(pEnvironment);
4933 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4935 *pcFound = 0;
4937 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4938 if(!hkeyDrivers) {
4939 ERR("Can't open Drivers key\n");
4940 return FALSE;
4943 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4944 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4945 RegCloseKey(hkeyDrivers);
4946 ERR("Can't query Drivers key\n");
4947 return FALSE;
4949 TRACE("Found %ld Drivers\n", *pcFound);
4951 /* get size of single struct
4952 * unicode and ascii structure have the same size
4954 size = di_sizeof[Level];
4956 if (data_offset == 0)
4957 data_offset = size * (*pcFound);
4958 *pcbNeeded = data_offset;
4960 for( i = 0; i < *pcFound; i++) {
4961 WCHAR DriverNameW[255];
4962 PBYTE table_ptr = NULL;
4963 PBYTE data_ptr = NULL;
4964 DWORD needed = 0;
4966 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, ARRAY_SIZE(DriverNameW)) != ERROR_SUCCESS) {
4967 ERR("Can't enum key number %ld\n", i);
4968 RegCloseKey(hkeyDrivers);
4969 return FALSE;
4972 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4973 table_ptr = pDriverInfo + (driver_index + i) * size;
4974 if (pDriverInfo && *pcbNeeded <= cbBuf)
4975 data_ptr = pDriverInfo + *pcbNeeded;
4977 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4978 env, Level, table_ptr, data_ptr,
4979 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4980 &needed)) {
4981 RegCloseKey(hkeyDrivers);
4982 return FALSE;
4985 *pcbNeeded += needed;
4988 RegCloseKey(hkeyDrivers);
4990 if(cbBuf < *pcbNeeded){
4991 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4992 return FALSE;
4995 return TRUE;
4998 /*****************************************************************************
4999 * EnumPrinterDriversW [WINSPOOL.@]
5001 * see function EnumPrinterDrivers for RETURNS, BUGS
5003 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5004 LPBYTE pDriverInfo, DWORD cbBuf,
5005 LPDWORD pcbNeeded, LPDWORD pcReturned)
5007 BOOL ret;
5008 DWORD found;
5010 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5012 SetLastError(RPC_X_NULL_REF_POINTER);
5013 return FALSE;
5016 /* check for local drivers */
5017 if((pName) && (pName[0])) {
5018 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5019 SetLastError(ERROR_ACCESS_DENIED);
5020 return FALSE;
5023 /* check input parameter */
5024 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5025 SetLastError(ERROR_INVALID_LEVEL);
5026 return FALSE;
5029 if(pDriverInfo && cbBuf > 0)
5030 memset( pDriverInfo, 0, cbBuf);
5032 /* Exception: pull all printers */
5033 if (pEnvironment && !wcscmp( pEnvironment, L"all" ))
5035 DWORD i, needed, bufsize = cbBuf;
5036 DWORD total_found = 0;
5037 DWORD data_offset;
5039 /* Precompute the overall total; we need this to know
5040 where pointers end and data begins (i.e. data_offset) */
5041 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5043 needed = found = 0;
5044 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5045 NULL, 0, 0, &needed, &found, 0);
5046 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5047 total_found += found;
5050 data_offset = di_sizeof[Level] * total_found;
5052 *pcReturned = 0;
5053 *pcbNeeded = 0;
5054 total_found = 0;
5055 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5057 needed = found = 0;
5058 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5059 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5060 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5061 else if (ret)
5062 *pcReturned += found;
5063 *pcbNeeded = needed;
5064 data_offset = needed;
5065 total_found += found;
5067 return ret;
5070 /* Normal behavior */
5071 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5072 0, cbBuf, pcbNeeded, &found, 0);
5073 if (ret)
5074 *pcReturned = found;
5076 return ret;
5079 /*****************************************************************************
5080 * EnumPrinterDriversA [WINSPOOL.@]
5082 * see function EnumPrinterDrivers for RETURNS, BUGS
5084 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5085 LPBYTE pDriverInfo, DWORD cbBuf,
5086 LPDWORD pcbNeeded, LPDWORD pcReturned)
5088 BOOL ret;
5089 UNICODE_STRING pNameW, pEnvironmentW;
5090 PWSTR pwstrNameW, pwstrEnvironmentW;
5091 LPBYTE buf = NULL;
5093 if (cbBuf)
5094 buf = malloc(cbBuf);
5096 pwstrNameW = asciitounicode(&pNameW, pName);
5097 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5099 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5100 buf, cbBuf, pcbNeeded, pcReturned);
5101 if (ret)
5102 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5104 free(buf);
5106 RtlFreeUnicodeString(&pNameW);
5107 RtlFreeUnicodeString(&pEnvironmentW);
5109 return ret;
5112 /******************************************************************************
5113 * EnumPortsA (WINSPOOL.@)
5115 * See EnumPortsW.
5118 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5119 LPDWORD pcbNeeded, LPDWORD pcReturned)
5121 BOOL res;
5122 LPBYTE bufferW = NULL;
5123 LPWSTR nameW = NULL;
5124 DWORD needed = 0;
5125 DWORD numentries = 0;
5126 INT len;
5128 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5129 cbBuf, pcbNeeded, pcReturned);
5131 /* convert servername to unicode */
5132 if (pName) {
5133 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5134 nameW = malloc(len * sizeof(WCHAR));
5135 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5137 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5138 needed = cbBuf * sizeof(WCHAR);
5139 if (needed) bufferW = malloc(needed);
5140 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5142 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5143 if (pcbNeeded) needed = *pcbNeeded;
5144 /* HeapReAlloc return NULL, when bufferW was NULL */
5145 bufferW = (bufferW) ? realloc(bufferW, needed) : malloc(needed);
5147 /* Try again with the large Buffer */
5148 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5150 needed = pcbNeeded ? *pcbNeeded : 0;
5151 numentries = pcReturned ? *pcReturned : 0;
5154 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5155 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5157 if (res) {
5158 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5159 DWORD entrysize = 0;
5160 DWORD index;
5161 LPSTR ptr;
5162 LPPORT_INFO_2W pi2w;
5163 LPPORT_INFO_2A pi2a;
5165 needed = 0;
5166 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5168 /* First pass: calculate the size for all Entries */
5169 pi2w = (LPPORT_INFO_2W) bufferW;
5170 pi2a = (LPPORT_INFO_2A) pPorts;
5171 index = 0;
5172 while (index < numentries) {
5173 index++;
5174 needed += entrysize; /* PORT_INFO_?A */
5175 TRACE("%p: parsing #%ld (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5177 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5178 NULL, 0, NULL, NULL);
5179 if (Level > 1) {
5180 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5181 NULL, 0, NULL, NULL);
5182 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5183 NULL, 0, NULL, NULL);
5185 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5186 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5187 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5190 /* check for errors and quit on failure */
5191 if (cbBuf < needed) {
5192 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5193 res = FALSE;
5194 goto cleanup;
5196 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5197 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5198 cbBuf -= len ; /* free Bytes in the user-Buffer */
5199 pi2w = (LPPORT_INFO_2W) bufferW;
5200 pi2a = (LPPORT_INFO_2A) pPorts;
5201 index = 0;
5202 /* Second Pass: Fill the User Buffer (if we have one) */
5203 while ((index < numentries) && pPorts) {
5204 index++;
5205 TRACE("%p: writing PORT_INFO_%ldA #%ld\n", pi2a, Level, index);
5206 pi2a->pPortName = ptr;
5207 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5208 ptr, cbBuf , NULL, NULL);
5209 ptr += len;
5210 cbBuf -= len;
5211 if (Level > 1) {
5212 pi2a->pMonitorName = ptr;
5213 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5214 ptr, cbBuf, NULL, NULL);
5215 ptr += len;
5216 cbBuf -= len;
5218 pi2a->pDescription = ptr;
5219 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5220 ptr, cbBuf, NULL, NULL);
5221 ptr += len;
5222 cbBuf -= len;
5224 pi2a->fPortType = pi2w->fPortType;
5225 pi2a->Reserved = 0; /* documented: "must be zero" */
5228 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5229 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5230 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5234 cleanup:
5235 if (pcbNeeded) *pcbNeeded = needed;
5236 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5238 free(nameW);
5239 free(bufferW);
5241 TRACE("returning %d with %ld (%ld byte for %ld of %ld entries)\n",
5242 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5244 return (res);
5248 /******************************************************************************
5249 * EnumPortsW (WINSPOOL.@)
5251 * Enumerate available Ports
5253 * PARAMS
5254 * pName [I] Servername or NULL (local Computer)
5255 * Level [I] Structure-Level (1 or 2)
5256 * pPorts [O] PTR to Buffer that receives the Result
5257 * cbBuf [I] Size of Buffer at pPorts
5258 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5259 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5261 * RETURNS
5262 * Success: TRUE
5263 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5266 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5269 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5270 cbBuf, pcbNeeded, pcReturned);
5272 if ((backend == NULL) && !load_backend()) return FALSE;
5274 /* Level is not checked in win9x */
5275 if (!Level || (Level > 2)) {
5276 WARN("level (%ld) is ignored in win9x\n", Level);
5277 SetLastError(ERROR_INVALID_LEVEL);
5278 return FALSE;
5280 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5281 SetLastError(RPC_X_NULL_REF_POINTER);
5282 return FALSE;
5285 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5288 /******************************************************************************
5289 * GetDefaultPrinterW (WINSPOOL.@)
5291 * FIXME
5292 * This function must read the value from data 'device' of key
5293 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5295 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5297 BOOL retval = TRUE;
5298 DWORD insize, len;
5299 WCHAR *buffer, *ptr;
5301 if (!namesize)
5303 SetLastError(ERROR_INVALID_PARAMETER);
5304 return FALSE;
5307 /* make the buffer big enough for the stuff from the profile/registry,
5308 * the content must fit into the local buffer to compute the correct
5309 * size even if the extern buffer is too small or not given.
5310 * (20 for ,driver,port) */
5311 insize = *namesize;
5312 len = max(100, (insize + 20));
5313 buffer = malloc( len * sizeof(WCHAR));
5315 if (!GetProfileStringW( L"windows", L"device", L"", buffer, len ))
5317 SetLastError (ERROR_FILE_NOT_FOUND);
5318 retval = FALSE;
5319 goto end;
5321 TRACE("%s\n", debugstr_w(buffer));
5323 if ((ptr = wcschr( buffer, ',' )) == NULL)
5325 SetLastError(ERROR_INVALID_NAME);
5326 retval = FALSE;
5327 goto end;
5330 *ptr = 0;
5331 *namesize = wcslen( buffer ) + 1;
5332 if(!name || (*namesize > insize))
5334 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5335 retval = FALSE;
5336 goto end;
5338 wcscpy( name, buffer );
5340 end:
5341 free( buffer);
5342 return retval;
5346 /******************************************************************************
5347 * GetDefaultPrinterA (WINSPOOL.@)
5349 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5351 BOOL retval = TRUE;
5352 DWORD insize = 0;
5353 WCHAR *bufferW = NULL;
5355 if (!namesize)
5357 SetLastError(ERROR_INVALID_PARAMETER);
5358 return FALSE;
5361 if(name && *namesize) {
5362 insize = *namesize;
5363 bufferW = malloc( insize * sizeof(WCHAR));
5366 if(!GetDefaultPrinterW( bufferW, namesize)) {
5367 retval = FALSE;
5368 goto end;
5371 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5372 NULL, NULL);
5373 if (!*namesize)
5375 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5376 retval = FALSE;
5378 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
5380 end:
5381 free( bufferW);
5382 return retval;
5386 /******************************************************************************
5387 * SetDefaultPrinterW (WINSPOOL.204)
5389 * Set the Name of the Default Printer
5391 * PARAMS
5392 * pszPrinter [I] Name of the Printer or NULL
5394 * RETURNS
5395 * Success: True
5396 * Failure: FALSE
5398 * NOTES
5399 * When the Parameter is NULL or points to an Empty String and
5400 * a Default Printer was already present, then this Function changes nothing.
5401 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5402 * the First enumerated local Printer is used.
5405 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5407 WCHAR default_printer[MAX_PATH];
5408 LPWSTR buffer = NULL;
5409 HKEY hreg;
5410 DWORD size;
5411 DWORD namelen;
5412 LONG lres;
5414 TRACE("(%s)\n", debugstr_w(pszPrinter));
5415 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5417 default_printer[0] = '\0';
5418 size = ARRAY_SIZE(default_printer);
5420 /* if we have a default Printer, do nothing. */
5421 if (GetDefaultPrinterW(default_printer, &size))
5422 return TRUE;
5424 pszPrinter = NULL;
5425 /* we have no default Printer: search local Printers and use the first */
5426 if (!create_printers_reg_key( system_printers_key, &hreg ))
5428 default_printer[0] = '\0';
5429 size = ARRAY_SIZE(default_printer);
5430 if (!RegEnumKeyExW( hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL ))
5432 pszPrinter = default_printer;
5433 TRACE("using %s\n", debugstr_w(pszPrinter));
5435 RegCloseKey( hreg );
5438 if (pszPrinter == NULL) {
5439 TRACE("no local printer found\n");
5440 SetLastError(ERROR_FILE_NOT_FOUND);
5441 return FALSE;
5445 /* "pszPrinter" is never empty or NULL here. */
5446 namelen = wcslen( pszPrinter );
5447 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5448 buffer = malloc(size * sizeof(WCHAR));
5449 if (!buffer || create_printers_reg_key( user_printers_key, &hreg ))
5451 free(buffer);
5452 SetLastError(ERROR_FILE_NOT_FOUND);
5453 return FALSE;
5456 /* read the devices entry for the printer (driver,port) to build the string for the
5457 default device entry (printer,driver,port) */
5458 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5459 buffer[namelen] = ',';
5460 namelen++; /* move index to the start of the driver */
5462 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5463 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5464 if (!lres) {
5465 HKEY hdev;
5467 if (!create_printers_reg_key( user_default_key, &hdev ))
5469 RegSetValueExW( hdev, L"device", 0, REG_SZ, (BYTE *)buffer, (wcslen( buffer ) + 1) * sizeof(WCHAR) );
5470 RegCloseKey(hdev);
5473 else
5475 if (lres != ERROR_FILE_NOT_FOUND)
5476 FIXME("RegQueryValueExW failed with %ld for %s\n", lres, debugstr_w(pszPrinter));
5478 SetLastError(ERROR_INVALID_PRINTER_NAME);
5481 RegCloseKey(hreg);
5482 free(buffer);
5483 return (lres == ERROR_SUCCESS);
5486 /******************************************************************************
5487 * SetDefaultPrinterA (WINSPOOL.202)
5489 * See SetDefaultPrinterW.
5492 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5494 LPWSTR bufferW = NULL;
5495 BOOL res;
5497 TRACE("(%s)\n", debugstr_a(pszPrinter));
5498 if(pszPrinter) {
5499 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5500 bufferW = malloc(len * sizeof(WCHAR));
5501 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5503 res = SetDefaultPrinterW(bufferW);
5504 free(bufferW);
5505 return res;
5508 /******************************************************************************
5509 * SetPrinterDataExA (WINSPOOL.@)
5511 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5512 LPCSTR pValueName, DWORD Type,
5513 LPBYTE pData, DWORD cbData)
5515 HKEY hkeyPrinter, hkeySubkey;
5516 DWORD ret;
5518 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
5519 debugstr_a(pValueName), Type, pData, cbData);
5521 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5522 != ERROR_SUCCESS)
5523 return ret;
5525 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5526 != ERROR_SUCCESS) {
5527 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5528 RegCloseKey(hkeyPrinter);
5529 return ret;
5531 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5532 RegCloseKey(hkeySubkey);
5533 RegCloseKey(hkeyPrinter);
5534 return ret;
5537 /******************************************************************************
5538 * SetPrinterDataExW (WINSPOOL.@)
5540 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5541 LPCWSTR pValueName, DWORD Type,
5542 LPBYTE pData, DWORD cbData)
5544 HKEY hkeyPrinter, hkeySubkey;
5545 DWORD ret;
5547 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
5548 debugstr_w(pValueName), Type, pData, cbData);
5550 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5551 != ERROR_SUCCESS)
5552 return ret;
5554 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5555 != ERROR_SUCCESS) {
5556 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5557 RegCloseKey(hkeyPrinter);
5558 return ret;
5560 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5561 RegCloseKey(hkeySubkey);
5562 RegCloseKey(hkeyPrinter);
5563 return ret;
5566 /******************************************************************************
5567 * SetPrinterDataA (WINSPOOL.@)
5569 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5570 LPBYTE pData, DWORD cbData)
5572 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5573 pData, cbData);
5576 /******************************************************************************
5577 * SetPrinterDataW (WINSPOOL.@)
5579 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5580 LPBYTE pData, DWORD cbData)
5582 return SetPrinterDataExW( hPrinter, L"PrinterDriverData", pValueName, Type,
5583 pData, cbData );
5586 /******************************************************************************
5587 * GetPrinterDataExA (WINSPOOL.@)
5589 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5590 LPCSTR pValueName, LPDWORD pType,
5591 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5593 opened_printer_t *printer;
5594 HKEY printers_key, hkeyPrinter = 0, hkeySubkey = 0;
5595 DWORD ret;
5597 TRACE("(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter, debugstr_a(pKeyName),
5598 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5600 printer = get_opened_printer(hPrinter);
5601 if(!printer) return ERROR_INVALID_HANDLE;
5603 ret = create_printers_reg_key( system_printers_key, &printers_key );
5604 if (ret) return ret;
5606 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5608 if (printer->name) {
5610 ret = RegOpenKeyW( printers_key, printer->name, &hkeyPrinter );
5611 if (ret)
5613 RegCloseKey( printers_key );
5614 return ret;
5616 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5617 WARN("Can't open subkey %s: %ld\n", debugstr_a(pKeyName), ret);
5618 RegCloseKey(hkeyPrinter);
5619 RegCloseKey( printers_key );
5620 return ret;
5623 *pcbNeeded = nSize;
5624 ret = RegQueryValueExA( printer->name ? hkeySubkey : printers_key, pValueName,
5625 0, pType, pData, pcbNeeded );
5627 if (!ret && !pData) ret = ERROR_MORE_DATA;
5629 RegCloseKey(hkeySubkey);
5630 RegCloseKey(hkeyPrinter);
5631 RegCloseKey( printers_key );
5633 TRACE("--> %ld\n", ret);
5634 return ret;
5637 /******************************************************************************
5638 * GetPrinterDataExW (WINSPOOL.@)
5640 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5641 LPCWSTR pValueName, LPDWORD pType,
5642 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5644 opened_printer_t *printer;
5645 HKEY printers_key, hkeyPrinter = 0, hkeySubkey = 0;
5646 DWORD ret;
5648 TRACE("(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter, debugstr_w(pKeyName),
5649 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5651 printer = get_opened_printer(hPrinter);
5652 if(!printer) return ERROR_INVALID_HANDLE;
5654 ret = create_printers_reg_key( system_printers_key, &printers_key );
5655 if (ret) return ret;
5657 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5659 if (printer->name)
5661 ret = RegOpenKeyW( printers_key, printer->name, &hkeyPrinter);
5662 if (ret)
5664 RegCloseKey( printers_key );
5665 return ret;
5667 if ((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS)
5669 WARN("Can't open subkey %s: %ld\n", debugstr_w(pKeyName), ret);
5670 RegCloseKey(hkeyPrinter);
5671 RegCloseKey( printers_key );
5672 return ret;
5675 *pcbNeeded = nSize;
5676 ret = RegQueryValueExW( printer->name ? hkeySubkey : printers_key, pValueName,
5677 0, pType, pData, pcbNeeded );
5679 if (!ret && !pData) ret = ERROR_MORE_DATA;
5681 RegCloseKey(hkeySubkey);
5682 RegCloseKey(hkeyPrinter);
5683 RegCloseKey( printers_key );
5685 TRACE("--> %ld\n", ret);
5686 return ret;
5689 /******************************************************************************
5690 * GetPrinterDataA (WINSPOOL.@)
5692 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5693 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5695 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5696 pData, nSize, pcbNeeded);
5699 /******************************************************************************
5700 * GetPrinterDataW (WINSPOOL.@)
5702 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5703 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5705 return GetPrinterDataExW( hPrinter, L"PrinterDriverData", pValueName, pType,
5706 pData, nSize, pcbNeeded );
5709 /*******************************************************************************
5710 * EnumPrinterDataExW [WINSPOOL.@]
5712 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5713 LPBYTE pEnumValues, DWORD cbEnumValues,
5714 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5716 HKEY hkPrinter, hkSubKey;
5717 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5718 cbValueNameLen, cbMaxValueLen, cbValueLen,
5719 cbBufSize, dwType;
5720 LPWSTR lpValueName;
5721 PBYTE lpValue;
5722 PPRINTER_ENUM_VALUESW ppev;
5724 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5726 if (pKeyName == NULL || *pKeyName == 0)
5727 return ERROR_INVALID_PARAMETER;
5729 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5730 if (ret != ERROR_SUCCESS)
5732 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
5733 hPrinter, ret);
5734 return ret;
5737 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5738 if (ret != ERROR_SUCCESS)
5740 r = RegCloseKey (hkPrinter);
5741 if (r != ERROR_SUCCESS)
5742 WARN ("RegCloseKey returned %li\n", r);
5743 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
5744 debugstr_w (pKeyName), ret);
5745 return ret;
5748 ret = RegCloseKey (hkPrinter);
5749 if (ret != ERROR_SUCCESS)
5751 ERR ("RegCloseKey returned %li\n", ret);
5752 r = RegCloseKey (hkSubKey);
5753 if (r != ERROR_SUCCESS)
5754 WARN ("RegCloseKey returned %li\n", r);
5755 return ret;
5758 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5759 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5760 if (ret != ERROR_SUCCESS)
5762 r = RegCloseKey (hkSubKey);
5763 if (r != ERROR_SUCCESS)
5764 WARN ("RegCloseKey returned %li\n", r);
5765 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
5766 return ret;
5769 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
5770 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5772 if (cValues == 0) /* empty key */
5774 r = RegCloseKey (hkSubKey);
5775 if (r != ERROR_SUCCESS)
5776 WARN ("RegCloseKey returned %li\n", r);
5777 *pcbEnumValues = *pnEnumValues = 0;
5778 return ERROR_SUCCESS;
5781 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5783 lpValueName = malloc (cbMaxValueNameLen * sizeof(WCHAR));
5784 if (lpValueName == NULL)
5786 ERR ("Failed to allocate %li WCHARs\n", cbMaxValueNameLen);
5787 r = RegCloseKey (hkSubKey);
5788 if (r != ERROR_SUCCESS)
5789 WARN ("RegCloseKey returned %li\n", r);
5790 return ERROR_OUTOFMEMORY;
5793 lpValue = malloc (cbMaxValueLen);
5794 if (lpValue == NULL)
5796 ERR ("Failed to allocate %li bytes\n", cbMaxValueLen);
5797 free (lpValueName);
5798 r = RegCloseKey (hkSubKey);
5799 if (r != ERROR_SUCCESS)
5800 WARN ("RegCloseKey returned %li\n", r);
5801 return ERROR_OUTOFMEMORY;
5804 TRACE ("pass 1: calculating buffer required for all names and values\n");
5806 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5808 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
5810 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5812 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5813 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5814 NULL, NULL, lpValue, &cbValueLen);
5815 if (ret != ERROR_SUCCESS)
5817 free (lpValue);
5818 free (lpValueName);
5819 r = RegCloseKey (hkSubKey);
5820 if (r != ERROR_SUCCESS)
5821 WARN ("RegCloseKey returned %li\n", r);
5822 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
5823 return ret;
5826 TRACE ("%s [%li]: name needs %li WCHARs, data needs %li bytes\n",
5827 debugstr_w (lpValueName), dwIndex,
5828 cbValueNameLen + 1, cbValueLen);
5830 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5831 cbBufSize += cbValueLen;
5834 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
5836 *pcbEnumValues = cbBufSize;
5837 *pnEnumValues = cValues;
5839 if (cbEnumValues < cbBufSize) /* buffer too small */
5841 free (lpValue);
5842 free (lpValueName);
5843 r = RegCloseKey (hkSubKey);
5844 if (r != ERROR_SUCCESS)
5845 WARN ("RegCloseKey returned %li\n", r);
5846 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
5847 return ERROR_MORE_DATA;
5850 TRACE ("pass 2: copying all names and values to buffer\n");
5852 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5853 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5855 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5857 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5858 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5859 NULL, &dwType, lpValue, &cbValueLen);
5860 if (ret != ERROR_SUCCESS)
5862 free (lpValue);
5863 free (lpValueName);
5864 r = RegCloseKey (hkSubKey);
5865 if (r != ERROR_SUCCESS)
5866 WARN ("RegCloseKey returned %li\n", r);
5867 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
5868 return ret;
5871 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5872 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5873 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5874 pEnumValues += cbValueNameLen;
5876 /* return # of *bytes* (including trailing \0), not # of chars */
5877 ppev[dwIndex].cbValueName = cbValueNameLen;
5879 ppev[dwIndex].dwType = dwType;
5881 memcpy (pEnumValues, lpValue, cbValueLen);
5882 ppev[dwIndex].pData = pEnumValues;
5883 pEnumValues += cbValueLen;
5885 ppev[dwIndex].cbData = cbValueLen;
5887 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
5888 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5891 free (lpValue);
5892 free (lpValueName);
5894 ret = RegCloseKey (hkSubKey);
5895 if (ret != ERROR_SUCCESS)
5897 ERR ("RegCloseKey returned %li\n", ret);
5898 return ret;
5901 return ERROR_SUCCESS;
5904 /*******************************************************************************
5905 * EnumPrinterDataExA [WINSPOOL.@]
5907 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5908 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5909 * what Windows 2000 SP1 does.
5912 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5913 LPBYTE pEnumValues, DWORD cbEnumValues,
5914 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5916 INT len;
5917 LPWSTR pKeyNameW;
5918 DWORD ret, dwIndex, dwBufSize;
5919 LPSTR pBuffer;
5921 TRACE ("%p %s\n", hPrinter, pKeyName);
5923 if (pKeyName == NULL || *pKeyName == 0)
5924 return ERROR_INVALID_PARAMETER;
5926 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5927 if (len == 0)
5929 ret = GetLastError ();
5930 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5931 return ret;
5934 pKeyNameW = malloc (len * sizeof(WCHAR));
5935 if (pKeyNameW == NULL)
5937 ERR ("Failed to allocate %li bytes\n",
5938 (LONG)(len * sizeof (WCHAR)));
5939 return ERROR_OUTOFMEMORY;
5942 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5944 ret = GetLastError ();
5945 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5946 free (pKeyNameW);
5947 return ret;
5950 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5951 pcbEnumValues, pnEnumValues);
5952 free (pKeyNameW);
5953 if (ret != ERROR_SUCCESS)
5955 TRACE ("EnumPrinterDataExW returned %li\n", ret);
5956 return ret;
5959 if (*pnEnumValues == 0) /* empty key */
5960 return ERROR_SUCCESS;
5962 dwBufSize = 0;
5963 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5965 PPRINTER_ENUM_VALUESW ppev =
5966 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5968 if (dwBufSize < ppev->cbValueName)
5969 dwBufSize = ppev->cbValueName;
5971 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5972 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5973 dwBufSize = ppev->cbData;
5976 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5978 pBuffer = malloc(dwBufSize);
5979 if (pBuffer == NULL)
5981 ERR ("Failed to allocate %li bytes\n", dwBufSize);
5982 return ERROR_OUTOFMEMORY;
5985 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5987 PPRINTER_ENUM_VALUESW ppev =
5988 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5990 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5991 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5992 NULL);
5993 if (len == 0)
5995 ret = GetLastError ();
5996 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5997 free (pBuffer);
5998 return ret;
6001 memcpy (ppev->pValueName, pBuffer, len);
6003 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer);
6005 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6006 ppev->dwType != REG_MULTI_SZ)
6007 continue;
6009 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6010 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6011 if (len == 0)
6013 ret = GetLastError ();
6014 ERR ("WideCharToMultiByte failed with code %li\n", ret);
6015 free (pBuffer);
6016 return ret;
6019 memcpy (ppev->pData, pBuffer, len);
6021 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer);
6022 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6025 free(pBuffer);
6026 return ERROR_SUCCESS;
6029 /******************************************************************************
6030 * AbortPrinter (WINSPOOL.@)
6032 BOOL WINAPI AbortPrinter(HANDLE printer)
6034 HANDLE handle = get_backend_handle(printer);
6036 TRACE("(%p)\n", printer);
6038 return backend->fpAbortPrinter(handle);
6041 /******************************************************************************
6042 * AddPortA (WINSPOOL.@)
6044 * See AddPortW.
6047 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6049 LPWSTR nameW = NULL;
6050 LPWSTR monitorW = NULL;
6051 DWORD len;
6052 BOOL res;
6054 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6056 if (pName) {
6057 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6058 nameW = malloc(len * sizeof(WCHAR));
6059 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6062 if (pMonitorName) {
6063 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6064 monitorW = malloc(len * sizeof(WCHAR));
6065 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6067 res = AddPortW(nameW, hWnd, monitorW);
6068 free(nameW);
6069 free(monitorW);
6070 return res;
6073 /******************************************************************************
6074 * AddPortW (WINSPOOL.@)
6076 * Add a Port for a specific Monitor
6078 * PARAMS
6079 * pName [I] Servername or NULL (local Computer)
6080 * hWnd [I] Handle to parent Window for the Dialog-Box
6081 * pMonitorName [I] Name of the Monitor that manage the Port
6083 * RETURNS
6084 * Success: TRUE
6085 * Failure: FALSE
6088 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6090 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6092 if ((backend == NULL) && !load_backend()) return FALSE;
6094 if (!pMonitorName) {
6095 SetLastError(RPC_X_NULL_REF_POINTER);
6096 return FALSE;
6099 return backend->fpAddPort(pName, hWnd, pMonitorName);
6102 /******************************************************************************
6103 * AddPortExA (WINSPOOL.@)
6105 * See AddPortExW.
6108 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6110 PORT_INFO_2W pi2W;
6111 PORT_INFO_2A * pi2A;
6112 LPWSTR nameW = NULL;
6113 LPWSTR monitorW = NULL;
6114 DWORD len;
6115 BOOL res;
6117 pi2A = (PORT_INFO_2A *) pBuffer;
6119 TRACE("(%s, %ld, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6120 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6122 if ((level < 1) || (level > 2)) {
6123 SetLastError(ERROR_INVALID_LEVEL);
6124 return FALSE;
6127 if (!pi2A) {
6128 SetLastError(ERROR_INVALID_PARAMETER);
6129 return FALSE;
6132 if (pName) {
6133 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6134 nameW = malloc(len * sizeof(WCHAR));
6135 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6138 if (pMonitorName) {
6139 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6140 monitorW = malloc(len * sizeof(WCHAR));
6141 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6144 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6146 if (pi2A->pPortName) {
6147 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6148 pi2W.pPortName = malloc(len * sizeof(WCHAR));
6149 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6152 if (level > 1) {
6153 if (pi2A->pMonitorName) {
6154 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6155 pi2W.pMonitorName = malloc(len * sizeof(WCHAR));
6156 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6159 if (pi2A->pDescription) {
6160 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6161 pi2W.pDescription = malloc(len * sizeof(WCHAR));
6162 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6164 pi2W.fPortType = pi2A->fPortType;
6165 pi2W.Reserved = pi2A->Reserved;
6168 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6170 free(nameW);
6171 free(monitorW);
6172 free(pi2W.pPortName);
6173 free(pi2W.pMonitorName);
6174 free(pi2W.pDescription);
6175 return res;
6179 /******************************************************************************
6180 * AddPortExW (WINSPOOL.@)
6182 * Add a Port for a specific Monitor, without presenting a user interface
6184 * PARAMS
6185 * pName [I] Servername or NULL (local Computer)
6186 * level [I] Structure-Level (1 or 2) for pBuffer
6187 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6188 * pMonitorName [I] Name of the Monitor that manage the Port
6190 * RETURNS
6191 * Success: TRUE
6192 * Failure: FALSE
6195 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6197 PORT_INFO_2W * pi2;
6199 pi2 = (PORT_INFO_2W *) pBuffer;
6201 TRACE("(%s, %ld, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6202 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6203 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6204 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6206 if ((backend == NULL) && !load_backend()) return FALSE;
6208 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6209 SetLastError(ERROR_INVALID_PARAMETER);
6210 return FALSE;
6213 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6216 /******************************************************************************
6217 * AddPrinterConnectionA (WINSPOOL.@)
6219 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6221 FIXME("%s\n", debugstr_a(pName));
6222 return FALSE;
6225 /******************************************************************************
6226 * AddPrinterConnectionW (WINSPOOL.@)
6228 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6230 FIXME("%s\n", debugstr_w(pName));
6231 return FALSE;
6234 /******************************************************************************
6235 * AddPrinterDriverExW (WINSPOOL.@)
6237 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6239 * PARAMS
6240 * pName [I] Servername or NULL (local Computer)
6241 * level [I] Level for the supplied DRIVER_INFO_*W struct
6242 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6243 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6245 * RESULTS
6246 * Success: TRUE
6247 * Failure: FALSE
6250 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6252 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6254 if ((backend == NULL) && !load_backend()) return FALSE;
6256 if (level < 2 || level == 5 || level == 7 || level > 8) {
6257 SetLastError(ERROR_INVALID_LEVEL);
6258 return FALSE;
6261 if (!pDriverInfo) {
6262 SetLastError(ERROR_INVALID_PARAMETER);
6263 return FALSE;
6266 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6269 /******************************************************************************
6270 * AddPrinterDriverExA (WINSPOOL.@)
6272 * See AddPrinterDriverExW.
6275 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6277 DRIVER_INFO_8A *diA;
6278 DRIVER_INFO_8W diW;
6279 LPWSTR nameW = NULL;
6280 DWORD lenA;
6281 DWORD len;
6282 BOOL res = FALSE;
6284 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6286 diA = (DRIVER_INFO_8A *) pDriverInfo;
6287 ZeroMemory(&diW, sizeof(diW));
6289 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6290 SetLastError(ERROR_INVALID_LEVEL);
6291 return FALSE;
6294 if (diA == NULL) {
6295 SetLastError(ERROR_INVALID_PARAMETER);
6296 return FALSE;
6299 /* convert servername to unicode */
6300 if (pName) {
6301 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6302 nameW = malloc(len * sizeof(WCHAR));
6303 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6306 /* common fields */
6307 diW.cVersion = diA->cVersion;
6309 if (diA->pName) {
6310 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6311 diW.pName = malloc(len * sizeof(WCHAR));
6312 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6315 if (diA->pEnvironment) {
6316 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6317 diW.pEnvironment = malloc(len * sizeof(WCHAR));
6318 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6321 if (diA->pDriverPath) {
6322 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6323 diW.pDriverPath = malloc(len * sizeof(WCHAR));
6324 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6327 if (diA->pDataFile) {
6328 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6329 diW.pDataFile = malloc(len * sizeof(WCHAR));
6330 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6333 if (diA->pConfigFile) {
6334 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6335 diW.pConfigFile = malloc(len * sizeof(WCHAR));
6336 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6339 if ((Level > 2) && diA->pHelpFile) {
6340 len = MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, NULL, 0);
6341 diW.pHelpFile = malloc(len * sizeof(WCHAR));
6342 MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, diW.pHelpFile, len);
6345 if ((Level > 2) && diA->pDependentFiles) {
6346 lenA = multi_sz_lenA(diA->pDependentFiles);
6347 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6348 diW.pDependentFiles = malloc(len * sizeof(WCHAR));
6349 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6352 if ((Level > 2) && diA->pMonitorName) {
6353 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6354 diW.pMonitorName = malloc(len * sizeof(WCHAR));
6355 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6358 if ((Level > 2) && diA->pDefaultDataType) {
6359 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6360 diW.pDefaultDataType = malloc(len * sizeof(WCHAR));
6361 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6364 if ((Level > 3) && diA->pszzPreviousNames) {
6365 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6366 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6367 diW.pszzPreviousNames = malloc(len * sizeof(WCHAR));
6368 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6371 if (Level > 5) {
6372 diW.ftDriverDate = diA->ftDriverDate;
6373 diW.dwlDriverVersion = diA->dwlDriverVersion;
6376 if ((Level > 5) && diA->pszMfgName) {
6377 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6378 diW.pszMfgName = malloc(len * sizeof(WCHAR));
6379 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6382 if ((Level > 5) && diA->pszOEMUrl) {
6383 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6384 diW.pszOEMUrl = malloc(len * sizeof(WCHAR));
6385 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6388 if ((Level > 5) && diA->pszHardwareID) {
6389 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6390 diW.pszHardwareID = malloc(len * sizeof(WCHAR));
6391 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6394 if ((Level > 5) && diA->pszProvider) {
6395 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6396 diW.pszProvider = malloc(len * sizeof(WCHAR));
6397 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6400 if ((Level > 7) && diA->pszPrintProcessor) {
6401 len = MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, NULL, 0);
6402 diW.pszPrintProcessor = malloc(len * sizeof(WCHAR));
6403 MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, diW.pszPrintProcessor, len);
6406 if ((Level > 7) && diA->pszVendorSetup) {
6407 len = MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, NULL, 0);
6408 diW.pszVendorSetup = malloc(len * sizeof(WCHAR));
6409 MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, diW.pszVendorSetup, len);
6412 if ((Level > 7) && diA->pszzColorProfiles) {
6413 lenA = multi_sz_lenA(diA->pszzColorProfiles);
6414 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, NULL, 0);
6415 diW.pszzColorProfiles = malloc(len * sizeof(WCHAR));
6416 MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, diW.pszzColorProfiles, len);
6419 if ((Level > 7) && diA->pszInfPath) {
6420 len = MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, NULL, 0);
6421 diW.pszInfPath = malloc(len * sizeof(WCHAR));
6422 MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, diW.pszInfPath, len);
6425 if ((Level > 7) && diA->pszzCoreDriverDependencies) {
6426 lenA = multi_sz_lenA(diA->pszzCoreDriverDependencies);
6427 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, NULL, 0);
6428 diW.pszzCoreDriverDependencies = malloc(len * sizeof(WCHAR));
6429 MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, diW.pszzCoreDriverDependencies, len);
6432 if (Level > 7) {
6433 diW.dwPrinterDriverAttributes = diA->dwPrinterDriverAttributes;
6434 diW.ftMinInboxDriverVerDate = diA->ftMinInboxDriverVerDate;
6435 diW.dwlMinInboxDriverVerVersion = diA->dwlMinInboxDriverVerVersion;
6438 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6439 TRACE("got %u with %lu\n", res, GetLastError());
6440 free(nameW);
6441 free(diW.pName);
6442 free(diW.pEnvironment);
6443 free(diW.pDriverPath);
6444 free(diW.pDataFile);
6445 free(diW.pConfigFile);
6446 free(diW.pHelpFile);
6447 free(diW.pDependentFiles);
6448 free(diW.pMonitorName);
6449 free(diW.pDefaultDataType);
6450 free(diW.pszzPreviousNames);
6451 free(diW.pszMfgName);
6452 free(diW.pszOEMUrl);
6453 free(diW.pszHardwareID);
6454 free(diW.pszProvider);
6455 free(diW.pszPrintProcessor);
6456 free(diW.pszVendorSetup);
6457 free(diW.pszzColorProfiles);
6458 free(diW.pszInfPath);
6459 free(diW.pszzCoreDriverDependencies);
6461 TRACE("=> %u with %lu\n", res, GetLastError());
6462 return res;
6465 /******************************************************************************
6466 * ConfigurePortA (WINSPOOL.@)
6468 * See ConfigurePortW.
6471 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6473 LPWSTR nameW = NULL;
6474 LPWSTR portW = NULL;
6475 INT len;
6476 DWORD res;
6478 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6480 /* convert servername to unicode */
6481 if (pName) {
6482 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6483 nameW = malloc(len * sizeof(WCHAR));
6484 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6487 /* convert portname to unicode */
6488 if (pPortName) {
6489 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6490 portW = malloc(len * sizeof(WCHAR));
6491 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6494 res = ConfigurePortW(nameW, hWnd, portW);
6495 free(nameW);
6496 free(portW);
6497 return res;
6500 /******************************************************************************
6501 * ConfigurePortW (WINSPOOL.@)
6503 * Display the Configuration-Dialog for a specific Port
6505 * PARAMS
6506 * pName [I] Servername or NULL (local Computer)
6507 * hWnd [I] Handle to parent Window for the Dialog-Box
6508 * pPortName [I] Name of the Port, that should be configured
6510 * RETURNS
6511 * Success: TRUE
6512 * Failure: FALSE
6515 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6518 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6520 if ((backend == NULL) && !load_backend()) return FALSE;
6522 if (!pPortName) {
6523 SetLastError(RPC_X_NULL_REF_POINTER);
6524 return FALSE;
6527 return backend->fpConfigurePort(pName, hWnd, pPortName);
6530 /******************************************************************************
6531 * ConnectToPrinterDlg (WINSPOOL.@)
6533 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6535 FIXME("%p %lx\n", hWnd, Flags);
6536 return NULL;
6539 /******************************************************************************
6540 * DeletePrinterConnectionA (WINSPOOL.@)
6542 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6544 FIXME("%s\n", debugstr_a(pName));
6545 return TRUE;
6548 /******************************************************************************
6549 * DeletePrinterConnectionW (WINSPOOL.@)
6551 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6553 FIXME("%s\n", debugstr_w(pName));
6554 return TRUE;
6557 /******************************************************************************
6558 * DeletePrinterDriverExW (WINSPOOL.@)
6560 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6561 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6563 HKEY hkey_drivers;
6564 BOOL ret = FALSE;
6566 TRACE("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
6567 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6569 if(pName && pName[0])
6571 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6572 SetLastError(ERROR_INVALID_PARAMETER);
6573 return FALSE;
6576 if(dwDeleteFlag)
6578 FIXME("dwDeleteFlag = %lx - unsupported\n", dwDeleteFlag);
6579 SetLastError(ERROR_INVALID_PARAMETER);
6580 return FALSE;
6583 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6585 if(!hkey_drivers)
6587 ERR("Can't open drivers key\n");
6588 return FALSE;
6591 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6592 ret = TRUE;
6594 RegCloseKey(hkey_drivers);
6596 return ret;
6599 /******************************************************************************
6600 * DeletePrinterDriverExA (WINSPOOL.@)
6602 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6603 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6605 UNICODE_STRING NameW, EnvW, DriverW;
6606 BOOL ret;
6608 asciitounicode(&NameW, pName);
6609 asciitounicode(&EnvW, pEnvironment);
6610 asciitounicode(&DriverW, pDriverName);
6612 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6614 RtlFreeUnicodeString(&DriverW);
6615 RtlFreeUnicodeString(&EnvW);
6616 RtlFreeUnicodeString(&NameW);
6618 return ret;
6621 /******************************************************************************
6622 * DeletePrinterDataExW (WINSPOOL.@)
6624 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6625 LPCWSTR pValueName)
6627 FIXME("%p %s %s\n", hPrinter,
6628 debugstr_w(pKeyName), debugstr_w(pValueName));
6629 return ERROR_INVALID_PARAMETER;
6632 /******************************************************************************
6633 * DeletePrinterDataExA (WINSPOOL.@)
6635 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6636 LPCSTR pValueName)
6638 FIXME("%p %s %s\n", hPrinter,
6639 debugstr_a(pKeyName), debugstr_a(pValueName));
6640 return ERROR_INVALID_PARAMETER;
6643 /******************************************************************************
6644 * DeletePrintProcessorA (WINSPOOL.@)
6646 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6648 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6649 debugstr_a(pPrintProcessorName));
6650 return TRUE;
6653 /******************************************************************************
6654 * DeletePrintProcessorW (WINSPOOL.@)
6656 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6658 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6659 debugstr_w(pPrintProcessorName));
6660 return TRUE;
6663 /******************************************************************************
6664 * DeletePrintProvidorA (WINSPOOL.@)
6666 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6668 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6669 debugstr_a(pPrintProviderName));
6670 return TRUE;
6673 /******************************************************************************
6674 * DeletePrintProvidorW (WINSPOOL.@)
6676 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6678 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6679 debugstr_w(pPrintProviderName));
6680 return TRUE;
6683 /******************************************************************************
6684 * EnumFormsA (WINSPOOL.@)
6686 BOOL WINAPI EnumFormsA( HANDLE printer, DWORD level, BYTE *form, DWORD size, DWORD *needed, DWORD *count )
6688 const DWORD *string_info = form_string_info( level );
6689 BOOL ret;
6690 DWORD i;
6692 if (!string_info) return FALSE;
6694 ret = EnumFormsW( printer, level, form, size, needed, count );
6695 if (ret)
6696 for (i = 0; i < *count; i++)
6697 packed_struct_WtoA( form + i * string_info[0], string_info );
6699 return ret;
6702 /******************************************************************************
6703 * EnumFormsW (WINSPOOL.@)
6705 BOOL WINAPI EnumFormsW( HANDLE printer, DWORD level, BYTE *form, DWORD size, DWORD *needed, DWORD *count )
6707 HANDLE handle = get_backend_handle( printer );
6709 TRACE( "(%p, %ld, %p, %ld, %p, %p)\n", printer, level, form, size, needed, count );
6711 if (!handle)
6713 SetLastError( ERROR_INVALID_HANDLE );
6714 return FALSE;
6717 if (!needed || !count)
6719 SetLastError( RPC_X_NULL_REF_POINTER );
6720 return FALSE;
6723 if (!form && size)
6725 SetLastError( ERROR_INVALID_USER_BUFFER );
6726 return FALSE;
6729 return backend->fpEnumForms( handle, level, form, size, needed, count );
6732 /*****************************************************************************
6733 * EnumMonitorsA [WINSPOOL.@]
6735 * See EnumMonitorsW.
6738 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6739 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6741 BOOL res;
6742 LPBYTE bufferW = NULL;
6743 LPWSTR nameW = NULL;
6744 DWORD needed = 0;
6745 DWORD numentries = 0;
6746 INT len;
6748 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6749 cbBuf, pcbNeeded, pcReturned);
6751 /* convert servername to unicode */
6752 if (pName) {
6753 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6754 nameW = malloc(len * sizeof(WCHAR));
6755 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6757 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6758 needed = cbBuf * sizeof(WCHAR);
6759 if (needed) bufferW = malloc(needed);
6760 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6762 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6763 if (pcbNeeded) needed = *pcbNeeded;
6764 /* HeapReAlloc return NULL, when bufferW was NULL */
6765 bufferW = (bufferW) ? realloc(bufferW, needed) : malloc(needed);
6767 /* Try again with the large Buffer */
6768 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6770 numentries = pcReturned ? *pcReturned : 0;
6771 needed = 0;
6773 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6774 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6776 if (res) {
6777 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6778 DWORD entrysize = 0;
6779 DWORD index;
6780 LPSTR ptr;
6781 LPMONITOR_INFO_2W mi2w;
6782 LPMONITOR_INFO_2A mi2a;
6784 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6785 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6787 /* First pass: calculate the size for all Entries */
6788 mi2w = (LPMONITOR_INFO_2W) bufferW;
6789 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6790 index = 0;
6791 while (index < numentries) {
6792 index++;
6793 needed += entrysize; /* MONITOR_INFO_?A */
6794 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6796 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6797 NULL, 0, NULL, NULL);
6798 if (Level > 1) {
6799 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6800 NULL, 0, NULL, NULL);
6801 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6802 NULL, 0, NULL, NULL);
6804 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6805 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6806 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6809 /* check for errors and quit on failure */
6810 if (cbBuf < needed) {
6811 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6812 res = FALSE;
6813 goto emA_cleanup;
6815 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6816 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6817 cbBuf -= len ; /* free Bytes in the user-Buffer */
6818 mi2w = (LPMONITOR_INFO_2W) bufferW;
6819 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6820 index = 0;
6821 /* Second Pass: Fill the User Buffer (if we have one) */
6822 while ((index < numentries) && pMonitors) {
6823 index++;
6824 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
6825 mi2a->pName = ptr;
6826 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6827 ptr, cbBuf , NULL, NULL);
6828 ptr += len;
6829 cbBuf -= len;
6830 if (Level > 1) {
6831 mi2a->pEnvironment = ptr;
6832 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6833 ptr, cbBuf, NULL, NULL);
6834 ptr += len;
6835 cbBuf -= len;
6837 mi2a->pDLLName = ptr;
6838 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6839 ptr, cbBuf, NULL, NULL);
6840 ptr += len;
6841 cbBuf -= len;
6843 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6844 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6845 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6848 emA_cleanup:
6849 if (pcbNeeded) *pcbNeeded = needed;
6850 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6852 free(nameW);
6853 free(bufferW);
6855 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
6856 (res), GetLastError(), needed, numentries);
6858 return (res);
6862 /*****************************************************************************
6863 * EnumMonitorsW [WINSPOOL.@]
6865 * Enumerate available Port-Monitors
6867 * PARAMS
6868 * pName [I] Servername or NULL (local Computer)
6869 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6870 * pMonitors [O] PTR to Buffer that receives the Result
6871 * cbBuf [I] Size of Buffer at pMonitors
6872 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6873 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6875 * RETURNS
6876 * Success: TRUE
6877 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6880 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6881 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6884 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6885 cbBuf, pcbNeeded, pcReturned);
6887 if ((backend == NULL) && !load_backend()) return FALSE;
6889 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6890 SetLastError(RPC_X_NULL_REF_POINTER);
6891 return FALSE;
6894 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6897 /******************************************************************************
6898 * SpoolerInit (WINSPOOL.@)
6900 * Initialize the Spooler
6902 * RETURNS
6903 * Success: TRUE
6904 * Failure: FALSE
6906 * NOTES
6907 * The function fails on windows, when the spooler service is not running
6910 BOOL WINAPI SpoolerInit(void)
6913 if ((backend == NULL) && !load_backend()) return FALSE;
6914 return TRUE;
6917 /******************************************************************************
6918 * XcvDataW (WINSPOOL.@)
6920 * Execute commands in the Printmonitor DLL
6922 * PARAMS
6923 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6924 * pszDataName [i] Name of the command to execute
6925 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6926 * cbInputData [i] Size in Bytes of Buffer at pInputData
6927 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6928 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6929 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6930 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6932 * RETURNS
6933 * Success: TRUE
6934 * Failure: FALSE
6936 * NOTES
6937 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6938 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6940 * Minimal List of commands, that a Printmonitor DLL should support:
6942 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6943 *| "AddPort" : Add a Port
6944 *| "DeletePort": Delete a Port
6946 * Many Printmonitors support additional commands. Examples for localspl.dll:
6947 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6948 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6951 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6952 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6953 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6955 opened_printer_t *printer;
6957 TRACE("(%p, %s, %p, %ld, %p, %ld, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6958 pInputData, cbInputData, pOutputData,
6959 cbOutputData, pcbOutputNeeded, pdwStatus);
6961 if ((backend == NULL) && !load_backend()) return FALSE;
6963 printer = get_opened_printer(hXcv);
6964 if (!printer || (!printer->backend_printer)) {
6965 SetLastError(ERROR_INVALID_HANDLE);
6966 return FALSE;
6969 if (!pcbOutputNeeded) {
6970 SetLastError(ERROR_INVALID_PARAMETER);
6971 return FALSE;
6974 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6975 SetLastError(RPC_X_NULL_REF_POINTER);
6976 return FALSE;
6979 *pcbOutputNeeded = 0;
6981 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6982 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6986 /*****************************************************************************
6987 * EnumPrinterDataA [WINSPOOL.@]
6990 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6991 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6992 DWORD cbData, LPDWORD pcbData )
6994 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
6995 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6996 return ERROR_NO_MORE_ITEMS;
6999 /*****************************************************************************
7000 * EnumPrinterDataW [WINSPOOL.@]
7003 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7004 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7005 DWORD cbData, LPDWORD pcbData )
7007 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
7008 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7009 return ERROR_NO_MORE_ITEMS;
7012 /*****************************************************************************
7013 * EnumPrinterKeyA [WINSPOOL.@]
7016 DWORD WINAPI EnumPrinterKeyA(HANDLE printer, const CHAR *key, CHAR *subkey, DWORD size, DWORD *needed)
7018 FIXME("%p %s %p %lx %p\n", printer, debugstr_a(key), subkey, size, needed);
7019 return ERROR_CALL_NOT_IMPLEMENTED;
7022 /*****************************************************************************
7023 * EnumPrinterKeyW [WINSPOOL.@]
7026 DWORD WINAPI EnumPrinterKeyW(HANDLE printer, const WCHAR *key, WCHAR *subkey, DWORD size, DWORD *needed)
7028 FIXME("%p %s %p %lx %p\n", printer, debugstr_w(key), subkey, size, needed);
7029 return ERROR_CALL_NOT_IMPLEMENTED;
7032 /*****************************************************************************
7033 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7036 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7037 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7038 LPDWORD pcbNeeded, LPDWORD pcReturned)
7040 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
7041 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7042 pcbNeeded, pcReturned);
7043 return FALSE;
7046 /*****************************************************************************
7047 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7050 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7051 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7052 LPDWORD pcbNeeded, LPDWORD pcReturned)
7054 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
7055 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7056 pcbNeeded, pcReturned);
7057 return FALSE;
7060 /*****************************************************************************
7061 * EnumPrintProcessorsA [WINSPOOL.@]
7063 * See EnumPrintProcessorsW.
7066 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7067 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7069 BOOL res;
7070 LPBYTE bufferW = NULL;
7071 LPWSTR nameW = NULL;
7072 LPWSTR envW = NULL;
7073 DWORD needed = 0;
7074 DWORD numentries = 0;
7075 INT len;
7077 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7078 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7080 /* convert names to unicode */
7081 if (pName) {
7082 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7083 nameW = malloc(len * sizeof(WCHAR));
7084 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7086 if (pEnvironment) {
7087 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7088 envW = malloc(len * sizeof(WCHAR));
7089 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7092 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7093 needed = cbBuf * sizeof(WCHAR);
7094 if (needed) bufferW = malloc(needed);
7095 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7097 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7098 if (pcbNeeded) needed = *pcbNeeded;
7099 /* HeapReAlloc return NULL, when bufferW was NULL */
7100 bufferW = (bufferW) ? realloc(bufferW, needed) : malloc(needed);
7102 /* Try again with the large Buffer */
7103 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7105 numentries = pcReturned ? *pcReturned : 0;
7106 needed = 0;
7108 if (res) {
7109 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7110 DWORD index;
7111 LPSTR ptr;
7112 PPRINTPROCESSOR_INFO_1W ppiw;
7113 PPRINTPROCESSOR_INFO_1A ppia;
7115 /* First pass: calculate the size for all Entries */
7116 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7117 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7118 index = 0;
7119 while (index < numentries) {
7120 index++;
7121 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7122 TRACE("%p: parsing #%ld (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7124 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7125 NULL, 0, NULL, NULL);
7127 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7128 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7131 /* check for errors and quit on failure */
7132 if (cbBuf < needed) {
7133 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7134 res = FALSE;
7135 goto epp_cleanup;
7138 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7139 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7140 cbBuf -= len ; /* free Bytes in the user-Buffer */
7141 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7142 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7143 index = 0;
7144 /* Second Pass: Fill the User Buffer (if we have one) */
7145 while ((index < numentries) && pPPInfo) {
7146 index++;
7147 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%ld\n", ppia, index);
7148 ppia->pName = ptr;
7149 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7150 ptr, cbBuf , NULL, NULL);
7151 ptr += len;
7152 cbBuf -= len;
7154 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7155 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7159 epp_cleanup:
7160 if (pcbNeeded) *pcbNeeded = needed;
7161 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7163 free(nameW);
7164 free(envW);
7165 free(bufferW);
7167 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
7168 (res), GetLastError(), needed, numentries);
7170 return (res);
7173 /*****************************************************************************
7174 * EnumPrintProcessorsW [WINSPOOL.@]
7176 * Enumerate available Print Processors
7178 * PARAMS
7179 * pName [I] Servername or NULL (local Computer)
7180 * pEnvironment [I] Printing-Environment or NULL (Default)
7181 * Level [I] Structure-Level (Only 1 is allowed)
7182 * pPPInfo [O] PTR to Buffer that receives the Result
7183 * cbBuf [I] Size of Buffer at pPPInfo
7184 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7185 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7187 * RETURNS
7188 * Success: TRUE
7189 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7192 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7193 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7196 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7197 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7199 if ((backend == NULL) && !load_backend()) return FALSE;
7201 if (!pcbNeeded || !pcReturned) {
7202 SetLastError(RPC_X_NULL_REF_POINTER);
7203 return FALSE;
7206 if (!pPPInfo && (cbBuf > 0)) {
7207 SetLastError(ERROR_INVALID_USER_BUFFER);
7208 return FALSE;
7211 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7212 cbBuf, pcbNeeded, pcReturned);
7215 /*****************************************************************************
7216 * ExtDeviceMode [WINSPOOL.@]
7219 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7220 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7221 DWORD fMode)
7223 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
7224 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7225 debugstr_a(pProfile), fMode);
7226 return -1;
7229 /*****************************************************************************
7230 * FindClosePrinterChangeNotification [WINSPOOL.@]
7233 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7235 FIXME("Stub: %p\n", hChange);
7236 return TRUE;
7239 /*****************************************************************************
7240 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7243 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7244 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7246 FIXME("Stub: %p %lx %lx %p\n",
7247 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7248 return INVALID_HANDLE_VALUE;
7251 /*****************************************************************************
7252 * FindNextPrinterChangeNotification [WINSPOOL.@]
7255 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7256 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7258 FIXME("Stub: %p %p %p %p\n",
7259 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7260 return FALSE;
7263 /*****************************************************************************
7264 * FreePrinterNotifyInfo [WINSPOOL.@]
7267 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7269 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7270 return TRUE;
7273 static inline const DWORD *job_string_info(DWORD level)
7275 static const DWORD info_1[] =
7277 sizeof(JOB_INFO_1W),
7278 FIELD_OFFSET(JOB_INFO_1W, pPrinterName),
7279 FIELD_OFFSET(JOB_INFO_1W, pMachineName),
7280 FIELD_OFFSET(JOB_INFO_1W, pUserName),
7281 FIELD_OFFSET(JOB_INFO_1W, pDocument),
7282 FIELD_OFFSET(JOB_INFO_1W, pDatatype),
7283 FIELD_OFFSET(JOB_INFO_1W, pStatus),
7286 static const DWORD info_2[] =
7288 sizeof(JOB_INFO_2W),
7289 FIELD_OFFSET(JOB_INFO_2W, pPrinterName),
7290 FIELD_OFFSET(JOB_INFO_2W, pMachineName),
7291 FIELD_OFFSET(JOB_INFO_2W, pUserName),
7292 FIELD_OFFSET(JOB_INFO_2W, pDocument),
7293 FIELD_OFFSET(JOB_INFO_2W, pNotifyName),
7294 FIELD_OFFSET(JOB_INFO_2W, pDatatype),
7295 FIELD_OFFSET(JOB_INFO_2W, pPrintProcessor),
7296 FIELD_OFFSET(JOB_INFO_2W, pParameters),
7297 FIELD_OFFSET(JOB_INFO_2W, pDriverName),
7298 FIELD_OFFSET(JOB_INFO_2W, pStatus),
7301 static const DWORD info_3[] =
7303 sizeof(JOB_INFO_3),
7307 switch (level)
7309 case 1: return info_1;
7310 case 2: return info_2;
7311 case 3: return info_3;
7314 SetLastError( ERROR_INVALID_LEVEL );
7315 return NULL;
7318 /*****************************************************************************
7319 * GetJobA [WINSPOOL.@]
7322 BOOL WINAPI GetJobA(HANDLE printer, DWORD job_id, DWORD level, BYTE *data,
7323 DWORD size, DWORD *needed)
7325 const DWORD *string_info = job_string_info(level);
7327 if (!string_info)
7328 return FALSE;
7330 if (!GetJobW(printer, job_id, level, data, size, needed))
7331 return FALSE;
7332 packed_struct_WtoA(data, string_info);
7333 if (level == 2)
7334 DEVMODEWtoA(((JOB_INFO_2W *)data)->pDevMode, ((JOB_INFO_2A *)data)->pDevMode);
7335 return TRUE;
7338 /*****************************************************************************
7339 * GetJobW [WINSPOOL.@]
7342 BOOL WINAPI GetJobW(HANDLE printer, DWORD job_id, DWORD level, BYTE *data,
7343 DWORD size, DWORD *needed)
7345 HANDLE handle = get_backend_handle(printer);
7347 TRACE("(%p, %ld, %ld, %p, %ld, %p)\n", printer, job_id, level, data, size, needed);
7349 if (!handle)
7351 SetLastError(ERROR_INVALID_HANDLE);
7352 return FALSE;
7355 return backend->fpGetJob(handle, job_id, level, data, size, needed);
7358 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7360 LPWSTR filename;
7362 switch(msg)
7364 case WM_INITDIALOG:
7365 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7366 return TRUE;
7368 case WM_COMMAND:
7369 if(HIWORD(wparam) == BN_CLICKED)
7371 if(LOWORD(wparam) == IDOK)
7373 HANDLE hf;
7374 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7375 LPWSTR *output;
7377 filename = malloc((len + 1) * sizeof(WCHAR));
7378 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7380 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7382 WCHAR caption[200], message[200];
7383 int mb_ret;
7385 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
7386 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, ARRAY_SIZE(message));
7387 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7388 if(mb_ret == IDCANCEL)
7390 free(filename);
7391 return TRUE;
7394 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7395 if(hf == INVALID_HANDLE_VALUE)
7397 WCHAR caption[200], message[200];
7399 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
7400 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, ARRAY_SIZE(message));
7401 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7402 free(filename);
7403 return TRUE;
7405 CloseHandle(hf);
7406 DeleteFileW(filename);
7407 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7408 *output = filename;
7409 EndDialog(hwnd, IDOK);
7410 return TRUE;
7412 if(LOWORD(wparam) == IDCANCEL)
7414 EndDialog(hwnd, IDCANCEL);
7415 return TRUE;
7418 return FALSE;
7420 return FALSE;
7423 /*****************************************************************************
7424 * get_filename
7426 static BOOL get_filename(LPWSTR *filename)
7428 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7429 file_dlg_proc, (LPARAM)filename) == IDOK;
7432 /*****************************************************************************
7433 * ScheduleJob [WINSPOOL.@]
7436 BOOL WINAPI ScheduleJob(HANDLE printer, DWORD job_id)
7438 HANDLE handle = get_backend_handle(printer);
7440 TRACE("(%p, %lx)\n", printer, job_id);
7442 if (!handle)
7444 SetLastError(ERROR_INVALID_HANDLE);
7445 return FALSE;
7448 return backend->fpScheduleJob(handle, job_id);
7451 /*****************************************************************************
7452 * StartDocDlgA [WINSPOOL.@]
7454 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7456 UNICODE_STRING usBuffer;
7457 DOCINFOW docW = { 0 };
7458 LPWSTR retW;
7459 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7460 LPSTR ret = NULL;
7462 docW.cbSize = sizeof(docW);
7463 if (doc->lpszDocName)
7465 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7466 if (!(docW.lpszDocName = docnameW)) goto failed;
7468 if (doc->lpszOutput)
7470 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7471 if (!(docW.lpszOutput = outputW)) goto failed;
7473 if (doc->lpszDatatype)
7475 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7476 if (!(docW.lpszDatatype = datatypeW)) goto failed;
7478 docW.fwType = doc->fwType;
7480 retW = StartDocDlgW(hPrinter, &docW);
7482 if(retW)
7484 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7485 ret = heap_alloc(len);
7486 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7487 heap_free(retW);
7490 failed:
7491 free(datatypeW);
7492 free(outputW);
7493 free(docnameW);
7495 return ret;
7498 static BOOL is_port(const WCHAR *port_list, const WCHAR *output)
7500 size_t len;
7502 if (wcschr(output, ':'))
7503 return TRUE;
7505 len = wcslen(output);
7506 while (port_list && *port_list)
7508 if (!wcsncmp(output, port_list, len) && (!port_list[len] || port_list[len] == ','))
7509 return TRUE;
7511 port_list = wcschr(port_list, ',');
7512 if (port_list) port_list++;
7514 return FALSE;
7517 /*****************************************************************************
7518 * StartDocDlgW [WINSPOOL.@]
7520 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7521 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7522 * port is "FILE:". Also returns the full path if passed a relative path.
7524 * The caller should free the returned string from the process heap.
7526 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7528 PRINTER_INFO_5W *pi5;
7529 LPWSTR ret = NULL;
7530 DWORD len, attr;
7531 BOOL b;
7533 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7534 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7535 return NULL;
7536 pi5 = malloc(len);
7537 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7539 /* Check whether default port is FILE: */
7540 b = !doc->lpszOutput && (!pi5->pPortName || wcscmp( pi5->pPortName, L"FILE:" ));
7541 if (!b && doc->lpszOutput && wcscmp( doc->lpszOutput, L"FILE:" ))
7542 b = is_port(pi5->pPortName, doc->lpszOutput);
7543 free(pi5);
7544 if (b)
7545 return NULL;
7547 if(doc->lpszOutput == NULL || !wcscmp( doc->lpszOutput, L"FILE:" ))
7549 LPWSTR name;
7551 if (get_filename(&name))
7553 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7555 free(name);
7556 return NULL;
7558 ret = heap_alloc(len * sizeof(WCHAR));
7559 GetFullPathNameW(name, len, ret, NULL);
7560 free(name);
7562 return ret;
7565 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7566 return NULL;
7568 ret = heap_alloc(len * sizeof(WCHAR));
7569 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7571 attr = GetFileAttributesW(ret);
7572 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7574 heap_free(ret);
7575 ret = NULL;
7577 return ret;
7580 /*****************************************************************************
7581 * UploadPrinterDriverPackageA [WINSPOOL.@]
7583 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
7584 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
7586 FIXME("%s, %s, %s, %lx, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
7587 flags, hwnd, dst, dstlen);
7588 return E_NOTIMPL;
7591 /*****************************************************************************
7592 * UploadPrinterDriverPackageW [WINSPOOL.@]
7594 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
7595 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
7597 FIXME("%s, %s, %s, %lx, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
7598 flags, hwnd, dst, dstlen);
7599 return E_NOTIMPL;
7602 /*****************************************************************************
7603 * PerfOpen [WINSPOOL.@]
7605 DWORD WINAPI PerfOpen(LPWSTR context)
7607 FIXME("%s: stub\n", debugstr_w(context));
7608 return ERROR_SUCCESS;
7611 /*****************************************************************************
7612 * PerfClose [WINSPOOL.@]
7614 DWORD WINAPI PerfClose(void)
7616 FIXME("stub\n");
7617 return ERROR_SUCCESS;
7620 /*****************************************************************************
7621 * PerfCollect [WINSPOOL.@]
7623 DWORD WINAPI PerfCollect(LPWSTR query, LPVOID *data, LPDWORD size, LPDWORD obj_count)
7625 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query), data, size, obj_count);
7626 *size = 0;
7627 *obj_count = 0;
7628 return ERROR_SUCCESS;
7631 /*****************************************************************************
7632 * GetSpoolFileHandle [WINSPOOL.@]
7634 HANDLE WINAPI GetSpoolFileHandle( HANDLE printer )
7636 FIXME( "%p: stub\n", printer );
7637 return INVALID_HANDLE_VALUE;
7640 /*****************************************************************************
7641 * SeekPrinter [WINSPOOL.@]
7643 BOOL WINAPI SeekPrinter(HANDLE printer, LARGE_INTEGER distance,
7644 LARGE_INTEGER *pos, DWORD method, BOOL bwrite)
7646 HANDLE handle = get_backend_handle(printer);
7648 TRACE("(%p %I64d %p %lx %x)\n", printer, distance.QuadPart, pos, method, bwrite);
7650 if (!handle)
7652 SetLastError(ERROR_INVALID_HANDLE);
7653 return FALSE;
7655 return backend->fpSeekPrinter(handle, distance, pos, method, bwrite);