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
33 #define NONAMELESSSTRUCT
34 #define NONAMELESSUNION
37 #define WIN32_NO_STATUS
47 #include "wine/windef16.h"
48 #include "wine/debug.h"
49 #include "wine/list.h"
50 #include "wine/rbtree.h"
51 #include "wine/heap.h"
52 #include <wine/unixlib.h>
54 #include "ddk/compstui.h"
55 #include "ddk/winsplp.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
60 /* ############################### */
62 static CRITICAL_SECTION printer_handles_cs
;
63 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
65 0, 0, &printer_handles_cs
,
66 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
67 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
69 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
71 /* ############################### */
75 HANDLE backend_printer
;
82 LPCWSTR versionregpath
;
83 LPCWSTR versionsubdir
;
88 struct wine_rb_entry entry
;
93 DWORD (WINAPI
*pDrvDeviceCapabilities
)(HANDLE
, const WCHAR
*, WORD
, void *, const DEVMODEW
*);
94 LONG (WINAPI
*pDrvDocumentPropertySheets
)(PROPSHEETUI_INFO
*, LPARAM
);
103 LPCWSTR pszPrinterName
;
108 } DOCUMENTPROPERTYHEADERW
;
111 DOCUMENTPROPERTYHEADERW dph
;
112 config_module_t
*config
;
113 } document_property_t
;
115 /* ############################### */
117 static opened_printer_t
**printer_handles
;
118 static UINT nb_printer_handles
;
120 static const WCHAR
* const May_Delete_Value
= L
"WineMayDeleteMe";
122 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
123 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
124 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
125 0, sizeof(DRIVER_INFO_8W
)};
128 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
129 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
130 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
131 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
132 sizeof(PRINTER_INFO_9W
)};
134 static const printenv_t env_x64
= { L
"Windows x64", L
"x64", 3, L
"\\Version-3", L
"\\3" };
135 static const printenv_t env_x86
= { L
"Windows NT x86", L
"w32x86", 3, L
"\\Version-3", L
"\\3" };
136 static const printenv_t env_arm
= { L
"Windows ARM", L
"arm", 3, L
"\\Version-3", L
"\\3" };
137 static const printenv_t env_arm64
= { L
"Windows ARM64", L
"arm64", 3, L
"\\Version-3", L
"\\3" };
138 static const printenv_t env_win40
= { L
"Windows 4.0", L
"win40", 0, L
"\\Version-0", L
"\\0" };
140 static const printenv_t
* const all_printenv
[] = { &env_x86
, &env_x64
, &env_arm
, &env_arm64
, &env_win40
};
143 #define env_arch env_x86
144 #elif defined __x86_64__
145 #define env_arch env_x64
146 #elif defined __arm__
147 #define env_arch env_arm
148 #elif defined __aarch64__
149 #define env_arch env_arm64
151 #error not defined for this cpu
154 /******************************************************************
155 * validate the user-supplied printing-environment [internal]
158 * env [I] PTR to Environment-String or NULL
162 * Success: PTR to printenv_t
165 * An empty string is handled the same way as NULL.
166 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
170 static const printenv_t
* validate_envW(LPCWSTR env
)
172 const printenv_t
*result
= NULL
;
175 TRACE("testing %s\n", debugstr_w(env
));
178 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
180 if (!wcsicmp( env
, all_printenv
[i
]->envname
))
182 result
= all_printenv
[i
];
187 if (result
== NULL
) {
188 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
189 SetLastError(ERROR_INVALID_ENVIRONMENT
);
191 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
195 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_arch
;
197 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
203 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
204 if passed a NULL string. This returns NULLs to the result.
206 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
210 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
211 return usBufferPtr
->Buffer
;
213 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
218 * Converts Unicode string to Ansi (possibly in place).
220 static void stringWtoA( const WCHAR
*strW
, char *strA
, size_t size
)
225 str
= (char *)strW
== strA
? malloc( size
) : strA
;
226 ret
= WideCharToMultiByte( CP_ACP
, 0, strW
, -1, str
, size
, NULL
, NULL
);
229 memcpy( strA
, str
, ret
);
232 memset( strA
+ ret
, 0, size
- ret
);
235 /***********************************************************
237 * Converts DEVMODEW to DEVMODEA (possibly in place).
238 * Allocates DEVMODEA if needed.
240 static DEVMODEA
*DEVMODEWtoA( const DEVMODEW
*dmW
, DEVMODEA
*dmA
)
244 if (!dmW
) return NULL
;
246 size
= sizeW
- CCHDEVICENAME
-
247 ((sizeW
> FIELD_OFFSET( DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
250 dmA
= calloc( 1, size
+ dmW
->dmDriverExtra
);
251 if (!dmA
) return NULL
;
253 stringWtoA( dmW
->dmDeviceName
, (char *)dmA
->dmDeviceName
, CCHDEVICENAME
);
255 if (FIELD_OFFSET( DEVMODEW
, dmFormName
) >= sizeW
)
257 memmove( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
258 sizeW
- FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
262 memmove( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
263 FIELD_OFFSET( DEVMODEW
, dmFormName
) - FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
264 stringWtoA( dmW
->dmFormName
, (char *)dmA
->dmFormName
, CCHFORMNAME
);
265 memmove( &dmA
->dmLogPixels
, &dmW
->dmLogPixels
, sizeW
- FIELD_OFFSET( DEVMODEW
, dmLogPixels
) );
269 memmove( (char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ sizeW
, dmW
->dmDriverExtra
);
273 /*********************************************************************
276 * Convert a packed struct from W to A overwriting the unicode strings
277 * with their ansi equivalents.
279 static void packed_struct_WtoA( BYTE
*data
, const DWORD
*string_info
)
283 string_info
++; /* sizeof */
284 while (*string_info
!= ~0u)
286 strW
= *(WCHAR
**)(data
+ *string_info
);
287 if (strW
) stringWtoA( strW
, (char *)strW
, (wcslen(strW
) + 1) * sizeof(WCHAR
) );
292 static inline const DWORD
*form_string_info( DWORD level
)
294 static const DWORD info_1
[] =
296 sizeof( FORM_INFO_1W
),
297 FIELD_OFFSET( FORM_INFO_1W
, pName
),
300 static const DWORD info_2
[] =
302 sizeof( FORM_INFO_2W
),
303 FIELD_OFFSET( FORM_INFO_2W
, pName
),
304 FIELD_OFFSET( FORM_INFO_2W
, pMuiDll
),
305 FIELD_OFFSET( FORM_INFO_2W
, pDisplayName
),
309 if (level
== 1) return info_1
;
310 if (level
== 2) return info_2
;
312 SetLastError( ERROR_INVALID_LEVEL
);
316 /*****************************************************************************
317 * WINSPOOL_OpenDriverReg [internal]
319 * opens the registry for the printer drivers depending on the given input
320 * variable pEnvironment
323 * the opened hkey on success
326 static HKEY
WINSPOOL_OpenDriverReg(const void *pEnvironment
)
330 const printenv_t
*env
;
332 static const WCHAR driver_fmt
[] = L
"System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers%s";
334 TRACE("(%s)\n", debugstr_w(pEnvironment
));
336 env
= validate_envW(pEnvironment
);
337 if (!env
) return NULL
;
339 len
= ARRAY_SIZE( driver_fmt
) + wcslen( env
->envname
) + wcslen( env
->versionregpath
);
340 buffer
= malloc( len
* sizeof(WCHAR
) );
343 swprintf( buffer
, len
, driver_fmt
, env
->envname
, env
->versionregpath
);
344 RegCreateKeyW( HKEY_LOCAL_MACHINE
, buffer
, &retval
);
358 static DWORD
create_printers_reg_key( enum printers_key type
, HKEY
*key
)
362 case system_printers_key
:
363 return RegCreateKeyW( HKEY_LOCAL_MACHINE
, L
"System\\CurrentControlSet\\Control\\Print\\Printers", key
);
364 case user_printers_key
:
365 return RegCreateKeyW( HKEY_CURRENT_USER
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices", key
);
367 return RegCreateKeyW( HKEY_CURRENT_USER
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\PrinterPorts", key
);
368 case user_default_key
:
369 return RegCreateKeyW( HKEY_CURRENT_USER
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows", key
);
371 return ERROR_PATH_NOT_FOUND
;
374 static CRITICAL_SECTION config_modules_cs
;
375 static CRITICAL_SECTION_DEBUG config_modules_cs_debug
=
377 0, 0, &config_modules_cs
,
378 { &config_modules_cs_debug
.ProcessLocksList
, &config_modules_cs_debug
.ProcessLocksList
},
379 0, 0, { (DWORD_PTR
)(__FILE__
": config_modules_cs") }
381 static CRITICAL_SECTION config_modules_cs
= { &config_modules_cs_debug
, -1, 0, 0, 0, 0 };
383 static int compare_config_modules(const void *key
, const struct wine_rb_entry
*entry
)
385 config_module_t
*module
= WINE_RB_ENTRY_VALUE(entry
, config_module_t
, entry
);
386 return wcsicmp( key
, module
->name
);
389 static struct wine_rb_tree config_modules
= { compare_config_modules
};
391 static void release_config_module(config_module_t
*config_module
)
393 if (InterlockedDecrement(&config_module
->ref
)) return;
394 FreeLibrary(config_module
->module
);
398 static config_module_t
*get_config_module(const WCHAR
*device
, BOOL grab
)
400 WCHAR driver_name
[100], driver
[MAX_PATH
];
402 HKEY printers_key
, printer_key
, drivers_key
, driver_key
;
403 HMODULE driver_module
;
404 config_module_t
*ret
= NULL
;
405 struct wine_rb_entry
*entry
;
409 EnterCriticalSection(&config_modules_cs
);
410 entry
= wine_rb_get(&config_modules
, device
);
412 ret
= WINE_RB_ENTRY_VALUE(entry
, config_module_t
, entry
);
413 if (grab
) InterlockedIncrement(&ret
->ref
);
418 if (create_printers_reg_key(system_printers_key
, &printers_key
))
420 ERR("Can't create Printers key\n");
424 r
= RegOpenKeyW(printers_key
, device
, &printer_key
);
425 RegCloseKey(printers_key
);
428 WARN("Device %s key not found\n", debugstr_w(device
));
432 size
= sizeof(driver_name
);
433 r
= RegQueryValueExW(printer_key
, L
"Printer Driver", 0, &type
, (BYTE
*)driver_name
, &size
);
434 RegCloseKey(printer_key
);
435 if (r
|| type
!= REG_SZ
)
437 WARN("Can't get Printer Driver name\n");
441 if (!(drivers_key
= WINSPOOL_OpenDriverReg(NULL
))) goto ret
;
443 res
= RegOpenKeyW(drivers_key
, driver_name
, &driver_key
);
444 RegCloseKey(drivers_key
);
446 WARN("Driver %s key not found\n", debugstr_w(driver_name
));
450 size
= sizeof(driver
);
451 if (!GetPrinterDriverDirectoryW(NULL
, NULL
, 1, (LPBYTE
)driver
, size
, &size
)) goto ret
;
453 len
= size
/ sizeof(WCHAR
) - 1;
454 driver
[len
++] = '\\';
456 driver
[len
++] = '\\';
457 size
= sizeof(driver
) - len
* sizeof(WCHAR
);
458 res
= RegQueryValueExW( driver_key
, L
"Configuration File", NULL
, &type
,
459 (BYTE
*)(driver
+ len
), &size
);
460 RegCloseKey(driver_key
);
461 if (res
|| type
!= REG_SZ
) {
462 WARN("no configuration file: %lu\n", res
);
466 if (!(driver_module
= LoadLibraryW(driver
))) {
467 WARN("Could not load %s\n", debugstr_w(driver
));
471 len
= wcslen( device
);
472 if (!(ret
= malloc(FIELD_OFFSET(config_module_t
, name
[len
+ 1]))))
475 ret
->ref
= 2; /* one for config_module and one for the caller */
476 ret
->module
= driver_module
;
477 ret
->pDrvDeviceCapabilities
= (void *)GetProcAddress(driver_module
, "DrvDeviceCapabilities");
478 ret
->pDrvDocumentPropertySheets
= (void *)GetProcAddress(driver_module
, "DrvDocumentPropertySheets");
479 wcscpy( ret
->name
, device
);
481 wine_rb_put(&config_modules
, ret
->name
, &ret
->entry
);
483 LeaveCriticalSection(&config_modules_cs
);
487 /* ################################ */
489 static int multi_sz_lenA(const char *str
)
491 const char *ptr
= str
;
495 ptr
+= strlen( ptr
) + 1;
498 return ptr
- str
+ 1;
501 /*****************************************************************************
504 * Return DWORD associated with name from hkey.
506 static DWORD
get_dword_from_reg( HKEY hkey
, const WCHAR
*name
)
508 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
511 ret
= RegQueryValueExW( hkey
, name
, 0, &type
, (LPBYTE
)&value
, &sz
);
513 if (ret
!= ERROR_SUCCESS
)
515 WARN( "Got ret = %ld on name %s\n", ret
, debugstr_w(name
) );
518 if (type
!= REG_DWORD
)
520 ERR( "Got type %ld\n", type
);
526 static inline DWORD
set_reg_DWORD( HKEY hkey
, const WCHAR
*keyname
, const DWORD value
)
528 return RegSetValueExW( hkey
, keyname
, 0, REG_DWORD
, (const BYTE
*)&value
, sizeof(value
) );
531 /******************************************************************
533 * Get the pointer to the opened printer referred by the handle
535 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
537 UINT_PTR idx
= (UINT_PTR
)hprn
;
538 opened_printer_t
*ret
= NULL
;
540 EnterCriticalSection(&printer_handles_cs
);
542 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
543 ret
= printer_handles
[idx
- 1];
545 LeaveCriticalSection(&printer_handles_cs
);
549 /******************************************************************
550 * get_opened_printer_name
551 * Get the pointer to the opened printer name referred by the handle
553 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
555 opened_printer_t
*printer
= get_opened_printer(hprn
);
556 if(!printer
) return NULL
;
557 return printer
->name
;
560 static HANDLE
get_backend_handle( HANDLE hprn
)
562 opened_printer_t
*printer
= get_opened_printer( hprn
);
563 if (!printer
) return NULL
;
564 return printer
->backend_printer
;
567 static DWORD
open_printer_reg_key( const WCHAR
*name
, HKEY
*key
)
573 err
= create_printers_reg_key( system_printers_key
, &printers
);
576 err
= RegOpenKeyW( printers
, name
, key
);
577 if (err
) err
= ERROR_INVALID_PRINTER_NAME
;
578 RegCloseKey( printers
);
582 /******************************************************************
583 * WINSPOOL_GetOpenedPrinterRegKey
586 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
588 LPCWSTR name
= get_opened_printer_name(hPrinter
);
590 if(!name
) return ERROR_INVALID_HANDLE
;
591 return open_printer_reg_key( name
, phkey
);
594 static BOOL
get_internal_fallback_ppd( const WCHAR
*ppd
)
600 HRSRC res
= FindResourceW( WINSPOOL_hInstance
, MAKEINTRESOURCEW(1), L
"PPDFILE" );
602 if (!res
|| !(ptr
= LoadResource( WINSPOOL_hInstance
, res
))) return FALSE
;
603 size
= SizeofResource( WINSPOOL_hInstance
, res
);
604 end
= memchr( ptr
, 0, size
); /* resource file may contain additional nulls */
605 if (end
) size
= end
- ptr
;
606 file
= CreateFileW( ppd
, GENERIC_WRITE
, FILE_SHARE_READ
, NULL
, CREATE_ALWAYS
, 0, 0 );
607 if (file
== INVALID_HANDLE_VALUE
) return FALSE
;
608 ret
= WriteFile( file
, ptr
, size
, &written
, NULL
) && written
== size
;
610 if (ret
) TRACE( "using internal fallback for %s\n", debugstr_w( ppd
));
611 else DeleteFileW( ppd
);
615 static WCHAR
*get_ppd_filename( const WCHAR
*dir
, const WCHAR
*file_name
)
617 static const WCHAR dot_ppd
[] = L
".ppd";
618 static const WCHAR invalid_chars
[] = L
"*?<>|\"/\\";
619 int dir_len
= wcslen( dir
), file_len
= wcslen( file_name
);
620 int len
= (dir_len
+ file_len
+ ARRAY_SIZE( dot_ppd
)) * sizeof(WCHAR
);
621 WCHAR
*ppd
= malloc( len
), *p
;
623 if (!ppd
) return NULL
;
624 memcpy( ppd
, dir
, dir_len
* sizeof(WCHAR
) );
625 memcpy( ppd
+ dir_len
, file_name
, file_len
* sizeof(WCHAR
) );
626 memcpy( ppd
+ dir_len
+ file_len
, dot_ppd
, sizeof(dot_ppd
) );
629 while ((p
= wcspbrk( p
, invalid_chars
))) *p
++ = '_';
634 static BOOL
add_printer_driver( const WCHAR
*name
, const WCHAR
*ppd_dir
)
636 WCHAR
*ppd
= get_ppd_filename( ppd_dir
, name
);
637 struct get_ppd_params ppd_params
;
638 UNICODE_STRING nt_ppd
= { .Buffer
= NULL
};
642 WCHAR raw
[] = L
"RAW", driver_nt
[] = L
"wineps.drv";
644 if (!ppd
) return FALSE
;
645 if (!RtlDosPathNameToNtPathName_U( ppd
, &nt_ppd
, NULL
, NULL
)) goto end
;
647 ppd_params
.printer
= name
;
648 ppd_params
.ppd
= nt_ppd
.Buffer
;
649 res
= !UNIX_CALL( get_ppd
, &ppd_params
) || get_internal_fallback_ppd( ppd
);
652 AddPrintProcessorW(NULL
, NULL
, driver_nt
, (WCHAR
*)L
"wineps");
654 memset( &di3
, 0, sizeof(DRIVER_INFO_3W
) );
656 di3
.pName
= (WCHAR
*)name
;
657 di3
.pDriverPath
= driver_nt
;
659 di3
.pConfigFile
= driver_nt
;
660 di3
.pDefaultDataType
= raw
;
662 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
664 di3
.pEnvironment
= (WCHAR
*)all_printenv
[i
]->envname
;
665 if (all_printenv
[i
]->driverversion
== 0)
667 WCHAR driver_9x
[] = L
"wineps16.drv";
668 /* We use wineps16.drv as driver for 16 bit */
669 di3
.pDriverPath
= driver_9x
;
670 di3
.pConfigFile
= driver_9x
;
672 res
= AddPrinterDriverExW( NULL
, 3, (BYTE
*)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
);
673 TRACE( "got %d and %ld for %s (%s)\n", res
, GetLastError(), debugstr_w( name
), debugstr_w( di3
.pEnvironment
) );
675 if (!res
&& (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
677 ERR( "failed with %lu for %s (%s) %s\n", GetLastError(), debugstr_w( name
),
678 debugstr_w( di3
.pEnvironment
), debugstr_w( di3
.pDriverPath
) );
683 ppd_params
.printer
= NULL
; /* unlink the ppd */
684 UNIX_CALL( get_ppd
, &ppd_params
);
687 RtlFreeUnicodeString( &nt_ppd
);
692 static WCHAR
*get_ppd_dir( void )
694 static const WCHAR wine_ppds
[] = L
"wine_ppds\\";
696 WCHAR
*dir
, tmp_path
[MAX_PATH
];
699 len
= GetTempPathW( ARRAY_SIZE( tmp_path
), tmp_path
);
700 if (!len
) return NULL
;
701 dir
= malloc( len
* sizeof(WCHAR
) + sizeof(wine_ppds
) ) ;
702 if (!dir
) return NULL
;
704 memcpy( dir
, tmp_path
, len
* sizeof(WCHAR
) );
705 memcpy( dir
+ len
, wine_ppds
, sizeof(wine_ppds
) );
706 res
= CreateDirectoryW( dir
, NULL
);
707 if (!res
&& GetLastError() != ERROR_ALREADY_EXISTS
)
712 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir
) );
716 static BOOL
init_unix_printers( void )
718 WCHAR
*port
, *ppd_dir
= NULL
, *default_printer
= NULL
;
719 unsigned int size
, num
;
720 struct enum_printers_params enum_params
= { NULL
, &size
, &num
};
721 HKEY printer_key
, printers_key
;
722 HANDLE added_printer
;
725 WCHAR raw
[] = L
"RAW", wineps
[] = L
"wineps", empty
[] = L
"";
728 if (create_printers_reg_key( system_printers_key
, &printers_key
))
730 ERR( "Can't create Printers key\n" );
738 free( enum_params
.printers
);
739 enum_params
.printers
= malloc( size
);
740 status
= UNIX_CALL( enum_printers
, &enum_params
);
741 } while (status
== STATUS_BUFFER_OVERFLOW
);
742 if (status
) goto end
;
744 TRACE( "Found %d CUPS %s:\n", num
, (num
== 1) ? "printer" : "printers" );
745 for (i
= 0; i
< num
; i
++)
747 struct printer_info
*printer
= enum_params
.printers
+ i
;
749 if (RegOpenKeyW( printers_key
, printer
->name
, &printer_key
) == ERROR_SUCCESS
)
751 DWORD status
= get_dword_from_reg( printer_key
, L
"Status" );
752 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
754 TRACE("Printer already exists\n");
755 RegDeleteValueW( printer_key
, May_Delete_Value
);
756 /* flag that the PPD file should be checked for an update */
757 set_reg_DWORD( printer_key
, L
"Status", status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
758 RegSetValueExW( printer_key
, L
"Print Processor", 0, REG_SZ
, (const BYTE
*)wineps
,
759 (wcslen( wineps
) + 1) * sizeof(WCHAR
));
760 RegCloseKey( printer_key
);
764 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir())) break;
765 if (!add_printer_driver( printer
->name
, ppd_dir
)) continue;
767 port
= malloc( sizeof(L
"CUPS:") + wcslen( printer
->name
) * sizeof(WCHAR
) );
768 wcscpy( port
, L
"CUPS:" );
769 wcscat( port
, printer
->name
);
771 memset( &pi2
, 0, sizeof(PRINTER_INFO_2W
) );
772 pi2
.pPrinterName
= printer
->name
;
774 pi2
.pPrintProcessor
= wineps
;
775 pi2
.pDriverName
= printer
->name
;
776 pi2
.pComment
= printer
->comment
;
777 pi2
.pLocation
= printer
->location
;
778 pi2
.pPortName
= port
;
779 pi2
.pParameters
= empty
;
780 pi2
.pShareName
= empty
;
781 pi2
.pSepFile
= empty
;
783 added_printer
= AddPrinterW( NULL
, 2, (BYTE
*)&pi2
);
784 if (added_printer
) ClosePrinter( added_printer
);
785 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
786 ERR( "printer '%s' not added by AddPrinter (error %ld)\n", debugstr_w( printer
->name
), GetLastError() );
790 if (printer
->is_default
) default_printer
= printer
->name
;
793 if (!default_printer
&& num
) default_printer
= enum_params
.printers
[0].name
;
794 if (default_printer
) SetDefaultPrinterW( default_printer
);
798 RemoveDirectoryW( ppd_dir
);
802 free( enum_params
.printers
);
803 RegCloseKey( printers_key
);
807 static void set_ppd_overrides( HANDLE printer
)
810 unsigned int name_size
= sizeof(buffer
);
811 struct get_default_page_size_params params
= { .name
= buffer
, .name_size
= &name_size
};
816 status
= UNIX_CALL( get_default_page_size
, ¶ms
);
817 if (status
!= STATUS_BUFFER_OVERFLOW
) break;
818 if (params
.name
!= buffer
) free( params
.name
);
819 params
.name
= malloc( name_size
);
820 if (!params
.name
) break;
822 if (!status
) SetPrinterDataExW( printer
, L
"PPD Overrides", L
"DefaultPageSize", REG_SZ
, (BYTE
*)params
.name
, name_size
);
823 if (params
.name
!= buffer
) free( params
.name
);
826 static BOOL
update_driver( HANDLE printer
)
829 const WCHAR
*name
= get_opened_printer_name( printer
);
832 if (!name
) return FALSE
;
833 if (!(ppd_dir
= get_ppd_dir())) return FALSE
;
835 TRACE( "updating driver %s\n", debugstr_w( name
) );
836 ret
= add_printer_driver( name
, ppd_dir
);
840 set_ppd_overrides( printer
);
842 /* call into the driver to update the devmode */
843 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
848 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
851 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
852 (wcslen( value
) + 1) * sizeof(WCHAR
));
854 return ERROR_FILE_NOT_FOUND
;
857 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
859 DEVMODEA
*dmA
= DEVMODEWtoA( dm
, NULL
);
860 DWORD ret
= ERROR_FILE_NOT_FOUND
;
862 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
863 and we support these drivers. NT writes DEVMODEW so somehow
864 we'll need to distinguish between these when we support NT
869 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
870 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
877 /******************************************************************
878 * get_servername_from_name (internal)
880 * for an external server, a copy of the serverpart from the full name is returned
883 static LPWSTR
get_servername_from_name(LPCWSTR name
)
887 WCHAR buffer
[MAX_PATH
];
890 if (name
== NULL
) return NULL
;
891 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
893 server
= wcsdup(&name
[2]); /* skip over both backslashes */
894 if (server
== NULL
) return NULL
;
896 /* strip '\' and the printername */
897 ptr
= wcschr( server
, '\\' );
898 if (ptr
) ptr
[0] = '\0';
900 TRACE("found %s\n", debugstr_w(server
));
902 len
= ARRAY_SIZE(buffer
);
903 if (GetComputerNameW(buffer
, &len
))
905 if (!wcscmp( buffer
, server
))
907 /* The requested Servername is our computername */
915 /******************************************************************
916 * get_basename_from_name (internal)
918 * skip over the serverpart from the full name
921 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
923 if (name
== NULL
) return NULL
;
924 if ((name
[0] == '\\') && (name
[1] == '\\'))
926 /* skip over the servername and search for the following '\' */
927 name
= wcschr( &name
[2], '\\' );
928 if ((name
) && (name
[1]))
930 /* found a separator ('\') followed by a name:
931 skip over the separator and return the rest */
936 /* no basename present (we found only a servername) */
943 static void free_printer_entry( opened_printer_t
*printer
)
945 /* the queue is shared, so don't free that here */
946 free( printer
->name
);
950 /******************************************************************
951 * get_opened_printer_entry
952 * Get the first place empty in the opened printer table
955 * - pDefault is ignored
957 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
959 opened_printer_t
*printer
= NULL
;
964 if ((backend
== NULL
) && !load_backend()) return NULL
;
966 servername
= get_servername_from_name(name
);
968 FIXME("server %s not supported\n", debugstr_w(servername
));
970 SetLastError(ERROR_INVALID_PRINTER_NAME
);
974 printername
= get_basename_from_name(name
);
975 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
977 /* an empty printername is invalid */
978 if (printername
&& (!printername
[0])) {
979 SetLastError(ERROR_INVALID_PARAMETER
);
983 EnterCriticalSection(&printer_handles_cs
);
985 for (handle
= 0; handle
< nb_printer_handles
; handle
++)
987 if (!printer_handles
[handle
])
991 if (handle
>= nb_printer_handles
)
993 opened_printer_t
**new_array
;
996 new_array
= realloc(printer_handles
, (nb_printer_handles
+ 16) * sizeof(*new_array
));
997 memset(new_array
+ nb_printer_handles
, 0, 16 * sizeof(*new_array
));
1001 new_array
= calloc(nb_printer_handles
+ 16, sizeof(*new_array
));
1009 printer_handles
= new_array
;
1010 nb_printer_handles
+= 16;
1013 if (!(printer
= calloc(1, sizeof(*printer
))))
1019 /* get a printer handle from the backend */
1020 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1025 /* clone the full name */
1026 printer
->name
= wcsdup(name
);
1027 if (name
&& (!printer
->name
)) {
1032 printer_handles
[handle
] = printer
;
1035 LeaveCriticalSection(&printer_handles_cs
);
1036 if (!handle
&& printer
)
1037 free_printer_entry( printer
);
1039 return (HANDLE
)handle
;
1042 static void old_printer_check( BOOL delete_phase
)
1044 PRINTER_INFO_5W
* pi
;
1045 DWORD needed
, type
, num
, delete, i
, size
;
1046 const DWORD one
= 1;
1050 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1051 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1053 pi
= malloc( needed
);
1054 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1055 for (i
= 0; i
< num
; i
++)
1057 if (!pi
[i
].pPortName
) continue;
1059 if (wcsncmp( pi
[i
].pPortName
, L
"CUPS:", ARRAY_SIZE(L
"CUPS:") - 1 ) &&
1060 wcsncmp( pi
[i
].pPortName
, L
"LPR:", ARRAY_SIZE(L
"LPR:") - 1 ))
1063 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1067 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1073 size
= sizeof( delete );
1074 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1078 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1079 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1081 DeletePrinter( hprn
);
1082 ClosePrinter( hprn
);
1084 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1091 static HANDLE init_mutex
;
1093 void WINSPOOL_LoadSystemPrinters(void)
1095 HKEY printers_key
, printer_key
;
1096 DWORD needed
, num
, i
;
1097 WCHAR PrinterName
[256];
1099 /* FIXME: The init code should be moved to spoolsv.exe */
1100 init_mutex
= CreateMutexW( NULL
, TRUE
, L
"__WINE_WINSPOOL_MUTEX__" );
1103 ERR( "Failed to create mutex\n" );
1106 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1108 WaitForSingleObject( init_mutex
, INFINITE
);
1109 ReleaseMutex( init_mutex
);
1110 TRACE( "Init already done\n" );
1114 /* This ensures that all printer entries have a valid Name value. If causes
1115 problems later if they don't. If one is found to be missed we create one
1116 and set it equal to the name of the key */
1117 if (!create_printers_reg_key( system_printers_key
, &printers_key
))
1119 if (!RegQueryInfoKeyW( printers_key
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
))
1120 for (i
= 0; i
< num
; i
++)
1121 if (!RegEnumKeyW( printers_key
, i
, PrinterName
, ARRAY_SIZE(PrinterName
) ))
1122 if (!RegOpenKeyW( printers_key
, PrinterName
, &printer_key
))
1124 if (RegQueryValueExW( printer_key
, L
"Name", 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
)
1125 set_reg_szW( printer_key
, L
"Name", PrinterName
);
1126 RegCloseKey( printer_key
);
1128 RegCloseKey( printers_key
);
1131 old_printer_check( FALSE
);
1132 init_unix_printers();
1133 old_printer_check( TRUE
);
1135 ReleaseMutex( init_mutex
);
1139 /******************************************************************
1140 * convert_printerinfo_W_to_A [internal]
1143 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1144 DWORD level
, DWORD outlen
, DWORD numentries
)
1150 TRACE("(%p, %p, %ld, %lu, %lu)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1152 len
= pi_sizeof
[level
] * numentries
;
1153 ptr
= (LPSTR
) out
+ len
;
1156 /* copy the numbers of all PRINTER_INFO_* first */
1157 memcpy(out
, pPrintersW
, len
);
1159 while (id
< numentries
) {
1163 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1164 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1166 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(piW
->pName
));
1167 if (piW
->pDescription
) {
1168 piA
->pDescription
= ptr
;
1169 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1170 ptr
, outlen
, NULL
, NULL
);
1176 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1177 ptr
, outlen
, NULL
, NULL
);
1181 if (piW
->pComment
) {
1182 piA
->pComment
= ptr
;
1183 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1184 ptr
, outlen
, NULL
, NULL
);
1193 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1194 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1196 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1197 if (piW
->pServerName
) {
1198 piA
->pServerName
= ptr
;
1199 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1200 ptr
, outlen
, NULL
, NULL
);
1204 if (piW
->pPrinterName
) {
1205 piA
->pPrinterName
= ptr
;
1206 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1207 ptr
, outlen
, NULL
, NULL
);
1211 if (piW
->pShareName
) {
1212 piA
->pShareName
= ptr
;
1213 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1214 ptr
, outlen
, NULL
, NULL
);
1218 if (piW
->pPortName
) {
1219 piA
->pPortName
= ptr
;
1220 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1221 ptr
, outlen
, NULL
, NULL
);
1225 if (piW
->pDriverName
) {
1226 piA
->pDriverName
= ptr
;
1227 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1228 ptr
, outlen
, NULL
, NULL
);
1232 if (piW
->pComment
) {
1233 piA
->pComment
= ptr
;
1234 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1235 ptr
, outlen
, NULL
, NULL
);
1239 if (piW
->pLocation
) {
1240 piA
->pLocation
= ptr
;
1241 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1242 ptr
, outlen
, NULL
, NULL
);
1249 /* align DEVMODEA to a DWORD boundary */
1250 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1254 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1255 DEVMODEWtoA(piW
->pDevMode
, piA
->pDevMode
);
1256 len
= piA
->pDevMode
->dmSize
+ piA
->pDevMode
->dmDriverExtra
;
1262 if (piW
->pSepFile
) {
1263 piA
->pSepFile
= ptr
;
1264 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1265 ptr
, outlen
, NULL
, NULL
);
1269 if (piW
->pPrintProcessor
) {
1270 piA
->pPrintProcessor
= ptr
;
1271 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1272 ptr
, outlen
, NULL
, NULL
);
1276 if (piW
->pDatatype
) {
1277 piA
->pDatatype
= ptr
;
1278 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1279 ptr
, outlen
, NULL
, NULL
);
1283 if (piW
->pParameters
) {
1284 piA
->pParameters
= ptr
;
1285 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1286 ptr
, outlen
, NULL
, NULL
);
1290 if (piW
->pSecurityDescriptor
) {
1291 piA
->pSecurityDescriptor
= NULL
;
1292 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1299 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1300 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1302 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1304 if (piW
->pPrinterName
) {
1305 piA
->pPrinterName
= ptr
;
1306 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1307 ptr
, outlen
, NULL
, NULL
);
1311 if (piW
->pServerName
) {
1312 piA
->pServerName
= ptr
;
1313 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1314 ptr
, outlen
, NULL
, NULL
);
1323 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1324 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1326 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1328 if (piW
->pPrinterName
) {
1329 piA
->pPrinterName
= ptr
;
1330 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1331 ptr
, outlen
, NULL
, NULL
);
1335 if (piW
->pPortName
) {
1336 piA
->pPortName
= ptr
;
1337 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1338 ptr
, outlen
, NULL
, NULL
);
1345 case 6: /* 6A and 6W are the same structure */
1350 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1351 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1353 TRACE("(%lu) #%lu\n", level
, id
);
1354 if (piW
->pszObjectGUID
) {
1355 piA
->pszObjectGUID
= ptr
;
1356 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1357 ptr
, outlen
, NULL
, NULL
);
1367 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1368 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1370 TRACE("(%lu) #%lu\n", level
, id
);
1373 /* align DEVMODEA to a DWORD boundary */
1374 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1378 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1379 DEVMODEWtoA(piW
->pDevMode
, piA
->pDevMode
);
1380 len
= piA
->pDevMode
->dmSize
+ piA
->pDevMode
->dmDriverExtra
;
1389 FIXME("for level %lu\n", level
);
1391 pPrintersW
+= pi_sizeof
[level
];
1392 out
+= pi_sizeof
[level
];
1397 /******************************************************************
1398 * convert_driverinfo_W_to_A [internal]
1401 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1402 DWORD level
, DWORD outlen
, DWORD numentries
)
1408 TRACE("(%p, %p, %ld, %lu, %lu)\n", out
, pDriversW
, level
, outlen
, numentries
);
1410 len
= di_sizeof
[level
] * numentries
;
1411 ptr
= (LPSTR
) out
+ len
;
1414 /* copy the numbers of all PRINTER_INFO_* first */
1415 memcpy(out
, pDriversW
, len
);
1417 #define COPY_STRING(fld) \
1420 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1421 ptr += len; outlen -= len;\
1423 #define COPY_MULTIZ_STRING(fld) \
1424 { LPWSTR p = diW->fld; if (p){ \
1427 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1428 ptr += len; outlen -= len; p += len;\
1430 while(len > 1 && outlen > 0); \
1433 while (id
< numentries
)
1439 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1440 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1442 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1449 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1450 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1452 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1455 COPY_STRING(pEnvironment
);
1456 COPY_STRING(pDriverPath
);
1457 COPY_STRING(pDataFile
);
1458 COPY_STRING(pConfigFile
);
1463 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1464 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1466 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1469 COPY_STRING(pEnvironment
);
1470 COPY_STRING(pDriverPath
);
1471 COPY_STRING(pDataFile
);
1472 COPY_STRING(pConfigFile
);
1473 COPY_STRING(pHelpFile
);
1474 COPY_MULTIZ_STRING(pDependentFiles
);
1475 COPY_STRING(pMonitorName
);
1476 COPY_STRING(pDefaultDataType
);
1481 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
1482 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
1484 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1487 COPY_STRING(pEnvironment
);
1488 COPY_STRING(pDriverPath
);
1489 COPY_STRING(pDataFile
);
1490 COPY_STRING(pConfigFile
);
1491 COPY_STRING(pHelpFile
);
1492 COPY_MULTIZ_STRING(pDependentFiles
);
1493 COPY_STRING(pMonitorName
);
1494 COPY_STRING(pDefaultDataType
);
1495 COPY_MULTIZ_STRING(pszzPreviousNames
);
1500 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
1501 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
1503 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1506 COPY_STRING(pEnvironment
);
1507 COPY_STRING(pDriverPath
);
1508 COPY_STRING(pDataFile
);
1509 COPY_STRING(pConfigFile
);
1514 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
1515 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
1517 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1520 COPY_STRING(pEnvironment
);
1521 COPY_STRING(pDriverPath
);
1522 COPY_STRING(pDataFile
);
1523 COPY_STRING(pConfigFile
);
1524 COPY_STRING(pHelpFile
);
1525 COPY_MULTIZ_STRING(pDependentFiles
);
1526 COPY_STRING(pMonitorName
);
1527 COPY_STRING(pDefaultDataType
);
1528 COPY_MULTIZ_STRING(pszzPreviousNames
);
1529 COPY_STRING(pszMfgName
);
1530 COPY_STRING(pszOEMUrl
);
1531 COPY_STRING(pszHardwareID
);
1532 COPY_STRING(pszProvider
);
1537 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
1538 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
1540 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1543 COPY_STRING(pEnvironment
);
1544 COPY_STRING(pDriverPath
);
1545 COPY_STRING(pDataFile
);
1546 COPY_STRING(pConfigFile
);
1547 COPY_STRING(pHelpFile
);
1548 COPY_MULTIZ_STRING(pDependentFiles
);
1549 COPY_STRING(pMonitorName
);
1550 COPY_STRING(pDefaultDataType
);
1551 COPY_MULTIZ_STRING(pszzPreviousNames
);
1552 COPY_STRING(pszMfgName
);
1553 COPY_STRING(pszOEMUrl
);
1554 COPY_STRING(pszHardwareID
);
1555 COPY_STRING(pszProvider
);
1556 COPY_STRING(pszPrintProcessor
);
1557 COPY_STRING(pszVendorSetup
);
1558 COPY_MULTIZ_STRING(pszzColorProfiles
);
1559 COPY_STRING(pszInfPath
);
1560 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
1566 FIXME("for level %lu\n", level
);
1569 pDriversW
+= di_sizeof
[level
];
1570 out
+= di_sizeof
[level
];
1575 #undef COPY_MULTIZ_STRING
1579 /***********************************************************
1582 static void *printer_info_AtoW( const void *data
, DWORD level
)
1585 UNICODE_STRING usBuffer
;
1587 if (!data
) return NULL
;
1589 if (level
< 1 || level
> 9) return NULL
;
1591 ret
= malloc( pi_sizeof
[level
] );
1592 if (!ret
) return NULL
;
1594 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
1600 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
1601 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
1603 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
1604 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
1605 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
1606 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
1607 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
1608 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
1609 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
1610 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
1611 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
1612 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
1613 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
1614 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
1621 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
1622 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
1624 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
1629 FIXME( "Unhandled level %ld\n", level
);
1637 /***********************************************************
1640 static void free_printer_info( void *data
, DWORD level
)
1648 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
1650 free( piW
->pServerName
);
1651 free( piW
->pPrinterName
);
1652 free( piW
->pShareName
);
1653 free( piW
->pPortName
);
1654 free( piW
->pDriverName
);
1655 free( piW
->pComment
);
1656 free( piW
->pLocation
);
1657 heap_free( piW
->pDevMode
);
1658 free( piW
->pSepFile
);
1659 free( piW
->pPrintProcessor
);
1660 free( piW
->pDatatype
);
1661 free( piW
->pParameters
);
1668 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
1670 heap_free( piW
->pDevMode
);
1675 FIXME( "Unhandled level %ld\n", level
);
1682 /******************************************************************
1683 * DeviceCapabilities [WINSPOOL.@]
1684 * DeviceCapabilitiesA [WINSPOOL.@]
1687 INT WINAPI
DeviceCapabilitiesA(const char *device
, const char *portA
, WORD cap
,
1688 char *output
, DEVMODEA
*devmodeA
)
1690 WCHAR
*device_name
= NULL
, *port
= NULL
;
1691 DEVMODEW
*devmode
= NULL
;
1694 len
= MultiByteToWideChar(CP_ACP
, 0, device
, -1, NULL
, 0);
1696 device_name
= malloc(len
* sizeof(WCHAR
));
1697 MultiByteToWideChar(CP_ACP
, 0, device
, -1, device_name
, len
);
1700 len
= MultiByteToWideChar(CP_ACP
, 0, portA
, -1, NULL
, 0);
1702 port
= malloc(len
* sizeof(WCHAR
));
1703 MultiByteToWideChar(CP_ACP
, 0, portA
, -1, port
, len
);
1706 if (devmodeA
) devmode
= GdiConvertToDevmodeW( devmodeA
);
1708 if (output
&& (cap
== DC_BINNAMES
|| cap
== DC_FILEDEPENDENCIES
|| cap
== DC_PAPERNAMES
)) {
1709 /* These need A -> W translation */
1710 unsigned int size
= 0, i
;
1713 ret
= DeviceCapabilitiesW(device_name
, port
, cap
, NULL
, devmode
);
1714 if (ret
== -1) goto cleanup
;
1721 case DC_FILEDEPENDENCIES
:
1725 outputW
= malloc(size
* ret
* sizeof(WCHAR
));
1726 ret
= DeviceCapabilitiesW(device_name
, port
, cap
, outputW
, devmode
);
1727 for (i
= 0; i
< ret
; i
++)
1728 WideCharToMultiByte(CP_ACP
, 0, outputW
+ (i
* size
), -1,
1729 output
+ (i
* size
), size
, NULL
, NULL
);
1732 ret
= DeviceCapabilitiesW(device_name
, port
, cap
, (WCHAR
*)output
, devmode
);
1741 /*****************************************************************************
1742 * DeviceCapabilitiesW [WINSPOOL.@]
1745 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1746 WORD fwCapability
, LPWSTR pOutput
,
1747 const DEVMODEW
*pDevMode
)
1749 config_module_t
*config
;
1752 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice
), debugstr_w(pPort
), fwCapability
,
1755 if (!(config
= get_config_module(pDevice
, TRUE
))) {
1756 WARN("Could not load config module for %s\n", debugstr_w(pDevice
));
1760 ret
= config
->pDrvDeviceCapabilities(NULL
/* FIXME */, pDevice
, fwCapability
,
1762 release_config_module(config
);
1766 /******************************************************************
1767 * DocumentPropertiesA [WINSPOOL.@]
1769 LONG WINAPI
DocumentPropertiesA(HWND hwnd
, HANDLE printer
, char *device_name
, DEVMODEA
*output
,
1770 DEVMODEA
*input
, DWORD mode
)
1772 DEVMODEW
*outputW
= NULL
, *inputW
= NULL
;
1773 WCHAR
*device
= NULL
;
1777 TRACE("(%p,%p,%s,%p,%p,%ld)\n", hwnd
, printer
, debugstr_a(device_name
), output
, input
, mode
);
1779 len
= MultiByteToWideChar(CP_ACP
, 0, device_name
, -1, NULL
, 0);
1781 device
= malloc(len
* sizeof(WCHAR
));
1782 MultiByteToWideChar(CP_ACP
, 0, device_name
, -1, device
, len
);
1785 if (output
&& (mode
& (DM_COPY
| DM_UPDATE
))) {
1786 ret
= DocumentPropertiesW(hwnd
, printer
, device
, NULL
, NULL
, 0);
1791 outputW
= malloc(ret
);
1794 if (input
&& (mode
& DM_IN_BUFFER
)) inputW
= GdiConvertToDevmodeW(input
);
1796 ret
= DocumentPropertiesW(hwnd
, printer
, device
, outputW
, inputW
, mode
);
1798 if (ret
>= 0 && outputW
&& (mode
& (DM_COPY
| DM_UPDATE
)))
1799 DEVMODEWtoA( outputW
, output
);
1805 if (!mode
&& ret
> 0) ret
-= CCHDEVICENAME
+ CCHFORMNAME
;
1809 static LONG WINAPI
document_callback(PROPSHEETUI_INFO
*info
, LPARAM lparam
)
1811 if (info
->Reason
== PROPSHEETUI_REASON_INIT
)
1813 document_property_t
*dp
= (document_property_t
*)info
->lParamInit
;
1815 if (!info
->pfnComPropSheet(info
->hComPropSheet
, CPSFUNC_ADD_PFNPROPSHEETUIW
,
1816 (LPARAM
)dp
->config
->pDrvDocumentPropertySheets
, (LPARAM
)&dp
->dph
))
1817 return ERR_CPSUI_GETLASTERROR
;
1822 /*****************************************************************************
1823 * DocumentPropertiesW (WINSPOOL.@)
1825 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1827 LPDEVMODEW pDevModeOutput
,
1828 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1830 document_property_t dp
;
1831 const WCHAR
*device
;
1834 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1835 hWnd
, hPrinter
, debugstr_w(pDeviceName
), pDevModeOutput
, pDevModeInput
, fMode
);
1837 device
= hPrinter
? get_opened_printer_name(hPrinter
) : pDeviceName
;
1839 ERR("no device name\n");
1843 dp
.dph
.cbSize
= sizeof(dp
.dph
);
1844 dp
.dph
.Reserved
= 0;
1845 dp
.dph
.hPrinter
= hPrinter
;
1846 dp
.dph
.pszPrinterName
= device
;
1847 dp
.dph
.pdmIn
= pDevModeInput
;
1848 dp
.dph
.pdmOut
= pDevModeOutput
;
1849 dp
.dph
.cbOut
= dp
.dph
.pdmOut
? dp
.dph
.pdmOut
->dmSize
: 0;
1850 dp
.dph
.fMode
= fMode
;
1851 dp
.config
= get_config_module(device
, TRUE
);
1853 ERR("Could not load config module for %s\n", debugstr_w(device
));
1857 if (!(fMode
& ~(DM_IN_BUFFER
| DM_OUT_BUFFER
| DM_OUT_DEFAULT
))) {
1858 ret
= dp
.config
->pDrvDocumentPropertySheets(NULL
, (LPARAM
)&dp
.dph
);
1860 if ((!fMode
|| !pDevModeOutput
) && dp
.dph
.cbOut
!= ret
)
1861 FIXME("size mismatch: ret = %ld cbOut = %ld\n", ret
, dp
.dph
.cbOut
);
1863 ret
= CommonPropertySheetUIW(hWnd
, document_callback
, (LPARAM
)&dp
, NULL
);
1866 release_config_module(dp
.config
);
1870 /*****************************************************************************
1871 * IsValidDevmodeA [WINSPOOL.@]
1873 * Validate a DEVMODE structure and fix errors if possible.
1876 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA pDevMode
, SIZE_T size
)
1878 FIXME("(%p,%Id): stub\n", pDevMode
, size
);
1886 /*****************************************************************************
1887 * IsValidDevmodeW [WINSPOOL.@]
1889 * Validate a DEVMODE structure and fix errors if possible.
1892 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW dm
, SIZE_T size
)
1900 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
1901 { DM_ORIENTATION
, F_SIZE(u1
.s1
.dmOrientation
) },
1902 { DM_PAPERSIZE
, F_SIZE(u1
.s1
.dmPaperSize
) },
1903 { DM_PAPERLENGTH
, F_SIZE(u1
.s1
.dmPaperLength
) },
1904 { DM_PAPERWIDTH
, F_SIZE(u1
.s1
.dmPaperWidth
) },
1905 { DM_SCALE
, F_SIZE(u1
.s1
.dmScale
) },
1906 { DM_COPIES
, F_SIZE(u1
.s1
.dmCopies
) },
1907 { DM_DEFAULTSOURCE
, F_SIZE(u1
.s1
.dmDefaultSource
) },
1908 { DM_PRINTQUALITY
, F_SIZE(u1
.s1
.dmPrintQuality
) },
1909 { DM_POSITION
, F_SIZE(u1
.s2
.dmPosition
) },
1910 { DM_DISPLAYORIENTATION
, F_SIZE(u1
.s2
.dmDisplayOrientation
) },
1911 { DM_DISPLAYFIXEDOUTPUT
, F_SIZE(u1
.s2
.dmDisplayFixedOutput
) },
1912 { DM_COLOR
, F_SIZE(dmColor
) },
1913 { DM_DUPLEX
, F_SIZE(dmDuplex
) },
1914 { DM_YRESOLUTION
, F_SIZE(dmYResolution
) },
1915 { DM_TTOPTION
, F_SIZE(dmTTOption
) },
1916 { DM_COLLATE
, F_SIZE(dmCollate
) },
1917 { DM_FORMNAME
, F_SIZE(dmFormName
) },
1918 { DM_LOGPIXELS
, F_SIZE(dmLogPixels
) },
1919 { DM_BITSPERPEL
, F_SIZE(dmBitsPerPel
) },
1920 { DM_PELSWIDTH
, F_SIZE(dmPelsWidth
) },
1921 { DM_PELSHEIGHT
, F_SIZE(dmPelsHeight
) },
1922 { DM_DISPLAYFLAGS
, F_SIZE(u2
.dmDisplayFlags
) },
1923 { DM_NUP
, F_SIZE(u2
.dmNup
) },
1924 { DM_DISPLAYFREQUENCY
, F_SIZE(dmDisplayFrequency
) },
1925 { DM_ICMMETHOD
, F_SIZE(dmICMMethod
) },
1926 { DM_ICMINTENT
, F_SIZE(dmICMIntent
) },
1927 { DM_MEDIATYPE
, F_SIZE(dmMediaType
) },
1928 { DM_DITHERTYPE
, F_SIZE(dmDitherType
) },
1929 { DM_PANNINGWIDTH
, F_SIZE(dmPanningWidth
) },
1930 { DM_PANNINGHEIGHT
, F_SIZE(dmPanningHeight
) }
1934 const DWORD fields_off
= FIELD_OFFSET(DEVMODEW
, dmFields
) + sizeof(dm
->dmFields
);
1936 if (!dm
) return FALSE
;
1937 if (size
< fields_off
) return FALSE
;
1938 if (dm
->dmSize
< fields_off
|| size
< dm
->dmSize
+ dm
->dmDriverExtra
) return FALSE
;
1940 for (i
= 0; i
< ARRAY_SIZE(map
); i
++)
1941 if ((dm
->dmFields
& map
[i
].flag
) && dm
->dmSize
< map
[i
].size
)
1947 /******************************************************************
1948 * OpenPrinterA [WINSPOOL.@]
1953 BOOL WINAPI
OpenPrinterA(LPSTR name
, HANDLE
*printer
, PRINTER_DEFAULTSA
*defaults
)
1955 return OpenPrinter2A(name
, printer
, defaults
, NULL
);
1958 /******************************************************************
1959 * OpenPrinterW [WINSPOOL.@]
1961 * Open a Printer / Printserver or a Printer-Object
1964 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1965 * phPrinter [O] The resulting Handle is stored here
1966 * pDefault [I] PTR to Default Printer Settings or NULL
1973 * lpPrinterName is one of:
1974 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1975 *| Printer: "PrinterName"
1976 *| Printer-Object: "PrinterName,Job xxx"
1977 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1978 *| XcvPort: "Servername,XcvPort PortName"
1981 *| Printer-Object not supported
1982 *| pDefaults is ignored
1985 BOOL WINAPI
OpenPrinterW(LPWSTR name
, HANDLE
*printer
, PRINTER_DEFAULTSW
*defaults
)
1987 return OpenPrinter2W(name
, printer
, defaults
, NULL
);
1990 BOOL WINAPI
OpenPrinter2A(LPSTR name
, HANDLE
*printer
,
1991 PRINTER_DEFAULTSA
*defaults
, PRINTER_OPTIONSA
*options
)
1993 UNICODE_STRING nameU
;
1994 UNICODE_STRING datatypeU
;
1995 PRINTER_DEFAULTSW defaultsW
, *p_defaultsW
= NULL
;
1996 PRINTER_OPTIONSW optionsW
, *p_optionsW
= NULL
;
2000 TRACE("(%s,%p,%p,%p)\n", debugstr_a(name
), printer
, defaults
, options
);
2002 nameW
= asciitounicode(&nameU
, name
);
2006 optionsW
.cbSize
= sizeof(optionsW
);
2007 optionsW
.dwFlags
= options
->dwFlags
;
2008 p_optionsW
= &optionsW
;
2013 defaultsW
.pDatatype
= asciitounicode(&datatypeU
, defaults
->pDatatype
);
2014 defaultsW
.pDevMode
= defaults
->pDevMode
? GdiConvertToDevmodeW(defaults
->pDevMode
) : NULL
;
2015 defaultsW
.DesiredAccess
= defaults
->DesiredAccess
;
2016 p_defaultsW
= &defaultsW
;
2019 ret
= OpenPrinter2W(nameW
, printer
, p_defaultsW
, p_optionsW
);
2023 RtlFreeUnicodeString(&datatypeU
);
2024 heap_free(defaultsW
.pDevMode
);
2026 RtlFreeUnicodeString(&nameU
);
2031 BOOL WINAPI
OpenPrinter2W(LPWSTR name
, HANDLE
*printer
,
2032 PRINTER_DEFAULTSW
*defaults
, PRINTER_OPTIONSW
*options
)
2036 TRACE("(%s,%p,%p,%p)\n", debugstr_w(name
), printer
, defaults
, options
);
2039 FIXME("flags %08lx ignored\n", options
->dwFlags
);
2043 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2044 SetLastError( ERROR_INVALID_PARAMETER
);
2048 /* Get the unique handle of the printer or Printserver */
2049 *printer
= get_opened_printer_entry( name
, defaults
);
2051 if (*printer
&& WINSPOOL_GetOpenedPrinterRegKey( *printer
, &key
) == ERROR_SUCCESS
)
2053 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2055 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2056 WaitForSingleObject( init_mutex
, INFINITE
);
2057 status
= get_dword_from_reg( key
, L
"Status" );
2058 set_reg_DWORD( key
, L
"Status", status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2059 ReleaseMutex( init_mutex
);
2060 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2061 update_driver( *printer
);
2065 TRACE("returning %d with %lu and %p\n", *printer
!= NULL
, GetLastError(), *printer
);
2066 return (*printer
!= NULL
);
2069 /******************************************************************
2070 * AddMonitorA [WINSPOOL.@]
2075 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2077 LPWSTR nameW
= NULL
;
2080 LPMONITOR_INFO_2A mi2a
;
2081 MONITOR_INFO_2W mi2w
;
2083 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2084 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2085 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2086 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2087 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2090 SetLastError(ERROR_INVALID_LEVEL
);
2094 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2100 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2101 nameW
= malloc(len
* sizeof(WCHAR
));
2102 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2105 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2107 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2108 mi2w
.pName
= malloc(len
* sizeof(WCHAR
));
2109 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2111 if (mi2a
->pEnvironment
) {
2112 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2113 mi2w
.pEnvironment
= malloc(len
* sizeof(WCHAR
));
2114 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2116 if (mi2a
->pDLLName
) {
2117 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2118 mi2w
.pDLLName
= malloc(len
* sizeof(WCHAR
));
2119 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2122 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2125 free(mi2w
.pEnvironment
);
2126 free(mi2w
.pDLLName
);
2132 /******************************************************************************
2133 * AddMonitorW [WINSPOOL.@]
2135 * Install a Printmonitor
2138 * pName [I] Servername or NULL (local Computer)
2139 * Level [I] Structure-Level (Must be 2)
2140 * pMonitors [I] PTR to MONITOR_INFO_2
2147 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2150 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2152 LPMONITOR_INFO_2W mi2w
;
2154 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2155 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2156 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2157 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2158 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2160 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2163 SetLastError(ERROR_INVALID_LEVEL
);
2167 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2172 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2175 /******************************************************************
2176 * DeletePrinterDriverA [WINSPOOL.@]
2179 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2181 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2184 /******************************************************************
2185 * DeletePrinterDriverW [WINSPOOL.@]
2188 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2190 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2193 /******************************************************************
2194 * DeleteMonitorA [WINSPOOL.@]
2196 * See DeleteMonitorW.
2199 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2201 LPWSTR nameW
= NULL
;
2202 LPWSTR EnvironmentW
= NULL
;
2203 LPWSTR MonitorNameW
= NULL
;
2208 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2209 nameW
= malloc(len
* sizeof(WCHAR
));
2210 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2214 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2215 EnvironmentW
= malloc(len
* sizeof(WCHAR
));
2216 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2219 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2220 MonitorNameW
= malloc(len
* sizeof(WCHAR
));
2221 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2224 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2232 /******************************************************************
2233 * DeleteMonitorW [WINSPOOL.@]
2235 * Delete a specific Printmonitor from a Printing-Environment
2238 * pName [I] Servername or NULL (local Computer)
2239 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2240 * pMonitorName [I] Name of the Monitor, that should be deleted
2247 * pEnvironment is ignored in Windows for the local Computer.
2250 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2253 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2254 debugstr_w(pMonitorName
));
2256 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2258 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2262 /******************************************************************
2263 * DeletePortA [WINSPOOL.@]
2268 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2270 LPWSTR nameW
= NULL
;
2271 LPWSTR portW
= NULL
;
2275 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2277 /* convert servername to unicode */
2279 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2280 nameW
= malloc(len
* sizeof(WCHAR
));
2281 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2284 /* convert portname to unicode */
2286 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2287 portW
= malloc(len
* sizeof(WCHAR
));
2288 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2291 res
= DeletePortW(nameW
, hWnd
, portW
);
2297 /******************************************************************
2298 * DeletePortW [WINSPOOL.@]
2300 * Delete a specific Port
2303 * pName [I] Servername or NULL (local Computer)
2304 * hWnd [I] Handle to parent Window for the Dialog-Box
2305 * pPortName [I] Name of the Port, that should be deleted
2312 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2314 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2316 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2319 SetLastError(RPC_X_NULL_REF_POINTER
);
2323 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2326 /******************************************************************************
2327 * WritePrinter [WINSPOOL.@]
2329 BOOL WINAPI
WritePrinter(HANDLE printer
, void *buf
, DWORD size
, DWORD
*written
)
2331 HANDLE handle
= get_backend_handle(printer
);
2333 TRACE("(%p, %p, %ld, %p)\n", printer
, buf
, size
, written
);
2337 SetLastError(ERROR_INVALID_HANDLE
);
2341 return backend
->fpWritePrinter(handle
, buf
, size
, written
);
2344 /*****************************************************************************
2345 * AddFormA [WINSPOOL.@]
2347 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2349 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
2353 /*****************************************************************************
2354 * AddFormW [WINSPOOL.@]
2356 BOOL WINAPI
AddFormW( HANDLE printer
, DWORD level
, BYTE
*form
)
2358 HANDLE handle
= get_backend_handle( printer
);
2360 TRACE( "(%p, %ld, %p)\n", printer
, level
, form
);
2364 SetLastError( ERROR_INVALID_HANDLE
);
2368 return backend
->fpAddForm( handle
, level
, form
);
2371 /*****************************************************************************
2372 * AddJobA [WINSPOOL.@]
2374 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2377 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2381 SetLastError(ERROR_INVALID_LEVEL
);
2385 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2388 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2389 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2390 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2391 if(*pcbNeeded
> cbBuf
) {
2392 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2395 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2396 addjobA
->JobId
= addjobW
->JobId
;
2397 addjobA
->Path
= (char *)(addjobA
+ 1);
2398 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2404 /*****************************************************************************
2405 * AddJobW [WINSPOOL.@]
2407 BOOL WINAPI
AddJobW(HANDLE printer
, DWORD level
, LPBYTE data
, DWORD size
, DWORD
*needed
)
2409 HANDLE handle
= get_backend_handle(printer
);
2411 TRACE("(%p, %ld, %p, %ld, %p)\n", printer
, level
, data
, size
, needed
);
2415 SetLastError(ERROR_INVALID_HANDLE
);
2419 return backend
->fpAddJob(handle
, level
, data
, size
, needed
);
2422 /*****************************************************************************
2423 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2425 * Return the PATH for the Print-Processors
2427 * See GetPrintProcessorDirectoryW.
2431 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2432 DWORD level
, LPBYTE Info
,
2433 DWORD cbBuf
, LPDWORD pcbNeeded
)
2435 LPWSTR serverW
= NULL
;
2440 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server
),
2441 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2445 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2446 serverW
= malloc(len
* sizeof(WCHAR
));
2447 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2451 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2452 envW
= malloc(len
* sizeof(WCHAR
));
2453 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2456 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2457 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2459 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2462 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2463 cbBuf
, NULL
, NULL
) > 0;
2466 TRACE(" required: 0x%lx/%ld\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2472 /*****************************************************************************
2473 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2475 * Return the PATH for the Print-Processors
2478 * server [I] Servername (NT only) or NULL (local Computer)
2479 * env [I] Printing-Environment (see below) or NULL (Default)
2480 * level [I] Structure-Level (must be 1)
2481 * Info [O] PTR to Buffer that receives the Result
2482 * cbBuf [I] Size of Buffer at "Info"
2483 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2484 * required for the Buffer at "Info"
2487 * Success: TRUE and in pcbNeeded the Bytes used in Info
2488 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2489 * if cbBuf is too small
2491 * Native Values returned in Info on Success:
2492 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2493 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2494 *| win9x(Windows 4.0): "%winsysdir%"
2496 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2499 * Only NULL or "" is supported for server
2502 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2503 DWORD level
, LPBYTE Info
,
2504 DWORD cbBuf
, LPDWORD pcbNeeded
)
2507 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2508 Info
, cbBuf
, pcbNeeded
);
2510 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2513 /* (Level != 1) is ignored in win9x */
2514 SetLastError(ERROR_INVALID_LEVEL
);
2518 if (pcbNeeded
== NULL
) {
2519 /* (pcbNeeded == NULL) is ignored in win9x */
2520 SetLastError(RPC_X_NULL_REF_POINTER
);
2524 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2527 /*****************************************************************************
2528 * set_devices_and_printerports [internal]
2530 * set the [Devices] and [PrinterPorts] entries for a printer.
2533 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
2535 DWORD portlen
= wcslen( pi
->pPortName
) * sizeof(WCHAR
);
2539 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
2541 /* FIXME: the driver must change to "winspool" */
2542 devline
= malloc( sizeof(L
"wineps.drv") + portlen
+ sizeof(L
",15,45") );
2545 wcscpy( devline
, L
"wineps.drv," );
2546 wcscat( devline
, pi
->pPortName
);
2548 TRACE("using %s\n", debugstr_w(devline
));
2549 if (!create_printers_reg_key( user_printers_key
, &key
))
2551 RegSetValueExW( key
, pi
->pPrinterName
, 0, REG_SZ
, (BYTE
*)devline
,
2552 (wcslen( devline
) + 1) * sizeof(WCHAR
) );
2556 wcscat( devline
, L
",15,45" );
2557 if (!create_printers_reg_key( user_ports_key
, &key
))
2559 RegSetValueExW( key
, pi
->pPrinterName
, 0, REG_SZ
, (BYTE
*)devline
,
2560 (wcslen( devline
) + 1) * sizeof(WCHAR
) );
2567 static BOOL
validate_print_proc(WCHAR
*server
, const WCHAR
*name
)
2569 PRINTPROCESSOR_INFO_1W
*ppi
;
2572 if (!EnumPrintProcessorsW(server
, NULL
, 1, NULL
, 0, &size
, &no
)
2573 && GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
2580 SetLastError(ERROR_OUTOFMEMORY
);
2583 if (!EnumPrintProcessorsW(server
, NULL
, 1, (BYTE
*)ppi
, size
, &size
, &no
))
2589 for (i
= 0; i
< no
; i
++)
2591 if (!wcsicmp(ppi
[i
].pName
, name
))
2598 /*****************************************************************************
2599 * AddPrinterW [WINSPOOL.@]
2601 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2603 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2606 HKEY printer_key
, printers_key
, hkeyDriver
, hkeyDrivers
;
2609 TRACE("(%s,%ld,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2611 if(pName
&& *pName
) {
2612 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2613 SetLastError(ERROR_INVALID_PARAMETER
);
2617 ERR("Level = %ld, unsupported!\n", Level
);
2618 SetLastError(ERROR_INVALID_LEVEL
);
2622 SetLastError(ERROR_INVALID_PARAMETER
);
2625 if (create_printers_reg_key( system_printers_key
, &printers_key
))
2627 ERR("Can't create Printers key\n");
2630 if (!RegOpenKeyW( printers_key
, pi
->pPrinterName
, &printer_key
))
2632 if (!RegQueryValueW( printer_key
, L
"Attributes", NULL
, NULL
))
2634 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2635 RegCloseKey( printer_key
);
2636 RegCloseKey( printers_key
);
2639 RegCloseKey( printer_key
);
2641 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
2643 ERR("Can't create Drivers key\n");
2644 RegCloseKey( printers_key
);
2647 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2649 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2650 RegCloseKey( printers_key
);
2651 RegCloseKey(hkeyDrivers
);
2652 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2655 RegCloseKey(hkeyDriver
);
2656 RegCloseKey(hkeyDrivers
);
2658 if (!validate_print_proc(pName
, pi
->pPrintProcessor
))
2660 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2661 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2662 RegCloseKey( printers_key
);
2666 if (RegCreateKeyW( printers_key
, pi
->pPrinterName
, &printer_key
))
2668 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2669 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2670 RegCloseKey( printers_key
);
2674 set_devices_and_printerports(pi
);
2676 set_reg_DWORD( printer_key
, L
"Attributes", pi
->Attributes
);
2677 set_reg_szW( printer_key
, L
"Datatype", pi
->pDatatype
);
2678 set_reg_DWORD( printer_key
, L
"Default Priority", pi
->DefaultPriority
);
2679 set_reg_szW( printer_key
, L
"Description", pi
->pComment
);
2680 set_reg_DWORD( printer_key
, L
"dnsTimeout", 0 );
2681 set_reg_szW( printer_key
, L
"Location", pi
->pLocation
);
2682 set_reg_szW( printer_key
, L
"Name", pi
->pPrinterName
);
2683 set_reg_szW( printer_key
, L
"Parameters", pi
->pParameters
);
2684 set_reg_szW( printer_key
, L
"Port", pi
->pPortName
);
2685 set_reg_szW( printer_key
, L
"Print Processor", pi
->pPrintProcessor
);
2686 set_reg_szW( printer_key
, L
"Printer Driver", pi
->pDriverName
);
2687 set_reg_DWORD( printer_key
, L
"Priority", pi
->Priority
);
2688 set_reg_szW( printer_key
, L
"Separator File", pi
->pSepFile
);
2689 set_reg_szW( printer_key
, L
"Share Name", pi
->pShareName
);
2690 set_reg_DWORD( printer_key
, L
"StartTime", pi
->StartTime
);
2691 set_reg_DWORD( printer_key
, L
"Status", pi
->Status
);
2692 set_reg_DWORD( printer_key
, L
"txTimeout", 0 );
2693 set_reg_DWORD( printer_key
, L
"UntilTime", pi
->UntilTime
);
2695 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2699 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2700 size
= sizeof(DEVMODEW
);
2706 dm
= calloc( 1, size
);
2708 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
2710 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2716 unsigned int len
= min( ARRAY_SIZE( dm
->dmDeviceName
) - 1, wcslen( pi
->pPrinterName
) );
2717 memcpy( dm
->dmDeviceName
, pi
->pPrinterName
, len
* sizeof(WCHAR
) );
2718 dm
->dmDeviceName
[len
] = '\0';
2722 set_reg_devmode( printer_key
, L
"Default DevMode", dm
);
2723 if (!pi
->pDevMode
) free( dm
);
2725 RegCloseKey( printer_key
);
2726 RegCloseKey( printers_key
);
2727 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2728 ERR("OpenPrinter failing\n");
2734 /*****************************************************************************
2735 * AddPrinterA [WINSPOOL.@]
2737 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2739 UNICODE_STRING pNameW
;
2741 PRINTER_INFO_2W
*piW
;
2742 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2745 TRACE("(%s, %ld, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
2747 ERR("Level = %ld, unsupported!\n", Level
);
2748 SetLastError(ERROR_INVALID_LEVEL
);
2751 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2752 piW
= printer_info_AtoW( piA
, Level
);
2754 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2756 free_printer_info( piW
, Level
);
2757 RtlFreeUnicodeString(&pNameW
);
2762 /*****************************************************************************
2763 * ClosePrinter [WINSPOOL.@]
2765 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2767 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2768 opened_printer_t
*printer
= NULL
;
2770 TRACE("(%p)\n", hPrinter
);
2772 EnterCriticalSection(&printer_handles_cs
);
2774 if ((i
> 0) && (i
<= nb_printer_handles
))
2775 printer
= printer_handles
[i
- 1];
2780 TRACE("closing %s\n", debugstr_w(printer
->name
));
2781 if (printer
->backend_printer
) {
2782 backend
->fpClosePrinter(printer
->backend_printer
);
2785 free_printer_entry( printer
);
2786 printer_handles
[i
- 1] = NULL
;
2787 LeaveCriticalSection(&printer_handles_cs
);
2791 LeaveCriticalSection(&printer_handles_cs
);
2792 SetLastError(ERROR_INVALID_HANDLE
);
2796 /*****************************************************************************
2797 * DeleteFormA [WINSPOOL.@]
2799 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2801 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2805 /*****************************************************************************
2806 * DeleteFormW [WINSPOOL.@]
2808 BOOL WINAPI
DeleteFormW( HANDLE printer
, WCHAR
*name
)
2810 HANDLE handle
= get_backend_handle( printer
);
2812 TRACE( "(%p, %s)\n", printer
, debugstr_w( name
) );
2816 SetLastError( ERROR_INVALID_HANDLE
);
2820 return backend
->fpDeleteForm( handle
, name
);
2823 /*****************************************************************************
2824 * DeletePrinter [WINSPOOL.@]
2826 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2828 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2829 config_module_t
*config_module
;
2831 WCHAR def
[MAX_PATH
];
2832 DWORD size
= ARRAY_SIZE(def
);
2835 SetLastError(ERROR_INVALID_HANDLE
);
2839 EnterCriticalSection(&config_modules_cs
);
2840 if ((config_module
= get_config_module(lpNameW
, FALSE
))) {
2841 wine_rb_remove(&config_modules
, &config_module
->entry
);
2842 release_config_module(config_module
);
2844 LeaveCriticalSection(&config_modules_cs
);
2846 if (!create_printers_reg_key( system_printers_key
, &key
))
2848 RegDeleteTreeW( key
, lpNameW
);
2852 if (!create_printers_reg_key( user_printers_key
, &key
))
2854 RegDeleteValueW( key
, lpNameW
);
2858 if (!create_printers_reg_key( user_ports_key
, &key
))
2860 RegDeleteValueW( key
, lpNameW
);
2864 if (GetDefaultPrinterW( def
, &size
) && !wcscmp( def
, lpNameW
))
2866 if (!create_printers_reg_key( user_default_key
, &key
))
2868 RegDeleteValueW( key
, L
"device" );
2871 SetDefaultPrinterW( NULL
);
2877 /*****************************************************************************
2878 * SetPrinterA [WINSPOOL.@]
2880 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
2887 dataW
= printer_info_AtoW( data
, level
);
2888 if (!dataW
) return FALSE
;
2891 ret
= SetPrinterW( printer
, level
, dataW
, command
);
2893 if (dataW
!= data
) free_printer_info( dataW
, level
);
2898 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
2900 set_reg_szW( key
, L
"Name", pi
->pPrinterName
);
2901 set_reg_szW( key
, L
"Share Name", pi
->pShareName
);
2902 set_reg_szW( key
, L
"Port", pi
->pPortName
);
2903 set_reg_szW( key
, L
"Printer Driver", pi
->pDriverName
);
2904 set_reg_szW( key
, L
"Description", pi
->pComment
);
2905 set_reg_szW( key
, L
"Location", pi
->pLocation
);
2908 set_reg_devmode( key
, L
"Default DevMode", pi
->pDevMode
);
2910 set_reg_szW( key
, L
"Separator File", pi
->pSepFile
);
2911 set_reg_szW( key
, L
"Print Processor", pi
->pPrintProcessor
);
2912 set_reg_szW( key
, L
"Datatype", pi
->pDatatype
);
2913 set_reg_szW( key
, L
"Parameters", pi
->pParameters
);
2915 set_reg_DWORD( key
, L
"Attributes", pi
->Attributes
);
2916 set_reg_DWORD( key
, L
"Priority", pi
->Priority
);
2917 set_reg_DWORD( key
, L
"Default Priority", pi
->DefaultPriority
);
2918 set_reg_DWORD( key
, L
"StartTime", pi
->StartTime
);
2919 set_reg_DWORD( key
, L
"UntilTime", pi
->UntilTime
);
2922 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
2924 if (!pi
->pDevMode
) return FALSE
;
2926 set_reg_devmode( key
, L
"Default DevMode", pi
->pDevMode
);
2930 /******************************************************************************
2931 * SetPrinterW [WINSPOOL.@]
2933 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
2938 TRACE( "(%p, %ld, %p, %ld)\n", printer
, level
, data
, command
);
2940 if (command
!= 0) FIXME( "Ignoring command %ld\n", command
);
2942 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
2949 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
2950 set_printer_2( key
, pi2
);
2956 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
2957 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
2961 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
2962 ret
= set_printer_9( key
, pi
);
2967 FIXME( "Unimplemented level %ld\n", level
);
2968 SetLastError( ERROR_INVALID_LEVEL
);
2975 /*****************************************************************************
2976 * SetJobA [WINSPOOL.@]
2978 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2979 LPBYTE pJob
, DWORD Command
)
2983 UNICODE_STRING usBuffer
;
2985 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2987 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2988 are all ignored by SetJob, so we don't bother copying them */
2996 JOB_INFO_1W
*info1W
= malloc(sizeof(*info1W
));
2997 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3000 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3001 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3002 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3003 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3004 info1W
->Status
= info1A
->Status
;
3005 info1W
->Priority
= info1A
->Priority
;
3006 info1W
->Position
= info1A
->Position
;
3007 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3012 JOB_INFO_2W
*info2W
= malloc(sizeof(*info2W
));
3013 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3016 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3017 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3018 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3019 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3020 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3021 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3022 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3023 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3024 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3025 info2W
->Status
= info2A
->Status
;
3026 info2W
->Priority
= info2A
->Priority
;
3027 info2W
->Position
= info2A
->Position
;
3028 info2W
->StartTime
= info2A
->StartTime
;
3029 info2W
->UntilTime
= info2A
->UntilTime
;
3030 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3034 JobW
= malloc(sizeof(JOB_INFO_3
));
3035 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3038 SetLastError(ERROR_INVALID_LEVEL
);
3042 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3048 JOB_INFO_1W
*info1W
= JobW
;
3049 free(info1W
->pUserName
);
3050 free(info1W
->pDocument
);
3051 free(info1W
->pDatatype
);
3052 free(info1W
->pStatus
);
3057 JOB_INFO_2W
*info2W
= JobW
;
3058 free(info2W
->pUserName
);
3059 free(info2W
->pDocument
);
3060 free(info2W
->pNotifyName
);
3061 free(info2W
->pDatatype
);
3062 free(info2W
->pPrintProcessor
);
3063 free(info2W
->pParameters
);
3064 heap_free(info2W
->pDevMode
);
3065 free(info2W
->pStatus
);
3074 /*****************************************************************************
3075 * SetJobW [WINSPOOL.@]
3077 BOOL WINAPI
SetJobW(HANDLE printer
, DWORD job_id
, DWORD level
,
3078 LPBYTE data
, DWORD command
)
3080 HANDLE handle
= get_backend_handle(printer
);
3082 TRACE("(%p, %ld, %ld, %p, %ld)\n", printer
, job_id
, level
, data
, command
);
3086 SetLastError(ERROR_INVALID_HANDLE
);
3090 return backend
->fpSetJob(handle
, job_id
, level
, data
, command
);
3093 /*****************************************************************************
3094 * EndDocPrinter [WINSPOOL.@]
3096 BOOL WINAPI
EndDocPrinter(HANDLE printer
)
3098 HANDLE handle
= get_backend_handle(printer
);
3100 TRACE("(%p)\n", printer
);
3104 SetLastError(ERROR_INVALID_HANDLE
);
3108 return backend
->fpEndDocPrinter(handle
);
3111 /*****************************************************************************
3112 * EndPagePrinter [WINSPOOL.@]
3114 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3116 FIXME("(%p): stub\n", hPrinter
);
3120 /*****************************************************************************
3121 * StartDocPrinterA [WINSPOOL.@]
3123 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3125 UNICODE_STRING usBuffer
;
3127 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3130 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3131 or one (DOC_INFO_3) extra DWORDs */
3135 doc2W
.JobId
= doc2
->JobId
;
3138 doc2W
.dwMode
= doc2
->dwMode
;
3141 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3142 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3143 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3147 SetLastError(ERROR_INVALID_LEVEL
);
3151 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3153 free(doc2W
.pDatatype
);
3154 free(doc2W
.pOutputFile
);
3155 free(doc2W
.pDocName
);
3160 /*****************************************************************************
3161 * StartDocPrinterW [WINSPOOL.@]
3163 DWORD WINAPI
StartDocPrinterW(HANDLE printer
, DWORD level
, BYTE
*doc_info
)
3165 HANDLE handle
= get_backend_handle(printer
);
3166 DOC_INFO_1W
*info
= (DOC_INFO_1W
*)doc_info
;
3168 TRACE("(%p, %ld, %p {%s, %s, %s})\n", printer
, level
, doc_info
,
3169 debugstr_w(info
->pDocName
), debugstr_w(info
->pOutputFile
),
3170 debugstr_w(info
->pDatatype
));
3174 SetLastError(ERROR_INVALID_HANDLE
);
3178 return backend
->fpStartDocPrinter(handle
, level
, doc_info
);
3181 /*****************************************************************************
3182 * StartPagePrinter [WINSPOOL.@]
3184 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3186 FIXME("(%p): stub\n", hPrinter
);
3190 /*****************************************************************************
3191 * GetFormA [WINSPOOL.@]
3193 BOOL WINAPI
GetFormA( HANDLE printer
, char *name
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
)
3195 UNICODE_STRING nameW
;
3196 const DWORD
*string_info
= form_string_info( level
);
3199 if (!string_info
) return FALSE
;
3201 asciitounicode( &nameW
, name
);
3203 ret
= GetFormW( printer
, nameW
.Buffer
, level
, form
, size
, needed
);
3204 if (ret
) packed_struct_WtoA( form
, string_info
);
3206 RtlFreeUnicodeString( &nameW
);
3210 /*****************************************************************************
3211 * GetFormW [WINSPOOL.@]
3213 BOOL WINAPI
GetFormW( HANDLE printer
, WCHAR
*name
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
)
3215 HANDLE handle
= get_backend_handle( printer
);
3217 TRACE( "(%p, %s, %ld, %p, %ld, %p)\n", printer
, debugstr_w( name
), level
, form
, size
, needed
);
3221 SetLastError( ERROR_INVALID_HANDLE
);
3225 return backend
->fpGetForm( handle
, name
, level
, form
, size
, needed
);
3228 /*****************************************************************************
3229 * SetFormA [WINSPOOL.@]
3231 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3234 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3238 /*****************************************************************************
3239 * SetFormW [WINSPOOL.@]
3241 BOOL WINAPI
SetFormW( HANDLE printer
, WCHAR
*name
, DWORD level
, BYTE
*form
)
3243 HANDLE handle
= get_backend_handle( printer
);
3245 TRACE( "(%p, %s, %ld, %p)\n", printer
, debugstr_w( name
), level
, form
);
3249 SetLastError( ERROR_INVALID_HANDLE
);
3253 return backend
->fpSetForm( handle
, name
, level
, form
);
3256 /*****************************************************************************
3257 * ReadPrinter [WINSPOOL.@]
3259 BOOL WINAPI
ReadPrinter(HANDLE printer
, void *buf
, DWORD size
, DWORD
*bytes_read
)
3261 HANDLE handle
= get_backend_handle(printer
);
3263 TRACE("(%p,%p,%ld,%p)\n", printer
, buf
, size
, bytes_read
);
3267 SetLastError( ERROR_INVALID_HANDLE
);
3271 return backend
->fpReadPrinter(handle
, buf
, size
, bytes_read
);
3274 /*****************************************************************************
3275 * ResetPrinterA [WINSPOOL.@]
3277 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3279 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3283 /*****************************************************************************
3284 * ResetPrinterW [WINSPOOL.@]
3286 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3288 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3292 /*****************************************************************************
3293 * get_filename_from_reg [internal]
3295 * Get ValueName from hkey storing result in out
3296 * when the Value in the registry has only a filename, use driverdir as prefix
3297 * outlen is space left in out
3298 * String is stored either as unicode or ansi
3302 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3303 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3305 WCHAR filename
[MAX_PATH
];
3309 LPWSTR buffer
= filename
;
3313 size
= sizeof(filename
);
3315 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3316 if (ret
== ERROR_MORE_DATA
) {
3317 TRACE("need dynamic buffer: %lu\n", size
);
3318 buffer
= malloc(size
);
3320 /* No Memory is bad */
3324 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3327 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3328 if (buffer
!= filename
) free(buffer
);
3334 /* do we have a full path ? */
3335 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3336 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3339 /* we must build the full Path */
3341 if ((out
) && (outlen
> dirlen
)) {
3342 wcscpy( (WCHAR
*)out
, driverdir
);
3350 /* write the filename */
3351 size
= (wcslen( ptr
) + 1) * sizeof(WCHAR
);
3352 if ((out
) && (outlen
>= size
)) {
3353 wcscpy( (WCHAR
*)out
, ptr
);
3360 ptr
+= wcslen( ptr
) + 1;
3361 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3364 if (buffer
!= filename
) free(buffer
);
3366 /* write the multisz-termination */
3367 if (type
== REG_MULTI_SZ
) {
3368 size
= sizeof(WCHAR
);
3371 if (out
&& (outlen
>= size
)) {
3372 memset (out
, 0, size
);
3378 /*****************************************************************************
3379 * WINSPOOL_GetStringFromReg
3381 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3382 * String is stored as unicode.
3384 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3385 DWORD buflen
, DWORD
*needed
)
3387 DWORD sz
= buflen
, type
;
3390 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3391 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3392 WARN("Got ret = %ld\n", ret
);
3396 /* add space for terminating '\0' */
3397 sz
+= sizeof(WCHAR
);
3401 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3406 /*****************************************************************************
3407 * WINSPOOL_GetDefaultDevMode
3409 * Get a default DevMode values for wineps.
3411 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr
, DWORD buflen
, DWORD
*needed
)
3413 if (buflen
>= sizeof(DEVMODEW
))
3415 DEVMODEW
*dm
= (DEVMODEW
*)ptr
;
3417 /* the driver will update registry with real values */
3418 memset(dm
, 0, sizeof(*dm
));
3419 dm
->dmSize
= sizeof(*dm
);
3420 wcscpy( dm
->dmDeviceName
, L
"wineps.drv" );
3422 *needed
= sizeof(DEVMODEW
);
3425 /*****************************************************************************
3426 * WINSPOOL_GetDevModeFromReg
3428 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3429 * DevMode is stored either as unicode or ansi.
3431 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3433 DWORD buflen
, DWORD
*needed
)
3435 DWORD sz
= buflen
, type
;
3438 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3439 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3440 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3441 if (sz
< sizeof(DEVMODEA
))
3443 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName
),sz
);
3446 /* ensures that dmSize is not erratically bogus if registry is invalid */
3447 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3448 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3449 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3450 if (ptr
&& (buflen
>= sz
)) {
3451 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3452 memcpy(ptr
, dmW
, sz
);
3459 /*********************************************************************
3460 * WINSPOOL_GetPrinter_1
3462 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3464 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3465 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3467 DWORD size
, left
= cbBuf
;
3468 BOOL space
= (cbBuf
> 0);
3473 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Name", ptr
, left
, &size
))
3475 if(space
&& size
<= left
) {
3476 pi1
->pName
= (LPWSTR
)ptr
;
3484 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3485 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Name", ptr
, left
, &size
))
3487 if(space
&& size
<= left
) {
3488 pi1
->pDescription
= (LPWSTR
)ptr
;
3496 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Description", ptr
, left
, &size
))
3498 if(space
&& size
<= left
) {
3499 pi1
->pComment
= (LPWSTR
)ptr
;
3507 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3509 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3510 memset(pi1
, 0, sizeof(*pi1
));
3514 /*********************************************************************
3515 * WINSPOOL_GetPrinter_2
3517 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3519 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3520 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3522 DWORD size
, left
= cbBuf
;
3523 BOOL space
= (cbBuf
> 0);
3528 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Name", ptr
, left
, &size
))
3530 if(space
&& size
<= left
) {
3531 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3538 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Share Name", ptr
, left
, &size
))
3540 if(space
&& size
<= left
) {
3541 pi2
->pShareName
= (LPWSTR
)ptr
;
3548 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Port", ptr
, left
, &size
))
3550 if(space
&& size
<= left
) {
3551 pi2
->pPortName
= (LPWSTR
)ptr
;
3558 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Printer Driver", ptr
, left
, &size
))
3560 if(space
&& size
<= left
) {
3561 pi2
->pDriverName
= (LPWSTR
)ptr
;
3568 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Description", ptr
, left
, &size
))
3570 if(space
&& size
<= left
) {
3571 pi2
->pComment
= (LPWSTR
)ptr
;
3578 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Location", ptr
, left
, &size
))
3580 if(space
&& size
<= left
) {
3581 pi2
->pLocation
= (LPWSTR
)ptr
;
3588 if (WINSPOOL_GetDevModeFromReg( hkeyPrinter
, L
"Default DevMode", ptr
, left
, &size
))
3590 if(space
&& size
<= left
) {
3591 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3600 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
3601 if(space
&& size
<= left
) {
3602 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3609 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Separator File", ptr
, left
, &size
))
3611 if(space
&& size
<= left
) {
3612 pi2
->pSepFile
= (LPWSTR
)ptr
;
3619 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Print Processor", ptr
, left
, &size
))
3621 if(space
&& size
<= left
) {
3622 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3629 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Datatype", ptr
, left
, &size
))
3631 if(space
&& size
<= left
) {
3632 pi2
->pDatatype
= (LPWSTR
)ptr
;
3639 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Parameters", ptr
, left
, &size
))
3641 if(space
&& size
<= left
) {
3642 pi2
->pParameters
= (LPWSTR
)ptr
;
3651 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, L
"Attributes" );
3652 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, L
"Priority" );
3653 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, L
"Default Priority" );
3654 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, L
"StartTime" );
3655 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, L
"UntilTime" );
3658 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3659 memset(pi2
, 0, sizeof(*pi2
));
3664 /*********************************************************************
3665 * WINSPOOL_GetPrinter_4
3667 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3669 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3670 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3672 DWORD size
, left
= cbBuf
;
3673 BOOL space
= (cbBuf
> 0);
3678 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Name", ptr
, left
, &size
))
3680 if(space
&& size
<= left
) {
3681 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3689 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, L
"Attributes" );
3692 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3693 memset(pi4
, 0, sizeof(*pi4
));
3698 /*********************************************************************
3699 * WINSPOOL_GetPrinter_5
3701 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3703 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3704 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3706 DWORD size
, left
= cbBuf
;
3707 BOOL space
= (cbBuf
> 0);
3712 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Name", ptr
, left
, &size
))
3714 if(space
&& size
<= left
) {
3715 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3722 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Port", ptr
, left
, &size
))
3724 if(space
&& size
<= left
) {
3725 pi5
->pPortName
= (LPWSTR
)ptr
;
3733 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, L
"Attributes" );
3734 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, L
"dnsTimeout" );
3735 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, L
"txTimeout" );
3738 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3739 memset(pi5
, 0, sizeof(*pi5
));
3744 /*********************************************************************
3745 * WINSPOOL_GetPrinter_7
3747 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3749 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3750 DWORD cbBuf
, LPDWORD pcbNeeded
)
3752 DWORD size
, left
= cbBuf
;
3753 BOOL space
= (cbBuf
> 0);
3758 if (!WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"ObjectGUID", ptr
, left
, &size
))
3761 size
= sizeof(pi7
->pszObjectGUID
);
3763 if (space
&& size
<= left
) {
3764 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3771 /* We do not have a Directory Service */
3772 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3775 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3776 memset(pi7
, 0, sizeof(*pi7
));
3781 /*********************************************************************
3782 * WINSPOOL_GetPrinter_9
3784 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3786 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3787 DWORD cbBuf
, LPDWORD pcbNeeded
)
3790 BOOL space
= (cbBuf
> 0);
3794 if (WINSPOOL_GetDevModeFromReg( hkeyPrinter
, L
"Default DevMode", buf
, cbBuf
, &size
))
3796 if(space
&& size
<= cbBuf
) {
3797 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3804 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
3805 if(space
&& size
<= cbBuf
) {
3806 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3812 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3813 memset(pi9
, 0, sizeof(*pi9
));
3818 /*****************************************************************************
3819 * GetPrinterW [WINSPOOL.@]
3821 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3822 DWORD cbBuf
, LPDWORD pcbNeeded
)
3824 DWORD size
, needed
= 0, err
;
3829 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3831 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
3834 SetLastError( err
);
3841 PRINTER_INFO_1W
*pi1
= (PRINTER_INFO_1W
*)pPrinter
;
3843 size
= sizeof(PRINTER_INFO_1W
);
3844 if (size
<= cbBuf
) {
3845 ptr
= pPrinter
+ size
;
3847 memset(pPrinter
, 0, size
);
3852 ret
= WINSPOOL_GetPrinter_1(hkeyPrinter
, pi1
, ptr
, cbBuf
, &needed
);
3859 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3861 size
= sizeof(PRINTER_INFO_2W
);
3863 ptr
= pPrinter
+ size
;
3865 memset(pPrinter
, 0, size
);
3870 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
3877 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3879 size
= sizeof(PRINTER_INFO_4W
);
3881 ptr
= pPrinter
+ size
;
3883 memset(pPrinter
, 0, size
);
3888 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
3896 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3898 size
= sizeof(PRINTER_INFO_5W
);
3900 ptr
= pPrinter
+ size
;
3902 memset(pPrinter
, 0, size
);
3908 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
3916 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
3918 size
= sizeof(PRINTER_INFO_6
);
3919 if (size
<= cbBuf
) {
3920 /* FIXME: We do not update the status yet */
3921 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, L
"Status" );
3933 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
3935 size
= sizeof(PRINTER_INFO_7W
);
3936 if (size
<= cbBuf
) {
3937 ptr
= pPrinter
+ size
;
3939 memset(pPrinter
, 0, size
);
3945 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
3952 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
3953 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3957 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
3959 size
= sizeof(PRINTER_INFO_9W
);
3961 ptr
= pPrinter
+ size
;
3963 memset(pPrinter
, 0, size
);
3969 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
3976 FIXME("Unimplemented level %ld\n", Level
);
3977 SetLastError(ERROR_INVALID_LEVEL
);
3978 RegCloseKey(hkeyPrinter
);
3982 RegCloseKey(hkeyPrinter
);
3984 TRACE("returning %d needed = %ld\n", ret
, needed
);
3985 if(pcbNeeded
) *pcbNeeded
= needed
;
3987 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3991 /*****************************************************************************
3992 * GetPrinterA [WINSPOOL.@]
3994 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3995 DWORD cbBuf
, LPDWORD pcbNeeded
)
4001 buf
= malloc(cbBuf
);
4003 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4005 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4011 /*****************************************************************************
4012 * WINSPOOL_EnumPrintersW
4014 * Implementation of EnumPrintersW
4016 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4017 DWORD dwLevel
, LPBYTE lpbPrinters
,
4018 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4019 LPDWORD lpdwReturned
)
4022 HKEY printers_key
, hkeyPrinter
;
4023 WCHAR PrinterName
[255];
4024 DWORD needed
= 0, number
= 0;
4025 DWORD used
, i
, left
;
4029 memset(lpbPrinters
, 0, cbBuf
);
4035 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4036 if(dwType
== PRINTER_ENUM_DEFAULT
)
4039 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4040 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4041 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4043 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4049 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4050 FIXME("dwType = %08lx\n", dwType
);
4051 SetLastError(ERROR_INVALID_FLAGS
);
4055 if (create_printers_reg_key( system_printers_key
, &printers_key
))
4057 ERR("Can't create Printers key\n");
4061 if (RegQueryInfoKeyA( printers_key
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
))
4063 RegCloseKey( printers_key
);
4064 ERR("Can't query Printers key\n");
4067 TRACE("Found %ld printers\n", number
);
4071 used
= number
* sizeof(PRINTER_INFO_1W
);
4074 used
= number
* sizeof(PRINTER_INFO_2W
);
4077 used
= number
* sizeof(PRINTER_INFO_4W
);
4080 used
= number
* sizeof(PRINTER_INFO_5W
);
4084 SetLastError(ERROR_INVALID_LEVEL
);
4085 RegCloseKey( printers_key
);
4088 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4090 for(i
= 0; i
< number
; i
++) {
4091 if (RegEnumKeyW( printers_key
, i
, PrinterName
, ARRAY_SIZE(PrinterName
) ))
4093 ERR("Can't enum key number %ld\n", i
);
4094 RegCloseKey( printers_key
);
4097 TRACE("Printer %ld is %s\n", i
, debugstr_w(PrinterName
));
4098 if (RegOpenKeyW( printers_key
, PrinterName
, &hkeyPrinter
))
4100 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4101 RegCloseKey( printers_key
);
4106 buf
= lpbPrinters
+ used
;
4107 left
= cbBuf
- used
;
4115 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4118 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4121 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4124 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4127 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4130 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4133 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4136 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4139 ERR("Shouldn't be here!\n");
4140 RegCloseKey(hkeyPrinter
);
4141 RegCloseKey( printers_key
);
4144 RegCloseKey(hkeyPrinter
);
4146 RegCloseKey( printers_key
);
4153 memset(lpbPrinters
, 0, cbBuf
);
4154 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4158 *lpdwReturned
= number
;
4159 SetLastError(ERROR_SUCCESS
);
4164 /******************************************************************
4165 * EnumPrintersW [WINSPOOL.@]
4167 * Enumerates the available printers, print servers and print
4168 * providers, depending on the specified flags, name and level.
4172 * If level is set to 1:
4173 * Returns an array of PRINTER_INFO_1 data structures in the
4174 * lpbPrinters buffer.
4176 * If level is set to 2:
4177 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4178 * Returns an array of PRINTER_INFO_2 data structures in the
4179 * lpbPrinters buffer. Note that according to MSDN also an
4180 * OpenPrinter should be performed on every remote printer.
4182 * If level is set to 4 (officially WinNT only):
4183 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4184 * Fast: Only the registry is queried to retrieve printer names,
4185 * no connection to the driver is made.
4186 * Returns an array of PRINTER_INFO_4 data structures in the
4187 * lpbPrinters buffer.
4189 * If level is set to 5 (officially WinNT4/Win9x only):
4190 * Fast: Only the registry is queried to retrieve printer names,
4191 * no connection to the driver is made.
4192 * Returns an array of PRINTER_INFO_5 data structures in the
4193 * lpbPrinters buffer.
4195 * If level set to 3 or 6+:
4196 * returns zero (failure!)
4198 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4202 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4203 * - Only levels 2, 4 and 5 are implemented at the moment.
4204 * - 16-bit printer drivers are not enumerated.
4205 * - Returned amount of bytes used/needed does not match the real Windoze
4206 * implementation (as in this implementation, all strings are part
4207 * of the buffer, whereas Win32 keeps them somewhere else)
4208 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4211 * - In a regular Wine installation, no registry settings for printers
4212 * exist, which makes this function return an empty list.
4214 BOOL WINAPI
EnumPrintersW(
4215 DWORD dwType
, /* [in] Types of print objects to enumerate */
4216 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4217 DWORD dwLevel
, /* [in] type of printer info structure */
4218 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4219 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4220 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4221 LPDWORD lpdwReturned
/* [out] number of entries returned */
4224 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4225 lpdwNeeded
, lpdwReturned
);
4228 /******************************************************************
4229 * EnumPrintersA [WINSPOOL.@]
4234 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4235 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4238 UNICODE_STRING pNameU
;
4242 TRACE("(0x%lx, %s, %lu, %p, %ld, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4243 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4245 pNameW
= asciitounicode(&pNameU
, pName
);
4247 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4248 MS Office need this */
4249 pPrintersW
= (pPrinters
&& cbBuf
) ? malloc(cbBuf
) : NULL
;
4251 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4253 RtlFreeUnicodeString(&pNameU
);
4255 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4261 /*****************************************************************************
4262 * WINSPOOL_GetDriverInfoFromReg [internal]
4264 * Enters the information from the registry into the DRIVER_INFO struct
4267 * zero if the printer driver does not exist in the registry
4268 * (only if Level > 1) otherwise nonzero
4270 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4273 const printenv_t
* env
,
4275 LPBYTE ptr
, /* DRIVER_INFO */
4276 LPBYTE pDriverStrings
, /* strings buffer */
4277 DWORD cbBuf
, /* size of string buffer */
4278 LPDWORD pcbNeeded
) /* space needed for str. */
4282 WCHAR driverdir
[MAX_PATH
];
4284 LPBYTE strPtr
= pDriverStrings
;
4285 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4287 TRACE("(%p, %s, %p, %ld, %p, %p, %ld)\n", hkeyDrivers
,
4288 debugstr_w(DriverName
), env
,
4289 Level
, di
, pDriverStrings
, cbBuf
);
4291 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4293 *pcbNeeded
= (wcslen( DriverName
) + 1) * sizeof(WCHAR
);
4294 if (*pcbNeeded
<= cbBuf
)
4295 wcscpy( (WCHAR
*)strPtr
, DriverName
);
4297 /* pName for level 1 has a different offset! */
4299 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4303 /* .cVersion and .pName for level > 1 */
4305 di
->cVersion
= env
->driverversion
;
4306 di
->pName
= (LPWSTR
) strPtr
;
4307 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4310 /* Reserve Space for "\\3\\" + \0 */
4311 size
= sizeof(driverdir
) - 4 * sizeof(WCHAR
);
4312 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4313 /* Should never Fail */
4316 wcscat( driverdir
, env
->versionsubdir
);
4317 wcscat( driverdir
, L
"\\" );
4319 /* dirlen must not include the terminating zero */
4320 dirlen
= wcslen( driverdir
) * sizeof(WCHAR
);
4322 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4323 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4324 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4329 size
= (wcslen( env
->envname
) + 1) * sizeof(WCHAR
);
4332 if (*pcbNeeded
<= cbBuf
) {
4333 wcscpy( (WCHAR
*)strPtr
, env
->envname
);
4334 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4335 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4338 /* .pDriverPath is the Graphics rendering engine.
4339 The full Path is required to avoid a crash in some apps */
4340 if (get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Driver", strPtr
, 0, &size
))
4343 if (*pcbNeeded
<= cbBuf
)
4344 get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Driver", strPtr
, size
, &tmp
);
4346 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4347 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4350 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4351 if (get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Data File", strPtr
, 0, &size
))
4354 if (*pcbNeeded
<= cbBuf
)
4355 get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Data File", strPtr
, size
, &size
);
4357 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4358 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4361 /* .pConfigFile is the Driver user Interface */
4362 if (get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Configuration File", strPtr
, 0, &size
))
4365 if (*pcbNeeded
<= cbBuf
)
4366 get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Configuration File", strPtr
, size
, &size
);
4368 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4369 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4373 RegCloseKey(hkeyDriver
);
4374 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
4379 RegCloseKey(hkeyDriver
);
4380 FIXME("level 5: incomplete\n");
4385 if (get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Help File", strPtr
, 0, &size
))
4388 if (*pcbNeeded
<= cbBuf
)
4389 get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Help File", strPtr
, size
, &size
);
4391 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4392 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4395 /* .pDependentFiles */
4396 if (get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Dependent Files", strPtr
, 0, &size
))
4399 if (*pcbNeeded
<= cbBuf
)
4400 get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Dependent Files", strPtr
, size
, &size
);
4402 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4403 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4405 else if (GetVersion() & 0x80000000) {
4406 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4407 size
= 2 * sizeof(WCHAR
);
4409 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4411 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4412 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4415 /* .pMonitorName is the optional Language Monitor */
4416 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Monitor", strPtr
, 0, &size
))
4419 if (*pcbNeeded
<= cbBuf
)
4420 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Monitor", strPtr
, size
, &size
);
4422 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4423 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4426 /* .pDefaultDataType */
4427 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Datatype", strPtr
, 0, &size
))
4430 if(*pcbNeeded
<= cbBuf
)
4431 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Datatype", strPtr
, size
, &size
);
4433 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4434 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4438 RegCloseKey(hkeyDriver
);
4439 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
4443 /* .pszzPreviousNames */
4444 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Previous Names", strPtr
, 0, &size
))
4447 if(*pcbNeeded
<= cbBuf
)
4448 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Previous Names", strPtr
, size
, &size
);
4450 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4451 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4455 RegCloseKey(hkeyDriver
);
4456 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
4460 /* support is missing, but not important enough for a FIXME */
4461 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4464 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Manufacturer", strPtr
, 0, &size
))
4467 if(*pcbNeeded
<= cbBuf
)
4468 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Manufacturer", strPtr
, size
, &size
);
4470 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4471 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4475 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"OEM Url", strPtr
, 0, &size
))
4478 if(*pcbNeeded
<= cbBuf
)
4479 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"OEM Url", strPtr
, size
, &size
);
4481 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4482 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4485 /* .pszHardwareID */
4486 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"HardwareID", strPtr
, 0, &size
))
4489 if(*pcbNeeded
<= cbBuf
)
4490 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"HardwareID", strPtr
, size
, &size
);
4492 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4493 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4497 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Provider", strPtr
, 0, &size
))
4500 if(*pcbNeeded
<= cbBuf
)
4501 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Provider", strPtr
, size
, &size
);
4503 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4504 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4508 RegCloseKey(hkeyDriver
);
4512 /* support is missing, but not important enough for a FIXME */
4513 TRACE("level 8: incomplete\n");
4515 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
4516 RegCloseKey(hkeyDriver
);
4520 /*****************************************************************************
4521 * GetPrinterDriverW [WINSPOOL.@]
4523 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4524 DWORD Level
, LPBYTE pDriverInfo
,
4525 DWORD cbBuf
, LPDWORD pcbNeeded
)
4528 WCHAR DriverName
[100];
4529 DWORD ret
, type
, size
, needed
= 0;
4531 HKEY hkeyPrinter
, hkeyDrivers
;
4532 const printenv_t
* env
;
4534 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4535 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4538 ZeroMemory(pDriverInfo
, cbBuf
);
4540 if (!(name
= get_opened_printer_name(hPrinter
))) {
4541 SetLastError(ERROR_INVALID_HANDLE
);
4545 if (Level
< 1 || Level
== 7 || Level
> 8) {
4546 SetLastError(ERROR_INVALID_LEVEL
);
4550 env
= validate_envW(pEnvironment
);
4551 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4553 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
4556 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
4557 SetLastError( ret
);
4561 size
= sizeof(DriverName
);
4563 ret
= RegQueryValueExW( hkeyPrinter
, L
"Printer Driver", 0, &type
, (BYTE
*)DriverName
, &size
);
4564 RegCloseKey(hkeyPrinter
);
4565 if(ret
!= ERROR_SUCCESS
) {
4566 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4570 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4572 ERR("Can't create Drivers key\n");
4576 size
= di_sizeof
[Level
];
4577 if ((size
<= cbBuf
) && pDriverInfo
)
4578 ptr
= pDriverInfo
+ size
;
4580 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4581 env
, Level
, pDriverInfo
, ptr
,
4582 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4584 RegCloseKey(hkeyDrivers
);
4588 RegCloseKey(hkeyDrivers
);
4590 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4591 TRACE("buffer space %ld required %ld\n", cbBuf
, size
+ needed
);
4592 if(cbBuf
>= size
+ needed
) return TRUE
;
4593 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4597 /*****************************************************************************
4598 * GetPrinterDriverA [WINSPOOL.@]
4600 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4601 DWORD Level
, LPBYTE pDriverInfo
,
4602 DWORD cbBuf
, LPDWORD pcbNeeded
)
4605 UNICODE_STRING pEnvW
;
4611 ZeroMemory(pDriverInfo
, cbBuf
);
4612 buf
= malloc(cbBuf
);
4615 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4616 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
4619 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
4623 RtlFreeUnicodeString(&pEnvW
);
4627 /*****************************************************************************
4628 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4630 * Return the PATH for the Printer-Drivers (UNICODE)
4633 * pName [I] Servername (NT only) or NULL (local Computer)
4634 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4635 * Level [I] Structure-Level (must be 1)
4636 * pDriverDirectory [O] PTR to Buffer that receives the Result
4637 * cbBuf [I] Size of Buffer at pDriverDirectory
4638 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4639 * required for pDriverDirectory
4642 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4643 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4644 * if cbBuf is too small
4646 * Native Values returned in pDriverDirectory on Success:
4647 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4648 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4649 *| win9x(Windows 4.0): "%winsysdir%"
4651 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4654 *- Only NULL or "" is supported for pName
4657 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4658 DWORD Level
, LPBYTE pDriverDirectory
,
4659 DWORD cbBuf
, LPDWORD pcbNeeded
)
4661 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
),
4662 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4664 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4667 /* (Level != 1) is ignored in win9x */
4668 SetLastError(ERROR_INVALID_LEVEL
);
4671 if (pcbNeeded
== NULL
) {
4672 /* (pcbNeeded == NULL) is ignored in win9x */
4673 SetLastError(RPC_X_NULL_REF_POINTER
);
4677 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4678 pDriverDirectory
, cbBuf
, pcbNeeded
);
4683 /*****************************************************************************
4684 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4686 * Return the PATH for the Printer-Drivers (ANSI)
4688 * See GetPrinterDriverDirectoryW.
4691 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4694 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4695 DWORD Level
, LPBYTE pDriverDirectory
,
4696 DWORD cbBuf
, LPDWORD pcbNeeded
)
4698 UNICODE_STRING nameW
, environmentW
;
4701 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4702 WCHAR
*driverDirectoryW
= NULL
;
4704 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName
),
4705 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4707 if (len
) driverDirectoryW
= malloc( len
);
4709 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4710 else nameW
.Buffer
= NULL
;
4711 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4712 else environmentW
.Buffer
= NULL
;
4714 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4715 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4718 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4719 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4721 *pcbNeeded
= needed
;
4722 ret
= needed
<= cbBuf
;
4724 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4726 TRACE("required: 0x%lx/%ld\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4728 free( driverDirectoryW
);
4729 RtlFreeUnicodeString(&environmentW
);
4730 RtlFreeUnicodeString(&nameW
);
4735 /*****************************************************************************
4736 * AddPrinterDriverA [WINSPOOL.@]
4738 * See AddPrinterDriverW.
4741 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4743 TRACE("(%s, %ld, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4744 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4747 /******************************************************************************
4748 * AddPrinterDriverW (WINSPOOL.@)
4750 * Install a Printer Driver
4753 * pName [I] Servername or NULL (local Computer)
4754 * level [I] Level for the supplied DRIVER_INFO_*W struct
4755 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4762 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4764 TRACE("(%s, %ld, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4765 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4768 /*****************************************************************************
4769 * AddPrintProcessorA [WINSPOOL.@]
4771 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4772 LPSTR pPrintProcessorName
)
4774 UNICODE_STRING NameW
, EnvW
, PathW
, ProcessorW
;
4777 TRACE("(%s,%s,%s,%s)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4778 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4780 asciitounicode(&NameW
, pName
);
4781 asciitounicode(&EnvW
, pEnvironment
);
4782 asciitounicode(&PathW
, pPathName
);
4783 asciitounicode(&ProcessorW
, pPrintProcessorName
);
4785 ret
= AddPrintProcessorW(NameW
.Buffer
, EnvW
.Buffer
, PathW
.Buffer
, ProcessorW
.Buffer
);
4787 RtlFreeUnicodeString(&ProcessorW
);
4788 RtlFreeUnicodeString(&PathW
);
4789 RtlFreeUnicodeString(&EnvW
);
4790 RtlFreeUnicodeString(&NameW
);
4795 /*****************************************************************************
4796 * AddPrintProcessorW [WINSPOOL.@]
4798 BOOL WINAPI
AddPrintProcessorW(WCHAR
*name
, WCHAR
*env
, WCHAR
*path
, WCHAR
*print_proc
)
4800 TRACE("(%s,%s,%s,%s)\n", debugstr_w(name
), debugstr_w(env
),
4801 debugstr_w(path
), debugstr_w(print_proc
));
4803 if (!path
|| !print_proc
)
4805 SetLastError(ERROR_INVALID_PARAMETER
);
4809 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4810 return backend
->fpAddPrintProcessor(name
, env
, path
, print_proc
);
4813 /*****************************************************************************
4814 * AddPrintProvidorA [WINSPOOL.@]
4816 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4818 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4822 /*****************************************************************************
4823 * AddPrintProvidorW [WINSPOOL.@]
4825 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4827 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4831 /*****************************************************************************
4832 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4834 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4835 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4837 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4838 pDevModeOutput
, pDevModeInput
);
4842 /*****************************************************************************
4843 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4845 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4846 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4848 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4849 pDevModeOutput
, pDevModeInput
);
4853 /*****************************************************************************
4854 * PrinterProperties [WINSPOOL.@]
4856 * Displays a dialog to set the properties of the printer.
4859 * nonzero on success or zero on failure
4862 * implemented as stub only
4864 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4865 HANDLE hPrinter
/* [in] handle to printer object */
4867 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4868 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4872 /*****************************************************************************
4873 * EnumJobsA [WINSPOOL.@]
4876 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4877 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4880 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4881 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4883 if(pcbNeeded
) *pcbNeeded
= 0;
4884 if(pcReturned
) *pcReturned
= 0;
4889 /*****************************************************************************
4890 * EnumJobsW [WINSPOOL.@]
4893 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4894 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4897 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4898 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4900 if(pcbNeeded
) *pcbNeeded
= 0;
4901 if(pcReturned
) *pcReturned
= 0;
4905 /*****************************************************************************
4906 * WINSPOOL_EnumPrinterDrivers [internal]
4908 * Delivers information about all printer drivers installed on the
4909 * localhost or a given server
4912 * nonzero on success or zero on failure. If the buffer for the returned
4913 * information is too small the function will return an error
4916 * - only implemented for localhost, foreign hosts will return an error
4918 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4919 DWORD Level
, LPBYTE pDriverInfo
,
4921 DWORD cbBuf
, LPDWORD pcbNeeded
,
4922 LPDWORD pcFound
, DWORD data_offset
)
4926 const printenv_t
* env
;
4928 TRACE("%s,%s,%ld,%p,%ld,%ld,%ld\n",
4929 debugstr_w(pName
), debugstr_w(pEnvironment
),
4930 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
4932 env
= validate_envW(pEnvironment
);
4933 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4937 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4939 ERR("Can't open Drivers key\n");
4943 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
4944 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4945 RegCloseKey(hkeyDrivers
);
4946 ERR("Can't query Drivers key\n");
4949 TRACE("Found %ld Drivers\n", *pcFound
);
4951 /* get size of single struct
4952 * unicode and ascii structure have the same size
4954 size
= di_sizeof
[Level
];
4956 if (data_offset
== 0)
4957 data_offset
= size
* (*pcFound
);
4958 *pcbNeeded
= data_offset
;
4960 for( i
= 0; i
< *pcFound
; i
++) {
4961 WCHAR DriverNameW
[255];
4962 PBYTE table_ptr
= NULL
;
4963 PBYTE data_ptr
= NULL
;
4966 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, ARRAY_SIZE(DriverNameW
)) != ERROR_SUCCESS
) {
4967 ERR("Can't enum key number %ld\n", i
);
4968 RegCloseKey(hkeyDrivers
);
4972 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
4973 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
4974 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
4975 data_ptr
= pDriverInfo
+ *pcbNeeded
;
4977 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4978 env
, Level
, table_ptr
, data_ptr
,
4979 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4981 RegCloseKey(hkeyDrivers
);
4985 *pcbNeeded
+= needed
;
4988 RegCloseKey(hkeyDrivers
);
4990 if(cbBuf
< *pcbNeeded
){
4991 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4998 /*****************************************************************************
4999 * EnumPrinterDriversW [WINSPOOL.@]
5001 * see function EnumPrinterDrivers for RETURNS, BUGS
5003 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5004 LPBYTE pDriverInfo
, DWORD cbBuf
,
5005 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5010 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5012 SetLastError(RPC_X_NULL_REF_POINTER
);
5016 /* check for local drivers */
5017 if((pName
) && (pName
[0])) {
5018 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5019 SetLastError(ERROR_ACCESS_DENIED
);
5023 /* check input parameter */
5024 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5025 SetLastError(ERROR_INVALID_LEVEL
);
5029 if(pDriverInfo
&& cbBuf
> 0)
5030 memset( pDriverInfo
, 0, cbBuf
);
5032 /* Exception: pull all printers */
5033 if (pEnvironment
&& !wcscmp( pEnvironment
, L
"all" ))
5035 DWORD i
, needed
, bufsize
= cbBuf
;
5036 DWORD total_found
= 0;
5039 /* Precompute the overall total; we need this to know
5040 where pointers end and data begins (i.e. data_offset) */
5041 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5044 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5045 NULL
, 0, 0, &needed
, &found
, 0);
5046 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5047 total_found
+= found
;
5050 data_offset
= di_sizeof
[Level
] * total_found
;
5055 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5058 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5059 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5060 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5062 *pcReturned
+= found
;
5063 *pcbNeeded
= needed
;
5064 data_offset
= needed
;
5065 total_found
+= found
;
5070 /* Normal behavior */
5071 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5072 0, cbBuf
, pcbNeeded
, &found
, 0);
5074 *pcReturned
= found
;
5079 /*****************************************************************************
5080 * EnumPrinterDriversA [WINSPOOL.@]
5082 * see function EnumPrinterDrivers for RETURNS, BUGS
5084 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5085 LPBYTE pDriverInfo
, DWORD cbBuf
,
5086 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5089 UNICODE_STRING pNameW
, pEnvironmentW
;
5090 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5094 buf
= malloc(cbBuf
);
5096 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5097 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5099 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5100 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5102 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5106 RtlFreeUnicodeString(&pNameW
);
5107 RtlFreeUnicodeString(&pEnvironmentW
);
5112 /******************************************************************************
5113 * EnumPortsA (WINSPOOL.@)
5118 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5119 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5122 LPBYTE bufferW
= NULL
;
5123 LPWSTR nameW
= NULL
;
5125 DWORD numentries
= 0;
5128 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5129 cbBuf
, pcbNeeded
, pcReturned
);
5131 /* convert servername to unicode */
5133 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5134 nameW
= malloc(len
* sizeof(WCHAR
));
5135 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5137 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5138 needed
= cbBuf
* sizeof(WCHAR
);
5139 if (needed
) bufferW
= malloc(needed
);
5140 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5142 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5143 if (pcbNeeded
) needed
= *pcbNeeded
;
5144 /* HeapReAlloc return NULL, when bufferW was NULL */
5145 bufferW
= (bufferW
) ? realloc(bufferW
, needed
) : malloc(needed
);
5147 /* Try again with the large Buffer */
5148 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5150 needed
= pcbNeeded
? *pcbNeeded
: 0;
5151 numentries
= pcReturned
? *pcReturned
: 0;
5154 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5155 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5158 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5159 DWORD entrysize
= 0;
5162 LPPORT_INFO_2W pi2w
;
5163 LPPORT_INFO_2A pi2a
;
5166 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5168 /* First pass: calculate the size for all Entries */
5169 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5170 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5172 while (index
< numentries
) {
5174 needed
+= entrysize
; /* PORT_INFO_?A */
5175 TRACE("%p: parsing #%ld (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5177 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5178 NULL
, 0, NULL
, NULL
);
5180 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5181 NULL
, 0, NULL
, NULL
);
5182 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5183 NULL
, 0, NULL
, NULL
);
5185 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5186 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5187 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5190 /* check for errors and quit on failure */
5191 if (cbBuf
< needed
) {
5192 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5196 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5197 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5198 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5199 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5200 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5202 /* Second Pass: Fill the User Buffer (if we have one) */
5203 while ((index
< numentries
) && pPorts
) {
5205 TRACE("%p: writing PORT_INFO_%ldA #%ld\n", pi2a
, Level
, index
);
5206 pi2a
->pPortName
= ptr
;
5207 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5208 ptr
, cbBuf
, NULL
, NULL
);
5212 pi2a
->pMonitorName
= ptr
;
5213 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5214 ptr
, cbBuf
, NULL
, NULL
);
5218 pi2a
->pDescription
= ptr
;
5219 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5220 ptr
, cbBuf
, NULL
, NULL
);
5224 pi2a
->fPortType
= pi2w
->fPortType
;
5225 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5228 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5229 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5230 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5235 if (pcbNeeded
) *pcbNeeded
= needed
;
5236 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5241 TRACE("returning %d with %ld (%ld byte for %ld of %ld entries)\n",
5242 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5248 /******************************************************************************
5249 * EnumPortsW (WINSPOOL.@)
5251 * Enumerate available Ports
5254 * pName [I] Servername or NULL (local Computer)
5255 * Level [I] Structure-Level (1 or 2)
5256 * pPorts [O] PTR to Buffer that receives the Result
5257 * cbBuf [I] Size of Buffer at pPorts
5258 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5259 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5263 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5266 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5269 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5270 cbBuf
, pcbNeeded
, pcReturned
);
5272 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5274 /* Level is not checked in win9x */
5275 if (!Level
|| (Level
> 2)) {
5276 WARN("level (%ld) is ignored in win9x\n", Level
);
5277 SetLastError(ERROR_INVALID_LEVEL
);
5280 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5281 SetLastError(RPC_X_NULL_REF_POINTER
);
5285 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5288 /******************************************************************************
5289 * GetDefaultPrinterW (WINSPOOL.@)
5292 * This function must read the value from data 'device' of key
5293 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5295 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5299 WCHAR
*buffer
, *ptr
;
5303 SetLastError(ERROR_INVALID_PARAMETER
);
5307 /* make the buffer big enough for the stuff from the profile/registry,
5308 * the content must fit into the local buffer to compute the correct
5309 * size even if the extern buffer is too small or not given.
5310 * (20 for ,driver,port) */
5312 len
= max(100, (insize
+ 20));
5313 buffer
= malloc( len
* sizeof(WCHAR
));
5315 if (!GetProfileStringW( L
"windows", L
"device", L
"", buffer
, len
))
5317 SetLastError (ERROR_FILE_NOT_FOUND
);
5321 TRACE("%s\n", debugstr_w(buffer
));
5323 if ((ptr
= wcschr( buffer
, ',' )) == NULL
)
5325 SetLastError(ERROR_INVALID_NAME
);
5331 *namesize
= wcslen( buffer
) + 1;
5332 if(!name
|| (*namesize
> insize
))
5334 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5338 wcscpy( name
, buffer
);
5346 /******************************************************************************
5347 * GetDefaultPrinterA (WINSPOOL.@)
5349 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5353 WCHAR
*bufferW
= NULL
;
5357 SetLastError(ERROR_INVALID_PARAMETER
);
5361 if(name
&& *namesize
) {
5363 bufferW
= malloc( insize
* sizeof(WCHAR
));
5366 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5371 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5375 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5378 TRACE("0x%08lx/0x%08lx:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5386 /******************************************************************************
5387 * SetDefaultPrinterW (WINSPOOL.204)
5389 * Set the Name of the Default Printer
5392 * pszPrinter [I] Name of the Printer or NULL
5399 * When the Parameter is NULL or points to an Empty String and
5400 * a Default Printer was already present, then this Function changes nothing.
5401 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5402 * the First enumerated local Printer is used.
5405 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5407 WCHAR default_printer
[MAX_PATH
];
5408 LPWSTR buffer
= NULL
;
5414 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5415 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5417 default_printer
[0] = '\0';
5418 size
= ARRAY_SIZE(default_printer
);
5420 /* if we have a default Printer, do nothing. */
5421 if (GetDefaultPrinterW(default_printer
, &size
))
5425 /* we have no default Printer: search local Printers and use the first */
5426 if (!create_printers_reg_key( system_printers_key
, &hreg
))
5428 default_printer
[0] = '\0';
5429 size
= ARRAY_SIZE(default_printer
);
5430 if (!RegEnumKeyExW( hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
))
5432 pszPrinter
= default_printer
;
5433 TRACE("using %s\n", debugstr_w(pszPrinter
));
5435 RegCloseKey( hreg
);
5438 if (pszPrinter
== NULL
) {
5439 TRACE("no local printer found\n");
5440 SetLastError(ERROR_FILE_NOT_FOUND
);
5445 /* "pszPrinter" is never empty or NULL here. */
5446 namelen
= wcslen( pszPrinter
);
5447 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5448 buffer
= malloc(size
* sizeof(WCHAR
));
5449 if (!buffer
|| create_printers_reg_key( user_printers_key
, &hreg
))
5452 SetLastError(ERROR_FILE_NOT_FOUND
);
5456 /* read the devices entry for the printer (driver,port) to build the string for the
5457 default device entry (printer,driver,port) */
5458 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5459 buffer
[namelen
] = ',';
5460 namelen
++; /* move index to the start of the driver */
5462 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5463 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5467 if (!create_printers_reg_key( user_default_key
, &hdev
))
5469 RegSetValueExW( hdev
, L
"device", 0, REG_SZ
, (BYTE
*)buffer
, (wcslen( buffer
) + 1) * sizeof(WCHAR
) );
5475 if (lres
!= ERROR_FILE_NOT_FOUND
)
5476 FIXME("RegQueryValueExW failed with %ld for %s\n", lres
, debugstr_w(pszPrinter
));
5478 SetLastError(ERROR_INVALID_PRINTER_NAME
);
5483 return (lres
== ERROR_SUCCESS
);
5486 /******************************************************************************
5487 * SetDefaultPrinterA (WINSPOOL.202)
5489 * See SetDefaultPrinterW.
5492 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5494 LPWSTR bufferW
= NULL
;
5497 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5499 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
5500 bufferW
= malloc(len
* sizeof(WCHAR
));
5501 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
5503 res
= SetDefaultPrinterW(bufferW
);
5508 /******************************************************************************
5509 * SetPrinterDataExA (WINSPOOL.@)
5511 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5512 LPCSTR pValueName
, DWORD Type
,
5513 LPBYTE pData
, DWORD cbData
)
5515 HKEY hkeyPrinter
, hkeySubkey
;
5518 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_a(pKeyName
),
5519 debugstr_a(pValueName
), Type
, pData
, cbData
);
5521 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5525 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5527 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5528 RegCloseKey(hkeyPrinter
);
5531 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5532 RegCloseKey(hkeySubkey
);
5533 RegCloseKey(hkeyPrinter
);
5537 /******************************************************************************
5538 * SetPrinterDataExW (WINSPOOL.@)
5540 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5541 LPCWSTR pValueName
, DWORD Type
,
5542 LPBYTE pData
, DWORD cbData
)
5544 HKEY hkeyPrinter
, hkeySubkey
;
5547 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_w(pKeyName
),
5548 debugstr_w(pValueName
), Type
, pData
, cbData
);
5550 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5554 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5556 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5557 RegCloseKey(hkeyPrinter
);
5560 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5561 RegCloseKey(hkeySubkey
);
5562 RegCloseKey(hkeyPrinter
);
5566 /******************************************************************************
5567 * SetPrinterDataA (WINSPOOL.@)
5569 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5570 LPBYTE pData
, DWORD cbData
)
5572 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5576 /******************************************************************************
5577 * SetPrinterDataW (WINSPOOL.@)
5579 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5580 LPBYTE pData
, DWORD cbData
)
5582 return SetPrinterDataExW( hPrinter
, L
"PrinterDriverData", pValueName
, Type
,
5586 /******************************************************************************
5587 * GetPrinterDataExA (WINSPOOL.@)
5589 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5590 LPCSTR pValueName
, LPDWORD pType
,
5591 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5593 opened_printer_t
*printer
;
5594 HKEY printers_key
, hkeyPrinter
= 0, hkeySubkey
= 0;
5597 TRACE("(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter
, debugstr_a(pKeyName
),
5598 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5600 printer
= get_opened_printer(hPrinter
);
5601 if(!printer
) return ERROR_INVALID_HANDLE
;
5603 ret
= create_printers_reg_key( system_printers_key
, &printers_key
);
5604 if (ret
) return ret
;
5606 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5608 if (printer
->name
) {
5610 ret
= RegOpenKeyW( printers_key
, printer
->name
, &hkeyPrinter
);
5613 RegCloseKey( printers_key
);
5616 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5617 WARN("Can't open subkey %s: %ld\n", debugstr_a(pKeyName
), ret
);
5618 RegCloseKey(hkeyPrinter
);
5619 RegCloseKey( printers_key
);
5624 ret
= RegQueryValueExA( printer
->name
? hkeySubkey
: printers_key
, pValueName
,
5625 0, pType
, pData
, pcbNeeded
);
5627 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5629 RegCloseKey(hkeySubkey
);
5630 RegCloseKey(hkeyPrinter
);
5631 RegCloseKey( printers_key
);
5633 TRACE("--> %ld\n", ret
);
5637 /******************************************************************************
5638 * GetPrinterDataExW (WINSPOOL.@)
5640 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5641 LPCWSTR pValueName
, LPDWORD pType
,
5642 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5644 opened_printer_t
*printer
;
5645 HKEY printers_key
, hkeyPrinter
= 0, hkeySubkey
= 0;
5648 TRACE("(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter
, debugstr_w(pKeyName
),
5649 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5651 printer
= get_opened_printer(hPrinter
);
5652 if(!printer
) return ERROR_INVALID_HANDLE
;
5654 ret
= create_printers_reg_key( system_printers_key
, &printers_key
);
5655 if (ret
) return ret
;
5657 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5661 ret
= RegOpenKeyW( printers_key
, printer
->name
, &hkeyPrinter
);
5664 RegCloseKey( printers_key
);
5667 if ((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
)
5669 WARN("Can't open subkey %s: %ld\n", debugstr_w(pKeyName
), ret
);
5670 RegCloseKey(hkeyPrinter
);
5671 RegCloseKey( printers_key
);
5676 ret
= RegQueryValueExW( printer
->name
? hkeySubkey
: printers_key
, pValueName
,
5677 0, pType
, pData
, pcbNeeded
);
5679 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5681 RegCloseKey(hkeySubkey
);
5682 RegCloseKey(hkeyPrinter
);
5683 RegCloseKey( printers_key
);
5685 TRACE("--> %ld\n", ret
);
5689 /******************************************************************************
5690 * GetPrinterDataA (WINSPOOL.@)
5692 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5693 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5695 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5696 pData
, nSize
, pcbNeeded
);
5699 /******************************************************************************
5700 * GetPrinterDataW (WINSPOOL.@)
5702 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5703 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5705 return GetPrinterDataExW( hPrinter
, L
"PrinterDriverData", pValueName
, pType
,
5706 pData
, nSize
, pcbNeeded
);
5709 /*******************************************************************************
5710 * EnumPrinterDataExW [WINSPOOL.@]
5712 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5713 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5714 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5716 HKEY hkPrinter
, hkSubKey
;
5717 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5718 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5722 PPRINTER_ENUM_VALUESW ppev
;
5724 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5726 if (pKeyName
== NULL
|| *pKeyName
== 0)
5727 return ERROR_INVALID_PARAMETER
;
5729 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5730 if (ret
!= ERROR_SUCCESS
)
5732 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
5737 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5738 if (ret
!= ERROR_SUCCESS
)
5740 r
= RegCloseKey (hkPrinter
);
5741 if (r
!= ERROR_SUCCESS
)
5742 WARN ("RegCloseKey returned %li\n", r
);
5743 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter
,
5744 debugstr_w (pKeyName
), ret
);
5748 ret
= RegCloseKey (hkPrinter
);
5749 if (ret
!= ERROR_SUCCESS
)
5751 ERR ("RegCloseKey returned %li\n", ret
);
5752 r
= RegCloseKey (hkSubKey
);
5753 if (r
!= ERROR_SUCCESS
)
5754 WARN ("RegCloseKey returned %li\n", r
);
5758 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5759 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5760 if (ret
!= ERROR_SUCCESS
)
5762 r
= RegCloseKey (hkSubKey
);
5763 if (r
!= ERROR_SUCCESS
)
5764 WARN ("RegCloseKey returned %li\n", r
);
5765 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey
, ret
);
5769 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
5770 "cbMaxValueLen = %li\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5772 if (cValues
== 0) /* empty key */
5774 r
= RegCloseKey (hkSubKey
);
5775 if (r
!= ERROR_SUCCESS
)
5776 WARN ("RegCloseKey returned %li\n", r
);
5777 *pcbEnumValues
= *pnEnumValues
= 0;
5778 return ERROR_SUCCESS
;
5781 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5783 lpValueName
= malloc (cbMaxValueNameLen
* sizeof(WCHAR
));
5784 if (lpValueName
== NULL
)
5786 ERR ("Failed to allocate %li WCHARs\n", cbMaxValueNameLen
);
5787 r
= RegCloseKey (hkSubKey
);
5788 if (r
!= ERROR_SUCCESS
)
5789 WARN ("RegCloseKey returned %li\n", r
);
5790 return ERROR_OUTOFMEMORY
;
5793 lpValue
= malloc (cbMaxValueLen
);
5794 if (lpValue
== NULL
)
5796 ERR ("Failed to allocate %li bytes\n", cbMaxValueLen
);
5798 r
= RegCloseKey (hkSubKey
);
5799 if (r
!= ERROR_SUCCESS
)
5800 WARN ("RegCloseKey returned %li\n", r
);
5801 return ERROR_OUTOFMEMORY
;
5804 TRACE ("pass 1: calculating buffer required for all names and values\n");
5806 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5808 TRACE ("%li bytes required for %li headers\n", cbBufSize
, cValues
);
5810 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5812 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5813 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5814 NULL
, NULL
, lpValue
, &cbValueLen
);
5815 if (ret
!= ERROR_SUCCESS
)
5819 r
= RegCloseKey (hkSubKey
);
5820 if (r
!= ERROR_SUCCESS
)
5821 WARN ("RegCloseKey returned %li\n", r
);
5822 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
5826 TRACE ("%s [%li]: name needs %li WCHARs, data needs %li bytes\n",
5827 debugstr_w (lpValueName
), dwIndex
,
5828 cbValueNameLen
+ 1, cbValueLen
);
5830 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5831 cbBufSize
+= cbValueLen
;
5834 TRACE ("%li bytes required for all %li values\n", cbBufSize
, cValues
);
5836 *pcbEnumValues
= cbBufSize
;
5837 *pnEnumValues
= cValues
;
5839 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5843 r
= RegCloseKey (hkSubKey
);
5844 if (r
!= ERROR_SUCCESS
)
5845 WARN ("RegCloseKey returned %li\n", r
);
5846 TRACE ("%li byte buffer is not large enough\n", cbEnumValues
);
5847 return ERROR_MORE_DATA
;
5850 TRACE ("pass 2: copying all names and values to buffer\n");
5852 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5853 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5855 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5857 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5858 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5859 NULL
, &dwType
, lpValue
, &cbValueLen
);
5860 if (ret
!= ERROR_SUCCESS
)
5864 r
= RegCloseKey (hkSubKey
);
5865 if (r
!= ERROR_SUCCESS
)
5866 WARN ("RegCloseKey returned %li\n", r
);
5867 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
5871 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5872 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5873 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5874 pEnumValues
+= cbValueNameLen
;
5876 /* return # of *bytes* (including trailing \0), not # of chars */
5877 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5879 ppev
[dwIndex
].dwType
= dwType
;
5881 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5882 ppev
[dwIndex
].pData
= pEnumValues
;
5883 pEnumValues
+= cbValueLen
;
5885 ppev
[dwIndex
].cbData
= cbValueLen
;
5887 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
5888 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5894 ret
= RegCloseKey (hkSubKey
);
5895 if (ret
!= ERROR_SUCCESS
)
5897 ERR ("RegCloseKey returned %li\n", ret
);
5901 return ERROR_SUCCESS
;
5904 /*******************************************************************************
5905 * EnumPrinterDataExA [WINSPOOL.@]
5907 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5908 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5909 * what Windows 2000 SP1 does.
5912 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5913 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5914 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5918 DWORD ret
, dwIndex
, dwBufSize
;
5921 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5923 if (pKeyName
== NULL
|| *pKeyName
== 0)
5924 return ERROR_INVALID_PARAMETER
;
5926 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5929 ret
= GetLastError ();
5930 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
5934 pKeyNameW
= malloc (len
* sizeof(WCHAR
));
5935 if (pKeyNameW
== NULL
)
5937 ERR ("Failed to allocate %li bytes\n",
5938 (LONG
)(len
* sizeof (WCHAR
)));
5939 return ERROR_OUTOFMEMORY
;
5942 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5944 ret
= GetLastError ();
5945 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
5950 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5951 pcbEnumValues
, pnEnumValues
);
5953 if (ret
!= ERROR_SUCCESS
)
5955 TRACE ("EnumPrinterDataExW returned %li\n", ret
);
5959 if (*pnEnumValues
== 0) /* empty key */
5960 return ERROR_SUCCESS
;
5963 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5965 PPRINTER_ENUM_VALUESW ppev
=
5966 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5968 if (dwBufSize
< ppev
->cbValueName
)
5969 dwBufSize
= ppev
->cbValueName
;
5971 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5972 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5973 dwBufSize
= ppev
->cbData
;
5976 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize
);
5978 pBuffer
= malloc(dwBufSize
);
5979 if (pBuffer
== NULL
)
5981 ERR ("Failed to allocate %li bytes\n", dwBufSize
);
5982 return ERROR_OUTOFMEMORY
;
5985 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5987 PPRINTER_ENUM_VALUESW ppev
=
5988 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5990 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5991 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5995 ret
= GetLastError ();
5996 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
6001 memcpy (ppev
->pValueName
, pBuffer
, len
);
6003 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer
);
6005 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6006 ppev
->dwType
!= REG_MULTI_SZ
)
6009 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6010 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6013 ret
= GetLastError ();
6014 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
6019 memcpy (ppev
->pData
, pBuffer
, len
);
6021 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer
);
6022 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6026 return ERROR_SUCCESS
;
6029 /******************************************************************************
6030 * AbortPrinter (WINSPOOL.@)
6032 BOOL WINAPI
AbortPrinter(HANDLE printer
)
6034 HANDLE handle
= get_backend_handle(printer
);
6036 TRACE("(%p)\n", printer
);
6038 return backend
->fpAbortPrinter(handle
);
6041 /******************************************************************************
6042 * AddPortA (WINSPOOL.@)
6047 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6049 LPWSTR nameW
= NULL
;
6050 LPWSTR monitorW
= NULL
;
6054 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6057 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6058 nameW
= malloc(len
* sizeof(WCHAR
));
6059 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6063 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6064 monitorW
= malloc(len
* sizeof(WCHAR
));
6065 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6067 res
= AddPortW(nameW
, hWnd
, monitorW
);
6073 /******************************************************************************
6074 * AddPortW (WINSPOOL.@)
6076 * Add a Port for a specific Monitor
6079 * pName [I] Servername or NULL (local Computer)
6080 * hWnd [I] Handle to parent Window for the Dialog-Box
6081 * pMonitorName [I] Name of the Monitor that manage the Port
6088 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6090 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6092 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6094 if (!pMonitorName
) {
6095 SetLastError(RPC_X_NULL_REF_POINTER
);
6099 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6102 /******************************************************************************
6103 * AddPortExA (WINSPOOL.@)
6108 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6111 PORT_INFO_2A
* pi2A
;
6112 LPWSTR nameW
= NULL
;
6113 LPWSTR monitorW
= NULL
;
6117 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6119 TRACE("(%s, %ld, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6120 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6122 if ((level
< 1) || (level
> 2)) {
6123 SetLastError(ERROR_INVALID_LEVEL
);
6128 SetLastError(ERROR_INVALID_PARAMETER
);
6133 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6134 nameW
= malloc(len
* sizeof(WCHAR
));
6135 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6139 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6140 monitorW
= malloc(len
* sizeof(WCHAR
));
6141 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6144 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6146 if (pi2A
->pPortName
) {
6147 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6148 pi2W
.pPortName
= malloc(len
* sizeof(WCHAR
));
6149 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6153 if (pi2A
->pMonitorName
) {
6154 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6155 pi2W
.pMonitorName
= malloc(len
* sizeof(WCHAR
));
6156 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6159 if (pi2A
->pDescription
) {
6160 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6161 pi2W
.pDescription
= malloc(len
* sizeof(WCHAR
));
6162 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6164 pi2W
.fPortType
= pi2A
->fPortType
;
6165 pi2W
.Reserved
= pi2A
->Reserved
;
6168 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6172 free(pi2W
.pPortName
);
6173 free(pi2W
.pMonitorName
);
6174 free(pi2W
.pDescription
);
6179 /******************************************************************************
6180 * AddPortExW (WINSPOOL.@)
6182 * Add a Port for a specific Monitor, without presenting a user interface
6185 * pName [I] Servername or NULL (local Computer)
6186 * level [I] Structure-Level (1 or 2) for pBuffer
6187 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6188 * pMonitorName [I] Name of the Monitor that manage the Port
6195 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6199 pi2
= (PORT_INFO_2W
*) pBuffer
;
6201 TRACE("(%s, %ld, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6202 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6203 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6204 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6206 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6208 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6209 SetLastError(ERROR_INVALID_PARAMETER
);
6213 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6216 /******************************************************************************
6217 * AddPrinterConnectionA (WINSPOOL.@)
6219 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6221 FIXME("%s\n", debugstr_a(pName
));
6225 /******************************************************************************
6226 * AddPrinterConnectionW (WINSPOOL.@)
6228 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6230 FIXME("%s\n", debugstr_w(pName
));
6234 /******************************************************************************
6235 * AddPrinterDriverExW (WINSPOOL.@)
6237 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6240 * pName [I] Servername or NULL (local Computer)
6241 * level [I] Level for the supplied DRIVER_INFO_*W struct
6242 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6243 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6250 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6252 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6254 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6256 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6257 SetLastError(ERROR_INVALID_LEVEL
);
6262 SetLastError(ERROR_INVALID_PARAMETER
);
6266 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6269 /******************************************************************************
6270 * AddPrinterDriverExA (WINSPOOL.@)
6272 * See AddPrinterDriverExW.
6275 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6277 DRIVER_INFO_8A
*diA
;
6279 LPWSTR nameW
= NULL
;
6284 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6286 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6287 ZeroMemory(&diW
, sizeof(diW
));
6289 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6290 SetLastError(ERROR_INVALID_LEVEL
);
6295 SetLastError(ERROR_INVALID_PARAMETER
);
6299 /* convert servername to unicode */
6301 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6302 nameW
= malloc(len
* sizeof(WCHAR
));
6303 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6307 diW
.cVersion
= diA
->cVersion
;
6310 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6311 diW
.pName
= malloc(len
* sizeof(WCHAR
));
6312 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6315 if (diA
->pEnvironment
) {
6316 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6317 diW
.pEnvironment
= malloc(len
* sizeof(WCHAR
));
6318 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6321 if (diA
->pDriverPath
) {
6322 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6323 diW
.pDriverPath
= malloc(len
* sizeof(WCHAR
));
6324 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6327 if (diA
->pDataFile
) {
6328 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6329 diW
.pDataFile
= malloc(len
* sizeof(WCHAR
));
6330 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6333 if (diA
->pConfigFile
) {
6334 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6335 diW
.pConfigFile
= malloc(len
* sizeof(WCHAR
));
6336 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6339 if ((Level
> 2) && diA
->pHelpFile
) {
6340 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, NULL
, 0);
6341 diW
.pHelpFile
= malloc(len
* sizeof(WCHAR
));
6342 MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, diW
.pHelpFile
, len
);
6345 if ((Level
> 2) && diA
->pDependentFiles
) {
6346 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6347 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6348 diW
.pDependentFiles
= malloc(len
* sizeof(WCHAR
));
6349 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6352 if ((Level
> 2) && diA
->pMonitorName
) {
6353 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6354 diW
.pMonitorName
= malloc(len
* sizeof(WCHAR
));
6355 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6358 if ((Level
> 2) && diA
->pDefaultDataType
) {
6359 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6360 diW
.pDefaultDataType
= malloc(len
* sizeof(WCHAR
));
6361 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6364 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6365 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6366 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6367 diW
.pszzPreviousNames
= malloc(len
* sizeof(WCHAR
));
6368 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6372 diW
.ftDriverDate
= diA
->ftDriverDate
;
6373 diW
.dwlDriverVersion
= diA
->dwlDriverVersion
;
6376 if ((Level
> 5) && diA
->pszMfgName
) {
6377 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6378 diW
.pszMfgName
= malloc(len
* sizeof(WCHAR
));
6379 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6382 if ((Level
> 5) && diA
->pszOEMUrl
) {
6383 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6384 diW
.pszOEMUrl
= malloc(len
* sizeof(WCHAR
));
6385 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6388 if ((Level
> 5) && diA
->pszHardwareID
) {
6389 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6390 diW
.pszHardwareID
= malloc(len
* sizeof(WCHAR
));
6391 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6394 if ((Level
> 5) && diA
->pszProvider
) {
6395 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6396 diW
.pszProvider
= malloc(len
* sizeof(WCHAR
));
6397 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6400 if ((Level
> 7) && diA
->pszPrintProcessor
) {
6401 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, NULL
, 0);
6402 diW
.pszPrintProcessor
= malloc(len
* sizeof(WCHAR
));
6403 MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, diW
.pszPrintProcessor
, len
);
6406 if ((Level
> 7) && diA
->pszVendorSetup
) {
6407 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, NULL
, 0);
6408 diW
.pszVendorSetup
= malloc(len
* sizeof(WCHAR
));
6409 MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, diW
.pszVendorSetup
, len
);
6412 if ((Level
> 7) && diA
->pszzColorProfiles
) {
6413 lenA
= multi_sz_lenA(diA
->pszzColorProfiles
);
6414 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, NULL
, 0);
6415 diW
.pszzColorProfiles
= malloc(len
* sizeof(WCHAR
));
6416 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, diW
.pszzColorProfiles
, len
);
6419 if ((Level
> 7) && diA
->pszInfPath
) {
6420 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, NULL
, 0);
6421 diW
.pszInfPath
= malloc(len
* sizeof(WCHAR
));
6422 MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, diW
.pszInfPath
, len
);
6425 if ((Level
> 7) && diA
->pszzCoreDriverDependencies
) {
6426 lenA
= multi_sz_lenA(diA
->pszzCoreDriverDependencies
);
6427 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, NULL
, 0);
6428 diW
.pszzCoreDriverDependencies
= malloc(len
* sizeof(WCHAR
));
6429 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, diW
.pszzCoreDriverDependencies
, len
);
6433 diW
.dwPrinterDriverAttributes
= diA
->dwPrinterDriverAttributes
;
6434 diW
.ftMinInboxDriverVerDate
= diA
->ftMinInboxDriverVerDate
;
6435 diW
.dwlMinInboxDriverVerVersion
= diA
->dwlMinInboxDriverVerVersion
;
6438 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6439 TRACE("got %u with %lu\n", res
, GetLastError());
6442 free(diW
.pEnvironment
);
6443 free(diW
.pDriverPath
);
6444 free(diW
.pDataFile
);
6445 free(diW
.pConfigFile
);
6446 free(diW
.pHelpFile
);
6447 free(diW
.pDependentFiles
);
6448 free(diW
.pMonitorName
);
6449 free(diW
.pDefaultDataType
);
6450 free(diW
.pszzPreviousNames
);
6451 free(diW
.pszMfgName
);
6452 free(diW
.pszOEMUrl
);
6453 free(diW
.pszHardwareID
);
6454 free(diW
.pszProvider
);
6455 free(diW
.pszPrintProcessor
);
6456 free(diW
.pszVendorSetup
);
6457 free(diW
.pszzColorProfiles
);
6458 free(diW
.pszInfPath
);
6459 free(diW
.pszzCoreDriverDependencies
);
6461 TRACE("=> %u with %lu\n", res
, GetLastError());
6465 /******************************************************************************
6466 * ConfigurePortA (WINSPOOL.@)
6468 * See ConfigurePortW.
6471 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6473 LPWSTR nameW
= NULL
;
6474 LPWSTR portW
= NULL
;
6478 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6480 /* convert servername to unicode */
6482 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6483 nameW
= malloc(len
* sizeof(WCHAR
));
6484 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6487 /* convert portname to unicode */
6489 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6490 portW
= malloc(len
* sizeof(WCHAR
));
6491 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6494 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6500 /******************************************************************************
6501 * ConfigurePortW (WINSPOOL.@)
6503 * Display the Configuration-Dialog for a specific Port
6506 * pName [I] Servername or NULL (local Computer)
6507 * hWnd [I] Handle to parent Window for the Dialog-Box
6508 * pPortName [I] Name of the Port, that should be configured
6515 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6518 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6520 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6523 SetLastError(RPC_X_NULL_REF_POINTER
);
6527 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6530 /******************************************************************************
6531 * ConnectToPrinterDlg (WINSPOOL.@)
6533 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6535 FIXME("%p %lx\n", hWnd
, Flags
);
6539 /******************************************************************************
6540 * DeletePrinterConnectionA (WINSPOOL.@)
6542 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6544 FIXME("%s\n", debugstr_a(pName
));
6548 /******************************************************************************
6549 * DeletePrinterConnectionW (WINSPOOL.@)
6551 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6553 FIXME("%s\n", debugstr_w(pName
));
6557 /******************************************************************************
6558 * DeletePrinterDriverExW (WINSPOOL.@)
6560 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6561 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6566 TRACE("%s %s %s %lx %lx\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6567 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6569 if(pName
&& pName
[0])
6571 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6572 SetLastError(ERROR_INVALID_PARAMETER
);
6578 FIXME("dwDeleteFlag = %lx - unsupported\n", dwDeleteFlag
);
6579 SetLastError(ERROR_INVALID_PARAMETER
);
6583 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
6587 ERR("Can't open drivers key\n");
6591 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6594 RegCloseKey(hkey_drivers
);
6599 /******************************************************************************
6600 * DeletePrinterDriverExA (WINSPOOL.@)
6602 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6603 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6605 UNICODE_STRING NameW
, EnvW
, DriverW
;
6608 asciitounicode(&NameW
, pName
);
6609 asciitounicode(&EnvW
, pEnvironment
);
6610 asciitounicode(&DriverW
, pDriverName
);
6612 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6614 RtlFreeUnicodeString(&DriverW
);
6615 RtlFreeUnicodeString(&EnvW
);
6616 RtlFreeUnicodeString(&NameW
);
6621 /******************************************************************************
6622 * DeletePrinterDataExW (WINSPOOL.@)
6624 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6627 FIXME("%p %s %s\n", hPrinter
,
6628 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6629 return ERROR_INVALID_PARAMETER
;
6632 /******************************************************************************
6633 * DeletePrinterDataExA (WINSPOOL.@)
6635 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6638 FIXME("%p %s %s\n", hPrinter
,
6639 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6640 return ERROR_INVALID_PARAMETER
;
6643 /******************************************************************************
6644 * DeletePrintProcessorA (WINSPOOL.@)
6646 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6648 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6649 debugstr_a(pPrintProcessorName
));
6653 /******************************************************************************
6654 * DeletePrintProcessorW (WINSPOOL.@)
6656 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6658 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6659 debugstr_w(pPrintProcessorName
));
6663 /******************************************************************************
6664 * DeletePrintProvidorA (WINSPOOL.@)
6666 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6668 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6669 debugstr_a(pPrintProviderName
));
6673 /******************************************************************************
6674 * DeletePrintProvidorW (WINSPOOL.@)
6676 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6678 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6679 debugstr_w(pPrintProviderName
));
6683 /******************************************************************************
6684 * EnumFormsA (WINSPOOL.@)
6686 BOOL WINAPI
EnumFormsA( HANDLE printer
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
, DWORD
*count
)
6688 const DWORD
*string_info
= form_string_info( level
);
6692 if (!string_info
) return FALSE
;
6694 ret
= EnumFormsW( printer
, level
, form
, size
, needed
, count
);
6696 for (i
= 0; i
< *count
; i
++)
6697 packed_struct_WtoA( form
+ i
* string_info
[0], string_info
);
6702 /******************************************************************************
6703 * EnumFormsW (WINSPOOL.@)
6705 BOOL WINAPI
EnumFormsW( HANDLE printer
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
, DWORD
*count
)
6707 HANDLE handle
= get_backend_handle( printer
);
6709 TRACE( "(%p, %ld, %p, %ld, %p, %p)\n", printer
, level
, form
, size
, needed
, count
);
6713 SetLastError( ERROR_INVALID_HANDLE
);
6717 if (!needed
|| !count
)
6719 SetLastError( RPC_X_NULL_REF_POINTER
);
6725 SetLastError( ERROR_INVALID_USER_BUFFER
);
6729 return backend
->fpEnumForms( handle
, level
, form
, size
, needed
, count
);
6732 /*****************************************************************************
6733 * EnumMonitorsA [WINSPOOL.@]
6735 * See EnumMonitorsW.
6738 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6739 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6742 LPBYTE bufferW
= NULL
;
6743 LPWSTR nameW
= NULL
;
6745 DWORD numentries
= 0;
6748 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6749 cbBuf
, pcbNeeded
, pcReturned
);
6751 /* convert servername to unicode */
6753 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6754 nameW
= malloc(len
* sizeof(WCHAR
));
6755 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6757 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6758 needed
= cbBuf
* sizeof(WCHAR
);
6759 if (needed
) bufferW
= malloc(needed
);
6760 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6762 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6763 if (pcbNeeded
) needed
= *pcbNeeded
;
6764 /* HeapReAlloc return NULL, when bufferW was NULL */
6765 bufferW
= (bufferW
) ? realloc(bufferW
, needed
) : malloc(needed
);
6767 /* Try again with the large Buffer */
6768 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6770 numentries
= pcReturned
? *pcReturned
: 0;
6773 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6774 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6777 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6778 DWORD entrysize
= 0;
6781 LPMONITOR_INFO_2W mi2w
;
6782 LPMONITOR_INFO_2A mi2a
;
6784 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6785 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6787 /* First pass: calculate the size for all Entries */
6788 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6789 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6791 while (index
< numentries
) {
6793 needed
+= entrysize
; /* MONITOR_INFO_?A */
6794 TRACE("%p: parsing #%ld (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6796 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6797 NULL
, 0, NULL
, NULL
);
6799 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6800 NULL
, 0, NULL
, NULL
);
6801 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6802 NULL
, 0, NULL
, NULL
);
6804 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6805 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6806 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6809 /* check for errors and quit on failure */
6810 if (cbBuf
< needed
) {
6811 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6815 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6816 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6817 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6818 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6819 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6821 /* Second Pass: Fill the User Buffer (if we have one) */
6822 while ((index
< numentries
) && pMonitors
) {
6824 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a
, Level
, index
);
6826 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6827 ptr
, cbBuf
, NULL
, NULL
);
6831 mi2a
->pEnvironment
= ptr
;
6832 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6833 ptr
, cbBuf
, NULL
, NULL
);
6837 mi2a
->pDLLName
= ptr
;
6838 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6839 ptr
, cbBuf
, NULL
, NULL
);
6843 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6844 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6845 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6849 if (pcbNeeded
) *pcbNeeded
= needed
;
6850 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6855 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
6856 (res
), GetLastError(), needed
, numentries
);
6862 /*****************************************************************************
6863 * EnumMonitorsW [WINSPOOL.@]
6865 * Enumerate available Port-Monitors
6868 * pName [I] Servername or NULL (local Computer)
6869 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6870 * pMonitors [O] PTR to Buffer that receives the Result
6871 * cbBuf [I] Size of Buffer at pMonitors
6872 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6873 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6877 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6880 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6881 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6884 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6885 cbBuf
, pcbNeeded
, pcReturned
);
6887 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6889 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6890 SetLastError(RPC_X_NULL_REF_POINTER
);
6894 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6897 /******************************************************************************
6898 * SpoolerInit (WINSPOOL.@)
6900 * Initialize the Spooler
6907 * The function fails on windows, when the spooler service is not running
6910 BOOL WINAPI
SpoolerInit(void)
6913 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6917 /******************************************************************************
6918 * XcvDataW (WINSPOOL.@)
6920 * Execute commands in the Printmonitor DLL
6923 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6924 * pszDataName [i] Name of the command to execute
6925 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6926 * cbInputData [i] Size in Bytes of Buffer at pInputData
6927 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6928 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6929 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6930 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6937 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6938 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6940 * Minimal List of commands, that a Printmonitor DLL should support:
6942 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6943 *| "AddPort" : Add a Port
6944 *| "DeletePort": Delete a Port
6946 * Many Printmonitors support additional commands. Examples for localspl.dll:
6947 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6948 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6951 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6952 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6953 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6955 opened_printer_t
*printer
;
6957 TRACE("(%p, %s, %p, %ld, %p, %ld, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6958 pInputData
, cbInputData
, pOutputData
,
6959 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6961 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6963 printer
= get_opened_printer(hXcv
);
6964 if (!printer
|| (!printer
->backend_printer
)) {
6965 SetLastError(ERROR_INVALID_HANDLE
);
6969 if (!pcbOutputNeeded
) {
6970 SetLastError(ERROR_INVALID_PARAMETER
);
6974 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6975 SetLastError(RPC_X_NULL_REF_POINTER
);
6979 *pcbOutputNeeded
= 0;
6981 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
6982 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6986 /*****************************************************************************
6987 * EnumPrinterDataA [WINSPOOL.@]
6990 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6991 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6992 DWORD cbData
, LPDWORD pcbData
)
6994 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
6995 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6996 return ERROR_NO_MORE_ITEMS
;
6999 /*****************************************************************************
7000 * EnumPrinterDataW [WINSPOOL.@]
7003 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7004 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7005 DWORD cbData
, LPDWORD pcbData
)
7007 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
7008 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7009 return ERROR_NO_MORE_ITEMS
;
7012 /*****************************************************************************
7013 * EnumPrinterKeyA [WINSPOOL.@]
7016 DWORD WINAPI
EnumPrinterKeyA(HANDLE printer
, const CHAR
*key
, CHAR
*subkey
, DWORD size
, DWORD
*needed
)
7018 FIXME("%p %s %p %lx %p\n", printer
, debugstr_a(key
), subkey
, size
, needed
);
7019 return ERROR_CALL_NOT_IMPLEMENTED
;
7022 /*****************************************************************************
7023 * EnumPrinterKeyW [WINSPOOL.@]
7026 DWORD WINAPI
EnumPrinterKeyW(HANDLE printer
, const WCHAR
*key
, WCHAR
*subkey
, DWORD size
, DWORD
*needed
)
7028 FIXME("%p %s %p %lx %p\n", printer
, debugstr_w(key
), subkey
, size
, needed
);
7029 return ERROR_CALL_NOT_IMPLEMENTED
;
7032 /*****************************************************************************
7033 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7036 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7037 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7038 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7040 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName
),
7041 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7042 pcbNeeded
, pcReturned
);
7046 /*****************************************************************************
7047 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7050 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7051 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7052 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7054 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
7055 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7056 pcbNeeded
, pcReturned
);
7060 /*****************************************************************************
7061 * EnumPrintProcessorsA [WINSPOOL.@]
7063 * See EnumPrintProcessorsW.
7066 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7067 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7070 LPBYTE bufferW
= NULL
;
7071 LPWSTR nameW
= NULL
;
7074 DWORD numentries
= 0;
7077 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7078 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7080 /* convert names to unicode */
7082 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7083 nameW
= malloc(len
* sizeof(WCHAR
));
7084 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7087 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7088 envW
= malloc(len
* sizeof(WCHAR
));
7089 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7092 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7093 needed
= cbBuf
* sizeof(WCHAR
);
7094 if (needed
) bufferW
= malloc(needed
);
7095 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7097 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7098 if (pcbNeeded
) needed
= *pcbNeeded
;
7099 /* HeapReAlloc return NULL, when bufferW was NULL */
7100 bufferW
= (bufferW
) ? realloc(bufferW
, needed
) : malloc(needed
);
7102 /* Try again with the large Buffer */
7103 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7105 numentries
= pcReturned
? *pcReturned
: 0;
7109 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7112 PPRINTPROCESSOR_INFO_1W ppiw
;
7113 PPRINTPROCESSOR_INFO_1A ppia
;
7115 /* First pass: calculate the size for all Entries */
7116 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7117 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7119 while (index
< numentries
) {
7121 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7122 TRACE("%p: parsing #%ld (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7124 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7125 NULL
, 0, NULL
, NULL
);
7127 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7128 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7131 /* check for errors and quit on failure */
7132 if (cbBuf
< needed
) {
7133 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7138 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7139 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7140 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7141 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7142 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7144 /* Second Pass: Fill the User Buffer (if we have one) */
7145 while ((index
< numentries
) && pPPInfo
) {
7147 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%ld\n", ppia
, index
);
7149 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7150 ptr
, cbBuf
, NULL
, NULL
);
7154 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7155 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7160 if (pcbNeeded
) *pcbNeeded
= needed
;
7161 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7167 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
7168 (res
), GetLastError(), needed
, numentries
);
7173 /*****************************************************************************
7174 * EnumPrintProcessorsW [WINSPOOL.@]
7176 * Enumerate available Print Processors
7179 * pName [I] Servername or NULL (local Computer)
7180 * pEnvironment [I] Printing-Environment or NULL (Default)
7181 * Level [I] Structure-Level (Only 1 is allowed)
7182 * pPPInfo [O] PTR to Buffer that receives the Result
7183 * cbBuf [I] Size of Buffer at pPPInfo
7184 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7185 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7189 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7192 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7193 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7196 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7197 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7199 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7201 if (!pcbNeeded
|| !pcReturned
) {
7202 SetLastError(RPC_X_NULL_REF_POINTER
);
7206 if (!pPPInfo
&& (cbBuf
> 0)) {
7207 SetLastError(ERROR_INVALID_USER_BUFFER
);
7211 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7212 cbBuf
, pcbNeeded
, pcReturned
);
7215 /*****************************************************************************
7216 * ExtDeviceMode [WINSPOOL.@]
7219 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7220 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7223 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd
, hInst
, pDevModeOutput
,
7224 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7225 debugstr_a(pProfile
), fMode
);
7229 /*****************************************************************************
7230 * FindClosePrinterChangeNotification [WINSPOOL.@]
7233 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7235 FIXME("Stub: %p\n", hChange
);
7239 /*****************************************************************************
7240 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7243 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7244 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7246 FIXME("Stub: %p %lx %lx %p\n",
7247 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7248 return INVALID_HANDLE_VALUE
;
7251 /*****************************************************************************
7252 * FindNextPrinterChangeNotification [WINSPOOL.@]
7255 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7256 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7258 FIXME("Stub: %p %p %p %p\n",
7259 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7263 /*****************************************************************************
7264 * FreePrinterNotifyInfo [WINSPOOL.@]
7267 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7269 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7273 static inline const DWORD
*job_string_info(DWORD level
)
7275 static const DWORD info_1
[] =
7277 sizeof(JOB_INFO_1W
),
7278 FIELD_OFFSET(JOB_INFO_1W
, pPrinterName
),
7279 FIELD_OFFSET(JOB_INFO_1W
, pMachineName
),
7280 FIELD_OFFSET(JOB_INFO_1W
, pUserName
),
7281 FIELD_OFFSET(JOB_INFO_1W
, pDocument
),
7282 FIELD_OFFSET(JOB_INFO_1W
, pDatatype
),
7283 FIELD_OFFSET(JOB_INFO_1W
, pStatus
),
7286 static const DWORD info_2
[] =
7288 sizeof(JOB_INFO_2W
),
7289 FIELD_OFFSET(JOB_INFO_2W
, pPrinterName
),
7290 FIELD_OFFSET(JOB_INFO_2W
, pMachineName
),
7291 FIELD_OFFSET(JOB_INFO_2W
, pUserName
),
7292 FIELD_OFFSET(JOB_INFO_2W
, pDocument
),
7293 FIELD_OFFSET(JOB_INFO_2W
, pNotifyName
),
7294 FIELD_OFFSET(JOB_INFO_2W
, pDatatype
),
7295 FIELD_OFFSET(JOB_INFO_2W
, pPrintProcessor
),
7296 FIELD_OFFSET(JOB_INFO_2W
, pParameters
),
7297 FIELD_OFFSET(JOB_INFO_2W
, pDriverName
),
7298 FIELD_OFFSET(JOB_INFO_2W
, pStatus
),
7301 static const DWORD info_3
[] =
7309 case 1: return info_1
;
7310 case 2: return info_2
;
7311 case 3: return info_3
;
7314 SetLastError( ERROR_INVALID_LEVEL
);
7318 /*****************************************************************************
7319 * GetJobA [WINSPOOL.@]
7322 BOOL WINAPI
GetJobA(HANDLE printer
, DWORD job_id
, DWORD level
, BYTE
*data
,
7323 DWORD size
, DWORD
*needed
)
7325 const DWORD
*string_info
= job_string_info(level
);
7330 if (!GetJobW(printer
, job_id
, level
, data
, size
, needed
))
7332 packed_struct_WtoA(data
, string_info
);
7334 DEVMODEWtoA(((JOB_INFO_2W
*)data
)->pDevMode
, ((JOB_INFO_2A
*)data
)->pDevMode
);
7338 /*****************************************************************************
7339 * GetJobW [WINSPOOL.@]
7342 BOOL WINAPI
GetJobW(HANDLE printer
, DWORD job_id
, DWORD level
, BYTE
*data
,
7343 DWORD size
, DWORD
*needed
)
7345 HANDLE handle
= get_backend_handle(printer
);
7347 TRACE("(%p, %ld, %ld, %p, %ld, %p)\n", printer
, job_id
, level
, data
, size
, needed
);
7351 SetLastError(ERROR_INVALID_HANDLE
);
7355 return backend
->fpGetJob(handle
, job_id
, level
, data
, size
, needed
);
7358 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7365 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7369 if(HIWORD(wparam
) == BN_CLICKED
)
7371 if(LOWORD(wparam
) == IDOK
)
7374 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7377 filename
= malloc((len
+ 1) * sizeof(WCHAR
));
7378 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7380 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7382 WCHAR caption
[200], message
[200];
7385 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
7386 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, ARRAY_SIZE(message
));
7387 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7388 if(mb_ret
== IDCANCEL
)
7394 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7395 if(hf
== INVALID_HANDLE_VALUE
)
7397 WCHAR caption
[200], message
[200];
7399 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
7400 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, ARRAY_SIZE(message
));
7401 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7406 DeleteFileW(filename
);
7407 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7409 EndDialog(hwnd
, IDOK
);
7412 if(LOWORD(wparam
) == IDCANCEL
)
7414 EndDialog(hwnd
, IDCANCEL
);
7423 /*****************************************************************************
7426 static BOOL
get_filename(LPWSTR
*filename
)
7428 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7429 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7432 /*****************************************************************************
7433 * ScheduleJob [WINSPOOL.@]
7436 BOOL WINAPI
ScheduleJob(HANDLE printer
, DWORD job_id
)
7438 HANDLE handle
= get_backend_handle(printer
);
7440 TRACE("(%p, %lx)\n", printer
, job_id
);
7444 SetLastError(ERROR_INVALID_HANDLE
);
7448 return backend
->fpScheduleJob(handle
, job_id
);
7451 /*****************************************************************************
7452 * StartDocDlgA [WINSPOOL.@]
7454 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7456 UNICODE_STRING usBuffer
;
7457 DOCINFOW docW
= { 0 };
7459 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7462 docW
.cbSize
= sizeof(docW
);
7463 if (doc
->lpszDocName
)
7465 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7466 if (!(docW
.lpszDocName
= docnameW
)) goto failed
;
7468 if (doc
->lpszOutput
)
7470 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7471 if (!(docW
.lpszOutput
= outputW
)) goto failed
;
7473 if (doc
->lpszDatatype
)
7475 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7476 if (!(docW
.lpszDatatype
= datatypeW
)) goto failed
;
7478 docW
.fwType
= doc
->fwType
;
7480 retW
= StartDocDlgW(hPrinter
, &docW
);
7484 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7485 ret
= heap_alloc(len
);
7486 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7498 static BOOL
is_port(const WCHAR
*port_list
, const WCHAR
*output
)
7502 if (wcschr(output
, ':'))
7505 len
= wcslen(output
);
7506 while (port_list
&& *port_list
)
7508 if (!wcsncmp(output
, port_list
, len
) && (!port_list
[len
] || port_list
[len
] == ','))
7511 port_list
= wcschr(port_list
, ',');
7512 if (port_list
) port_list
++;
7517 /*****************************************************************************
7518 * StartDocDlgW [WINSPOOL.@]
7520 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7521 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7522 * port is "FILE:". Also returns the full path if passed a relative path.
7524 * The caller should free the returned string from the process heap.
7526 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7528 PRINTER_INFO_5W
*pi5
;
7533 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7534 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7537 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7539 /* Check whether default port is FILE: */
7540 b
= !doc
->lpszOutput
&& (!pi5
->pPortName
|| wcscmp( pi5
->pPortName
, L
"FILE:" ));
7541 if (!b
&& doc
->lpszOutput
&& wcscmp( doc
->lpszOutput
, L
"FILE:" ))
7542 b
= is_port(pi5
->pPortName
, doc
->lpszOutput
);
7547 if(doc
->lpszOutput
== NULL
|| !wcscmp( doc
->lpszOutput
, L
"FILE:" ))
7551 if (get_filename(&name
))
7553 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7558 ret
= heap_alloc(len
* sizeof(WCHAR
));
7559 GetFullPathNameW(name
, len
, ret
, NULL
);
7565 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7568 ret
= heap_alloc(len
* sizeof(WCHAR
));
7569 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7571 attr
= GetFileAttributesW(ret
);
7572 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7580 /*****************************************************************************
7581 * UploadPrinterDriverPackageA [WINSPOOL.@]
7583 HRESULT WINAPI
UploadPrinterDriverPackageA( LPCSTR server
, LPCSTR path
, LPCSTR env
,
7584 DWORD flags
, HWND hwnd
, LPSTR dst
, PULONG dstlen
)
7586 FIXME("%s, %s, %s, %lx, %p, %p, %p\n", debugstr_a(server
), debugstr_a(path
), debugstr_a(env
),
7587 flags
, hwnd
, dst
, dstlen
);
7591 /*****************************************************************************
7592 * UploadPrinterDriverPackageW [WINSPOOL.@]
7594 HRESULT WINAPI
UploadPrinterDriverPackageW( LPCWSTR server
, LPCWSTR path
, LPCWSTR env
,
7595 DWORD flags
, HWND hwnd
, LPWSTR dst
, PULONG dstlen
)
7597 FIXME("%s, %s, %s, %lx, %p, %p, %p\n", debugstr_w(server
), debugstr_w(path
), debugstr_w(env
),
7598 flags
, hwnd
, dst
, dstlen
);
7602 /*****************************************************************************
7603 * PerfOpen [WINSPOOL.@]
7605 DWORD WINAPI
PerfOpen(LPWSTR context
)
7607 FIXME("%s: stub\n", debugstr_w(context
));
7608 return ERROR_SUCCESS
;
7611 /*****************************************************************************
7612 * PerfClose [WINSPOOL.@]
7614 DWORD WINAPI
PerfClose(void)
7617 return ERROR_SUCCESS
;
7620 /*****************************************************************************
7621 * PerfCollect [WINSPOOL.@]
7623 DWORD WINAPI
PerfCollect(LPWSTR query
, LPVOID
*data
, LPDWORD size
, LPDWORD obj_count
)
7625 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query
), data
, size
, obj_count
);
7628 return ERROR_SUCCESS
;
7631 /*****************************************************************************
7632 * GetSpoolFileHandle [WINSPOOL.@]
7634 HANDLE WINAPI
GetSpoolFileHandle( HANDLE printer
)
7636 FIXME( "%p: stub\n", printer
);
7637 return INVALID_HANDLE_VALUE
;
7640 /*****************************************************************************
7641 * SeekPrinter [WINSPOOL.@]
7643 BOOL WINAPI
SeekPrinter(HANDLE printer
, LARGE_INTEGER distance
,
7644 LARGE_INTEGER
*pos
, DWORD method
, BOOL bwrite
)
7646 HANDLE handle
= get_backend_handle(printer
);
7648 TRACE("(%p %I64d %p %lx %x)\n", printer
, distance
.QuadPart
, pos
, method
, bwrite
);
7652 SetLastError(ERROR_INVALID_HANDLE
);
7655 return backend
->fpSeekPrinter(handle
, distance
, pos
, method
, bwrite
);