server: Use a shared_object_t for the dummy object.
[wine.git] / dlls / winspool.drv / info.c
blob45521809f15a36f46a999db9b27f3854c319be24
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 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winuser.h"
38 #include "winerror.h"
39 #include "winreg.h"
40 #include "wingdi.h"
41 #include "winspool.h"
42 #include "winternl.h"
43 #include "winnls.h"
44 #include "wine/windef16.h"
45 #include "wine/debug.h"
46 #include "wine/list.h"
47 #include "wine/rbtree.h"
48 #include "wine/heap.h"
49 #include <wine/unixlib.h>
51 #include "ddk/compstui.h"
52 #include "ddk/winsplp.h"
53 #include "wspool.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
57 /* ############################### */
59 static CRITICAL_SECTION printer_handles_cs;
60 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
62 0, 0, &printer_handles_cs,
63 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
64 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
66 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
68 /* ############################### */
70 typedef struct {
71 LPWSTR name;
72 HANDLE backend_printer;
73 } opened_printer_t;
75 typedef struct {
76 LPCWSTR envname;
77 LPCWSTR subdir;
78 DWORD driverversion;
79 LPCWSTR versionregpath;
80 LPCWSTR versionsubdir;
81 } printenv_t;
83 typedef struct
85 struct wine_rb_entry entry;
86 HMODULE module;
87 LONG ref;
89 /* entry points */
90 DWORD (WINAPI *pDrvDeviceCapabilities)(HANDLE, const WCHAR *, WORD, void *, const DEVMODEW *);
91 LONG (WINAPI *pDrvDocumentPropertySheets)(PROPSHEETUI_INFO*, LPARAM);
93 WCHAR name[1];
94 } config_module_t;
96 typedef struct {
97 WORD cbSize;
98 WORD Reserved;
99 HANDLE hPrinter;
100 LPCWSTR pszPrinterName;
101 PDEVMODEW pdmIn;
102 PDEVMODEW pdmOut;
103 DWORD cbOut;
104 DWORD fMode;
105 } DOCUMENTPROPERTYHEADERW;
107 typedef struct {
108 DOCUMENTPROPERTYHEADERW dph;
109 config_module_t *config;
110 } document_property_t;
112 /* ############################### */
114 static opened_printer_t **printer_handles;
115 static UINT nb_printer_handles;
117 static const WCHAR * const May_Delete_Value = L"WineMayDeleteMe";
119 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
120 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
121 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
122 0, sizeof(DRIVER_INFO_8W)};
125 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
126 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
127 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
128 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
129 sizeof(PRINTER_INFO_9W)};
131 static const printenv_t env_x64 = { L"Windows x64", L"x64", 3, L"\\Version-3", L"\\3" };
132 static const printenv_t env_x86 = { L"Windows NT x86", L"w32x86", 3, L"\\Version-3", L"\\3" };
133 static const printenv_t env_arm = { L"Windows ARM", L"arm", 3, L"\\Version-3", L"\\3" };
134 static const printenv_t env_arm64 = { L"Windows ARM64", L"arm64", 3, L"\\Version-3", L"\\3" };
135 static const printenv_t env_win40 = { L"Windows 4.0", L"win40", 0, L"\\Version-0", L"\\0" };
137 static const printenv_t * const all_printenv[] = { &env_x86, &env_x64, &env_arm, &env_arm64, &env_win40 };
139 #ifdef __i386__
140 #define env_arch env_x86
141 #elif defined __x86_64__
142 #define env_arch env_x64
143 #elif defined __arm__
144 #define env_arch env_arm
145 #elif defined __aarch64__
146 #define env_arch env_arm64
147 #else
148 #error not defined for this cpu
149 #endif
151 /******************************************************************
152 * validate the user-supplied printing-environment [internal]
154 * PARAMS
155 * env [I] PTR to Environment-String or NULL
157 * RETURNS
158 * Failure: NULL
159 * Success: PTR to printenv_t
161 * NOTES
162 * An empty string is handled the same way as NULL.
163 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
167 static const printenv_t * validate_envW(LPCWSTR env)
169 const printenv_t *result = NULL;
170 unsigned int i;
172 TRACE("testing %s\n", debugstr_w(env));
173 if (env && env[0])
175 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
177 if (!wcsicmp( env, all_printenv[i]->envname ))
179 result = all_printenv[i];
180 break;
184 if (result == NULL) {
185 FIXME("unsupported Environment: %s\n", debugstr_w(env));
186 SetLastError(ERROR_INVALID_ENVIRONMENT);
188 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
190 else
192 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_arch;
194 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
196 return result;
200 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
201 if passed a NULL string. This returns NULLs to the result.
203 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
205 if ( (src) )
207 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
208 return usBufferPtr->Buffer;
210 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
211 return NULL;
214 /* stringWtoA
215 * Converts Unicode string to Ansi (possibly in place).
217 static void stringWtoA( const WCHAR *strW, char *strA, size_t size )
219 DWORD ret;
220 char *str;
222 str = (char *)strW == strA ? malloc( size ) : strA;
223 ret = WideCharToMultiByte( CP_ACP, 0, strW, -1, str, size, NULL, NULL );
224 if (str != strA)
226 memcpy( strA, str, ret );
227 free( str );
229 memset( strA + ret, 0, size - ret );
232 /***********************************************************
233 * DEVMODEWtoA
234 * Converts DEVMODEW to DEVMODEA (possibly in place).
235 * Allocates DEVMODEA if needed.
237 static DEVMODEA *DEVMODEWtoA( const DEVMODEW *dmW, DEVMODEA *dmA )
239 DWORD size, sizeW;
241 if (!dmW) return NULL;
242 sizeW = dmW->dmSize;
243 size = sizeW - CCHDEVICENAME -
244 ((sizeW > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
246 if (!dmA)
247 dmA = calloc( 1, size + dmW->dmDriverExtra );
248 if (!dmA) return NULL;
250 stringWtoA( dmW->dmDeviceName, (char *)dmA->dmDeviceName, CCHDEVICENAME );
252 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= sizeW)
254 memmove( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
255 sizeW - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
257 else
259 memmove( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
260 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
261 stringWtoA( dmW->dmFormName, (char *)dmA->dmFormName, CCHFORMNAME );
262 memmove( &dmA->dmLogPixels, &dmW->dmLogPixels, sizeW - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
265 dmA->dmSize = size;
266 memmove( (char *)dmA + dmA->dmSize, (const char *)dmW + sizeW, dmW->dmDriverExtra );
267 return dmA;
270 /*********************************************************************
271 * packed_struct_WtoA
273 * Convert a packed struct from W to A overwriting the unicode strings
274 * with their ansi equivalents.
276 static void packed_struct_WtoA( BYTE *data, const DWORD *string_info )
278 WCHAR *strW;
280 string_info++; /* sizeof */
281 while (*string_info != ~0u)
283 strW = *(WCHAR **)(data + *string_info);
284 if (strW) stringWtoA( strW, (char *)strW, (wcslen(strW) + 1) * sizeof(WCHAR) );
285 string_info++;
289 static inline const DWORD *form_string_info( DWORD level )
291 static const DWORD info_1[] =
293 sizeof( FORM_INFO_1W ),
294 FIELD_OFFSET( FORM_INFO_1W, pName ),
297 static const DWORD info_2[] =
299 sizeof( FORM_INFO_2W ),
300 FIELD_OFFSET( FORM_INFO_2W, pName ),
301 FIELD_OFFSET( FORM_INFO_2W, pMuiDll ),
302 FIELD_OFFSET( FORM_INFO_2W, pDisplayName ),
306 if (level == 1) return info_1;
307 if (level == 2) return info_2;
309 SetLastError( ERROR_INVALID_LEVEL );
310 return NULL;
313 /*****************************************************************************
314 * WINSPOOL_OpenDriverReg [internal]
316 * opens the registry for the printer drivers depending on the given input
317 * variable pEnvironment
319 * RETURNS:
320 * the opened hkey on success
321 * NULL on error
323 static HKEY WINSPOOL_OpenDriverReg(const void *pEnvironment)
325 HKEY retval = NULL;
326 LPWSTR buffer;
327 const printenv_t *env;
328 unsigned int len;
329 static const WCHAR driver_fmt[] = L"System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers%s";
331 TRACE("(%s)\n", debugstr_w(pEnvironment));
333 env = validate_envW(pEnvironment);
334 if (!env) return NULL;
336 len = ARRAY_SIZE( driver_fmt ) + wcslen( env->envname ) + wcslen( env->versionregpath );
337 buffer = malloc( len * sizeof(WCHAR) );
338 if (buffer)
340 swprintf( buffer, len, driver_fmt, env->envname, env->versionregpath );
341 RegCreateKeyW( HKEY_LOCAL_MACHINE, buffer, &retval );
342 free( buffer );
344 return retval;
347 enum printers_key
349 system_printers_key,
350 user_printers_key,
351 user_ports_key,
352 user_default_key,
355 static DWORD create_printers_reg_key( enum printers_key type, HKEY *key )
357 switch( type )
359 case system_printers_key:
360 return RegCreateKeyW( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Print\\Printers", key );
361 case user_printers_key:
362 return RegCreateKeyW( HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices", key );
363 case user_ports_key:
364 return RegCreateKeyW( HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\PrinterPorts", key );
365 case user_default_key:
366 return RegCreateKeyW( HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows", key );
368 return ERROR_PATH_NOT_FOUND;
371 static CRITICAL_SECTION config_modules_cs;
372 static CRITICAL_SECTION_DEBUG config_modules_cs_debug =
374 0, 0, &config_modules_cs,
375 { &config_modules_cs_debug.ProcessLocksList, &config_modules_cs_debug.ProcessLocksList },
376 0, 0, { (DWORD_PTR)(__FILE__ ": config_modules_cs") }
378 static CRITICAL_SECTION config_modules_cs = { &config_modules_cs_debug, -1, 0, 0, 0, 0 };
380 static int compare_config_modules(const void *key, const struct wine_rb_entry *entry)
382 config_module_t *module = WINE_RB_ENTRY_VALUE(entry, config_module_t, entry);
383 return wcsicmp( key, module->name );
386 static struct wine_rb_tree config_modules = { compare_config_modules };
388 static void release_config_module(config_module_t *config_module)
390 if (InterlockedDecrement(&config_module->ref)) return;
391 FreeLibrary(config_module->module);
392 free(config_module);
395 static config_module_t *get_config_module(const WCHAR *device, BOOL grab)
397 WCHAR driver_name[100], driver[MAX_PATH];
398 DWORD size, len;
399 HKEY printers_key, printer_key, drivers_key, driver_key;
400 HMODULE driver_module;
401 config_module_t *ret = NULL;
402 struct wine_rb_entry *entry;
403 DWORD r, type;
404 LSTATUS res;
406 EnterCriticalSection(&config_modules_cs);
407 entry = wine_rb_get(&config_modules, device);
408 if (entry) {
409 ret = WINE_RB_ENTRY_VALUE(entry, config_module_t, entry);
410 if (grab) InterlockedIncrement(&ret->ref);
411 goto ret;
413 if (!grab) goto ret;
415 if (create_printers_reg_key(system_printers_key, &printers_key))
417 ERR("Can't create Printers key\n");
418 goto ret;
421 r = RegOpenKeyW(printers_key, device, &printer_key);
422 RegCloseKey(printers_key);
423 if (r)
425 WARN("Device %s key not found\n", debugstr_w(device));
426 goto ret;
429 size = sizeof(driver_name);
430 r = RegQueryValueExW(printer_key, L"Printer Driver", 0, &type, (BYTE *)driver_name, &size);
431 RegCloseKey(printer_key);
432 if (r || type != REG_SZ)
434 WARN("Can't get Printer Driver name\n");
435 goto ret;
438 if (!(drivers_key = WINSPOOL_OpenDriverReg(NULL))) goto ret;
440 res = RegOpenKeyW(drivers_key, driver_name, &driver_key);
441 RegCloseKey(drivers_key);
442 if (res) {
443 WARN("Driver %s key not found\n", debugstr_w(driver_name));
444 goto ret;
447 size = sizeof(driver);
448 if (!GetPrinterDriverDirectoryW(NULL, NULL, 1, (LPBYTE)driver, size, &size)) goto ret;
450 len = size / sizeof(WCHAR) - 1;
451 driver[len++] = '\\';
452 driver[len++] = '3';
453 driver[len++] = '\\';
454 size = sizeof(driver) - len * sizeof(WCHAR);
455 res = RegQueryValueExW( driver_key, L"Configuration File", NULL, &type,
456 (BYTE *)(driver + len), &size );
457 RegCloseKey(driver_key);
458 if (res || type != REG_SZ) {
459 WARN("no configuration file: %lu\n", res);
460 goto ret;
463 if (!(driver_module = LoadLibraryW(driver))) {
464 WARN("Could not load %s\n", debugstr_w(driver));
465 goto ret;
468 len = wcslen( device );
469 if (!(ret = malloc(FIELD_OFFSET(config_module_t, name[len + 1]))))
470 goto ret;
472 ret->ref = 2; /* one for config_module and one for the caller */
473 ret->module = driver_module;
474 ret->pDrvDeviceCapabilities = (void *)GetProcAddress(driver_module, "DrvDeviceCapabilities");
475 ret->pDrvDocumentPropertySheets = (void *)GetProcAddress(driver_module, "DrvDocumentPropertySheets");
476 wcscpy( ret->name, device );
478 wine_rb_put(&config_modules, ret->name, &ret->entry);
479 ret:
480 LeaveCriticalSection(&config_modules_cs);
481 return ret;
484 /* ################################ */
486 static int multi_sz_lenA(const char *str)
488 const char *ptr = str;
489 if(!str) return 0;
492 ptr += strlen( ptr ) + 1;
493 } while(*ptr);
495 return ptr - str + 1;
498 /*****************************************************************************
499 * get_dword_from_reg
501 * Return DWORD associated with name from hkey.
503 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
505 DWORD sz = sizeof(DWORD), type, value = 0;
506 LONG ret;
508 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
510 if (ret != ERROR_SUCCESS)
512 WARN( "Got ret = %ld on name %s\n", ret, debugstr_w(name) );
513 return 0;
515 if (type != REG_DWORD)
517 ERR( "Got type %ld\n", type );
518 return 0;
520 return value;
523 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
525 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
528 /******************************************************************
529 * get_opened_printer
530 * Get the pointer to the opened printer referred by the handle
532 static opened_printer_t *get_opened_printer(HANDLE hprn)
534 UINT_PTR idx = (UINT_PTR)hprn;
535 opened_printer_t *ret = NULL;
537 EnterCriticalSection(&printer_handles_cs);
539 if ((idx > 0) && (idx <= nb_printer_handles)) {
540 ret = printer_handles[idx - 1];
542 LeaveCriticalSection(&printer_handles_cs);
543 return ret;
546 /******************************************************************
547 * get_opened_printer_name
548 * Get the pointer to the opened printer name referred by the handle
550 static LPCWSTR get_opened_printer_name(HANDLE hprn)
552 opened_printer_t *printer = get_opened_printer(hprn);
553 if(!printer) return NULL;
554 return printer->name;
557 static HANDLE get_backend_handle( HANDLE hprn )
559 opened_printer_t *printer = get_opened_printer( hprn );
560 if (!printer) return NULL;
561 return printer->backend_printer;
564 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
566 HKEY printers;
567 DWORD err;
569 *key = NULL;
570 err = create_printers_reg_key( system_printers_key, &printers );
571 if (err) return err;
573 err = RegOpenKeyW( printers, name, key );
574 if (err) err = ERROR_INVALID_PRINTER_NAME;
575 RegCloseKey( printers );
576 return err;
579 /******************************************************************
580 * WINSPOOL_GetOpenedPrinterRegKey
583 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
585 LPCWSTR name = get_opened_printer_name(hPrinter);
587 if(!name) return ERROR_INVALID_HANDLE;
588 return open_printer_reg_key( name, phkey );
591 static BOOL get_internal_fallback_ppd( const WCHAR *ppd )
593 char *ptr, *end;
594 DWORD size, written;
595 HANDLE file;
596 BOOL ret;
597 HRSRC res = FindResourceW( WINSPOOL_hInstance, MAKEINTRESOURCEW(1), L"PPDFILE" );
599 if (!res || !(ptr = LoadResource( WINSPOOL_hInstance, res ))) return FALSE;
600 size = SizeofResource( WINSPOOL_hInstance, res );
601 end = memchr( ptr, 0, size ); /* resource file may contain additional nulls */
602 if (end) size = end - ptr;
603 file = CreateFileW( ppd, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
604 if (file == INVALID_HANDLE_VALUE) return FALSE;
605 ret = WriteFile( file, ptr, size, &written, NULL ) && written == size;
606 CloseHandle( file );
607 if (ret) TRACE( "using internal fallback for %s\n", debugstr_w( ppd ));
608 else DeleteFileW( ppd );
609 return ret;
612 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
614 static const WCHAR dot_ppd[] = L".ppd";
615 static const WCHAR invalid_chars[] = L"*?<>|\"/\\";
616 int dir_len = wcslen( dir ), file_len = wcslen( file_name );
617 int len = (dir_len + file_len + ARRAY_SIZE( dot_ppd )) * sizeof(WCHAR);
618 WCHAR *ppd = malloc( len ), *p;
620 if (!ppd) return NULL;
621 memcpy( ppd, dir, dir_len * sizeof(WCHAR) );
622 memcpy( ppd + dir_len, file_name, file_len * sizeof(WCHAR) );
623 memcpy( ppd + dir_len + file_len, dot_ppd, sizeof(dot_ppd) );
625 p = ppd + dir_len;
626 while ((p = wcspbrk( p, invalid_chars ))) *p++ = '_';
628 return ppd;
631 static BOOL add_printer_driver( const WCHAR *name, const WCHAR *ppd_dir )
633 WCHAR *ppd = get_ppd_filename( ppd_dir, name );
634 struct get_ppd_params ppd_params;
635 UNICODE_STRING nt_ppd = { .Buffer = NULL };
636 DRIVER_INFO_3W di3;
637 unsigned int i;
638 BOOL res = FALSE;
639 WCHAR raw[] = L"RAW", driver_nt[] = L"wineps.drv", driver_9x[] = L"wineps16.drv";
641 if (!ppd) return FALSE;
642 if (!RtlDosPathNameToNtPathName_U( ppd, &nt_ppd, NULL, NULL )) goto end;
644 ppd_params.printer = name;
645 ppd_params.ppd = nt_ppd.Buffer;
646 res = !UNIX_CALL( get_ppd, &ppd_params ) || get_internal_fallback_ppd( ppd );
647 if (!res) goto end;
649 AddPrintProcessorW(NULL, NULL, driver_nt, (WCHAR *)L"wineps");
651 memset( &di3, 0, sizeof(DRIVER_INFO_3W) );
652 di3.cVersion = 3;
653 di3.pName = (WCHAR *)name;
654 di3.pDriverPath = driver_nt;
655 di3.pDataFile = ppd;
656 di3.pConfigFile = driver_nt;
657 di3.pDefaultDataType = raw;
659 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
661 di3.pEnvironment = (WCHAR *)all_printenv[i]->envname;
662 if (all_printenv[i]->driverversion == 0)
664 /* We use wineps16.drv as driver for 16 bit */
665 di3.pDriverPath = driver_9x;
666 di3.pConfigFile = driver_9x;
668 res = AddPrinterDriverExW( NULL, 3, (BYTE *)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY );
669 TRACE( "got %d and %ld for %s (%s)\n", res, GetLastError(), debugstr_w( name ), debugstr_w( di3.pEnvironment ) );
671 if (!res && (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED))
673 ERR( "failed with %lu for %s (%s) %s\n", GetLastError(), debugstr_w( name ),
674 debugstr_w( di3.pEnvironment ), debugstr_w( di3.pDriverPath ) );
675 break;
677 res = TRUE;
679 ppd_params.printer = NULL; /* unlink the ppd */
680 UNIX_CALL( get_ppd, &ppd_params );
682 end:
683 RtlFreeUnicodeString( &nt_ppd );
684 free( ppd );
685 return res;
688 static WCHAR *get_ppd_dir( void )
690 static const WCHAR wine_ppds[] = L"wine_ppds\\";
691 DWORD len;
692 WCHAR *dir, tmp_path[MAX_PATH];
693 BOOL res;
695 len = GetTempPathW( ARRAY_SIZE( tmp_path ), tmp_path );
696 if (!len) return NULL;
697 dir = malloc( len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
698 if (!dir) return NULL;
700 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
701 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
702 res = CreateDirectoryW( dir, NULL );
703 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
705 free( dir );
706 dir = NULL;
708 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
709 return dir;
712 static BOOL init_unix_printers( void )
714 WCHAR *port, *ppd_dir = NULL, *default_printer = NULL;
715 unsigned int size, num;
716 struct enum_printers_params enum_params = { NULL, &size, &num };
717 HKEY printer_key, printers_key;
718 HANDLE added_printer;
719 PRINTER_INFO_2W pi2;
720 NTSTATUS status;
721 WCHAR raw[] = L"RAW", wineps[] = L"wineps", empty[] = L"";
722 int i;
724 if (create_printers_reg_key( system_printers_key, &printers_key ))
726 ERR( "Can't create Printers key\n" );
727 return FALSE;
730 size = 10000;
733 size *= 2;
734 free( enum_params.printers );
735 enum_params.printers = malloc( size );
736 status = UNIX_CALL( enum_printers, &enum_params );
737 } while (status == STATUS_BUFFER_OVERFLOW);
738 if (status) goto end;
740 TRACE( "Found %d CUPS %s:\n", num, (num == 1) ? "printer" : "printers" );
741 for (i = 0; i < num; i++)
743 struct printer_info *printer = enum_params.printers + i;
745 if (RegOpenKeyW( printers_key, printer->name, &printer_key ) == ERROR_SUCCESS)
747 DWORD status = get_dword_from_reg( printer_key, L"Status" );
748 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
749 and continue */
750 TRACE("Printer already exists\n");
751 RegDeleteValueW( printer_key, May_Delete_Value );
752 /* flag that the PPD file should be checked for an update */
753 set_reg_DWORD( printer_key, L"Status", status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
754 RegSetValueExW( printer_key, L"Print Processor", 0, REG_SZ, (const BYTE*)wineps,
755 (wcslen( wineps ) + 1) * sizeof(WCHAR));
756 RegCloseKey( printer_key );
758 else
760 if (!ppd_dir && !(ppd_dir = get_ppd_dir())) break;
761 if (!add_printer_driver( printer->name, ppd_dir )) continue;
763 port = malloc( sizeof(L"CUPS:") + wcslen( printer->name ) * sizeof(WCHAR) );
764 wcscpy( port, L"CUPS:" );
765 wcscat( port, printer->name );
767 memset( &pi2, 0, sizeof(PRINTER_INFO_2W) );
768 pi2.pPrinterName = printer->name;
769 pi2.pDatatype = raw;
770 pi2.pPrintProcessor = wineps;
771 pi2.pDriverName = printer->name;
772 pi2.pComment = printer->comment;
773 pi2.pLocation = printer->location;
774 pi2.pPortName = port;
775 pi2.pParameters = empty;
776 pi2.pShareName = empty;
777 pi2.pSepFile = empty;
779 added_printer = AddPrinterW( NULL, 2, (BYTE *)&pi2 );
780 if (added_printer) ClosePrinter( added_printer );
781 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
782 ERR( "printer '%s' not added by AddPrinter (error %ld)\n", debugstr_w( printer->name ), GetLastError() );
784 free( port );
786 if (printer->is_default) default_printer = printer->name;
789 if (!default_printer && num) default_printer = enum_params.printers[0].name;
790 if (default_printer) SetDefaultPrinterW( default_printer );
792 if (ppd_dir)
794 RemoveDirectoryW( ppd_dir );
795 free( ppd_dir );
797 end:
798 free( enum_params.printers );
799 RegCloseKey( printers_key );
800 return TRUE;
803 static void set_ppd_overrides( HANDLE printer )
805 WCHAR buffer[256];
806 unsigned int name_size = sizeof(buffer);
807 struct get_default_page_size_params params = { .name = buffer, .name_size = &name_size };
808 NTSTATUS status;
810 while (1)
812 status = UNIX_CALL( get_default_page_size, &params );
813 if (status != STATUS_BUFFER_OVERFLOW) break;
814 if (params.name != buffer) free( params.name );
815 params.name = malloc( name_size );
816 if (!params.name) break;
818 if (!status) SetPrinterDataExW( printer, L"PPD Overrides", L"DefaultPageSize", REG_SZ, (BYTE*)params.name, name_size );
819 if (params.name != buffer) free( params.name );
822 static BOOL update_driver( HANDLE printer )
824 BOOL ret;
825 const WCHAR *name = get_opened_printer_name( printer );
826 WCHAR *ppd_dir;
828 if (!name) return FALSE;
829 if (!(ppd_dir = get_ppd_dir())) return FALSE;
831 TRACE( "updating driver %s\n", debugstr_w( name ) );
832 ret = add_printer_driver( name, ppd_dir );
834 free( ppd_dir );
836 set_ppd_overrides( printer );
838 /* call into the driver to update the devmode */
839 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
841 return ret;
844 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
846 if (value)
847 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
848 (wcslen( value ) + 1) * sizeof(WCHAR));
849 else
850 return ERROR_FILE_NOT_FOUND;
853 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
855 DEVMODEA *dmA = DEVMODEWtoA( dm, NULL );
856 DWORD ret = ERROR_FILE_NOT_FOUND;
858 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
859 and we support these drivers. NT writes DEVMODEW so somehow
860 we'll need to distinguish between these when we support NT
861 drivers */
863 if (dmA)
865 ret = RegSetValueExW( key, name, 0, REG_BINARY,
866 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
867 free( dmA );
870 return ret;
873 /******************************************************************
874 * get_servername_from_name (internal)
876 * for an external server, a copy of the serverpart from the full name is returned
879 static LPWSTR get_servername_from_name(LPCWSTR name)
881 LPWSTR server;
882 LPWSTR ptr;
883 WCHAR buffer[MAX_PATH];
884 DWORD len;
886 if (name == NULL) return NULL;
887 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
889 server = wcsdup(&name[2]); /* skip over both backslashes */
890 if (server == NULL) return NULL;
892 /* strip '\' and the printername */
893 ptr = wcschr( server, '\\' );
894 if (ptr) ptr[0] = '\0';
896 TRACE("found %s\n", debugstr_w(server));
898 len = ARRAY_SIZE(buffer);
899 if (GetComputerNameW(buffer, &len))
901 if (!wcscmp( buffer, server ))
903 /* The requested Servername is our computername */
904 free(server);
905 return NULL;
908 return server;
911 /******************************************************************
912 * get_basename_from_name (internal)
914 * skip over the serverpart from the full name
917 static LPCWSTR get_basename_from_name(LPCWSTR name)
919 if (name == NULL) return NULL;
920 if ((name[0] == '\\') && (name[1] == '\\'))
922 /* skip over the servername and search for the following '\' */
923 name = wcschr( &name[2], '\\' );
924 if ((name) && (name[1]))
926 /* found a separator ('\') followed by a name:
927 skip over the separator and return the rest */
928 name++;
930 else
932 /* no basename present (we found only a servername) */
933 return NULL;
936 return name;
939 static void free_printer_entry( opened_printer_t *printer )
941 /* the queue is shared, so don't free that here */
942 free( printer->name );
943 free( printer );
946 /******************************************************************
947 * get_opened_printer_entry
948 * Get the first place empty in the opened printer table
950 * ToDo:
951 * - pDefault is ignored
953 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
955 opened_printer_t *printer = NULL;
956 LPWSTR servername;
957 LPCWSTR printername;
958 UINT_PTR handle;
960 if ((backend == NULL) && !load_backend()) return NULL;
962 servername = get_servername_from_name(name);
963 if (servername) {
964 FIXME("server %s not supported\n", debugstr_w(servername));
965 free(servername);
966 SetLastError(ERROR_INVALID_PRINTER_NAME);
967 return NULL;
970 printername = get_basename_from_name(name);
971 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
973 /* an empty printername is invalid */
974 if (printername && (!printername[0])) {
975 SetLastError(ERROR_INVALID_PARAMETER);
976 return NULL;
979 EnterCriticalSection(&printer_handles_cs);
981 for (handle = 0; handle < nb_printer_handles; handle++)
983 if (!printer_handles[handle])
984 break;
987 if (handle >= nb_printer_handles)
989 opened_printer_t **new_array;
990 if (printer_handles)
992 new_array = realloc(printer_handles, (nb_printer_handles + 16) * sizeof(*new_array));
993 memset(new_array + nb_printer_handles, 0, 16 * sizeof(*new_array));
995 else
997 new_array = calloc(nb_printer_handles + 16, sizeof(*new_array));
1000 if (!new_array)
1002 handle = 0;
1003 goto end;
1005 printer_handles = new_array;
1006 nb_printer_handles += 16;
1009 if (!(printer = calloc(1, sizeof(*printer))))
1011 handle = 0;
1012 goto end;
1015 /* get a printer handle from the backend */
1016 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1017 handle = 0;
1018 goto end;
1021 /* clone the full name */
1022 printer->name = wcsdup(name);
1023 if (name && (!printer->name)) {
1024 handle = 0;
1025 goto end;
1028 printer_handles[handle] = printer;
1029 handle++;
1030 end:
1031 LeaveCriticalSection(&printer_handles_cs);
1032 if (!handle && printer)
1033 free_printer_entry( printer );
1035 return (HANDLE)handle;
1038 static void old_printer_check( BOOL delete_phase )
1040 PRINTER_INFO_5W* pi;
1041 DWORD needed, type, num, delete, i, size;
1042 const DWORD one = 1;
1043 HKEY key;
1044 HANDLE hprn;
1046 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1047 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1049 pi = malloc( needed );
1050 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1051 for (i = 0; i < num; i++)
1053 if (!pi[i].pPortName) continue;
1055 if (wcsncmp( pi[i].pPortName, L"CUPS:", ARRAY_SIZE(L"CUPS:") - 1 ) &&
1056 wcsncmp( pi[i].pPortName, L"LPR:", ARRAY_SIZE(L"LPR:") - 1 ))
1057 continue;
1059 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1061 if (!delete_phase)
1063 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1064 RegCloseKey( key );
1066 else
1068 delete = 0;
1069 size = sizeof( delete );
1070 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1071 RegCloseKey( key );
1072 if (delete)
1074 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1075 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1077 DeletePrinter( hprn );
1078 ClosePrinter( hprn );
1080 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1084 free(pi);
1087 static HANDLE init_mutex;
1089 void WINSPOOL_LoadSystemPrinters(void)
1091 HKEY printers_key, printer_key;
1092 DWORD needed, num, i;
1093 WCHAR PrinterName[256];
1095 /* FIXME: The init code should be moved to spoolsv.exe */
1096 init_mutex = CreateMutexW( NULL, TRUE, L"__WINE_WINSPOOL_MUTEX__" );
1097 if (!init_mutex)
1099 ERR( "Failed to create mutex\n" );
1100 return;
1102 if (GetLastError() == ERROR_ALREADY_EXISTS)
1104 WaitForSingleObject( init_mutex, INFINITE );
1105 ReleaseMutex( init_mutex );
1106 TRACE( "Init already done\n" );
1107 return;
1110 /* This ensures that all printer entries have a valid Name value. If causes
1111 problems later if they don't. If one is found to be missed we create one
1112 and set it equal to the name of the key */
1113 if (!create_printers_reg_key( system_printers_key, &printers_key ))
1115 if (!RegQueryInfoKeyW( printers_key, NULL, NULL, NULL, &num, NULL, NULL, NULL, NULL, NULL, NULL, NULL ))
1116 for (i = 0; i < num; i++)
1117 if (!RegEnumKeyW( printers_key, i, PrinterName, ARRAY_SIZE(PrinterName) ))
1118 if (!RegOpenKeyW( printers_key, PrinterName, &printer_key ))
1120 if (RegQueryValueExW( printer_key, L"Name", 0, 0, 0, &needed ) == ERROR_FILE_NOT_FOUND)
1121 set_reg_szW( printer_key, L"Name", PrinterName );
1122 RegCloseKey( printer_key );
1124 RegCloseKey( printers_key );
1127 old_printer_check( FALSE );
1128 init_unix_printers();
1129 old_printer_check( TRUE );
1131 ReleaseMutex( init_mutex );
1132 return;
1135 /******************************************************************
1136 * convert_printerinfo_W_to_A [internal]
1139 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1140 DWORD level, DWORD outlen, DWORD numentries)
1142 DWORD id = 0;
1143 LPSTR ptr;
1144 INT len;
1146 TRACE("(%p, %p, %ld, %lu, %lu)\n", out, pPrintersW, level, outlen, numentries);
1148 len = pi_sizeof[level] * numentries;
1149 ptr = (LPSTR) out + len;
1150 outlen -= len;
1152 /* copy the numbers of all PRINTER_INFO_* first */
1153 memcpy(out, pPrintersW, len);
1155 while (id < numentries) {
1156 switch (level) {
1157 case 1:
1159 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1160 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1162 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(piW->pName));
1163 if (piW->pDescription) {
1164 piA->pDescription = ptr;
1165 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1166 ptr, outlen, NULL, NULL);
1167 ptr += len;
1168 outlen -= len;
1170 if (piW->pName) {
1171 piA->pName = ptr;
1172 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1173 ptr, outlen, NULL, NULL);
1174 ptr += len;
1175 outlen -= len;
1177 if (piW->pComment) {
1178 piA->pComment = ptr;
1179 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1180 ptr, outlen, NULL, NULL);
1181 ptr += len;
1182 outlen -= len;
1184 break;
1187 case 2:
1189 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1190 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1192 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(piW->pPrinterName));
1193 if (piW->pServerName) {
1194 piA->pServerName = ptr;
1195 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1196 ptr, outlen, NULL, NULL);
1197 ptr += len;
1198 outlen -= len;
1200 if (piW->pPrinterName) {
1201 piA->pPrinterName = ptr;
1202 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1203 ptr, outlen, NULL, NULL);
1204 ptr += len;
1205 outlen -= len;
1207 if (piW->pShareName) {
1208 piA->pShareName = ptr;
1209 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1210 ptr, outlen, NULL, NULL);
1211 ptr += len;
1212 outlen -= len;
1214 if (piW->pPortName) {
1215 piA->pPortName = ptr;
1216 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1217 ptr, outlen, NULL, NULL);
1218 ptr += len;
1219 outlen -= len;
1221 if (piW->pDriverName) {
1222 piA->pDriverName = ptr;
1223 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1224 ptr, outlen, NULL, NULL);
1225 ptr += len;
1226 outlen -= len;
1228 if (piW->pComment) {
1229 piA->pComment = ptr;
1230 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1231 ptr, outlen, NULL, NULL);
1232 ptr += len;
1233 outlen -= len;
1235 if (piW->pLocation) {
1236 piA->pLocation = ptr;
1237 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1238 ptr, outlen, NULL, NULL);
1239 ptr += len;
1240 outlen -= len;
1243 if (piW->pDevMode)
1245 /* align DEVMODEA to a DWORD boundary */
1246 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1247 ptr += len;
1248 outlen -= len;
1250 piA->pDevMode = (LPDEVMODEA) ptr;
1251 DEVMODEWtoA(piW->pDevMode, piA->pDevMode);
1252 len = piA->pDevMode->dmSize + piA->pDevMode->dmDriverExtra;
1254 ptr += len;
1255 outlen -= len;
1258 if (piW->pSepFile) {
1259 piA->pSepFile = ptr;
1260 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1261 ptr, outlen, NULL, NULL);
1262 ptr += len;
1263 outlen -= len;
1265 if (piW->pPrintProcessor) {
1266 piA->pPrintProcessor = ptr;
1267 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1268 ptr, outlen, NULL, NULL);
1269 ptr += len;
1270 outlen -= len;
1272 if (piW->pDatatype) {
1273 piA->pDatatype = ptr;
1274 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1275 ptr, outlen, NULL, NULL);
1276 ptr += len;
1277 outlen -= len;
1279 if (piW->pParameters) {
1280 piA->pParameters = ptr;
1281 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1282 ptr, outlen, NULL, NULL);
1283 ptr += len;
1284 outlen -= len;
1286 if (piW->pSecurityDescriptor) {
1287 piA->pSecurityDescriptor = NULL;
1288 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1290 break;
1293 case 4:
1295 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1296 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1298 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(piW->pPrinterName));
1300 if (piW->pPrinterName) {
1301 piA->pPrinterName = ptr;
1302 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1303 ptr, outlen, NULL, NULL);
1304 ptr += len;
1305 outlen -= len;
1307 if (piW->pServerName) {
1308 piA->pServerName = ptr;
1309 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1310 ptr, outlen, NULL, NULL);
1311 ptr += len;
1312 outlen -= len;
1314 break;
1317 case 5:
1319 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1320 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1322 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(piW->pPrinterName));
1324 if (piW->pPrinterName) {
1325 piA->pPrinterName = ptr;
1326 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1327 ptr, outlen, NULL, NULL);
1328 ptr += len;
1329 outlen -= len;
1331 if (piW->pPortName) {
1332 piA->pPortName = ptr;
1333 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1334 ptr, outlen, NULL, NULL);
1335 ptr += len;
1336 outlen -= len;
1338 break;
1341 case 6: /* 6A and 6W are the same structure */
1342 break;
1344 case 7:
1346 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1347 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1349 TRACE("(%lu) #%lu\n", level, id);
1350 if (piW->pszObjectGUID) {
1351 piA->pszObjectGUID = ptr;
1352 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1353 ptr, outlen, NULL, NULL);
1354 ptr += len;
1355 outlen -= len;
1357 break;
1360 case 8:
1361 case 9:
1363 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1364 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1366 TRACE("(%lu) #%lu\n", level, id);
1367 if (piW->pDevMode)
1369 /* align DEVMODEA to a DWORD boundary */
1370 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1371 ptr += len;
1372 outlen -= len;
1374 piA->pDevMode = (LPDEVMODEA) ptr;
1375 DEVMODEWtoA(piW->pDevMode, piA->pDevMode);
1376 len = piA->pDevMode->dmSize + piA->pDevMode->dmDriverExtra;
1378 ptr += len;
1379 outlen -= len;
1381 break;
1384 default:
1385 FIXME("for level %lu\n", level);
1387 pPrintersW += pi_sizeof[level];
1388 out += pi_sizeof[level];
1389 id++;
1393 /******************************************************************
1394 * convert_driverinfo_W_to_A [internal]
1397 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1398 DWORD level, DWORD outlen, DWORD numentries)
1400 DWORD id = 0;
1401 LPSTR ptr;
1402 INT len;
1404 TRACE("(%p, %p, %ld, %lu, %lu)\n", out, pDriversW, level, outlen, numentries);
1406 len = di_sizeof[level] * numentries;
1407 ptr = (LPSTR) out + len;
1408 outlen -= len;
1410 /* copy the numbers of all PRINTER_INFO_* first */
1411 memcpy(out, pDriversW, len);
1413 #define COPY_STRING(fld) \
1414 { if (diW->fld){ \
1415 diA->fld = ptr; \
1416 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1417 ptr += len; outlen -= len;\
1419 #define COPY_MULTIZ_STRING(fld) \
1420 { LPWSTR p = diW->fld; if (p){ \
1421 diA->fld = ptr; \
1422 do {\
1423 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1424 ptr += len; outlen -= len; p += len;\
1426 while(len > 1 && outlen > 0); \
1429 while (id < numentries)
1431 switch (level)
1433 case 1:
1435 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1436 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1438 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1440 COPY_STRING(pName);
1441 break;
1443 case 2:
1445 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1446 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1448 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1450 COPY_STRING(pName);
1451 COPY_STRING(pEnvironment);
1452 COPY_STRING(pDriverPath);
1453 COPY_STRING(pDataFile);
1454 COPY_STRING(pConfigFile);
1455 break;
1457 case 3:
1459 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1460 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1462 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1464 COPY_STRING(pName);
1465 COPY_STRING(pEnvironment);
1466 COPY_STRING(pDriverPath);
1467 COPY_STRING(pDataFile);
1468 COPY_STRING(pConfigFile);
1469 COPY_STRING(pHelpFile);
1470 COPY_MULTIZ_STRING(pDependentFiles);
1471 COPY_STRING(pMonitorName);
1472 COPY_STRING(pDefaultDataType);
1473 break;
1475 case 4:
1477 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1478 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1480 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1482 COPY_STRING(pName);
1483 COPY_STRING(pEnvironment);
1484 COPY_STRING(pDriverPath);
1485 COPY_STRING(pDataFile);
1486 COPY_STRING(pConfigFile);
1487 COPY_STRING(pHelpFile);
1488 COPY_MULTIZ_STRING(pDependentFiles);
1489 COPY_STRING(pMonitorName);
1490 COPY_STRING(pDefaultDataType);
1491 COPY_MULTIZ_STRING(pszzPreviousNames);
1492 break;
1494 case 5:
1496 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1497 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1499 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1501 COPY_STRING(pName);
1502 COPY_STRING(pEnvironment);
1503 COPY_STRING(pDriverPath);
1504 COPY_STRING(pDataFile);
1505 COPY_STRING(pConfigFile);
1506 break;
1508 case 6:
1510 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1511 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1513 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1515 COPY_STRING(pName);
1516 COPY_STRING(pEnvironment);
1517 COPY_STRING(pDriverPath);
1518 COPY_STRING(pDataFile);
1519 COPY_STRING(pConfigFile);
1520 COPY_STRING(pHelpFile);
1521 COPY_MULTIZ_STRING(pDependentFiles);
1522 COPY_STRING(pMonitorName);
1523 COPY_STRING(pDefaultDataType);
1524 COPY_MULTIZ_STRING(pszzPreviousNames);
1525 COPY_STRING(pszMfgName);
1526 COPY_STRING(pszOEMUrl);
1527 COPY_STRING(pszHardwareID);
1528 COPY_STRING(pszProvider);
1529 break;
1531 case 8:
1533 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1534 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1536 TRACE("(%lu) #%lu: %s\n", level, id, debugstr_w(diW->pName));
1538 COPY_STRING(pName);
1539 COPY_STRING(pEnvironment);
1540 COPY_STRING(pDriverPath);
1541 COPY_STRING(pDataFile);
1542 COPY_STRING(pConfigFile);
1543 COPY_STRING(pHelpFile);
1544 COPY_MULTIZ_STRING(pDependentFiles);
1545 COPY_STRING(pMonitorName);
1546 COPY_STRING(pDefaultDataType);
1547 COPY_MULTIZ_STRING(pszzPreviousNames);
1548 COPY_STRING(pszMfgName);
1549 COPY_STRING(pszOEMUrl);
1550 COPY_STRING(pszHardwareID);
1551 COPY_STRING(pszProvider);
1552 COPY_STRING(pszPrintProcessor);
1553 COPY_STRING(pszVendorSetup);
1554 COPY_MULTIZ_STRING(pszzColorProfiles);
1555 COPY_STRING(pszInfPath);
1556 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1557 break;
1561 default:
1562 FIXME("for level %lu\n", level);
1565 pDriversW += di_sizeof[level];
1566 out += di_sizeof[level];
1567 id++;
1570 #undef COPY_STRING
1571 #undef COPY_MULTIZ_STRING
1575 /***********************************************************
1576 * printer_info_AtoW
1578 static void *printer_info_AtoW( const void *data, DWORD level )
1580 void *ret;
1581 UNICODE_STRING usBuffer;
1583 if (!data) return NULL;
1585 if (level < 1 || level > 9) return NULL;
1587 ret = malloc( pi_sizeof[level] );
1588 if (!ret) return NULL;
1590 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1592 switch (level)
1594 case 2:
1596 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1597 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1599 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1600 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1601 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1602 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1603 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1604 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1605 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1606 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1607 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1608 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1609 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1610 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1611 break;
1614 case 8:
1615 case 9:
1617 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1618 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1620 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1621 break;
1624 default:
1625 FIXME( "Unhandled level %ld\n", level );
1626 free( ret );
1627 return NULL;
1630 return ret;
1633 /***********************************************************
1634 * free_printer_info
1636 static void free_printer_info( void *data, DWORD level )
1638 if (!data) return;
1640 switch (level)
1642 case 2:
1644 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1646 free( piW->pServerName );
1647 free( piW->pPrinterName );
1648 free( piW->pShareName );
1649 free( piW->pPortName );
1650 free( piW->pDriverName );
1651 free( piW->pComment );
1652 free( piW->pLocation );
1653 heap_free( piW->pDevMode );
1654 free( piW->pSepFile );
1655 free( piW->pPrintProcessor );
1656 free( piW->pDatatype );
1657 free( piW->pParameters );
1658 break;
1661 case 8:
1662 case 9:
1664 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1666 heap_free( piW->pDevMode );
1667 break;
1670 default:
1671 FIXME( "Unhandled level %ld\n", level );
1674 free( data );
1675 return;
1678 /******************************************************************
1679 * DeviceCapabilities [WINSPOOL.@]
1680 * DeviceCapabilitiesA [WINSPOOL.@]
1683 INT WINAPI DeviceCapabilitiesA(const char *device, const char *portA, WORD cap,
1684 char *output, DEVMODEA *devmodeA)
1686 WCHAR *device_name = NULL, *port = NULL;
1687 DEVMODEW *devmode = NULL;
1688 DWORD ret, len;
1690 len = MultiByteToWideChar(CP_ACP, 0, device, -1, NULL, 0);
1691 if (len) {
1692 device_name = malloc(len * sizeof(WCHAR));
1693 MultiByteToWideChar(CP_ACP, 0, device, -1, device_name, len);
1696 len = MultiByteToWideChar(CP_ACP, 0, portA, -1, NULL, 0);
1697 if (len) {
1698 port = malloc(len * sizeof(WCHAR));
1699 MultiByteToWideChar(CP_ACP, 0, portA, -1, port, len);
1702 if (devmodeA) devmode = GdiConvertToDevmodeW( devmodeA );
1704 if (output && (cap == DC_BINNAMES || cap == DC_FILEDEPENDENCIES || cap == DC_PAPERNAMES)) {
1705 /* These need A -> W translation */
1706 unsigned int size = 0, i;
1707 WCHAR *outputW;
1709 ret = DeviceCapabilitiesW(device_name, port, cap, NULL, devmode);
1710 if (ret == -1) goto cleanup;
1712 switch (cap) {
1713 case DC_BINNAMES:
1714 size = 24;
1715 break;
1716 case DC_PAPERNAMES:
1717 case DC_FILEDEPENDENCIES:
1718 size = 64;
1719 break;
1721 outputW = malloc(size * ret * sizeof(WCHAR));
1722 ret = DeviceCapabilitiesW(device_name, port, cap, outputW, devmode);
1723 for (i = 0; i < ret; i++)
1724 WideCharToMultiByte(CP_ACP, 0, outputW + (i * size), -1,
1725 output + (i * size), size, NULL, NULL);
1726 free(outputW);
1727 } else {
1728 ret = DeviceCapabilitiesW(device_name, port, cap, (WCHAR *)output, devmode);
1730 cleanup:
1731 free(device_name);
1732 heap_free(devmode);
1733 free(port);
1734 return ret;
1737 /*****************************************************************************
1738 * DeviceCapabilitiesW [WINSPOOL.@]
1741 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1742 WORD fwCapability, LPWSTR pOutput,
1743 const DEVMODEW *pDevMode)
1745 config_module_t *config;
1746 int ret;
1748 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability,
1749 pOutput, pDevMode);
1751 if (!(config = get_config_module(pDevice, TRUE))) {
1752 WARN("Could not load config module for %s\n", debugstr_w(pDevice));
1753 return 0;
1756 ret = config->pDrvDeviceCapabilities(NULL /* FIXME */, pDevice, fwCapability,
1757 pOutput, pDevMode);
1758 release_config_module(config);
1759 return ret;
1762 /******************************************************************
1763 * DocumentPropertiesA [WINSPOOL.@]
1765 LONG WINAPI DocumentPropertiesA(HWND hwnd, HANDLE printer, char *device_name, DEVMODEA *output,
1766 DEVMODEA *input, DWORD mode)
1768 DEVMODEW *outputW = NULL, *inputW = NULL;
1769 WCHAR *device = NULL;
1770 unsigned int len;
1771 int ret;
1773 TRACE("(%p,%p,%s,%p,%p,%ld)\n", hwnd, printer, debugstr_a(device_name), output, input, mode);
1775 len = MultiByteToWideChar(CP_ACP, 0, device_name, -1, NULL, 0);
1776 if (len) {
1777 device = malloc(len * sizeof(WCHAR));
1778 MultiByteToWideChar(CP_ACP, 0, device_name, -1, device, len);
1781 if (output && (mode & (DM_COPY | DM_UPDATE))) {
1782 ret = DocumentPropertiesW(hwnd, printer, device, NULL, NULL, 0);
1783 if (ret <= 0) {
1784 free(device);
1785 return -1;
1787 outputW = malloc(ret);
1790 if (input && (mode & DM_IN_BUFFER)) inputW = GdiConvertToDevmodeW(input);
1792 ret = DocumentPropertiesW(hwnd, printer, device, outputW, inputW, mode);
1794 if (ret >= 0 && outputW && (mode & (DM_COPY | DM_UPDATE)))
1795 DEVMODEWtoA( outputW, output );
1797 free(device);
1798 heap_free(inputW);
1799 free(outputW);
1801 if (!mode && ret > 0) ret -= CCHDEVICENAME + CCHFORMNAME;
1802 return ret;
1805 static LONG WINAPI document_callback(PROPSHEETUI_INFO *info, LPARAM lparam)
1807 if (info->Reason == PROPSHEETUI_REASON_INIT)
1809 document_property_t *dp = (document_property_t *)info->lParamInit;
1811 if (!info->pfnComPropSheet(info->hComPropSheet, CPSFUNC_ADD_PFNPROPSHEETUIW,
1812 (LPARAM)dp->config->pDrvDocumentPropertySheets, (LPARAM)&dp->dph))
1813 return ERR_CPSUI_GETLASTERROR;
1815 return CPSUI_OK;
1818 /*****************************************************************************
1819 * DocumentPropertiesW (WINSPOOL.@)
1821 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1822 LPWSTR pDeviceName,
1823 LPDEVMODEW pDevModeOutput,
1824 LPDEVMODEW pDevModeInput, DWORD fMode)
1826 document_property_t dp;
1827 const WCHAR *device;
1828 LONG ret;
1830 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1831 hWnd, hPrinter, debugstr_w(pDeviceName), pDevModeOutput, pDevModeInput, fMode);
1833 device = hPrinter ? get_opened_printer_name(hPrinter) : pDeviceName;
1834 if (!device) {
1835 ERR("no device name\n");
1836 return -1;
1839 dp.dph.cbSize = sizeof(dp.dph);
1840 dp.dph.Reserved = 0;
1841 dp.dph.hPrinter = hPrinter;
1842 dp.dph.pszPrinterName = device;
1843 dp.dph.pdmIn = pDevModeInput;
1844 dp.dph.pdmOut = pDevModeOutput;
1845 dp.dph.cbOut = dp.dph.pdmOut ? dp.dph.pdmOut->dmSize : 0;
1846 dp.dph.fMode = fMode;
1847 dp.config = get_config_module(device, TRUE);
1848 if (!dp.config) {
1849 ERR("Could not load config module for %s\n", debugstr_w(device));
1850 return -1;
1853 if (!(fMode & ~(DM_IN_BUFFER | DM_OUT_BUFFER | DM_OUT_DEFAULT))) {
1854 ret = dp.config->pDrvDocumentPropertySheets(NULL, (LPARAM)&dp.dph);
1856 if ((!fMode || !pDevModeOutput) && dp.dph.cbOut != ret)
1857 FIXME("size mismatch: ret = %ld cbOut = %ld\n", ret, dp.dph.cbOut);
1858 } else {
1859 ret = CommonPropertySheetUIW(hWnd, document_callback, (LPARAM)&dp, NULL);
1862 release_config_module(dp.config);
1863 return ret;
1866 /*****************************************************************************
1867 * IsValidDevmodeA [WINSPOOL.@]
1869 * Validate a DEVMODE structure and fix errors if possible.
1872 BOOL WINAPI IsValidDevmodeA(PDEVMODEA pDevMode, SIZE_T size)
1874 FIXME("(%p,%Id): stub\n", pDevMode, size);
1876 if(!pDevMode)
1877 return FALSE;
1879 return TRUE;
1882 /*****************************************************************************
1883 * IsValidDevmodeW [WINSPOOL.@]
1885 * Validate a DEVMODE structure and fix errors if possible.
1888 BOOL WINAPI IsValidDevmodeW(PDEVMODEW dm, SIZE_T size)
1890 static const struct
1892 DWORD flag;
1893 SIZE_T size;
1894 } map[] =
1896 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
1897 { DM_ORIENTATION, F_SIZE(dmOrientation) },
1898 { DM_PAPERSIZE, F_SIZE(dmPaperSize) },
1899 { DM_PAPERLENGTH, F_SIZE(dmPaperLength) },
1900 { DM_PAPERWIDTH, F_SIZE(dmPaperWidth) },
1901 { DM_SCALE, F_SIZE(dmScale) },
1902 { DM_COPIES, F_SIZE(dmCopies) },
1903 { DM_DEFAULTSOURCE, F_SIZE(dmDefaultSource) },
1904 { DM_PRINTQUALITY, F_SIZE(dmPrintQuality) },
1905 { DM_POSITION, F_SIZE(dmPosition) },
1906 { DM_DISPLAYORIENTATION, F_SIZE(dmDisplayOrientation) },
1907 { DM_DISPLAYFIXEDOUTPUT, F_SIZE(dmDisplayFixedOutput) },
1908 { DM_COLOR, F_SIZE(dmColor) },
1909 { DM_DUPLEX, F_SIZE(dmDuplex) },
1910 { DM_YRESOLUTION, F_SIZE(dmYResolution) },
1911 { DM_TTOPTION, F_SIZE(dmTTOption) },
1912 { DM_COLLATE, F_SIZE(dmCollate) },
1913 { DM_FORMNAME, F_SIZE(dmFormName) },
1914 { DM_LOGPIXELS, F_SIZE(dmLogPixels) },
1915 { DM_BITSPERPEL, F_SIZE(dmBitsPerPel) },
1916 { DM_PELSWIDTH, F_SIZE(dmPelsWidth) },
1917 { DM_PELSHEIGHT, F_SIZE(dmPelsHeight) },
1918 { DM_DISPLAYFLAGS, F_SIZE(dmDisplayFlags) },
1919 { DM_NUP, F_SIZE(dmNup) },
1920 { DM_DISPLAYFREQUENCY, F_SIZE(dmDisplayFrequency) },
1921 { DM_ICMMETHOD, F_SIZE(dmICMMethod) },
1922 { DM_ICMINTENT, F_SIZE(dmICMIntent) },
1923 { DM_MEDIATYPE, F_SIZE(dmMediaType) },
1924 { DM_DITHERTYPE, F_SIZE(dmDitherType) },
1925 { DM_PANNINGWIDTH, F_SIZE(dmPanningWidth) },
1926 { DM_PANNINGHEIGHT, F_SIZE(dmPanningHeight) }
1927 #undef F_SIZE
1929 int i;
1930 const DWORD fields_off = FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(dm->dmFields);
1932 if (!dm) return FALSE;
1933 if (size < fields_off) return FALSE;
1934 if (dm->dmSize < fields_off || size < dm->dmSize + dm->dmDriverExtra) return FALSE;
1936 for (i = 0; i < ARRAY_SIZE(map); i++)
1937 if ((dm->dmFields & map[i].flag) && dm->dmSize < map[i].size)
1938 return FALSE;
1940 return TRUE;
1943 /******************************************************************
1944 * OpenPrinterA [WINSPOOL.@]
1946 * See OpenPrinterW.
1949 BOOL WINAPI OpenPrinterA(LPSTR name, HANDLE *printer, PRINTER_DEFAULTSA *defaults)
1951 return OpenPrinter2A(name, printer, defaults, NULL);
1954 /******************************************************************
1955 * OpenPrinterW [WINSPOOL.@]
1957 * Open a Printer / Printserver or a Printer-Object
1959 * PARAMS
1960 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1961 * phPrinter [O] The resulting Handle is stored here
1962 * pDefault [I] PTR to Default Printer Settings or NULL
1964 * RETURNS
1965 * Success: TRUE
1966 * Failure: FALSE
1968 * NOTES
1969 * lpPrinterName is one of:
1970 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1971 *| Printer: "PrinterName"
1972 *| Printer-Object: "PrinterName,Job xxx"
1973 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1974 *| XcvPort: "Servername,XcvPort PortName"
1976 * BUGS
1977 *| Printer-Object not supported
1978 *| pDefaults is ignored
1981 BOOL WINAPI OpenPrinterW(LPWSTR name, HANDLE *printer, PRINTER_DEFAULTSW *defaults)
1983 return OpenPrinter2W(name, printer, defaults, NULL);
1986 BOOL WINAPI OpenPrinter2A(LPSTR name, HANDLE *printer,
1987 PRINTER_DEFAULTSA *defaults, PRINTER_OPTIONSA *options)
1989 UNICODE_STRING nameU;
1990 UNICODE_STRING datatypeU;
1991 PRINTER_DEFAULTSW defaultsW, *p_defaultsW = NULL;
1992 PRINTER_OPTIONSW optionsW, *p_optionsW = NULL;
1993 WCHAR *nameW;
1994 BOOL ret;
1996 TRACE("(%s,%p,%p,%p)\n", debugstr_a(name), printer, defaults, options);
1998 nameW = asciitounicode(&nameU, name);
2000 if (options)
2002 optionsW.cbSize = sizeof(optionsW);
2003 optionsW.dwFlags = options->dwFlags;
2004 p_optionsW = &optionsW;
2007 if (defaults)
2009 defaultsW.pDatatype = asciitounicode(&datatypeU, defaults->pDatatype);
2010 defaultsW.pDevMode = defaults->pDevMode ? GdiConvertToDevmodeW(defaults->pDevMode) : NULL;
2011 defaultsW.DesiredAccess = defaults->DesiredAccess;
2012 p_defaultsW = &defaultsW;
2015 ret = OpenPrinter2W(nameW, printer, p_defaultsW, p_optionsW);
2017 if (p_defaultsW)
2019 RtlFreeUnicodeString(&datatypeU);
2020 heap_free(defaultsW.pDevMode);
2022 RtlFreeUnicodeString(&nameU);
2024 return ret;
2027 BOOL WINAPI OpenPrinter2W(LPWSTR name, HANDLE *printer,
2028 PRINTER_DEFAULTSW *defaults, PRINTER_OPTIONSW *options)
2030 HKEY key;
2032 TRACE("(%s,%p,%p,%p)\n", debugstr_w(name), printer, defaults, options);
2034 if (options)
2035 FIXME("flags %08lx ignored\n", options->dwFlags);
2037 if(!printer)
2039 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2040 SetLastError( ERROR_INVALID_PARAMETER );
2041 return FALSE;
2044 /* Get the unique handle of the printer or Printserver */
2045 *printer = get_opened_printer_entry( name, defaults );
2047 if (*printer && WINSPOOL_GetOpenedPrinterRegKey( *printer, &key ) == ERROR_SUCCESS)
2049 DWORD deleting = 0, size = sizeof( deleting ), type;
2050 DWORD status;
2051 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2052 WaitForSingleObject( init_mutex, INFINITE );
2053 status = get_dword_from_reg( key, L"Status" );
2054 set_reg_DWORD( key, L"Status", status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2055 ReleaseMutex( init_mutex );
2056 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2057 update_driver( *printer );
2058 RegCloseKey( key );
2061 TRACE("returning %d with %lu and %p\n", *printer != NULL, GetLastError(), *printer);
2062 return (*printer != NULL);
2065 /******************************************************************
2066 * AddMonitorA [WINSPOOL.@]
2068 * See AddMonitorW.
2071 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2073 LPWSTR nameW = NULL;
2074 INT len;
2075 BOOL res;
2076 LPMONITOR_INFO_2A mi2a;
2077 MONITOR_INFO_2W mi2w;
2079 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2080 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2081 debugstr_a(mi2a ? mi2a->pName : NULL),
2082 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2083 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2085 if (Level != 2) {
2086 SetLastError(ERROR_INVALID_LEVEL);
2087 return FALSE;
2090 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2091 if (mi2a == NULL) {
2092 return FALSE;
2095 if (pName) {
2096 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2097 nameW = malloc(len * sizeof(WCHAR));
2098 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2101 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2102 if (mi2a->pName) {
2103 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2104 mi2w.pName = malloc(len * sizeof(WCHAR));
2105 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2107 if (mi2a->pEnvironment) {
2108 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2109 mi2w.pEnvironment = malloc(len * sizeof(WCHAR));
2110 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2112 if (mi2a->pDLLName) {
2113 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2114 mi2w.pDLLName = malloc(len * sizeof(WCHAR));
2115 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2118 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2120 free(mi2w.pName);
2121 free(mi2w.pEnvironment);
2122 free(mi2w.pDLLName);
2124 free(nameW);
2125 return (res);
2128 /******************************************************************************
2129 * AddMonitorW [WINSPOOL.@]
2131 * Install a Printmonitor
2133 * PARAMS
2134 * pName [I] Servername or NULL (local Computer)
2135 * Level [I] Structure-Level (Must be 2)
2136 * pMonitors [I] PTR to MONITOR_INFO_2
2138 * RETURNS
2139 * Success: TRUE
2140 * Failure: FALSE
2142 * NOTES
2143 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2146 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2148 LPMONITOR_INFO_2W mi2w;
2150 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2151 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2152 debugstr_w(mi2w ? mi2w->pName : NULL),
2153 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2154 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2156 if ((backend == NULL) && !load_backend()) return FALSE;
2158 if (Level != 2) {
2159 SetLastError(ERROR_INVALID_LEVEL);
2160 return FALSE;
2163 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2164 if (mi2w == NULL) {
2165 return FALSE;
2168 return backend->fpAddMonitor(pName, Level, pMonitors);
2171 /******************************************************************
2172 * DeletePrinterDriverA [WINSPOOL.@]
2175 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2177 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2180 /******************************************************************
2181 * DeletePrinterDriverW [WINSPOOL.@]
2184 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2186 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2189 /******************************************************************
2190 * DeleteMonitorA [WINSPOOL.@]
2192 * See DeleteMonitorW.
2195 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2197 LPWSTR nameW = NULL;
2198 LPWSTR EnvironmentW = NULL;
2199 LPWSTR MonitorNameW = NULL;
2200 BOOL res;
2201 INT len;
2203 if (pName) {
2204 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2205 nameW = malloc(len * sizeof(WCHAR));
2206 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2209 if (pEnvironment) {
2210 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2211 EnvironmentW = malloc(len * sizeof(WCHAR));
2212 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2214 if (pMonitorName) {
2215 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2216 MonitorNameW = malloc(len * sizeof(WCHAR));
2217 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2220 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2222 free(MonitorNameW);
2223 free(EnvironmentW);
2224 free(nameW);
2225 return (res);
2228 /******************************************************************
2229 * DeleteMonitorW [WINSPOOL.@]
2231 * Delete a specific Printmonitor from a Printing-Environment
2233 * PARAMS
2234 * pName [I] Servername or NULL (local Computer)
2235 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2236 * pMonitorName [I] Name of the Monitor, that should be deleted
2238 * RETURNS
2239 * Success: TRUE
2240 * Failure: FALSE
2242 * NOTES
2243 * pEnvironment is ignored in Windows for the local Computer.
2246 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2249 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2250 debugstr_w(pMonitorName));
2252 if ((backend == NULL) && !load_backend()) return FALSE;
2254 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2258 /******************************************************************
2259 * DeletePortA [WINSPOOL.@]
2261 * See DeletePortW.
2264 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2266 LPWSTR nameW = NULL;
2267 LPWSTR portW = NULL;
2268 INT len;
2269 DWORD res;
2271 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2273 /* convert servername to unicode */
2274 if (pName) {
2275 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2276 nameW = malloc(len * sizeof(WCHAR));
2277 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2280 /* convert portname to unicode */
2281 if (pPortName) {
2282 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2283 portW = malloc(len * sizeof(WCHAR));
2284 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2287 res = DeletePortW(nameW, hWnd, portW);
2288 free(nameW);
2289 free(portW);
2290 return res;
2293 /******************************************************************
2294 * DeletePortW [WINSPOOL.@]
2296 * Delete a specific Port
2298 * PARAMS
2299 * pName [I] Servername or NULL (local Computer)
2300 * hWnd [I] Handle to parent Window for the Dialog-Box
2301 * pPortName [I] Name of the Port, that should be deleted
2303 * RETURNS
2304 * Success: TRUE
2305 * Failure: FALSE
2308 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2310 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2312 if ((backend == NULL) && !load_backend()) return FALSE;
2314 if (!pPortName) {
2315 SetLastError(RPC_X_NULL_REF_POINTER);
2316 return FALSE;
2319 return backend->fpDeletePort(pName, hWnd, pPortName);
2322 /******************************************************************************
2323 * WritePrinter [WINSPOOL.@]
2325 BOOL WINAPI WritePrinter(HANDLE printer, void *buf, DWORD size, DWORD *written)
2327 HANDLE handle = get_backend_handle(printer);
2329 TRACE("(%p, %p, %ld, %p)\n", printer, buf, size, written);
2331 if (!handle)
2333 SetLastError(ERROR_INVALID_HANDLE);
2334 return FALSE;
2337 return backend->fpWritePrinter(handle, buf, size, written);
2340 /*****************************************************************************
2341 * AddFormA [WINSPOOL.@]
2343 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2345 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
2346 return TRUE;
2349 /*****************************************************************************
2350 * AddFormW [WINSPOOL.@]
2352 BOOL WINAPI AddFormW( HANDLE printer, DWORD level, BYTE *form )
2354 HANDLE handle = get_backend_handle( printer );
2356 TRACE( "(%p, %ld, %p)\n", printer, level, form );
2358 if (!handle)
2360 SetLastError( ERROR_INVALID_HANDLE );
2361 return FALSE;
2364 return backend->fpAddForm( handle, level, form );
2367 /*****************************************************************************
2368 * AddJobA [WINSPOOL.@]
2370 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2372 BOOL ret;
2373 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2374 DWORD needed;
2376 if(Level != 1) {
2377 SetLastError(ERROR_INVALID_LEVEL);
2378 return FALSE;
2381 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2383 if(ret) {
2384 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2385 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2386 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2387 if(*pcbNeeded > cbBuf) {
2388 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2389 ret = FALSE;
2390 } else {
2391 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2392 addjobA->JobId = addjobW->JobId;
2393 addjobA->Path = (char *)(addjobA + 1);
2394 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2397 return ret;
2400 /*****************************************************************************
2401 * AddJobW [WINSPOOL.@]
2403 BOOL WINAPI AddJobW(HANDLE printer, DWORD level, LPBYTE data, DWORD size, DWORD *needed)
2405 HANDLE handle = get_backend_handle(printer);
2407 TRACE("(%p, %ld, %p, %ld, %p)\n", printer, level, data, size, needed);
2409 if (!handle)
2411 SetLastError(ERROR_INVALID_HANDLE);
2412 return FALSE;
2415 return backend->fpAddJob(handle, level, data, size, needed);
2418 /*****************************************************************************
2419 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2421 * Return the PATH for the Print-Processors
2423 * See GetPrintProcessorDirectoryW.
2427 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2428 DWORD level, LPBYTE Info,
2429 DWORD cbBuf, LPDWORD pcbNeeded)
2431 LPWSTR serverW = NULL;
2432 LPWSTR envW = NULL;
2433 BOOL ret;
2434 INT len;
2436 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server),
2437 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2440 if (server) {
2441 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2442 serverW = malloc(len * sizeof(WCHAR));
2443 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2446 if (env) {
2447 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2448 envW = malloc(len * sizeof(WCHAR));
2449 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2452 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2453 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2455 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2456 cbBuf, pcbNeeded);
2458 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2459 cbBuf, NULL, NULL) > 0;
2462 TRACE(" required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2463 free(envW);
2464 free(serverW);
2465 return ret;
2468 /*****************************************************************************
2469 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2471 * Return the PATH for the Print-Processors
2473 * PARAMS
2474 * server [I] Servername (NT only) or NULL (local Computer)
2475 * env [I] Printing-Environment (see below) or NULL (Default)
2476 * level [I] Structure-Level (must be 1)
2477 * Info [O] PTR to Buffer that receives the Result
2478 * cbBuf [I] Size of Buffer at "Info"
2479 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2480 * required for the Buffer at "Info"
2482 * RETURNS
2483 * Success: TRUE and in pcbNeeded the Bytes used in Info
2484 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2485 * if cbBuf is too small
2487 * Native Values returned in Info on Success:
2488 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2489 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2490 *| win9x(Windows 4.0): "%winsysdir%"
2492 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2494 * BUGS
2495 * Only NULL or "" is supported for server
2498 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2499 DWORD level, LPBYTE Info,
2500 DWORD cbBuf, LPDWORD pcbNeeded)
2503 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server), debugstr_w(env), level,
2504 Info, cbBuf, pcbNeeded);
2506 if ((backend == NULL) && !load_backend()) return FALSE;
2508 if (level != 1) {
2509 /* (Level != 1) is ignored in win9x */
2510 SetLastError(ERROR_INVALID_LEVEL);
2511 return FALSE;
2514 if (pcbNeeded == NULL) {
2515 /* (pcbNeeded == NULL) is ignored in win9x */
2516 SetLastError(RPC_X_NULL_REF_POINTER);
2517 return FALSE;
2520 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2523 /*****************************************************************************
2524 * set_devices_and_printerports [internal]
2526 * set the [Devices] and [PrinterPorts] entries for a printer.
2529 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2531 DWORD portlen = wcslen( pi->pPortName ) * sizeof(WCHAR);
2532 WCHAR *devline;
2533 HKEY key;
2535 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2537 /* FIXME: the driver must change to "winspool" */
2538 devline = malloc( sizeof(L"wineps.drv") + portlen + sizeof(L",15,45") );
2539 if (devline)
2541 wcscpy( devline, L"wineps.drv," );
2542 wcscat( devline, pi->pPortName );
2544 TRACE("using %s\n", debugstr_w(devline));
2545 if (!create_printers_reg_key( user_printers_key, &key ))
2547 RegSetValueExW( key, pi->pPrinterName, 0, REG_SZ, (BYTE *)devline,
2548 (wcslen( devline ) + 1) * sizeof(WCHAR) );
2549 RegCloseKey( key );
2552 wcscat( devline, L",15,45" );
2553 if (!create_printers_reg_key( user_ports_key, &key ))
2555 RegSetValueExW( key, pi->pPrinterName, 0, REG_SZ, (BYTE *)devline,
2556 (wcslen( devline ) + 1) * sizeof(WCHAR) );
2557 RegCloseKey( key );
2559 free(devline);
2563 static BOOL validate_print_proc(WCHAR *server, const WCHAR *name)
2565 PRINTPROCESSOR_INFO_1W *ppi;
2566 DWORD size, i, no;
2568 if (!EnumPrintProcessorsW(server, NULL, 1, NULL, 0, &size, &no)
2569 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2571 return FALSE;
2573 ppi = malloc(size);
2574 if (!ppi)
2576 SetLastError(ERROR_OUTOFMEMORY);
2577 return FALSE;
2579 if (!EnumPrintProcessorsW(server, NULL, 1, (BYTE*)ppi, size, &size, &no))
2581 free(ppi);
2582 return FALSE;
2585 for (i = 0; i < no; i++)
2587 if (!wcsicmp(ppi[i].pName, name))
2588 break;
2590 free(ppi);
2591 return i != no;
2594 /*****************************************************************************
2595 * AddPrinterW [WINSPOOL.@]
2597 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2599 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2600 LPDEVMODEW dm;
2601 HANDLE retval;
2602 HKEY printer_key, printers_key, hkeyDriver, hkeyDrivers;
2603 LONG size;
2605 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
2607 if(pName && *pName) {
2608 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2609 SetLastError(ERROR_INVALID_PARAMETER);
2610 return 0;
2612 if(Level != 2) {
2613 ERR("Level = %ld, unsupported!\n", Level);
2614 SetLastError(ERROR_INVALID_LEVEL);
2615 return 0;
2617 if(!pPrinter) {
2618 SetLastError(ERROR_INVALID_PARAMETER);
2619 return 0;
2621 if (create_printers_reg_key( system_printers_key, &printers_key ))
2623 ERR("Can't create Printers key\n");
2624 return 0;
2626 if (!RegOpenKeyW( printers_key, pi->pPrinterName, &printer_key ))
2628 if (!RegQueryValueW( printer_key, L"Attributes", NULL, NULL ))
2630 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2631 RegCloseKey( printer_key );
2632 RegCloseKey( printers_key );
2633 return 0;
2635 RegCloseKey( printer_key );
2637 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2638 if(!hkeyDrivers) {
2639 ERR("Can't create Drivers key\n");
2640 RegCloseKey( printers_key );
2641 return 0;
2643 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2644 ERROR_SUCCESS) {
2645 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2646 RegCloseKey( printers_key );
2647 RegCloseKey(hkeyDrivers);
2648 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2649 return 0;
2651 RegCloseKey(hkeyDriver);
2652 RegCloseKey(hkeyDrivers);
2654 if (!validate_print_proc(pName, pi->pPrintProcessor))
2656 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2657 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2658 RegCloseKey( printers_key );
2659 return 0;
2662 if (RegCreateKeyW( printers_key, pi->pPrinterName, &printer_key ))
2664 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2665 SetLastError(ERROR_INVALID_PRINTER_NAME);
2666 RegCloseKey( printers_key );
2667 return 0;
2670 set_devices_and_printerports(pi);
2672 set_reg_DWORD( printer_key, L"Attributes", pi->Attributes );
2673 set_reg_szW( printer_key, L"Datatype", pi->pDatatype );
2674 set_reg_DWORD( printer_key, L"Default Priority", pi->DefaultPriority );
2675 set_reg_szW( printer_key, L"Description", pi->pComment );
2676 set_reg_DWORD( printer_key, L"dnsTimeout", 0 );
2677 set_reg_szW( printer_key, L"Location", pi->pLocation );
2678 set_reg_szW( printer_key, L"Name", pi->pPrinterName );
2679 set_reg_szW( printer_key, L"Parameters", pi->pParameters );
2680 set_reg_szW( printer_key, L"Port", pi->pPortName );
2681 set_reg_szW( printer_key, L"Print Processor", pi->pPrintProcessor );
2682 set_reg_szW( printer_key, L"Printer Driver", pi->pDriverName );
2683 set_reg_DWORD( printer_key, L"Priority", pi->Priority );
2684 set_reg_szW( printer_key, L"Separator File", pi->pSepFile );
2685 set_reg_szW( printer_key, L"Share Name", pi->pShareName );
2686 set_reg_DWORD( printer_key, L"StartTime", pi->StartTime );
2687 set_reg_DWORD( printer_key, L"Status", pi->Status );
2688 set_reg_DWORD( printer_key, L"txTimeout", 0 );
2689 set_reg_DWORD( printer_key, L"UntilTime", pi->UntilTime );
2691 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2693 if (size < 0)
2695 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2696 size = sizeof(DEVMODEW);
2698 if(pi->pDevMode)
2699 dm = pi->pDevMode;
2700 else
2702 dm = calloc( 1, size );
2703 dm->dmSize = size;
2704 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2706 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2707 free( dm );
2708 dm = NULL;
2710 else
2712 unsigned int len = min( ARRAY_SIZE( dm->dmDeviceName ) - 1, wcslen( pi->pPrinterName ) );
2713 memcpy( dm->dmDeviceName, pi->pPrinterName, len * sizeof(WCHAR) );
2714 dm->dmDeviceName[len] = '\0';
2718 set_reg_devmode( printer_key, L"Default DevMode", dm );
2719 if (!pi->pDevMode) free( dm );
2721 RegCloseKey( printer_key );
2722 RegCloseKey( printers_key );
2723 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2724 ERR("OpenPrinter failing\n");
2725 return 0;
2727 return retval;
2730 /*****************************************************************************
2731 * AddPrinterA [WINSPOOL.@]
2733 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2735 UNICODE_STRING pNameW;
2736 PWSTR pwstrNameW;
2737 PRINTER_INFO_2W *piW;
2738 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2739 HANDLE ret;
2741 TRACE("(%s, %ld, %p)\n", debugstr_a(pName), Level, pPrinter);
2742 if(Level != 2) {
2743 ERR("Level = %ld, unsupported!\n", Level);
2744 SetLastError(ERROR_INVALID_LEVEL);
2745 return 0;
2747 pwstrNameW = asciitounicode(&pNameW,pName);
2748 piW = printer_info_AtoW( piA, Level );
2750 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2752 free_printer_info( piW, Level );
2753 RtlFreeUnicodeString(&pNameW);
2754 return ret;
2758 /*****************************************************************************
2759 * ClosePrinter [WINSPOOL.@]
2761 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2763 UINT_PTR i = (UINT_PTR)hPrinter;
2764 opened_printer_t *printer = NULL;
2766 TRACE("(%p)\n", hPrinter);
2768 EnterCriticalSection(&printer_handles_cs);
2770 if ((i > 0) && (i <= nb_printer_handles))
2771 printer = printer_handles[i - 1];
2774 if(printer)
2776 TRACE("closing %s\n", debugstr_w(printer->name));
2777 if (printer->backend_printer) {
2778 backend->fpClosePrinter(printer->backend_printer);
2781 free_printer_entry( printer );
2782 printer_handles[i - 1] = NULL;
2783 LeaveCriticalSection(&printer_handles_cs);
2784 return TRUE;
2787 LeaveCriticalSection(&printer_handles_cs);
2788 SetLastError(ERROR_INVALID_HANDLE);
2789 return FALSE;
2792 /*****************************************************************************
2793 * DeleteFormA [WINSPOOL.@]
2795 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2797 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2798 return TRUE;
2801 /*****************************************************************************
2802 * DeleteFormW [WINSPOOL.@]
2804 BOOL WINAPI DeleteFormW( HANDLE printer, WCHAR *name )
2806 HANDLE handle = get_backend_handle( printer );
2808 TRACE( "(%p, %s)\n", printer, debugstr_w( name ) );
2810 if (!handle)
2812 SetLastError( ERROR_INVALID_HANDLE );
2813 return FALSE;
2816 return backend->fpDeleteForm( handle, name );
2819 /*****************************************************************************
2820 * DeletePrinter [WINSPOOL.@]
2822 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2824 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2825 config_module_t *config_module;
2826 HKEY key;
2827 WCHAR def[MAX_PATH];
2828 DWORD size = ARRAY_SIZE(def);
2830 if(!lpNameW) {
2831 SetLastError(ERROR_INVALID_HANDLE);
2832 return FALSE;
2835 EnterCriticalSection(&config_modules_cs);
2836 if ((config_module = get_config_module(lpNameW, FALSE))) {
2837 wine_rb_remove(&config_modules, &config_module->entry);
2838 release_config_module(config_module);
2840 LeaveCriticalSection(&config_modules_cs);
2842 if (!create_printers_reg_key( system_printers_key, &key ))
2844 RegDeleteTreeW( key, lpNameW );
2845 RegCloseKey( key );
2848 if (!create_printers_reg_key( user_printers_key, &key ))
2850 RegDeleteValueW( key, lpNameW );
2851 RegCloseKey( key );
2854 if (!create_printers_reg_key( user_ports_key, &key ))
2856 RegDeleteValueW( key, lpNameW );
2857 RegCloseKey( key );
2860 if (GetDefaultPrinterW( def, &size ) && !wcscmp( def, lpNameW ))
2862 if (!create_printers_reg_key( user_default_key, &key ))
2864 RegDeleteValueW( key, L"device" );
2865 RegCloseKey( key );
2867 SetDefaultPrinterW( NULL );
2870 return TRUE;
2873 /*****************************************************************************
2874 * SetPrinterA [WINSPOOL.@]
2876 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2878 BYTE *dataW = data;
2879 BOOL ret;
2881 if (level != 0)
2883 dataW = printer_info_AtoW( data, level );
2884 if (!dataW) return FALSE;
2887 ret = SetPrinterW( printer, level, dataW, command );
2889 if (dataW != data) free_printer_info( dataW, level );
2891 return ret;
2894 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
2896 set_reg_szW( key, L"Name", pi->pPrinterName );
2897 set_reg_szW( key, L"Share Name", pi->pShareName );
2898 set_reg_szW( key, L"Port", pi->pPortName );
2899 set_reg_szW( key, L"Printer Driver", pi->pDriverName );
2900 set_reg_szW( key, L"Description", pi->pComment );
2901 set_reg_szW( key, L"Location", pi->pLocation );
2903 if (pi->pDevMode)
2904 set_reg_devmode( key, L"Default DevMode", pi->pDevMode );
2906 set_reg_szW( key, L"Separator File", pi->pSepFile );
2907 set_reg_szW( key, L"Print Processor", pi->pPrintProcessor );
2908 set_reg_szW( key, L"Datatype", pi->pDatatype );
2909 set_reg_szW( key, L"Parameters", pi->pParameters );
2911 set_reg_DWORD( key, L"Attributes", pi->Attributes );
2912 set_reg_DWORD( key, L"Priority", pi->Priority );
2913 set_reg_DWORD( key, L"Default Priority", pi->DefaultPriority );
2914 set_reg_DWORD( key, L"StartTime", pi->StartTime );
2915 set_reg_DWORD( key, L"UntilTime", pi->UntilTime );
2918 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
2920 if (!pi->pDevMode) return FALSE;
2922 set_reg_devmode( key, L"Default DevMode", pi->pDevMode );
2923 return TRUE;
2926 /******************************************************************************
2927 * SetPrinterW [WINSPOOL.@]
2929 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2931 HKEY key;
2932 BOOL ret = FALSE;
2934 TRACE( "(%p, %ld, %p, %ld)\n", printer, level, data, command );
2936 if (command != 0) FIXME( "Ignoring command %ld\n", command );
2938 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
2939 return FALSE;
2941 switch (level)
2943 case 2:
2945 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
2946 set_printer_2( key, pi2 );
2947 ret = TRUE;
2948 break;
2951 case 8:
2952 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
2953 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
2954 /* fall through */
2955 case 9:
2957 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
2958 ret = set_printer_9( key, pi );
2959 break;
2962 default:
2963 FIXME( "Unimplemented level %ld\n", level );
2964 SetLastError( ERROR_INVALID_LEVEL );
2967 RegCloseKey( key );
2968 return ret;
2971 /*****************************************************************************
2972 * SetJobA [WINSPOOL.@]
2974 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2975 LPBYTE pJob, DWORD Command)
2977 BOOL ret;
2978 void *JobW;
2979 UNICODE_STRING usBuffer;
2981 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2983 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2984 are all ignored by SetJob, so we don't bother copying them */
2985 switch(Level)
2987 case 0:
2988 JobW = NULL;
2989 break;
2990 case 1:
2992 JOB_INFO_1W *info1W = malloc(sizeof(*info1W));
2993 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2995 JobW = info1W;
2996 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2997 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2998 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2999 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3000 info1W->Status = info1A->Status;
3001 info1W->Priority = info1A->Priority;
3002 info1W->Position = info1A->Position;
3003 info1W->PagesPrinted = info1A->PagesPrinted;
3004 break;
3006 case 2:
3008 JOB_INFO_2W *info2W = malloc(sizeof(*info2W));
3009 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3011 JobW = info2W;
3012 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3013 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3014 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3015 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3016 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3017 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3018 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3019 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3020 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3021 info2W->Status = info2A->Status;
3022 info2W->Priority = info2A->Priority;
3023 info2W->Position = info2A->Position;
3024 info2W->StartTime = info2A->StartTime;
3025 info2W->UntilTime = info2A->UntilTime;
3026 info2W->PagesPrinted = info2A->PagesPrinted;
3027 break;
3029 case 3:
3030 JobW = malloc(sizeof(JOB_INFO_3));
3031 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3032 break;
3033 default:
3034 SetLastError(ERROR_INVALID_LEVEL);
3035 return FALSE;
3038 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3040 switch(Level)
3042 case 1:
3044 JOB_INFO_1W *info1W = JobW;
3045 free(info1W->pUserName);
3046 free(info1W->pDocument);
3047 free(info1W->pDatatype);
3048 free(info1W->pStatus);
3049 break;
3051 case 2:
3053 JOB_INFO_2W *info2W = JobW;
3054 free(info2W->pUserName);
3055 free(info2W->pDocument);
3056 free(info2W->pNotifyName);
3057 free(info2W->pDatatype);
3058 free(info2W->pPrintProcessor);
3059 free(info2W->pParameters);
3060 heap_free(info2W->pDevMode);
3061 free(info2W->pStatus);
3062 break;
3065 free(JobW);
3067 return ret;
3070 /*****************************************************************************
3071 * SetJobW [WINSPOOL.@]
3073 BOOL WINAPI SetJobW(HANDLE printer, DWORD job_id, DWORD level,
3074 LPBYTE data, DWORD command)
3076 HANDLE handle = get_backend_handle(printer);
3078 TRACE("(%p, %ld, %ld, %p, %ld)\n", printer, job_id, level, data, command);
3080 if (!handle)
3082 SetLastError(ERROR_INVALID_HANDLE);
3083 return FALSE;
3086 return backend->fpSetJob(handle, job_id, level, data, command);
3089 /*****************************************************************************
3090 * EndDocPrinter [WINSPOOL.@]
3092 BOOL WINAPI EndDocPrinter(HANDLE printer)
3094 HANDLE handle = get_backend_handle(printer);
3096 TRACE("(%p)\n", printer);
3098 if (!handle)
3100 SetLastError(ERROR_INVALID_HANDLE);
3101 return FALSE;
3104 return backend->fpEndDocPrinter(handle);
3107 /*****************************************************************************
3108 * EndPagePrinter [WINSPOOL.@]
3110 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3112 FIXME("(%p): stub\n", hPrinter);
3113 return TRUE;
3116 /*****************************************************************************
3117 * StartDocPrinterA [WINSPOOL.@]
3119 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3121 UNICODE_STRING usBuffer;
3122 DOC_INFO_2W doc2W;
3123 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3124 DWORD ret;
3126 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3127 or one (DOC_INFO_3) extra DWORDs */
3129 switch(Level) {
3130 case 2:
3131 doc2W.JobId = doc2->JobId;
3132 /* fall through */
3133 case 3:
3134 doc2W.dwMode = doc2->dwMode;
3135 /* fall through */
3136 case 1:
3137 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3138 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3139 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3140 break;
3142 default:
3143 SetLastError(ERROR_INVALID_LEVEL);
3144 return FALSE;
3147 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3149 free(doc2W.pDatatype);
3150 free(doc2W.pOutputFile);
3151 free(doc2W.pDocName);
3153 return ret;
3156 /*****************************************************************************
3157 * StartDocPrinterW [WINSPOOL.@]
3159 DWORD WINAPI StartDocPrinterW(HANDLE printer, DWORD level, BYTE *doc_info)
3161 HANDLE handle = get_backend_handle(printer);
3162 DOC_INFO_1W *info = (DOC_INFO_1W *)doc_info;
3164 TRACE("(%p, %ld, %p {%s, %s, %s})\n", printer, level, doc_info,
3165 debugstr_w(info->pDocName), debugstr_w(info->pOutputFile),
3166 debugstr_w(info->pDatatype));
3168 if (!handle)
3170 SetLastError(ERROR_INVALID_HANDLE);
3171 return 0;
3174 return backend->fpStartDocPrinter(handle, level, doc_info);
3177 /*****************************************************************************
3178 * StartPagePrinter [WINSPOOL.@]
3180 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3182 FIXME("(%p): stub\n", hPrinter);
3183 return TRUE;
3186 /*****************************************************************************
3187 * GetFormA [WINSPOOL.@]
3189 BOOL WINAPI GetFormA( HANDLE printer, char *name, DWORD level, BYTE *form, DWORD size, DWORD *needed )
3191 UNICODE_STRING nameW;
3192 const DWORD *string_info = form_string_info( level );
3193 BOOL ret;
3195 if (!string_info) return FALSE;
3197 asciitounicode( &nameW, name );
3199 ret = GetFormW( printer, nameW.Buffer, level, form, size, needed );
3200 if (ret) packed_struct_WtoA( form, string_info );
3202 RtlFreeUnicodeString( &nameW );
3203 return ret;
3206 /*****************************************************************************
3207 * GetFormW [WINSPOOL.@]
3209 BOOL WINAPI GetFormW( HANDLE printer, WCHAR *name, DWORD level, BYTE *form, DWORD size, DWORD *needed )
3211 HANDLE handle = get_backend_handle( printer );
3213 TRACE( "(%p, %s, %ld, %p, %ld, %p)\n", printer, debugstr_w( name ), level, form, size, needed );
3215 if (!handle)
3217 SetLastError( ERROR_INVALID_HANDLE );
3218 return FALSE;
3221 return backend->fpGetForm( handle, name, level, form, size, needed );
3224 /*****************************************************************************
3225 * SetFormA [WINSPOOL.@]
3227 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3228 LPBYTE pForm)
3230 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
3231 return FALSE;
3234 /*****************************************************************************
3235 * SetFormW [WINSPOOL.@]
3237 BOOL WINAPI SetFormW( HANDLE printer, WCHAR *name, DWORD level, BYTE *form )
3239 HANDLE handle = get_backend_handle( printer );
3241 TRACE( "(%p, %s, %ld, %p)\n", printer, debugstr_w( name ), level, form );
3243 if (!handle)
3245 SetLastError( ERROR_INVALID_HANDLE );
3246 return FALSE;
3249 return backend->fpSetForm( handle, name, level, form );
3252 /*****************************************************************************
3253 * ReadPrinter [WINSPOOL.@]
3255 BOOL WINAPI ReadPrinter(HANDLE printer, void *buf, DWORD size, DWORD *bytes_read)
3257 HANDLE handle = get_backend_handle(printer);
3259 TRACE("(%p,%p,%ld,%p)\n", printer, buf, size, bytes_read);
3261 if (!handle)
3263 SetLastError( ERROR_INVALID_HANDLE );
3264 return FALSE;
3267 return backend->fpReadPrinter(handle, buf, size, bytes_read);
3270 /*****************************************************************************
3271 * ResetPrinterA [WINSPOOL.@]
3273 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3275 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3276 return FALSE;
3279 /*****************************************************************************
3280 * ResetPrinterW [WINSPOOL.@]
3282 BOOL WINAPI ResetPrinterW(HANDLE printer, PRINTER_DEFAULTSW *def)
3284 HANDLE handle = get_backend_handle(printer);
3286 TRACE("(%p, %p)\n", printer, def);
3288 if (!handle)
3290 SetLastError( ERROR_INVALID_HANDLE );
3291 return FALSE;
3294 return backend->fpResetPrinter(handle, def);
3297 /*****************************************************************************
3298 * get_filename_from_reg [internal]
3300 * Get ValueName from hkey storing result in out
3301 * when the Value in the registry has only a filename, use driverdir as prefix
3302 * outlen is space left in out
3303 * String is stored either as unicode or ansi
3307 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3308 LPBYTE out, DWORD outlen, LPDWORD needed)
3310 WCHAR filename[MAX_PATH];
3311 DWORD size;
3312 DWORD type;
3313 LONG ret;
3314 LPWSTR buffer = filename;
3315 LPWSTR ptr;
3317 *needed = 0;
3318 size = sizeof(filename);
3319 buffer[0] = '\0';
3320 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3321 if (ret == ERROR_MORE_DATA) {
3322 TRACE("need dynamic buffer: %lu\n", size);
3323 buffer = malloc(size);
3324 if (!buffer) {
3325 /* No Memory is bad */
3326 return FALSE;
3328 buffer[0] = '\0';
3329 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3332 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3333 if (buffer != filename) free(buffer);
3334 return FALSE;
3337 ptr = buffer;
3338 while (ptr) {
3339 /* do we have a full path ? */
3340 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3341 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3343 if (!ret) {
3344 /* we must build the full Path */
3345 *needed += dirlen;
3346 if ((out) && (outlen > dirlen)) {
3347 wcscpy( (WCHAR *)out, driverdir );
3348 out += dirlen;
3349 outlen -= dirlen;
3351 else
3352 out = NULL;
3355 /* write the filename */
3356 size = (wcslen( ptr ) + 1) * sizeof(WCHAR);
3357 if ((out) && (outlen >= size)) {
3358 wcscpy( (WCHAR *)out, ptr );
3359 out += size;
3360 outlen -= size;
3362 else
3363 out = NULL;
3364 *needed += size;
3365 ptr += wcslen( ptr ) + 1;
3366 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3369 if (buffer != filename) free(buffer);
3371 /* write the multisz-termination */
3372 if (type == REG_MULTI_SZ) {
3373 size = sizeof(WCHAR);
3375 *needed += size;
3376 if (out && (outlen >= size)) {
3377 memset (out, 0, size);
3380 return TRUE;
3383 /*****************************************************************************
3384 * WINSPOOL_GetStringFromReg
3386 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3387 * String is stored as unicode.
3389 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3390 DWORD buflen, DWORD *needed)
3392 DWORD sz = buflen, type;
3393 LONG ret;
3395 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3396 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3397 WARN("Got ret = %ld\n", ret);
3398 *needed = 0;
3399 return FALSE;
3401 /* add space for terminating '\0' */
3402 sz += sizeof(WCHAR);
3403 *needed = sz;
3405 if (ptr)
3406 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3408 return TRUE;
3411 /*****************************************************************************
3412 * WINSPOOL_GetDefaultDevMode
3414 * Get a default DevMode values for wineps.
3416 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
3418 if (buflen >= sizeof(DEVMODEW))
3420 DEVMODEW *dm = (DEVMODEW *)ptr;
3422 /* the driver will update registry with real values */
3423 memset(dm, 0, sizeof(*dm));
3424 dm->dmSize = sizeof(*dm);
3425 wcscpy( dm->dmDeviceName, L"wineps.drv" );
3427 *needed = sizeof(DEVMODEW);
3430 /*****************************************************************************
3431 * WINSPOOL_GetDevModeFromReg
3433 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3434 * DevMode is stored either as unicode or ansi.
3436 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3437 LPBYTE ptr,
3438 DWORD buflen, DWORD *needed)
3440 DWORD sz = buflen, type;
3441 LONG ret;
3443 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3444 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3445 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3446 if (sz < sizeof(DEVMODEA))
3448 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
3449 return FALSE;
3451 /* ensures that dmSize is not erratically bogus if registry is invalid */
3452 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3453 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3454 sz += (CCHDEVICENAME + CCHFORMNAME);
3455 if (ptr && (buflen >= sz)) {
3456 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3457 memcpy(ptr, dmW, sz);
3458 heap_free(dmW);
3460 *needed = sz;
3461 return TRUE;
3464 /*********************************************************************
3465 * WINSPOOL_GetPrinter_1
3467 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3469 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3470 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3472 DWORD size, left = cbBuf;
3473 BOOL space = (cbBuf > 0);
3474 LPBYTE ptr = buf;
3476 *pcbNeeded = 0;
3478 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3480 if(space && size <= left) {
3481 pi1->pName = (LPWSTR)ptr;
3482 ptr += size;
3483 left -= size;
3484 } else
3485 space = FALSE;
3486 *pcbNeeded += size;
3489 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3490 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3492 if(space && size <= left) {
3493 pi1->pDescription = (LPWSTR)ptr;
3494 ptr += size;
3495 left -= size;
3496 } else
3497 space = FALSE;
3498 *pcbNeeded += size;
3501 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Description", ptr, left, &size ))
3503 if(space && size <= left) {
3504 pi1->pComment = (LPWSTR)ptr;
3505 ptr += size;
3506 left -= size;
3507 } else
3508 space = FALSE;
3509 *pcbNeeded += size;
3512 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3514 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3515 memset(pi1, 0, sizeof(*pi1));
3517 return space;
3519 /*********************************************************************
3520 * WINSPOOL_GetPrinter_2
3522 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3524 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3525 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3527 DWORD size, left = cbBuf;
3528 BOOL space = (cbBuf > 0);
3529 LPBYTE ptr = buf;
3531 *pcbNeeded = 0;
3533 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3535 if(space && size <= left) {
3536 pi2->pPrinterName = (LPWSTR)ptr;
3537 ptr += size;
3538 left -= size;
3539 } else
3540 space = FALSE;
3541 *pcbNeeded += size;
3543 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Share Name", ptr, left, &size))
3545 if(space && size <= left) {
3546 pi2->pShareName = (LPWSTR)ptr;
3547 ptr += size;
3548 left -= size;
3549 } else
3550 space = FALSE;
3551 *pcbNeeded += size;
3553 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Port", ptr, left, &size ))
3555 if(space && size <= left) {
3556 pi2->pPortName = (LPWSTR)ptr;
3557 ptr += size;
3558 left -= size;
3559 } else
3560 space = FALSE;
3561 *pcbNeeded += size;
3563 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Printer Driver", ptr, left, &size ))
3565 if(space && size <= left) {
3566 pi2->pDriverName = (LPWSTR)ptr;
3567 ptr += size;
3568 left -= size;
3569 } else
3570 space = FALSE;
3571 *pcbNeeded += size;
3573 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Description", ptr, left, &size ))
3575 if(space && size <= left) {
3576 pi2->pComment = (LPWSTR)ptr;
3577 ptr += size;
3578 left -= size;
3579 } else
3580 space = FALSE;
3581 *pcbNeeded += size;
3583 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Location", ptr, left, &size ))
3585 if(space && size <= left) {
3586 pi2->pLocation = (LPWSTR)ptr;
3587 ptr += size;
3588 left -= size;
3589 } else
3590 space = FALSE;
3591 *pcbNeeded += size;
3593 if (WINSPOOL_GetDevModeFromReg( hkeyPrinter, L"Default DevMode", ptr, left, &size ))
3595 if(space && size <= left) {
3596 pi2->pDevMode = (LPDEVMODEW)ptr;
3597 ptr += size;
3598 left -= size;
3599 } else
3600 space = FALSE;
3601 *pcbNeeded += size;
3603 else
3605 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3606 if(space && size <= left) {
3607 pi2->pDevMode = (LPDEVMODEW)ptr;
3608 ptr += size;
3609 left -= size;
3610 } else
3611 space = FALSE;
3612 *pcbNeeded += size;
3614 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Separator File", ptr, left, &size ))
3616 if(space && size <= left) {
3617 pi2->pSepFile = (LPWSTR)ptr;
3618 ptr += size;
3619 left -= size;
3620 } else
3621 space = FALSE;
3622 *pcbNeeded += size;
3624 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Print Processor", ptr, left, &size ))
3626 if(space && size <= left) {
3627 pi2->pPrintProcessor = (LPWSTR)ptr;
3628 ptr += size;
3629 left -= size;
3630 } else
3631 space = FALSE;
3632 *pcbNeeded += size;
3634 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Datatype", ptr, left, &size ))
3636 if(space && size <= left) {
3637 pi2->pDatatype = (LPWSTR)ptr;
3638 ptr += size;
3639 left -= size;
3640 } else
3641 space = FALSE;
3642 *pcbNeeded += size;
3644 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Parameters", ptr, left, &size ))
3646 if(space && size <= left) {
3647 pi2->pParameters = (LPWSTR)ptr;
3648 ptr += size;
3649 left -= size;
3650 } else
3651 space = FALSE;
3652 *pcbNeeded += size;
3654 if (pi2)
3656 pi2->Attributes = get_dword_from_reg( hkeyPrinter, L"Attributes" );
3657 pi2->Priority = get_dword_from_reg( hkeyPrinter, L"Priority" );
3658 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, L"Default Priority" );
3659 pi2->StartTime = get_dword_from_reg( hkeyPrinter, L"StartTime" );
3660 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, L"UntilTime" );
3663 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3664 memset(pi2, 0, sizeof(*pi2));
3666 return space;
3669 /*********************************************************************
3670 * WINSPOOL_GetPrinter_4
3672 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3674 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3675 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3677 DWORD size, left = cbBuf;
3678 BOOL space = (cbBuf > 0);
3679 LPBYTE ptr = buf;
3681 *pcbNeeded = 0;
3683 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3685 if(space && size <= left) {
3686 pi4->pPrinterName = (LPWSTR)ptr;
3687 ptr += size;
3688 left -= size;
3689 } else
3690 space = FALSE;
3691 *pcbNeeded += size;
3693 if(pi4) {
3694 pi4->Attributes = get_dword_from_reg( hkeyPrinter, L"Attributes" );
3697 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3698 memset(pi4, 0, sizeof(*pi4));
3700 return space;
3703 /*********************************************************************
3704 * WINSPOOL_GetPrinter_5
3706 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3708 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3709 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3711 DWORD size, left = cbBuf;
3712 BOOL space = (cbBuf > 0);
3713 LPBYTE ptr = buf;
3715 *pcbNeeded = 0;
3717 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Name", ptr, left, &size ))
3719 if(space && size <= left) {
3720 pi5->pPrinterName = (LPWSTR)ptr;
3721 ptr += size;
3722 left -= size;
3723 } else
3724 space = FALSE;
3725 *pcbNeeded += size;
3727 if (WINSPOOL_GetStringFromReg( hkeyPrinter, L"Port", ptr, left, &size ))
3729 if(space && size <= left) {
3730 pi5->pPortName = (LPWSTR)ptr;
3731 ptr += size;
3732 left -= size;
3733 } else
3734 space = FALSE;
3735 *pcbNeeded += size;
3737 if(pi5) {
3738 pi5->Attributes = get_dword_from_reg( hkeyPrinter, L"Attributes" );
3739 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, L"dnsTimeout" );
3740 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, L"txTimeout" );
3743 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3744 memset(pi5, 0, sizeof(*pi5));
3746 return space;
3749 /*********************************************************************
3750 * WINSPOOL_GetPrinter_7
3752 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3754 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3755 DWORD cbBuf, LPDWORD pcbNeeded)
3757 DWORD size, left = cbBuf;
3758 BOOL space = (cbBuf > 0);
3759 LPBYTE ptr = buf;
3761 *pcbNeeded = 0;
3763 if (!WINSPOOL_GetStringFromReg( hkeyPrinter, L"ObjectGUID", ptr, left, &size ))
3765 ptr = NULL;
3766 size = sizeof(pi7->pszObjectGUID);
3768 if (space && size <= left) {
3769 pi7->pszObjectGUID = (LPWSTR)ptr;
3770 ptr += size;
3771 left -= size;
3772 } else
3773 space = FALSE;
3774 *pcbNeeded += size;
3775 if (pi7) {
3776 /* We do not have a Directory Service */
3777 pi7->dwAction = DSPRINT_UNPUBLISH;
3780 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3781 memset(pi7, 0, sizeof(*pi7));
3783 return space;
3786 /*********************************************************************
3787 * WINSPOOL_GetPrinter_9
3789 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3791 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3792 DWORD cbBuf, LPDWORD pcbNeeded)
3794 DWORD size;
3795 BOOL space = (cbBuf > 0);
3797 *pcbNeeded = 0;
3799 if (WINSPOOL_GetDevModeFromReg( hkeyPrinter, L"Default DevMode", buf, cbBuf, &size ))
3801 if(space && size <= cbBuf) {
3802 pi9->pDevMode = (LPDEVMODEW)buf;
3803 } else
3804 space = FALSE;
3805 *pcbNeeded += size;
3807 else
3809 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3810 if(space && size <= cbBuf) {
3811 pi9->pDevMode = (LPDEVMODEW)buf;
3812 } else
3813 space = FALSE;
3814 *pcbNeeded += size;
3817 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3818 memset(pi9, 0, sizeof(*pi9));
3820 return space;
3823 /*****************************************************************************
3824 * GetPrinterW [WINSPOOL.@]
3826 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3827 DWORD cbBuf, LPDWORD pcbNeeded)
3829 DWORD size, needed = 0, err;
3830 LPBYTE ptr = NULL;
3831 HKEY hkeyPrinter;
3832 BOOL ret;
3834 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3836 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
3837 if (err)
3839 SetLastError( err );
3840 return FALSE;
3843 switch(Level) {
3844 case 1:
3846 PRINTER_INFO_1W *pi1 = (PRINTER_INFO_1W *)pPrinter;
3848 size = sizeof(PRINTER_INFO_1W);
3849 if (size <= cbBuf) {
3850 ptr = pPrinter + size;
3851 cbBuf -= size;
3852 memset(pPrinter, 0, size);
3853 } else {
3854 pi1 = NULL;
3855 cbBuf = 0;
3857 ret = WINSPOOL_GetPrinter_1(hkeyPrinter, pi1, ptr, cbBuf, &needed);
3858 needed += size;
3859 break;
3862 case 2:
3864 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3866 size = sizeof(PRINTER_INFO_2W);
3867 if(size <= cbBuf) {
3868 ptr = pPrinter + size;
3869 cbBuf -= size;
3870 memset(pPrinter, 0, size);
3871 } else {
3872 pi2 = NULL;
3873 cbBuf = 0;
3875 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3876 needed += size;
3877 break;
3880 case 4:
3882 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3884 size = sizeof(PRINTER_INFO_4W);
3885 if(size <= cbBuf) {
3886 ptr = pPrinter + size;
3887 cbBuf -= size;
3888 memset(pPrinter, 0, size);
3889 } else {
3890 pi4 = NULL;
3891 cbBuf = 0;
3893 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3894 needed += size;
3895 break;
3899 case 5:
3901 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3903 size = sizeof(PRINTER_INFO_5W);
3904 if(size <= cbBuf) {
3905 ptr = pPrinter + size;
3906 cbBuf -= size;
3907 memset(pPrinter, 0, size);
3908 } else {
3909 pi5 = NULL;
3910 cbBuf = 0;
3913 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3914 needed += size;
3915 break;
3919 case 6:
3921 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3923 size = sizeof(PRINTER_INFO_6);
3924 if (size <= cbBuf) {
3925 /* FIXME: We do not update the status yet */
3926 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, L"Status" );
3927 ret = TRUE;
3928 } else {
3929 ret = FALSE;
3932 needed += size;
3933 break;
3936 case 7:
3938 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3940 size = sizeof(PRINTER_INFO_7W);
3941 if (size <= cbBuf) {
3942 ptr = pPrinter + size;
3943 cbBuf -= size;
3944 memset(pPrinter, 0, size);
3945 } else {
3946 pi7 = NULL;
3947 cbBuf = 0;
3950 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3951 needed += size;
3952 break;
3956 case 8:
3957 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
3958 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3959 /* fall through */
3960 case 9:
3962 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3964 size = sizeof(PRINTER_INFO_9W);
3965 if(size <= cbBuf) {
3966 ptr = pPrinter + size;
3967 cbBuf -= size;
3968 memset(pPrinter, 0, size);
3969 } else {
3970 pi9 = NULL;
3971 cbBuf = 0;
3974 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3975 needed += size;
3976 break;
3980 default:
3981 FIXME("Unimplemented level %ld\n", Level);
3982 SetLastError(ERROR_INVALID_LEVEL);
3983 RegCloseKey(hkeyPrinter);
3984 return FALSE;
3987 RegCloseKey(hkeyPrinter);
3989 TRACE("returning %d needed = %ld\n", ret, needed);
3990 if(pcbNeeded) *pcbNeeded = needed;
3991 if(!ret)
3992 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3993 return ret;
3996 /*****************************************************************************
3997 * GetPrinterA [WINSPOOL.@]
3999 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4000 DWORD cbBuf, LPDWORD pcbNeeded)
4002 BOOL ret;
4003 LPBYTE buf = NULL;
4005 if (cbBuf)
4006 buf = malloc(cbBuf);
4008 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4009 if (ret)
4010 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4011 free(buf);
4013 return ret;
4016 /*****************************************************************************
4017 * WINSPOOL_EnumPrintersW
4019 * Implementation of EnumPrintersW
4021 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4022 DWORD dwLevel, LPBYTE lpbPrinters,
4023 DWORD cbBuf, LPDWORD lpdwNeeded,
4024 LPDWORD lpdwReturned)
4027 HKEY printers_key, hkeyPrinter;
4028 WCHAR PrinterName[255];
4029 DWORD needed = 0, number = 0;
4030 DWORD used, i, left;
4031 PBYTE pi, buf;
4033 if(lpbPrinters)
4034 memset(lpbPrinters, 0, cbBuf);
4035 if(lpdwReturned)
4036 *lpdwReturned = 0;
4037 if(lpdwNeeded)
4038 *lpdwNeeded = 0;
4040 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4041 if(dwType == PRINTER_ENUM_DEFAULT)
4042 return TRUE;
4044 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4045 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4046 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4047 if (!dwType) {
4048 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4049 return TRUE;
4054 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4055 FIXME("dwType = %08lx\n", dwType);
4056 SetLastError(ERROR_INVALID_FLAGS);
4057 return FALSE;
4060 if (create_printers_reg_key( system_printers_key, &printers_key ))
4062 ERR("Can't create Printers key\n");
4063 return FALSE;
4066 if (RegQueryInfoKeyA( printers_key, NULL, NULL, NULL, &number, NULL, NULL, NULL, NULL, NULL, NULL, NULL ))
4068 RegCloseKey( printers_key );
4069 ERR("Can't query Printers key\n");
4070 return FALSE;
4072 TRACE("Found %ld printers\n", number);
4074 switch(dwLevel) {
4075 case 1:
4076 used = number * sizeof(PRINTER_INFO_1W);
4077 break;
4078 case 2:
4079 used = number * sizeof(PRINTER_INFO_2W);
4080 break;
4081 case 4:
4082 used = number * sizeof(PRINTER_INFO_4W);
4083 break;
4084 case 5:
4085 used = number * sizeof(PRINTER_INFO_5W);
4086 break;
4088 default:
4089 SetLastError(ERROR_INVALID_LEVEL);
4090 RegCloseKey( printers_key );
4091 return FALSE;
4093 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4095 for(i = 0; i < number; i++) {
4096 if (RegEnumKeyW( printers_key, i, PrinterName, ARRAY_SIZE(PrinterName) ))
4098 ERR("Can't enum key number %ld\n", i);
4099 RegCloseKey( printers_key );
4100 return FALSE;
4102 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
4103 if (RegOpenKeyW( printers_key, PrinterName, &hkeyPrinter ))
4105 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4106 RegCloseKey( printers_key );
4107 return FALSE;
4110 if(cbBuf > used) {
4111 buf = lpbPrinters + used;
4112 left = cbBuf - used;
4113 } else {
4114 buf = NULL;
4115 left = 0;
4118 switch(dwLevel) {
4119 case 1:
4120 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4121 left, &needed);
4122 used += needed;
4123 if(pi) pi += sizeof(PRINTER_INFO_1W);
4124 break;
4125 case 2:
4126 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4127 left, &needed);
4128 used += needed;
4129 if(pi) pi += sizeof(PRINTER_INFO_2W);
4130 break;
4131 case 4:
4132 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4133 left, &needed);
4134 used += needed;
4135 if(pi) pi += sizeof(PRINTER_INFO_4W);
4136 break;
4137 case 5:
4138 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4139 left, &needed);
4140 used += needed;
4141 if(pi) pi += sizeof(PRINTER_INFO_5W);
4142 break;
4143 default:
4144 ERR("Shouldn't be here!\n");
4145 RegCloseKey(hkeyPrinter);
4146 RegCloseKey( printers_key );
4147 return FALSE;
4149 RegCloseKey(hkeyPrinter);
4151 RegCloseKey( printers_key );
4153 if(lpdwNeeded)
4154 *lpdwNeeded = used;
4156 if(used > cbBuf) {
4157 if(lpbPrinters)
4158 memset(lpbPrinters, 0, cbBuf);
4159 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4160 return FALSE;
4162 if(lpdwReturned)
4163 *lpdwReturned = number;
4164 SetLastError(ERROR_SUCCESS);
4165 return TRUE;
4169 /******************************************************************
4170 * EnumPrintersW [WINSPOOL.@]
4172 * Enumerates the available printers, print servers and print
4173 * providers, depending on the specified flags, name and level.
4175 * RETURNS:
4177 * If level is set to 1:
4178 * Returns an array of PRINTER_INFO_1 data structures in the
4179 * lpbPrinters buffer.
4181 * If level is set to 2:
4182 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4183 * Returns an array of PRINTER_INFO_2 data structures in the
4184 * lpbPrinters buffer. Note that according to MSDN also an
4185 * OpenPrinter should be performed on every remote printer.
4187 * If level is set to 4 (officially WinNT only):
4188 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4189 * Fast: Only the registry is queried to retrieve printer names,
4190 * no connection to the driver is made.
4191 * Returns an array of PRINTER_INFO_4 data structures in the
4192 * lpbPrinters buffer.
4194 * If level is set to 5 (officially WinNT4/Win9x only):
4195 * Fast: Only the registry is queried to retrieve printer names,
4196 * no connection to the driver is made.
4197 * Returns an array of PRINTER_INFO_5 data structures in the
4198 * lpbPrinters buffer.
4200 * If level set to 3 or 6+:
4201 * returns zero (failure!)
4203 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4204 * for information.
4206 * BUGS:
4207 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4208 * - Only levels 2, 4 and 5 are implemented at the moment.
4209 * - 16-bit printer drivers are not enumerated.
4210 * - Returned amount of bytes used/needed does not match the real Windoze
4211 * implementation (as in this implementation, all strings are part
4212 * of the buffer, whereas Win32 keeps them somewhere else)
4213 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4215 * NOTE:
4216 * - In a regular Wine installation, no registry settings for printers
4217 * exist, which makes this function return an empty list.
4219 BOOL WINAPI EnumPrintersW(
4220 DWORD dwType, /* [in] Types of print objects to enumerate */
4221 LPWSTR lpszName, /* [in] name of objects to enumerate */
4222 DWORD dwLevel, /* [in] type of printer info structure */
4223 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4224 DWORD cbBuf, /* [in] max size of buffer in bytes */
4225 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4226 LPDWORD lpdwReturned /* [out] number of entries returned */
4229 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4230 lpdwNeeded, lpdwReturned);
4233 /******************************************************************
4234 * EnumPrintersA [WINSPOOL.@]
4236 * See EnumPrintersW
4239 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4240 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4242 BOOL ret;
4243 UNICODE_STRING pNameU;
4244 LPWSTR pNameW;
4245 LPBYTE pPrintersW;
4247 TRACE("(0x%lx, %s, %lu, %p, %ld, %p, %p)\n", flags, debugstr_a(pName), level,
4248 pPrinters, cbBuf, pcbNeeded, pcReturned);
4250 pNameW = asciitounicode(&pNameU, pName);
4252 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4253 MS Office need this */
4254 pPrintersW = (pPrinters && cbBuf) ? malloc(cbBuf) : NULL;
4256 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4258 RtlFreeUnicodeString(&pNameU);
4259 if (ret) {
4260 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4262 free(pPrintersW);
4263 return ret;
4266 /*****************************************************************************
4267 * WINSPOOL_GetDriverInfoFromReg [internal]
4269 * Enters the information from the registry into the DRIVER_INFO struct
4271 * RETURNS
4272 * zero if the printer driver does not exist in the registry
4273 * (only if Level > 1) otherwise nonzero
4275 static BOOL WINSPOOL_GetDriverInfoFromReg(
4276 HKEY hkeyDrivers,
4277 LPWSTR DriverName,
4278 const printenv_t * env,
4279 DWORD Level,
4280 LPBYTE ptr, /* DRIVER_INFO */
4281 LPBYTE pDriverStrings, /* strings buffer */
4282 DWORD cbBuf, /* size of string buffer */
4283 LPDWORD pcbNeeded) /* space needed for str. */
4285 DWORD size, tmp;
4286 HKEY hkeyDriver;
4287 WCHAR driverdir[MAX_PATH];
4288 DWORD dirlen;
4289 LPBYTE strPtr = pDriverStrings;
4290 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4292 TRACE("(%p, %s, %p, %ld, %p, %p, %ld)\n", hkeyDrivers,
4293 debugstr_w(DriverName), env,
4294 Level, di, pDriverStrings, cbBuf);
4296 if (di) ZeroMemory(di, di_sizeof[Level]);
4298 *pcbNeeded = (wcslen( DriverName ) + 1) * sizeof(WCHAR);
4299 if (*pcbNeeded <= cbBuf)
4300 wcscpy( (WCHAR *)strPtr, DriverName );
4302 /* pName for level 1 has a different offset! */
4303 if (Level == 1) {
4304 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4305 return TRUE;
4308 /* .cVersion and .pName for level > 1 */
4309 if (di) {
4310 di->cVersion = env->driverversion;
4311 di->pName = (LPWSTR) strPtr;
4312 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4315 /* Reserve Space for "\\3\\" + \0 */
4316 size = sizeof(driverdir) - 4 * sizeof(WCHAR);
4317 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4318 /* Should never Fail */
4319 return FALSE;
4321 wcscat( driverdir, env->versionsubdir );
4322 wcscat( driverdir, L"\\" );
4324 /* dirlen must not include the terminating zero */
4325 dirlen = wcslen( driverdir ) * sizeof(WCHAR);
4327 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4328 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4329 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4330 return FALSE;
4333 /* pEnvironment */
4334 size = (wcslen( env->envname ) + 1) * sizeof(WCHAR);
4336 *pcbNeeded += size;
4337 if (*pcbNeeded <= cbBuf) {
4338 wcscpy( (WCHAR *)strPtr, env->envname );
4339 if (di) di->pEnvironment = (LPWSTR)strPtr;
4340 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4343 /* .pDriverPath is the Graphics rendering engine.
4344 The full Path is required to avoid a crash in some apps */
4345 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Driver", strPtr, 0, &size ))
4347 *pcbNeeded += size;
4348 if (*pcbNeeded <= cbBuf)
4349 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Driver", strPtr, size, &tmp );
4351 if (di) di->pDriverPath = (LPWSTR)strPtr;
4352 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4355 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4356 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Data File", strPtr, 0, &size ))
4358 *pcbNeeded += size;
4359 if (*pcbNeeded <= cbBuf)
4360 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Data File", strPtr, size, &size );
4362 if (di) di->pDataFile = (LPWSTR)strPtr;
4363 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4366 /* .pConfigFile is the Driver user Interface */
4367 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Configuration File", strPtr, 0, &size ))
4369 *pcbNeeded += size;
4370 if (*pcbNeeded <= cbBuf)
4371 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Configuration File", strPtr, size, &size );
4373 if (di) di->pConfigFile = (LPWSTR)strPtr;
4374 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4377 if (Level == 2 ) {
4378 RegCloseKey(hkeyDriver);
4379 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
4380 return TRUE;
4383 if (Level == 5 ) {
4384 RegCloseKey(hkeyDriver);
4385 FIXME("level 5: incomplete\n");
4386 return TRUE;
4389 /* .pHelpFile */
4390 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Help File", strPtr, 0, &size ))
4392 *pcbNeeded += size;
4393 if (*pcbNeeded <= cbBuf)
4394 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Help File", strPtr, size, &size );
4396 if (di) di->pHelpFile = (LPWSTR)strPtr;
4397 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4400 /* .pDependentFiles */
4401 if (get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Dependent Files", strPtr, 0, &size ))
4403 *pcbNeeded += size;
4404 if (*pcbNeeded <= cbBuf)
4405 get_filename_from_reg( hkeyDriver, driverdir, dirlen, L"Dependent Files", strPtr, size, &size );
4407 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4408 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4410 else if (GetVersion() & 0x80000000) {
4411 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4412 size = 2 * sizeof(WCHAR);
4413 *pcbNeeded += size;
4414 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4416 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4417 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4420 /* .pMonitorName is the optional Language Monitor */
4421 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Monitor", strPtr, 0, &size ))
4423 *pcbNeeded += size;
4424 if (*pcbNeeded <= cbBuf)
4425 WINSPOOL_GetStringFromReg( hkeyDriver, L"Monitor", strPtr, size, &size );
4427 if (di) di->pMonitorName = (LPWSTR)strPtr;
4428 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4431 /* .pDefaultDataType */
4432 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Datatype", strPtr, 0, &size ))
4434 *pcbNeeded += size;
4435 if(*pcbNeeded <= cbBuf)
4436 WINSPOOL_GetStringFromReg( hkeyDriver, L"Datatype", strPtr, size, &size );
4438 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4439 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4442 if (Level == 3 ) {
4443 RegCloseKey(hkeyDriver);
4444 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
4445 return TRUE;
4448 /* .pszzPreviousNames */
4449 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Previous Names", strPtr, 0, &size ))
4451 *pcbNeeded += size;
4452 if(*pcbNeeded <= cbBuf)
4453 WINSPOOL_GetStringFromReg( hkeyDriver, L"Previous Names", strPtr, size, &size );
4455 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4456 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4459 if (Level == 4 ) {
4460 RegCloseKey(hkeyDriver);
4461 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
4462 return TRUE;
4465 /* support is missing, but not important enough for a FIXME */
4466 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4468 /* .pszMfgName */
4469 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Manufacturer", strPtr, 0, &size ))
4471 *pcbNeeded += size;
4472 if(*pcbNeeded <= cbBuf)
4473 WINSPOOL_GetStringFromReg( hkeyDriver, L"Manufacturer", strPtr, size, &size );
4475 if (di) di->pszMfgName = (LPWSTR)strPtr;
4476 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4479 /* .pszOEMUrl */
4480 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"OEM Url", strPtr, 0, &size ))
4482 *pcbNeeded += size;
4483 if(*pcbNeeded <= cbBuf)
4484 WINSPOOL_GetStringFromReg( hkeyDriver, L"OEM Url", strPtr, size, &size );
4486 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4487 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4490 /* .pszHardwareID */
4491 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"HardwareID", strPtr, 0, &size ))
4493 *pcbNeeded += size;
4494 if(*pcbNeeded <= cbBuf)
4495 WINSPOOL_GetStringFromReg( hkeyDriver, L"HardwareID", strPtr, size, &size );
4497 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4498 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4501 /* .pszProvider */
4502 if (WINSPOOL_GetStringFromReg( hkeyDriver, L"Provider", strPtr, 0, &size ))
4504 *pcbNeeded += size;
4505 if(*pcbNeeded <= cbBuf)
4506 WINSPOOL_GetStringFromReg( hkeyDriver, L"Provider", strPtr, size, &size );
4508 if (di) di->pszProvider = (LPWSTR)strPtr;
4509 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4512 if (Level == 6 ) {
4513 RegCloseKey(hkeyDriver);
4514 return TRUE;
4517 /* support is missing, but not important enough for a FIXME */
4518 TRACE("level 8: incomplete\n");
4520 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
4521 RegCloseKey(hkeyDriver);
4522 return TRUE;
4525 /*****************************************************************************
4526 * GetPrinterDriverW [WINSPOOL.@]
4528 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4529 DWORD Level, LPBYTE pDriverInfo,
4530 DWORD cbBuf, LPDWORD pcbNeeded)
4532 LPCWSTR name;
4533 WCHAR DriverName[100];
4534 DWORD ret, type, size, needed = 0;
4535 LPBYTE ptr = NULL;
4536 HKEY hkeyPrinter, hkeyDrivers;
4537 const printenv_t * env;
4539 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
4540 Level,pDriverInfo,cbBuf, pcbNeeded);
4542 if (cbBuf > 0)
4543 ZeroMemory(pDriverInfo, cbBuf);
4545 if (!(name = get_opened_printer_name(hPrinter))) {
4546 SetLastError(ERROR_INVALID_HANDLE);
4547 return FALSE;
4550 if (Level < 1 || Level == 7 || Level > 8) {
4551 SetLastError(ERROR_INVALID_LEVEL);
4552 return FALSE;
4555 env = validate_envW(pEnvironment);
4556 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4558 ret = open_printer_reg_key( name, &hkeyPrinter );
4559 if (ret)
4561 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4562 SetLastError( ret );
4563 return FALSE;
4566 size = sizeof(DriverName);
4567 DriverName[0] = 0;
4568 ret = RegQueryValueExW( hkeyPrinter, L"Printer Driver", 0, &type, (BYTE *)DriverName, &size );
4569 RegCloseKey(hkeyPrinter);
4570 if(ret != ERROR_SUCCESS) {
4571 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4572 return FALSE;
4575 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4576 if(!hkeyDrivers) {
4577 ERR("Can't create Drivers key\n");
4578 return FALSE;
4581 size = di_sizeof[Level];
4582 if ((size <= cbBuf) && pDriverInfo)
4583 ptr = pDriverInfo + size;
4585 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4586 env, Level, pDriverInfo, ptr,
4587 (cbBuf < size) ? 0 : cbBuf - size,
4588 &needed)) {
4589 RegCloseKey(hkeyDrivers);
4590 return FALSE;
4593 RegCloseKey(hkeyDrivers);
4595 if(pcbNeeded) *pcbNeeded = size + needed;
4596 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
4597 if(cbBuf >= size + needed) return TRUE;
4598 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4599 return FALSE;
4602 /*****************************************************************************
4603 * GetPrinterDriverA [WINSPOOL.@]
4605 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4606 DWORD Level, LPBYTE pDriverInfo,
4607 DWORD cbBuf, LPDWORD pcbNeeded)
4609 BOOL ret;
4610 UNICODE_STRING pEnvW;
4611 PWSTR pwstrEnvW;
4612 LPBYTE buf = NULL;
4614 if (cbBuf)
4616 ZeroMemory(pDriverInfo, cbBuf);
4617 buf = malloc(cbBuf);
4620 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4621 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4622 cbBuf, pcbNeeded);
4623 if (ret)
4624 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4626 free(buf);
4628 RtlFreeUnicodeString(&pEnvW);
4629 return ret;
4632 /*****************************************************************************
4633 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4635 * Return the PATH for the Printer-Drivers (UNICODE)
4637 * PARAMS
4638 * pName [I] Servername (NT only) or NULL (local Computer)
4639 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4640 * Level [I] Structure-Level (must be 1)
4641 * pDriverDirectory [O] PTR to Buffer that receives the Result
4642 * cbBuf [I] Size of Buffer at pDriverDirectory
4643 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4644 * required for pDriverDirectory
4646 * RETURNS
4647 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4648 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4649 * if cbBuf is too small
4651 * Native Values returned in pDriverDirectory on Success:
4652 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4653 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4654 *| win9x(Windows 4.0): "%winsysdir%"
4656 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4658 * FIXME
4659 *- Only NULL or "" is supported for pName
4662 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4663 DWORD Level, LPBYTE pDriverDirectory,
4664 DWORD cbBuf, LPDWORD pcbNeeded)
4666 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
4667 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4669 if ((backend == NULL) && !load_backend()) return FALSE;
4671 if (Level != 1) {
4672 /* (Level != 1) is ignored in win9x */
4673 SetLastError(ERROR_INVALID_LEVEL);
4674 return FALSE;
4676 if (pcbNeeded == NULL) {
4677 /* (pcbNeeded == NULL) is ignored in win9x */
4678 SetLastError(RPC_X_NULL_REF_POINTER);
4679 return FALSE;
4682 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4683 pDriverDirectory, cbBuf, pcbNeeded);
4688 /*****************************************************************************
4689 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4691 * Return the PATH for the Printer-Drivers (ANSI)
4693 * See GetPrinterDriverDirectoryW.
4695 * NOTES
4696 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4699 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4700 DWORD Level, LPBYTE pDriverDirectory,
4701 DWORD cbBuf, LPDWORD pcbNeeded)
4703 UNICODE_STRING nameW, environmentW;
4704 BOOL ret;
4705 DWORD pcbNeededW;
4706 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4707 WCHAR *driverDirectoryW = NULL;
4709 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
4710 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4712 if (len) driverDirectoryW = malloc( len );
4714 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4715 else nameW.Buffer = NULL;
4716 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4717 else environmentW.Buffer = NULL;
4719 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4720 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4721 if (ret) {
4722 DWORD needed;
4723 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4724 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4725 if(pcbNeeded)
4726 *pcbNeeded = needed;
4727 ret = needed <= cbBuf;
4728 } else
4729 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4731 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4733 free( driverDirectoryW );
4734 RtlFreeUnicodeString(&environmentW);
4735 RtlFreeUnicodeString(&nameW);
4737 return ret;
4740 /*****************************************************************************
4741 * AddPrinterDriverA [WINSPOOL.@]
4743 * See AddPrinterDriverW.
4746 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4748 TRACE("(%s, %ld, %p)\n", debugstr_a(pName), level, pDriverInfo);
4749 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4752 /******************************************************************************
4753 * AddPrinterDriverW (WINSPOOL.@)
4755 * Install a Printer Driver
4757 * PARAMS
4758 * pName [I] Servername or NULL (local Computer)
4759 * level [I] Level for the supplied DRIVER_INFO_*W struct
4760 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4762 * RESULTS
4763 * Success: TRUE
4764 * Failure: FALSE
4767 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4769 TRACE("(%s, %ld, %p)\n", debugstr_w(pName), level, pDriverInfo);
4770 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4773 /*****************************************************************************
4774 * AddPrintProcessorA [WINSPOOL.@]
4776 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4777 LPSTR pPrintProcessorName)
4779 UNICODE_STRING NameW, EnvW, PathW, ProcessorW;
4780 BOOL ret;
4782 TRACE("(%s,%s,%s,%s)\n", debugstr_a(pName), debugstr_a(pEnvironment),
4783 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4785 asciitounicode(&NameW, pName);
4786 asciitounicode(&EnvW, pEnvironment);
4787 asciitounicode(&PathW, pPathName);
4788 asciitounicode(&ProcessorW, pPrintProcessorName);
4790 ret = AddPrintProcessorW(NameW.Buffer, EnvW.Buffer, PathW.Buffer, ProcessorW.Buffer);
4792 RtlFreeUnicodeString(&ProcessorW);
4793 RtlFreeUnicodeString(&PathW);
4794 RtlFreeUnicodeString(&EnvW);
4795 RtlFreeUnicodeString(&NameW);
4797 return ret;
4800 /*****************************************************************************
4801 * AddPrintProcessorW [WINSPOOL.@]
4803 BOOL WINAPI AddPrintProcessorW(WCHAR *name, WCHAR *env, WCHAR *path, WCHAR *print_proc)
4805 TRACE("(%s,%s,%s,%s)\n", debugstr_w(name), debugstr_w(env),
4806 debugstr_w(path), debugstr_w(print_proc));
4808 if (!path || !print_proc)
4810 SetLastError(ERROR_INVALID_PARAMETER);
4811 return FALSE;
4814 if ((backend == NULL) && !load_backend()) return FALSE;
4815 return backend->fpAddPrintProcessor(name, env, path, print_proc);
4818 /*****************************************************************************
4819 * AddPrintProvidorA [WINSPOOL.@]
4821 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4823 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4824 return FALSE;
4827 /*****************************************************************************
4828 * AddPrintProvidorW [WINSPOOL.@]
4830 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4832 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4833 return FALSE;
4836 /*****************************************************************************
4837 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4839 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4840 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4842 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4843 pDevModeOutput, pDevModeInput);
4844 return 0;
4847 /*****************************************************************************
4848 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4850 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4851 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4853 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4854 pDevModeOutput, pDevModeInput);
4855 return 0;
4858 /*****************************************************************************
4859 * PrinterProperties [WINSPOOL.@]
4861 * Displays a dialog to set the properties of the printer.
4863 * RETURNS
4864 * nonzero on success or zero on failure
4866 * BUGS
4867 * implemented as stub only
4869 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4870 HANDLE hPrinter /* [in] handle to printer object */
4872 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4873 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4874 return FALSE;
4877 /*****************************************************************************
4878 * EnumJobsA [WINSPOOL.@]
4881 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4882 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4883 LPDWORD pcReturned)
4885 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4886 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4888 if(pcbNeeded) *pcbNeeded = 0;
4889 if(pcReturned) *pcReturned = 0;
4890 return FALSE;
4894 /*****************************************************************************
4895 * EnumJobsW [WINSPOOL.@]
4898 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4899 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4900 LPDWORD pcReturned)
4902 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4903 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4905 if(pcbNeeded) *pcbNeeded = 0;
4906 if(pcReturned) *pcReturned = 0;
4907 return FALSE;
4910 /*****************************************************************************
4911 * WINSPOOL_EnumPrinterDrivers [internal]
4913 * Delivers information about all printer drivers installed on the
4914 * localhost or a given server
4916 * RETURNS
4917 * nonzero on success or zero on failure. If the buffer for the returned
4918 * information is too small the function will return an error
4920 * BUGS
4921 * - only implemented for localhost, foreign hosts will return an error
4923 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4924 DWORD Level, LPBYTE pDriverInfo,
4925 DWORD driver_index,
4926 DWORD cbBuf, LPDWORD pcbNeeded,
4927 LPDWORD pcFound, DWORD data_offset)
4929 { HKEY hkeyDrivers;
4930 DWORD i, size = 0;
4931 const printenv_t * env;
4933 TRACE("%s,%s,%ld,%p,%ld,%ld,%ld\n",
4934 debugstr_w(pName), debugstr_w(pEnvironment),
4935 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4937 env = validate_envW(pEnvironment);
4938 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4940 *pcFound = 0;
4942 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4943 if(!hkeyDrivers) {
4944 ERR("Can't open Drivers key\n");
4945 return FALSE;
4948 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4949 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4950 RegCloseKey(hkeyDrivers);
4951 ERR("Can't query Drivers key\n");
4952 return FALSE;
4954 TRACE("Found %ld Drivers\n", *pcFound);
4956 /* get size of single struct
4957 * unicode and ascii structure have the same size
4959 size = di_sizeof[Level];
4961 if (data_offset == 0)
4962 data_offset = size * (*pcFound);
4963 *pcbNeeded = data_offset;
4965 for( i = 0; i < *pcFound; i++) {
4966 WCHAR DriverNameW[255];
4967 PBYTE table_ptr = NULL;
4968 PBYTE data_ptr = NULL;
4969 DWORD needed = 0;
4971 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, ARRAY_SIZE(DriverNameW)) != ERROR_SUCCESS) {
4972 ERR("Can't enum key number %ld\n", i);
4973 RegCloseKey(hkeyDrivers);
4974 return FALSE;
4977 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4978 table_ptr = pDriverInfo + (driver_index + i) * size;
4979 if (pDriverInfo && *pcbNeeded <= cbBuf)
4980 data_ptr = pDriverInfo + *pcbNeeded;
4982 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4983 env, Level, table_ptr, data_ptr,
4984 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4985 &needed)) {
4986 RegCloseKey(hkeyDrivers);
4987 return FALSE;
4990 *pcbNeeded += needed;
4993 RegCloseKey(hkeyDrivers);
4995 if(cbBuf < *pcbNeeded){
4996 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4997 return FALSE;
5000 return TRUE;
5003 /*****************************************************************************
5004 * EnumPrinterDriversW [WINSPOOL.@]
5006 * see function EnumPrinterDrivers for RETURNS, BUGS
5008 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5009 LPBYTE pDriverInfo, DWORD cbBuf,
5010 LPDWORD pcbNeeded, LPDWORD pcReturned)
5012 BOOL ret;
5013 DWORD found;
5015 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5017 SetLastError(RPC_X_NULL_REF_POINTER);
5018 return FALSE;
5021 /* check for local drivers */
5022 if((pName) && (pName[0])) {
5023 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5024 SetLastError(ERROR_ACCESS_DENIED);
5025 return FALSE;
5028 /* check input parameter */
5029 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5030 SetLastError(ERROR_INVALID_LEVEL);
5031 return FALSE;
5034 if(pDriverInfo && cbBuf > 0)
5035 memset( pDriverInfo, 0, cbBuf);
5037 /* Exception: pull all printers */
5038 if (pEnvironment && !wcscmp( pEnvironment, L"all" ))
5040 DWORD i, needed, bufsize = cbBuf;
5041 DWORD total_found = 0;
5042 DWORD data_offset;
5044 /* Precompute the overall total; we need this to know
5045 where pointers end and data begins (i.e. data_offset) */
5046 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5048 needed = found = 0;
5049 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5050 NULL, 0, 0, &needed, &found, 0);
5051 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5052 total_found += found;
5055 data_offset = di_sizeof[Level] * total_found;
5057 *pcReturned = 0;
5058 *pcbNeeded = 0;
5059 total_found = 0;
5060 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5062 needed = found = 0;
5063 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5064 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5065 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5066 else if (ret)
5067 *pcReturned += found;
5068 *pcbNeeded = needed;
5069 data_offset = needed;
5070 total_found += found;
5072 return ret;
5075 /* Normal behavior */
5076 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5077 0, cbBuf, pcbNeeded, &found, 0);
5078 if (ret)
5079 *pcReturned = found;
5081 return ret;
5084 /*****************************************************************************
5085 * EnumPrinterDriversA [WINSPOOL.@]
5087 * see function EnumPrinterDrivers for RETURNS, BUGS
5089 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5090 LPBYTE pDriverInfo, DWORD cbBuf,
5091 LPDWORD pcbNeeded, LPDWORD pcReturned)
5093 BOOL ret;
5094 UNICODE_STRING pNameW, pEnvironmentW;
5095 PWSTR pwstrNameW, pwstrEnvironmentW;
5096 LPBYTE buf = NULL;
5098 if (cbBuf)
5099 buf = malloc(cbBuf);
5101 pwstrNameW = asciitounicode(&pNameW, pName);
5102 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5104 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5105 buf, cbBuf, pcbNeeded, pcReturned);
5106 if (ret)
5107 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5109 free(buf);
5111 RtlFreeUnicodeString(&pNameW);
5112 RtlFreeUnicodeString(&pEnvironmentW);
5114 return ret;
5117 /******************************************************************************
5118 * EnumPortsA (WINSPOOL.@)
5120 * See EnumPortsW.
5123 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5124 LPDWORD pcbNeeded, LPDWORD pcReturned)
5126 BOOL res;
5127 LPBYTE bufferW = NULL;
5128 LPWSTR nameW = NULL;
5129 DWORD needed = 0;
5130 DWORD numentries = 0;
5131 INT len;
5133 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5134 cbBuf, pcbNeeded, pcReturned);
5136 /* convert servername to unicode */
5137 if (pName) {
5138 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5139 nameW = malloc(len * sizeof(WCHAR));
5140 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5142 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5143 needed = cbBuf * sizeof(WCHAR);
5144 if (needed) bufferW = malloc(needed);
5145 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5147 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5148 if (pcbNeeded) needed = *pcbNeeded;
5149 /* HeapReAlloc return NULL, when bufferW was NULL */
5150 bufferW = (bufferW) ? realloc(bufferW, needed) : malloc(needed);
5152 /* Try again with the large Buffer */
5153 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5155 needed = pcbNeeded ? *pcbNeeded : 0;
5156 numentries = pcReturned ? *pcReturned : 0;
5159 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5160 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5162 if (res) {
5163 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5164 DWORD entrysize = 0;
5165 DWORD index;
5166 LPSTR ptr;
5167 LPPORT_INFO_2W pi2w;
5168 LPPORT_INFO_2A pi2a;
5170 needed = 0;
5171 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5173 /* First pass: calculate the size for all Entries */
5174 pi2w = (LPPORT_INFO_2W) bufferW;
5175 pi2a = (LPPORT_INFO_2A) pPorts;
5176 index = 0;
5177 while (index < numentries) {
5178 index++;
5179 needed += entrysize; /* PORT_INFO_?A */
5180 TRACE("%p: parsing #%ld (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5182 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5183 NULL, 0, NULL, NULL);
5184 if (Level > 1) {
5185 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5186 NULL, 0, NULL, NULL);
5187 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5188 NULL, 0, NULL, NULL);
5190 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5191 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5192 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5195 /* check for errors and quit on failure */
5196 if (cbBuf < needed) {
5197 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5198 res = FALSE;
5199 goto cleanup;
5201 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5202 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5203 cbBuf -= len ; /* free Bytes in the user-Buffer */
5204 pi2w = (LPPORT_INFO_2W) bufferW;
5205 pi2a = (LPPORT_INFO_2A) pPorts;
5206 index = 0;
5207 /* Second Pass: Fill the User Buffer (if we have one) */
5208 while ((index < numentries) && pPorts) {
5209 index++;
5210 TRACE("%p: writing PORT_INFO_%ldA #%ld\n", pi2a, Level, index);
5211 pi2a->pPortName = ptr;
5212 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5213 ptr, cbBuf , NULL, NULL);
5214 ptr += len;
5215 cbBuf -= len;
5216 if (Level > 1) {
5217 pi2a->pMonitorName = ptr;
5218 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5219 ptr, cbBuf, NULL, NULL);
5220 ptr += len;
5221 cbBuf -= len;
5223 pi2a->pDescription = ptr;
5224 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5225 ptr, cbBuf, NULL, NULL);
5226 ptr += len;
5227 cbBuf -= len;
5229 pi2a->fPortType = pi2w->fPortType;
5230 pi2a->Reserved = 0; /* documented: "must be zero" */
5233 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5234 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5235 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5239 cleanup:
5240 if (pcbNeeded) *pcbNeeded = needed;
5241 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5243 free(nameW);
5244 free(bufferW);
5246 TRACE("returning %d with %ld (%ld byte for %ld of %ld entries)\n",
5247 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5249 return (res);
5253 /******************************************************************************
5254 * EnumPortsW (WINSPOOL.@)
5256 * Enumerate available Ports
5258 * PARAMS
5259 * pName [I] Servername or NULL (local Computer)
5260 * Level [I] Structure-Level (1 or 2)
5261 * pPorts [O] PTR to Buffer that receives the Result
5262 * cbBuf [I] Size of Buffer at pPorts
5263 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5264 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5266 * RETURNS
5267 * Success: TRUE
5268 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5271 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5274 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5275 cbBuf, pcbNeeded, pcReturned);
5277 if ((backend == NULL) && !load_backend()) return FALSE;
5279 /* Level is not checked in win9x */
5280 if (!Level || (Level > 2)) {
5281 WARN("level (%ld) is ignored in win9x\n", Level);
5282 SetLastError(ERROR_INVALID_LEVEL);
5283 return FALSE;
5285 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5286 SetLastError(RPC_X_NULL_REF_POINTER);
5287 return FALSE;
5290 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5293 /******************************************************************************
5294 * GetDefaultPrinterW (WINSPOOL.@)
5296 * FIXME
5297 * This function must read the value from data 'device' of key
5298 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5300 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5302 BOOL retval = TRUE;
5303 DWORD insize, len;
5304 WCHAR *buffer, *ptr;
5306 if (!namesize)
5308 SetLastError(ERROR_INVALID_PARAMETER);
5309 return FALSE;
5312 /* make the buffer big enough for the stuff from the profile/registry,
5313 * the content must fit into the local buffer to compute the correct
5314 * size even if the extern buffer is too small or not given.
5315 * (20 for ,driver,port) */
5316 insize = *namesize;
5317 len = max(100, (insize + 20));
5318 buffer = malloc( len * sizeof(WCHAR));
5320 if (!GetProfileStringW( L"windows", L"device", L"", buffer, len ))
5322 SetLastError (ERROR_FILE_NOT_FOUND);
5323 retval = FALSE;
5324 goto end;
5326 TRACE("%s\n", debugstr_w(buffer));
5328 if ((ptr = wcschr( buffer, ',' )) == NULL)
5330 SetLastError(ERROR_INVALID_NAME);
5331 retval = FALSE;
5332 goto end;
5335 *ptr = 0;
5336 *namesize = wcslen( buffer ) + 1;
5337 if(!name || (*namesize > insize))
5339 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5340 retval = FALSE;
5341 goto end;
5343 wcscpy( name, buffer );
5345 end:
5346 free( buffer);
5347 return retval;
5351 /******************************************************************************
5352 * GetDefaultPrinterA (WINSPOOL.@)
5354 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5356 BOOL retval = TRUE;
5357 DWORD insize = 0;
5358 WCHAR *bufferW = NULL;
5360 if (!namesize)
5362 SetLastError(ERROR_INVALID_PARAMETER);
5363 return FALSE;
5366 if(name && *namesize) {
5367 insize = *namesize;
5368 bufferW = malloc( insize * sizeof(WCHAR));
5371 if(!GetDefaultPrinterW( bufferW, namesize)) {
5372 retval = FALSE;
5373 goto end;
5376 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5377 NULL, NULL);
5378 if (!*namesize)
5380 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5381 retval = FALSE;
5383 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
5385 end:
5386 free( bufferW);
5387 return retval;
5391 /******************************************************************************
5392 * SetDefaultPrinterW (WINSPOOL.204)
5394 * Set the Name of the Default Printer
5396 * PARAMS
5397 * pszPrinter [I] Name of the Printer or NULL
5399 * RETURNS
5400 * Success: True
5401 * Failure: FALSE
5403 * NOTES
5404 * When the Parameter is NULL or points to an Empty String and
5405 * a Default Printer was already present, then this Function changes nothing.
5406 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5407 * the First enumerated local Printer is used.
5410 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5412 WCHAR default_printer[MAX_PATH];
5413 LPWSTR buffer = NULL;
5414 HKEY hreg;
5415 DWORD size;
5416 DWORD namelen;
5417 LONG lres;
5419 TRACE("(%s)\n", debugstr_w(pszPrinter));
5420 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5422 default_printer[0] = '\0';
5423 size = ARRAY_SIZE(default_printer);
5425 /* if we have a default Printer, do nothing. */
5426 if (GetDefaultPrinterW(default_printer, &size))
5427 return TRUE;
5429 pszPrinter = NULL;
5430 /* we have no default Printer: search local Printers and use the first */
5431 if (!create_printers_reg_key( system_printers_key, &hreg ))
5433 default_printer[0] = '\0';
5434 size = ARRAY_SIZE(default_printer);
5435 if (!RegEnumKeyExW( hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL ))
5437 pszPrinter = default_printer;
5438 TRACE("using %s\n", debugstr_w(pszPrinter));
5440 RegCloseKey( hreg );
5443 if (pszPrinter == NULL) {
5444 TRACE("no local printer found\n");
5445 SetLastError(ERROR_FILE_NOT_FOUND);
5446 return FALSE;
5450 /* "pszPrinter" is never empty or NULL here. */
5451 namelen = wcslen( pszPrinter );
5452 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5453 buffer = malloc(size * sizeof(WCHAR));
5454 if (!buffer || create_printers_reg_key( user_printers_key, &hreg ))
5456 free(buffer);
5457 SetLastError(ERROR_FILE_NOT_FOUND);
5458 return FALSE;
5461 /* read the devices entry for the printer (driver,port) to build the string for the
5462 default device entry (printer,driver,port) */
5463 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5464 buffer[namelen] = ',';
5465 namelen++; /* move index to the start of the driver */
5467 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5468 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5469 if (!lres) {
5470 HKEY hdev;
5472 if (!create_printers_reg_key( user_default_key, &hdev ))
5474 RegSetValueExW( hdev, L"device", 0, REG_SZ, (BYTE *)buffer, (wcslen( buffer ) + 1) * sizeof(WCHAR) );
5475 RegCloseKey(hdev);
5478 else
5480 if (lres != ERROR_FILE_NOT_FOUND)
5481 FIXME("RegQueryValueExW failed with %ld for %s\n", lres, debugstr_w(pszPrinter));
5483 SetLastError(ERROR_INVALID_PRINTER_NAME);
5486 RegCloseKey(hreg);
5487 free(buffer);
5488 return (lres == ERROR_SUCCESS);
5491 /******************************************************************************
5492 * SetDefaultPrinterA (WINSPOOL.202)
5494 * See SetDefaultPrinterW.
5497 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5499 LPWSTR bufferW = NULL;
5500 BOOL res;
5502 TRACE("(%s)\n", debugstr_a(pszPrinter));
5503 if(pszPrinter) {
5504 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5505 bufferW = malloc(len * sizeof(WCHAR));
5506 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5508 res = SetDefaultPrinterW(bufferW);
5509 free(bufferW);
5510 return res;
5513 /******************************************************************************
5514 * SetPrinterDataExA (WINSPOOL.@)
5516 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5517 LPCSTR pValueName, DWORD Type,
5518 LPBYTE pData, DWORD cbData)
5520 HKEY hkeyPrinter, hkeySubkey;
5521 DWORD ret;
5523 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
5524 debugstr_a(pValueName), Type, pData, cbData);
5526 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5527 != ERROR_SUCCESS)
5528 return ret;
5530 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5531 != ERROR_SUCCESS) {
5532 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5533 RegCloseKey(hkeyPrinter);
5534 return ret;
5536 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5537 RegCloseKey(hkeySubkey);
5538 RegCloseKey(hkeyPrinter);
5539 return ret;
5542 /******************************************************************************
5543 * SetPrinterDataExW (WINSPOOL.@)
5545 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5546 LPCWSTR pValueName, DWORD Type,
5547 LPBYTE pData, DWORD cbData)
5549 HKEY hkeyPrinter, hkeySubkey;
5550 DWORD ret;
5552 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
5553 debugstr_w(pValueName), Type, pData, cbData);
5555 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5556 != ERROR_SUCCESS)
5557 return ret;
5559 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5560 != ERROR_SUCCESS) {
5561 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5562 RegCloseKey(hkeyPrinter);
5563 return ret;
5565 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5566 RegCloseKey(hkeySubkey);
5567 RegCloseKey(hkeyPrinter);
5568 return ret;
5571 /******************************************************************************
5572 * SetPrinterDataA (WINSPOOL.@)
5574 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5575 LPBYTE pData, DWORD cbData)
5577 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5578 pData, cbData);
5581 /******************************************************************************
5582 * SetPrinterDataW (WINSPOOL.@)
5584 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5585 LPBYTE pData, DWORD cbData)
5587 return SetPrinterDataExW( hPrinter, L"PrinterDriverData", pValueName, Type,
5588 pData, cbData );
5591 /******************************************************************************
5592 * GetPrinterDataExA (WINSPOOL.@)
5594 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5595 LPCSTR pValueName, LPDWORD pType,
5596 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5598 opened_printer_t *printer;
5599 HKEY printers_key, hkeyPrinter = 0, hkeySubkey = 0;
5600 DWORD ret;
5602 TRACE("(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter, debugstr_a(pKeyName),
5603 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5605 printer = get_opened_printer(hPrinter);
5606 if(!printer) return ERROR_INVALID_HANDLE;
5608 ret = create_printers_reg_key( system_printers_key, &printers_key );
5609 if (ret) return ret;
5611 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5613 if (printer->name) {
5615 ret = RegOpenKeyW( printers_key, printer->name, &hkeyPrinter );
5616 if (ret)
5618 RegCloseKey( printers_key );
5619 return ret;
5621 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5622 WARN("Can't open subkey %s: %ld\n", debugstr_a(pKeyName), ret);
5623 RegCloseKey(hkeyPrinter);
5624 RegCloseKey( printers_key );
5625 return ret;
5628 *pcbNeeded = nSize;
5629 ret = RegQueryValueExA( printer->name ? hkeySubkey : printers_key, pValueName,
5630 0, pType, pData, pcbNeeded );
5632 if (!ret && !pData) ret = ERROR_MORE_DATA;
5634 RegCloseKey(hkeySubkey);
5635 RegCloseKey(hkeyPrinter);
5636 RegCloseKey( printers_key );
5638 TRACE("--> %ld\n", ret);
5639 return ret;
5642 /******************************************************************************
5643 * GetPrinterDataExW (WINSPOOL.@)
5645 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5646 LPCWSTR pValueName, LPDWORD pType,
5647 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5649 opened_printer_t *printer;
5650 HKEY printers_key, hkeyPrinter = 0, hkeySubkey = 0;
5651 DWORD ret;
5653 TRACE("(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter, debugstr_w(pKeyName),
5654 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5656 printer = get_opened_printer(hPrinter);
5657 if(!printer) return ERROR_INVALID_HANDLE;
5659 ret = create_printers_reg_key( system_printers_key, &printers_key );
5660 if (ret) return ret;
5662 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5664 if (printer->name)
5666 ret = RegOpenKeyW( printers_key, printer->name, &hkeyPrinter);
5667 if (ret)
5669 RegCloseKey( printers_key );
5670 return ret;
5672 if ((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS)
5674 WARN("Can't open subkey %s: %ld\n", debugstr_w(pKeyName), ret);
5675 RegCloseKey(hkeyPrinter);
5676 RegCloseKey( printers_key );
5677 return ret;
5680 *pcbNeeded = nSize;
5681 ret = RegQueryValueExW( printer->name ? hkeySubkey : printers_key, pValueName,
5682 0, pType, pData, pcbNeeded );
5684 if (!ret && !pData) ret = ERROR_MORE_DATA;
5686 RegCloseKey(hkeySubkey);
5687 RegCloseKey(hkeyPrinter);
5688 RegCloseKey( printers_key );
5690 TRACE("--> %ld\n", ret);
5691 return ret;
5694 /******************************************************************************
5695 * GetPrinterDataA (WINSPOOL.@)
5697 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5698 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5700 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5701 pData, nSize, pcbNeeded);
5704 /******************************************************************************
5705 * GetPrinterDataW (WINSPOOL.@)
5707 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5708 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5710 return GetPrinterDataExW( hPrinter, L"PrinterDriverData", pValueName, pType,
5711 pData, nSize, pcbNeeded );
5714 /*******************************************************************************
5715 * EnumPrinterDataExW [WINSPOOL.@]
5717 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5718 LPBYTE pEnumValues, DWORD cbEnumValues,
5719 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5721 HKEY hkPrinter, hkSubKey;
5722 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5723 cbValueNameLen, cbMaxValueLen, cbValueLen,
5724 cbBufSize, dwType;
5725 LPWSTR lpValueName;
5726 PBYTE lpValue;
5727 PPRINTER_ENUM_VALUESW ppev;
5729 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5731 if (pKeyName == NULL || *pKeyName == 0)
5732 return ERROR_INVALID_PARAMETER;
5734 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5735 if (ret != ERROR_SUCCESS)
5737 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
5738 hPrinter, ret);
5739 return ret;
5742 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5743 if (ret != ERROR_SUCCESS)
5745 r = RegCloseKey (hkPrinter);
5746 if (r != ERROR_SUCCESS)
5747 WARN ("RegCloseKey returned %li\n", r);
5748 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
5749 debugstr_w (pKeyName), ret);
5750 return ret;
5753 ret = RegCloseKey (hkPrinter);
5754 if (ret != ERROR_SUCCESS)
5756 ERR ("RegCloseKey returned %li\n", ret);
5757 r = RegCloseKey (hkSubKey);
5758 if (r != ERROR_SUCCESS)
5759 WARN ("RegCloseKey returned %li\n", r);
5760 return ret;
5763 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5764 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5765 if (ret != ERROR_SUCCESS)
5767 r = RegCloseKey (hkSubKey);
5768 if (r != ERROR_SUCCESS)
5769 WARN ("RegCloseKey returned %li\n", r);
5770 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
5771 return ret;
5774 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
5775 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5777 if (cValues == 0) /* empty key */
5779 r = RegCloseKey (hkSubKey);
5780 if (r != ERROR_SUCCESS)
5781 WARN ("RegCloseKey returned %li\n", r);
5782 *pcbEnumValues = *pnEnumValues = 0;
5783 return ERROR_SUCCESS;
5786 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5788 lpValueName = malloc (cbMaxValueNameLen * sizeof(WCHAR));
5789 if (lpValueName == NULL)
5791 ERR ("Failed to allocate %li WCHARs\n", cbMaxValueNameLen);
5792 r = RegCloseKey (hkSubKey);
5793 if (r != ERROR_SUCCESS)
5794 WARN ("RegCloseKey returned %li\n", r);
5795 return ERROR_OUTOFMEMORY;
5798 lpValue = malloc (cbMaxValueLen);
5799 if (lpValue == NULL)
5801 ERR ("Failed to allocate %li bytes\n", cbMaxValueLen);
5802 free (lpValueName);
5803 r = RegCloseKey (hkSubKey);
5804 if (r != ERROR_SUCCESS)
5805 WARN ("RegCloseKey returned %li\n", r);
5806 return ERROR_OUTOFMEMORY;
5809 TRACE ("pass 1: calculating buffer required for all names and values\n");
5811 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5813 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
5815 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5817 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5818 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5819 NULL, NULL, lpValue, &cbValueLen);
5820 if (ret != ERROR_SUCCESS)
5822 free (lpValue);
5823 free (lpValueName);
5824 r = RegCloseKey (hkSubKey);
5825 if (r != ERROR_SUCCESS)
5826 WARN ("RegCloseKey returned %li\n", r);
5827 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
5828 return ret;
5831 TRACE ("%s [%li]: name needs %li WCHARs, data needs %li bytes\n",
5832 debugstr_w (lpValueName), dwIndex,
5833 cbValueNameLen + 1, cbValueLen);
5835 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5836 cbBufSize += cbValueLen;
5839 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
5841 *pcbEnumValues = cbBufSize;
5842 *pnEnumValues = cValues;
5844 if (cbEnumValues < cbBufSize) /* buffer too small */
5846 free (lpValue);
5847 free (lpValueName);
5848 r = RegCloseKey (hkSubKey);
5849 if (r != ERROR_SUCCESS)
5850 WARN ("RegCloseKey returned %li\n", r);
5851 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
5852 return ERROR_MORE_DATA;
5855 TRACE ("pass 2: copying all names and values to buffer\n");
5857 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5858 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5860 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5862 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5863 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5864 NULL, &dwType, lpValue, &cbValueLen);
5865 if (ret != ERROR_SUCCESS)
5867 free (lpValue);
5868 free (lpValueName);
5869 r = RegCloseKey (hkSubKey);
5870 if (r != ERROR_SUCCESS)
5871 WARN ("RegCloseKey returned %li\n", r);
5872 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
5873 return ret;
5876 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5877 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5878 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5879 pEnumValues += cbValueNameLen;
5881 /* return # of *bytes* (including trailing \0), not # of chars */
5882 ppev[dwIndex].cbValueName = cbValueNameLen;
5884 ppev[dwIndex].dwType = dwType;
5886 memcpy (pEnumValues, lpValue, cbValueLen);
5887 ppev[dwIndex].pData = pEnumValues;
5888 pEnumValues += cbValueLen;
5890 ppev[dwIndex].cbData = cbValueLen;
5892 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
5893 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5896 free (lpValue);
5897 free (lpValueName);
5899 ret = RegCloseKey (hkSubKey);
5900 if (ret != ERROR_SUCCESS)
5902 ERR ("RegCloseKey returned %li\n", ret);
5903 return ret;
5906 return ERROR_SUCCESS;
5909 /*******************************************************************************
5910 * EnumPrinterDataExA [WINSPOOL.@]
5912 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5913 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5914 * what Windows 2000 SP1 does.
5917 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5918 LPBYTE pEnumValues, DWORD cbEnumValues,
5919 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5921 INT len;
5922 LPWSTR pKeyNameW;
5923 DWORD ret, dwIndex, dwBufSize;
5924 LPSTR pBuffer;
5926 TRACE ("%p %s\n", hPrinter, pKeyName);
5928 if (pKeyName == NULL || *pKeyName == 0)
5929 return ERROR_INVALID_PARAMETER;
5931 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5932 if (len == 0)
5934 ret = GetLastError ();
5935 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5936 return ret;
5939 pKeyNameW = malloc (len * sizeof(WCHAR));
5940 if (pKeyNameW == NULL)
5942 ERR ("Failed to allocate %li bytes\n",
5943 (LONG)(len * sizeof (WCHAR)));
5944 return ERROR_OUTOFMEMORY;
5947 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5949 ret = GetLastError ();
5950 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5951 free (pKeyNameW);
5952 return ret;
5955 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5956 pcbEnumValues, pnEnumValues);
5957 free (pKeyNameW);
5958 if (ret != ERROR_SUCCESS)
5960 TRACE ("EnumPrinterDataExW returned %li\n", ret);
5961 return ret;
5964 if (*pnEnumValues == 0) /* empty key */
5965 return ERROR_SUCCESS;
5967 dwBufSize = 0;
5968 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5970 PPRINTER_ENUM_VALUESW ppev =
5971 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5973 if (dwBufSize < ppev->cbValueName)
5974 dwBufSize = ppev->cbValueName;
5976 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5977 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5978 dwBufSize = ppev->cbData;
5981 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5983 pBuffer = malloc(dwBufSize);
5984 if (pBuffer == NULL)
5986 ERR ("Failed to allocate %li bytes\n", dwBufSize);
5987 return ERROR_OUTOFMEMORY;
5990 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5992 PPRINTER_ENUM_VALUESW ppev =
5993 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5995 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5996 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5997 NULL);
5998 if (len == 0)
6000 ret = GetLastError ();
6001 ERR ("WideCharToMultiByte failed with code %li\n", ret);
6002 free (pBuffer);
6003 return ret;
6006 memcpy (ppev->pValueName, pBuffer, len);
6008 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer);
6010 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6011 ppev->dwType != REG_MULTI_SZ)
6012 continue;
6014 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6015 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6016 if (len == 0)
6018 ret = GetLastError ();
6019 ERR ("WideCharToMultiByte failed with code %li\n", ret);
6020 free (pBuffer);
6021 return ret;
6024 memcpy (ppev->pData, pBuffer, len);
6026 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer);
6027 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6030 free(pBuffer);
6031 return ERROR_SUCCESS;
6034 /******************************************************************************
6035 * AbortPrinter (WINSPOOL.@)
6037 BOOL WINAPI AbortPrinter(HANDLE printer)
6039 HANDLE handle = get_backend_handle(printer);
6041 TRACE("(%p)\n", printer);
6043 return backend->fpAbortPrinter(handle);
6046 /******************************************************************************
6047 * AddPortA (WINSPOOL.@)
6049 * See AddPortW.
6052 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6054 LPWSTR nameW = NULL;
6055 LPWSTR monitorW = NULL;
6056 DWORD len;
6057 BOOL res;
6059 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6061 if (pName) {
6062 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6063 nameW = malloc(len * sizeof(WCHAR));
6064 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6067 if (pMonitorName) {
6068 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6069 monitorW = malloc(len * sizeof(WCHAR));
6070 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6072 res = AddPortW(nameW, hWnd, monitorW);
6073 free(nameW);
6074 free(monitorW);
6075 return res;
6078 /******************************************************************************
6079 * AddPortW (WINSPOOL.@)
6081 * Add a Port for a specific Monitor
6083 * PARAMS
6084 * pName [I] Servername or NULL (local Computer)
6085 * hWnd [I] Handle to parent Window for the Dialog-Box
6086 * pMonitorName [I] Name of the Monitor that manage the Port
6088 * RETURNS
6089 * Success: TRUE
6090 * Failure: FALSE
6093 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6095 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6097 if ((backend == NULL) && !load_backend()) return FALSE;
6099 if (!pMonitorName) {
6100 SetLastError(RPC_X_NULL_REF_POINTER);
6101 return FALSE;
6104 return backend->fpAddPort(pName, hWnd, pMonitorName);
6107 /******************************************************************************
6108 * AddPortExA (WINSPOOL.@)
6110 * See AddPortExW.
6113 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6115 PORT_INFO_2W pi2W;
6116 PORT_INFO_2A * pi2A;
6117 LPWSTR nameW = NULL;
6118 LPWSTR monitorW = NULL;
6119 DWORD len;
6120 BOOL res;
6122 pi2A = (PORT_INFO_2A *) pBuffer;
6124 TRACE("(%s, %ld, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6125 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6127 if ((level < 1) || (level > 2)) {
6128 SetLastError(ERROR_INVALID_LEVEL);
6129 return FALSE;
6132 if (!pi2A) {
6133 SetLastError(ERROR_INVALID_PARAMETER);
6134 return FALSE;
6137 if (pName) {
6138 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6139 nameW = malloc(len * sizeof(WCHAR));
6140 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6143 if (pMonitorName) {
6144 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6145 monitorW = malloc(len * sizeof(WCHAR));
6146 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6149 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6151 if (pi2A->pPortName) {
6152 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6153 pi2W.pPortName = malloc(len * sizeof(WCHAR));
6154 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6157 if (level > 1) {
6158 if (pi2A->pMonitorName) {
6159 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6160 pi2W.pMonitorName = malloc(len * sizeof(WCHAR));
6161 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6164 if (pi2A->pDescription) {
6165 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6166 pi2W.pDescription = malloc(len * sizeof(WCHAR));
6167 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6169 pi2W.fPortType = pi2A->fPortType;
6170 pi2W.Reserved = pi2A->Reserved;
6173 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6175 free(nameW);
6176 free(monitorW);
6177 free(pi2W.pPortName);
6178 free(pi2W.pMonitorName);
6179 free(pi2W.pDescription);
6180 return res;
6184 /******************************************************************************
6185 * AddPortExW (WINSPOOL.@)
6187 * Add a Port for a specific Monitor, without presenting a user interface
6189 * PARAMS
6190 * pName [I] Servername or NULL (local Computer)
6191 * level [I] Structure-Level (1 or 2) for pBuffer
6192 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6193 * pMonitorName [I] Name of the Monitor that manage the Port
6195 * RETURNS
6196 * Success: TRUE
6197 * Failure: FALSE
6200 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6202 PORT_INFO_2W * pi2;
6204 pi2 = (PORT_INFO_2W *) pBuffer;
6206 TRACE("(%s, %ld, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6207 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6208 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6209 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6211 if ((backend == NULL) && !load_backend()) return FALSE;
6213 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6214 SetLastError(ERROR_INVALID_PARAMETER);
6215 return FALSE;
6218 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6221 /******************************************************************************
6222 * AddPrinterConnectionA (WINSPOOL.@)
6224 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6226 FIXME("%s\n", debugstr_a(pName));
6227 return FALSE;
6230 /******************************************************************************
6231 * AddPrinterConnectionW (WINSPOOL.@)
6233 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6235 FIXME("%s\n", debugstr_w(pName));
6236 return FALSE;
6239 /******************************************************************************
6240 * AddPrinterDriverExW (WINSPOOL.@)
6242 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6244 * PARAMS
6245 * pName [I] Servername or NULL (local Computer)
6246 * level [I] Level for the supplied DRIVER_INFO_*W struct
6247 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6248 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6250 * RESULTS
6251 * Success: TRUE
6252 * Failure: FALSE
6255 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6257 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6259 if ((backend == NULL) && !load_backend()) return FALSE;
6261 if (level < 2 || level == 5 || level == 7 || level > 8) {
6262 SetLastError(ERROR_INVALID_LEVEL);
6263 return FALSE;
6266 if (!pDriverInfo) {
6267 SetLastError(ERROR_INVALID_PARAMETER);
6268 return FALSE;
6271 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6274 /******************************************************************************
6275 * AddPrinterDriverExA (WINSPOOL.@)
6277 * See AddPrinterDriverExW.
6280 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6282 DRIVER_INFO_8A *diA;
6283 DRIVER_INFO_8W diW;
6284 LPWSTR nameW = NULL;
6285 DWORD lenA;
6286 DWORD len;
6287 BOOL res = FALSE;
6289 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6291 diA = (DRIVER_INFO_8A *) pDriverInfo;
6292 ZeroMemory(&diW, sizeof(diW));
6294 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6295 SetLastError(ERROR_INVALID_LEVEL);
6296 return FALSE;
6299 if (diA == NULL) {
6300 SetLastError(ERROR_INVALID_PARAMETER);
6301 return FALSE;
6304 /* convert servername to unicode */
6305 if (pName) {
6306 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6307 nameW = malloc(len * sizeof(WCHAR));
6308 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6311 /* common fields */
6312 diW.cVersion = diA->cVersion;
6314 if (diA->pName) {
6315 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6316 diW.pName = malloc(len * sizeof(WCHAR));
6317 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6320 if (diA->pEnvironment) {
6321 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6322 diW.pEnvironment = malloc(len * sizeof(WCHAR));
6323 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6326 if (diA->pDriverPath) {
6327 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6328 diW.pDriverPath = malloc(len * sizeof(WCHAR));
6329 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6332 if (diA->pDataFile) {
6333 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6334 diW.pDataFile = malloc(len * sizeof(WCHAR));
6335 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6338 if (diA->pConfigFile) {
6339 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6340 diW.pConfigFile = malloc(len * sizeof(WCHAR));
6341 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6344 if ((Level > 2) && diA->pHelpFile) {
6345 len = MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, NULL, 0);
6346 diW.pHelpFile = malloc(len * sizeof(WCHAR));
6347 MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, diW.pHelpFile, len);
6350 if ((Level > 2) && diA->pDependentFiles) {
6351 lenA = multi_sz_lenA(diA->pDependentFiles);
6352 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6353 diW.pDependentFiles = malloc(len * sizeof(WCHAR));
6354 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6357 if ((Level > 2) && diA->pMonitorName) {
6358 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6359 diW.pMonitorName = malloc(len * sizeof(WCHAR));
6360 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6363 if ((Level > 2) && diA->pDefaultDataType) {
6364 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6365 diW.pDefaultDataType = malloc(len * sizeof(WCHAR));
6366 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6369 if ((Level > 3) && diA->pszzPreviousNames) {
6370 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6371 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6372 diW.pszzPreviousNames = malloc(len * sizeof(WCHAR));
6373 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6376 if (Level > 5) {
6377 diW.ftDriverDate = diA->ftDriverDate;
6378 diW.dwlDriverVersion = diA->dwlDriverVersion;
6381 if ((Level > 5) && diA->pszMfgName) {
6382 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6383 diW.pszMfgName = malloc(len * sizeof(WCHAR));
6384 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6387 if ((Level > 5) && diA->pszOEMUrl) {
6388 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6389 diW.pszOEMUrl = malloc(len * sizeof(WCHAR));
6390 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6393 if ((Level > 5) && diA->pszHardwareID) {
6394 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6395 diW.pszHardwareID = malloc(len * sizeof(WCHAR));
6396 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6399 if ((Level > 5) && diA->pszProvider) {
6400 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6401 diW.pszProvider = malloc(len * sizeof(WCHAR));
6402 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6405 if ((Level > 7) && diA->pszPrintProcessor) {
6406 len = MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, NULL, 0);
6407 diW.pszPrintProcessor = malloc(len * sizeof(WCHAR));
6408 MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, diW.pszPrintProcessor, len);
6411 if ((Level > 7) && diA->pszVendorSetup) {
6412 len = MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, NULL, 0);
6413 diW.pszVendorSetup = malloc(len * sizeof(WCHAR));
6414 MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, diW.pszVendorSetup, len);
6417 if ((Level > 7) && diA->pszzColorProfiles) {
6418 lenA = multi_sz_lenA(diA->pszzColorProfiles);
6419 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, NULL, 0);
6420 diW.pszzColorProfiles = malloc(len * sizeof(WCHAR));
6421 MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, diW.pszzColorProfiles, len);
6424 if ((Level > 7) && diA->pszInfPath) {
6425 len = MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, NULL, 0);
6426 diW.pszInfPath = malloc(len * sizeof(WCHAR));
6427 MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, diW.pszInfPath, len);
6430 if ((Level > 7) && diA->pszzCoreDriverDependencies) {
6431 lenA = multi_sz_lenA(diA->pszzCoreDriverDependencies);
6432 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, NULL, 0);
6433 diW.pszzCoreDriverDependencies = malloc(len * sizeof(WCHAR));
6434 MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, diW.pszzCoreDriverDependencies, len);
6437 if (Level > 7) {
6438 diW.dwPrinterDriverAttributes = diA->dwPrinterDriverAttributes;
6439 diW.ftMinInboxDriverVerDate = diA->ftMinInboxDriverVerDate;
6440 diW.dwlMinInboxDriverVerVersion = diA->dwlMinInboxDriverVerVersion;
6443 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6444 TRACE("got %u with %lu\n", res, GetLastError());
6445 free(nameW);
6446 free(diW.pName);
6447 free(diW.pEnvironment);
6448 free(diW.pDriverPath);
6449 free(diW.pDataFile);
6450 free(diW.pConfigFile);
6451 free(diW.pHelpFile);
6452 free(diW.pDependentFiles);
6453 free(diW.pMonitorName);
6454 free(diW.pDefaultDataType);
6455 free(diW.pszzPreviousNames);
6456 free(diW.pszMfgName);
6457 free(diW.pszOEMUrl);
6458 free(diW.pszHardwareID);
6459 free(diW.pszProvider);
6460 free(diW.pszPrintProcessor);
6461 free(diW.pszVendorSetup);
6462 free(diW.pszzColorProfiles);
6463 free(diW.pszInfPath);
6464 free(diW.pszzCoreDriverDependencies);
6466 TRACE("=> %u with %lu\n", res, GetLastError());
6467 return res;
6470 /******************************************************************************
6471 * ConfigurePortA (WINSPOOL.@)
6473 * See ConfigurePortW.
6476 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6478 LPWSTR nameW = NULL;
6479 LPWSTR portW = NULL;
6480 INT len;
6481 DWORD res;
6483 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6485 /* convert servername to unicode */
6486 if (pName) {
6487 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6488 nameW = malloc(len * sizeof(WCHAR));
6489 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6492 /* convert portname to unicode */
6493 if (pPortName) {
6494 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6495 portW = malloc(len * sizeof(WCHAR));
6496 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6499 res = ConfigurePortW(nameW, hWnd, portW);
6500 free(nameW);
6501 free(portW);
6502 return res;
6505 /******************************************************************************
6506 * ConfigurePortW (WINSPOOL.@)
6508 * Display the Configuration-Dialog for a specific Port
6510 * PARAMS
6511 * pName [I] Servername or NULL (local Computer)
6512 * hWnd [I] Handle to parent Window for the Dialog-Box
6513 * pPortName [I] Name of the Port, that should be configured
6515 * RETURNS
6516 * Success: TRUE
6517 * Failure: FALSE
6520 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6523 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6525 if ((backend == NULL) && !load_backend()) return FALSE;
6527 if (!pPortName) {
6528 SetLastError(RPC_X_NULL_REF_POINTER);
6529 return FALSE;
6532 return backend->fpConfigurePort(pName, hWnd, pPortName);
6535 /******************************************************************************
6536 * ConnectToPrinterDlg (WINSPOOL.@)
6538 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6540 FIXME("%p %lx\n", hWnd, Flags);
6541 return NULL;
6544 /******************************************************************************
6545 * DeletePrinterConnectionA (WINSPOOL.@)
6547 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6549 FIXME("%s\n", debugstr_a(pName));
6550 return TRUE;
6553 /******************************************************************************
6554 * DeletePrinterConnectionW (WINSPOOL.@)
6556 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6558 FIXME("%s\n", debugstr_w(pName));
6559 return TRUE;
6562 /******************************************************************************
6563 * DeletePrinterDriverExW (WINSPOOL.@)
6565 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6566 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6568 HKEY hkey_drivers;
6569 BOOL ret = FALSE;
6571 TRACE("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
6572 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6574 if(pName && pName[0])
6576 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6577 SetLastError(ERROR_INVALID_PARAMETER);
6578 return FALSE;
6581 if(dwDeleteFlag)
6583 FIXME("dwDeleteFlag = %lx - unsupported\n", dwDeleteFlag);
6584 SetLastError(ERROR_INVALID_PARAMETER);
6585 return FALSE;
6588 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6590 if(!hkey_drivers)
6592 ERR("Can't open drivers key\n");
6593 return FALSE;
6596 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6597 ret = TRUE;
6599 RegCloseKey(hkey_drivers);
6601 return ret;
6604 /******************************************************************************
6605 * DeletePrinterDriverExA (WINSPOOL.@)
6607 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6608 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6610 UNICODE_STRING NameW, EnvW, DriverW;
6611 BOOL ret;
6613 asciitounicode(&NameW, pName);
6614 asciitounicode(&EnvW, pEnvironment);
6615 asciitounicode(&DriverW, pDriverName);
6617 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6619 RtlFreeUnicodeString(&DriverW);
6620 RtlFreeUnicodeString(&EnvW);
6621 RtlFreeUnicodeString(&NameW);
6623 return ret;
6626 /******************************************************************************
6627 * DeletePrinterDataExW (WINSPOOL.@)
6629 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6630 LPCWSTR pValueName)
6632 FIXME("%p %s %s\n", hPrinter,
6633 debugstr_w(pKeyName), debugstr_w(pValueName));
6634 return ERROR_INVALID_PARAMETER;
6637 /******************************************************************************
6638 * DeletePrinterDataExA (WINSPOOL.@)
6640 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6641 LPCSTR pValueName)
6643 FIXME("%p %s %s\n", hPrinter,
6644 debugstr_a(pKeyName), debugstr_a(pValueName));
6645 return ERROR_INVALID_PARAMETER;
6648 /******************************************************************************
6649 * DeletePrintProcessorA (WINSPOOL.@)
6651 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6653 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6654 debugstr_a(pPrintProcessorName));
6655 return TRUE;
6658 /******************************************************************************
6659 * DeletePrintProcessorW (WINSPOOL.@)
6661 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6663 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6664 debugstr_w(pPrintProcessorName));
6665 return TRUE;
6668 /******************************************************************************
6669 * DeletePrintProvidorA (WINSPOOL.@)
6671 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6673 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6674 debugstr_a(pPrintProviderName));
6675 return TRUE;
6678 /******************************************************************************
6679 * DeletePrintProvidorW (WINSPOOL.@)
6681 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6683 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6684 debugstr_w(pPrintProviderName));
6685 return TRUE;
6688 /******************************************************************************
6689 * EnumFormsA (WINSPOOL.@)
6691 BOOL WINAPI EnumFormsA( HANDLE printer, DWORD level, BYTE *form, DWORD size, DWORD *needed, DWORD *count )
6693 const DWORD *string_info = form_string_info( level );
6694 BOOL ret;
6695 DWORD i;
6697 if (!string_info) return FALSE;
6699 ret = EnumFormsW( printer, level, form, size, needed, count );
6700 if (ret)
6701 for (i = 0; i < *count; i++)
6702 packed_struct_WtoA( form + i * string_info[0], string_info );
6704 return ret;
6707 /******************************************************************************
6708 * EnumFormsW (WINSPOOL.@)
6710 BOOL WINAPI EnumFormsW( HANDLE printer, DWORD level, BYTE *form, DWORD size, DWORD *needed, DWORD *count )
6712 HANDLE handle = get_backend_handle( printer );
6714 TRACE( "(%p, %ld, %p, %ld, %p, %p)\n", printer, level, form, size, needed, count );
6716 if (!handle)
6718 SetLastError( ERROR_INVALID_HANDLE );
6719 return FALSE;
6722 if (!needed || !count)
6724 SetLastError( RPC_X_NULL_REF_POINTER );
6725 return FALSE;
6728 if (!form && size)
6730 SetLastError( ERROR_INVALID_USER_BUFFER );
6731 return FALSE;
6734 return backend->fpEnumForms( handle, level, form, size, needed, count );
6737 /*****************************************************************************
6738 * EnumMonitorsA [WINSPOOL.@]
6740 * See EnumMonitorsW.
6743 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6744 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6746 BOOL res;
6747 LPBYTE bufferW = NULL;
6748 LPWSTR nameW = NULL;
6749 DWORD needed = 0;
6750 DWORD numentries = 0;
6751 INT len;
6753 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6754 cbBuf, pcbNeeded, pcReturned);
6756 /* convert servername to unicode */
6757 if (pName) {
6758 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6759 nameW = malloc(len * sizeof(WCHAR));
6760 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6762 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6763 needed = cbBuf * sizeof(WCHAR);
6764 if (needed) bufferW = malloc(needed);
6765 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6767 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6768 if (pcbNeeded) needed = *pcbNeeded;
6769 /* HeapReAlloc return NULL, when bufferW was NULL */
6770 bufferW = (bufferW) ? realloc(bufferW, needed) : malloc(needed);
6772 /* Try again with the large Buffer */
6773 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6775 numentries = pcReturned ? *pcReturned : 0;
6776 needed = 0;
6778 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6779 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6781 if (res) {
6782 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6783 DWORD entrysize = 0;
6784 DWORD index;
6785 LPSTR ptr;
6786 LPMONITOR_INFO_2W mi2w;
6787 LPMONITOR_INFO_2A mi2a;
6789 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6790 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6792 /* First pass: calculate the size for all Entries */
6793 mi2w = (LPMONITOR_INFO_2W) bufferW;
6794 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6795 index = 0;
6796 while (index < numentries) {
6797 index++;
6798 needed += entrysize; /* MONITOR_INFO_?A */
6799 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6801 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6802 NULL, 0, NULL, NULL);
6803 if (Level > 1) {
6804 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6805 NULL, 0, NULL, NULL);
6806 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6807 NULL, 0, NULL, NULL);
6809 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6810 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6811 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6814 /* check for errors and quit on failure */
6815 if (cbBuf < needed) {
6816 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6817 res = FALSE;
6818 goto emA_cleanup;
6820 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6821 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6822 cbBuf -= len ; /* free Bytes in the user-Buffer */
6823 mi2w = (LPMONITOR_INFO_2W) bufferW;
6824 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6825 index = 0;
6826 /* Second Pass: Fill the User Buffer (if we have one) */
6827 while ((index < numentries) && pMonitors) {
6828 index++;
6829 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
6830 mi2a->pName = ptr;
6831 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6832 ptr, cbBuf , NULL, NULL);
6833 ptr += len;
6834 cbBuf -= len;
6835 if (Level > 1) {
6836 mi2a->pEnvironment = ptr;
6837 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6838 ptr, cbBuf, NULL, NULL);
6839 ptr += len;
6840 cbBuf -= len;
6842 mi2a->pDLLName = ptr;
6843 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6844 ptr, cbBuf, NULL, NULL);
6845 ptr += len;
6846 cbBuf -= len;
6848 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6849 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6850 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6853 emA_cleanup:
6854 if (pcbNeeded) *pcbNeeded = needed;
6855 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6857 free(nameW);
6858 free(bufferW);
6860 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
6861 (res), GetLastError(), needed, numentries);
6863 return (res);
6867 /*****************************************************************************
6868 * EnumMonitorsW [WINSPOOL.@]
6870 * Enumerate available Port-Monitors
6872 * PARAMS
6873 * pName [I] Servername or NULL (local Computer)
6874 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6875 * pMonitors [O] PTR to Buffer that receives the Result
6876 * cbBuf [I] Size of Buffer at pMonitors
6877 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6878 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6880 * RETURNS
6881 * Success: TRUE
6882 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6885 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6886 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6889 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6890 cbBuf, pcbNeeded, pcReturned);
6892 if ((backend == NULL) && !load_backend()) return FALSE;
6894 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6895 SetLastError(RPC_X_NULL_REF_POINTER);
6896 return FALSE;
6899 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6902 /******************************************************************************
6903 * SpoolerInit (WINSPOOL.@)
6905 * Initialize the Spooler
6907 * RETURNS
6908 * Success: TRUE
6909 * Failure: FALSE
6911 * NOTES
6912 * The function fails on windows, when the spooler service is not running
6915 BOOL WINAPI SpoolerInit(void)
6918 if ((backend == NULL) && !load_backend()) return FALSE;
6919 return TRUE;
6922 /******************************************************************************
6923 * XcvDataW (WINSPOOL.@)
6925 * Execute commands in the Printmonitor DLL
6927 * PARAMS
6928 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6929 * pszDataName [i] Name of the command to execute
6930 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6931 * cbInputData [i] Size in Bytes of Buffer at pInputData
6932 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6933 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6934 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6935 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6937 * RETURNS
6938 * Success: TRUE
6939 * Failure: FALSE
6941 * NOTES
6942 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6943 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6945 * Minimal List of commands, that a Printmonitor DLL should support:
6947 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6948 *| "AddPort" : Add a Port
6949 *| "DeletePort": Delete a Port
6951 * Many Printmonitors support additional commands. Examples for localspl.dll:
6952 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6953 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6956 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6957 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6958 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6960 opened_printer_t *printer;
6962 TRACE("(%p, %s, %p, %ld, %p, %ld, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6963 pInputData, cbInputData, pOutputData,
6964 cbOutputData, pcbOutputNeeded, pdwStatus);
6966 if ((backend == NULL) && !load_backend()) return FALSE;
6968 printer = get_opened_printer(hXcv);
6969 if (!printer || (!printer->backend_printer)) {
6970 SetLastError(ERROR_INVALID_HANDLE);
6971 return FALSE;
6974 if (!pcbOutputNeeded) {
6975 SetLastError(ERROR_INVALID_PARAMETER);
6976 return FALSE;
6979 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6980 SetLastError(RPC_X_NULL_REF_POINTER);
6981 return FALSE;
6984 *pcbOutputNeeded = 0;
6986 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6987 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6991 /*****************************************************************************
6992 * EnumPrinterDataA [WINSPOOL.@]
6995 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR 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 * EnumPrinterDataW [WINSPOOL.@]
7008 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7009 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7010 DWORD cbData, LPDWORD pcbData )
7012 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
7013 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7014 return ERROR_NO_MORE_ITEMS;
7017 /*****************************************************************************
7018 * EnumPrinterKeyA [WINSPOOL.@]
7021 DWORD WINAPI EnumPrinterKeyA(HANDLE printer, const CHAR *key, CHAR *subkey, DWORD size, DWORD *needed)
7023 FIXME("%p %s %p %lx %p\n", printer, debugstr_a(key), subkey, size, needed);
7024 return ERROR_CALL_NOT_IMPLEMENTED;
7027 /*****************************************************************************
7028 * EnumPrinterKeyW [WINSPOOL.@]
7031 DWORD WINAPI EnumPrinterKeyW(HANDLE printer, const WCHAR *key, WCHAR *subkey, DWORD size, DWORD *needed)
7033 FIXME("%p %s %p %lx %p\n", printer, debugstr_w(key), subkey, size, needed);
7034 return ERROR_CALL_NOT_IMPLEMENTED;
7037 /*****************************************************************************
7038 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7041 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7042 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7043 LPDWORD pcbNeeded, LPDWORD pcReturned)
7045 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
7046 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7047 pcbNeeded, pcReturned);
7048 return FALSE;
7051 /*****************************************************************************
7052 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7055 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7056 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7057 LPDWORD pcbNeeded, LPDWORD pcReturned)
7059 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
7060 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7061 pcbNeeded, pcReturned);
7062 return FALSE;
7065 /*****************************************************************************
7066 * EnumPrintProcessorsA [WINSPOOL.@]
7068 * See EnumPrintProcessorsW.
7071 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7072 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7074 BOOL res;
7075 LPBYTE bufferW = NULL;
7076 LPWSTR nameW = NULL;
7077 LPWSTR envW = NULL;
7078 DWORD needed = 0;
7079 DWORD numentries = 0;
7080 INT len;
7082 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7083 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7085 /* convert names to unicode */
7086 if (pName) {
7087 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7088 nameW = malloc(len * sizeof(WCHAR));
7089 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7091 if (pEnvironment) {
7092 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7093 envW = malloc(len * sizeof(WCHAR));
7094 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7097 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7098 needed = cbBuf * sizeof(WCHAR);
7099 if (needed) bufferW = malloc(needed);
7100 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7102 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7103 if (pcbNeeded) needed = *pcbNeeded;
7104 /* HeapReAlloc return NULL, when bufferW was NULL */
7105 bufferW = (bufferW) ? realloc(bufferW, needed) : malloc(needed);
7107 /* Try again with the large Buffer */
7108 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7110 numentries = pcReturned ? *pcReturned : 0;
7111 needed = 0;
7113 if (res) {
7114 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7115 DWORD index;
7116 LPSTR ptr;
7117 PPRINTPROCESSOR_INFO_1W ppiw;
7118 PPRINTPROCESSOR_INFO_1A ppia;
7120 /* First pass: calculate the size for all Entries */
7121 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7122 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7123 index = 0;
7124 while (index < numentries) {
7125 index++;
7126 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7127 TRACE("%p: parsing #%ld (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7129 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7130 NULL, 0, NULL, NULL);
7132 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7133 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7136 /* check for errors and quit on failure */
7137 if (cbBuf < needed) {
7138 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7139 res = FALSE;
7140 goto epp_cleanup;
7143 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7144 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7145 cbBuf -= len ; /* free Bytes in the user-Buffer */
7146 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7147 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7148 index = 0;
7149 /* Second Pass: Fill the User Buffer (if we have one) */
7150 while ((index < numentries) && pPPInfo) {
7151 index++;
7152 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%ld\n", ppia, index);
7153 ppia->pName = ptr;
7154 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7155 ptr, cbBuf , NULL, NULL);
7156 ptr += len;
7157 cbBuf -= len;
7159 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7160 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7164 epp_cleanup:
7165 if (pcbNeeded) *pcbNeeded = needed;
7166 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7168 free(nameW);
7169 free(envW);
7170 free(bufferW);
7172 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
7173 (res), GetLastError(), needed, numentries);
7175 return (res);
7178 /*****************************************************************************
7179 * EnumPrintProcessorsW [WINSPOOL.@]
7181 * Enumerate available Print Processors
7183 * PARAMS
7184 * pName [I] Servername or NULL (local Computer)
7185 * pEnvironment [I] Printing-Environment or NULL (Default)
7186 * Level [I] Structure-Level (Only 1 is allowed)
7187 * pPPInfo [O] PTR to Buffer that receives the Result
7188 * cbBuf [I] Size of Buffer at pPPInfo
7189 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7190 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7192 * RETURNS
7193 * Success: TRUE
7194 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7197 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7198 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7201 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7202 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7204 if ((backend == NULL) && !load_backend()) return FALSE;
7206 if (!pcbNeeded || !pcReturned) {
7207 SetLastError(RPC_X_NULL_REF_POINTER);
7208 return FALSE;
7211 if (!pPPInfo && (cbBuf > 0)) {
7212 SetLastError(ERROR_INVALID_USER_BUFFER);
7213 return FALSE;
7216 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7217 cbBuf, pcbNeeded, pcReturned);
7220 /*****************************************************************************
7221 * ExtDeviceMode [WINSPOOL.@]
7224 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7225 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7226 DWORD fMode)
7228 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
7229 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7230 debugstr_a(pProfile), fMode);
7231 return -1;
7234 /*****************************************************************************
7235 * FindClosePrinterChangeNotification [WINSPOOL.@]
7238 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7240 FIXME("Stub: %p\n", hChange);
7241 return TRUE;
7244 /*****************************************************************************
7245 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7248 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7249 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7251 FIXME("Stub: %p %lx %lx %p\n",
7252 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7253 return INVALID_HANDLE_VALUE;
7256 /*****************************************************************************
7257 * FindNextPrinterChangeNotification [WINSPOOL.@]
7260 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7261 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7263 FIXME("Stub: %p %p %p %p\n",
7264 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7265 return FALSE;
7268 /*****************************************************************************
7269 * FreePrinterNotifyInfo [WINSPOOL.@]
7272 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7274 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7275 return TRUE;
7278 static inline const DWORD *job_string_info(DWORD level)
7280 static const DWORD info_1[] =
7282 sizeof(JOB_INFO_1W),
7283 FIELD_OFFSET(JOB_INFO_1W, pPrinterName),
7284 FIELD_OFFSET(JOB_INFO_1W, pMachineName),
7285 FIELD_OFFSET(JOB_INFO_1W, pUserName),
7286 FIELD_OFFSET(JOB_INFO_1W, pDocument),
7287 FIELD_OFFSET(JOB_INFO_1W, pDatatype),
7288 FIELD_OFFSET(JOB_INFO_1W, pStatus),
7291 static const DWORD info_2[] =
7293 sizeof(JOB_INFO_2W),
7294 FIELD_OFFSET(JOB_INFO_2W, pPrinterName),
7295 FIELD_OFFSET(JOB_INFO_2W, pMachineName),
7296 FIELD_OFFSET(JOB_INFO_2W, pUserName),
7297 FIELD_OFFSET(JOB_INFO_2W, pDocument),
7298 FIELD_OFFSET(JOB_INFO_2W, pNotifyName),
7299 FIELD_OFFSET(JOB_INFO_2W, pDatatype),
7300 FIELD_OFFSET(JOB_INFO_2W, pPrintProcessor),
7301 FIELD_OFFSET(JOB_INFO_2W, pParameters),
7302 FIELD_OFFSET(JOB_INFO_2W, pDriverName),
7303 FIELD_OFFSET(JOB_INFO_2W, pStatus),
7306 static const DWORD info_3[] =
7308 sizeof(JOB_INFO_3),
7312 switch (level)
7314 case 1: return info_1;
7315 case 2: return info_2;
7316 case 3: return info_3;
7319 SetLastError( ERROR_INVALID_LEVEL );
7320 return NULL;
7323 /*****************************************************************************
7324 * GetJobA [WINSPOOL.@]
7327 BOOL WINAPI GetJobA(HANDLE printer, DWORD job_id, DWORD level, BYTE *data,
7328 DWORD size, DWORD *needed)
7330 const DWORD *string_info = job_string_info(level);
7332 if (!string_info)
7333 return FALSE;
7335 if (!GetJobW(printer, job_id, level, data, size, needed))
7336 return FALSE;
7337 packed_struct_WtoA(data, string_info);
7338 if (level == 2)
7339 DEVMODEWtoA(((JOB_INFO_2W *)data)->pDevMode, ((JOB_INFO_2A *)data)->pDevMode);
7340 return TRUE;
7343 /*****************************************************************************
7344 * GetJobW [WINSPOOL.@]
7347 BOOL WINAPI GetJobW(HANDLE printer, DWORD job_id, DWORD level, BYTE *data,
7348 DWORD size, DWORD *needed)
7350 HANDLE handle = get_backend_handle(printer);
7352 TRACE("(%p, %ld, %ld, %p, %ld, %p)\n", printer, job_id, level, data, size, needed);
7354 if (!handle)
7356 SetLastError(ERROR_INVALID_HANDLE);
7357 return FALSE;
7360 return backend->fpGetJob(handle, job_id, level, data, size, needed);
7363 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7365 LPWSTR filename;
7367 switch(msg)
7369 case WM_INITDIALOG:
7370 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7371 return TRUE;
7373 case WM_COMMAND:
7374 if(HIWORD(wparam) == BN_CLICKED)
7376 if(LOWORD(wparam) == IDOK)
7378 HANDLE hf;
7379 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7380 LPWSTR *output;
7382 filename = malloc((len + 1) * sizeof(WCHAR));
7383 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7385 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7387 WCHAR caption[200], message[200];
7388 int mb_ret;
7390 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
7391 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, ARRAY_SIZE(message));
7392 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7393 if(mb_ret == IDCANCEL)
7395 free(filename);
7396 return TRUE;
7399 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7400 if(hf == INVALID_HANDLE_VALUE)
7402 WCHAR caption[200], message[200];
7404 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
7405 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, ARRAY_SIZE(message));
7406 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7407 free(filename);
7408 return TRUE;
7410 CloseHandle(hf);
7411 DeleteFileW(filename);
7412 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7413 *output = filename;
7414 EndDialog(hwnd, IDOK);
7415 return TRUE;
7417 if(LOWORD(wparam) == IDCANCEL)
7419 EndDialog(hwnd, IDCANCEL);
7420 return TRUE;
7423 return FALSE;
7425 return FALSE;
7428 /*****************************************************************************
7429 * get_filename
7431 static BOOL get_filename(LPWSTR *filename)
7433 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7434 file_dlg_proc, (LPARAM)filename) == IDOK;
7437 /*****************************************************************************
7438 * ScheduleJob [WINSPOOL.@]
7441 BOOL WINAPI ScheduleJob(HANDLE printer, DWORD job_id)
7443 HANDLE handle = get_backend_handle(printer);
7445 TRACE("(%p, %lx)\n", printer, job_id);
7447 if (!handle)
7449 SetLastError(ERROR_INVALID_HANDLE);
7450 return FALSE;
7453 return backend->fpScheduleJob(handle, job_id);
7456 /*****************************************************************************
7457 * StartDocDlgA [WINSPOOL.@]
7459 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7461 UNICODE_STRING usBuffer;
7462 DOCINFOW docW = { 0 };
7463 LPWSTR retW;
7464 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7465 LPSTR ret = NULL;
7467 docW.cbSize = sizeof(docW);
7468 if (doc->lpszDocName)
7470 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7471 if (!(docW.lpszDocName = docnameW)) goto failed;
7473 if (doc->lpszOutput)
7475 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7476 if (!(docW.lpszOutput = outputW)) goto failed;
7478 if (doc->lpszDatatype)
7480 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7481 if (!(docW.lpszDatatype = datatypeW)) goto failed;
7483 docW.fwType = doc->fwType;
7485 retW = StartDocDlgW(hPrinter, &docW);
7487 if(retW)
7489 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7490 ret = heap_alloc(len);
7491 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7492 heap_free(retW);
7495 failed:
7496 free(datatypeW);
7497 free(outputW);
7498 free(docnameW);
7500 return ret;
7503 static BOOL is_port(const WCHAR *port_list, const WCHAR *output)
7505 size_t len;
7507 if (wcschr(output, ':'))
7508 return TRUE;
7510 len = wcslen(output);
7511 while (port_list && *port_list)
7513 if (!wcsncmp(output, port_list, len) && (!port_list[len] || port_list[len] == ','))
7514 return TRUE;
7516 port_list = wcschr(port_list, ',');
7517 if (port_list) port_list++;
7519 return FALSE;
7522 /*****************************************************************************
7523 * StartDocDlgW [WINSPOOL.@]
7525 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7526 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7527 * port is "FILE:". Also returns the full path if passed a relative path.
7529 * The caller should free the returned string from the process heap.
7531 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7533 PRINTER_INFO_5W *pi5;
7534 LPWSTR ret = NULL;
7535 DWORD len, attr;
7536 BOOL b;
7538 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7539 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7540 return NULL;
7541 pi5 = malloc(len);
7542 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7544 /* Check whether default port is FILE: */
7545 b = !doc->lpszOutput && (!pi5->pPortName || wcscmp( pi5->pPortName, L"FILE:" ));
7546 if (!b && doc->lpszOutput && wcscmp( doc->lpszOutput, L"FILE:" ))
7547 b = is_port(pi5->pPortName, doc->lpszOutput);
7548 free(pi5);
7549 if (b)
7550 return NULL;
7552 if(doc->lpszOutput == NULL || !wcscmp( doc->lpszOutput, L"FILE:" ))
7554 LPWSTR name;
7556 if (get_filename(&name))
7558 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7560 free(name);
7561 return NULL;
7563 ret = heap_alloc(len * sizeof(WCHAR));
7564 GetFullPathNameW(name, len, ret, NULL);
7565 free(name);
7567 return ret;
7570 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7571 return NULL;
7573 ret = heap_alloc(len * sizeof(WCHAR));
7574 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7576 attr = GetFileAttributesW(ret);
7577 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7579 heap_free(ret);
7580 ret = NULL;
7582 return ret;
7585 /*****************************************************************************
7586 * UploadPrinterDriverPackageA [WINSPOOL.@]
7588 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
7589 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
7591 FIXME("%s, %s, %s, %lx, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
7592 flags, hwnd, dst, dstlen);
7593 return E_NOTIMPL;
7596 /*****************************************************************************
7597 * UploadPrinterDriverPackageW [WINSPOOL.@]
7599 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
7600 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
7602 FIXME("%s, %s, %s, %lx, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
7603 flags, hwnd, dst, dstlen);
7604 return E_NOTIMPL;
7607 /*****************************************************************************
7608 * PerfOpen [WINSPOOL.@]
7610 DWORD WINAPI PerfOpen(LPWSTR context)
7612 FIXME("%s: stub\n", debugstr_w(context));
7613 return ERROR_SUCCESS;
7616 /*****************************************************************************
7617 * PerfClose [WINSPOOL.@]
7619 DWORD WINAPI PerfClose(void)
7621 FIXME("stub\n");
7622 return ERROR_SUCCESS;
7625 /*****************************************************************************
7626 * PerfCollect [WINSPOOL.@]
7628 DWORD WINAPI PerfCollect(LPWSTR query, LPVOID *data, LPDWORD size, LPDWORD obj_count)
7630 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query), data, size, obj_count);
7631 *size = 0;
7632 *obj_count = 0;
7633 return ERROR_SUCCESS;
7636 /*****************************************************************************
7637 * GetSpoolFileHandle [WINSPOOL.@]
7639 HANDLE WINAPI GetSpoolFileHandle( HANDLE printer )
7641 FIXME( "%p: stub\n", printer );
7642 return INVALID_HANDLE_VALUE;
7645 /*****************************************************************************
7646 * SeekPrinter [WINSPOOL.@]
7648 BOOL WINAPI SeekPrinter(HANDLE printer, LARGE_INTEGER distance,
7649 LARGE_INTEGER *pos, DWORD method, BOOL bwrite)
7651 HANDLE handle = get_backend_handle(printer);
7653 TRACE("(%p %I64d %p %lx %x)\n", printer, distance.QuadPart, pos, method, bwrite);
7655 if (!handle)
7657 SetLastError(ERROR_INVALID_HANDLE);
7658 return FALSE;
7660 return backend->fpSeekPrinter(handle, distance, pos, method, bwrite);