winspool: Improve the grammar of a comment in get_servername_from_name.
[wine.git] / dlls / winspool.drv / info.c
blob9ce3125787f0fa27eeb14d5e8d7d5ed4b52dcb3b
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;
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 RtlInitUnicodeString( &nt_ppd, NULL );
646 if (!RtlDosPathNameToNtPathName_U( ppd, &nt_ppd, NULL, NULL )) goto end;
648 ppd_params.printer = name;
649 ppd_params.ppd = nt_ppd.Buffer;
650 res = !UNIX_CALL( get_ppd, &ppd_params ) || get_internal_fallback_ppd( ppd );
651 if (!res) goto end;
653 memset( &di3, 0, sizeof(DRIVER_INFO_3W) );
654 di3.cVersion = 3;
655 di3.pName = (WCHAR *)name;
656 di3.pDriverPath = driver_nt;
657 di3.pDataFile = ppd;
658 di3.pConfigFile = driver_nt;
659 di3.pDefaultDataType = raw;
661 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
663 di3.pEnvironment = (WCHAR *)all_printenv[i]->envname;
664 if (all_printenv[i]->driverversion == 0)
666 WCHAR driver_9x[] = L"wineps16.drv";
667 /* We use wineps16.drv as driver for 16 bit */
668 di3.pDriverPath = driver_9x;
669 di3.pConfigFile = driver_9x;
671 res = AddPrinterDriverExW( NULL, 3, (BYTE *)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY );
672 TRACE( "got %d and %ld for %s (%s)\n", res, GetLastError(), debugstr_w( name ), debugstr_w( di3.pEnvironment ) );
674 if (!res && (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED))
676 ERR( "failed with %lu for %s (%s) %s\n", GetLastError(), debugstr_w( name ),
677 debugstr_w( di3.pEnvironment ), debugstr_w( di3.pDriverPath ) );
678 break;
680 res = TRUE;
682 ppd_params.printer = NULL; /* unlink the ppd */
683 UNIX_CALL( get_ppd, &ppd_params );
685 end:
686 RtlFreeUnicodeString( &nt_ppd );
687 free( ppd );
688 return res;
691 static WCHAR *get_ppd_dir( void )
693 static const WCHAR wine_ppds[] = L"wine_ppds\\";
694 DWORD len;
695 WCHAR *dir, tmp_path[MAX_PATH];
696 BOOL res;
698 len = GetTempPathW( ARRAY_SIZE( tmp_path ), tmp_path );
699 if (!len) return NULL;
700 dir = malloc( len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
701 if (!dir) return NULL;
703 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
704 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
705 res = CreateDirectoryW( dir, NULL );
706 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
708 free( dir );
709 dir = NULL;
711 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
712 return dir;
715 static BOOL init_unix_printers( void )
717 WCHAR *port, *ppd_dir = NULL, *default_printer = NULL;
718 unsigned int size, num;
719 struct enum_printers_params enum_params = { NULL, &size, &num };
720 HKEY printer_key, printers_key;
721 HANDLE added_printer;
722 PRINTER_INFO_2W pi2;
723 NTSTATUS status;
724 WCHAR raw[] = L"RAW", winprint[] = L"WinPrint", empty[] = L"";
725 int i;
727 if (create_printers_reg_key( system_printers_key, &printers_key ))
729 ERR( "Can't create Printers key\n" );
730 return FALSE;
733 size = 10000;
736 size *= 2;
737 free( enum_params.printers );
738 enum_params.printers = malloc( size );
739 status = UNIX_CALL( enum_printers, &enum_params );
740 } while (status == STATUS_BUFFER_OVERFLOW);
741 if (status) goto end;
743 TRACE( "Found %d CUPS %s:\n", num, (num == 1) ? "printer" : "printers" );
744 for (i = 0; i < num; i++)
746 struct printer_info *printer = enum_params.printers + i;
748 if (RegOpenKeyW( printers_key, printer->name, &printer_key ) == ERROR_SUCCESS)
750 DWORD status = get_dword_from_reg( printer_key, L"Status" );
751 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
752 and continue */
753 TRACE("Printer already exists\n");
754 RegDeleteValueW( printer_key, May_Delete_Value );
755 /* flag that the PPD file should be checked for an update */
756 set_reg_DWORD( printer_key, L"Status", status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
757 RegCloseKey( printer_key );
759 else
761 if (!ppd_dir && !(ppd_dir = get_ppd_dir())) break;
762 if (!add_printer_driver( printer->name, ppd_dir )) continue;
764 port = malloc( sizeof(L"CUPS:") + wcslen( printer->name ) * sizeof(WCHAR) );
765 wcscpy( port, L"CUPS:" );
766 wcscat( port, printer->name );
768 memset( &pi2, 0, sizeof(PRINTER_INFO_2W) );
769 pi2.pPrinterName = printer->name;
770 pi2.pDatatype = raw;
771 pi2.pPrintProcessor = winprint;
772 pi2.pDriverName = printer->name;
773 pi2.pComment = printer->comment;
774 pi2.pLocation = printer->location;
775 pi2.pPortName = port;
776 pi2.pParameters = empty;
777 pi2.pShareName = empty;
778 pi2.pSepFile = empty;
780 added_printer = AddPrinterW( NULL, 2, (BYTE *)&pi2 );
781 if (added_printer) ClosePrinter( added_printer );
782 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
783 ERR( "printer '%s' not added by AddPrinter (error %ld)\n", debugstr_w( printer->name ), GetLastError() );
785 free( port );
787 if (printer->is_default) default_printer = printer->name;
790 if (!default_printer && num) default_printer = enum_params.printers[0].name;
791 if (default_printer) SetDefaultPrinterW( default_printer );
793 if (ppd_dir)
795 RemoveDirectoryW( ppd_dir );
796 free( ppd_dir );
798 end:
799 free( enum_params.printers );
800 RegCloseKey( printers_key );
801 return TRUE;
804 static void set_ppd_overrides( HANDLE printer )
806 WCHAR buffer[256];
807 unsigned int name_size = sizeof(buffer);
808 struct get_default_page_size_params params = { .name = buffer, .name_size = &name_size };
809 NTSTATUS status;
811 while (1)
813 status = UNIX_CALL( get_default_page_size, &params );
814 if (status != STATUS_BUFFER_OVERFLOW) break;
815 if (params.name != buffer) free( params.name );
816 params.name = malloc( name_size );
817 if (!params.name) break;
819 if (!status) SetPrinterDataExW( printer, L"PPD Overrides", L"DefaultPageSize", REG_SZ, (BYTE*)params.name, name_size );
820 if (params.name != buffer) free( params.name );
823 static BOOL update_driver( HANDLE printer )
825 BOOL ret;
826 const WCHAR *name = get_opened_printer_name( printer );
827 WCHAR *ppd_dir;
829 if (!name) return FALSE;
830 if (!(ppd_dir = get_ppd_dir())) return FALSE;
832 TRACE( "updating driver %s\n", debugstr_w( name ) );
833 ret = add_printer_driver( name, ppd_dir );
835 free( ppd_dir );
837 set_ppd_overrides( printer );
839 /* call into the driver to update the devmode */
840 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
842 return ret;
845 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
847 if (value)
848 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
849 (wcslen( value ) + 1) * sizeof(WCHAR));
850 else
851 return ERROR_FILE_NOT_FOUND;
854 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
856 DEVMODEA *dmA = DEVMODEWtoA( dm, NULL );
857 DWORD ret = ERROR_FILE_NOT_FOUND;
859 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
860 and we support these drivers. NT writes DEVMODEW so somehow
861 we'll need to distinguish between these when we support NT
862 drivers */
864 if (dmA)
866 ret = RegSetValueExW( key, name, 0, REG_BINARY,
867 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
868 free( dmA );
871 return ret;
874 /******************************************************************
875 * get_servername_from_name (internal)
877 * for an external server, a copy of the serverpart from the full name is returned
880 static LPWSTR get_servername_from_name(LPCWSTR name)
882 LPWSTR server;
883 LPWSTR ptr;
884 WCHAR buffer[MAX_PATH];
885 DWORD len;
887 if (name == NULL) return NULL;
888 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
890 server = wcsdup(&name[2]); /* skip over both backslashes */
891 if (server == NULL) return NULL;
893 /* strip '\' and the printername */
894 ptr = wcschr( server, '\\' );
895 if (ptr) ptr[0] = '\0';
897 TRACE("found %s\n", debugstr_w(server));
899 len = ARRAY_SIZE(buffer);
900 if (GetComputerNameW(buffer, &len))
902 if (!wcscmp( buffer, server ))
904 /* The requested Servername is our computername */
905 free(server);
906 return NULL;
909 return server;
912 /******************************************************************
913 * get_basename_from_name (internal)
915 * skip over the serverpart from the full name
918 static LPCWSTR get_basename_from_name(LPCWSTR name)
920 if (name == NULL) return NULL;
921 if ((name[0] == '\\') && (name[1] == '\\'))
923 /* skip over the servername and search for the following '\' */
924 name = wcschr( &name[2], '\\' );
925 if ((name) && (name[1]))
927 /* found a separator ('\') followed by a name:
928 skip over the separator and return the rest */
929 name++;
931 else
933 /* no basename present (we found only a servername) */
934 return NULL;
937 return name;
940 static void free_printer_entry( opened_printer_t *printer )
942 /* the queue is shared, so don't free that here */
943 free( printer->name );
944 free( printer );
947 /******************************************************************
948 * get_opened_printer_entry
949 * Get the first place empty in the opened printer table
951 * ToDo:
952 * - pDefault is ignored
954 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
956 opened_printer_t *printer = NULL;
957 LPWSTR servername;
958 LPCWSTR printername;
959 UINT_PTR handle;
961 if ((backend == NULL) && !load_backend()) return NULL;
963 servername = get_servername_from_name(name);
964 if (servername) {
965 FIXME("server %s not supported\n", debugstr_w(servername));
966 free(servername);
967 SetLastError(ERROR_INVALID_PRINTER_NAME);
968 return NULL;
971 printername = get_basename_from_name(name);
972 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
974 /* an empty printername is invalid */
975 if (printername && (!printername[0])) {
976 SetLastError(ERROR_INVALID_PARAMETER);
977 return NULL;
980 EnterCriticalSection(&printer_handles_cs);
982 for (handle = 0; handle < nb_printer_handles; handle++)
984 if (!printer_handles[handle])
985 break;
988 if (handle >= nb_printer_handles)
990 opened_printer_t **new_array;
991 if (printer_handles)
993 new_array = realloc(printer_handles, (nb_printer_handles + 16) * sizeof(*new_array));
994 memset(new_array + nb_printer_handles, 0, 16 * sizeof(*new_array));
996 else
998 new_array = calloc(nb_printer_handles + 16, sizeof(*new_array));
1001 if (!new_array)
1003 handle = 0;
1004 goto end;
1006 printer_handles = new_array;
1007 nb_printer_handles += 16;
1010 if (!(printer = calloc(1, sizeof(*printer))))
1012 handle = 0;
1013 goto end;
1016 /* get a printer handle from the backend */
1017 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1018 handle = 0;
1019 goto end;
1022 /* clone the full name */
1023 printer->name = wcsdup(name);
1024 if (name && (!printer->name)) {
1025 handle = 0;
1026 goto end;
1029 printer_handles[handle] = printer;
1030 handle++;
1031 end:
1032 LeaveCriticalSection(&printer_handles_cs);
1033 if (!handle && printer)
1034 free_printer_entry( printer );
1036 return (HANDLE)handle;
1039 static void old_printer_check( BOOL delete_phase )
1041 PRINTER_INFO_5W* pi;
1042 DWORD needed, type, num, delete, i, size;
1043 const DWORD one = 1;
1044 HKEY key;
1045 HANDLE hprn;
1047 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1048 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1050 pi = malloc( needed );
1051 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1052 for (i = 0; i < num; i++)
1054 if (!pi[i].pPortName) continue;
1056 if (wcsncmp( pi[i].pPortName, L"CUPS:", ARRAY_SIZE(L"CUPS:") - 1 ) &&
1057 wcsncmp( pi[i].pPortName, L"LPR:", ARRAY_SIZE(L"LPR:") - 1 ))
1058 continue;
1060 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1062 if (!delete_phase)
1064 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1065 RegCloseKey( key );
1067 else
1069 delete = 0;
1070 size = sizeof( delete );
1071 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1072 RegCloseKey( key );
1073 if (delete)
1075 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1076 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1078 DeletePrinter( hprn );
1079 ClosePrinter( hprn );
1081 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1085 free(pi);
1088 static HANDLE init_mutex;
1090 void WINSPOOL_LoadSystemPrinters(void)
1092 HKEY printers_key, printer_key;
1093 DWORD needed, num, i;
1094 WCHAR PrinterName[256];
1096 /* FIXME: The init code should be moved to spoolsv.exe */
1097 init_mutex = CreateMutexW( NULL, TRUE, L"__WINE_WINSPOOL_MUTEX__" );
1098 if (!init_mutex)
1100 ERR( "Failed to create mutex\n" );
1101 return;
1103 if (GetLastError() == ERROR_ALREADY_EXISTS)
1105 WaitForSingleObject( init_mutex, INFINITE );
1106 ReleaseMutex( init_mutex );
1107 TRACE( "Init already done\n" );
1108 return;
1111 /* This ensures that all printer entries have a valid Name value. If causes
1112 problems later if they don't. If one is found to be missed we create one
1113 and set it equal to the name of the key */
1114 if (!create_printers_reg_key( system_printers_key, &printers_key ))
1116 if (!RegQueryInfoKeyW( printers_key, NULL, NULL, NULL, &num, NULL, NULL, NULL, NULL, NULL, NULL, NULL ))
1117 for (i = 0; i < num; i++)
1118 if (!RegEnumKeyW( printers_key, i, PrinterName, ARRAY_SIZE(PrinterName) ))
1119 if (!RegOpenKeyW( printers_key, PrinterName, &printer_key ))
1121 if (RegQueryValueExW( printer_key, L"Name", 0, 0, 0, &needed ) == ERROR_FILE_NOT_FOUND)
1122 set_reg_szW( printer_key, L"Name", PrinterName );
1123 RegCloseKey( printer_key );
1125 RegCloseKey( printers_key );
1128 old_printer_check( FALSE );
1129 init_unix_printers();
1130 old_printer_check( TRUE );
1132 ReleaseMutex( init_mutex );
1133 return;
1136 /******************************************************************
1137 * convert_printerinfo_W_to_A [internal]
1140 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1141 DWORD level, DWORD outlen, DWORD numentries)
1143 DWORD id = 0;
1144 LPSTR ptr;
1145 INT len;
1147 TRACE("(%p, %p, %ld, %lu, %lu)\n", out, pPrintersW, level, outlen, numentries);
1149 len = pi_sizeof[level] * numentries;
1150 ptr = (LPSTR) out + len;
1151 outlen -= len;
1153 /* copy the numbers of all PRINTER_INFO_* first */
1154 memcpy(out, pPrintersW, len);
1156 while (id < numentries) {
1157 switch (level) {
1158 case 1:
1160 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1161 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1163 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(piW->pName));
1164 if (piW->pDescription) {
1165 piA->pDescription = ptr;
1166 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1167 ptr, outlen, NULL, NULL);
1168 ptr += len;
1169 outlen -= len;
1171 if (piW->pName) {
1172 piA->pName = ptr;
1173 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1174 ptr, outlen, NULL, NULL);
1175 ptr += len;
1176 outlen -= len;
1178 if (piW->pComment) {
1179 piA->pComment = ptr;
1180 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1181 ptr, outlen, NULL, NULL);
1182 ptr += len;
1183 outlen -= len;
1185 break;
1188 case 2:
1190 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1191 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1193 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(piW->pPrinterName));
1194 if (piW->pServerName) {
1195 piA->pServerName = ptr;
1196 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1197 ptr, outlen, NULL, NULL);
1198 ptr += len;
1199 outlen -= len;
1201 if (piW->pPrinterName) {
1202 piA->pPrinterName = ptr;
1203 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1204 ptr, outlen, NULL, NULL);
1205 ptr += len;
1206 outlen -= len;
1208 if (piW->pShareName) {
1209 piA->pShareName = ptr;
1210 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1211 ptr, outlen, NULL, NULL);
1212 ptr += len;
1213 outlen -= len;
1215 if (piW->pPortName) {
1216 piA->pPortName = ptr;
1217 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1218 ptr, outlen, NULL, NULL);
1219 ptr += len;
1220 outlen -= len;
1222 if (piW->pDriverName) {
1223 piA->pDriverName = ptr;
1224 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1225 ptr, outlen, NULL, NULL);
1226 ptr += len;
1227 outlen -= len;
1229 if (piW->pComment) {
1230 piA->pComment = ptr;
1231 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1232 ptr, outlen, NULL, NULL);
1233 ptr += len;
1234 outlen -= len;
1236 if (piW->pLocation) {
1237 piA->pLocation = ptr;
1238 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1239 ptr, outlen, NULL, NULL);
1240 ptr += len;
1241 outlen -= len;
1244 if (piW->pDevMode)
1246 /* align DEVMODEA to a DWORD boundary */
1247 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1248 ptr += len;
1249 outlen -= len;
1251 piA->pDevMode = (LPDEVMODEA) ptr;
1252 DEVMODEWtoA(piW->pDevMode, piA->pDevMode);
1253 len = piA->pDevMode->dmSize + piA->pDevMode->dmDriverExtra;
1255 ptr += len;
1256 outlen -= len;
1259 if (piW->pSepFile) {
1260 piA->pSepFile = ptr;
1261 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1262 ptr, outlen, NULL, NULL);
1263 ptr += len;
1264 outlen -= len;
1266 if (piW->pPrintProcessor) {
1267 piA->pPrintProcessor = ptr;
1268 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1269 ptr, outlen, NULL, NULL);
1270 ptr += len;
1271 outlen -= len;
1273 if (piW->pDatatype) {
1274 piA->pDatatype = ptr;
1275 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1276 ptr, outlen, NULL, NULL);
1277 ptr += len;
1278 outlen -= len;
1280 if (piW->pParameters) {
1281 piA->pParameters = ptr;
1282 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1283 ptr, outlen, NULL, NULL);
1284 ptr += len;
1285 outlen -= len;
1287 if (piW->pSecurityDescriptor) {
1288 piA->pSecurityDescriptor = NULL;
1289 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1291 break;
1294 case 4:
1296 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1297 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1299 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(piW->pPrinterName));
1301 if (piW->pPrinterName) {
1302 piA->pPrinterName = ptr;
1303 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1304 ptr, outlen, NULL, NULL);
1305 ptr += len;
1306 outlen -= len;
1308 if (piW->pServerName) {
1309 piA->pServerName = ptr;
1310 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1311 ptr, outlen, NULL, NULL);
1312 ptr += len;
1313 outlen -= len;
1315 break;
1318 case 5:
1320 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1321 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1323 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(piW->pPrinterName));
1325 if (piW->pPrinterName) {
1326 piA->pPrinterName = ptr;
1327 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1328 ptr, outlen, NULL, NULL);
1329 ptr += len;
1330 outlen -= len;
1332 if (piW->pPortName) {
1333 piA->pPortName = ptr;
1334 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1335 ptr, outlen, NULL, NULL);
1336 ptr += len;
1337 outlen -= len;
1339 break;
1342 case 6: /* 6A and 6W are the same structure */
1343 break;
1345 case 7:
1347 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1348 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1350 TRACE("(%lu) #%lu\n", level, id);
1351 if (piW->pszObjectGUID) {
1352 piA->pszObjectGUID = ptr;
1353 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1354 ptr, outlen, NULL, NULL);
1355 ptr += len;
1356 outlen -= len;
1358 break;
1361 case 8:
1362 case 9:
1364 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1365 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1367 TRACE("(%lu) #%lu\n", level, id);
1368 if (piW->pDevMode)
1370 /* align DEVMODEA to a DWORD boundary */
1371 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1372 ptr += len;
1373 outlen -= len;
1375 piA->pDevMode = (LPDEVMODEA) ptr;
1376 DEVMODEWtoA(piW->pDevMode, piA->pDevMode);
1377 len = piA->pDevMode->dmSize + piA->pDevMode->dmDriverExtra;
1379 ptr += len;
1380 outlen -= len;
1382 break;
1385 default:
1386 FIXME("for level %lu\n", level);
1388 pPrintersW += pi_sizeof[level];
1389 out += pi_sizeof[level];
1390 id++;
1394 /******************************************************************
1395 * convert_driverinfo_W_to_A [internal]
1398 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1399 DWORD level, DWORD outlen, DWORD numentries)
1401 DWORD id = 0;
1402 LPSTR ptr;
1403 INT len;
1405 TRACE("(%p, %p, %ld, %lu, %lu)\n", out, pDriversW, level, outlen, numentries);
1407 len = di_sizeof[level] * numentries;
1408 ptr = (LPSTR) out + len;
1409 outlen -= len;
1411 /* copy the numbers of all PRINTER_INFO_* first */
1412 memcpy(out, pDriversW, len);
1414 #define COPY_STRING(fld) \
1415 { if (diW->fld){ \
1416 diA->fld = ptr; \
1417 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1418 ptr += len; outlen -= len;\
1420 #define COPY_MULTIZ_STRING(fld) \
1421 { LPWSTR p = diW->fld; if (p){ \
1422 diA->fld = ptr; \
1423 do {\
1424 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1425 ptr += len; outlen -= len; p += len;\
1427 while(len > 1 && outlen > 0); \
1430 while (id < numentries)
1432 switch (level)
1434 case 1:
1436 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1437 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1439 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1441 COPY_STRING(pName);
1442 break;
1444 case 2:
1446 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1447 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1449 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1451 COPY_STRING(pName);
1452 COPY_STRING(pEnvironment);
1453 COPY_STRING(pDriverPath);
1454 COPY_STRING(pDataFile);
1455 COPY_STRING(pConfigFile);
1456 break;
1458 case 3:
1460 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1461 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1463 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1465 COPY_STRING(pName);
1466 COPY_STRING(pEnvironment);
1467 COPY_STRING(pDriverPath);
1468 COPY_STRING(pDataFile);
1469 COPY_STRING(pConfigFile);
1470 COPY_STRING(pHelpFile);
1471 COPY_MULTIZ_STRING(pDependentFiles);
1472 COPY_STRING(pMonitorName);
1473 COPY_STRING(pDefaultDataType);
1474 break;
1476 case 4:
1478 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1479 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1481 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1483 COPY_STRING(pName);
1484 COPY_STRING(pEnvironment);
1485 COPY_STRING(pDriverPath);
1486 COPY_STRING(pDataFile);
1487 COPY_STRING(pConfigFile);
1488 COPY_STRING(pHelpFile);
1489 COPY_MULTIZ_STRING(pDependentFiles);
1490 COPY_STRING(pMonitorName);
1491 COPY_STRING(pDefaultDataType);
1492 COPY_MULTIZ_STRING(pszzPreviousNames);
1493 break;
1495 case 5:
1497 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1498 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1500 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1502 COPY_STRING(pName);
1503 COPY_STRING(pEnvironment);
1504 COPY_STRING(pDriverPath);
1505 COPY_STRING(pDataFile);
1506 COPY_STRING(pConfigFile);
1507 break;
1509 case 6:
1511 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1512 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1514 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1516 COPY_STRING(pName);
1517 COPY_STRING(pEnvironment);
1518 COPY_STRING(pDriverPath);
1519 COPY_STRING(pDataFile);
1520 COPY_STRING(pConfigFile);
1521 COPY_STRING(pHelpFile);
1522 COPY_MULTIZ_STRING(pDependentFiles);
1523 COPY_STRING(pMonitorName);
1524 COPY_STRING(pDefaultDataType);
1525 COPY_MULTIZ_STRING(pszzPreviousNames);
1526 COPY_STRING(pszMfgName);
1527 COPY_STRING(pszOEMUrl);
1528 COPY_STRING(pszHardwareID);
1529 COPY_STRING(pszProvider);
1530 break;
1532 case 8:
1534 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1535 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1537 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1539 COPY_STRING(pName);
1540 COPY_STRING(pEnvironment);
1541 COPY_STRING(pDriverPath);
1542 COPY_STRING(pDataFile);
1543 COPY_STRING(pConfigFile);
1544 COPY_STRING(pHelpFile);
1545 COPY_MULTIZ_STRING(pDependentFiles);
1546 COPY_STRING(pMonitorName);
1547 COPY_STRING(pDefaultDataType);
1548 COPY_MULTIZ_STRING(pszzPreviousNames);
1549 COPY_STRING(pszMfgName);
1550 COPY_STRING(pszOEMUrl);
1551 COPY_STRING(pszHardwareID);
1552 COPY_STRING(pszProvider);
1553 COPY_STRING(pszPrintProcessor);
1554 COPY_STRING(pszVendorSetup);
1555 COPY_MULTIZ_STRING(pszzColorProfiles);
1556 COPY_STRING(pszInfPath);
1557 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1558 break;
1562 default:
1563 FIXME("for level %lu\n", level);
1566 pDriversW += di_sizeof[level];
1567 out += di_sizeof[level];
1568 id++;
1571 #undef COPY_STRING
1572 #undef COPY_MULTIZ_STRING
1576 /***********************************************************
1577 * printer_info_AtoW
1579 static void *printer_info_AtoW( const void *data, DWORD level )
1581 void *ret;
1582 UNICODE_STRING usBuffer;
1584 if (!data) return NULL;
1586 if (level < 1 || level > 9) return NULL;
1588 ret = malloc( pi_sizeof[level] );
1589 if (!ret) return NULL;
1591 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1593 switch (level)
1595 case 2:
1597 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1598 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1600 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1601 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1602 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1603 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1604 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1605 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1606 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1607 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1608 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1609 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1610 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1611 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1612 break;
1615 case 8:
1616 case 9:
1618 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1619 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1621 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1622 break;
1625 default:
1626 FIXME( "Unhandled level %ld\n", level );
1627 free( ret );
1628 return NULL;
1631 return ret;
1634 /***********************************************************
1635 * free_printer_info
1637 static void free_printer_info( void *data, DWORD level )
1639 if (!data) return;
1641 switch (level)
1643 case 2:
1645 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1647 free( piW->pServerName );
1648 free( piW->pPrinterName );
1649 free( piW->pShareName );
1650 free( piW->pPortName );
1651 free( piW->pDriverName );
1652 free( piW->pComment );
1653 free( piW->pLocation );
1654 heap_free( piW->pDevMode );
1655 free( piW->pSepFile );
1656 free( piW->pPrintProcessor );
1657 free( piW->pDatatype );
1658 free( piW->pParameters );
1659 break;
1662 case 8:
1663 case 9:
1665 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1667 heap_free( piW->pDevMode );
1668 break;
1671 default:
1672 FIXME( "Unhandled level %ld\n", level );
1675 free( data );
1676 return;
1679 /******************************************************************
1680 * DeviceCapabilities [WINSPOOL.@]
1681 * DeviceCapabilitiesA [WINSPOOL.@]
1684 INT WINAPI DeviceCapabilitiesA(const char *device, const char *portA, WORD cap,
1685 char *output, DEVMODEA *devmodeA)
1687 WCHAR *device_name = NULL, *port = NULL;
1688 DEVMODEW *devmode = NULL;
1689 DWORD ret, len;
1691 len = MultiByteToWideChar(CP_ACP, 0, device, -1, NULL, 0);
1692 if (len) {
1693 device_name = malloc(len * sizeof(WCHAR));
1694 MultiByteToWideChar(CP_ACP, 0, device, -1, device_name, len);
1697 len = MultiByteToWideChar(CP_ACP, 0, portA, -1, NULL, 0);
1698 if (len) {
1699 port = malloc(len * sizeof(WCHAR));
1700 MultiByteToWideChar(CP_ACP, 0, portA, -1, port, len);
1703 if (devmodeA) devmode = GdiConvertToDevmodeW( devmodeA );
1705 if (output && (cap == DC_BINNAMES || cap == DC_FILEDEPENDENCIES || cap == DC_PAPERNAMES)) {
1706 /* These need A -> W translation */
1707 unsigned int size = 0, i;
1708 WCHAR *outputW;
1710 ret = DeviceCapabilitiesW(device_name, port, cap, NULL, devmode);
1711 if (ret == -1) goto cleanup;
1713 switch (cap) {
1714 case DC_BINNAMES:
1715 size = 24;
1716 break;
1717 case DC_PAPERNAMES:
1718 case DC_FILEDEPENDENCIES:
1719 size = 64;
1720 break;
1722 outputW = malloc(size * ret * sizeof(WCHAR));
1723 ret = DeviceCapabilitiesW(device_name, port, cap, outputW, devmode);
1724 for (i = 0; i < ret; i++)
1725 WideCharToMultiByte(CP_ACP, 0, outputW + (i * size), -1,
1726 output + (i * size), size, NULL, NULL);
1727 free(outputW);
1728 } else {
1729 ret = DeviceCapabilitiesW(device_name, port, cap, (WCHAR *)output, devmode);
1731 cleanup:
1732 free(device_name);
1733 heap_free(devmode);
1734 free(port);
1735 return ret;
1738 /*****************************************************************************
1739 * DeviceCapabilitiesW [WINSPOOL.@]
1742 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1743 WORD fwCapability, LPWSTR pOutput,
1744 const DEVMODEW *pDevMode)
1746 config_module_t *config;
1747 int ret;
1749 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability,
1750 pOutput, pDevMode);
1752 if (!(config = get_config_module(pDevice, TRUE))) {
1753 WARN("Could not load config module for %s\n", debugstr_w(pDevice));
1754 return 0;
1757 ret = config->pDrvDeviceCapabilities(NULL /* FIXME */, pDevice, fwCapability,
1758 pOutput, pDevMode);
1759 release_config_module(config);
1760 return ret;
1763 /******************************************************************
1764 * DocumentPropertiesA [WINSPOOL.@]
1766 LONG WINAPI DocumentPropertiesA(HWND hwnd, HANDLE printer, char *device_name, DEVMODEA *output,
1767 DEVMODEA *input, DWORD mode)
1769 DEVMODEW *outputW = NULL, *inputW = NULL;
1770 WCHAR *device = NULL;
1771 unsigned int len;
1772 int ret;
1774 TRACE("(%p,%p,%s,%p,%p,%ld)\n", hwnd, printer, debugstr_a(device_name), output, input, mode);
1776 len = MultiByteToWideChar(CP_ACP, 0, device_name, -1, NULL, 0);
1777 if (len) {
1778 device = malloc(len * sizeof(WCHAR));
1779 MultiByteToWideChar(CP_ACP, 0, device_name, -1, device, len);
1782 if (output && (mode & (DM_COPY | DM_UPDATE))) {
1783 ret = DocumentPropertiesW(hwnd, printer, device, NULL, NULL, 0);
1784 if (ret <= 0) {
1785 free(device);
1786 return -1;
1788 outputW = malloc(ret);
1791 if (input && (mode & DM_IN_BUFFER)) inputW = GdiConvertToDevmodeW(input);
1793 ret = DocumentPropertiesW(hwnd, printer, device, outputW, inputW, mode);
1795 if (ret >= 0 && outputW && (mode & (DM_COPY | DM_UPDATE)))
1796 DEVMODEWtoA( outputW, output );
1798 free(device);
1799 heap_free(inputW);
1800 free(outputW);
1802 if (!mode && ret > 0) ret -= CCHDEVICENAME + CCHFORMNAME;
1803 return ret;
1806 static LONG WINAPI document_callback(PROPSHEETUI_INFO *info, LPARAM lparam)
1808 if (info->Reason == PROPSHEETUI_REASON_INIT)
1810 document_property_t *dp = (document_property_t *)info->lParamInit;
1812 if (!info->pfnComPropSheet(info->hComPropSheet, CPSFUNC_ADD_PFNPROPSHEETUIW,
1813 (LPARAM)dp->config->pDrvDocumentPropertySheets, (LPARAM)&dp->dph))
1814 return ERR_CPSUI_GETLASTERROR;
1816 return CPSUI_OK;
1819 /*****************************************************************************
1820 * DocumentPropertiesW (WINSPOOL.@)
1822 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1823 LPWSTR pDeviceName,
1824 LPDEVMODEW pDevModeOutput,
1825 LPDEVMODEW pDevModeInput, DWORD fMode)
1827 document_property_t dp;
1828 const WCHAR *device;
1829 LONG ret;
1831 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1832 hWnd, hPrinter, debugstr_w(pDeviceName), pDevModeOutput, pDevModeInput, fMode);
1834 device = hPrinter ? get_opened_printer_name(hPrinter) : pDeviceName;
1835 if (!device) {
1836 ERR("no device name\n");
1837 return -1;
1840 dp.dph.cbSize = sizeof(dp.dph);
1841 dp.dph.Reserved = 0;
1842 dp.dph.hPrinter = hPrinter;
1843 dp.dph.pszPrinterName = device;
1844 dp.dph.pdmIn = pDevModeInput;
1845 dp.dph.pdmOut = pDevModeOutput;
1846 dp.dph.cbOut = dp.dph.pdmOut ? dp.dph.pdmOut->dmSize : 0;
1847 dp.dph.fMode = fMode;
1848 dp.config = get_config_module(device, TRUE);
1849 if (!dp.config) {
1850 ERR("Could not load config module for %s\n", debugstr_w(device));
1851 return -1;
1854 if (!(fMode & ~(DM_IN_BUFFER | DM_OUT_BUFFER | DM_OUT_DEFAULT))) {
1855 ret = dp.config->pDrvDocumentPropertySheets(NULL, (LPARAM)&dp.dph);
1857 if ((!fMode || !pDevModeOutput) && dp.dph.cbOut != ret)
1858 FIXME("size mismatch: ret = %ld cbOut = %ld\n", ret, dp.dph.cbOut);
1859 } else {
1860 ret = CommonPropertySheetUIW(hWnd, document_callback, (LPARAM)&dp, NULL);
1863 release_config_module(dp.config);
1864 return ret;
1867 /*****************************************************************************
1868 * IsValidDevmodeA [WINSPOOL.@]
1870 * Validate a DEVMODE structure and fix errors if possible.
1873 BOOL WINAPI IsValidDevmodeA(PDEVMODEA pDevMode, SIZE_T size)
1875 FIXME("(%p,%Id): stub\n", pDevMode, size);
1877 if(!pDevMode)
1878 return FALSE;
1880 return TRUE;
1883 /*****************************************************************************
1884 * IsValidDevmodeW [WINSPOOL.@]
1886 * Validate a DEVMODE structure and fix errors if possible.
1889 BOOL WINAPI IsValidDevmodeW(PDEVMODEW dm, SIZE_T size)
1891 static const struct
1893 DWORD flag;
1894 SIZE_T size;
1895 } map[] =
1897 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
1898 { DM_ORIENTATION, F_SIZE(u1.s1.dmOrientation) },
1899 { DM_PAPERSIZE, F_SIZE(u1.s1.dmPaperSize) },
1900 { DM_PAPERLENGTH, F_SIZE(u1.s1.dmPaperLength) },
1901 { DM_PAPERWIDTH, F_SIZE(u1.s1.dmPaperWidth) },
1902 { DM_SCALE, F_SIZE(u1.s1.dmScale) },
1903 { DM_COPIES, F_SIZE(u1.s1.dmCopies) },
1904 { DM_DEFAULTSOURCE, F_SIZE(u1.s1.dmDefaultSource) },
1905 { DM_PRINTQUALITY, F_SIZE(u1.s1.dmPrintQuality) },
1906 { DM_POSITION, F_SIZE(u1.s2.dmPosition) },
1907 { DM_DISPLAYORIENTATION, F_SIZE(u1.s2.dmDisplayOrientation) },
1908 { DM_DISPLAYFIXEDOUTPUT, F_SIZE(u1.s2.dmDisplayFixedOutput) },
1909 { DM_COLOR, F_SIZE(dmColor) },
1910 { DM_DUPLEX, F_SIZE(dmDuplex) },
1911 { DM_YRESOLUTION, F_SIZE(dmYResolution) },
1912 { DM_TTOPTION, F_SIZE(dmTTOption) },
1913 { DM_COLLATE, F_SIZE(dmCollate) },
1914 { DM_FORMNAME, F_SIZE(dmFormName) },
1915 { DM_LOGPIXELS, F_SIZE(dmLogPixels) },
1916 { DM_BITSPERPEL, F_SIZE(dmBitsPerPel) },
1917 { DM_PELSWIDTH, F_SIZE(dmPelsWidth) },
1918 { DM_PELSHEIGHT, F_SIZE(dmPelsHeight) },
1919 { DM_DISPLAYFLAGS, F_SIZE(u2.dmDisplayFlags) },
1920 { DM_NUP, F_SIZE(u2.dmNup) },
1921 { DM_DISPLAYFREQUENCY, F_SIZE(dmDisplayFrequency) },
1922 { DM_ICMMETHOD, F_SIZE(dmICMMethod) },
1923 { DM_ICMINTENT, F_SIZE(dmICMIntent) },
1924 { DM_MEDIATYPE, F_SIZE(dmMediaType) },
1925 { DM_DITHERTYPE, F_SIZE(dmDitherType) },
1926 { DM_PANNINGWIDTH, F_SIZE(dmPanningWidth) },
1927 { DM_PANNINGHEIGHT, F_SIZE(dmPanningHeight) }
1928 #undef F_SIZE
1930 int i;
1932 if (!dm) return FALSE;
1933 if (size < FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(dm->dmFields)) return FALSE;
1935 for (i = 0; i < ARRAY_SIZE(map); i++)
1936 if ((dm->dmFields & map[i].flag) && size < map[i].size)
1937 return FALSE;
1939 return TRUE;
1942 /******************************************************************
1943 * OpenPrinterA [WINSPOOL.@]
1945 * See OpenPrinterW.
1948 BOOL WINAPI OpenPrinterA(LPSTR name, HANDLE *printer, PRINTER_DEFAULTSA *defaults)
1950 return OpenPrinter2A(name, printer, defaults, NULL);
1953 /******************************************************************
1954 * OpenPrinterW [WINSPOOL.@]
1956 * Open a Printer / Printserver or a Printer-Object
1958 * PARAMS
1959 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1960 * phPrinter [O] The resulting Handle is stored here
1961 * pDefault [I] PTR to Default Printer Settings or NULL
1963 * RETURNS
1964 * Success: TRUE
1965 * Failure: FALSE
1967 * NOTES
1968 * lpPrinterName is one of:
1969 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1970 *| Printer: "PrinterName"
1971 *| Printer-Object: "PrinterName,Job xxx"
1972 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1973 *| XcvPort: "Servername,XcvPort PortName"
1975 * BUGS
1976 *| Printer-Object not supported
1977 *| pDefaults is ignored
1980 BOOL WINAPI OpenPrinterW(LPWSTR name, HANDLE *printer, PRINTER_DEFAULTSW *defaults)
1982 return OpenPrinter2W(name, printer, defaults, NULL);
1985 BOOL WINAPI OpenPrinter2A(LPSTR name, HANDLE *printer,
1986 PRINTER_DEFAULTSA *defaults, PRINTER_OPTIONSA *options)
1988 UNICODE_STRING nameU;
1989 UNICODE_STRING datatypeU;
1990 PRINTER_DEFAULTSW defaultsW, *p_defaultsW = NULL;
1991 PRINTER_OPTIONSW optionsW, *p_optionsW = NULL;
1992 WCHAR *nameW;
1993 BOOL ret;
1995 TRACE("(%s,%p,%p,%p)\n", debugstr_a(name), printer, defaults, options);
1997 nameW = asciitounicode(&nameU, name);
1999 if (options)
2001 optionsW.cbSize = sizeof(optionsW);
2002 optionsW.dwFlags = options->dwFlags;
2003 p_optionsW = &optionsW;
2006 if (defaults)
2008 defaultsW.pDatatype = asciitounicode(&datatypeU, defaults->pDatatype);
2009 defaultsW.pDevMode = defaults->pDevMode ? GdiConvertToDevmodeW(defaults->pDevMode) : NULL;
2010 defaultsW.DesiredAccess = defaults->DesiredAccess;
2011 p_defaultsW = &defaultsW;
2014 ret = OpenPrinter2W(nameW, printer, p_defaultsW, p_optionsW);
2016 if (p_defaultsW)
2018 RtlFreeUnicodeString(&datatypeU);
2019 heap_free(defaultsW.pDevMode);
2021 RtlFreeUnicodeString(&nameU);
2023 return ret;
2026 BOOL WINAPI OpenPrinter2W(LPWSTR name, HANDLE *printer,
2027 PRINTER_DEFAULTSW *defaults, PRINTER_OPTIONSW *options)
2029 HKEY key;
2031 TRACE("(%s,%p,%p,%p)\n", debugstr_w(name), printer, defaults, options);
2033 if (options)
2034 FIXME("flags %08lx ignored\n", options->dwFlags);
2036 if(!printer)
2038 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2039 SetLastError( ERROR_INVALID_PARAMETER );
2040 return FALSE;
2043 /* Get the unique handle of the printer or Printserver */
2044 *printer = get_opened_printer_entry( name, defaults );
2046 if (*printer && WINSPOOL_GetOpenedPrinterRegKey( *printer, &key ) == ERROR_SUCCESS)
2048 DWORD deleting = 0, size = sizeof( deleting ), type;
2049 DWORD status;
2050 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2051 WaitForSingleObject( init_mutex, INFINITE );
2052 status = get_dword_from_reg( key, L"Status" );
2053 set_reg_DWORD( key, L"Status", status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2054 ReleaseMutex( init_mutex );
2055 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2056 update_driver( *printer );
2057 RegCloseKey( key );
2060 TRACE("returning %d with %lu and %p\n", *printer != NULL, GetLastError(), *printer);
2061 return (*printer != NULL);
2064 /******************************************************************
2065 * AddMonitorA [WINSPOOL.@]
2067 * See AddMonitorW.
2070 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2072 LPWSTR nameW = NULL;
2073 INT len;
2074 BOOL res;
2075 LPMONITOR_INFO_2A mi2a;
2076 MONITOR_INFO_2W mi2w;
2078 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2079 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2080 debugstr_a(mi2a ? mi2a->pName : NULL),
2081 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2082 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2084 if (Level != 2) {
2085 SetLastError(ERROR_INVALID_LEVEL);
2086 return FALSE;
2089 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2090 if (mi2a == NULL) {
2091 return FALSE;
2094 if (pName) {
2095 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2096 nameW = malloc(len * sizeof(WCHAR));
2097 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2100 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2101 if (mi2a->pName) {
2102 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2103 mi2w.pName = malloc(len * sizeof(WCHAR));
2104 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2106 if (mi2a->pEnvironment) {
2107 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2108 mi2w.pEnvironment = malloc(len * sizeof(WCHAR));
2109 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2111 if (mi2a->pDLLName) {
2112 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2113 mi2w.pDLLName = malloc(len * sizeof(WCHAR));
2114 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2117 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2119 free(mi2w.pName);
2120 free(mi2w.pEnvironment);
2121 free(mi2w.pDLLName);
2123 free(nameW);
2124 return (res);
2127 /******************************************************************************
2128 * AddMonitorW [WINSPOOL.@]
2130 * Install a Printmonitor
2132 * PARAMS
2133 * pName [I] Servername or NULL (local Computer)
2134 * Level [I] Structure-Level (Must be 2)
2135 * pMonitors [I] PTR to MONITOR_INFO_2
2137 * RETURNS
2138 * Success: TRUE
2139 * Failure: FALSE
2141 * NOTES
2142 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2145 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2147 LPMONITOR_INFO_2W mi2w;
2149 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2150 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2151 debugstr_w(mi2w ? mi2w->pName : NULL),
2152 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2153 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2155 if ((backend == NULL) && !load_backend()) return FALSE;
2157 if (Level != 2) {
2158 SetLastError(ERROR_INVALID_LEVEL);
2159 return FALSE;
2162 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2163 if (mi2w == NULL) {
2164 return FALSE;
2167 return backend->fpAddMonitor(pName, Level, pMonitors);
2170 /******************************************************************
2171 * DeletePrinterDriverA [WINSPOOL.@]
2174 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2176 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2179 /******************************************************************
2180 * DeletePrinterDriverW [WINSPOOL.@]
2183 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2185 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2188 /******************************************************************
2189 * DeleteMonitorA [WINSPOOL.@]
2191 * See DeleteMonitorW.
2194 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2196 LPWSTR nameW = NULL;
2197 LPWSTR EnvironmentW = NULL;
2198 LPWSTR MonitorNameW = NULL;
2199 BOOL res;
2200 INT len;
2202 if (pName) {
2203 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2204 nameW = malloc(len * sizeof(WCHAR));
2205 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2208 if (pEnvironment) {
2209 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2210 EnvironmentW = malloc(len * sizeof(WCHAR));
2211 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2213 if (pMonitorName) {
2214 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2215 MonitorNameW = malloc(len * sizeof(WCHAR));
2216 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2219 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2221 free(MonitorNameW);
2222 free(EnvironmentW);
2223 free(nameW);
2224 return (res);
2227 /******************************************************************
2228 * DeleteMonitorW [WINSPOOL.@]
2230 * Delete a specific Printmonitor from a Printing-Environment
2232 * PARAMS
2233 * pName [I] Servername or NULL (local Computer)
2234 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2235 * pMonitorName [I] Name of the Monitor, that should be deleted
2237 * RETURNS
2238 * Success: TRUE
2239 * Failure: FALSE
2241 * NOTES
2242 * pEnvironment is ignored in Windows for the local Computer.
2245 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2248 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2249 debugstr_w(pMonitorName));
2251 if ((backend == NULL) && !load_backend()) return FALSE;
2253 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2257 /******************************************************************
2258 * DeletePortA [WINSPOOL.@]
2260 * See DeletePortW.
2263 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2265 LPWSTR nameW = NULL;
2266 LPWSTR portW = NULL;
2267 INT len;
2268 DWORD res;
2270 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2272 /* convert servername to unicode */
2273 if (pName) {
2274 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2275 nameW = malloc(len * sizeof(WCHAR));
2276 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2279 /* convert portname to unicode */
2280 if (pPortName) {
2281 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2282 portW = malloc(len * sizeof(WCHAR));
2283 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2286 res = DeletePortW(nameW, hWnd, portW);
2287 free(nameW);
2288 free(portW);
2289 return res;
2292 /******************************************************************
2293 * DeletePortW [WINSPOOL.@]
2295 * Delete a specific Port
2297 * PARAMS
2298 * pName [I] Servername or NULL (local Computer)
2299 * hWnd [I] Handle to parent Window for the Dialog-Box
2300 * pPortName [I] Name of the Port, that should be deleted
2302 * RETURNS
2303 * Success: TRUE
2304 * Failure: FALSE
2307 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2309 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2311 if ((backend == NULL) && !load_backend()) return FALSE;
2313 if (!pPortName) {
2314 SetLastError(RPC_X_NULL_REF_POINTER);
2315 return FALSE;
2318 return backend->fpDeletePort(pName, hWnd, pPortName);
2321 /******************************************************************************
2322 * WritePrinter [WINSPOOL.@]
2324 BOOL WINAPI WritePrinter(HANDLE printer, void *buf, DWORD size, DWORD *written)
2326 HANDLE handle = get_backend_handle(printer);
2328 TRACE("(%p, %p, %ld, %p)\n", printer, buf, size, written);
2330 if (!handle)
2332 SetLastError(ERROR_INVALID_HANDLE);
2333 return FALSE;
2336 return backend->fpWritePrinter(handle, buf, size, written);
2339 /*****************************************************************************
2340 * AddFormA [WINSPOOL.@]
2342 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2344 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
2345 return TRUE;
2348 /*****************************************************************************
2349 * AddFormW [WINSPOOL.@]
2351 BOOL WINAPI AddFormW( HANDLE printer, DWORD level, BYTE *form )
2353 HANDLE handle = get_backend_handle( printer );
2355 TRACE( "(%p, %ld, %p)\n", printer, level, form );
2357 if (!handle)
2359 SetLastError( ERROR_INVALID_HANDLE );
2360 return FALSE;
2363 return backend->fpAddForm( handle, level, form );
2366 /*****************************************************************************
2367 * AddJobA [WINSPOOL.@]
2369 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2371 BOOL ret;
2372 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2373 DWORD needed;
2375 if(Level != 1) {
2376 SetLastError(ERROR_INVALID_LEVEL);
2377 return FALSE;
2380 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2382 if(ret) {
2383 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2384 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2385 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2386 if(*pcbNeeded > cbBuf) {
2387 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2388 ret = FALSE;
2389 } else {
2390 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2391 addjobA->JobId = addjobW->JobId;
2392 addjobA->Path = (char *)(addjobA + 1);
2393 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2396 return ret;
2399 /*****************************************************************************
2400 * AddJobW [WINSPOOL.@]
2402 BOOL WINAPI AddJobW(HANDLE printer, DWORD level, LPBYTE data, DWORD size, DWORD *needed)
2404 HANDLE handle = get_backend_handle(printer);
2406 TRACE("(%p, %ld, %p, %ld, %p)\n", printer, level, data, size, needed);
2408 if (!handle)
2410 SetLastError(ERROR_INVALID_HANDLE);
2411 return FALSE;
2414 return backend->fpAddJob(handle, level, data, size, needed);
2417 /*****************************************************************************
2418 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2420 * Return the PATH for the Print-Processors
2422 * See GetPrintProcessorDirectoryW.
2426 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2427 DWORD level, LPBYTE Info,
2428 DWORD cbBuf, LPDWORD pcbNeeded)
2430 LPWSTR serverW = NULL;
2431 LPWSTR envW = NULL;
2432 BOOL ret;
2433 INT len;
2435 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server),
2436 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2439 if (server) {
2440 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2441 serverW = malloc(len * sizeof(WCHAR));
2442 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2445 if (env) {
2446 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2447 envW = malloc(len * sizeof(WCHAR));
2448 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2451 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2452 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2454 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2455 cbBuf, pcbNeeded);
2457 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2458 cbBuf, NULL, NULL) > 0;
2461 TRACE(" required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2462 free(envW);
2463 free(serverW);
2464 return ret;
2467 /*****************************************************************************
2468 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2470 * Return the PATH for the Print-Processors
2472 * PARAMS
2473 * server [I] Servername (NT only) or NULL (local Computer)
2474 * env [I] Printing-Environment (see below) or NULL (Default)
2475 * level [I] Structure-Level (must be 1)
2476 * Info [O] PTR to Buffer that receives the Result
2477 * cbBuf [I] Size of Buffer at "Info"
2478 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2479 * required for the Buffer at "Info"
2481 * RETURNS
2482 * Success: TRUE and in pcbNeeded the Bytes used in Info
2483 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2484 * if cbBuf is too small
2486 * Native Values returned in Info on Success:
2487 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2488 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2489 *| win9x(Windows 4.0): "%winsysdir%"
2491 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2493 * BUGS
2494 * Only NULL or "" is supported for server
2497 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2498 DWORD level, LPBYTE Info,
2499 DWORD cbBuf, LPDWORD pcbNeeded)
2502 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server), debugstr_w(env), level,
2503 Info, cbBuf, pcbNeeded);
2505 if ((backend == NULL) && !load_backend()) return FALSE;
2507 if (level != 1) {
2508 /* (Level != 1) is ignored in win9x */
2509 SetLastError(ERROR_INVALID_LEVEL);
2510 return FALSE;
2513 if (pcbNeeded == NULL) {
2514 /* (pcbNeeded == NULL) is ignored in win9x */
2515 SetLastError(RPC_X_NULL_REF_POINTER);
2516 return FALSE;
2519 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2522 /*****************************************************************************
2523 * set_devices_and_printerports [internal]
2525 * set the [Devices] and [PrinterPorts] entries for a printer.
2528 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2530 DWORD portlen = wcslen( pi->pPortName ) * sizeof(WCHAR);
2531 WCHAR *devline;
2532 HKEY key;
2534 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2536 /* FIXME: the driver must change to "winspool" */
2537 devline = malloc( sizeof(L"wineps.drv") + portlen + sizeof(L",15,45") );
2538 if (devline)
2540 wcscpy( devline, L"wineps.drv," );
2541 wcscat( devline, pi->pPortName );
2543 TRACE("using %s\n", debugstr_w(devline));
2544 if (!create_printers_reg_key( user_printers_key, &key ))
2546 RegSetValueExW( key, pi->pPrinterName, 0, REG_SZ, (BYTE *)devline,
2547 (wcslen( devline ) + 1) * sizeof(WCHAR) );
2548 RegCloseKey( key );
2551 wcscat( devline, L",15,45" );
2552 if (!create_printers_reg_key( user_ports_key, &key ))
2554 RegSetValueExW( key, pi->pPrinterName, 0, REG_SZ, (BYTE *)devline,
2555 (wcslen( devline ) + 1) * sizeof(WCHAR) );
2556 RegCloseKey( key );
2558 free(devline);
2562 static BOOL validate_print_proc(WCHAR *server, const WCHAR *name)
2564 PRINTPROCESSOR_INFO_1W *ppi;
2565 DWORD size, i, no;
2567 if (!EnumPrintProcessorsW(server, NULL, 1, NULL, 0, &size, &no)
2568 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2570 return FALSE;
2572 ppi = malloc(size);
2573 if (!ppi)
2575 SetLastError(ERROR_OUTOFMEMORY);
2576 return FALSE;
2578 if (!EnumPrintProcessorsW(server, NULL, 1, (BYTE*)ppi, size, &size, &no))
2580 free(ppi);
2581 return FALSE;
2584 for (i = 0; i < no; i++)
2586 if (!wcsicmp(ppi[i].pName, name))
2587 break;
2589 free(ppi);
2590 return i != no;
2593 /*****************************************************************************
2594 * AddPrinterW [WINSPOOL.@]
2596 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2598 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2599 LPDEVMODEW dm;
2600 HANDLE retval;
2601 HKEY printer_key, printers_key, hkeyDriver, hkeyDrivers;
2602 LONG size;
2604 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
2606 if(pName && *pName) {
2607 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2608 SetLastError(ERROR_INVALID_PARAMETER);
2609 return 0;
2611 if(Level != 2) {
2612 ERR("Level = %ld, unsupported!\n", Level);
2613 SetLastError(ERROR_INVALID_LEVEL);
2614 return 0;
2616 if(!pPrinter) {
2617 SetLastError(ERROR_INVALID_PARAMETER);
2618 return 0;
2620 if (create_printers_reg_key( system_printers_key, &printers_key ))
2622 ERR("Can't create Printers key\n");
2623 return 0;
2625 if (!RegOpenKeyW( printers_key, pi->pPrinterName, &printer_key ))
2627 if (!RegQueryValueW( printer_key, L"Attributes", NULL, NULL ))
2629 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2630 RegCloseKey( printer_key );
2631 RegCloseKey( printers_key );
2632 return 0;
2634 RegCloseKey( printer_key );
2636 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2637 if(!hkeyDrivers) {
2638 ERR("Can't create Drivers key\n");
2639 RegCloseKey( printers_key );
2640 return 0;
2642 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2643 ERROR_SUCCESS) {
2644 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2645 RegCloseKey( printers_key );
2646 RegCloseKey(hkeyDrivers);
2647 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2648 return 0;
2650 RegCloseKey(hkeyDriver);
2651 RegCloseKey(hkeyDrivers);
2653 if (!validate_print_proc(pName, pi->pPrintProcessor))
2655 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2656 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2657 RegCloseKey( printers_key );
2658 return 0;
2661 if (RegCreateKeyW( printers_key, pi->pPrinterName, &printer_key ))
2663 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2664 SetLastError(ERROR_INVALID_PRINTER_NAME);
2665 RegCloseKey( printers_key );
2666 return 0;
2669 set_devices_and_printerports(pi);
2671 set_reg_DWORD( printer_key, L"Attributes", pi->Attributes );
2672 set_reg_szW( printer_key, L"Datatype", pi->pDatatype );
2673 set_reg_DWORD( printer_key, L"Default Priority", pi->DefaultPriority );
2674 set_reg_szW( printer_key, L"Description", pi->pComment );
2675 set_reg_DWORD( printer_key, L"dnsTimeout", 0 );
2676 set_reg_szW( printer_key, L"Location", pi->pLocation );
2677 set_reg_szW( printer_key, L"Name", pi->pPrinterName );
2678 set_reg_szW( printer_key, L"Parameters", pi->pParameters );
2679 set_reg_szW( printer_key, L"Port", pi->pPortName );
2680 set_reg_szW( printer_key, L"Print Processor", pi->pPrintProcessor );
2681 set_reg_szW( printer_key, L"Printer Driver", pi->pDriverName );
2682 set_reg_DWORD( printer_key, L"Priority", pi->Priority );
2683 set_reg_szW( printer_key, L"Separator File", pi->pSepFile );
2684 set_reg_szW( printer_key, L"Share Name", pi->pShareName );
2685 set_reg_DWORD( printer_key, L"StartTime", pi->StartTime );
2686 set_reg_DWORD( printer_key, L"Status", pi->Status );
2687 set_reg_DWORD( printer_key, L"txTimeout", 0 );
2688 set_reg_DWORD( printer_key, L"UntilTime", pi->UntilTime );
2690 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2692 if (size < 0)
2694 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2695 size = sizeof(DEVMODEW);
2697 if(pi->pDevMode)
2698 dm = pi->pDevMode;
2699 else
2701 dm = calloc( 1, size );
2702 dm->dmSize = size;
2703 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2705 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2706 free( dm );
2707 dm = NULL;
2709 else
2711 unsigned int len = min( ARRAY_SIZE( dm->dmDeviceName ) - 1, wcslen( pi->pPrinterName ) );
2712 memcpy( dm->dmDeviceName, pi->pPrinterName, len * sizeof(WCHAR) );
2713 dm->dmDeviceName[len] = '\0';
2717 set_reg_devmode( printer_key, L"Default DevMode", dm );
2718 if (!pi->pDevMode) free( dm );
2720 RegCloseKey( printer_key );
2721 RegCloseKey( printers_key );
2722 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2723 ERR("OpenPrinter failing\n");
2724 return 0;
2726 return retval;
2729 /*****************************************************************************
2730 * AddPrinterA [WINSPOOL.@]
2732 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2734 UNICODE_STRING pNameW;
2735 PWSTR pwstrNameW;
2736 PRINTER_INFO_2W *piW;
2737 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2738 HANDLE ret;
2740 TRACE("(%s, %ld, %p)\n", debugstr_a(pName), Level, pPrinter);
2741 if(Level != 2) {
2742 ERR("Level = %ld, unsupported!\n", Level);
2743 SetLastError(ERROR_INVALID_LEVEL);
2744 return 0;
2746 pwstrNameW = asciitounicode(&pNameW,pName);
2747 piW = printer_info_AtoW( piA, Level );
2749 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2751 free_printer_info( piW, Level );
2752 RtlFreeUnicodeString(&pNameW);
2753 return ret;
2757 /*****************************************************************************
2758 * ClosePrinter [WINSPOOL.@]
2760 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2762 UINT_PTR i = (UINT_PTR)hPrinter;
2763 opened_printer_t *printer = NULL;
2765 TRACE("(%p)\n", hPrinter);
2767 EnterCriticalSection(&printer_handles_cs);
2769 if ((i > 0) && (i <= nb_printer_handles))
2770 printer = printer_handles[i - 1];
2773 if(printer)
2775 TRACE("closing %s\n", debugstr_w(printer->name));
2776 if (printer->backend_printer) {
2777 backend->fpClosePrinter(printer->backend_printer);
2780 free_printer_entry( printer );
2781 printer_handles[i - 1] = NULL;
2782 LeaveCriticalSection(&printer_handles_cs);
2783 return TRUE;
2786 LeaveCriticalSection(&printer_handles_cs);
2787 SetLastError(ERROR_INVALID_HANDLE);
2788 return FALSE;
2791 /*****************************************************************************
2792 * DeleteFormA [WINSPOOL.@]
2794 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2796 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2797 return TRUE;
2800 /*****************************************************************************
2801 * DeleteFormW [WINSPOOL.@]
2803 BOOL WINAPI DeleteFormW( HANDLE printer, WCHAR *name )
2805 HANDLE handle = get_backend_handle( printer );
2807 TRACE( "(%p, %s)\n", printer, debugstr_w( name ) );
2809 if (!handle)
2811 SetLastError( ERROR_INVALID_HANDLE );
2812 return FALSE;
2815 return backend->fpDeleteForm( handle, name );
2818 /*****************************************************************************
2819 * DeletePrinter [WINSPOOL.@]
2821 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2823 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2824 config_module_t *config_module;
2825 HKEY key;
2826 WCHAR def[MAX_PATH];
2827 DWORD size = ARRAY_SIZE(def);
2829 if(!lpNameW) {
2830 SetLastError(ERROR_INVALID_HANDLE);
2831 return FALSE;
2834 EnterCriticalSection(&config_modules_cs);
2835 if ((config_module = get_config_module(lpNameW, FALSE))) {
2836 wine_rb_remove(&config_modules, &config_module->entry);
2837 release_config_module(config_module);
2839 LeaveCriticalSection(&config_modules_cs);
2841 if (!create_printers_reg_key( system_printers_key, &key ))
2843 RegDeleteTreeW( key, lpNameW );
2844 RegCloseKey( key );
2847 if (!create_printers_reg_key( user_printers_key, &key ))
2849 RegDeleteValueW( key, lpNameW );
2850 RegCloseKey( key );
2853 if (!create_printers_reg_key( user_ports_key, &key ))
2855 RegDeleteValueW( key, lpNameW );
2856 RegCloseKey( key );
2859 if (GetDefaultPrinterW( def, &size ) && !wcscmp( def, lpNameW ))
2861 if (!create_printers_reg_key( user_default_key, &key ))
2863 RegDeleteValueW( key, L"device" );
2864 RegCloseKey( key );
2866 SetDefaultPrinterW( NULL );
2869 return TRUE;
2872 /*****************************************************************************
2873 * SetPrinterA [WINSPOOL.@]
2875 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2877 BYTE *dataW = data;
2878 BOOL ret;
2880 if (level != 0)
2882 dataW = printer_info_AtoW( data, level );
2883 if (!dataW) return FALSE;
2886 ret = SetPrinterW( printer, level, dataW, command );
2888 if (dataW != data) free_printer_info( dataW, level );
2890 return ret;
2893 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
2895 set_reg_szW( key, L"Name", pi->pPrinterName );
2896 set_reg_szW( key, L"Share Name", pi->pShareName );
2897 set_reg_szW( key, L"Port", pi->pPortName );
2898 set_reg_szW( key, L"Printer Driver", pi->pDriverName );
2899 set_reg_szW( key, L"Description", pi->pComment );
2900 set_reg_szW( key, L"Location", pi->pLocation );
2902 if (pi->pDevMode)
2903 set_reg_devmode( key, L"Default DevMode", pi->pDevMode );
2905 set_reg_szW( key, L"Separator File", pi->pSepFile );
2906 set_reg_szW( key, L"Print Processor", pi->pPrintProcessor );
2907 set_reg_szW( key, L"Datatype", pi->pDatatype );
2908 set_reg_szW( key, L"Parameters", pi->pParameters );
2910 set_reg_DWORD( key, L"Attributes", pi->Attributes );
2911 set_reg_DWORD( key, L"Priority", pi->Priority );
2912 set_reg_DWORD( key, L"Default Priority", pi->DefaultPriority );
2913 set_reg_DWORD( key, L"StartTime", pi->StartTime );
2914 set_reg_DWORD( key, L"UntilTime", pi->UntilTime );
2917 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
2919 if (!pi->pDevMode) return FALSE;
2921 set_reg_devmode( key, L"Default DevMode", pi->pDevMode );
2922 return TRUE;
2925 /******************************************************************************
2926 * SetPrinterW [WINSPOOL.@]
2928 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2930 HKEY key;
2931 BOOL ret = FALSE;
2933 TRACE( "(%p, %ld, %p, %ld)\n", printer, level, data, command );
2935 if (command != 0) FIXME( "Ignoring command %ld\n", command );
2937 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
2938 return FALSE;
2940 switch (level)
2942 case 2:
2944 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
2945 set_printer_2( key, pi2 );
2946 ret = TRUE;
2947 break;
2950 case 8:
2951 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
2952 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
2953 /* fall through */
2954 case 9:
2956 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
2957 ret = set_printer_9( key, pi );
2958 break;
2961 default:
2962 FIXME( "Unimplemented level %ld\n", level );
2963 SetLastError( ERROR_INVALID_LEVEL );
2966 RegCloseKey( key );
2967 return ret;
2970 /*****************************************************************************
2971 * SetJobA [WINSPOOL.@]
2973 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2974 LPBYTE pJob, DWORD Command)
2976 BOOL ret;
2977 LPBYTE JobW;
2978 UNICODE_STRING usBuffer;
2980 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2982 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2983 are all ignored by SetJob, so we don't bother copying them */
2984 switch(Level)
2986 case 0:
2987 JobW = NULL;
2988 break;
2989 case 1:
2991 JOB_INFO_1W *info1W = malloc(sizeof(*info1W));
2992 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2994 JobW = (LPBYTE)info1W;
2995 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2996 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2997 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2998 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2999 info1W->Status = info1A->Status;
3000 info1W->Priority = info1A->Priority;
3001 info1W->Position = info1A->Position;
3002 info1W->PagesPrinted = info1A->PagesPrinted;
3003 break;
3005 case 2:
3007 JOB_INFO_2W *info2W = malloc(sizeof(*info2W));
3008 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3010 JobW = (LPBYTE)info2W;
3011 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3012 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3013 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3014 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3015 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3016 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3017 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3018 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3019 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3020 info2W->Status = info2A->Status;
3021 info2W->Priority = info2A->Priority;
3022 info2W->Position = info2A->Position;
3023 info2W->StartTime = info2A->StartTime;
3024 info2W->UntilTime = info2A->UntilTime;
3025 info2W->PagesPrinted = info2A->PagesPrinted;
3026 break;
3028 case 3:
3029 JobW = malloc(sizeof(JOB_INFO_3));
3030 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3031 break;
3032 default:
3033 SetLastError(ERROR_INVALID_LEVEL);
3034 return FALSE;
3037 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3039 switch(Level)
3041 case 1:
3043 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3044 free(info1W->pUserName);
3045 free(info1W->pDocument);
3046 free(info1W->pDatatype);
3047 free(info1W->pStatus);
3048 break;
3050 case 2:
3052 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3053 free(info2W->pUserName);
3054 free(info2W->pDocument);
3055 free(info2W->pNotifyName);
3056 free(info2W->pDatatype);
3057 free(info2W->pPrintProcessor);
3058 free(info2W->pParameters);
3059 heap_free(info2W->pDevMode);
3060 free(info2W->pStatus);
3061 break;
3064 free(JobW);
3066 return ret;
3069 /*****************************************************************************
3070 * SetJobW [WINSPOOL.@]
3072 BOOL WINAPI SetJobW(HANDLE printer, DWORD job_id, DWORD level,
3073 LPBYTE data, DWORD command)
3075 HANDLE handle = get_backend_handle(printer);
3077 TRACE("(%p, %ld, %ld, %p, %ld)\n", printer, job_id, level, data, command);
3079 if (!handle)
3081 SetLastError(ERROR_INVALID_HANDLE);
3082 return FALSE;
3085 return backend->fpSetJob(handle, job_id, level, data, command);
3088 /*****************************************************************************
3089 * EndDocPrinter [WINSPOOL.@]
3091 BOOL WINAPI EndDocPrinter(HANDLE printer)
3093 HANDLE handle = get_backend_handle(printer);
3095 TRACE("(%p)\n", printer);
3097 if (!handle)
3099 SetLastError(ERROR_INVALID_HANDLE);
3100 return FALSE;
3103 return backend->fpEndDocPrinter(handle);
3106 /*****************************************************************************
3107 * EndPagePrinter [WINSPOOL.@]
3109 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3111 FIXME("(%p): stub\n", hPrinter);
3112 return TRUE;
3115 /*****************************************************************************
3116 * StartDocPrinterA [WINSPOOL.@]
3118 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3120 UNICODE_STRING usBuffer;
3121 DOC_INFO_2W doc2W;
3122 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3123 DWORD ret;
3125 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3126 or one (DOC_INFO_3) extra DWORDs */
3128 switch(Level) {
3129 case 2:
3130 doc2W.JobId = doc2->JobId;
3131 /* fall through */
3132 case 3:
3133 doc2W.dwMode = doc2->dwMode;
3134 /* fall through */
3135 case 1:
3136 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3137 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3138 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3139 break;
3141 default:
3142 SetLastError(ERROR_INVALID_LEVEL);
3143 return FALSE;
3146 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3148 free(doc2W.pDatatype);
3149 free(doc2W.pOutputFile);
3150 free(doc2W.pDocName);
3152 return ret;
3155 /*****************************************************************************
3156 * StartDocPrinterW [WINSPOOL.@]
3158 DWORD WINAPI StartDocPrinterW(HANDLE printer, DWORD level, BYTE *doc_info)
3160 HANDLE handle = get_backend_handle(printer);
3161 DOC_INFO_1W *info = (DOC_INFO_1W *)doc_info;
3163 TRACE("(%p, %ld, %p {%s, %s, %s})\n", printer, level, doc_info,
3164 debugstr_w(info->pDocName), debugstr_w(info->pOutputFile),
3165 debugstr_w(info->pDatatype));
3167 if (!handle)
3169 SetLastError(ERROR_INVALID_HANDLE);
3170 return 0;
3173 return backend->fpStartDocPrinter(handle, level, doc_info);
3176 /*****************************************************************************
3177 * StartPagePrinter [WINSPOOL.@]
3179 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3181 FIXME("(%p): stub\n", hPrinter);
3182 return TRUE;
3185 /*****************************************************************************
3186 * GetFormA [WINSPOOL.@]
3188 BOOL WINAPI GetFormA( HANDLE printer, char *name, DWORD level, BYTE *form, DWORD size, DWORD *needed )
3190 UNICODE_STRING nameW;
3191 const DWORD *string_info = form_string_info( level );
3192 BOOL ret;
3194 if (!string_info) return FALSE;
3196 asciitounicode( &nameW, name );
3198 ret = GetFormW( printer, nameW.Buffer, level, form, size, needed );
3199 if (ret) packed_struct_WtoA( form, string_info );
3201 RtlFreeUnicodeString( &nameW );
3202 return ret;
3205 /*****************************************************************************
3206 * GetFormW [WINSPOOL.@]
3208 BOOL WINAPI GetFormW( HANDLE printer, WCHAR *name, DWORD level, BYTE *form, DWORD size, DWORD *needed )
3210 HANDLE handle = get_backend_handle( printer );
3212 TRACE( "(%p, %s, %ld, %p, %ld, %p)\n", printer, debugstr_w( name ), level, form, size, needed );
3214 if (!handle)
3216 SetLastError( ERROR_INVALID_HANDLE );
3217 return FALSE;
3220 return backend->fpGetForm( handle, name, level, form, size, needed );
3223 /*****************************************************************************
3224 * SetFormA [WINSPOOL.@]
3226 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3227 LPBYTE pForm)
3229 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
3230 return FALSE;
3233 /*****************************************************************************
3234 * SetFormW [WINSPOOL.@]
3236 BOOL WINAPI SetFormW( HANDLE printer, WCHAR *name, DWORD level, BYTE *form )
3238 HANDLE handle = get_backend_handle( printer );
3240 TRACE( "(%p, %s, %ld, %p)\n", printer, debugstr_w( name ), level, form );
3242 if (!handle)
3244 SetLastError( ERROR_INVALID_HANDLE );
3245 return FALSE;
3248 return backend->fpSetForm( handle, name, level, form );
3251 /*****************************************************************************
3252 * ReadPrinter [WINSPOOL.@]
3254 BOOL WINAPI ReadPrinter(HANDLE printer, void *buf, DWORD size, DWORD *bytes_read)
3256 HANDLE handle = get_backend_handle(printer);
3258 TRACE("(%p,%p,%ld,%p)\n", printer, buf, size, bytes_read);
3260 if (!handle)
3262 SetLastError( ERROR_INVALID_HANDLE );
3263 return FALSE;
3266 return backend->fpReadPrinter(handle, buf, size, bytes_read);
3269 /*****************************************************************************
3270 * ResetPrinterA [WINSPOOL.@]
3272 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3274 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3275 return FALSE;
3278 /*****************************************************************************
3279 * ResetPrinterW [WINSPOOL.@]
3281 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3283 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3284 return FALSE;
3287 /*****************************************************************************
3288 * get_filename_from_reg [internal]
3290 * Get ValueName from hkey storing result in out
3291 * when the Value in the registry has only a filename, use driverdir as prefix
3292 * outlen is space left in out
3293 * String is stored either as unicode or ansi
3297 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3298 LPBYTE out, DWORD outlen, LPDWORD needed)
3300 WCHAR filename[MAX_PATH];
3301 DWORD size;
3302 DWORD type;
3303 LONG ret;
3304 LPWSTR buffer = filename;
3305 LPWSTR ptr;
3307 *needed = 0;
3308 size = sizeof(filename);
3309 buffer[0] = '\0';
3310 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3311 if (ret == ERROR_MORE_DATA) {
3312 TRACE("need dynamic buffer: %lu\n", size);
3313 buffer = malloc(size);
3314 if (!buffer) {
3315 /* No Memory is bad */
3316 return FALSE;
3318 buffer[0] = '\0';
3319 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3322 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3323 if (buffer != filename) free(buffer);
3324 return FALSE;
3327 ptr = buffer;
3328 while (ptr) {
3329 /* do we have a full path ? */
3330 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3331 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3333 if (!ret) {
3334 /* we must build the full Path */
3335 *needed += dirlen;
3336 if ((out) && (outlen > dirlen)) {
3337 wcscpy( (WCHAR *)out, driverdir );
3338 out += dirlen;
3339 outlen -= dirlen;
3341 else
3342 out = NULL;
3345 /* write the filename */
3346 size = (wcslen( ptr ) + 1) * sizeof(WCHAR);
3347 if ((out) && (outlen >= size)) {
3348 wcscpy( (WCHAR *)out, ptr );
3349 out += size;
3350 outlen -= size;
3352 else
3353 out = NULL;
3354 *needed += size;
3355 ptr += wcslen( ptr ) + 1;
3356 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3359 if (buffer != filename) free(buffer);
3361 /* write the multisz-termination */
3362 if (type == REG_MULTI_SZ) {
3363 size = sizeof(WCHAR);
3365 *needed += size;
3366 if (out && (outlen >= size)) {
3367 memset (out, 0, size);
3370 return TRUE;
3373 /*****************************************************************************
3374 * WINSPOOL_GetStringFromReg
3376 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3377 * String is stored as unicode.
3379 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3380 DWORD buflen, DWORD *needed)
3382 DWORD sz = buflen, type;
3383 LONG ret;
3385 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3386 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3387 WARN("Got ret = %ld\n", ret);
3388 *needed = 0;
3389 return FALSE;
3391 /* add space for terminating '\0' */
3392 sz += sizeof(WCHAR);
3393 *needed = sz;
3395 if (ptr)
3396 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3398 return TRUE;
3401 /*****************************************************************************
3402 * WINSPOOL_GetDefaultDevMode
3404 * Get a default DevMode values for wineps.
3406 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
3408 if (buflen >= sizeof(DEVMODEW))
3410 DEVMODEW *dm = (DEVMODEW *)ptr;
3412 /* the driver will update registry with real values */
3413 memset(dm, 0, sizeof(*dm));
3414 dm->dmSize = sizeof(*dm);
3415 wcscpy( dm->dmDeviceName, L"wineps.drv" );
3417 *needed = sizeof(DEVMODEW);
3420 /*****************************************************************************
3421 * WINSPOOL_GetDevModeFromReg
3423 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3424 * DevMode is stored either as unicode or ansi.
3426 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3427 LPBYTE ptr,
3428 DWORD buflen, DWORD *needed)
3430 DWORD sz = buflen, type;
3431 LONG ret;
3433 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3434 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3435 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3436 if (sz < sizeof(DEVMODEA))
3438 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
3439 return FALSE;
3441 /* ensures that dmSize is not erratically bogus if registry is invalid */
3442 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3443 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3444 sz += (CCHDEVICENAME + CCHFORMNAME);
3445 if (ptr && (buflen >= sz)) {
3446 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3447 memcpy(ptr, dmW, sz);
3448 heap_free(dmW);
3450 *needed = sz;
3451 return TRUE;
3454 /*********************************************************************
3455 * WINSPOOL_GetPrinter_1
3457 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3459 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3460 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3462 DWORD size, left = cbBuf;
3463 BOOL space = (cbBuf > 0);
3464 LPBYTE ptr = buf;
3466 *pcbNeeded = 0;
3468 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3470 if(space && size <= left) {
3471 pi1->pName = (LPWSTR)ptr;
3472 ptr += size;
3473 left -= size;
3474 } else
3475 space = FALSE;
3476 *pcbNeeded += size;
3479 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3480 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3482 if(space && size <= left) {
3483 pi1->pDescription = (LPWSTR)ptr;
3484 ptr += size;
3485 left -= size;
3486 } else
3487 space = FALSE;
3488 *pcbNeeded += size;
3491 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Description", ptr, left, &size ))
3493 if(space && size <= left) {
3494 pi1->pComment = (LPWSTR)ptr;
3495 ptr += size;
3496 left -= size;
3497 } else
3498 space = FALSE;
3499 *pcbNeeded += size;
3502 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3504 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3505 memset(pi1, 0, sizeof(*pi1));
3507 return space;
3509 /*********************************************************************
3510 * WINSPOOL_GetPrinter_2
3512 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3514 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3515 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3517 DWORD size, left = cbBuf;
3518 BOOL space = (cbBuf > 0);
3519 LPBYTE ptr = buf;
3521 *pcbNeeded = 0;
3523 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3525 if(space && size <= left) {
3526 pi2->pPrinterName = (LPWSTR)ptr;
3527 ptr += size;
3528 left -= size;
3529 } else
3530 space = FALSE;
3531 *pcbNeeded += size;
3533 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Share Name", ptr, left, &size))
3535 if(space && size <= left) {
3536 pi2->pShareName = (LPWSTR)ptr;
3537 ptr += size;
3538 left -= size;
3539 } else
3540 space = FALSE;
3541 *pcbNeeded += size;
3543 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Port", ptr, left, &size ))
3545 if(space && size <= left) {
3546 pi2->pPortName = (LPWSTR)ptr;
3547 ptr += size;
3548 left -= size;
3549 } else
3550 space = FALSE;
3551 *pcbNeeded += size;
3553 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Printer Driver", ptr, left, &size ))
3555 if(space && size <= left) {
3556 pi2->pDriverName = (LPWSTR)ptr;
3557 ptr += size;
3558 left -= size;
3559 } else
3560 space = FALSE;
3561 *pcbNeeded += size;
3563 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Description", ptr, left, &size ))
3565 if(space && size <= left) {
3566 pi2->pComment = (LPWSTR)ptr;
3567 ptr += size;
3568 left -= size;
3569 } else
3570 space = FALSE;
3571 *pcbNeeded += size;
3573 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Location", ptr, left, &size ))
3575 if(space && size <= left) {
3576 pi2->pLocation = (LPWSTR)ptr;
3577 ptr += size;
3578 left -= size;
3579 } else
3580 space = FALSE;
3581 *pcbNeeded += size;
3583 if (WINSPOOL_GetDevModeFromReg( hkeyPrinter, L"Default DevMode", ptr, left, &size ))
3585 if(space && size <= left) {
3586 pi2->pDevMode = (LPDEVMODEW)ptr;
3587 ptr += size;
3588 left -= size;
3589 } else
3590 space = FALSE;
3591 *pcbNeeded += size;
3593 else
3595 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3596 if(space && size <= left) {
3597 pi2->pDevMode = (LPDEVMODEW)ptr;
3598 ptr += size;
3599 left -= size;
3600 } else
3601 space = FALSE;
3602 *pcbNeeded += size;
3604 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Separator File", ptr, left, &size ))
3606 if(space && size <= left) {
3607 pi2->pSepFile = (LPWSTR)ptr;
3608 ptr += size;
3609 left -= size;
3610 } else
3611 space = FALSE;
3612 *pcbNeeded += size;
3614 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Print Processor", ptr, left, &size ))
3616 if(space && size <= left) {
3617 pi2->pPrintProcessor = (LPWSTR)ptr;
3618 ptr += size;
3619 left -= size;
3620 } else
3621 space = FALSE;
3622 *pcbNeeded += size;
3624 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Datatype", ptr, left, &size ))
3626 if(space && size <= left) {
3627 pi2->pDatatype = (LPWSTR)ptr;
3628 ptr += size;
3629 left -= size;
3630 } else
3631 space = FALSE;
3632 *pcbNeeded += size;
3634 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Parameters", ptr, left, &size ))
3636 if(space && size <= left) {
3637 pi2->pParameters = (LPWSTR)ptr;
3638 ptr += size;
3639 left -= size;
3640 } else
3641 space = FALSE;
3642 *pcbNeeded += size;
3644 if (pi2)
3646 pi2->Attributes = get_dword_from_reg( hkeyPrinter, L"Attributes" );
3647 pi2->Priority = get_dword_from_reg( hkeyPrinter, L"Priority" );
3648 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, L"Default Priority" );
3649 pi2->StartTime = get_dword_from_reg( hkeyPrinter, L"StartTime" );
3650 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, L"UntilTime" );
3653 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3654 memset(pi2, 0, sizeof(*pi2));
3656 return space;
3659 /*********************************************************************
3660 * WINSPOOL_GetPrinter_4
3662 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3664 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3665 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3667 DWORD size, left = cbBuf;
3668 BOOL space = (cbBuf > 0);
3669 LPBYTE ptr = buf;
3671 *pcbNeeded = 0;
3673 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3675 if(space && size <= left) {
3676 pi4->pPrinterName = (LPWSTR)ptr;
3677 ptr += size;
3678 left -= size;
3679 } else
3680 space = FALSE;
3681 *pcbNeeded += size;
3683 if(pi4) {
3684 pi4->Attributes = get_dword_from_reg( hkeyPrinter, L"Attributes" );
3687 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3688 memset(pi4, 0, sizeof(*pi4));
3690 return space;
3693 /*********************************************************************
3694 * WINSPOOL_GetPrinter_5
3696 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3698 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3699 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3701 DWORD size, left = cbBuf;
3702 BOOL space = (cbBuf > 0);
3703 LPBYTE ptr = buf;
3705 *pcbNeeded = 0;
3707 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3709 if(space && size <= left) {
3710 pi5->pPrinterName = (LPWSTR)ptr;
3711 ptr += size;
3712 left -= size;
3713 } else
3714 space = FALSE;
3715 *pcbNeeded += size;
3717 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Port", ptr, left, &size ))
3719 if(space && size <= left) {
3720 pi5->pPortName = (LPWSTR)ptr;
3721 ptr += size;
3722 left -= size;
3723 } else
3724 space = FALSE;
3725 *pcbNeeded += size;
3727 if(pi5) {
3728 pi5->Attributes = get_dword_from_reg( hkeyPrinter, L"Attributes" );
3729 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, L"dnsTimeout" );
3730 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, L"txTimeout" );
3733 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3734 memset(pi5, 0, sizeof(*pi5));
3736 return space;
3739 /*********************************************************************
3740 * WINSPOOL_GetPrinter_7
3742 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3744 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3745 DWORD cbBuf, LPDWORD pcbNeeded)
3747 DWORD size, left = cbBuf;
3748 BOOL space = (cbBuf > 0);
3749 LPBYTE ptr = buf;
3751 *pcbNeeded = 0;
3753 if (!WINSPOOL_GetStringFromReg( hkeyPrinter, L"ObjectGUID", ptr, left, &size ))
3755 ptr = NULL;
3756 size = sizeof(pi7->pszObjectGUID);
3758 if (space && size <= left) {
3759 pi7->pszObjectGUID = (LPWSTR)ptr;
3760 ptr += size;
3761 left -= size;
3762 } else
3763 space = FALSE;
3764 *pcbNeeded += size;
3765 if (pi7) {
3766 /* We do not have a Directory Service */
3767 pi7->dwAction = DSPRINT_UNPUBLISH;
3770 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3771 memset(pi7, 0, sizeof(*pi7));
3773 return space;
3776 /*********************************************************************
3777 * WINSPOOL_GetPrinter_9
3779 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3781 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3782 DWORD cbBuf, LPDWORD pcbNeeded)
3784 DWORD size;
3785 BOOL space = (cbBuf > 0);
3787 *pcbNeeded = 0;
3789 if (WINSPOOL_GetDevModeFromReg( hkeyPrinter, L"Default DevMode", buf, cbBuf, &size ))
3791 if(space && size <= cbBuf) {
3792 pi9->pDevMode = (LPDEVMODEW)buf;
3793 } else
3794 space = FALSE;
3795 *pcbNeeded += size;
3797 else
3799 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3800 if(space && size <= cbBuf) {
3801 pi9->pDevMode = (LPDEVMODEW)buf;
3802 } else
3803 space = FALSE;
3804 *pcbNeeded += size;
3807 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3808 memset(pi9, 0, sizeof(*pi9));
3810 return space;
3813 /*****************************************************************************
3814 * GetPrinterW [WINSPOOL.@]
3816 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3817 DWORD cbBuf, LPDWORD pcbNeeded)
3819 DWORD size, needed = 0, err;
3820 LPBYTE ptr = NULL;
3821 HKEY hkeyPrinter;
3822 BOOL ret;
3824 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3826 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
3827 if (err)
3829 SetLastError( err );
3830 return FALSE;
3833 switch(Level) {
3834 case 1:
3836 PRINTER_INFO_1W *pi1 = (PRINTER_INFO_1W *)pPrinter;
3838 size = sizeof(PRINTER_INFO_1W);
3839 if (size <= cbBuf) {
3840 ptr = pPrinter + size;
3841 cbBuf -= size;
3842 memset(pPrinter, 0, size);
3843 } else {
3844 pi1 = NULL;
3845 cbBuf = 0;
3847 ret = WINSPOOL_GetPrinter_1(hkeyPrinter, pi1, ptr, cbBuf, &needed);
3848 needed += size;
3849 break;
3852 case 2:
3854 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3856 size = sizeof(PRINTER_INFO_2W);
3857 if(size <= cbBuf) {
3858 ptr = pPrinter + size;
3859 cbBuf -= size;
3860 memset(pPrinter, 0, size);
3861 } else {
3862 pi2 = NULL;
3863 cbBuf = 0;
3865 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3866 needed += size;
3867 break;
3870 case 4:
3872 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3874 size = sizeof(PRINTER_INFO_4W);
3875 if(size <= cbBuf) {
3876 ptr = pPrinter + size;
3877 cbBuf -= size;
3878 memset(pPrinter, 0, size);
3879 } else {
3880 pi4 = NULL;
3881 cbBuf = 0;
3883 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3884 needed += size;
3885 break;
3889 case 5:
3891 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3893 size = sizeof(PRINTER_INFO_5W);
3894 if(size <= cbBuf) {
3895 ptr = pPrinter + size;
3896 cbBuf -= size;
3897 memset(pPrinter, 0, size);
3898 } else {
3899 pi5 = NULL;
3900 cbBuf = 0;
3903 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3904 needed += size;
3905 break;
3909 case 6:
3911 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3913 size = sizeof(PRINTER_INFO_6);
3914 if (size <= cbBuf) {
3915 /* FIXME: We do not update the status yet */
3916 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, L"Status" );
3917 ret = TRUE;
3918 } else {
3919 ret = FALSE;
3922 needed += size;
3923 break;
3926 case 7:
3928 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3930 size = sizeof(PRINTER_INFO_7W);
3931 if (size <= cbBuf) {
3932 ptr = pPrinter + size;
3933 cbBuf -= size;
3934 memset(pPrinter, 0, size);
3935 } else {
3936 pi7 = NULL;
3937 cbBuf = 0;
3940 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3941 needed += size;
3942 break;
3946 case 8:
3947 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
3948 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3949 /* fall through */
3950 case 9:
3952 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3954 size = sizeof(PRINTER_INFO_9W);
3955 if(size <= cbBuf) {
3956 ptr = pPrinter + size;
3957 cbBuf -= size;
3958 memset(pPrinter, 0, size);
3959 } else {
3960 pi9 = NULL;
3961 cbBuf = 0;
3964 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3965 needed += size;
3966 break;
3970 default:
3971 FIXME("Unimplemented level %ld\n", Level);
3972 SetLastError(ERROR_INVALID_LEVEL);
3973 RegCloseKey(hkeyPrinter);
3974 return FALSE;
3977 RegCloseKey(hkeyPrinter);
3979 TRACE("returning %d needed = %ld\n", ret, needed);
3980 if(pcbNeeded) *pcbNeeded = needed;
3981 if(!ret)
3982 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3983 return ret;
3986 /*****************************************************************************
3987 * GetPrinterA [WINSPOOL.@]
3989 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3990 DWORD cbBuf, LPDWORD pcbNeeded)
3992 BOOL ret;
3993 LPBYTE buf = NULL;
3995 if (cbBuf)
3996 buf = malloc(cbBuf);
3998 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3999 if (ret)
4000 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4001 free(buf);
4003 return ret;
4006 /*****************************************************************************
4007 * WINSPOOL_EnumPrintersW
4009 * Implementation of EnumPrintersW
4011 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4012 DWORD dwLevel, LPBYTE lpbPrinters,
4013 DWORD cbBuf, LPDWORD lpdwNeeded,
4014 LPDWORD lpdwReturned)
4017 HKEY printers_key, hkeyPrinter;
4018 WCHAR PrinterName[255];
4019 DWORD needed = 0, number = 0;
4020 DWORD used, i, left;
4021 PBYTE pi, buf;
4023 if(lpbPrinters)
4024 memset(lpbPrinters, 0, cbBuf);
4025 if(lpdwReturned)
4026 *lpdwReturned = 0;
4027 if(lpdwNeeded)
4028 *lpdwNeeded = 0;
4030 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4031 if(dwType == PRINTER_ENUM_DEFAULT)
4032 return TRUE;
4034 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4035 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4036 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4037 if (!dwType) {
4038 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4039 return TRUE;
4044 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4045 FIXME("dwType = %08lx\n", dwType);
4046 SetLastError(ERROR_INVALID_FLAGS);
4047 return FALSE;
4050 if (create_printers_reg_key( system_printers_key, &printers_key ))
4052 ERR("Can't create Printers key\n");
4053 return FALSE;
4056 if (RegQueryInfoKeyA( printers_key, NULL, NULL, NULL, &number, NULL, NULL, NULL, NULL, NULL, NULL, NULL ))
4058 RegCloseKey( printers_key );
4059 ERR("Can't query Printers key\n");
4060 return FALSE;
4062 TRACE("Found %ld printers\n", number);
4064 switch(dwLevel) {
4065 case 1:
4066 used = number * sizeof(PRINTER_INFO_1W);
4067 break;
4068 case 2:
4069 used = number * sizeof(PRINTER_INFO_2W);
4070 break;
4071 case 4:
4072 used = number * sizeof(PRINTER_INFO_4W);
4073 break;
4074 case 5:
4075 used = number * sizeof(PRINTER_INFO_5W);
4076 break;
4078 default:
4079 SetLastError(ERROR_INVALID_LEVEL);
4080 RegCloseKey( printers_key );
4081 return FALSE;
4083 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4085 for(i = 0; i < number; i++) {
4086 if (RegEnumKeyW( printers_key, i, PrinterName, ARRAY_SIZE(PrinterName) ))
4088 ERR("Can't enum key number %ld\n", i);
4089 RegCloseKey( printers_key );
4090 return FALSE;
4092 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
4093 if (RegOpenKeyW( printers_key, PrinterName, &hkeyPrinter ))
4095 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4096 RegCloseKey( printers_key );
4097 return FALSE;
4100 if(cbBuf > used) {
4101 buf = lpbPrinters + used;
4102 left = cbBuf - used;
4103 } else {
4104 buf = NULL;
4105 left = 0;
4108 switch(dwLevel) {
4109 case 1:
4110 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4111 left, &needed);
4112 used += needed;
4113 if(pi) pi += sizeof(PRINTER_INFO_1W);
4114 break;
4115 case 2:
4116 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4117 left, &needed);
4118 used += needed;
4119 if(pi) pi += sizeof(PRINTER_INFO_2W);
4120 break;
4121 case 4:
4122 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4123 left, &needed);
4124 used += needed;
4125 if(pi) pi += sizeof(PRINTER_INFO_4W);
4126 break;
4127 case 5:
4128 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4129 left, &needed);
4130 used += needed;
4131 if(pi) pi += sizeof(PRINTER_INFO_5W);
4132 break;
4133 default:
4134 ERR("Shouldn't be here!\n");
4135 RegCloseKey(hkeyPrinter);
4136 RegCloseKey( printers_key );
4137 return FALSE;
4139 RegCloseKey(hkeyPrinter);
4141 RegCloseKey( printers_key );
4143 if(lpdwNeeded)
4144 *lpdwNeeded = used;
4146 if(used > cbBuf) {
4147 if(lpbPrinters)
4148 memset(lpbPrinters, 0, cbBuf);
4149 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4150 return FALSE;
4152 if(lpdwReturned)
4153 *lpdwReturned = number;
4154 SetLastError(ERROR_SUCCESS);
4155 return TRUE;
4159 /******************************************************************
4160 * EnumPrintersW [WINSPOOL.@]
4162 * Enumerates the available printers, print servers and print
4163 * providers, depending on the specified flags, name and level.
4165 * RETURNS:
4167 * If level is set to 1:
4168 * Returns an array of PRINTER_INFO_1 data structures in the
4169 * lpbPrinters buffer.
4171 * If level is set to 2:
4172 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4173 * Returns an array of PRINTER_INFO_2 data structures in the
4174 * lpbPrinters buffer. Note that according to MSDN also an
4175 * OpenPrinter should be performed on every remote printer.
4177 * If level is set to 4 (officially WinNT only):
4178 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4179 * Fast: Only the registry is queried to retrieve printer names,
4180 * no connection to the driver is made.
4181 * Returns an array of PRINTER_INFO_4 data structures in the
4182 * lpbPrinters buffer.
4184 * If level is set to 5 (officially WinNT4/Win9x only):
4185 * Fast: Only the registry is queried to retrieve printer names,
4186 * no connection to the driver is made.
4187 * Returns an array of PRINTER_INFO_5 data structures in the
4188 * lpbPrinters buffer.
4190 * If level set to 3 or 6+:
4191 * returns zero (failure!)
4193 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4194 * for information.
4196 * BUGS:
4197 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4198 * - Only levels 2, 4 and 5 are implemented at the moment.
4199 * - 16-bit printer drivers are not enumerated.
4200 * - Returned amount of bytes used/needed does not match the real Windoze
4201 * implementation (as in this implementation, all strings are part
4202 * of the buffer, whereas Win32 keeps them somewhere else)
4203 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4205 * NOTE:
4206 * - In a regular Wine installation, no registry settings for printers
4207 * exist, which makes this function return an empty list.
4209 BOOL WINAPI EnumPrintersW(
4210 DWORD dwType, /* [in] Types of print objects to enumerate */
4211 LPWSTR lpszName, /* [in] name of objects to enumerate */
4212 DWORD dwLevel, /* [in] type of printer info structure */
4213 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4214 DWORD cbBuf, /* [in] max size of buffer in bytes */
4215 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4216 LPDWORD lpdwReturned /* [out] number of entries returned */
4219 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4220 lpdwNeeded, lpdwReturned);
4223 /******************************************************************
4224 * EnumPrintersA [WINSPOOL.@]
4226 * See EnumPrintersW
4229 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4230 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4232 BOOL ret;
4233 UNICODE_STRING pNameU;
4234 LPWSTR pNameW;
4235 LPBYTE pPrintersW;
4237 TRACE("(0x%lx, %s, %lu, %p, %ld, %p, %p)\n", flags, debugstr_a(pName), level,
4238 pPrinters, cbBuf, pcbNeeded, pcReturned);
4240 pNameW = asciitounicode(&pNameU, pName);
4242 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4243 MS Office need this */
4244 pPrintersW = (pPrinters && cbBuf) ? malloc(cbBuf) : NULL;
4246 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4248 RtlFreeUnicodeString(&pNameU);
4249 if (ret) {
4250 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4252 free(pPrintersW);
4253 return ret;
4256 /*****************************************************************************
4257 * WINSPOOL_GetDriverInfoFromReg [internal]
4259 * Enters the information from the registry into the DRIVER_INFO struct
4261 * RETURNS
4262 * zero if the printer driver does not exist in the registry
4263 * (only if Level > 1) otherwise nonzero
4265 static BOOL WINSPOOL_GetDriverInfoFromReg(
4266 HKEY hkeyDrivers,
4267 LPWSTR DriverName,
4268 const printenv_t * env,
4269 DWORD Level,
4270 LPBYTE ptr, /* DRIVER_INFO */
4271 LPBYTE pDriverStrings, /* strings buffer */
4272 DWORD cbBuf, /* size of string buffer */
4273 LPDWORD pcbNeeded) /* space needed for str. */
4275 DWORD size, tmp;
4276 HKEY hkeyDriver;
4277 WCHAR driverdir[MAX_PATH];
4278 DWORD dirlen;
4279 LPBYTE strPtr = pDriverStrings;
4280 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4282 TRACE("(%p, %s, %p, %ld, %p, %p, %ld)\n", hkeyDrivers,
4283 debugstr_w(DriverName), env,
4284 Level, di, pDriverStrings, cbBuf);
4286 if (di) ZeroMemory(di, di_sizeof[Level]);
4288 *pcbNeeded = (wcslen( DriverName ) + 1) * sizeof(WCHAR);
4289 if (*pcbNeeded <= cbBuf)
4290 wcscpy( (WCHAR *)strPtr, DriverName );
4292 /* pName for level 1 has a different offset! */
4293 if (Level == 1) {
4294 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4295 return TRUE;
4298 /* .cVersion and .pName for level > 1 */
4299 if (di) {
4300 di->cVersion = env->driverversion;
4301 di->pName = (LPWSTR) strPtr;
4302 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4305 /* Reserve Space for "\\3\\" + \0 */
4306 size = sizeof(driverdir) - 4 * sizeof(WCHAR);
4307 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4308 /* Should never Fail */
4309 return FALSE;
4311 wcscat( driverdir, env->versionsubdir );
4312 wcscat( driverdir, L"\\" );
4314 /* dirlen must not include the terminating zero */
4315 dirlen = wcslen( driverdir ) * sizeof(WCHAR);
4317 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4318 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4319 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4320 return FALSE;
4323 /* pEnvironment */
4324 size = (wcslen( env->envname ) + 1) * sizeof(WCHAR);
4326 *pcbNeeded += size;
4327 if (*pcbNeeded <= cbBuf) {
4328 wcscpy( (WCHAR *)strPtr, env->envname );
4329 if (di) di->pEnvironment = (LPWSTR)strPtr;
4330 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4333 /* .pDriverPath is the Graphics rendering engine.
4334 The full Path is required to avoid a crash in some apps */
4335 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Driver", strPtr, 0, &size ))
4337 *pcbNeeded += size;
4338 if (*pcbNeeded <= cbBuf)
4339 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Driver", strPtr, size, &tmp );
4341 if (di) di->pDriverPath = (LPWSTR)strPtr;
4342 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4345 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4346 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Data File", strPtr, 0, &size ))
4348 *pcbNeeded += size;
4349 if (*pcbNeeded <= cbBuf)
4350 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Data File", strPtr, size, &size );
4352 if (di) di->pDataFile = (LPWSTR)strPtr;
4353 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4356 /* .pConfigFile is the Driver user Interface */
4357 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Configuration File", strPtr, 0, &size ))
4359 *pcbNeeded += size;
4360 if (*pcbNeeded <= cbBuf)
4361 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Configuration File", strPtr, size, &size );
4363 if (di) di->pConfigFile = (LPWSTR)strPtr;
4364 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4367 if (Level == 2 ) {
4368 RegCloseKey(hkeyDriver);
4369 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
4370 return TRUE;
4373 if (Level == 5 ) {
4374 RegCloseKey(hkeyDriver);
4375 FIXME("level 5: incomplete\n");
4376 return TRUE;
4379 /* .pHelpFile */
4380 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Help File", strPtr, 0, &size ))
4382 *pcbNeeded += size;
4383 if (*pcbNeeded <= cbBuf)
4384 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Help File", strPtr, size, &size );
4386 if (di) di->pHelpFile = (LPWSTR)strPtr;
4387 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4390 /* .pDependentFiles */
4391 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Dependent Files", strPtr, 0, &size ))
4393 *pcbNeeded += size;
4394 if (*pcbNeeded <= cbBuf)
4395 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Dependent Files", strPtr, size, &size );
4397 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4398 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4400 else if (GetVersion() & 0x80000000) {
4401 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4402 size = 2 * sizeof(WCHAR);
4403 *pcbNeeded += size;
4404 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4406 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4407 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4410 /* .pMonitorName is the optional Language Monitor */
4411 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Monitor", strPtr, 0, &size ))
4413 *pcbNeeded += size;
4414 if (*pcbNeeded <= cbBuf)
4415 WINSPOOL_GetStringFromReg( hkeyDriver, L"Monitor", strPtr, size, &size );
4417 if (di) di->pMonitorName = (LPWSTR)strPtr;
4418 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4421 /* .pDefaultDataType */
4422 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Datatype", strPtr, 0, &size ))
4424 *pcbNeeded += size;
4425 if(*pcbNeeded <= cbBuf)
4426 WINSPOOL_GetStringFromReg( hkeyDriver, L"Datatype", strPtr, size, &size );
4428 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4429 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4432 if (Level == 3 ) {
4433 RegCloseKey(hkeyDriver);
4434 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
4435 return TRUE;
4438 /* .pszzPreviousNames */
4439 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Previous Names", strPtr, 0, &size ))
4441 *pcbNeeded += size;
4442 if(*pcbNeeded <= cbBuf)
4443 WINSPOOL_GetStringFromReg( hkeyDriver, L"Previous Names", strPtr, size, &size );
4445 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4446 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4449 if (Level == 4 ) {
4450 RegCloseKey(hkeyDriver);
4451 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
4452 return TRUE;
4455 /* support is missing, but not important enough for a FIXME */
4456 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4458 /* .pszMfgName */
4459 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Manufacturer", strPtr, 0, &size ))
4461 *pcbNeeded += size;
4462 if(*pcbNeeded <= cbBuf)
4463 WINSPOOL_GetStringFromReg( hkeyDriver, L"Manufacturer", strPtr, size, &size );
4465 if (di) di->pszMfgName = (LPWSTR)strPtr;
4466 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4469 /* .pszOEMUrl */
4470 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"OEM Url", strPtr, 0, &size ))
4472 *pcbNeeded += size;
4473 if(*pcbNeeded <= cbBuf)
4474 WINSPOOL_GetStringFromReg( hkeyDriver, L"OEM Url", strPtr, size, &size );
4476 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4477 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4480 /* .pszHardwareID */
4481 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"HardwareID", strPtr, 0, &size ))
4483 *pcbNeeded += size;
4484 if(*pcbNeeded <= cbBuf)
4485 WINSPOOL_GetStringFromReg( hkeyDriver, L"HardwareID", strPtr, size, &size );
4487 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4488 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4491 /* .pszProvider */
4492 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Provider", strPtr, 0, &size ))
4494 *pcbNeeded += size;
4495 if(*pcbNeeded <= cbBuf)
4496 WINSPOOL_GetStringFromReg( hkeyDriver, L"Provider", strPtr, size, &size );
4498 if (di) di->pszProvider = (LPWSTR)strPtr;
4499 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4502 if (Level == 6 ) {
4503 RegCloseKey(hkeyDriver);
4504 return TRUE;
4507 /* support is missing, but not important enough for a FIXME */
4508 TRACE("level 8: incomplete\n");
4510 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
4511 RegCloseKey(hkeyDriver);
4512 return TRUE;
4515 /*****************************************************************************
4516 * GetPrinterDriverW [WINSPOOL.@]
4518 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4519 DWORD Level, LPBYTE pDriverInfo,
4520 DWORD cbBuf, LPDWORD pcbNeeded)
4522 LPCWSTR name;
4523 WCHAR DriverName[100];
4524 DWORD ret, type, size, needed = 0;
4525 LPBYTE ptr = NULL;
4526 HKEY hkeyPrinter, hkeyDrivers;
4527 const printenv_t * env;
4529 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
4530 Level,pDriverInfo,cbBuf, pcbNeeded);
4532 if (cbBuf > 0)
4533 ZeroMemory(pDriverInfo, cbBuf);
4535 if (!(name = get_opened_printer_name(hPrinter))) {
4536 SetLastError(ERROR_INVALID_HANDLE);
4537 return FALSE;
4540 if (Level < 1 || Level == 7 || Level > 8) {
4541 SetLastError(ERROR_INVALID_LEVEL);
4542 return FALSE;
4545 env = validate_envW(pEnvironment);
4546 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4548 ret = open_printer_reg_key( name, &hkeyPrinter );
4549 if (ret)
4551 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4552 SetLastError( ret );
4553 return FALSE;
4556 size = sizeof(DriverName);
4557 DriverName[0] = 0;
4558 ret = RegQueryValueExW( hkeyPrinter, L"Printer Driver", 0, &type, (BYTE *)DriverName, &size );
4559 RegCloseKey(hkeyPrinter);
4560 if(ret != ERROR_SUCCESS) {
4561 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4562 return FALSE;
4565 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4566 if(!hkeyDrivers) {
4567 ERR("Can't create Drivers key\n");
4568 return FALSE;
4571 size = di_sizeof[Level];
4572 if ((size <= cbBuf) && pDriverInfo)
4573 ptr = pDriverInfo + size;
4575 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4576 env, Level, pDriverInfo, ptr,
4577 (cbBuf < size) ? 0 : cbBuf - size,
4578 &needed)) {
4579 RegCloseKey(hkeyDrivers);
4580 return FALSE;
4583 RegCloseKey(hkeyDrivers);
4585 if(pcbNeeded) *pcbNeeded = size + needed;
4586 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
4587 if(cbBuf >= size + needed) return TRUE;
4588 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4589 return FALSE;
4592 /*****************************************************************************
4593 * GetPrinterDriverA [WINSPOOL.@]
4595 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4596 DWORD Level, LPBYTE pDriverInfo,
4597 DWORD cbBuf, LPDWORD pcbNeeded)
4599 BOOL ret;
4600 UNICODE_STRING pEnvW;
4601 PWSTR pwstrEnvW;
4602 LPBYTE buf = NULL;
4604 if (cbBuf)
4606 ZeroMemory(pDriverInfo, cbBuf);
4607 buf = malloc(cbBuf);
4610 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4611 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4612 cbBuf, pcbNeeded);
4613 if (ret)
4614 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4616 free(buf);
4618 RtlFreeUnicodeString(&pEnvW);
4619 return ret;
4622 /*****************************************************************************
4623 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4625 * Return the PATH for the Printer-Drivers (UNICODE)
4627 * PARAMS
4628 * pName [I] Servername (NT only) or NULL (local Computer)
4629 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4630 * Level [I] Structure-Level (must be 1)
4631 * pDriverDirectory [O] PTR to Buffer that receives the Result
4632 * cbBuf [I] Size of Buffer at pDriverDirectory
4633 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4634 * required for pDriverDirectory
4636 * RETURNS
4637 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4638 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4639 * if cbBuf is too small
4641 * Native Values returned in pDriverDirectory on Success:
4642 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4643 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4644 *| win9x(Windows 4.0): "%winsysdir%"
4646 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4648 * FIXME
4649 *- Only NULL or "" is supported for pName
4652 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4653 DWORD Level, LPBYTE pDriverDirectory,
4654 DWORD cbBuf, LPDWORD pcbNeeded)
4656 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
4657 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4659 if ((backend == NULL) && !load_backend()) return FALSE;
4661 if (Level != 1) {
4662 /* (Level != 1) is ignored in win9x */
4663 SetLastError(ERROR_INVALID_LEVEL);
4664 return FALSE;
4666 if (pcbNeeded == NULL) {
4667 /* (pcbNeeded == NULL) is ignored in win9x */
4668 SetLastError(RPC_X_NULL_REF_POINTER);
4669 return FALSE;
4672 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4673 pDriverDirectory, cbBuf, pcbNeeded);
4678 /*****************************************************************************
4679 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4681 * Return the PATH for the Printer-Drivers (ANSI)
4683 * See GetPrinterDriverDirectoryW.
4685 * NOTES
4686 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4689 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4690 DWORD Level, LPBYTE pDriverDirectory,
4691 DWORD cbBuf, LPDWORD pcbNeeded)
4693 UNICODE_STRING nameW, environmentW;
4694 BOOL ret;
4695 DWORD pcbNeededW;
4696 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4697 WCHAR *driverDirectoryW = NULL;
4699 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
4700 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4702 if (len) driverDirectoryW = malloc( len );
4704 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4705 else nameW.Buffer = NULL;
4706 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4707 else environmentW.Buffer = NULL;
4709 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4710 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4711 if (ret) {
4712 DWORD needed;
4713 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4714 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4715 if(pcbNeeded)
4716 *pcbNeeded = needed;
4717 ret = needed <= cbBuf;
4718 } else
4719 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4721 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4723 free( driverDirectoryW );
4724 RtlFreeUnicodeString(&environmentW);
4725 RtlFreeUnicodeString(&nameW);
4727 return ret;
4730 /*****************************************************************************
4731 * AddPrinterDriverA [WINSPOOL.@]
4733 * See AddPrinterDriverW.
4736 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4738 TRACE("(%s, %ld, %p)\n", debugstr_a(pName), level, pDriverInfo);
4739 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4742 /******************************************************************************
4743 * AddPrinterDriverW (WINSPOOL.@)
4745 * Install a Printer Driver
4747 * PARAMS
4748 * pName [I] Servername or NULL (local Computer)
4749 * level [I] Level for the supplied DRIVER_INFO_*W struct
4750 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4752 * RESULTS
4753 * Success: TRUE
4754 * Failure: FALSE
4757 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4759 TRACE("(%s, %ld, %p)\n", debugstr_w(pName), level, pDriverInfo);
4760 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4763 /*****************************************************************************
4764 * AddPrintProcessorA [WINSPOOL.@]
4766 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4767 LPSTR pPrintProcessorName)
4769 UNICODE_STRING NameW, EnvW, PathW, ProcessorW;
4770 BOOL ret;
4772 TRACE("(%s,%s,%s,%s)\n", debugstr_a(pName), debugstr_a(pEnvironment),
4773 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4775 asciitounicode(&NameW, pName);
4776 asciitounicode(&EnvW, pEnvironment);
4777 asciitounicode(&PathW, pPathName);
4778 asciitounicode(&ProcessorW, pPrintProcessorName);
4780 ret = AddPrintProcessorW(NameW.Buffer, EnvW.Buffer, PathW.Buffer, ProcessorW.Buffer);
4782 RtlFreeUnicodeString(&ProcessorW);
4783 RtlFreeUnicodeString(&PathW);
4784 RtlFreeUnicodeString(&EnvW);
4785 RtlFreeUnicodeString(&NameW);
4787 return ret;
4790 /*****************************************************************************
4791 * AddPrintProcessorW [WINSPOOL.@]
4793 BOOL WINAPI AddPrintProcessorW(WCHAR *name, WCHAR *env, WCHAR *path, WCHAR *print_proc)
4795 TRACE("(%s,%s,%s,%s)\n", debugstr_w(name), debugstr_w(env),
4796 debugstr_w(path), debugstr_w(print_proc));
4798 if (!path || !print_proc)
4800 SetLastError(ERROR_INVALID_PARAMETER);
4801 return FALSE;
4804 if ((backend == NULL) && !load_backend()) return FALSE;
4805 return backend->fpAddPrintProcessor(name, env, path, print_proc);
4808 /*****************************************************************************
4809 * AddPrintProvidorA [WINSPOOL.@]
4811 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4813 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4814 return FALSE;
4817 /*****************************************************************************
4818 * AddPrintProvidorW [WINSPOOL.@]
4820 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4822 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4823 return FALSE;
4826 /*****************************************************************************
4827 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4829 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4830 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4832 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4833 pDevModeOutput, pDevModeInput);
4834 return 0;
4837 /*****************************************************************************
4838 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4840 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4841 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4843 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4844 pDevModeOutput, pDevModeInput);
4845 return 0;
4848 /*****************************************************************************
4849 * PrinterProperties [WINSPOOL.@]
4851 * Displays a dialog to set the properties of the printer.
4853 * RETURNS
4854 * nonzero on success or zero on failure
4856 * BUGS
4857 * implemented as stub only
4859 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4860 HANDLE hPrinter /* [in] handle to printer object */
4862 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4863 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4864 return FALSE;
4867 /*****************************************************************************
4868 * EnumJobsA [WINSPOOL.@]
4871 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4872 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4873 LPDWORD pcReturned)
4875 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4876 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4878 if(pcbNeeded) *pcbNeeded = 0;
4879 if(pcReturned) *pcReturned = 0;
4880 return FALSE;
4884 /*****************************************************************************
4885 * EnumJobsW [WINSPOOL.@]
4888 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4889 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4890 LPDWORD pcReturned)
4892 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4893 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4895 if(pcbNeeded) *pcbNeeded = 0;
4896 if(pcReturned) *pcReturned = 0;
4897 return FALSE;
4900 /*****************************************************************************
4901 * WINSPOOL_EnumPrinterDrivers [internal]
4903 * Delivers information about all printer drivers installed on the
4904 * localhost or a given server
4906 * RETURNS
4907 * nonzero on success or zero on failure. If the buffer for the returned
4908 * information is too small the function will return an error
4910 * BUGS
4911 * - only implemented for localhost, foreign hosts will return an error
4913 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4914 DWORD Level, LPBYTE pDriverInfo,
4915 DWORD driver_index,
4916 DWORD cbBuf, LPDWORD pcbNeeded,
4917 LPDWORD pcFound, DWORD data_offset)
4919 { HKEY hkeyDrivers;
4920 DWORD i, size = 0;
4921 const printenv_t * env;
4923 TRACE("%s,%s,%ld,%p,%ld,%ld,%ld\n",
4924 debugstr_w(pName), debugstr_w(pEnvironment),
4925 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4927 env = validate_envW(pEnvironment);
4928 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4930 *pcFound = 0;
4932 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4933 if(!hkeyDrivers) {
4934 ERR("Can't open Drivers key\n");
4935 return FALSE;
4938 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4939 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4940 RegCloseKey(hkeyDrivers);
4941 ERR("Can't query Drivers key\n");
4942 return FALSE;
4944 TRACE("Found %ld Drivers\n", *pcFound);
4946 /* get size of single struct
4947 * unicode and ascii structure have the same size
4949 size = di_sizeof[Level];
4951 if (data_offset == 0)
4952 data_offset = size * (*pcFound);
4953 *pcbNeeded = data_offset;
4955 for( i = 0; i < *pcFound; i++) {
4956 WCHAR DriverNameW[255];
4957 PBYTE table_ptr = NULL;
4958 PBYTE data_ptr = NULL;
4959 DWORD needed = 0;
4961 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, ARRAY_SIZE(DriverNameW)) != ERROR_SUCCESS) {
4962 ERR("Can't enum key number %ld\n", i);
4963 RegCloseKey(hkeyDrivers);
4964 return FALSE;
4967 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4968 table_ptr = pDriverInfo + (driver_index + i) * size;
4969 if (pDriverInfo && *pcbNeeded <= cbBuf)
4970 data_ptr = pDriverInfo + *pcbNeeded;
4972 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4973 env, Level, table_ptr, data_ptr,
4974 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4975 &needed)) {
4976 RegCloseKey(hkeyDrivers);
4977 return FALSE;
4980 *pcbNeeded += needed;
4983 RegCloseKey(hkeyDrivers);
4985 if(cbBuf < *pcbNeeded){
4986 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4987 return FALSE;
4990 return TRUE;
4993 /*****************************************************************************
4994 * EnumPrinterDriversW [WINSPOOL.@]
4996 * see function EnumPrinterDrivers for RETURNS, BUGS
4998 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4999 LPBYTE pDriverInfo, DWORD cbBuf,
5000 LPDWORD pcbNeeded, LPDWORD pcReturned)
5002 BOOL ret;
5003 DWORD found;
5005 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5007 SetLastError(RPC_X_NULL_REF_POINTER);
5008 return FALSE;
5011 /* check for local drivers */
5012 if((pName) && (pName[0])) {
5013 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5014 SetLastError(ERROR_ACCESS_DENIED);
5015 return FALSE;
5018 /* check input parameter */
5019 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5020 SetLastError(ERROR_INVALID_LEVEL);
5021 return FALSE;
5024 if(pDriverInfo && cbBuf > 0)
5025 memset( pDriverInfo, 0, cbBuf);
5027 /* Exception: pull all printers */
5028 if (pEnvironment && !wcscmp( pEnvironment, L"all" ))
5030 DWORD i, needed, bufsize = cbBuf;
5031 DWORD total_found = 0;
5032 DWORD data_offset;
5034 /* Precompute the overall total; we need this to know
5035 where pointers end and data begins (i.e. data_offset) */
5036 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5038 needed = found = 0;
5039 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5040 NULL, 0, 0, &needed, &found, 0);
5041 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5042 total_found += found;
5045 data_offset = di_sizeof[Level] * total_found;
5047 *pcReturned = 0;
5048 *pcbNeeded = 0;
5049 total_found = 0;
5050 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5052 needed = found = 0;
5053 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5054 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5055 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5056 else if (ret)
5057 *pcReturned += found;
5058 *pcbNeeded = needed;
5059 data_offset = needed;
5060 total_found += found;
5062 return ret;
5065 /* Normal behavior */
5066 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5067 0, cbBuf, pcbNeeded, &found, 0);
5068 if (ret)
5069 *pcReturned = found;
5071 return ret;
5074 /*****************************************************************************
5075 * EnumPrinterDriversA [WINSPOOL.@]
5077 * see function EnumPrinterDrivers for RETURNS, BUGS
5079 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5080 LPBYTE pDriverInfo, DWORD cbBuf,
5081 LPDWORD pcbNeeded, LPDWORD pcReturned)
5083 BOOL ret;
5084 UNICODE_STRING pNameW, pEnvironmentW;
5085 PWSTR pwstrNameW, pwstrEnvironmentW;
5086 LPBYTE buf = NULL;
5088 if (cbBuf)
5089 buf = malloc(cbBuf);
5091 pwstrNameW = asciitounicode(&pNameW, pName);
5092 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5094 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5095 buf, cbBuf, pcbNeeded, pcReturned);
5096 if (ret)
5097 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5099 free(buf);
5101 RtlFreeUnicodeString(&pNameW);
5102 RtlFreeUnicodeString(&pEnvironmentW);
5104 return ret;
5107 /******************************************************************************
5108 * EnumPortsA (WINSPOOL.@)
5110 * See EnumPortsW.
5113 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5114 LPDWORD pcbNeeded, LPDWORD pcReturned)
5116 BOOL res;
5117 LPBYTE bufferW = NULL;
5118 LPWSTR nameW = NULL;
5119 DWORD needed = 0;
5120 DWORD numentries = 0;
5121 INT len;
5123 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5124 cbBuf, pcbNeeded, pcReturned);
5126 /* convert servername to unicode */
5127 if (pName) {
5128 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5129 nameW = malloc(len * sizeof(WCHAR));
5130 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5132 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5133 needed = cbBuf * sizeof(WCHAR);
5134 if (needed) bufferW = malloc(needed);
5135 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5137 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5138 if (pcbNeeded) needed = *pcbNeeded;
5139 /* HeapReAlloc return NULL, when bufferW was NULL */
5140 bufferW = (bufferW) ? realloc(bufferW, needed) : malloc(needed);
5142 /* Try again with the large Buffer */
5143 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5145 needed = pcbNeeded ? *pcbNeeded : 0;
5146 numentries = pcReturned ? *pcReturned : 0;
5149 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5150 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5152 if (res) {
5153 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5154 DWORD entrysize = 0;
5155 DWORD index;
5156 LPSTR ptr;
5157 LPPORT_INFO_2W pi2w;
5158 LPPORT_INFO_2A pi2a;
5160 needed = 0;
5161 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5163 /* First pass: calculate the size for all Entries */
5164 pi2w = (LPPORT_INFO_2W) bufferW;
5165 pi2a = (LPPORT_INFO_2A) pPorts;
5166 index = 0;
5167 while (index < numentries) {
5168 index++;
5169 needed += entrysize; /* PORT_INFO_?A */
5170 TRACE("%p: parsing #%ld (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5172 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5173 NULL, 0, NULL, NULL);
5174 if (Level > 1) {
5175 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5176 NULL, 0, NULL, NULL);
5177 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5178 NULL, 0, NULL, NULL);
5180 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5181 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5182 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5185 /* check for errors and quit on failure */
5186 if (cbBuf < needed) {
5187 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5188 res = FALSE;
5189 goto cleanup;
5191 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5192 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5193 cbBuf -= len ; /* free Bytes in the user-Buffer */
5194 pi2w = (LPPORT_INFO_2W) bufferW;
5195 pi2a = (LPPORT_INFO_2A) pPorts;
5196 index = 0;
5197 /* Second Pass: Fill the User Buffer (if we have one) */
5198 while ((index < numentries) && pPorts) {
5199 index++;
5200 TRACE("%p: writing PORT_INFO_%ldA #%ld\n", pi2a, Level, index);
5201 pi2a->pPortName = ptr;
5202 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5203 ptr, cbBuf , NULL, NULL);
5204 ptr += len;
5205 cbBuf -= len;
5206 if (Level > 1) {
5207 pi2a->pMonitorName = ptr;
5208 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5209 ptr, cbBuf, NULL, NULL);
5210 ptr += len;
5211 cbBuf -= len;
5213 pi2a->pDescription = ptr;
5214 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5215 ptr, cbBuf, NULL, NULL);
5216 ptr += len;
5217 cbBuf -= len;
5219 pi2a->fPortType = pi2w->fPortType;
5220 pi2a->Reserved = 0; /* documented: "must be zero" */
5223 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5224 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5225 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5229 cleanup:
5230 if (pcbNeeded) *pcbNeeded = needed;
5231 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5233 free(nameW);
5234 free(bufferW);
5236 TRACE("returning %d with %ld (%ld byte for %ld of %ld entries)\n",
5237 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5239 return (res);
5243 /******************************************************************************
5244 * EnumPortsW (WINSPOOL.@)
5246 * Enumerate available Ports
5248 * PARAMS
5249 * pName [I] Servername or NULL (local Computer)
5250 * Level [I] Structure-Level (1 or 2)
5251 * pPorts [O] PTR to Buffer that receives the Result
5252 * cbBuf [I] Size of Buffer at pPorts
5253 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5254 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5256 * RETURNS
5257 * Success: TRUE
5258 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5261 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5264 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5265 cbBuf, pcbNeeded, pcReturned);
5267 if ((backend == NULL) && !load_backend()) return FALSE;
5269 /* Level is not checked in win9x */
5270 if (!Level || (Level > 2)) {
5271 WARN("level (%ld) is ignored in win9x\n", Level);
5272 SetLastError(ERROR_INVALID_LEVEL);
5273 return FALSE;
5275 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5276 SetLastError(RPC_X_NULL_REF_POINTER);
5277 return FALSE;
5280 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5283 /******************************************************************************
5284 * GetDefaultPrinterW (WINSPOOL.@)
5286 * FIXME
5287 * This function must read the value from data 'device' of key
5288 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5290 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5292 BOOL retval = TRUE;
5293 DWORD insize, len;
5294 WCHAR *buffer, *ptr;
5296 if (!namesize)
5298 SetLastError(ERROR_INVALID_PARAMETER);
5299 return FALSE;
5302 /* make the buffer big enough for the stuff from the profile/registry,
5303 * the content must fit into the local buffer to compute the correct
5304 * size even if the extern buffer is too small or not given.
5305 * (20 for ,driver,port) */
5306 insize = *namesize;
5307 len = max(100, (insize + 20));
5308 buffer = malloc( len * sizeof(WCHAR));
5310 if (!GetProfileStringW( L"windows", L"device", L"", buffer, len ))
5312 SetLastError (ERROR_FILE_NOT_FOUND);
5313 retval = FALSE;
5314 goto end;
5316 TRACE("%s\n", debugstr_w(buffer));
5318 if ((ptr = wcschr( buffer, ',' )) == NULL)
5320 SetLastError(ERROR_INVALID_NAME);
5321 retval = FALSE;
5322 goto end;
5325 *ptr = 0;
5326 *namesize = wcslen( buffer ) + 1;
5327 if(!name || (*namesize > insize))
5329 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5330 retval = FALSE;
5331 goto end;
5333 wcscpy( name, buffer );
5335 end:
5336 free( buffer);
5337 return retval;
5341 /******************************************************************************
5342 * GetDefaultPrinterA (WINSPOOL.@)
5344 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5346 BOOL retval = TRUE;
5347 DWORD insize = 0;
5348 WCHAR *bufferW = NULL;
5350 if (!namesize)
5352 SetLastError(ERROR_INVALID_PARAMETER);
5353 return FALSE;
5356 if(name && *namesize) {
5357 insize = *namesize;
5358 bufferW = malloc( insize * sizeof(WCHAR));
5361 if(!GetDefaultPrinterW( bufferW, namesize)) {
5362 retval = FALSE;
5363 goto end;
5366 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5367 NULL, NULL);
5368 if (!*namesize)
5370 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5371 retval = FALSE;
5373 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
5375 end:
5376 free( bufferW);
5377 return retval;
5381 /******************************************************************************
5382 * SetDefaultPrinterW (WINSPOOL.204)
5384 * Set the Name of the Default Printer
5386 * PARAMS
5387 * pszPrinter [I] Name of the Printer or NULL
5389 * RETURNS
5390 * Success: True
5391 * Failure: FALSE
5393 * NOTES
5394 * When the Parameter is NULL or points to an Empty String and
5395 * a Default Printer was already present, then this Function changes nothing.
5396 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5397 * the First enumerated local Printer is used.
5400 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5402 WCHAR default_printer[MAX_PATH];
5403 LPWSTR buffer = NULL;
5404 HKEY hreg;
5405 DWORD size;
5406 DWORD namelen;
5407 LONG lres;
5409 TRACE("(%s)\n", debugstr_w(pszPrinter));
5410 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5412 default_printer[0] = '\0';
5413 size = ARRAY_SIZE(default_printer);
5415 /* if we have a default Printer, do nothing. */
5416 if (GetDefaultPrinterW(default_printer, &size))
5417 return TRUE;
5419 pszPrinter = NULL;
5420 /* we have no default Printer: search local Printers and use the first */
5421 if (!create_printers_reg_key( system_printers_key, &hreg ))
5423 default_printer[0] = '\0';
5424 size = ARRAY_SIZE(default_printer);
5425 if (!RegEnumKeyExW( hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL ))
5427 pszPrinter = default_printer;
5428 TRACE("using %s\n", debugstr_w(pszPrinter));
5430 RegCloseKey( hreg );
5433 if (pszPrinter == NULL) {
5434 TRACE("no local printer found\n");
5435 SetLastError(ERROR_FILE_NOT_FOUND);
5436 return FALSE;
5440 /* "pszPrinter" is never empty or NULL here. */
5441 namelen = wcslen( pszPrinter );
5442 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5443 buffer = malloc(size * sizeof(WCHAR));
5444 if (!buffer || create_printers_reg_key( user_printers_key, &hreg ))
5446 free(buffer);
5447 SetLastError(ERROR_FILE_NOT_FOUND);
5448 return FALSE;
5451 /* read the devices entry for the printer (driver,port) to build the string for the
5452 default device entry (printer,driver,port) */
5453 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5454 buffer[namelen] = ',';
5455 namelen++; /* move index to the start of the driver */
5457 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5458 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5459 if (!lres) {
5460 HKEY hdev;
5462 if (!create_printers_reg_key( user_default_key, &hdev ))
5464 RegSetValueExW( hdev, L"device", 0, REG_SZ, (BYTE *)buffer, (wcslen( buffer ) + 1) * sizeof(WCHAR) );
5465 RegCloseKey(hdev);
5468 else
5470 if (lres != ERROR_FILE_NOT_FOUND)
5471 FIXME("RegQueryValueExW failed with %ld for %s\n", lres, debugstr_w(pszPrinter));
5473 SetLastError(ERROR_INVALID_PRINTER_NAME);
5476 RegCloseKey(hreg);
5477 free(buffer);
5478 return (lres == ERROR_SUCCESS);
5481 /******************************************************************************
5482 * SetDefaultPrinterA (WINSPOOL.202)
5484 * See SetDefaultPrinterW.
5487 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5489 LPWSTR bufferW = NULL;
5490 BOOL res;
5492 TRACE("(%s)\n", debugstr_a(pszPrinter));
5493 if(pszPrinter) {
5494 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5495 bufferW = malloc(len * sizeof(WCHAR));
5496 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5498 res = SetDefaultPrinterW(bufferW);
5499 free(bufferW);
5500 return res;
5503 /******************************************************************************
5504 * SetPrinterDataExA (WINSPOOL.@)
5506 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5507 LPCSTR pValueName, DWORD Type,
5508 LPBYTE pData, DWORD cbData)
5510 HKEY hkeyPrinter, hkeySubkey;
5511 DWORD ret;
5513 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
5514 debugstr_a(pValueName), Type, pData, cbData);
5516 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5517 != ERROR_SUCCESS)
5518 return ret;
5520 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5521 != ERROR_SUCCESS) {
5522 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5523 RegCloseKey(hkeyPrinter);
5524 return ret;
5526 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5527 RegCloseKey(hkeySubkey);
5528 RegCloseKey(hkeyPrinter);
5529 return ret;
5532 /******************************************************************************
5533 * SetPrinterDataExW (WINSPOOL.@)
5535 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5536 LPCWSTR pValueName, DWORD Type,
5537 LPBYTE pData, DWORD cbData)
5539 HKEY hkeyPrinter, hkeySubkey;
5540 DWORD ret;
5542 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
5543 debugstr_w(pValueName), Type, pData, cbData);
5545 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5546 != ERROR_SUCCESS)
5547 return ret;
5549 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5550 != ERROR_SUCCESS) {
5551 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5552 RegCloseKey(hkeyPrinter);
5553 return ret;
5555 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5556 RegCloseKey(hkeySubkey);
5557 RegCloseKey(hkeyPrinter);
5558 return ret;
5561 /******************************************************************************
5562 * SetPrinterDataA (WINSPOOL.@)
5564 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5565 LPBYTE pData, DWORD cbData)
5567 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5568 pData, cbData);
5571 /******************************************************************************
5572 * SetPrinterDataW (WINSPOOL.@)
5574 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5575 LPBYTE pData, DWORD cbData)
5577 return SetPrinterDataExW( hPrinter, L"PrinterDriverData", pValueName, Type,
5578 pData, cbData );
5581 /******************************************************************************
5582 * GetPrinterDataExA (WINSPOOL.@)
5584 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5585 LPCSTR pValueName, LPDWORD pType,
5586 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5588 opened_printer_t *printer;
5589 HKEY printers_key, hkeyPrinter = 0, hkeySubkey = 0;
5590 DWORD ret;
5592 TRACE("(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter, debugstr_a(pKeyName),
5593 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5595 printer = get_opened_printer(hPrinter);
5596 if(!printer) return ERROR_INVALID_HANDLE;
5598 ret = create_printers_reg_key( system_printers_key, &printers_key );
5599 if (ret) return ret;
5601 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5603 if (printer->name) {
5605 ret = RegOpenKeyW( printers_key, printer->name, &hkeyPrinter );
5606 if (ret)
5608 RegCloseKey( printers_key );
5609 return ret;
5611 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5612 WARN("Can't open subkey %s: %ld\n", debugstr_a(pKeyName), ret);
5613 RegCloseKey(hkeyPrinter);
5614 RegCloseKey( printers_key );
5615 return ret;
5618 *pcbNeeded = nSize;
5619 ret = RegQueryValueExA( printer->name ? hkeySubkey : printers_key, pValueName,
5620 0, pType, pData, pcbNeeded );
5622 if (!ret && !pData) ret = ERROR_MORE_DATA;
5624 RegCloseKey(hkeySubkey);
5625 RegCloseKey(hkeyPrinter);
5626 RegCloseKey( printers_key );
5628 TRACE("--> %ld\n", ret);
5629 return ret;
5632 /******************************************************************************
5633 * GetPrinterDataExW (WINSPOOL.@)
5635 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5636 LPCWSTR pValueName, LPDWORD pType,
5637 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5639 opened_printer_t *printer;
5640 HKEY printers_key, hkeyPrinter = 0, hkeySubkey = 0;
5641 DWORD ret;
5643 TRACE("(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter, debugstr_w(pKeyName),
5644 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5646 printer = get_opened_printer(hPrinter);
5647 if(!printer) return ERROR_INVALID_HANDLE;
5649 ret = create_printers_reg_key( system_printers_key, &printers_key );
5650 if (ret) return ret;
5652 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5654 if (printer->name)
5656 ret = RegOpenKeyW( printers_key, printer->name, &hkeyPrinter);
5657 if (ret)
5659 RegCloseKey( printers_key );
5660 return ret;
5662 if ((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS)
5664 WARN("Can't open subkey %s: %ld\n", debugstr_w(pKeyName), ret);
5665 RegCloseKey(hkeyPrinter);
5666 RegCloseKey( printers_key );
5667 return ret;
5670 *pcbNeeded = nSize;
5671 ret = RegQueryValueExW( printer->name ? hkeySubkey : printers_key, pValueName,
5672 0, pType, pData, pcbNeeded );
5674 if (!ret && !pData) ret = ERROR_MORE_DATA;
5676 RegCloseKey(hkeySubkey);
5677 RegCloseKey(hkeyPrinter);
5678 RegCloseKey( printers_key );
5680 TRACE("--> %ld\n", ret);
5681 return ret;
5684 /******************************************************************************
5685 * GetPrinterDataA (WINSPOOL.@)
5687 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5688 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5690 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5691 pData, nSize, pcbNeeded);
5694 /******************************************************************************
5695 * GetPrinterDataW (WINSPOOL.@)
5697 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5698 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5700 return GetPrinterDataExW( hPrinter, L"PrinterDriverData", pValueName, pType,
5701 pData, nSize, pcbNeeded );
5704 /*******************************************************************************
5705 * EnumPrinterDataExW [WINSPOOL.@]
5707 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5708 LPBYTE pEnumValues, DWORD cbEnumValues,
5709 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5711 HKEY hkPrinter, hkSubKey;
5712 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5713 cbValueNameLen, cbMaxValueLen, cbValueLen,
5714 cbBufSize, dwType;
5715 LPWSTR lpValueName;
5716 PBYTE lpValue;
5717 PPRINTER_ENUM_VALUESW ppev;
5719 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5721 if (pKeyName == NULL || *pKeyName == 0)
5722 return ERROR_INVALID_PARAMETER;
5724 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5725 if (ret != ERROR_SUCCESS)
5727 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
5728 hPrinter, ret);
5729 return ret;
5732 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5733 if (ret != ERROR_SUCCESS)
5735 r = RegCloseKey (hkPrinter);
5736 if (r != ERROR_SUCCESS)
5737 WARN ("RegCloseKey returned %li\n", r);
5738 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
5739 debugstr_w (pKeyName), ret);
5740 return ret;
5743 ret = RegCloseKey (hkPrinter);
5744 if (ret != ERROR_SUCCESS)
5746 ERR ("RegCloseKey returned %li\n", ret);
5747 r = RegCloseKey (hkSubKey);
5748 if (r != ERROR_SUCCESS)
5749 WARN ("RegCloseKey returned %li\n", r);
5750 return ret;
5753 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5754 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5755 if (ret != ERROR_SUCCESS)
5757 r = RegCloseKey (hkSubKey);
5758 if (r != ERROR_SUCCESS)
5759 WARN ("RegCloseKey returned %li\n", r);
5760 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
5761 return ret;
5764 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
5765 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5767 if (cValues == 0) /* empty key */
5769 r = RegCloseKey (hkSubKey);
5770 if (r != ERROR_SUCCESS)
5771 WARN ("RegCloseKey returned %li\n", r);
5772 *pcbEnumValues = *pnEnumValues = 0;
5773 return ERROR_SUCCESS;
5776 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5778 lpValueName = malloc (cbMaxValueNameLen * sizeof(WCHAR));
5779 if (lpValueName == NULL)
5781 ERR ("Failed to allocate %li WCHARs\n", cbMaxValueNameLen);
5782 r = RegCloseKey (hkSubKey);
5783 if (r != ERROR_SUCCESS)
5784 WARN ("RegCloseKey returned %li\n", r);
5785 return ERROR_OUTOFMEMORY;
5788 lpValue = malloc (cbMaxValueLen);
5789 if (lpValue == NULL)
5791 ERR ("Failed to allocate %li bytes\n", cbMaxValueLen);
5792 free (lpValueName);
5793 r = RegCloseKey (hkSubKey);
5794 if (r != ERROR_SUCCESS)
5795 WARN ("RegCloseKey returned %li\n", r);
5796 return ERROR_OUTOFMEMORY;
5799 TRACE ("pass 1: calculating buffer required for all names and values\n");
5801 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5803 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
5805 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5807 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5808 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5809 NULL, NULL, lpValue, &cbValueLen);
5810 if (ret != ERROR_SUCCESS)
5812 free (lpValue);
5813 free (lpValueName);
5814 r = RegCloseKey (hkSubKey);
5815 if (r != ERROR_SUCCESS)
5816 WARN ("RegCloseKey returned %li\n", r);
5817 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
5818 return ret;
5821 TRACE ("%s [%li]: name needs %li WCHARs, data needs %li bytes\n",
5822 debugstr_w (lpValueName), dwIndex,
5823 cbValueNameLen + 1, cbValueLen);
5825 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5826 cbBufSize += cbValueLen;
5829 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
5831 *pcbEnumValues = cbBufSize;
5832 *pnEnumValues = cValues;
5834 if (cbEnumValues < cbBufSize) /* buffer too small */
5836 free (lpValue);
5837 free (lpValueName);
5838 r = RegCloseKey (hkSubKey);
5839 if (r != ERROR_SUCCESS)
5840 WARN ("RegCloseKey returned %li\n", r);
5841 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
5842 return ERROR_MORE_DATA;
5845 TRACE ("pass 2: copying all names and values to buffer\n");
5847 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5848 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5850 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5852 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5853 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5854 NULL, &dwType, lpValue, &cbValueLen);
5855 if (ret != ERROR_SUCCESS)
5857 free (lpValue);
5858 free (lpValueName);
5859 r = RegCloseKey (hkSubKey);
5860 if (r != ERROR_SUCCESS)
5861 WARN ("RegCloseKey returned %li\n", r);
5862 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
5863 return ret;
5866 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5867 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5868 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5869 pEnumValues += cbValueNameLen;
5871 /* return # of *bytes* (including trailing \0), not # of chars */
5872 ppev[dwIndex].cbValueName = cbValueNameLen;
5874 ppev[dwIndex].dwType = dwType;
5876 memcpy (pEnumValues, lpValue, cbValueLen);
5877 ppev[dwIndex].pData = pEnumValues;
5878 pEnumValues += cbValueLen;
5880 ppev[dwIndex].cbData = cbValueLen;
5882 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
5883 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5886 free (lpValue);
5887 free (lpValueName);
5889 ret = RegCloseKey (hkSubKey);
5890 if (ret != ERROR_SUCCESS)
5892 ERR ("RegCloseKey returned %li\n", ret);
5893 return ret;
5896 return ERROR_SUCCESS;
5899 /*******************************************************************************
5900 * EnumPrinterDataExA [WINSPOOL.@]
5902 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5903 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5904 * what Windows 2000 SP1 does.
5907 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5908 LPBYTE pEnumValues, DWORD cbEnumValues,
5909 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5911 INT len;
5912 LPWSTR pKeyNameW;
5913 DWORD ret, dwIndex, dwBufSize;
5914 LPSTR pBuffer;
5916 TRACE ("%p %s\n", hPrinter, pKeyName);
5918 if (pKeyName == NULL || *pKeyName == 0)
5919 return ERROR_INVALID_PARAMETER;
5921 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5922 if (len == 0)
5924 ret = GetLastError ();
5925 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5926 return ret;
5929 pKeyNameW = malloc (len * sizeof(WCHAR));
5930 if (pKeyNameW == NULL)
5932 ERR ("Failed to allocate %li bytes\n",
5933 (LONG)(len * sizeof (WCHAR)));
5934 return ERROR_OUTOFMEMORY;
5937 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5939 ret = GetLastError ();
5940 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5941 free (pKeyNameW);
5942 return ret;
5945 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5946 pcbEnumValues, pnEnumValues);
5947 free (pKeyNameW);
5948 if (ret != ERROR_SUCCESS)
5950 TRACE ("EnumPrinterDataExW returned %li\n", ret);
5951 return ret;
5954 if (*pnEnumValues == 0) /* empty key */
5955 return ERROR_SUCCESS;
5957 dwBufSize = 0;
5958 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5960 PPRINTER_ENUM_VALUESW ppev =
5961 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5963 if (dwBufSize < ppev->cbValueName)
5964 dwBufSize = ppev->cbValueName;
5966 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5967 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5968 dwBufSize = ppev->cbData;
5971 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5973 pBuffer = malloc(dwBufSize);
5974 if (pBuffer == NULL)
5976 ERR ("Failed to allocate %li bytes\n", dwBufSize);
5977 return ERROR_OUTOFMEMORY;
5980 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5982 PPRINTER_ENUM_VALUESW ppev =
5983 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5985 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5986 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5987 NULL);
5988 if (len == 0)
5990 ret = GetLastError ();
5991 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5992 free (pBuffer);
5993 return ret;
5996 memcpy (ppev->pValueName, pBuffer, len);
5998 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer);
6000 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6001 ppev->dwType != REG_MULTI_SZ)
6002 continue;
6004 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6005 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6006 if (len == 0)
6008 ret = GetLastError ();
6009 ERR ("WideCharToMultiByte failed with code %li\n", ret);
6010 free (pBuffer);
6011 return ret;
6014 memcpy (ppev->pData, pBuffer, len);
6016 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer);
6017 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6020 free(pBuffer);
6021 return ERROR_SUCCESS;
6024 /******************************************************************************
6025 * AbortPrinter (WINSPOOL.@)
6027 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6029 FIXME("(%p), stub!\n", hPrinter);
6030 return TRUE;
6033 /******************************************************************************
6034 * AddPortA (WINSPOOL.@)
6036 * See AddPortW.
6039 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6041 LPWSTR nameW = NULL;
6042 LPWSTR monitorW = NULL;
6043 DWORD len;
6044 BOOL res;
6046 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6048 if (pName) {
6049 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6050 nameW = malloc(len * sizeof(WCHAR));
6051 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6054 if (pMonitorName) {
6055 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6056 monitorW = malloc(len * sizeof(WCHAR));
6057 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6059 res = AddPortW(nameW, hWnd, monitorW);
6060 free(nameW);
6061 free(monitorW);
6062 return res;
6065 /******************************************************************************
6066 * AddPortW (WINSPOOL.@)
6068 * Add a Port for a specific Monitor
6070 * PARAMS
6071 * pName [I] Servername or NULL (local Computer)
6072 * hWnd [I] Handle to parent Window for the Dialog-Box
6073 * pMonitorName [I] Name of the Monitor that manage the Port
6075 * RETURNS
6076 * Success: TRUE
6077 * Failure: FALSE
6080 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6082 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6084 if ((backend == NULL) && !load_backend()) return FALSE;
6086 if (!pMonitorName) {
6087 SetLastError(RPC_X_NULL_REF_POINTER);
6088 return FALSE;
6091 return backend->fpAddPort(pName, hWnd, pMonitorName);
6094 /******************************************************************************
6095 * AddPortExA (WINSPOOL.@)
6097 * See AddPortExW.
6100 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6102 PORT_INFO_2W pi2W;
6103 PORT_INFO_2A * pi2A;
6104 LPWSTR nameW = NULL;
6105 LPWSTR monitorW = NULL;
6106 DWORD len;
6107 BOOL res;
6109 pi2A = (PORT_INFO_2A *) pBuffer;
6111 TRACE("(%s, %ld, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6112 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6114 if ((level < 1) || (level > 2)) {
6115 SetLastError(ERROR_INVALID_LEVEL);
6116 return FALSE;
6119 if (!pi2A) {
6120 SetLastError(ERROR_INVALID_PARAMETER);
6121 return FALSE;
6124 if (pName) {
6125 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6126 nameW = malloc(len * sizeof(WCHAR));
6127 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6130 if (pMonitorName) {
6131 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6132 monitorW = malloc(len * sizeof(WCHAR));
6133 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6136 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6138 if (pi2A->pPortName) {
6139 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6140 pi2W.pPortName = malloc(len * sizeof(WCHAR));
6141 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6144 if (level > 1) {
6145 if (pi2A->pMonitorName) {
6146 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6147 pi2W.pMonitorName = malloc(len * sizeof(WCHAR));
6148 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6151 if (pi2A->pDescription) {
6152 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6153 pi2W.pDescription = malloc(len * sizeof(WCHAR));
6154 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6156 pi2W.fPortType = pi2A->fPortType;
6157 pi2W.Reserved = pi2A->Reserved;
6160 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6162 free(nameW);
6163 free(monitorW);
6164 free(pi2W.pPortName);
6165 free(pi2W.pMonitorName);
6166 free(pi2W.pDescription);
6167 return res;
6171 /******************************************************************************
6172 * AddPortExW (WINSPOOL.@)
6174 * Add a Port for a specific Monitor, without presenting a user interface
6176 * PARAMS
6177 * pName [I] Servername or NULL (local Computer)
6178 * level [I] Structure-Level (1 or 2) for pBuffer
6179 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6180 * pMonitorName [I] Name of the Monitor that manage the Port
6182 * RETURNS
6183 * Success: TRUE
6184 * Failure: FALSE
6187 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6189 PORT_INFO_2W * pi2;
6191 pi2 = (PORT_INFO_2W *) pBuffer;
6193 TRACE("(%s, %ld, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6194 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6195 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6196 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6198 if ((backend == NULL) && !load_backend()) return FALSE;
6200 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6201 SetLastError(ERROR_INVALID_PARAMETER);
6202 return FALSE;
6205 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6208 /******************************************************************************
6209 * AddPrinterConnectionA (WINSPOOL.@)
6211 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6213 FIXME("%s\n", debugstr_a(pName));
6214 return FALSE;
6217 /******************************************************************************
6218 * AddPrinterConnectionW (WINSPOOL.@)
6220 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6222 FIXME("%s\n", debugstr_w(pName));
6223 return FALSE;
6226 /******************************************************************************
6227 * AddPrinterDriverExW (WINSPOOL.@)
6229 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6231 * PARAMS
6232 * pName [I] Servername or NULL (local Computer)
6233 * level [I] Level for the supplied DRIVER_INFO_*W struct
6234 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6235 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6237 * RESULTS
6238 * Success: TRUE
6239 * Failure: FALSE
6242 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6244 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6246 if ((backend == NULL) && !load_backend()) return FALSE;
6248 if (level < 2 || level == 5 || level == 7 || level > 8) {
6249 SetLastError(ERROR_INVALID_LEVEL);
6250 return FALSE;
6253 if (!pDriverInfo) {
6254 SetLastError(ERROR_INVALID_PARAMETER);
6255 return FALSE;
6258 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6261 /******************************************************************************
6262 * AddPrinterDriverExA (WINSPOOL.@)
6264 * See AddPrinterDriverExW.
6267 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6269 DRIVER_INFO_8A *diA;
6270 DRIVER_INFO_8W diW;
6271 LPWSTR nameW = NULL;
6272 DWORD lenA;
6273 DWORD len;
6274 BOOL res = FALSE;
6276 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6278 diA = (DRIVER_INFO_8A *) pDriverInfo;
6279 ZeroMemory(&diW, sizeof(diW));
6281 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6282 SetLastError(ERROR_INVALID_LEVEL);
6283 return FALSE;
6286 if (diA == NULL) {
6287 SetLastError(ERROR_INVALID_PARAMETER);
6288 return FALSE;
6291 /* convert servername to unicode */
6292 if (pName) {
6293 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6294 nameW = malloc(len * sizeof(WCHAR));
6295 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6298 /* common fields */
6299 diW.cVersion = diA->cVersion;
6301 if (diA->pName) {
6302 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6303 diW.pName = malloc(len * sizeof(WCHAR));
6304 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6307 if (diA->pEnvironment) {
6308 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6309 diW.pEnvironment = malloc(len * sizeof(WCHAR));
6310 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6313 if (diA->pDriverPath) {
6314 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6315 diW.pDriverPath = malloc(len * sizeof(WCHAR));
6316 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6319 if (diA->pDataFile) {
6320 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6321 diW.pDataFile = malloc(len * sizeof(WCHAR));
6322 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6325 if (diA->pConfigFile) {
6326 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6327 diW.pConfigFile = malloc(len * sizeof(WCHAR));
6328 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6331 if ((Level > 2) && diA->pHelpFile) {
6332 len = MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, NULL, 0);
6333 diW.pHelpFile = malloc(len * sizeof(WCHAR));
6334 MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, diW.pHelpFile, len);
6337 if ((Level > 2) && diA->pDependentFiles) {
6338 lenA = multi_sz_lenA(diA->pDependentFiles);
6339 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6340 diW.pDependentFiles = malloc(len * sizeof(WCHAR));
6341 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6344 if ((Level > 2) && diA->pMonitorName) {
6345 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6346 diW.pMonitorName = malloc(len * sizeof(WCHAR));
6347 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6350 if ((Level > 2) && diA->pDefaultDataType) {
6351 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6352 diW.pDefaultDataType = malloc(len * sizeof(WCHAR));
6353 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6356 if ((Level > 3) && diA->pszzPreviousNames) {
6357 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6358 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6359 diW.pszzPreviousNames = malloc(len * sizeof(WCHAR));
6360 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6363 if (Level > 5) {
6364 diW.ftDriverDate = diA->ftDriverDate;
6365 diW.dwlDriverVersion = diA->dwlDriverVersion;
6368 if ((Level > 5) && diA->pszMfgName) {
6369 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6370 diW.pszMfgName = malloc(len * sizeof(WCHAR));
6371 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6374 if ((Level > 5) && diA->pszOEMUrl) {
6375 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6376 diW.pszOEMUrl = malloc(len * sizeof(WCHAR));
6377 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6380 if ((Level > 5) && diA->pszHardwareID) {
6381 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6382 diW.pszHardwareID = malloc(len * sizeof(WCHAR));
6383 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6386 if ((Level > 5) && diA->pszProvider) {
6387 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6388 diW.pszProvider = malloc(len * sizeof(WCHAR));
6389 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6392 if ((Level > 7) && diA->pszPrintProcessor) {
6393 len = MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, NULL, 0);
6394 diW.pszPrintProcessor = malloc(len * sizeof(WCHAR));
6395 MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, diW.pszPrintProcessor, len);
6398 if ((Level > 7) && diA->pszVendorSetup) {
6399 len = MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, NULL, 0);
6400 diW.pszVendorSetup = malloc(len * sizeof(WCHAR));
6401 MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, diW.pszVendorSetup, len);
6404 if ((Level > 7) && diA->pszzColorProfiles) {
6405 lenA = multi_sz_lenA(diA->pszzColorProfiles);
6406 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, NULL, 0);
6407 diW.pszzColorProfiles = malloc(len * sizeof(WCHAR));
6408 MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, diW.pszzColorProfiles, len);
6411 if ((Level > 7) && diA->pszInfPath) {
6412 len = MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, NULL, 0);
6413 diW.pszInfPath = malloc(len * sizeof(WCHAR));
6414 MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, diW.pszInfPath, len);
6417 if ((Level > 7) && diA->pszzCoreDriverDependencies) {
6418 lenA = multi_sz_lenA(diA->pszzCoreDriverDependencies);
6419 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, NULL, 0);
6420 diW.pszzCoreDriverDependencies = malloc(len * sizeof(WCHAR));
6421 MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, diW.pszzCoreDriverDependencies, len);
6424 if (Level > 7) {
6425 diW.dwPrinterDriverAttributes = diA->dwPrinterDriverAttributes;
6426 diW.ftMinInboxDriverVerDate = diA->ftMinInboxDriverVerDate;
6427 diW.dwlMinInboxDriverVerVersion = diA->dwlMinInboxDriverVerVersion;
6430 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6431 TRACE("got %u with %lu\n", res, GetLastError());
6432 free(nameW);
6433 free(diW.pName);
6434 free(diW.pEnvironment);
6435 free(diW.pDriverPath);
6436 free(diW.pDataFile);
6437 free(diW.pConfigFile);
6438 free(diW.pHelpFile);
6439 free(diW.pDependentFiles);
6440 free(diW.pMonitorName);
6441 free(diW.pDefaultDataType);
6442 free(diW.pszzPreviousNames);
6443 free(diW.pszMfgName);
6444 free(diW.pszOEMUrl);
6445 free(diW.pszHardwareID);
6446 free(diW.pszProvider);
6447 free(diW.pszPrintProcessor);
6448 free(diW.pszVendorSetup);
6449 free(diW.pszzColorProfiles);
6450 free(diW.pszInfPath);
6451 free(diW.pszzCoreDriverDependencies);
6453 TRACE("=> %u with %lu\n", res, GetLastError());
6454 return res;
6457 /******************************************************************************
6458 * ConfigurePortA (WINSPOOL.@)
6460 * See ConfigurePortW.
6463 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6465 LPWSTR nameW = NULL;
6466 LPWSTR portW = NULL;
6467 INT len;
6468 DWORD res;
6470 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6472 /* convert servername to unicode */
6473 if (pName) {
6474 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6475 nameW = malloc(len * sizeof(WCHAR));
6476 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6479 /* convert portname to unicode */
6480 if (pPortName) {
6481 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6482 portW = malloc(len * sizeof(WCHAR));
6483 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6486 res = ConfigurePortW(nameW, hWnd, portW);
6487 free(nameW);
6488 free(portW);
6489 return res;
6492 /******************************************************************************
6493 * ConfigurePortW (WINSPOOL.@)
6495 * Display the Configuration-Dialog for a specific Port
6497 * PARAMS
6498 * pName [I] Servername or NULL (local Computer)
6499 * hWnd [I] Handle to parent Window for the Dialog-Box
6500 * pPortName [I] Name of the Port, that should be configured
6502 * RETURNS
6503 * Success: TRUE
6504 * Failure: FALSE
6507 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6510 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6512 if ((backend == NULL) && !load_backend()) return FALSE;
6514 if (!pPortName) {
6515 SetLastError(RPC_X_NULL_REF_POINTER);
6516 return FALSE;
6519 return backend->fpConfigurePort(pName, hWnd, pPortName);
6522 /******************************************************************************
6523 * ConnectToPrinterDlg (WINSPOOL.@)
6525 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6527 FIXME("%p %lx\n", hWnd, Flags);
6528 return NULL;
6531 /******************************************************************************
6532 * DeletePrinterConnectionA (WINSPOOL.@)
6534 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6536 FIXME("%s\n", debugstr_a(pName));
6537 return TRUE;
6540 /******************************************************************************
6541 * DeletePrinterConnectionW (WINSPOOL.@)
6543 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6545 FIXME("%s\n", debugstr_w(pName));
6546 return TRUE;
6549 /******************************************************************************
6550 * DeletePrinterDriverExW (WINSPOOL.@)
6552 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6553 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6555 HKEY hkey_drivers;
6556 BOOL ret = FALSE;
6558 TRACE("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
6559 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6561 if(pName && pName[0])
6563 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6564 SetLastError(ERROR_INVALID_PARAMETER);
6565 return FALSE;
6568 if(dwDeleteFlag)
6570 FIXME("dwDeleteFlag = %lx - unsupported\n", dwDeleteFlag);
6571 SetLastError(ERROR_INVALID_PARAMETER);
6572 return FALSE;
6575 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6577 if(!hkey_drivers)
6579 ERR("Can't open drivers key\n");
6580 return FALSE;
6583 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6584 ret = TRUE;
6586 RegCloseKey(hkey_drivers);
6588 return ret;
6591 /******************************************************************************
6592 * DeletePrinterDriverExA (WINSPOOL.@)
6594 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6595 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6597 UNICODE_STRING NameW, EnvW, DriverW;
6598 BOOL ret;
6600 asciitounicode(&NameW, pName);
6601 asciitounicode(&EnvW, pEnvironment);
6602 asciitounicode(&DriverW, pDriverName);
6604 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6606 RtlFreeUnicodeString(&DriverW);
6607 RtlFreeUnicodeString(&EnvW);
6608 RtlFreeUnicodeString(&NameW);
6610 return ret;
6613 /******************************************************************************
6614 * DeletePrinterDataExW (WINSPOOL.@)
6616 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6617 LPCWSTR pValueName)
6619 FIXME("%p %s %s\n", hPrinter,
6620 debugstr_w(pKeyName), debugstr_w(pValueName));
6621 return ERROR_INVALID_PARAMETER;
6624 /******************************************************************************
6625 * DeletePrinterDataExA (WINSPOOL.@)
6627 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6628 LPCSTR pValueName)
6630 FIXME("%p %s %s\n", hPrinter,
6631 debugstr_a(pKeyName), debugstr_a(pValueName));
6632 return ERROR_INVALID_PARAMETER;
6635 /******************************************************************************
6636 * DeletePrintProcessorA (WINSPOOL.@)
6638 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6640 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6641 debugstr_a(pPrintProcessorName));
6642 return TRUE;
6645 /******************************************************************************
6646 * DeletePrintProcessorW (WINSPOOL.@)
6648 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6650 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6651 debugstr_w(pPrintProcessorName));
6652 return TRUE;
6655 /******************************************************************************
6656 * DeletePrintProvidorA (WINSPOOL.@)
6658 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6660 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6661 debugstr_a(pPrintProviderName));
6662 return TRUE;
6665 /******************************************************************************
6666 * DeletePrintProvidorW (WINSPOOL.@)
6668 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6670 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6671 debugstr_w(pPrintProviderName));
6672 return TRUE;
6675 /******************************************************************************
6676 * EnumFormsA (WINSPOOL.@)
6678 BOOL WINAPI EnumFormsA( HANDLE printer, DWORD level, BYTE *form, DWORD size, DWORD *needed, DWORD *count )
6680 const DWORD *string_info = form_string_info( level );
6681 BOOL ret;
6682 DWORD i;
6684 if (!string_info) return FALSE;
6686 ret = EnumFormsW( printer, level, form, size, needed, count );
6687 if (ret)
6688 for (i = 0; i < *count; i++)
6689 packed_struct_WtoA( form + i * string_info[0], string_info );
6691 return ret;
6694 /******************************************************************************
6695 * EnumFormsW (WINSPOOL.@)
6697 BOOL WINAPI EnumFormsW( HANDLE printer, DWORD level, BYTE *form, DWORD size, DWORD *needed, DWORD *count )
6699 HANDLE handle = get_backend_handle( printer );
6701 TRACE( "(%p, %ld, %p, %ld, %p, %p)\n", printer, level, form, size, needed, count );
6703 if (!handle)
6705 SetLastError( ERROR_INVALID_HANDLE );
6706 return FALSE;
6709 if (!needed || !count)
6711 SetLastError( RPC_X_NULL_REF_POINTER );
6712 return FALSE;
6715 if (!form && size)
6717 SetLastError( ERROR_INVALID_USER_BUFFER );
6718 return FALSE;
6721 return backend->fpEnumForms( handle, level, form, size, needed, count );
6724 /*****************************************************************************
6725 * EnumMonitorsA [WINSPOOL.@]
6727 * See EnumMonitorsW.
6730 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6731 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6733 BOOL res;
6734 LPBYTE bufferW = NULL;
6735 LPWSTR nameW = NULL;
6736 DWORD needed = 0;
6737 DWORD numentries = 0;
6738 INT len;
6740 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6741 cbBuf, pcbNeeded, pcReturned);
6743 /* convert servername to unicode */
6744 if (pName) {
6745 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6746 nameW = malloc(len * sizeof(WCHAR));
6747 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6749 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6750 needed = cbBuf * sizeof(WCHAR);
6751 if (needed) bufferW = malloc(needed);
6752 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6754 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6755 if (pcbNeeded) needed = *pcbNeeded;
6756 /* HeapReAlloc return NULL, when bufferW was NULL */
6757 bufferW = (bufferW) ? realloc(bufferW, needed) : malloc(needed);
6759 /* Try again with the large Buffer */
6760 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6762 numentries = pcReturned ? *pcReturned : 0;
6763 needed = 0;
6765 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6766 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6768 if (res) {
6769 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6770 DWORD entrysize = 0;
6771 DWORD index;
6772 LPSTR ptr;
6773 LPMONITOR_INFO_2W mi2w;
6774 LPMONITOR_INFO_2A mi2a;
6776 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6777 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6779 /* First pass: calculate the size for all Entries */
6780 mi2w = (LPMONITOR_INFO_2W) bufferW;
6781 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6782 index = 0;
6783 while (index < numentries) {
6784 index++;
6785 needed += entrysize; /* MONITOR_INFO_?A */
6786 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6788 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6789 NULL, 0, NULL, NULL);
6790 if (Level > 1) {
6791 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6792 NULL, 0, NULL, NULL);
6793 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6794 NULL, 0, NULL, NULL);
6796 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6797 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6798 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6801 /* check for errors and quit on failure */
6802 if (cbBuf < needed) {
6803 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6804 res = FALSE;
6805 goto emA_cleanup;
6807 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6808 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6809 cbBuf -= len ; /* free Bytes in the user-Buffer */
6810 mi2w = (LPMONITOR_INFO_2W) bufferW;
6811 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6812 index = 0;
6813 /* Second Pass: Fill the User Buffer (if we have one) */
6814 while ((index < numentries) && pMonitors) {
6815 index++;
6816 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
6817 mi2a->pName = ptr;
6818 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6819 ptr, cbBuf , NULL, NULL);
6820 ptr += len;
6821 cbBuf -= len;
6822 if (Level > 1) {
6823 mi2a->pEnvironment = ptr;
6824 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6825 ptr, cbBuf, NULL, NULL);
6826 ptr += len;
6827 cbBuf -= len;
6829 mi2a->pDLLName = ptr;
6830 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6831 ptr, cbBuf, NULL, NULL);
6832 ptr += len;
6833 cbBuf -= len;
6835 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6836 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6837 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6840 emA_cleanup:
6841 if (pcbNeeded) *pcbNeeded = needed;
6842 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6844 free(nameW);
6845 free(bufferW);
6847 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
6848 (res), GetLastError(), needed, numentries);
6850 return (res);
6854 /*****************************************************************************
6855 * EnumMonitorsW [WINSPOOL.@]
6857 * Enumerate available Port-Monitors
6859 * PARAMS
6860 * pName [I] Servername or NULL (local Computer)
6861 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6862 * pMonitors [O] PTR to Buffer that receives the Result
6863 * cbBuf [I] Size of Buffer at pMonitors
6864 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6865 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6867 * RETURNS
6868 * Success: TRUE
6869 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6872 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6873 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6876 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6877 cbBuf, pcbNeeded, pcReturned);
6879 if ((backend == NULL) && !load_backend()) return FALSE;
6881 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6882 SetLastError(RPC_X_NULL_REF_POINTER);
6883 return FALSE;
6886 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6889 /******************************************************************************
6890 * SpoolerInit (WINSPOOL.@)
6892 * Initialize the Spooler
6894 * RETURNS
6895 * Success: TRUE
6896 * Failure: FALSE
6898 * NOTES
6899 * The function fails on windows, when the spooler service is not running
6902 BOOL WINAPI SpoolerInit(void)
6905 if ((backend == NULL) && !load_backend()) return FALSE;
6906 return TRUE;
6909 /******************************************************************************
6910 * XcvDataW (WINSPOOL.@)
6912 * Execute commands in the Printmonitor DLL
6914 * PARAMS
6915 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6916 * pszDataName [i] Name of the command to execute
6917 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6918 * cbInputData [i] Size in Bytes of Buffer at pInputData
6919 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6920 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6921 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6922 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6924 * RETURNS
6925 * Success: TRUE
6926 * Failure: FALSE
6928 * NOTES
6929 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6930 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6932 * Minimal List of commands, that a Printmonitor DLL should support:
6934 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6935 *| "AddPort" : Add a Port
6936 *| "DeletePort": Delete a Port
6938 * Many Printmonitors support additional commands. Examples for localspl.dll:
6939 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6940 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6943 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6944 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6945 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6947 opened_printer_t *printer;
6949 TRACE("(%p, %s, %p, %ld, %p, %ld, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6950 pInputData, cbInputData, pOutputData,
6951 cbOutputData, pcbOutputNeeded, pdwStatus);
6953 if ((backend == NULL) && !load_backend()) return FALSE;
6955 printer = get_opened_printer(hXcv);
6956 if (!printer || (!printer->backend_printer)) {
6957 SetLastError(ERROR_INVALID_HANDLE);
6958 return FALSE;
6961 if (!pcbOutputNeeded) {
6962 SetLastError(ERROR_INVALID_PARAMETER);
6963 return FALSE;
6966 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6967 SetLastError(RPC_X_NULL_REF_POINTER);
6968 return FALSE;
6971 *pcbOutputNeeded = 0;
6973 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6974 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6978 /*****************************************************************************
6979 * EnumPrinterDataA [WINSPOOL.@]
6982 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6983 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6984 DWORD cbData, LPDWORD pcbData )
6986 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
6987 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6988 return ERROR_NO_MORE_ITEMS;
6991 /*****************************************************************************
6992 * EnumPrinterDataW [WINSPOOL.@]
6995 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6996 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6997 DWORD cbData, LPDWORD pcbData )
6999 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
7000 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7001 return ERROR_NO_MORE_ITEMS;
7004 /*****************************************************************************
7005 * EnumPrinterKeyA [WINSPOOL.@]
7008 DWORD WINAPI EnumPrinterKeyA(HANDLE printer, const CHAR *key, CHAR *subkey, DWORD size, DWORD *needed)
7010 FIXME("%p %s %p %lx %p\n", printer, debugstr_a(key), subkey, size, needed);
7011 return ERROR_CALL_NOT_IMPLEMENTED;
7014 /*****************************************************************************
7015 * EnumPrinterKeyW [WINSPOOL.@]
7018 DWORD WINAPI EnumPrinterKeyW(HANDLE printer, const WCHAR *key, WCHAR *subkey, DWORD size, DWORD *needed)
7020 FIXME("%p %s %p %lx %p\n", printer, debugstr_w(key), subkey, size, needed);
7021 return ERROR_CALL_NOT_IMPLEMENTED;
7024 /*****************************************************************************
7025 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7028 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7029 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7030 LPDWORD pcbNeeded, LPDWORD pcReturned)
7032 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
7033 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7034 pcbNeeded, pcReturned);
7035 return FALSE;
7038 /*****************************************************************************
7039 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7042 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7043 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7044 LPDWORD pcbNeeded, LPDWORD pcReturned)
7046 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
7047 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7048 pcbNeeded, pcReturned);
7049 return FALSE;
7052 /*****************************************************************************
7053 * EnumPrintProcessorsA [WINSPOOL.@]
7055 * See EnumPrintProcessorsW.
7058 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7059 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7061 BOOL res;
7062 LPBYTE bufferW = NULL;
7063 LPWSTR nameW = NULL;
7064 LPWSTR envW = NULL;
7065 DWORD needed = 0;
7066 DWORD numentries = 0;
7067 INT len;
7069 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7070 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7072 /* convert names to unicode */
7073 if (pName) {
7074 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7075 nameW = malloc(len * sizeof(WCHAR));
7076 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7078 if (pEnvironment) {
7079 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7080 envW = malloc(len * sizeof(WCHAR));
7081 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7084 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7085 needed = cbBuf * sizeof(WCHAR);
7086 if (needed) bufferW = malloc(needed);
7087 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7089 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7090 if (pcbNeeded) needed = *pcbNeeded;
7091 /* HeapReAlloc return NULL, when bufferW was NULL */
7092 bufferW = (bufferW) ? realloc(bufferW, needed) : malloc(needed);
7094 /* Try again with the large Buffer */
7095 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7097 numentries = pcReturned ? *pcReturned : 0;
7098 needed = 0;
7100 if (res) {
7101 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7102 DWORD index;
7103 LPSTR ptr;
7104 PPRINTPROCESSOR_INFO_1W ppiw;
7105 PPRINTPROCESSOR_INFO_1A ppia;
7107 /* First pass: calculate the size for all Entries */
7108 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7109 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7110 index = 0;
7111 while (index < numentries) {
7112 index++;
7113 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7114 TRACE("%p: parsing #%ld (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7116 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7117 NULL, 0, NULL, NULL);
7119 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7120 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7123 /* check for errors and quit on failure */
7124 if (cbBuf < needed) {
7125 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7126 res = FALSE;
7127 goto epp_cleanup;
7130 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7131 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7132 cbBuf -= len ; /* free Bytes in the user-Buffer */
7133 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7134 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7135 index = 0;
7136 /* Second Pass: Fill the User Buffer (if we have one) */
7137 while ((index < numentries) && pPPInfo) {
7138 index++;
7139 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%ld\n", ppia, index);
7140 ppia->pName = ptr;
7141 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7142 ptr, cbBuf , NULL, NULL);
7143 ptr += len;
7144 cbBuf -= len;
7146 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7147 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7151 epp_cleanup:
7152 if (pcbNeeded) *pcbNeeded = needed;
7153 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7155 free(nameW);
7156 free(envW);
7157 free(bufferW);
7159 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
7160 (res), GetLastError(), needed, numentries);
7162 return (res);
7165 /*****************************************************************************
7166 * EnumPrintProcessorsW [WINSPOOL.@]
7168 * Enumerate available Print Processors
7170 * PARAMS
7171 * pName [I] Servername or NULL (local Computer)
7172 * pEnvironment [I] Printing-Environment or NULL (Default)
7173 * Level [I] Structure-Level (Only 1 is allowed)
7174 * pPPInfo [O] PTR to Buffer that receives the Result
7175 * cbBuf [I] Size of Buffer at pPPInfo
7176 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7177 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7179 * RETURNS
7180 * Success: TRUE
7181 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7184 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7185 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7188 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7189 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7191 if ((backend == NULL) && !load_backend()) return FALSE;
7193 if (!pcbNeeded || !pcReturned) {
7194 SetLastError(RPC_X_NULL_REF_POINTER);
7195 return FALSE;
7198 if (!pPPInfo && (cbBuf > 0)) {
7199 SetLastError(ERROR_INVALID_USER_BUFFER);
7200 return FALSE;
7203 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7204 cbBuf, pcbNeeded, pcReturned);
7207 /*****************************************************************************
7208 * ExtDeviceMode [WINSPOOL.@]
7211 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7212 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7213 DWORD fMode)
7215 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
7216 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7217 debugstr_a(pProfile), fMode);
7218 return -1;
7221 /*****************************************************************************
7222 * FindClosePrinterChangeNotification [WINSPOOL.@]
7225 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7227 FIXME("Stub: %p\n", hChange);
7228 return TRUE;
7231 /*****************************************************************************
7232 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7235 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7236 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7238 FIXME("Stub: %p %lx %lx %p\n",
7239 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7240 return INVALID_HANDLE_VALUE;
7243 /*****************************************************************************
7244 * FindNextPrinterChangeNotification [WINSPOOL.@]
7247 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7248 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7250 FIXME("Stub: %p %p %p %p\n",
7251 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7252 return FALSE;
7255 /*****************************************************************************
7256 * FreePrinterNotifyInfo [WINSPOOL.@]
7259 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7261 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7262 return TRUE;
7265 static inline const DWORD *job_string_info(DWORD level)
7267 static const DWORD info_1[] =
7269 sizeof(JOB_INFO_1W),
7270 FIELD_OFFSET(JOB_INFO_1W, pPrinterName),
7271 FIELD_OFFSET(JOB_INFO_1W, pMachineName),
7272 FIELD_OFFSET(JOB_INFO_1W, pUserName),
7273 FIELD_OFFSET(JOB_INFO_1W, pDocument),
7274 FIELD_OFFSET(JOB_INFO_1W, pDatatype),
7275 FIELD_OFFSET(JOB_INFO_1W, pStatus),
7278 static const DWORD info_2[] =
7280 sizeof(JOB_INFO_2W),
7281 FIELD_OFFSET(JOB_INFO_2W, pPrinterName),
7282 FIELD_OFFSET(JOB_INFO_2W, pMachineName),
7283 FIELD_OFFSET(JOB_INFO_2W, pUserName),
7284 FIELD_OFFSET(JOB_INFO_2W, pDocument),
7285 FIELD_OFFSET(JOB_INFO_2W, pNotifyName),
7286 FIELD_OFFSET(JOB_INFO_2W, pDatatype),
7287 FIELD_OFFSET(JOB_INFO_2W, pPrintProcessor),
7288 FIELD_OFFSET(JOB_INFO_2W, pParameters),
7289 FIELD_OFFSET(JOB_INFO_2W, pDriverName),
7290 FIELD_OFFSET(JOB_INFO_2W, pStatus),
7293 static const DWORD info_3[] =
7295 sizeof(JOB_INFO_3),
7299 switch (level)
7301 case 1: return info_1;
7302 case 2: return info_2;
7303 case 3: return info_3;
7306 SetLastError( ERROR_INVALID_LEVEL );
7307 return NULL;
7310 /*****************************************************************************
7311 * GetJobA [WINSPOOL.@]
7314 BOOL WINAPI GetJobA(HANDLE printer, DWORD job_id, DWORD level, BYTE *data,
7315 DWORD size, DWORD *needed)
7317 const DWORD *string_info = job_string_info(level);
7319 if (!string_info)
7320 return FALSE;
7322 if (!GetJobW(printer, job_id, level, data, size, needed))
7323 return FALSE;
7324 packed_struct_WtoA(data, string_info);
7325 if (level == 2)
7326 DEVMODEWtoA(((JOB_INFO_2W *)data)->pDevMode, ((JOB_INFO_2A *)data)->pDevMode);
7327 return TRUE;
7330 /*****************************************************************************
7331 * GetJobW [WINSPOOL.@]
7334 BOOL WINAPI GetJobW(HANDLE printer, DWORD job_id, DWORD level, BYTE *data,
7335 DWORD size, DWORD *needed)
7337 HANDLE handle = get_backend_handle(printer);
7339 TRACE("(%p, %ld, %ld, %p, %ld, %p)\n", printer, job_id, level, data, size, needed);
7341 if (!handle)
7343 SetLastError(ERROR_INVALID_HANDLE);
7344 return FALSE;
7347 return backend->fpGetJob(handle, job_id, level, data, size, needed);
7350 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7352 LPWSTR filename;
7354 switch(msg)
7356 case WM_INITDIALOG:
7357 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7358 return TRUE;
7360 case WM_COMMAND:
7361 if(HIWORD(wparam) == BN_CLICKED)
7363 if(LOWORD(wparam) == IDOK)
7365 HANDLE hf;
7366 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7367 LPWSTR *output;
7369 filename = malloc((len + 1) * sizeof(WCHAR));
7370 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7372 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7374 WCHAR caption[200], message[200];
7375 int mb_ret;
7377 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
7378 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, ARRAY_SIZE(message));
7379 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7380 if(mb_ret == IDCANCEL)
7382 free(filename);
7383 return TRUE;
7386 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7387 if(hf == INVALID_HANDLE_VALUE)
7389 WCHAR caption[200], message[200];
7391 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
7392 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, ARRAY_SIZE(message));
7393 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7394 free(filename);
7395 return TRUE;
7397 CloseHandle(hf);
7398 DeleteFileW(filename);
7399 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7400 *output = filename;
7401 EndDialog(hwnd, IDOK);
7402 return TRUE;
7404 if(LOWORD(wparam) == IDCANCEL)
7406 EndDialog(hwnd, IDCANCEL);
7407 return TRUE;
7410 return FALSE;
7412 return FALSE;
7415 /*****************************************************************************
7416 * get_filename
7418 static BOOL get_filename(LPWSTR *filename)
7420 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7421 file_dlg_proc, (LPARAM)filename) == IDOK;
7424 /*****************************************************************************
7425 * ScheduleJob [WINSPOOL.@]
7428 BOOL WINAPI ScheduleJob(HANDLE printer, DWORD job_id)
7430 HANDLE handle = get_backend_handle(printer);
7432 TRACE("(%p, %lx)\n", printer, job_id);
7434 if (!handle)
7436 SetLastError(ERROR_INVALID_HANDLE);
7437 return FALSE;
7440 return backend->fpScheduleJob(handle, job_id);
7443 /*****************************************************************************
7444 * StartDocDlgA [WINSPOOL.@]
7446 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7448 UNICODE_STRING usBuffer;
7449 DOCINFOW docW = { 0 };
7450 LPWSTR retW;
7451 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7452 LPSTR ret = NULL;
7454 docW.cbSize = sizeof(docW);
7455 if (doc->lpszDocName)
7457 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7458 if (!(docW.lpszDocName = docnameW)) goto failed;
7460 if (doc->lpszOutput)
7462 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7463 if (!(docW.lpszOutput = outputW)) goto failed;
7465 if (doc->lpszDatatype)
7467 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7468 if (!(docW.lpszDatatype = datatypeW)) goto failed;
7470 docW.fwType = doc->fwType;
7472 retW = StartDocDlgW(hPrinter, &docW);
7474 if(retW)
7476 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7477 ret = heap_alloc(len);
7478 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7479 heap_free(retW);
7482 failed:
7483 free(datatypeW);
7484 free(outputW);
7485 free(docnameW);
7487 return ret;
7490 static BOOL is_port(const WCHAR *port_list, const WCHAR *output)
7492 size_t len;
7494 if (!output)
7495 return FALSE;
7497 if (wcschr(output, ':'))
7498 return TRUE;
7500 len = wcslen(output);
7501 while (port_list && *port_list)
7503 if (!wcsncmp(output, port_list, len) && (!port_list[len] || port_list[len] == ','))
7504 return TRUE;
7506 port_list = wcschr(port_list, ',');
7507 if (port_list) port_list++;
7509 return FALSE;
7512 /*****************************************************************************
7513 * StartDocDlgW [WINSPOOL.@]
7515 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7516 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7517 * port is "FILE:". Also returns the full path if passed a relative path.
7519 * The caller should free the returned string from the process heap.
7521 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7523 PRINTER_INFO_5W *pi5;
7524 LPWSTR ret = NULL;
7525 DWORD len, attr;
7526 BOOL b;
7528 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7529 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7530 return NULL;
7531 pi5 = malloc(len);
7532 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7534 /* Check whether default port is FILE: */
7535 b = !doc->lpszOutput && (!pi5->pPortName || wcscmp( pi5->pPortName, L"FILE:" ));
7536 if (!b)
7537 b = is_port(pi5->pPortName, doc->lpszOutput);
7538 free(pi5);
7539 if (b)
7540 return NULL;
7542 if(doc->lpszOutput == NULL || !wcscmp( doc->lpszOutput, L"FILE:" ))
7544 LPWSTR name;
7546 if (get_filename(&name))
7548 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7550 free(name);
7551 return NULL;
7553 ret = heap_alloc(len * sizeof(WCHAR));
7554 GetFullPathNameW(name, len, ret, NULL);
7555 free(name);
7557 return ret;
7560 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7561 return NULL;
7563 ret = heap_alloc(len * sizeof(WCHAR));
7564 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7566 attr = GetFileAttributesW(ret);
7567 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7569 heap_free(ret);
7570 ret = NULL;
7572 return ret;
7575 /*****************************************************************************
7576 * UploadPrinterDriverPackageA [WINSPOOL.@]
7578 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
7579 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
7581 FIXME("%s, %s, %s, %lx, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
7582 flags, hwnd, dst, dstlen);
7583 return E_NOTIMPL;
7586 /*****************************************************************************
7587 * UploadPrinterDriverPackageW [WINSPOOL.@]
7589 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
7590 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
7592 FIXME("%s, %s, %s, %lx, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
7593 flags, hwnd, dst, dstlen);
7594 return E_NOTIMPL;
7597 /*****************************************************************************
7598 * PerfOpen [WINSPOOL.@]
7600 DWORD WINAPI PerfOpen(LPWSTR context)
7602 FIXME("%s: stub\n", debugstr_w(context));
7603 return ERROR_SUCCESS;
7606 /*****************************************************************************
7607 * PerfClose [WINSPOOL.@]
7609 DWORD WINAPI PerfClose(void)
7611 FIXME("stub\n");
7612 return ERROR_SUCCESS;
7615 /*****************************************************************************
7616 * PerfCollect [WINSPOOL.@]
7618 DWORD WINAPI PerfCollect(LPWSTR query, LPVOID *data, LPDWORD size, LPDWORD obj_count)
7620 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query), data, size, obj_count);
7621 *size = 0;
7622 *obj_count = 0;
7623 return ERROR_SUCCESS;
7626 /*****************************************************************************
7627 * GetSpoolFileHandle [WINSPOOL.@]
7629 HANDLE WINAPI GetSpoolFileHandle( HANDLE printer )
7631 FIXME( "%p: stub\n", printer );
7632 return INVALID_HANDLE_VALUE;
7635 /*****************************************************************************
7636 * SeekPrinter [WINSPOOL.@]
7638 BOOL WINAPI SeekPrinter(HANDLE printer, LARGE_INTEGER distance,
7639 LARGE_INTEGER *pos, DWORD method, BOOL bwrite)
7641 HANDLE handle = get_backend_handle(printer);
7643 TRACE("(%p %I64d %p %lx %x)\n", printer, distance.QuadPart, pos, method, bwrite);
7645 if (!handle)
7647 SetLastError(ERROR_INVALID_HANDLE);
7648 return FALSE;
7650 return backend->fpSeekPrinter(handle, distance, pos, method, bwrite);