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
;
642 WCHAR raw
[] = L
"RAW", driver_nt
[] = L
"wineps.drv";
644 if (!ppd
) return FALSE
;
645 RtlInitUnicodeString( &nt_ppd
, NULL
);
646 if (!RtlDosPathNameToNtPathName_U( ppd
, &nt_ppd
, NULL
, NULL
)) goto end
;
648 ppd_params
.printer
= name
;
649 ppd_params
.ppd
= nt_ppd
.Buffer
;
650 res
= !UNIX_CALL( get_ppd
, &ppd_params
) || get_internal_fallback_ppd( ppd
);
653 memset( &di3
, 0, sizeof(DRIVER_INFO_3W
) );
655 di3
.pName
= (WCHAR
*)name
;
656 di3
.pDriverPath
= driver_nt
;
658 di3
.pConfigFile
= driver_nt
;
659 di3
.pDefaultDataType
= raw
;
661 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
663 di3
.pEnvironment
= (WCHAR
*)all_printenv
[i
]->envname
;
664 if (all_printenv
[i
]->driverversion
== 0)
666 WCHAR driver_9x
[] = L
"wineps16.drv";
667 /* We use wineps16.drv as driver for 16 bit */
668 di3
.pDriverPath
= driver_9x
;
669 di3
.pConfigFile
= driver_9x
;
671 res
= AddPrinterDriverExW( NULL
, 3, (BYTE
*)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
);
672 TRACE( "got %d and %ld for %s (%s)\n", res
, GetLastError(), debugstr_w( name
), debugstr_w( di3
.pEnvironment
) );
674 if (!res
&& (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
676 ERR( "failed with %lu for %s (%s) %s\n", GetLastError(), debugstr_w( name
),
677 debugstr_w( di3
.pEnvironment
), debugstr_w( di3
.pDriverPath
) );
682 ppd_params
.printer
= NULL
; /* unlink the ppd */
683 UNIX_CALL( get_ppd
, &ppd_params
);
686 RtlFreeUnicodeString( &nt_ppd
);
691 static WCHAR
*get_ppd_dir( void )
693 static const WCHAR wine_ppds
[] = L
"wine_ppds\\";
695 WCHAR
*dir
, tmp_path
[MAX_PATH
];
698 len
= GetTempPathW( ARRAY_SIZE( tmp_path
), tmp_path
);
699 if (!len
) return NULL
;
700 dir
= malloc( len
* sizeof(WCHAR
) + sizeof(wine_ppds
) ) ;
701 if (!dir
) return NULL
;
703 memcpy( dir
, tmp_path
, len
* sizeof(WCHAR
) );
704 memcpy( dir
+ len
, wine_ppds
, sizeof(wine_ppds
) );
705 res
= CreateDirectoryW( dir
, NULL
);
706 if (!res
&& GetLastError() != ERROR_ALREADY_EXISTS
)
711 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir
) );
715 static BOOL
init_unix_printers( void )
717 WCHAR
*port
, *ppd_dir
= NULL
, *default_printer
= NULL
;
718 unsigned int size
, num
;
719 struct enum_printers_params enum_params
= { NULL
, &size
, &num
};
720 HKEY printer_key
, printers_key
;
721 HANDLE added_printer
;
724 WCHAR raw
[] = L
"RAW", winprint
[] = L
"WinPrint", empty
[] = L
"";
727 if (create_printers_reg_key( system_printers_key
, &printers_key
))
729 ERR( "Can't create Printers key\n" );
737 free( enum_params
.printers
);
738 enum_params
.printers
= malloc( size
);
739 status
= UNIX_CALL( enum_printers
, &enum_params
);
740 } while (status
== STATUS_BUFFER_OVERFLOW
);
741 if (status
) goto end
;
743 TRACE( "Found %d CUPS %s:\n", num
, (num
== 1) ? "printer" : "printers" );
744 for (i
= 0; i
< num
; i
++)
746 struct printer_info
*printer
= enum_params
.printers
+ i
;
748 if (RegOpenKeyW( printers_key
, printer
->name
, &printer_key
) == ERROR_SUCCESS
)
750 DWORD status
= get_dword_from_reg( printer_key
, L
"Status" );
751 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
753 TRACE("Printer already exists\n");
754 RegDeleteValueW( printer_key
, May_Delete_Value
);
755 /* flag that the PPD file should be checked for an update */
756 set_reg_DWORD( printer_key
, L
"Status", status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
757 RegCloseKey( printer_key
);
761 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir())) break;
762 if (!add_printer_driver( printer
->name
, ppd_dir
)) continue;
764 port
= malloc( sizeof(L
"CUPS:") + wcslen( printer
->name
) * sizeof(WCHAR
) );
765 wcscpy( port
, L
"CUPS:" );
766 wcscat( port
, printer
->name
);
768 memset( &pi2
, 0, sizeof(PRINTER_INFO_2W
) );
769 pi2
.pPrinterName
= printer
->name
;
771 pi2
.pPrintProcessor
= winprint
;
772 pi2
.pDriverName
= printer
->name
;
773 pi2
.pComment
= printer
->comment
;
774 pi2
.pLocation
= printer
->location
;
775 pi2
.pPortName
= port
;
776 pi2
.pParameters
= empty
;
777 pi2
.pShareName
= empty
;
778 pi2
.pSepFile
= empty
;
780 added_printer
= AddPrinterW( NULL
, 2, (BYTE
*)&pi2
);
781 if (added_printer
) ClosePrinter( added_printer
);
782 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
783 ERR( "printer '%s' not added by AddPrinter (error %ld)\n", debugstr_w( printer
->name
), GetLastError() );
787 if (printer
->is_default
) default_printer
= printer
->name
;
790 if (!default_printer
&& num
) default_printer
= enum_params
.printers
[0].name
;
791 if (default_printer
) SetDefaultPrinterW( default_printer
);
795 RemoveDirectoryW( ppd_dir
);
799 free( enum_params
.printers
);
800 RegCloseKey( printers_key
);
804 static void set_ppd_overrides( HANDLE printer
)
807 unsigned int name_size
= sizeof(buffer
);
808 struct get_default_page_size_params params
= { .name
= buffer
, .name_size
= &name_size
};
813 status
= UNIX_CALL( get_default_page_size
, ¶ms
);
814 if (status
!= STATUS_BUFFER_OVERFLOW
) break;
815 if (params
.name
!= buffer
) free( params
.name
);
816 params
.name
= malloc( name_size
);
817 if (!params
.name
) break;
819 if (!status
) SetPrinterDataExW( printer
, L
"PPD Overrides", L
"DefaultPageSize", REG_SZ
, (BYTE
*)params
.name
, name_size
);
820 if (params
.name
!= buffer
) free( params
.name
);
823 static BOOL
update_driver( HANDLE printer
)
826 const WCHAR
*name
= get_opened_printer_name( printer
);
829 if (!name
) return FALSE
;
830 if (!(ppd_dir
= get_ppd_dir())) return FALSE
;
832 TRACE( "updating driver %s\n", debugstr_w( name
) );
833 ret
= add_printer_driver( name
, ppd_dir
);
837 set_ppd_overrides( printer
);
839 /* call into the driver to update the devmode */
840 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
845 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
848 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
849 (wcslen( value
) + 1) * sizeof(WCHAR
));
851 return ERROR_FILE_NOT_FOUND
;
854 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
856 DEVMODEA
*dmA
= DEVMODEWtoA( dm
, NULL
);
857 DWORD ret
= ERROR_FILE_NOT_FOUND
;
859 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
860 and we support these drivers. NT writes DEVMODEW so somehow
861 we'll need to distinguish between these when we support NT
866 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
867 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
874 /******************************************************************
875 * get_servername_from_name (internal)
877 * for an external server, a copy of the serverpart from the full name is returned
880 static LPWSTR
get_servername_from_name(LPCWSTR name
)
884 WCHAR buffer
[MAX_PATH
];
887 if (name
== NULL
) return NULL
;
888 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
890 server
= wcsdup(&name
[2]); /* skip over both backslash */
891 if (server
== NULL
) return NULL
;
893 /* strip '\' and the printername */
894 ptr
= wcschr( server
, '\\' );
895 if (ptr
) ptr
[0] = '\0';
897 TRACE("found %s\n", debugstr_w(server
));
899 len
= ARRAY_SIZE(buffer
);
900 if (GetComputerNameW(buffer
, &len
))
902 if (!wcscmp( buffer
, server
))
904 /* The requested Servername is our computername */
912 /******************************************************************
913 * get_basename_from_name (internal)
915 * skip over the serverpart from the full name
918 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
920 if (name
== NULL
) return NULL
;
921 if ((name
[0] == '\\') && (name
[1] == '\\'))
923 /* skip over the servername and search for the following '\' */
924 name
= wcschr( &name
[2], '\\' );
925 if ((name
) && (name
[1]))
927 /* found a separator ('\') followed by a name:
928 skip over the separator and return the rest */
933 /* no basename present (we found only a servername) */
940 static void free_printer_entry( opened_printer_t
*printer
)
942 /* the queue is shared, so don't free that here */
943 free( printer
->name
);
947 /******************************************************************
948 * get_opened_printer_entry
949 * Get the first place empty in the opened printer table
952 * - pDefault is ignored
954 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
956 opened_printer_t
*printer
= NULL
;
961 if ((backend
== NULL
) && !load_backend()) return NULL
;
963 servername
= get_servername_from_name(name
);
965 FIXME("server %s not supported\n", debugstr_w(servername
));
967 SetLastError(ERROR_INVALID_PRINTER_NAME
);
971 printername
= get_basename_from_name(name
);
972 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
974 /* an empty printername is invalid */
975 if (printername
&& (!printername
[0])) {
976 SetLastError(ERROR_INVALID_PARAMETER
);
980 EnterCriticalSection(&printer_handles_cs
);
982 for (handle
= 0; handle
< nb_printer_handles
; handle
++)
984 if (!printer_handles
[handle
])
988 if (handle
>= nb_printer_handles
)
990 opened_printer_t
**new_array
;
993 new_array
= realloc(printer_handles
, (nb_printer_handles
+ 16) * sizeof(*new_array
));
994 memset(new_array
+ nb_printer_handles
, 0, 16 * sizeof(*new_array
));
998 new_array
= calloc(nb_printer_handles
+ 16, sizeof(*new_array
));
1006 printer_handles
= new_array
;
1007 nb_printer_handles
+= 16;
1010 if (!(printer
= calloc(1, sizeof(*printer
))))
1016 /* get a printer handle from the backend */
1017 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1022 /* clone the full name */
1023 printer
->name
= wcsdup(name
);
1024 if (name
&& (!printer
->name
)) {
1029 printer_handles
[handle
] = printer
;
1032 LeaveCriticalSection(&printer_handles_cs
);
1033 if (!handle
&& printer
)
1034 free_printer_entry( printer
);
1036 return (HANDLE
)handle
;
1039 static void old_printer_check( BOOL delete_phase
)
1041 PRINTER_INFO_5W
* pi
;
1042 DWORD needed
, type
, num
, delete, i
, size
;
1043 const DWORD one
= 1;
1047 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1048 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1050 pi
= malloc( needed
);
1051 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1052 for (i
= 0; i
< num
; i
++)
1054 if (!pi
[i
].pPortName
) continue;
1056 if (wcsncmp( pi
[i
].pPortName
, L
"CUPS:", ARRAY_SIZE(L
"CUPS:") - 1 ) &&
1057 wcsncmp( pi
[i
].pPortName
, L
"LPR:", ARRAY_SIZE(L
"LPR:") - 1 ))
1060 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1064 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1070 size
= sizeof( delete );
1071 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1075 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1076 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1078 DeletePrinter( hprn
);
1079 ClosePrinter( hprn
);
1081 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1088 static HANDLE init_mutex
;
1090 void WINSPOOL_LoadSystemPrinters(void)
1092 HKEY printers_key
, printer_key
;
1093 DWORD needed
, num
, i
;
1094 WCHAR PrinterName
[256];
1096 /* FIXME: The init code should be moved to spoolsv.exe */
1097 init_mutex
= CreateMutexW( NULL
, TRUE
, L
"__WINE_WINSPOOL_MUTEX__" );
1100 ERR( "Failed to create mutex\n" );
1103 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1105 WaitForSingleObject( init_mutex
, INFINITE
);
1106 ReleaseMutex( init_mutex
);
1107 TRACE( "Init already done\n" );
1111 /* This ensures that all printer entries have a valid Name value. If causes
1112 problems later if they don't. If one is found to be missed we create one
1113 and set it equal to the name of the key */
1114 if (!create_printers_reg_key( system_printers_key
, &printers_key
))
1116 if (!RegQueryInfoKeyW( printers_key
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
))
1117 for (i
= 0; i
< num
; i
++)
1118 if (!RegEnumKeyW( printers_key
, i
, PrinterName
, ARRAY_SIZE(PrinterName
) ))
1119 if (!RegOpenKeyW( printers_key
, PrinterName
, &printer_key
))
1121 if (RegQueryValueExW( printer_key
, L
"Name", 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
)
1122 set_reg_szW( printer_key
, L
"Name", PrinterName
);
1123 RegCloseKey( printer_key
);
1125 RegCloseKey( printers_key
);
1128 old_printer_check( FALSE
);
1129 init_unix_printers();
1130 old_printer_check( TRUE
);
1132 ReleaseMutex( init_mutex
);
1136 /******************************************************************
1137 * convert_printerinfo_W_to_A [internal]
1140 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1141 DWORD level
, DWORD outlen
, DWORD numentries
)
1147 TRACE("(%p, %p, %ld, %lu, %lu)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1149 len
= pi_sizeof
[level
] * numentries
;
1150 ptr
= (LPSTR
) out
+ len
;
1153 /* copy the numbers of all PRINTER_INFO_* first */
1154 memcpy(out
, pPrintersW
, len
);
1156 while (id
< numentries
) {
1160 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1161 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1163 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(piW
->pName
));
1164 if (piW
->pDescription
) {
1165 piA
->pDescription
= ptr
;
1166 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1167 ptr
, outlen
, NULL
, NULL
);
1173 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1174 ptr
, outlen
, NULL
, NULL
);
1178 if (piW
->pComment
) {
1179 piA
->pComment
= ptr
;
1180 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1181 ptr
, outlen
, NULL
, NULL
);
1190 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1191 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1193 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1194 if (piW
->pServerName
) {
1195 piA
->pServerName
= ptr
;
1196 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1197 ptr
, outlen
, NULL
, NULL
);
1201 if (piW
->pPrinterName
) {
1202 piA
->pPrinterName
= ptr
;
1203 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1204 ptr
, outlen
, NULL
, NULL
);
1208 if (piW
->pShareName
) {
1209 piA
->pShareName
= ptr
;
1210 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1211 ptr
, outlen
, NULL
, NULL
);
1215 if (piW
->pPortName
) {
1216 piA
->pPortName
= ptr
;
1217 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1218 ptr
, outlen
, NULL
, NULL
);
1222 if (piW
->pDriverName
) {
1223 piA
->pDriverName
= ptr
;
1224 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1225 ptr
, outlen
, NULL
, NULL
);
1229 if (piW
->pComment
) {
1230 piA
->pComment
= ptr
;
1231 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1232 ptr
, outlen
, NULL
, NULL
);
1236 if (piW
->pLocation
) {
1237 piA
->pLocation
= ptr
;
1238 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1239 ptr
, outlen
, NULL
, NULL
);
1246 /* align DEVMODEA to a DWORD boundary */
1247 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1251 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1252 DEVMODEWtoA(piW
->pDevMode
, piA
->pDevMode
);
1253 len
= piA
->pDevMode
->dmSize
+ piA
->pDevMode
->dmDriverExtra
;
1259 if (piW
->pSepFile
) {
1260 piA
->pSepFile
= ptr
;
1261 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1262 ptr
, outlen
, NULL
, NULL
);
1266 if (piW
->pPrintProcessor
) {
1267 piA
->pPrintProcessor
= ptr
;
1268 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1269 ptr
, outlen
, NULL
, NULL
);
1273 if (piW
->pDatatype
) {
1274 piA
->pDatatype
= ptr
;
1275 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1276 ptr
, outlen
, NULL
, NULL
);
1280 if (piW
->pParameters
) {
1281 piA
->pParameters
= ptr
;
1282 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1283 ptr
, outlen
, NULL
, NULL
);
1287 if (piW
->pSecurityDescriptor
) {
1288 piA
->pSecurityDescriptor
= NULL
;
1289 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1296 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1297 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1299 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1301 if (piW
->pPrinterName
) {
1302 piA
->pPrinterName
= ptr
;
1303 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1304 ptr
, outlen
, NULL
, NULL
);
1308 if (piW
->pServerName
) {
1309 piA
->pServerName
= ptr
;
1310 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1311 ptr
, outlen
, NULL
, NULL
);
1320 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1321 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1323 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1325 if (piW
->pPrinterName
) {
1326 piA
->pPrinterName
= ptr
;
1327 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1328 ptr
, outlen
, NULL
, NULL
);
1332 if (piW
->pPortName
) {
1333 piA
->pPortName
= ptr
;
1334 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1335 ptr
, outlen
, NULL
, NULL
);
1342 case 6: /* 6A and 6W are the same structure */
1347 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1348 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1350 TRACE("(%lu) #%lu\n", level
, id
);
1351 if (piW
->pszObjectGUID
) {
1352 piA
->pszObjectGUID
= ptr
;
1353 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1354 ptr
, outlen
, NULL
, NULL
);
1364 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1365 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1367 TRACE("(%lu) #%lu\n", level
, id
);
1370 /* align DEVMODEA to a DWORD boundary */
1371 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1375 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1376 DEVMODEWtoA(piW
->pDevMode
, piA
->pDevMode
);
1377 len
= piA
->pDevMode
->dmSize
+ piA
->pDevMode
->dmDriverExtra
;
1386 FIXME("for level %lu\n", level
);
1388 pPrintersW
+= pi_sizeof
[level
];
1389 out
+= pi_sizeof
[level
];
1394 /******************************************************************
1395 * convert_driverinfo_W_to_A [internal]
1398 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1399 DWORD level
, DWORD outlen
, DWORD numentries
)
1405 TRACE("(%p, %p, %ld, %lu, %lu)\n", out
, pDriversW
, level
, outlen
, numentries
);
1407 len
= di_sizeof
[level
] * numentries
;
1408 ptr
= (LPSTR
) out
+ len
;
1411 /* copy the numbers of all PRINTER_INFO_* first */
1412 memcpy(out
, pDriversW
, len
);
1414 #define COPY_STRING(fld) \
1417 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1418 ptr += len; outlen -= len;\
1420 #define COPY_MULTIZ_STRING(fld) \
1421 { LPWSTR p = diW->fld; if (p){ \
1424 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1425 ptr += len; outlen -= len; p += len;\
1427 while(len > 1 && outlen > 0); \
1430 while (id
< numentries
)
1436 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1437 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1439 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1446 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1447 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1449 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1452 COPY_STRING(pEnvironment
);
1453 COPY_STRING(pDriverPath
);
1454 COPY_STRING(pDataFile
);
1455 COPY_STRING(pConfigFile
);
1460 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1461 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1463 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1466 COPY_STRING(pEnvironment
);
1467 COPY_STRING(pDriverPath
);
1468 COPY_STRING(pDataFile
);
1469 COPY_STRING(pConfigFile
);
1470 COPY_STRING(pHelpFile
);
1471 COPY_MULTIZ_STRING(pDependentFiles
);
1472 COPY_STRING(pMonitorName
);
1473 COPY_STRING(pDefaultDataType
);
1478 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
1479 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
1481 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1484 COPY_STRING(pEnvironment
);
1485 COPY_STRING(pDriverPath
);
1486 COPY_STRING(pDataFile
);
1487 COPY_STRING(pConfigFile
);
1488 COPY_STRING(pHelpFile
);
1489 COPY_MULTIZ_STRING(pDependentFiles
);
1490 COPY_STRING(pMonitorName
);
1491 COPY_STRING(pDefaultDataType
);
1492 COPY_MULTIZ_STRING(pszzPreviousNames
);
1497 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
1498 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
1500 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1503 COPY_STRING(pEnvironment
);
1504 COPY_STRING(pDriverPath
);
1505 COPY_STRING(pDataFile
);
1506 COPY_STRING(pConfigFile
);
1511 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
1512 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
1514 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1517 COPY_STRING(pEnvironment
);
1518 COPY_STRING(pDriverPath
);
1519 COPY_STRING(pDataFile
);
1520 COPY_STRING(pConfigFile
);
1521 COPY_STRING(pHelpFile
);
1522 COPY_MULTIZ_STRING(pDependentFiles
);
1523 COPY_STRING(pMonitorName
);
1524 COPY_STRING(pDefaultDataType
);
1525 COPY_MULTIZ_STRING(pszzPreviousNames
);
1526 COPY_STRING(pszMfgName
);
1527 COPY_STRING(pszOEMUrl
);
1528 COPY_STRING(pszHardwareID
);
1529 COPY_STRING(pszProvider
);
1534 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
1535 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
1537 TRACE("(%lu) #%lu: %s\n", level
, id
, debugstr_w(diW
->pName
));
1540 COPY_STRING(pEnvironment
);
1541 COPY_STRING(pDriverPath
);
1542 COPY_STRING(pDataFile
);
1543 COPY_STRING(pConfigFile
);
1544 COPY_STRING(pHelpFile
);
1545 COPY_MULTIZ_STRING(pDependentFiles
);
1546 COPY_STRING(pMonitorName
);
1547 COPY_STRING(pDefaultDataType
);
1548 COPY_MULTIZ_STRING(pszzPreviousNames
);
1549 COPY_STRING(pszMfgName
);
1550 COPY_STRING(pszOEMUrl
);
1551 COPY_STRING(pszHardwareID
);
1552 COPY_STRING(pszProvider
);
1553 COPY_STRING(pszPrintProcessor
);
1554 COPY_STRING(pszVendorSetup
);
1555 COPY_MULTIZ_STRING(pszzColorProfiles
);
1556 COPY_STRING(pszInfPath
);
1557 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
1563 FIXME("for level %lu\n", level
);
1566 pDriversW
+= di_sizeof
[level
];
1567 out
+= di_sizeof
[level
];
1572 #undef COPY_MULTIZ_STRING
1576 /***********************************************************
1579 static void *printer_info_AtoW( const void *data
, DWORD level
)
1582 UNICODE_STRING usBuffer
;
1584 if (!data
) return NULL
;
1586 if (level
< 1 || level
> 9) return NULL
;
1588 ret
= malloc( pi_sizeof
[level
] );
1589 if (!ret
) return NULL
;
1591 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
1597 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
1598 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
1600 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
1601 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
1602 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
1603 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
1604 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
1605 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
1606 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
1607 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
1608 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
1609 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
1610 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
1611 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
1618 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
1619 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
1621 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
1626 FIXME( "Unhandled level %ld\n", level
);
1634 /***********************************************************
1637 static void free_printer_info( void *data
, DWORD level
)
1645 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
1647 free( piW
->pServerName
);
1648 free( piW
->pPrinterName
);
1649 free( piW
->pShareName
);
1650 free( piW
->pPortName
);
1651 free( piW
->pDriverName
);
1652 free( piW
->pComment
);
1653 free( piW
->pLocation
);
1654 heap_free( piW
->pDevMode
);
1655 free( piW
->pSepFile
);
1656 free( piW
->pPrintProcessor
);
1657 free( piW
->pDatatype
);
1658 free( piW
->pParameters
);
1665 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
1667 heap_free( piW
->pDevMode
);
1672 FIXME( "Unhandled level %ld\n", level
);
1679 /******************************************************************
1680 * DeviceCapabilities [WINSPOOL.@]
1681 * DeviceCapabilitiesA [WINSPOOL.@]
1684 INT WINAPI
DeviceCapabilitiesA(const char *device
, const char *portA
, WORD cap
,
1685 char *output
, DEVMODEA
*devmodeA
)
1687 WCHAR
*device_name
= NULL
, *port
= NULL
;
1688 DEVMODEW
*devmode
= NULL
;
1691 len
= MultiByteToWideChar(CP_ACP
, 0, device
, -1, NULL
, 0);
1693 device_name
= malloc(len
* sizeof(WCHAR
));
1694 MultiByteToWideChar(CP_ACP
, 0, device
, -1, device_name
, len
);
1697 len
= MultiByteToWideChar(CP_ACP
, 0, portA
, -1, NULL
, 0);
1699 port
= malloc(len
* sizeof(WCHAR
));
1700 MultiByteToWideChar(CP_ACP
, 0, portA
, -1, port
, len
);
1703 if (devmodeA
) devmode
= GdiConvertToDevmodeW( devmodeA
);
1705 if (output
&& (cap
== DC_BINNAMES
|| cap
== DC_FILEDEPENDENCIES
|| cap
== DC_PAPERNAMES
)) {
1706 /* These need A -> W translation */
1707 unsigned int size
= 0, i
;
1710 ret
= DeviceCapabilitiesW(device_name
, port
, cap
, NULL
, devmode
);
1711 if (ret
== -1) goto cleanup
;
1718 case DC_FILEDEPENDENCIES
:
1722 outputW
= malloc(size
* ret
* sizeof(WCHAR
));
1723 ret
= DeviceCapabilitiesW(device_name
, port
, cap
, outputW
, devmode
);
1724 for (i
= 0; i
< ret
; i
++)
1725 WideCharToMultiByte(CP_ACP
, 0, outputW
+ (i
* size
), -1,
1726 output
+ (i
* size
), size
, NULL
, NULL
);
1729 ret
= DeviceCapabilitiesW(device_name
, port
, cap
, (WCHAR
*)output
, devmode
);
1738 /*****************************************************************************
1739 * DeviceCapabilitiesW [WINSPOOL.@]
1742 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1743 WORD fwCapability
, LPWSTR pOutput
,
1744 const DEVMODEW
*pDevMode
)
1746 config_module_t
*config
;
1749 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice
), debugstr_w(pPort
), fwCapability
,
1752 if (!(config
= get_config_module(pDevice
, TRUE
))) {
1753 WARN("Could not load config module for %s\n", debugstr_w(pDevice
));
1757 ret
= config
->pDrvDeviceCapabilities(NULL
/* FIXME */, pDevice
, fwCapability
,
1759 release_config_module(config
);
1763 /******************************************************************
1764 * DocumentPropertiesA [WINSPOOL.@]
1766 LONG WINAPI
DocumentPropertiesA(HWND hwnd
, HANDLE printer
, char *device_name
, DEVMODEA
*output
,
1767 DEVMODEA
*input
, DWORD mode
)
1769 DEVMODEW
*outputW
= NULL
, *inputW
= NULL
;
1770 WCHAR
*device
= NULL
;
1774 TRACE("(%p,%p,%s,%p,%p,%ld)\n", hwnd
, printer
, debugstr_a(device_name
), output
, input
, mode
);
1776 len
= MultiByteToWideChar(CP_ACP
, 0, device_name
, -1, NULL
, 0);
1778 device
= malloc(len
* sizeof(WCHAR
));
1779 MultiByteToWideChar(CP_ACP
, 0, device_name
, -1, device
, len
);
1782 if (output
&& (mode
& (DM_COPY
| DM_UPDATE
))) {
1783 ret
= DocumentPropertiesW(hwnd
, printer
, device
, NULL
, NULL
, 0);
1788 outputW
= malloc(ret
);
1791 if (input
&& (mode
& DM_IN_BUFFER
)) inputW
= GdiConvertToDevmodeW(input
);
1793 ret
= DocumentPropertiesW(hwnd
, printer
, device
, outputW
, inputW
, mode
);
1795 if (ret
>= 0 && outputW
&& (mode
& (DM_COPY
| DM_UPDATE
)))
1796 DEVMODEWtoA( outputW
, output
);
1802 if (!mode
&& ret
> 0) ret
-= CCHDEVICENAME
+ CCHFORMNAME
;
1806 static LONG WINAPI
document_callback(PROPSHEETUI_INFO
*info
, LPARAM lparam
)
1808 if (info
->Reason
== PROPSHEETUI_REASON_INIT
)
1810 document_property_t
*dp
= (document_property_t
*)info
->lParamInit
;
1812 if (!info
->pfnComPropSheet(info
->hComPropSheet
, CPSFUNC_ADD_PFNPROPSHEETUIW
,
1813 (LPARAM
)dp
->config
->pDrvDocumentPropertySheets
, (LPARAM
)&dp
->dph
))
1814 return ERR_CPSUI_GETLASTERROR
;
1819 /*****************************************************************************
1820 * DocumentPropertiesW (WINSPOOL.@)
1822 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1824 LPDEVMODEW pDevModeOutput
,
1825 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1827 document_property_t dp
;
1828 const WCHAR
*device
;
1831 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1832 hWnd
, hPrinter
, debugstr_w(pDeviceName
), pDevModeOutput
, pDevModeInput
, fMode
);
1834 device
= hPrinter
? get_opened_printer_name(hPrinter
) : pDeviceName
;
1836 ERR("no device name\n");
1840 dp
.dph
.cbSize
= sizeof(dp
.dph
);
1841 dp
.dph
.Reserved
= 0;
1842 dp
.dph
.hPrinter
= hPrinter
;
1843 dp
.dph
.pszPrinterName
= device
;
1844 dp
.dph
.pdmIn
= pDevModeInput
;
1845 dp
.dph
.pdmOut
= pDevModeOutput
;
1846 dp
.dph
.cbOut
= dp
.dph
.pdmOut
? dp
.dph
.pdmOut
->dmSize
: 0;
1847 dp
.dph
.fMode
= fMode
;
1848 dp
.config
= get_config_module(device
, TRUE
);
1850 ERR("Could not load config module for %s\n", debugstr_w(device
));
1854 if (!(fMode
& ~(DM_IN_BUFFER
| DM_OUT_BUFFER
| DM_OUT_DEFAULT
))) {
1855 ret
= dp
.config
->pDrvDocumentPropertySheets(NULL
, (LPARAM
)&dp
.dph
);
1857 if ((!fMode
|| !pDevModeOutput
) && dp
.dph
.cbOut
!= ret
)
1858 FIXME("size mismatch: ret = %ld cbOut = %ld\n", ret
, dp
.dph
.cbOut
);
1860 ret
= CommonPropertySheetUIW(hWnd
, document_callback
, (LPARAM
)&dp
, NULL
);
1863 release_config_module(dp
.config
);
1867 /*****************************************************************************
1868 * IsValidDevmodeA [WINSPOOL.@]
1870 * Validate a DEVMODE structure and fix errors if possible.
1873 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA pDevMode
, SIZE_T size
)
1875 FIXME("(%p,%Id): stub\n", pDevMode
, size
);
1883 /*****************************************************************************
1884 * IsValidDevmodeW [WINSPOOL.@]
1886 * Validate a DEVMODE structure and fix errors if possible.
1889 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW dm
, SIZE_T size
)
1897 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
1898 { DM_ORIENTATION
, F_SIZE(u1
.s1
.dmOrientation
) },
1899 { DM_PAPERSIZE
, F_SIZE(u1
.s1
.dmPaperSize
) },
1900 { DM_PAPERLENGTH
, F_SIZE(u1
.s1
.dmPaperLength
) },
1901 { DM_PAPERWIDTH
, F_SIZE(u1
.s1
.dmPaperWidth
) },
1902 { DM_SCALE
, F_SIZE(u1
.s1
.dmScale
) },
1903 { DM_COPIES
, F_SIZE(u1
.s1
.dmCopies
) },
1904 { DM_DEFAULTSOURCE
, F_SIZE(u1
.s1
.dmDefaultSource
) },
1905 { DM_PRINTQUALITY
, F_SIZE(u1
.s1
.dmPrintQuality
) },
1906 { DM_POSITION
, F_SIZE(u1
.s2
.dmPosition
) },
1907 { DM_DISPLAYORIENTATION
, F_SIZE(u1
.s2
.dmDisplayOrientation
) },
1908 { DM_DISPLAYFIXEDOUTPUT
, F_SIZE(u1
.s2
.dmDisplayFixedOutput
) },
1909 { DM_COLOR
, F_SIZE(dmColor
) },
1910 { DM_DUPLEX
, F_SIZE(dmDuplex
) },
1911 { DM_YRESOLUTION
, F_SIZE(dmYResolution
) },
1912 { DM_TTOPTION
, F_SIZE(dmTTOption
) },
1913 { DM_COLLATE
, F_SIZE(dmCollate
) },
1914 { DM_FORMNAME
, F_SIZE(dmFormName
) },
1915 { DM_LOGPIXELS
, F_SIZE(dmLogPixels
) },
1916 { DM_BITSPERPEL
, F_SIZE(dmBitsPerPel
) },
1917 { DM_PELSWIDTH
, F_SIZE(dmPelsWidth
) },
1918 { DM_PELSHEIGHT
, F_SIZE(dmPelsHeight
) },
1919 { DM_DISPLAYFLAGS
, F_SIZE(u2
.dmDisplayFlags
) },
1920 { DM_NUP
, F_SIZE(u2
.dmNup
) },
1921 { DM_DISPLAYFREQUENCY
, F_SIZE(dmDisplayFrequency
) },
1922 { DM_ICMMETHOD
, F_SIZE(dmICMMethod
) },
1923 { DM_ICMINTENT
, F_SIZE(dmICMIntent
) },
1924 { DM_MEDIATYPE
, F_SIZE(dmMediaType
) },
1925 { DM_DITHERTYPE
, F_SIZE(dmDitherType
) },
1926 { DM_PANNINGWIDTH
, F_SIZE(dmPanningWidth
) },
1927 { DM_PANNINGHEIGHT
, F_SIZE(dmPanningHeight
) }
1932 if (!dm
) return FALSE
;
1933 if (size
< FIELD_OFFSET(DEVMODEW
, dmFields
) + sizeof(dm
->dmFields
)) return FALSE
;
1935 for (i
= 0; i
< ARRAY_SIZE(map
); i
++)
1936 if ((dm
->dmFields
& map
[i
].flag
) && size
< map
[i
].size
)
1942 /******************************************************************
1943 * OpenPrinterA [WINSPOOL.@]
1948 BOOL WINAPI
OpenPrinterA(LPSTR name
, HANDLE
*printer
, PRINTER_DEFAULTSA
*defaults
)
1950 return OpenPrinter2A(name
, printer
, defaults
, NULL
);
1953 /******************************************************************
1954 * OpenPrinterW [WINSPOOL.@]
1956 * Open a Printer / Printserver or a Printer-Object
1959 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1960 * phPrinter [O] The resulting Handle is stored here
1961 * pDefault [I] PTR to Default Printer Settings or NULL
1968 * lpPrinterName is one of:
1969 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1970 *| Printer: "PrinterName"
1971 *| Printer-Object: "PrinterName,Job xxx"
1972 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1973 *| XcvPort: "Servername,XcvPort PortName"
1976 *| Printer-Object not supported
1977 *| pDefaults is ignored
1980 BOOL WINAPI
OpenPrinterW(LPWSTR name
, HANDLE
*printer
, PRINTER_DEFAULTSW
*defaults
)
1982 return OpenPrinter2W(name
, printer
, defaults
, NULL
);
1985 BOOL WINAPI
OpenPrinter2A(LPSTR name
, HANDLE
*printer
,
1986 PRINTER_DEFAULTSA
*defaults
, PRINTER_OPTIONSA
*options
)
1988 UNICODE_STRING nameU
;
1989 UNICODE_STRING datatypeU
;
1990 PRINTER_DEFAULTSW defaultsW
, *p_defaultsW
= NULL
;
1991 PRINTER_OPTIONSW optionsW
, *p_optionsW
= NULL
;
1995 TRACE("(%s,%p,%p,%p)\n", debugstr_a(name
), printer
, defaults
, options
);
1997 nameW
= asciitounicode(&nameU
, name
);
2001 optionsW
.cbSize
= sizeof(optionsW
);
2002 optionsW
.dwFlags
= options
->dwFlags
;
2003 p_optionsW
= &optionsW
;
2008 defaultsW
.pDatatype
= asciitounicode(&datatypeU
, defaults
->pDatatype
);
2009 defaultsW
.pDevMode
= defaults
->pDevMode
? GdiConvertToDevmodeW(defaults
->pDevMode
) : NULL
;
2010 defaultsW
.DesiredAccess
= defaults
->DesiredAccess
;
2011 p_defaultsW
= &defaultsW
;
2014 ret
= OpenPrinter2W(nameW
, printer
, p_defaultsW
, p_optionsW
);
2018 RtlFreeUnicodeString(&datatypeU
);
2019 heap_free(defaultsW
.pDevMode
);
2021 RtlFreeUnicodeString(&nameU
);
2026 BOOL WINAPI
OpenPrinter2W(LPWSTR name
, HANDLE
*printer
,
2027 PRINTER_DEFAULTSW
*defaults
, PRINTER_OPTIONSW
*options
)
2031 TRACE("(%s,%p,%p,%p)\n", debugstr_w(name
), printer
, defaults
, options
);
2034 FIXME("flags %08lx ignored\n", options
->dwFlags
);
2038 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2039 SetLastError( ERROR_INVALID_PARAMETER
);
2043 /* Get the unique handle of the printer or Printserver */
2044 *printer
= get_opened_printer_entry( name
, defaults
);
2046 if (*printer
&& WINSPOOL_GetOpenedPrinterRegKey( *printer
, &key
) == ERROR_SUCCESS
)
2048 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2050 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2051 WaitForSingleObject( init_mutex
, INFINITE
);
2052 status
= get_dword_from_reg( key
, L
"Status" );
2053 set_reg_DWORD( key
, L
"Status", status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2054 ReleaseMutex( init_mutex
);
2055 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2056 update_driver( *printer
);
2060 TRACE("returning %d with %lu and %p\n", *printer
!= NULL
, GetLastError(), *printer
);
2061 return (*printer
!= NULL
);
2064 /******************************************************************
2065 * AddMonitorA [WINSPOOL.@]
2070 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2072 LPWSTR nameW
= NULL
;
2075 LPMONITOR_INFO_2A mi2a
;
2076 MONITOR_INFO_2W mi2w
;
2078 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2079 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2080 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2081 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2082 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2085 SetLastError(ERROR_INVALID_LEVEL
);
2089 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2095 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2096 nameW
= malloc(len
* sizeof(WCHAR
));
2097 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2100 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2102 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2103 mi2w
.pName
= malloc(len
* sizeof(WCHAR
));
2104 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2106 if (mi2a
->pEnvironment
) {
2107 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2108 mi2w
.pEnvironment
= malloc(len
* sizeof(WCHAR
));
2109 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2111 if (mi2a
->pDLLName
) {
2112 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2113 mi2w
.pDLLName
= malloc(len
* sizeof(WCHAR
));
2114 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2117 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2120 free(mi2w
.pEnvironment
);
2121 free(mi2w
.pDLLName
);
2127 /******************************************************************************
2128 * AddMonitorW [WINSPOOL.@]
2130 * Install a Printmonitor
2133 * pName [I] Servername or NULL (local Computer)
2134 * Level [I] Structure-Level (Must be 2)
2135 * pMonitors [I] PTR to MONITOR_INFO_2
2142 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2145 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2147 LPMONITOR_INFO_2W mi2w
;
2149 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2150 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2151 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2152 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2153 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2155 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2158 SetLastError(ERROR_INVALID_LEVEL
);
2162 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2167 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2170 /******************************************************************
2171 * DeletePrinterDriverA [WINSPOOL.@]
2174 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2176 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2179 /******************************************************************
2180 * DeletePrinterDriverW [WINSPOOL.@]
2183 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2185 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2188 /******************************************************************
2189 * DeleteMonitorA [WINSPOOL.@]
2191 * See DeleteMonitorW.
2194 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2196 LPWSTR nameW
= NULL
;
2197 LPWSTR EnvironmentW
= NULL
;
2198 LPWSTR MonitorNameW
= NULL
;
2203 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2204 nameW
= malloc(len
* sizeof(WCHAR
));
2205 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2209 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2210 EnvironmentW
= malloc(len
* sizeof(WCHAR
));
2211 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2214 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2215 MonitorNameW
= malloc(len
* sizeof(WCHAR
));
2216 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2219 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2227 /******************************************************************
2228 * DeleteMonitorW [WINSPOOL.@]
2230 * Delete a specific Printmonitor from a Printing-Environment
2233 * pName [I] Servername or NULL (local Computer)
2234 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2235 * pMonitorName [I] Name of the Monitor, that should be deleted
2242 * pEnvironment is ignored in Windows for the local Computer.
2245 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2248 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2249 debugstr_w(pMonitorName
));
2251 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2253 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2257 /******************************************************************
2258 * DeletePortA [WINSPOOL.@]
2263 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2265 LPWSTR nameW
= NULL
;
2266 LPWSTR portW
= NULL
;
2270 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2272 /* convert servername to unicode */
2274 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2275 nameW
= malloc(len
* sizeof(WCHAR
));
2276 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2279 /* convert portname to unicode */
2281 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2282 portW
= malloc(len
* sizeof(WCHAR
));
2283 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2286 res
= DeletePortW(nameW
, hWnd
, portW
);
2292 /******************************************************************
2293 * DeletePortW [WINSPOOL.@]
2295 * Delete a specific Port
2298 * pName [I] Servername or NULL (local Computer)
2299 * hWnd [I] Handle to parent Window for the Dialog-Box
2300 * pPortName [I] Name of the Port, that should be deleted
2307 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2309 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2311 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2314 SetLastError(RPC_X_NULL_REF_POINTER
);
2318 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2321 /******************************************************************************
2322 * WritePrinter [WINSPOOL.@]
2324 BOOL WINAPI
WritePrinter(HANDLE printer
, void *buf
, DWORD size
, DWORD
*written
)
2326 HANDLE handle
= get_backend_handle(printer
);
2328 TRACE("(%p, %p, %ld, %p)\n", printer
, buf
, size
, written
);
2332 SetLastError(ERROR_INVALID_HANDLE
);
2336 return backend
->fpWritePrinter(handle
, buf
, size
, written
);
2339 /*****************************************************************************
2340 * AddFormA [WINSPOOL.@]
2342 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2344 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
2348 /*****************************************************************************
2349 * AddFormW [WINSPOOL.@]
2351 BOOL WINAPI
AddFormW( HANDLE printer
, DWORD level
, BYTE
*form
)
2353 HANDLE handle
= get_backend_handle( printer
);
2355 TRACE( "(%p, %ld, %p)\n", printer
, level
, form
);
2359 SetLastError( ERROR_INVALID_HANDLE
);
2363 return backend
->fpAddForm( handle
, level
, form
);
2366 /*****************************************************************************
2367 * AddJobA [WINSPOOL.@]
2369 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2372 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2376 SetLastError(ERROR_INVALID_LEVEL
);
2380 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2383 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2384 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2385 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2386 if(*pcbNeeded
> cbBuf
) {
2387 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2390 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2391 addjobA
->JobId
= addjobW
->JobId
;
2392 addjobA
->Path
= (char *)(addjobA
+ 1);
2393 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2399 /*****************************************************************************
2400 * AddJobW [WINSPOOL.@]
2402 BOOL WINAPI
AddJobW(HANDLE printer
, DWORD level
, LPBYTE data
, DWORD size
, DWORD
*needed
)
2404 HANDLE handle
= get_backend_handle(printer
);
2406 TRACE("(%p, %ld, %p, %ld, %p)\n", printer
, level
, data
, size
, needed
);
2410 SetLastError(ERROR_INVALID_HANDLE
);
2414 return backend
->fpAddJob(handle
, level
, data
, size
, needed
);
2417 /*****************************************************************************
2418 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2420 * Return the PATH for the Print-Processors
2422 * See GetPrintProcessorDirectoryW.
2426 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2427 DWORD level
, LPBYTE Info
,
2428 DWORD cbBuf
, LPDWORD pcbNeeded
)
2430 LPWSTR serverW
= NULL
;
2435 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server
),
2436 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2440 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2441 serverW
= malloc(len
* sizeof(WCHAR
));
2442 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2446 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2447 envW
= malloc(len
* sizeof(WCHAR
));
2448 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2451 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2452 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2454 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2457 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2458 cbBuf
, NULL
, NULL
) > 0;
2461 TRACE(" required: 0x%lx/%ld\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2467 /*****************************************************************************
2468 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2470 * Return the PATH for the Print-Processors
2473 * server [I] Servername (NT only) or NULL (local Computer)
2474 * env [I] Printing-Environment (see below) or NULL (Default)
2475 * level [I] Structure-Level (must be 1)
2476 * Info [O] PTR to Buffer that receives the Result
2477 * cbBuf [I] Size of Buffer at "Info"
2478 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2479 * required for the Buffer at "Info"
2482 * Success: TRUE and in pcbNeeded the Bytes used in Info
2483 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2484 * if cbBuf is too small
2486 * Native Values returned in Info on Success:
2487 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2488 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2489 *| win9x(Windows 4.0): "%winsysdir%"
2491 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2494 * Only NULL or "" is supported for server
2497 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2498 DWORD level
, LPBYTE Info
,
2499 DWORD cbBuf
, LPDWORD pcbNeeded
)
2502 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2503 Info
, cbBuf
, pcbNeeded
);
2505 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2508 /* (Level != 1) is ignored in win9x */
2509 SetLastError(ERROR_INVALID_LEVEL
);
2513 if (pcbNeeded
== NULL
) {
2514 /* (pcbNeeded == NULL) is ignored in win9x */
2515 SetLastError(RPC_X_NULL_REF_POINTER
);
2519 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2522 /*****************************************************************************
2523 * set_devices_and_printerports [internal]
2525 * set the [Devices] and [PrinterPorts] entries for a printer.
2528 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
2530 DWORD portlen
= wcslen( pi
->pPortName
) * sizeof(WCHAR
);
2534 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
2536 /* FIXME: the driver must change to "winspool" */
2537 devline
= malloc( sizeof(L
"wineps.drv") + portlen
+ sizeof(L
",15,45") );
2540 wcscpy( devline
, L
"wineps.drv," );
2541 wcscat( devline
, pi
->pPortName
);
2543 TRACE("using %s\n", debugstr_w(devline
));
2544 if (!create_printers_reg_key( user_printers_key
, &key
))
2546 RegSetValueExW( key
, pi
->pPrinterName
, 0, REG_SZ
, (BYTE
*)devline
,
2547 (wcslen( devline
) + 1) * sizeof(WCHAR
) );
2551 wcscat( devline
, L
",15,45" );
2552 if (!create_printers_reg_key( user_ports_key
, &key
))
2554 RegSetValueExW( key
, pi
->pPrinterName
, 0, REG_SZ
, (BYTE
*)devline
,
2555 (wcslen( devline
) + 1) * sizeof(WCHAR
) );
2562 static BOOL
validate_print_proc(WCHAR
*server
, const WCHAR
*name
)
2564 PRINTPROCESSOR_INFO_1W
*ppi
;
2567 if (!EnumPrintProcessorsW(server
, NULL
, 1, NULL
, 0, &size
, &no
)
2568 && GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
2575 SetLastError(ERROR_OUTOFMEMORY
);
2578 if (!EnumPrintProcessorsW(server
, NULL
, 1, (BYTE
*)ppi
, size
, &size
, &no
))
2584 for (i
= 0; i
< no
; i
++)
2586 if (!wcsicmp(ppi
[i
].pName
, name
))
2593 /*****************************************************************************
2594 * AddPrinterW [WINSPOOL.@]
2596 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2598 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2601 HKEY printer_key
, printers_key
, hkeyDriver
, hkeyDrivers
;
2604 TRACE("(%s,%ld,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2606 if(pName
&& *pName
) {
2607 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2608 SetLastError(ERROR_INVALID_PARAMETER
);
2612 ERR("Level = %ld, unsupported!\n", Level
);
2613 SetLastError(ERROR_INVALID_LEVEL
);
2617 SetLastError(ERROR_INVALID_PARAMETER
);
2620 if (create_printers_reg_key( system_printers_key
, &printers_key
))
2622 ERR("Can't create Printers key\n");
2625 if (!RegOpenKeyW( printers_key
, pi
->pPrinterName
, &printer_key
))
2627 if (!RegQueryValueW( printer_key
, L
"Attributes", NULL
, NULL
))
2629 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2630 RegCloseKey( printer_key
);
2631 RegCloseKey( printers_key
);
2634 RegCloseKey( printer_key
);
2636 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
2638 ERR("Can't create Drivers key\n");
2639 RegCloseKey( printers_key
);
2642 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2644 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2645 RegCloseKey( printers_key
);
2646 RegCloseKey(hkeyDrivers
);
2647 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2650 RegCloseKey(hkeyDriver
);
2651 RegCloseKey(hkeyDrivers
);
2653 if (!validate_print_proc(pName
, pi
->pPrintProcessor
))
2655 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2656 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2657 RegCloseKey( printers_key
);
2661 if (RegCreateKeyW( printers_key
, pi
->pPrinterName
, &printer_key
))
2663 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2664 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2665 RegCloseKey( printers_key
);
2669 set_devices_and_printerports(pi
);
2671 set_reg_DWORD( printer_key
, L
"Attributes", pi
->Attributes
);
2672 set_reg_szW( printer_key
, L
"Datatype", pi
->pDatatype
);
2673 set_reg_DWORD( printer_key
, L
"Default Priority", pi
->DefaultPriority
);
2674 set_reg_szW( printer_key
, L
"Description", pi
->pComment
);
2675 set_reg_DWORD( printer_key
, L
"dnsTimeout", 0 );
2676 set_reg_szW( printer_key
, L
"Location", pi
->pLocation
);
2677 set_reg_szW( printer_key
, L
"Name", pi
->pPrinterName
);
2678 set_reg_szW( printer_key
, L
"Parameters", pi
->pParameters
);
2679 set_reg_szW( printer_key
, L
"Port", pi
->pPortName
);
2680 set_reg_szW( printer_key
, L
"Print Processor", pi
->pPrintProcessor
);
2681 set_reg_szW( printer_key
, L
"Printer Driver", pi
->pDriverName
);
2682 set_reg_DWORD( printer_key
, L
"Priority", pi
->Priority
);
2683 set_reg_szW( printer_key
, L
"Separator File", pi
->pSepFile
);
2684 set_reg_szW( printer_key
, L
"Share Name", pi
->pShareName
);
2685 set_reg_DWORD( printer_key
, L
"StartTime", pi
->StartTime
);
2686 set_reg_DWORD( printer_key
, L
"Status", pi
->Status
);
2687 set_reg_DWORD( printer_key
, L
"txTimeout", 0 );
2688 set_reg_DWORD( printer_key
, L
"UntilTime", pi
->UntilTime
);
2690 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2694 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2695 size
= sizeof(DEVMODEW
);
2701 dm
= calloc( 1, size
);
2703 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
2705 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2711 unsigned int len
= min( ARRAY_SIZE( dm
->dmDeviceName
) - 1, wcslen( pi
->pPrinterName
) );
2712 memcpy( dm
->dmDeviceName
, pi
->pPrinterName
, len
* sizeof(WCHAR
) );
2713 dm
->dmDeviceName
[len
] = '\0';
2717 set_reg_devmode( printer_key
, L
"Default DevMode", dm
);
2718 if (!pi
->pDevMode
) free( dm
);
2720 RegCloseKey( printer_key
);
2721 RegCloseKey( printers_key
);
2722 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2723 ERR("OpenPrinter failing\n");
2729 /*****************************************************************************
2730 * AddPrinterA [WINSPOOL.@]
2732 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2734 UNICODE_STRING pNameW
;
2736 PRINTER_INFO_2W
*piW
;
2737 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2740 TRACE("(%s, %ld, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
2742 ERR("Level = %ld, unsupported!\n", Level
);
2743 SetLastError(ERROR_INVALID_LEVEL
);
2746 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2747 piW
= printer_info_AtoW( piA
, Level
);
2749 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2751 free_printer_info( piW
, Level
);
2752 RtlFreeUnicodeString(&pNameW
);
2757 /*****************************************************************************
2758 * ClosePrinter [WINSPOOL.@]
2760 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2762 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2763 opened_printer_t
*printer
= NULL
;
2765 TRACE("(%p)\n", hPrinter
);
2767 EnterCriticalSection(&printer_handles_cs
);
2769 if ((i
> 0) && (i
<= nb_printer_handles
))
2770 printer
= printer_handles
[i
- 1];
2775 TRACE("closing %s\n", debugstr_w(printer
->name
));
2776 if (printer
->backend_printer
) {
2777 backend
->fpClosePrinter(printer
->backend_printer
);
2780 free_printer_entry( printer
);
2781 printer_handles
[i
- 1] = NULL
;
2782 LeaveCriticalSection(&printer_handles_cs
);
2786 LeaveCriticalSection(&printer_handles_cs
);
2787 SetLastError(ERROR_INVALID_HANDLE
);
2791 /*****************************************************************************
2792 * DeleteFormA [WINSPOOL.@]
2794 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2796 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2800 /*****************************************************************************
2801 * DeleteFormW [WINSPOOL.@]
2803 BOOL WINAPI
DeleteFormW( HANDLE printer
, WCHAR
*name
)
2805 HANDLE handle
= get_backend_handle( printer
);
2807 TRACE( "(%p, %s)\n", printer
, debugstr_w( name
) );
2811 SetLastError( ERROR_INVALID_HANDLE
);
2815 return backend
->fpDeleteForm( handle
, name
);
2818 /*****************************************************************************
2819 * DeletePrinter [WINSPOOL.@]
2821 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2823 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2824 config_module_t
*config_module
;
2826 WCHAR def
[MAX_PATH
];
2827 DWORD size
= ARRAY_SIZE(def
);
2830 SetLastError(ERROR_INVALID_HANDLE
);
2834 EnterCriticalSection(&config_modules_cs
);
2835 if ((config_module
= get_config_module(lpNameW
, FALSE
))) {
2836 wine_rb_remove(&config_modules
, &config_module
->entry
);
2837 release_config_module(config_module
);
2839 LeaveCriticalSection(&config_modules_cs
);
2841 if (!create_printers_reg_key( system_printers_key
, &key
))
2843 RegDeleteTreeW( key
, lpNameW
);
2847 if (!create_printers_reg_key( user_printers_key
, &key
))
2849 RegDeleteValueW( key
, lpNameW
);
2853 if (!create_printers_reg_key( user_ports_key
, &key
))
2855 RegDeleteValueW( key
, lpNameW
);
2859 if (GetDefaultPrinterW( def
, &size
) && !wcscmp( def
, lpNameW
))
2861 if (!create_printers_reg_key( user_default_key
, &key
))
2863 RegDeleteValueW( key
, L
"device" );
2866 SetDefaultPrinterW( NULL
);
2872 /*****************************************************************************
2873 * SetPrinterA [WINSPOOL.@]
2875 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
2882 dataW
= printer_info_AtoW( data
, level
);
2883 if (!dataW
) return FALSE
;
2886 ret
= SetPrinterW( printer
, level
, dataW
, command
);
2888 if (dataW
!= data
) free_printer_info( dataW
, level
);
2893 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
2895 set_reg_szW( key
, L
"Name", pi
->pPrinterName
);
2896 set_reg_szW( key
, L
"Share Name", pi
->pShareName
);
2897 set_reg_szW( key
, L
"Port", pi
->pPortName
);
2898 set_reg_szW( key
, L
"Printer Driver", pi
->pDriverName
);
2899 set_reg_szW( key
, L
"Description", pi
->pComment
);
2900 set_reg_szW( key
, L
"Location", pi
->pLocation
);
2903 set_reg_devmode( key
, L
"Default DevMode", pi
->pDevMode
);
2905 set_reg_szW( key
, L
"Separator File", pi
->pSepFile
);
2906 set_reg_szW( key
, L
"Print Processor", pi
->pPrintProcessor
);
2907 set_reg_szW( key
, L
"Datatype", pi
->pDatatype
);
2908 set_reg_szW( key
, L
"Parameters", pi
->pParameters
);
2910 set_reg_DWORD( key
, L
"Attributes", pi
->Attributes
);
2911 set_reg_DWORD( key
, L
"Priority", pi
->Priority
);
2912 set_reg_DWORD( key
, L
"Default Priority", pi
->DefaultPriority
);
2913 set_reg_DWORD( key
, L
"StartTime", pi
->StartTime
);
2914 set_reg_DWORD( key
, L
"UntilTime", pi
->UntilTime
);
2917 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
2919 if (!pi
->pDevMode
) return FALSE
;
2921 set_reg_devmode( key
, L
"Default DevMode", pi
->pDevMode
);
2925 /******************************************************************************
2926 * SetPrinterW [WINSPOOL.@]
2928 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
2933 TRACE( "(%p, %ld, %p, %ld)\n", printer
, level
, data
, command
);
2935 if (command
!= 0) FIXME( "Ignoring command %ld\n", command
);
2937 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
2944 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
2945 set_printer_2( key
, pi2
);
2951 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
2952 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
2956 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
2957 ret
= set_printer_9( key
, pi
);
2962 FIXME( "Unimplemented level %ld\n", level
);
2963 SetLastError( ERROR_INVALID_LEVEL
);
2970 /*****************************************************************************
2971 * SetJobA [WINSPOOL.@]
2973 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2974 LPBYTE pJob
, DWORD Command
)
2978 UNICODE_STRING usBuffer
;
2980 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2982 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2983 are all ignored by SetJob, so we don't bother copying them */
2991 JOB_INFO_1W
*info1W
= malloc(sizeof(*info1W
));
2992 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
2994 JobW
= (LPBYTE
)info1W
;
2995 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
2996 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
2997 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
2998 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
2999 info1W
->Status
= info1A
->Status
;
3000 info1W
->Priority
= info1A
->Priority
;
3001 info1W
->Position
= info1A
->Position
;
3002 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3007 JOB_INFO_2W
*info2W
= malloc(sizeof(*info2W
));
3008 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3010 JobW
= (LPBYTE
)info2W
;
3011 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3012 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3013 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3014 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3015 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3016 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3017 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3018 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3019 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3020 info2W
->Status
= info2A
->Status
;
3021 info2W
->Priority
= info2A
->Priority
;
3022 info2W
->Position
= info2A
->Position
;
3023 info2W
->StartTime
= info2A
->StartTime
;
3024 info2W
->UntilTime
= info2A
->UntilTime
;
3025 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3029 JobW
= malloc(sizeof(JOB_INFO_3
));
3030 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3033 SetLastError(ERROR_INVALID_LEVEL
);
3037 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3043 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3044 free(info1W
->pUserName
);
3045 free(info1W
->pDocument
);
3046 free(info1W
->pDatatype
);
3047 free(info1W
->pStatus
);
3052 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3053 free(info2W
->pUserName
);
3054 free(info2W
->pDocument
);
3055 free(info2W
->pNotifyName
);
3056 free(info2W
->pDatatype
);
3057 free(info2W
->pPrintProcessor
);
3058 free(info2W
->pParameters
);
3059 heap_free(info2W
->pDevMode
);
3060 free(info2W
->pStatus
);
3069 /*****************************************************************************
3070 * SetJobW [WINSPOOL.@]
3072 BOOL WINAPI
SetJobW(HANDLE printer
, DWORD job_id
, DWORD level
,
3073 LPBYTE data
, DWORD command
)
3075 HANDLE handle
= get_backend_handle(printer
);
3077 TRACE("(%p, %ld, %ld, %p, %ld)\n", printer
, job_id
, level
, data
, command
);
3081 SetLastError(ERROR_INVALID_HANDLE
);
3085 return backend
->fpSetJob(handle
, job_id
, level
, data
, command
);
3088 /*****************************************************************************
3089 * EndDocPrinter [WINSPOOL.@]
3091 BOOL WINAPI
EndDocPrinter(HANDLE printer
)
3093 HANDLE handle
= get_backend_handle(printer
);
3095 TRACE("(%p)\n", printer
);
3099 SetLastError(ERROR_INVALID_HANDLE
);
3103 return backend
->fpEndDocPrinter(handle
);
3106 /*****************************************************************************
3107 * EndPagePrinter [WINSPOOL.@]
3109 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3111 FIXME("(%p): stub\n", hPrinter
);
3115 /*****************************************************************************
3116 * StartDocPrinterA [WINSPOOL.@]
3118 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3120 UNICODE_STRING usBuffer
;
3122 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3125 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3126 or one (DOC_INFO_3) extra DWORDs */
3130 doc2W
.JobId
= doc2
->JobId
;
3133 doc2W
.dwMode
= doc2
->dwMode
;
3136 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3137 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3138 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3142 SetLastError(ERROR_INVALID_LEVEL
);
3146 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3148 free(doc2W
.pDatatype
);
3149 free(doc2W
.pOutputFile
);
3150 free(doc2W
.pDocName
);
3155 /*****************************************************************************
3156 * StartDocPrinterW [WINSPOOL.@]
3158 DWORD WINAPI
StartDocPrinterW(HANDLE printer
, DWORD level
, BYTE
*doc_info
)
3160 HANDLE handle
= get_backend_handle(printer
);
3161 DOC_INFO_1W
*info
= (DOC_INFO_1W
*)doc_info
;
3163 TRACE("(%p, %ld, %p {%s, %s, %s})\n", printer
, level
, doc_info
,
3164 debugstr_w(info
->pDocName
), debugstr_w(info
->pOutputFile
),
3165 debugstr_w(info
->pDatatype
));
3169 SetLastError(ERROR_INVALID_HANDLE
);
3173 return backend
->fpStartDocPrinter(handle
, level
, doc_info
);
3176 /*****************************************************************************
3177 * StartPagePrinter [WINSPOOL.@]
3179 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3181 FIXME("(%p): stub\n", hPrinter
);
3185 /*****************************************************************************
3186 * GetFormA [WINSPOOL.@]
3188 BOOL WINAPI
GetFormA( HANDLE printer
, char *name
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
)
3190 UNICODE_STRING nameW
;
3191 const DWORD
*string_info
= form_string_info( level
);
3194 if (!string_info
) return FALSE
;
3196 asciitounicode( &nameW
, name
);
3198 ret
= GetFormW( printer
, nameW
.Buffer
, level
, form
, size
, needed
);
3199 if (ret
) packed_struct_WtoA( form
, string_info
);
3201 RtlFreeUnicodeString( &nameW
);
3205 /*****************************************************************************
3206 * GetFormW [WINSPOOL.@]
3208 BOOL WINAPI
GetFormW( HANDLE printer
, WCHAR
*name
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
)
3210 HANDLE handle
= get_backend_handle( printer
);
3212 TRACE( "(%p, %s, %ld, %p, %ld, %p)\n", printer
, debugstr_w( name
), level
, form
, size
, needed
);
3216 SetLastError( ERROR_INVALID_HANDLE
);
3220 return backend
->fpGetForm( handle
, name
, level
, form
, size
, needed
);
3223 /*****************************************************************************
3224 * SetFormA [WINSPOOL.@]
3226 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3229 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3233 /*****************************************************************************
3234 * SetFormW [WINSPOOL.@]
3236 BOOL WINAPI
SetFormW( HANDLE printer
, WCHAR
*name
, DWORD level
, BYTE
*form
)
3238 HANDLE handle
= get_backend_handle( printer
);
3240 TRACE( "(%p, %s, %ld, %p)\n", printer
, debugstr_w( name
), level
, form
);
3244 SetLastError( ERROR_INVALID_HANDLE
);
3248 return backend
->fpSetForm( handle
, name
, level
, form
);
3251 /*****************************************************************************
3252 * ReadPrinter [WINSPOOL.@]
3254 BOOL WINAPI
ReadPrinter(HANDLE printer
, void *buf
, DWORD size
, DWORD
*bytes_read
)
3256 HANDLE handle
= get_backend_handle(printer
);
3258 TRACE("(%p,%p,%ld,%p)\n", printer
, buf
, size
, bytes_read
);
3262 SetLastError( ERROR_INVALID_HANDLE
);
3266 return backend
->fpReadPrinter(handle
, buf
, size
, bytes_read
);
3269 /*****************************************************************************
3270 * ResetPrinterA [WINSPOOL.@]
3272 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3274 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3278 /*****************************************************************************
3279 * ResetPrinterW [WINSPOOL.@]
3281 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3283 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3287 /*****************************************************************************
3288 * get_filename_from_reg [internal]
3290 * Get ValueName from hkey storing result in out
3291 * when the Value in the registry has only a filename, use driverdir as prefix
3292 * outlen is space left in out
3293 * String is stored either as unicode or ansi
3297 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3298 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3300 WCHAR filename
[MAX_PATH
];
3304 LPWSTR buffer
= filename
;
3308 size
= sizeof(filename
);
3310 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3311 if (ret
== ERROR_MORE_DATA
) {
3312 TRACE("need dynamic buffer: %lu\n", size
);
3313 buffer
= malloc(size
);
3315 /* No Memory is bad */
3319 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3322 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3323 if (buffer
!= filename
) free(buffer
);
3329 /* do we have a full path ? */
3330 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3331 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3334 /* we must build the full Path */
3336 if ((out
) && (outlen
> dirlen
)) {
3337 wcscpy( (WCHAR
*)out
, driverdir
);
3345 /* write the filename */
3346 size
= (wcslen( ptr
) + 1) * sizeof(WCHAR
);
3347 if ((out
) && (outlen
>= size
)) {
3348 wcscpy( (WCHAR
*)out
, ptr
);
3355 ptr
+= wcslen( ptr
) + 1;
3356 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3359 if (buffer
!= filename
) free(buffer
);
3361 /* write the multisz-termination */
3362 if (type
== REG_MULTI_SZ
) {
3363 size
= sizeof(WCHAR
);
3366 if (out
&& (outlen
>= size
)) {
3367 memset (out
, 0, size
);
3373 /*****************************************************************************
3374 * WINSPOOL_GetStringFromReg
3376 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3377 * String is stored as unicode.
3379 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3380 DWORD buflen
, DWORD
*needed
)
3382 DWORD sz
= buflen
, type
;
3385 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3386 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3387 WARN("Got ret = %ld\n", ret
);
3391 /* add space for terminating '\0' */
3392 sz
+= sizeof(WCHAR
);
3396 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3401 /*****************************************************************************
3402 * WINSPOOL_GetDefaultDevMode
3404 * Get a default DevMode values for wineps.
3406 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr
, DWORD buflen
, DWORD
*needed
)
3408 if (buflen
>= sizeof(DEVMODEW
))
3410 DEVMODEW
*dm
= (DEVMODEW
*)ptr
;
3412 /* the driver will update registry with real values */
3413 memset(dm
, 0, sizeof(*dm
));
3414 dm
->dmSize
= sizeof(*dm
);
3415 wcscpy( dm
->dmDeviceName
, L
"wineps.drv" );
3417 *needed
= sizeof(DEVMODEW
);
3420 /*****************************************************************************
3421 * WINSPOOL_GetDevModeFromReg
3423 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3424 * DevMode is stored either as unicode or ansi.
3426 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3428 DWORD buflen
, DWORD
*needed
)
3430 DWORD sz
= buflen
, type
;
3433 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3434 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3435 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3436 if (sz
< sizeof(DEVMODEA
))
3438 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName
),sz
);
3441 /* ensures that dmSize is not erratically bogus if registry is invalid */
3442 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3443 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3444 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3445 if (ptr
&& (buflen
>= sz
)) {
3446 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3447 memcpy(ptr
, dmW
, sz
);
3454 /*********************************************************************
3455 * WINSPOOL_GetPrinter_1
3457 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3459 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3460 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3462 DWORD size
, left
= cbBuf
;
3463 BOOL space
= (cbBuf
> 0);
3468 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Name", ptr
, left
, &size
))
3470 if(space
&& size
<= left
) {
3471 pi1
->pName
= (LPWSTR
)ptr
;
3479 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3480 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Name", ptr
, left
, &size
))
3482 if(space
&& size
<= left
) {
3483 pi1
->pDescription
= (LPWSTR
)ptr
;
3491 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Description", ptr
, left
, &size
))
3493 if(space
&& size
<= left
) {
3494 pi1
->pComment
= (LPWSTR
)ptr
;
3502 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3504 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3505 memset(pi1
, 0, sizeof(*pi1
));
3509 /*********************************************************************
3510 * WINSPOOL_GetPrinter_2
3512 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3514 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3515 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3517 DWORD size
, left
= cbBuf
;
3518 BOOL space
= (cbBuf
> 0);
3523 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Name", ptr
, left
, &size
))
3525 if(space
&& size
<= left
) {
3526 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3533 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Share Name", ptr
, left
, &size
))
3535 if(space
&& size
<= left
) {
3536 pi2
->pShareName
= (LPWSTR
)ptr
;
3543 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Port", ptr
, left
, &size
))
3545 if(space
&& size
<= left
) {
3546 pi2
->pPortName
= (LPWSTR
)ptr
;
3553 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Printer Driver", ptr
, left
, &size
))
3555 if(space
&& size
<= left
) {
3556 pi2
->pDriverName
= (LPWSTR
)ptr
;
3563 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Description", ptr
, left
, &size
))
3565 if(space
&& size
<= left
) {
3566 pi2
->pComment
= (LPWSTR
)ptr
;
3573 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Location", ptr
, left
, &size
))
3575 if(space
&& size
<= left
) {
3576 pi2
->pLocation
= (LPWSTR
)ptr
;
3583 if (WINSPOOL_GetDevModeFromReg( hkeyPrinter
, L
"Default DevMode", ptr
, left
, &size
))
3585 if(space
&& size
<= left
) {
3586 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3595 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
3596 if(space
&& size
<= left
) {
3597 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3604 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Separator File", ptr
, left
, &size
))
3606 if(space
&& size
<= left
) {
3607 pi2
->pSepFile
= (LPWSTR
)ptr
;
3614 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Print Processor", ptr
, left
, &size
))
3616 if(space
&& size
<= left
) {
3617 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3624 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Datatype", ptr
, left
, &size
))
3626 if(space
&& size
<= left
) {
3627 pi2
->pDatatype
= (LPWSTR
)ptr
;
3634 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Parameters", ptr
, left
, &size
))
3636 if(space
&& size
<= left
) {
3637 pi2
->pParameters
= (LPWSTR
)ptr
;
3646 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, L
"Attributes" );
3647 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, L
"Priority" );
3648 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, L
"Default Priority" );
3649 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, L
"StartTime" );
3650 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, L
"UntilTime" );
3653 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3654 memset(pi2
, 0, sizeof(*pi2
));
3659 /*********************************************************************
3660 * WINSPOOL_GetPrinter_4
3662 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3664 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3665 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3667 DWORD size
, left
= cbBuf
;
3668 BOOL space
= (cbBuf
> 0);
3673 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Name", ptr
, left
, &size
))
3675 if(space
&& size
<= left
) {
3676 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3684 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, L
"Attributes" );
3687 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3688 memset(pi4
, 0, sizeof(*pi4
));
3693 /*********************************************************************
3694 * WINSPOOL_GetPrinter_5
3696 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3698 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3699 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3701 DWORD size
, left
= cbBuf
;
3702 BOOL space
= (cbBuf
> 0);
3707 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Name", ptr
, left
, &size
))
3709 if(space
&& size
<= left
) {
3710 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3717 if (WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"Port", ptr
, left
, &size
))
3719 if(space
&& size
<= left
) {
3720 pi5
->pPortName
= (LPWSTR
)ptr
;
3728 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, L
"Attributes" );
3729 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, L
"dnsTimeout" );
3730 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, L
"txTimeout" );
3733 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3734 memset(pi5
, 0, sizeof(*pi5
));
3739 /*********************************************************************
3740 * WINSPOOL_GetPrinter_7
3742 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3744 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3745 DWORD cbBuf
, LPDWORD pcbNeeded
)
3747 DWORD size
, left
= cbBuf
;
3748 BOOL space
= (cbBuf
> 0);
3753 if (!WINSPOOL_GetStringFromReg( hkeyPrinter
, L
"ObjectGUID", ptr
, left
, &size
))
3756 size
= sizeof(pi7
->pszObjectGUID
);
3758 if (space
&& size
<= left
) {
3759 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3766 /* We do not have a Directory Service */
3767 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3770 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3771 memset(pi7
, 0, sizeof(*pi7
));
3776 /*********************************************************************
3777 * WINSPOOL_GetPrinter_9
3779 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3781 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3782 DWORD cbBuf
, LPDWORD pcbNeeded
)
3785 BOOL space
= (cbBuf
> 0);
3789 if (WINSPOOL_GetDevModeFromReg( hkeyPrinter
, L
"Default DevMode", buf
, cbBuf
, &size
))
3791 if(space
&& size
<= cbBuf
) {
3792 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3799 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
3800 if(space
&& size
<= cbBuf
) {
3801 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3807 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3808 memset(pi9
, 0, sizeof(*pi9
));
3813 /*****************************************************************************
3814 * GetPrinterW [WINSPOOL.@]
3816 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3817 DWORD cbBuf
, LPDWORD pcbNeeded
)
3819 DWORD size
, needed
= 0, err
;
3824 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3826 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
3829 SetLastError( err
);
3836 PRINTER_INFO_1W
*pi1
= (PRINTER_INFO_1W
*)pPrinter
;
3838 size
= sizeof(PRINTER_INFO_1W
);
3839 if (size
<= cbBuf
) {
3840 ptr
= pPrinter
+ size
;
3842 memset(pPrinter
, 0, size
);
3847 ret
= WINSPOOL_GetPrinter_1(hkeyPrinter
, pi1
, ptr
, cbBuf
, &needed
);
3854 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3856 size
= sizeof(PRINTER_INFO_2W
);
3858 ptr
= pPrinter
+ size
;
3860 memset(pPrinter
, 0, size
);
3865 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
3872 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3874 size
= sizeof(PRINTER_INFO_4W
);
3876 ptr
= pPrinter
+ size
;
3878 memset(pPrinter
, 0, size
);
3883 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
3891 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3893 size
= sizeof(PRINTER_INFO_5W
);
3895 ptr
= pPrinter
+ size
;
3897 memset(pPrinter
, 0, size
);
3903 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
3911 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
3913 size
= sizeof(PRINTER_INFO_6
);
3914 if (size
<= cbBuf
) {
3915 /* FIXME: We do not update the status yet */
3916 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, L
"Status" );
3928 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
3930 size
= sizeof(PRINTER_INFO_7W
);
3931 if (size
<= cbBuf
) {
3932 ptr
= pPrinter
+ size
;
3934 memset(pPrinter
, 0, size
);
3940 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
3947 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
3948 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3952 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
3954 size
= sizeof(PRINTER_INFO_9W
);
3956 ptr
= pPrinter
+ size
;
3958 memset(pPrinter
, 0, size
);
3964 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
3971 FIXME("Unimplemented level %ld\n", Level
);
3972 SetLastError(ERROR_INVALID_LEVEL
);
3973 RegCloseKey(hkeyPrinter
);
3977 RegCloseKey(hkeyPrinter
);
3979 TRACE("returning %d needed = %ld\n", ret
, needed
);
3980 if(pcbNeeded
) *pcbNeeded
= needed
;
3982 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3986 /*****************************************************************************
3987 * GetPrinterA [WINSPOOL.@]
3989 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3990 DWORD cbBuf
, LPDWORD pcbNeeded
)
3996 buf
= malloc(cbBuf
);
3998 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4000 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4006 /*****************************************************************************
4007 * WINSPOOL_EnumPrintersW
4009 * Implementation of EnumPrintersW
4011 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4012 DWORD dwLevel
, LPBYTE lpbPrinters
,
4013 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4014 LPDWORD lpdwReturned
)
4017 HKEY printers_key
, hkeyPrinter
;
4018 WCHAR PrinterName
[255];
4019 DWORD needed
= 0, number
= 0;
4020 DWORD used
, i
, left
;
4024 memset(lpbPrinters
, 0, cbBuf
);
4030 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4031 if(dwType
== PRINTER_ENUM_DEFAULT
)
4034 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4035 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4036 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4038 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4044 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4045 FIXME("dwType = %08lx\n", dwType
);
4046 SetLastError(ERROR_INVALID_FLAGS
);
4050 if (create_printers_reg_key( system_printers_key
, &printers_key
))
4052 ERR("Can't create Printers key\n");
4056 if (RegQueryInfoKeyA( printers_key
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
))
4058 RegCloseKey( printers_key
);
4059 ERR("Can't query Printers key\n");
4062 TRACE("Found %ld printers\n", number
);
4066 used
= number
* sizeof(PRINTER_INFO_1W
);
4069 used
= number
* sizeof(PRINTER_INFO_2W
);
4072 used
= number
* sizeof(PRINTER_INFO_4W
);
4075 used
= number
* sizeof(PRINTER_INFO_5W
);
4079 SetLastError(ERROR_INVALID_LEVEL
);
4080 RegCloseKey( printers_key
);
4083 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4085 for(i
= 0; i
< number
; i
++) {
4086 if (RegEnumKeyW( printers_key
, i
, PrinterName
, ARRAY_SIZE(PrinterName
) ))
4088 ERR("Can't enum key number %ld\n", i
);
4089 RegCloseKey( printers_key
);
4092 TRACE("Printer %ld is %s\n", i
, debugstr_w(PrinterName
));
4093 if (RegOpenKeyW( printers_key
, PrinterName
, &hkeyPrinter
))
4095 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4096 RegCloseKey( printers_key
);
4101 buf
= lpbPrinters
+ used
;
4102 left
= cbBuf
- used
;
4110 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4113 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4116 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4119 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4122 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4125 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4128 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4131 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4134 ERR("Shouldn't be here!\n");
4135 RegCloseKey(hkeyPrinter
);
4136 RegCloseKey( printers_key
);
4139 RegCloseKey(hkeyPrinter
);
4141 RegCloseKey( printers_key
);
4148 memset(lpbPrinters
, 0, cbBuf
);
4149 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4153 *lpdwReturned
= number
;
4154 SetLastError(ERROR_SUCCESS
);
4159 /******************************************************************
4160 * EnumPrintersW [WINSPOOL.@]
4162 * Enumerates the available printers, print servers and print
4163 * providers, depending on the specified flags, name and level.
4167 * If level is set to 1:
4168 * Returns an array of PRINTER_INFO_1 data structures in the
4169 * lpbPrinters buffer.
4171 * If level is set to 2:
4172 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4173 * Returns an array of PRINTER_INFO_2 data structures in the
4174 * lpbPrinters buffer. Note that according to MSDN also an
4175 * OpenPrinter should be performed on every remote printer.
4177 * If level is set to 4 (officially WinNT only):
4178 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4179 * Fast: Only the registry is queried to retrieve printer names,
4180 * no connection to the driver is made.
4181 * Returns an array of PRINTER_INFO_4 data structures in the
4182 * lpbPrinters buffer.
4184 * If level is set to 5 (officially WinNT4/Win9x only):
4185 * Fast: Only the registry is queried to retrieve printer names,
4186 * no connection to the driver is made.
4187 * Returns an array of PRINTER_INFO_5 data structures in the
4188 * lpbPrinters buffer.
4190 * If level set to 3 or 6+:
4191 * returns zero (failure!)
4193 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4197 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4198 * - Only levels 2, 4 and 5 are implemented at the moment.
4199 * - 16-bit printer drivers are not enumerated.
4200 * - Returned amount of bytes used/needed does not match the real Windoze
4201 * implementation (as in this implementation, all strings are part
4202 * of the buffer, whereas Win32 keeps them somewhere else)
4203 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4206 * - In a regular Wine installation, no registry settings for printers
4207 * exist, which makes this function return an empty list.
4209 BOOL WINAPI
EnumPrintersW(
4210 DWORD dwType
, /* [in] Types of print objects to enumerate */
4211 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4212 DWORD dwLevel
, /* [in] type of printer info structure */
4213 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4214 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4215 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4216 LPDWORD lpdwReturned
/* [out] number of entries returned */
4219 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4220 lpdwNeeded
, lpdwReturned
);
4223 /******************************************************************
4224 * EnumPrintersA [WINSPOOL.@]
4229 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4230 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4233 UNICODE_STRING pNameU
;
4237 TRACE("(0x%lx, %s, %lu, %p, %ld, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4238 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4240 pNameW
= asciitounicode(&pNameU
, pName
);
4242 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4243 MS Office need this */
4244 pPrintersW
= (pPrinters
&& cbBuf
) ? malloc(cbBuf
) : NULL
;
4246 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4248 RtlFreeUnicodeString(&pNameU
);
4250 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4256 /*****************************************************************************
4257 * WINSPOOL_GetDriverInfoFromReg [internal]
4259 * Enters the information from the registry into the DRIVER_INFO struct
4262 * zero if the printer driver does not exist in the registry
4263 * (only if Level > 1) otherwise nonzero
4265 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4268 const printenv_t
* env
,
4270 LPBYTE ptr
, /* DRIVER_INFO */
4271 LPBYTE pDriverStrings
, /* strings buffer */
4272 DWORD cbBuf
, /* size of string buffer */
4273 LPDWORD pcbNeeded
) /* space needed for str. */
4277 WCHAR driverdir
[MAX_PATH
];
4279 LPBYTE strPtr
= pDriverStrings
;
4280 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4282 TRACE("(%p, %s, %p, %ld, %p, %p, %ld)\n", hkeyDrivers
,
4283 debugstr_w(DriverName
), env
,
4284 Level
, di
, pDriverStrings
, cbBuf
);
4286 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4288 *pcbNeeded
= (wcslen( DriverName
) + 1) * sizeof(WCHAR
);
4289 if (*pcbNeeded
<= cbBuf
)
4290 wcscpy( (WCHAR
*)strPtr
, DriverName
);
4292 /* pName for level 1 has a different offset! */
4294 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4298 /* .cVersion and .pName for level > 1 */
4300 di
->cVersion
= env
->driverversion
;
4301 di
->pName
= (LPWSTR
) strPtr
;
4302 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4305 /* Reserve Space for "\\3\\" + \0 */
4306 size
= sizeof(driverdir
) - 4 * sizeof(WCHAR
);
4307 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4308 /* Should never Fail */
4311 wcscat( driverdir
, env
->versionsubdir
);
4312 wcscat( driverdir
, L
"\\" );
4314 /* dirlen must not include the terminating zero */
4315 dirlen
= wcslen( driverdir
) * sizeof(WCHAR
);
4317 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4318 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4319 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4324 size
= (wcslen( env
->envname
) + 1) * sizeof(WCHAR
);
4327 if (*pcbNeeded
<= cbBuf
) {
4328 wcscpy( (WCHAR
*)strPtr
, env
->envname
);
4329 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4330 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4333 /* .pDriverPath is the Graphics rendering engine.
4334 The full Path is required to avoid a crash in some apps */
4335 if (get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Driver", strPtr
, 0, &size
))
4338 if (*pcbNeeded
<= cbBuf
)
4339 get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Driver", strPtr
, size
, &tmp
);
4341 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4342 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4345 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4346 if (get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Data File", strPtr
, 0, &size
))
4349 if (*pcbNeeded
<= cbBuf
)
4350 get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Data File", strPtr
, size
, &size
);
4352 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4353 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4356 /* .pConfigFile is the Driver user Interface */
4357 if (get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Configuration File", strPtr
, 0, &size
))
4360 if (*pcbNeeded
<= cbBuf
)
4361 get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Configuration File", strPtr
, size
, &size
);
4363 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4364 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4368 RegCloseKey(hkeyDriver
);
4369 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
4374 RegCloseKey(hkeyDriver
);
4375 FIXME("level 5: incomplete\n");
4380 if (get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Help File", strPtr
, 0, &size
))
4383 if (*pcbNeeded
<= cbBuf
)
4384 get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Help File", strPtr
, size
, &size
);
4386 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4387 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4390 /* .pDependentFiles */
4391 if (get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Dependent Files", strPtr
, 0, &size
))
4394 if (*pcbNeeded
<= cbBuf
)
4395 get_filename_from_reg( hkeyDriver
, driverdir
, dirlen
, L
"Dependent Files", strPtr
, size
, &size
);
4397 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4398 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4400 else if (GetVersion() & 0x80000000) {
4401 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4402 size
= 2 * sizeof(WCHAR
);
4404 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4406 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4407 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4410 /* .pMonitorName is the optional Language Monitor */
4411 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Monitor", strPtr
, 0, &size
))
4414 if (*pcbNeeded
<= cbBuf
)
4415 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Monitor", strPtr
, size
, &size
);
4417 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4418 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4421 /* .pDefaultDataType */
4422 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Datatype", strPtr
, 0, &size
))
4425 if(*pcbNeeded
<= cbBuf
)
4426 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Datatype", strPtr
, size
, &size
);
4428 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4429 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4433 RegCloseKey(hkeyDriver
);
4434 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
4438 /* .pszzPreviousNames */
4439 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Previous Names", strPtr
, 0, &size
))
4442 if(*pcbNeeded
<= cbBuf
)
4443 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Previous Names", strPtr
, size
, &size
);
4445 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4446 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4450 RegCloseKey(hkeyDriver
);
4451 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
4455 /* support is missing, but not important enough for a FIXME */
4456 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4459 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Manufacturer", strPtr
, 0, &size
))
4462 if(*pcbNeeded
<= cbBuf
)
4463 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Manufacturer", strPtr
, size
, &size
);
4465 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4466 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4470 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"OEM Url", strPtr
, 0, &size
))
4473 if(*pcbNeeded
<= cbBuf
)
4474 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"OEM Url", strPtr
, size
, &size
);
4476 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4477 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4480 /* .pszHardwareID */
4481 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"HardwareID", strPtr
, 0, &size
))
4484 if(*pcbNeeded
<= cbBuf
)
4485 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"HardwareID", strPtr
, size
, &size
);
4487 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4488 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4492 if (WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Provider", strPtr
, 0, &size
))
4495 if(*pcbNeeded
<= cbBuf
)
4496 WINSPOOL_GetStringFromReg( hkeyDriver
, L
"Provider", strPtr
, size
, &size
);
4498 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4499 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4503 RegCloseKey(hkeyDriver
);
4507 /* support is missing, but not important enough for a FIXME */
4508 TRACE("level 8: incomplete\n");
4510 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
4511 RegCloseKey(hkeyDriver
);
4515 /*****************************************************************************
4516 * GetPrinterDriverW [WINSPOOL.@]
4518 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4519 DWORD Level
, LPBYTE pDriverInfo
,
4520 DWORD cbBuf
, LPDWORD pcbNeeded
)
4523 WCHAR DriverName
[100];
4524 DWORD ret
, type
, size
, needed
= 0;
4526 HKEY hkeyPrinter
, hkeyDrivers
;
4527 const printenv_t
* env
;
4529 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4530 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4533 ZeroMemory(pDriverInfo
, cbBuf
);
4535 if (!(name
= get_opened_printer_name(hPrinter
))) {
4536 SetLastError(ERROR_INVALID_HANDLE
);
4540 if (Level
< 1 || Level
== 7 || Level
> 8) {
4541 SetLastError(ERROR_INVALID_LEVEL
);
4545 env
= validate_envW(pEnvironment
);
4546 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4548 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
4551 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
4552 SetLastError( ret
);
4556 size
= sizeof(DriverName
);
4558 ret
= RegQueryValueExW( hkeyPrinter
, L
"Printer Driver", 0, &type
, (BYTE
*)DriverName
, &size
);
4559 RegCloseKey(hkeyPrinter
);
4560 if(ret
!= ERROR_SUCCESS
) {
4561 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4565 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4567 ERR("Can't create Drivers key\n");
4571 size
= di_sizeof
[Level
];
4572 if ((size
<= cbBuf
) && pDriverInfo
)
4573 ptr
= pDriverInfo
+ size
;
4575 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4576 env
, Level
, pDriverInfo
, ptr
,
4577 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4579 RegCloseKey(hkeyDrivers
);
4583 RegCloseKey(hkeyDrivers
);
4585 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4586 TRACE("buffer space %ld required %ld\n", cbBuf
, size
+ needed
);
4587 if(cbBuf
>= size
+ needed
) return TRUE
;
4588 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4592 /*****************************************************************************
4593 * GetPrinterDriverA [WINSPOOL.@]
4595 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4596 DWORD Level
, LPBYTE pDriverInfo
,
4597 DWORD cbBuf
, LPDWORD pcbNeeded
)
4600 UNICODE_STRING pEnvW
;
4606 ZeroMemory(pDriverInfo
, cbBuf
);
4607 buf
= malloc(cbBuf
);
4610 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4611 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
4614 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
4618 RtlFreeUnicodeString(&pEnvW
);
4622 /*****************************************************************************
4623 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4625 * Return the PATH for the Printer-Drivers (UNICODE)
4628 * pName [I] Servername (NT only) or NULL (local Computer)
4629 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4630 * Level [I] Structure-Level (must be 1)
4631 * pDriverDirectory [O] PTR to Buffer that receives the Result
4632 * cbBuf [I] Size of Buffer at pDriverDirectory
4633 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4634 * required for pDriverDirectory
4637 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4638 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4639 * if cbBuf is too small
4641 * Native Values returned in pDriverDirectory on Success:
4642 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4643 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4644 *| win9x(Windows 4.0): "%winsysdir%"
4646 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4649 *- Only NULL or "" is supported for pName
4652 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4653 DWORD Level
, LPBYTE pDriverDirectory
,
4654 DWORD cbBuf
, LPDWORD pcbNeeded
)
4656 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
),
4657 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4659 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4662 /* (Level != 1) is ignored in win9x */
4663 SetLastError(ERROR_INVALID_LEVEL
);
4666 if (pcbNeeded
== NULL
) {
4667 /* (pcbNeeded == NULL) is ignored in win9x */
4668 SetLastError(RPC_X_NULL_REF_POINTER
);
4672 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4673 pDriverDirectory
, cbBuf
, pcbNeeded
);
4678 /*****************************************************************************
4679 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4681 * Return the PATH for the Printer-Drivers (ANSI)
4683 * See GetPrinterDriverDirectoryW.
4686 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4689 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4690 DWORD Level
, LPBYTE pDriverDirectory
,
4691 DWORD cbBuf
, LPDWORD pcbNeeded
)
4693 UNICODE_STRING nameW
, environmentW
;
4696 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4697 WCHAR
*driverDirectoryW
= NULL
;
4699 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName
),
4700 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4702 if (len
) driverDirectoryW
= malloc( len
);
4704 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4705 else nameW
.Buffer
= NULL
;
4706 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4707 else environmentW
.Buffer
= NULL
;
4709 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4710 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4713 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4714 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4716 *pcbNeeded
= needed
;
4717 ret
= needed
<= cbBuf
;
4719 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4721 TRACE("required: 0x%lx/%ld\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4723 free( driverDirectoryW
);
4724 RtlFreeUnicodeString(&environmentW
);
4725 RtlFreeUnicodeString(&nameW
);
4730 /*****************************************************************************
4731 * AddPrinterDriverA [WINSPOOL.@]
4733 * See AddPrinterDriverW.
4736 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4738 TRACE("(%s, %ld, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4739 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4742 /******************************************************************************
4743 * AddPrinterDriverW (WINSPOOL.@)
4745 * Install a Printer Driver
4748 * pName [I] Servername or NULL (local Computer)
4749 * level [I] Level for the supplied DRIVER_INFO_*W struct
4750 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4757 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4759 TRACE("(%s, %ld, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4760 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4763 /*****************************************************************************
4764 * AddPrintProcessorA [WINSPOOL.@]
4766 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4767 LPSTR pPrintProcessorName
)
4769 UNICODE_STRING NameW
, EnvW
, PathW
, ProcessorW
;
4772 TRACE("(%s,%s,%s,%s)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4773 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4775 asciitounicode(&NameW
, pName
);
4776 asciitounicode(&EnvW
, pEnvironment
);
4777 asciitounicode(&PathW
, pPathName
);
4778 asciitounicode(&ProcessorW
, pPrintProcessorName
);
4780 ret
= AddPrintProcessorW(NameW
.Buffer
, EnvW
.Buffer
, PathW
.Buffer
, ProcessorW
.Buffer
);
4782 RtlFreeUnicodeString(&ProcessorW
);
4783 RtlFreeUnicodeString(&PathW
);
4784 RtlFreeUnicodeString(&EnvW
);
4785 RtlFreeUnicodeString(&NameW
);
4790 /*****************************************************************************
4791 * AddPrintProcessorW [WINSPOOL.@]
4793 BOOL WINAPI
AddPrintProcessorW(WCHAR
*name
, WCHAR
*env
, WCHAR
*path
, WCHAR
*print_proc
)
4795 TRACE("(%s,%s,%s,%s)\n", debugstr_w(name
), debugstr_w(env
),
4796 debugstr_w(path
), debugstr_w(print_proc
));
4798 if (!path
|| !print_proc
)
4800 SetLastError(ERROR_INVALID_PARAMETER
);
4804 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4805 return backend
->fpAddPrintProcessor(name
, env
, path
, print_proc
);
4808 /*****************************************************************************
4809 * AddPrintProvidorA [WINSPOOL.@]
4811 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4813 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4817 /*****************************************************************************
4818 * AddPrintProvidorW [WINSPOOL.@]
4820 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4822 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4826 /*****************************************************************************
4827 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4829 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4830 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4832 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4833 pDevModeOutput
, pDevModeInput
);
4837 /*****************************************************************************
4838 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4840 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4841 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4843 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4844 pDevModeOutput
, pDevModeInput
);
4848 /*****************************************************************************
4849 * PrinterProperties [WINSPOOL.@]
4851 * Displays a dialog to set the properties of the printer.
4854 * nonzero on success or zero on failure
4857 * implemented as stub only
4859 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4860 HANDLE hPrinter
/* [in] handle to printer object */
4862 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4863 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4867 /*****************************************************************************
4868 * EnumJobsA [WINSPOOL.@]
4871 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4872 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4875 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4876 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4878 if(pcbNeeded
) *pcbNeeded
= 0;
4879 if(pcReturned
) *pcReturned
= 0;
4884 /*****************************************************************************
4885 * EnumJobsW [WINSPOOL.@]
4888 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4889 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4892 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4893 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4895 if(pcbNeeded
) *pcbNeeded
= 0;
4896 if(pcReturned
) *pcReturned
= 0;
4900 /*****************************************************************************
4901 * WINSPOOL_EnumPrinterDrivers [internal]
4903 * Delivers information about all printer drivers installed on the
4904 * localhost or a given server
4907 * nonzero on success or zero on failure. If the buffer for the returned
4908 * information is too small the function will return an error
4911 * - only implemented for localhost, foreign hosts will return an error
4913 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4914 DWORD Level
, LPBYTE pDriverInfo
,
4916 DWORD cbBuf
, LPDWORD pcbNeeded
,
4917 LPDWORD pcFound
, DWORD data_offset
)
4921 const printenv_t
* env
;
4923 TRACE("%s,%s,%ld,%p,%ld,%ld,%ld\n",
4924 debugstr_w(pName
), debugstr_w(pEnvironment
),
4925 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
4927 env
= validate_envW(pEnvironment
);
4928 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4932 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4934 ERR("Can't open Drivers key\n");
4938 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
4939 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4940 RegCloseKey(hkeyDrivers
);
4941 ERR("Can't query Drivers key\n");
4944 TRACE("Found %ld Drivers\n", *pcFound
);
4946 /* get size of single struct
4947 * unicode and ascii structure have the same size
4949 size
= di_sizeof
[Level
];
4951 if (data_offset
== 0)
4952 data_offset
= size
* (*pcFound
);
4953 *pcbNeeded
= data_offset
;
4955 for( i
= 0; i
< *pcFound
; i
++) {
4956 WCHAR DriverNameW
[255];
4957 PBYTE table_ptr
= NULL
;
4958 PBYTE data_ptr
= NULL
;
4961 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, ARRAY_SIZE(DriverNameW
)) != ERROR_SUCCESS
) {
4962 ERR("Can't enum key number %ld\n", i
);
4963 RegCloseKey(hkeyDrivers
);
4967 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
4968 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
4969 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
4970 data_ptr
= pDriverInfo
+ *pcbNeeded
;
4972 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4973 env
, Level
, table_ptr
, data_ptr
,
4974 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4976 RegCloseKey(hkeyDrivers
);
4980 *pcbNeeded
+= needed
;
4983 RegCloseKey(hkeyDrivers
);
4985 if(cbBuf
< *pcbNeeded
){
4986 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4993 /*****************************************************************************
4994 * EnumPrinterDriversW [WINSPOOL.@]
4996 * see function EnumPrinterDrivers for RETURNS, BUGS
4998 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4999 LPBYTE pDriverInfo
, DWORD cbBuf
,
5000 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5005 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5007 SetLastError(RPC_X_NULL_REF_POINTER
);
5011 /* check for local drivers */
5012 if((pName
) && (pName
[0])) {
5013 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5014 SetLastError(ERROR_ACCESS_DENIED
);
5018 /* check input parameter */
5019 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5020 SetLastError(ERROR_INVALID_LEVEL
);
5024 if(pDriverInfo
&& cbBuf
> 0)
5025 memset( pDriverInfo
, 0, cbBuf
);
5027 /* Exception: pull all printers */
5028 if (pEnvironment
&& !wcscmp( pEnvironment
, L
"all" ))
5030 DWORD i
, needed
, bufsize
= cbBuf
;
5031 DWORD total_found
= 0;
5034 /* Precompute the overall total; we need this to know
5035 where pointers end and data begins (i.e. data_offset) */
5036 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5039 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5040 NULL
, 0, 0, &needed
, &found
, 0);
5041 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5042 total_found
+= found
;
5045 data_offset
= di_sizeof
[Level
] * total_found
;
5050 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5053 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5054 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5055 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5057 *pcReturned
+= found
;
5058 *pcbNeeded
= needed
;
5059 data_offset
= needed
;
5060 total_found
+= found
;
5065 /* Normal behavior */
5066 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5067 0, cbBuf
, pcbNeeded
, &found
, 0);
5069 *pcReturned
= found
;
5074 /*****************************************************************************
5075 * EnumPrinterDriversA [WINSPOOL.@]
5077 * see function EnumPrinterDrivers for RETURNS, BUGS
5079 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5080 LPBYTE pDriverInfo
, DWORD cbBuf
,
5081 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5084 UNICODE_STRING pNameW
, pEnvironmentW
;
5085 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5089 buf
= malloc(cbBuf
);
5091 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5092 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5094 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5095 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5097 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5101 RtlFreeUnicodeString(&pNameW
);
5102 RtlFreeUnicodeString(&pEnvironmentW
);
5107 /******************************************************************************
5108 * EnumPortsA (WINSPOOL.@)
5113 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5114 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5117 LPBYTE bufferW
= NULL
;
5118 LPWSTR nameW
= NULL
;
5120 DWORD numentries
= 0;
5123 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5124 cbBuf
, pcbNeeded
, pcReturned
);
5126 /* convert servername to unicode */
5128 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5129 nameW
= malloc(len
* sizeof(WCHAR
));
5130 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5132 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5133 needed
= cbBuf
* sizeof(WCHAR
);
5134 if (needed
) bufferW
= malloc(needed
);
5135 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5137 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5138 if (pcbNeeded
) needed
= *pcbNeeded
;
5139 /* HeapReAlloc return NULL, when bufferW was NULL */
5140 bufferW
= (bufferW
) ? realloc(bufferW
, needed
) : malloc(needed
);
5142 /* Try again with the large Buffer */
5143 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5145 needed
= pcbNeeded
? *pcbNeeded
: 0;
5146 numentries
= pcReturned
? *pcReturned
: 0;
5149 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5150 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5153 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5154 DWORD entrysize
= 0;
5157 LPPORT_INFO_2W pi2w
;
5158 LPPORT_INFO_2A pi2a
;
5161 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5163 /* First pass: calculate the size for all Entries */
5164 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5165 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5167 while (index
< numentries
) {
5169 needed
+= entrysize
; /* PORT_INFO_?A */
5170 TRACE("%p: parsing #%ld (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5172 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5173 NULL
, 0, NULL
, NULL
);
5175 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5176 NULL
, 0, NULL
, NULL
);
5177 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5178 NULL
, 0, NULL
, NULL
);
5180 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5181 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5182 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5185 /* check for errors and quit on failure */
5186 if (cbBuf
< needed
) {
5187 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5191 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5192 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5193 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5194 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5195 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5197 /* Second Pass: Fill the User Buffer (if we have one) */
5198 while ((index
< numentries
) && pPorts
) {
5200 TRACE("%p: writing PORT_INFO_%ldA #%ld\n", pi2a
, Level
, index
);
5201 pi2a
->pPortName
= ptr
;
5202 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5203 ptr
, cbBuf
, NULL
, NULL
);
5207 pi2a
->pMonitorName
= ptr
;
5208 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5209 ptr
, cbBuf
, NULL
, NULL
);
5213 pi2a
->pDescription
= ptr
;
5214 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5215 ptr
, cbBuf
, NULL
, NULL
);
5219 pi2a
->fPortType
= pi2w
->fPortType
;
5220 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5223 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5224 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5225 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5230 if (pcbNeeded
) *pcbNeeded
= needed
;
5231 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5236 TRACE("returning %d with %ld (%ld byte for %ld of %ld entries)\n",
5237 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5243 /******************************************************************************
5244 * EnumPortsW (WINSPOOL.@)
5246 * Enumerate available Ports
5249 * pName [I] Servername or NULL (local Computer)
5250 * Level [I] Structure-Level (1 or 2)
5251 * pPorts [O] PTR to Buffer that receives the Result
5252 * cbBuf [I] Size of Buffer at pPorts
5253 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5254 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5258 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5261 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5264 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5265 cbBuf
, pcbNeeded
, pcReturned
);
5267 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5269 /* Level is not checked in win9x */
5270 if (!Level
|| (Level
> 2)) {
5271 WARN("level (%ld) is ignored in win9x\n", Level
);
5272 SetLastError(ERROR_INVALID_LEVEL
);
5275 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5276 SetLastError(RPC_X_NULL_REF_POINTER
);
5280 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5283 /******************************************************************************
5284 * GetDefaultPrinterW (WINSPOOL.@)
5287 * This function must read the value from data 'device' of key
5288 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5290 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5294 WCHAR
*buffer
, *ptr
;
5298 SetLastError(ERROR_INVALID_PARAMETER
);
5302 /* make the buffer big enough for the stuff from the profile/registry,
5303 * the content must fit into the local buffer to compute the correct
5304 * size even if the extern buffer is too small or not given.
5305 * (20 for ,driver,port) */
5307 len
= max(100, (insize
+ 20));
5308 buffer
= malloc( len
* sizeof(WCHAR
));
5310 if (!GetProfileStringW( L
"windows", L
"device", L
"", buffer
, len
))
5312 SetLastError (ERROR_FILE_NOT_FOUND
);
5316 TRACE("%s\n", debugstr_w(buffer
));
5318 if ((ptr
= wcschr( buffer
, ',' )) == NULL
)
5320 SetLastError(ERROR_INVALID_NAME
);
5326 *namesize
= wcslen( buffer
) + 1;
5327 if(!name
|| (*namesize
> insize
))
5329 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5333 wcscpy( name
, buffer
);
5341 /******************************************************************************
5342 * GetDefaultPrinterA (WINSPOOL.@)
5344 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5348 WCHAR
*bufferW
= NULL
;
5352 SetLastError(ERROR_INVALID_PARAMETER
);
5356 if(name
&& *namesize
) {
5358 bufferW
= malloc( insize
* sizeof(WCHAR
));
5361 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5366 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5370 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5373 TRACE("0x%08lx/0x%08lx:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5381 /******************************************************************************
5382 * SetDefaultPrinterW (WINSPOOL.204)
5384 * Set the Name of the Default Printer
5387 * pszPrinter [I] Name of the Printer or NULL
5394 * When the Parameter is NULL or points to an Empty String and
5395 * a Default Printer was already present, then this Function changes nothing.
5396 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5397 * the First enumerated local Printer is used.
5400 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5402 WCHAR default_printer
[MAX_PATH
];
5403 LPWSTR buffer
= NULL
;
5409 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5410 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5412 default_printer
[0] = '\0';
5413 size
= ARRAY_SIZE(default_printer
);
5415 /* if we have a default Printer, do nothing. */
5416 if (GetDefaultPrinterW(default_printer
, &size
))
5420 /* we have no default Printer: search local Printers and use the first */
5421 if (!create_printers_reg_key( system_printers_key
, &hreg
))
5423 default_printer
[0] = '\0';
5424 size
= ARRAY_SIZE(default_printer
);
5425 if (!RegEnumKeyExW( hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
))
5427 pszPrinter
= default_printer
;
5428 TRACE("using %s\n", debugstr_w(pszPrinter
));
5430 RegCloseKey( hreg
);
5433 if (pszPrinter
== NULL
) {
5434 TRACE("no local printer found\n");
5435 SetLastError(ERROR_FILE_NOT_FOUND
);
5440 /* "pszPrinter" is never empty or NULL here. */
5441 namelen
= wcslen( pszPrinter
);
5442 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5443 buffer
= malloc(size
* sizeof(WCHAR
));
5444 if (!buffer
|| create_printers_reg_key( user_printers_key
, &hreg
))
5447 SetLastError(ERROR_FILE_NOT_FOUND
);
5451 /* read the devices entry for the printer (driver,port) to build the string for the
5452 default device entry (printer,driver,port) */
5453 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5454 buffer
[namelen
] = ',';
5455 namelen
++; /* move index to the start of the driver */
5457 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5458 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5462 if (!create_printers_reg_key( user_default_key
, &hdev
))
5464 RegSetValueExW( hdev
, L
"device", 0, REG_SZ
, (BYTE
*)buffer
, (wcslen( buffer
) + 1) * sizeof(WCHAR
) );
5470 if (lres
!= ERROR_FILE_NOT_FOUND
)
5471 FIXME("RegQueryValueExW failed with %ld for %s\n", lres
, debugstr_w(pszPrinter
));
5473 SetLastError(ERROR_INVALID_PRINTER_NAME
);
5478 return (lres
== ERROR_SUCCESS
);
5481 /******************************************************************************
5482 * SetDefaultPrinterA (WINSPOOL.202)
5484 * See SetDefaultPrinterW.
5487 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5489 LPWSTR bufferW
= NULL
;
5492 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5494 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
5495 bufferW
= malloc(len
* sizeof(WCHAR
));
5496 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
5498 res
= SetDefaultPrinterW(bufferW
);
5503 /******************************************************************************
5504 * SetPrinterDataExA (WINSPOOL.@)
5506 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5507 LPCSTR pValueName
, DWORD Type
,
5508 LPBYTE pData
, DWORD cbData
)
5510 HKEY hkeyPrinter
, hkeySubkey
;
5513 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_a(pKeyName
),
5514 debugstr_a(pValueName
), Type
, pData
, cbData
);
5516 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5520 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5522 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5523 RegCloseKey(hkeyPrinter
);
5526 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5527 RegCloseKey(hkeySubkey
);
5528 RegCloseKey(hkeyPrinter
);
5532 /******************************************************************************
5533 * SetPrinterDataExW (WINSPOOL.@)
5535 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5536 LPCWSTR pValueName
, DWORD Type
,
5537 LPBYTE pData
, DWORD cbData
)
5539 HKEY hkeyPrinter
, hkeySubkey
;
5542 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_w(pKeyName
),
5543 debugstr_w(pValueName
), Type
, pData
, cbData
);
5545 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5549 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5551 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5552 RegCloseKey(hkeyPrinter
);
5555 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5556 RegCloseKey(hkeySubkey
);
5557 RegCloseKey(hkeyPrinter
);
5561 /******************************************************************************
5562 * SetPrinterDataA (WINSPOOL.@)
5564 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5565 LPBYTE pData
, DWORD cbData
)
5567 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5571 /******************************************************************************
5572 * SetPrinterDataW (WINSPOOL.@)
5574 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5575 LPBYTE pData
, DWORD cbData
)
5577 return SetPrinterDataExW( hPrinter
, L
"PrinterDriverData", pValueName
, Type
,
5581 /******************************************************************************
5582 * GetPrinterDataExA (WINSPOOL.@)
5584 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5585 LPCSTR pValueName
, LPDWORD pType
,
5586 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5588 opened_printer_t
*printer
;
5589 HKEY printers_key
, hkeyPrinter
= 0, hkeySubkey
= 0;
5592 TRACE("(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter
, debugstr_a(pKeyName
),
5593 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5595 printer
= get_opened_printer(hPrinter
);
5596 if(!printer
) return ERROR_INVALID_HANDLE
;
5598 ret
= create_printers_reg_key( system_printers_key
, &printers_key
);
5599 if (ret
) return ret
;
5601 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5603 if (printer
->name
) {
5605 ret
= RegOpenKeyW( printers_key
, printer
->name
, &hkeyPrinter
);
5608 RegCloseKey( printers_key
);
5611 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5612 WARN("Can't open subkey %s: %ld\n", debugstr_a(pKeyName
), ret
);
5613 RegCloseKey(hkeyPrinter
);
5614 RegCloseKey( printers_key
);
5619 ret
= RegQueryValueExA( printer
->name
? hkeySubkey
: printers_key
, pValueName
,
5620 0, pType
, pData
, pcbNeeded
);
5622 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5624 RegCloseKey(hkeySubkey
);
5625 RegCloseKey(hkeyPrinter
);
5626 RegCloseKey( printers_key
);
5628 TRACE("--> %ld\n", ret
);
5632 /******************************************************************************
5633 * GetPrinterDataExW (WINSPOOL.@)
5635 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5636 LPCWSTR pValueName
, LPDWORD pType
,
5637 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5639 opened_printer_t
*printer
;
5640 HKEY printers_key
, hkeyPrinter
= 0, hkeySubkey
= 0;
5643 TRACE("(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter
, debugstr_w(pKeyName
),
5644 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5646 printer
= get_opened_printer(hPrinter
);
5647 if(!printer
) return ERROR_INVALID_HANDLE
;
5649 ret
= create_printers_reg_key( system_printers_key
, &printers_key
);
5650 if (ret
) return ret
;
5652 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5656 ret
= RegOpenKeyW( printers_key
, printer
->name
, &hkeyPrinter
);
5659 RegCloseKey( printers_key
);
5662 if ((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
)
5664 WARN("Can't open subkey %s: %ld\n", debugstr_w(pKeyName
), ret
);
5665 RegCloseKey(hkeyPrinter
);
5666 RegCloseKey( printers_key
);
5671 ret
= RegQueryValueExW( printer
->name
? hkeySubkey
: printers_key
, pValueName
,
5672 0, pType
, pData
, pcbNeeded
);
5674 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5676 RegCloseKey(hkeySubkey
);
5677 RegCloseKey(hkeyPrinter
);
5678 RegCloseKey( printers_key
);
5680 TRACE("--> %ld\n", ret
);
5684 /******************************************************************************
5685 * GetPrinterDataA (WINSPOOL.@)
5687 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5688 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5690 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5691 pData
, nSize
, pcbNeeded
);
5694 /******************************************************************************
5695 * GetPrinterDataW (WINSPOOL.@)
5697 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5698 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5700 return GetPrinterDataExW( hPrinter
, L
"PrinterDriverData", pValueName
, pType
,
5701 pData
, nSize
, pcbNeeded
);
5704 /*******************************************************************************
5705 * EnumPrinterDataExW [WINSPOOL.@]
5707 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5708 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5709 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5711 HKEY hkPrinter
, hkSubKey
;
5712 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5713 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5717 PPRINTER_ENUM_VALUESW ppev
;
5719 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5721 if (pKeyName
== NULL
|| *pKeyName
== 0)
5722 return ERROR_INVALID_PARAMETER
;
5724 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5725 if (ret
!= ERROR_SUCCESS
)
5727 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
5732 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5733 if (ret
!= ERROR_SUCCESS
)
5735 r
= RegCloseKey (hkPrinter
);
5736 if (r
!= ERROR_SUCCESS
)
5737 WARN ("RegCloseKey returned %li\n", r
);
5738 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter
,
5739 debugstr_w (pKeyName
), ret
);
5743 ret
= RegCloseKey (hkPrinter
);
5744 if (ret
!= ERROR_SUCCESS
)
5746 ERR ("RegCloseKey returned %li\n", ret
);
5747 r
= RegCloseKey (hkSubKey
);
5748 if (r
!= ERROR_SUCCESS
)
5749 WARN ("RegCloseKey returned %li\n", r
);
5753 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5754 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5755 if (ret
!= ERROR_SUCCESS
)
5757 r
= RegCloseKey (hkSubKey
);
5758 if (r
!= ERROR_SUCCESS
)
5759 WARN ("RegCloseKey returned %li\n", r
);
5760 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey
, ret
);
5764 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
5765 "cbMaxValueLen = %li\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5767 if (cValues
== 0) /* empty key */
5769 r
= RegCloseKey (hkSubKey
);
5770 if (r
!= ERROR_SUCCESS
)
5771 WARN ("RegCloseKey returned %li\n", r
);
5772 *pcbEnumValues
= *pnEnumValues
= 0;
5773 return ERROR_SUCCESS
;
5776 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5778 lpValueName
= malloc (cbMaxValueNameLen
* sizeof(WCHAR
));
5779 if (lpValueName
== NULL
)
5781 ERR ("Failed to allocate %li WCHARs\n", cbMaxValueNameLen
);
5782 r
= RegCloseKey (hkSubKey
);
5783 if (r
!= ERROR_SUCCESS
)
5784 WARN ("RegCloseKey returned %li\n", r
);
5785 return ERROR_OUTOFMEMORY
;
5788 lpValue
= malloc (cbMaxValueLen
);
5789 if (lpValue
== NULL
)
5791 ERR ("Failed to allocate %li bytes\n", cbMaxValueLen
);
5793 r
= RegCloseKey (hkSubKey
);
5794 if (r
!= ERROR_SUCCESS
)
5795 WARN ("RegCloseKey returned %li\n", r
);
5796 return ERROR_OUTOFMEMORY
;
5799 TRACE ("pass 1: calculating buffer required for all names and values\n");
5801 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5803 TRACE ("%li bytes required for %li headers\n", cbBufSize
, cValues
);
5805 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5807 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5808 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5809 NULL
, NULL
, lpValue
, &cbValueLen
);
5810 if (ret
!= ERROR_SUCCESS
)
5814 r
= RegCloseKey (hkSubKey
);
5815 if (r
!= ERROR_SUCCESS
)
5816 WARN ("RegCloseKey returned %li\n", r
);
5817 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
5821 TRACE ("%s [%li]: name needs %li WCHARs, data needs %li bytes\n",
5822 debugstr_w (lpValueName
), dwIndex
,
5823 cbValueNameLen
+ 1, cbValueLen
);
5825 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5826 cbBufSize
+= cbValueLen
;
5829 TRACE ("%li bytes required for all %li values\n", cbBufSize
, cValues
);
5831 *pcbEnumValues
= cbBufSize
;
5832 *pnEnumValues
= cValues
;
5834 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5838 r
= RegCloseKey (hkSubKey
);
5839 if (r
!= ERROR_SUCCESS
)
5840 WARN ("RegCloseKey returned %li\n", r
);
5841 TRACE ("%li byte buffer is not large enough\n", cbEnumValues
);
5842 return ERROR_MORE_DATA
;
5845 TRACE ("pass 2: copying all names and values to buffer\n");
5847 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5848 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5850 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5852 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5853 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5854 NULL
, &dwType
, lpValue
, &cbValueLen
);
5855 if (ret
!= ERROR_SUCCESS
)
5859 r
= RegCloseKey (hkSubKey
);
5860 if (r
!= ERROR_SUCCESS
)
5861 WARN ("RegCloseKey returned %li\n", r
);
5862 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
5866 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5867 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5868 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5869 pEnumValues
+= cbValueNameLen
;
5871 /* return # of *bytes* (including trailing \0), not # of chars */
5872 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5874 ppev
[dwIndex
].dwType
= dwType
;
5876 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5877 ppev
[dwIndex
].pData
= pEnumValues
;
5878 pEnumValues
+= cbValueLen
;
5880 ppev
[dwIndex
].cbData
= cbValueLen
;
5882 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
5883 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5889 ret
= RegCloseKey (hkSubKey
);
5890 if (ret
!= ERROR_SUCCESS
)
5892 ERR ("RegCloseKey returned %li\n", ret
);
5896 return ERROR_SUCCESS
;
5899 /*******************************************************************************
5900 * EnumPrinterDataExA [WINSPOOL.@]
5902 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5903 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5904 * what Windows 2000 SP1 does.
5907 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5908 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5909 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5913 DWORD ret
, dwIndex
, dwBufSize
;
5916 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5918 if (pKeyName
== NULL
|| *pKeyName
== 0)
5919 return ERROR_INVALID_PARAMETER
;
5921 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5924 ret
= GetLastError ();
5925 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
5929 pKeyNameW
= malloc (len
* sizeof(WCHAR
));
5930 if (pKeyNameW
== NULL
)
5932 ERR ("Failed to allocate %li bytes\n",
5933 (LONG
)(len
* sizeof (WCHAR
)));
5934 return ERROR_OUTOFMEMORY
;
5937 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5939 ret
= GetLastError ();
5940 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
5945 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5946 pcbEnumValues
, pnEnumValues
);
5948 if (ret
!= ERROR_SUCCESS
)
5950 TRACE ("EnumPrinterDataExW returned %li\n", ret
);
5954 if (*pnEnumValues
== 0) /* empty key */
5955 return ERROR_SUCCESS
;
5958 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5960 PPRINTER_ENUM_VALUESW ppev
=
5961 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5963 if (dwBufSize
< ppev
->cbValueName
)
5964 dwBufSize
= ppev
->cbValueName
;
5966 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5967 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5968 dwBufSize
= ppev
->cbData
;
5971 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize
);
5973 pBuffer
= malloc(dwBufSize
);
5974 if (pBuffer
== NULL
)
5976 ERR ("Failed to allocate %li bytes\n", dwBufSize
);
5977 return ERROR_OUTOFMEMORY
;
5980 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5982 PPRINTER_ENUM_VALUESW ppev
=
5983 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5985 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5986 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5990 ret
= GetLastError ();
5991 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
5996 memcpy (ppev
->pValueName
, pBuffer
, len
);
5998 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer
);
6000 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6001 ppev
->dwType
!= REG_MULTI_SZ
)
6004 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6005 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6008 ret
= GetLastError ();
6009 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
6014 memcpy (ppev
->pData
, pBuffer
, len
);
6016 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer
);
6017 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6021 return ERROR_SUCCESS
;
6024 /******************************************************************************
6025 * AbortPrinter (WINSPOOL.@)
6027 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6029 FIXME("(%p), stub!\n", hPrinter
);
6033 /******************************************************************************
6034 * AddPortA (WINSPOOL.@)
6039 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6041 LPWSTR nameW
= NULL
;
6042 LPWSTR monitorW
= NULL
;
6046 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6049 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6050 nameW
= malloc(len
* sizeof(WCHAR
));
6051 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6055 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6056 monitorW
= malloc(len
* sizeof(WCHAR
));
6057 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6059 res
= AddPortW(nameW
, hWnd
, monitorW
);
6065 /******************************************************************************
6066 * AddPortW (WINSPOOL.@)
6068 * Add a Port for a specific Monitor
6071 * pName [I] Servername or NULL (local Computer)
6072 * hWnd [I] Handle to parent Window for the Dialog-Box
6073 * pMonitorName [I] Name of the Monitor that manage the Port
6080 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6082 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6084 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6086 if (!pMonitorName
) {
6087 SetLastError(RPC_X_NULL_REF_POINTER
);
6091 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6094 /******************************************************************************
6095 * AddPortExA (WINSPOOL.@)
6100 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6103 PORT_INFO_2A
* pi2A
;
6104 LPWSTR nameW
= NULL
;
6105 LPWSTR monitorW
= NULL
;
6109 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6111 TRACE("(%s, %ld, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6112 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6114 if ((level
< 1) || (level
> 2)) {
6115 SetLastError(ERROR_INVALID_LEVEL
);
6120 SetLastError(ERROR_INVALID_PARAMETER
);
6125 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6126 nameW
= malloc(len
* sizeof(WCHAR
));
6127 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6131 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6132 monitorW
= malloc(len
* sizeof(WCHAR
));
6133 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6136 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6138 if (pi2A
->pPortName
) {
6139 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6140 pi2W
.pPortName
= malloc(len
* sizeof(WCHAR
));
6141 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6145 if (pi2A
->pMonitorName
) {
6146 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6147 pi2W
.pMonitorName
= malloc(len
* sizeof(WCHAR
));
6148 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6151 if (pi2A
->pDescription
) {
6152 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6153 pi2W
.pDescription
= malloc(len
* sizeof(WCHAR
));
6154 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6156 pi2W
.fPortType
= pi2A
->fPortType
;
6157 pi2W
.Reserved
= pi2A
->Reserved
;
6160 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6164 free(pi2W
.pPortName
);
6165 free(pi2W
.pMonitorName
);
6166 free(pi2W
.pDescription
);
6171 /******************************************************************************
6172 * AddPortExW (WINSPOOL.@)
6174 * Add a Port for a specific Monitor, without presenting a user interface
6177 * pName [I] Servername or NULL (local Computer)
6178 * level [I] Structure-Level (1 or 2) for pBuffer
6179 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6180 * pMonitorName [I] Name of the Monitor that manage the Port
6187 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6191 pi2
= (PORT_INFO_2W
*) pBuffer
;
6193 TRACE("(%s, %ld, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6194 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6195 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6196 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6198 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6200 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6201 SetLastError(ERROR_INVALID_PARAMETER
);
6205 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6208 /******************************************************************************
6209 * AddPrinterConnectionA (WINSPOOL.@)
6211 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6213 FIXME("%s\n", debugstr_a(pName
));
6217 /******************************************************************************
6218 * AddPrinterConnectionW (WINSPOOL.@)
6220 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6222 FIXME("%s\n", debugstr_w(pName
));
6226 /******************************************************************************
6227 * AddPrinterDriverExW (WINSPOOL.@)
6229 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6232 * pName [I] Servername or NULL (local Computer)
6233 * level [I] Level for the supplied DRIVER_INFO_*W struct
6234 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6235 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6242 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6244 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6246 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6248 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6249 SetLastError(ERROR_INVALID_LEVEL
);
6254 SetLastError(ERROR_INVALID_PARAMETER
);
6258 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6261 /******************************************************************************
6262 * AddPrinterDriverExA (WINSPOOL.@)
6264 * See AddPrinterDriverExW.
6267 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6269 DRIVER_INFO_8A
*diA
;
6271 LPWSTR nameW
= NULL
;
6276 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6278 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6279 ZeroMemory(&diW
, sizeof(diW
));
6281 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6282 SetLastError(ERROR_INVALID_LEVEL
);
6287 SetLastError(ERROR_INVALID_PARAMETER
);
6291 /* convert servername to unicode */
6293 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6294 nameW
= malloc(len
* sizeof(WCHAR
));
6295 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6299 diW
.cVersion
= diA
->cVersion
;
6302 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6303 diW
.pName
= malloc(len
* sizeof(WCHAR
));
6304 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6307 if (diA
->pEnvironment
) {
6308 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6309 diW
.pEnvironment
= malloc(len
* sizeof(WCHAR
));
6310 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6313 if (diA
->pDriverPath
) {
6314 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6315 diW
.pDriverPath
= malloc(len
* sizeof(WCHAR
));
6316 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6319 if (diA
->pDataFile
) {
6320 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6321 diW
.pDataFile
= malloc(len
* sizeof(WCHAR
));
6322 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6325 if (diA
->pConfigFile
) {
6326 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6327 diW
.pConfigFile
= malloc(len
* sizeof(WCHAR
));
6328 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6331 if ((Level
> 2) && diA
->pHelpFile
) {
6332 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, NULL
, 0);
6333 diW
.pHelpFile
= malloc(len
* sizeof(WCHAR
));
6334 MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, diW
.pHelpFile
, len
);
6337 if ((Level
> 2) && diA
->pDependentFiles
) {
6338 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6339 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6340 diW
.pDependentFiles
= malloc(len
* sizeof(WCHAR
));
6341 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6344 if ((Level
> 2) && diA
->pMonitorName
) {
6345 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6346 diW
.pMonitorName
= malloc(len
* sizeof(WCHAR
));
6347 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6350 if ((Level
> 2) && diA
->pDefaultDataType
) {
6351 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6352 diW
.pDefaultDataType
= malloc(len
* sizeof(WCHAR
));
6353 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6356 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6357 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6358 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6359 diW
.pszzPreviousNames
= malloc(len
* sizeof(WCHAR
));
6360 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6364 diW
.ftDriverDate
= diA
->ftDriverDate
;
6365 diW
.dwlDriverVersion
= diA
->dwlDriverVersion
;
6368 if ((Level
> 5) && diA
->pszMfgName
) {
6369 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6370 diW
.pszMfgName
= malloc(len
* sizeof(WCHAR
));
6371 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6374 if ((Level
> 5) && diA
->pszOEMUrl
) {
6375 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6376 diW
.pszOEMUrl
= malloc(len
* sizeof(WCHAR
));
6377 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6380 if ((Level
> 5) && diA
->pszHardwareID
) {
6381 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6382 diW
.pszHardwareID
= malloc(len
* sizeof(WCHAR
));
6383 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6386 if ((Level
> 5) && diA
->pszProvider
) {
6387 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6388 diW
.pszProvider
= malloc(len
* sizeof(WCHAR
));
6389 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6392 if ((Level
> 7) && diA
->pszPrintProcessor
) {
6393 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, NULL
, 0);
6394 diW
.pszPrintProcessor
= malloc(len
* sizeof(WCHAR
));
6395 MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, diW
.pszPrintProcessor
, len
);
6398 if ((Level
> 7) && diA
->pszVendorSetup
) {
6399 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, NULL
, 0);
6400 diW
.pszVendorSetup
= malloc(len
* sizeof(WCHAR
));
6401 MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, diW
.pszVendorSetup
, len
);
6404 if ((Level
> 7) && diA
->pszzColorProfiles
) {
6405 lenA
= multi_sz_lenA(diA
->pszzColorProfiles
);
6406 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, NULL
, 0);
6407 diW
.pszzColorProfiles
= malloc(len
* sizeof(WCHAR
));
6408 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, diW
.pszzColorProfiles
, len
);
6411 if ((Level
> 7) && diA
->pszInfPath
) {
6412 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, NULL
, 0);
6413 diW
.pszInfPath
= malloc(len
* sizeof(WCHAR
));
6414 MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, diW
.pszInfPath
, len
);
6417 if ((Level
> 7) && diA
->pszzCoreDriverDependencies
) {
6418 lenA
= multi_sz_lenA(diA
->pszzCoreDriverDependencies
);
6419 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, NULL
, 0);
6420 diW
.pszzCoreDriverDependencies
= malloc(len
* sizeof(WCHAR
));
6421 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, diW
.pszzCoreDriverDependencies
, len
);
6425 diW
.dwPrinterDriverAttributes
= diA
->dwPrinterDriverAttributes
;
6426 diW
.ftMinInboxDriverVerDate
= diA
->ftMinInboxDriverVerDate
;
6427 diW
.dwlMinInboxDriverVerVersion
= diA
->dwlMinInboxDriverVerVersion
;
6430 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6431 TRACE("got %u with %lu\n", res
, GetLastError());
6434 free(diW
.pEnvironment
);
6435 free(diW
.pDriverPath
);
6436 free(diW
.pDataFile
);
6437 free(diW
.pConfigFile
);
6438 free(diW
.pHelpFile
);
6439 free(diW
.pDependentFiles
);
6440 free(diW
.pMonitorName
);
6441 free(diW
.pDefaultDataType
);
6442 free(diW
.pszzPreviousNames
);
6443 free(diW
.pszMfgName
);
6444 free(diW
.pszOEMUrl
);
6445 free(diW
.pszHardwareID
);
6446 free(diW
.pszProvider
);
6447 free(diW
.pszPrintProcessor
);
6448 free(diW
.pszVendorSetup
);
6449 free(diW
.pszzColorProfiles
);
6450 free(diW
.pszInfPath
);
6451 free(diW
.pszzCoreDriverDependencies
);
6453 TRACE("=> %u with %lu\n", res
, GetLastError());
6457 /******************************************************************************
6458 * ConfigurePortA (WINSPOOL.@)
6460 * See ConfigurePortW.
6463 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6465 LPWSTR nameW
= NULL
;
6466 LPWSTR portW
= NULL
;
6470 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6472 /* convert servername to unicode */
6474 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6475 nameW
= malloc(len
* sizeof(WCHAR
));
6476 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6479 /* convert portname to unicode */
6481 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6482 portW
= malloc(len
* sizeof(WCHAR
));
6483 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6486 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6492 /******************************************************************************
6493 * ConfigurePortW (WINSPOOL.@)
6495 * Display the Configuration-Dialog for a specific Port
6498 * pName [I] Servername or NULL (local Computer)
6499 * hWnd [I] Handle to parent Window for the Dialog-Box
6500 * pPortName [I] Name of the Port, that should be configured
6507 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6510 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6512 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6515 SetLastError(RPC_X_NULL_REF_POINTER
);
6519 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6522 /******************************************************************************
6523 * ConnectToPrinterDlg (WINSPOOL.@)
6525 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6527 FIXME("%p %lx\n", hWnd
, Flags
);
6531 /******************************************************************************
6532 * DeletePrinterConnectionA (WINSPOOL.@)
6534 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6536 FIXME("%s\n", debugstr_a(pName
));
6540 /******************************************************************************
6541 * DeletePrinterConnectionW (WINSPOOL.@)
6543 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6545 FIXME("%s\n", debugstr_w(pName
));
6549 /******************************************************************************
6550 * DeletePrinterDriverExW (WINSPOOL.@)
6552 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6553 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6558 TRACE("%s %s %s %lx %lx\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6559 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6561 if(pName
&& pName
[0])
6563 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6564 SetLastError(ERROR_INVALID_PARAMETER
);
6570 FIXME("dwDeleteFlag = %lx - unsupported\n", dwDeleteFlag
);
6571 SetLastError(ERROR_INVALID_PARAMETER
);
6575 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
6579 ERR("Can't open drivers key\n");
6583 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6586 RegCloseKey(hkey_drivers
);
6591 /******************************************************************************
6592 * DeletePrinterDriverExA (WINSPOOL.@)
6594 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6595 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6597 UNICODE_STRING NameW
, EnvW
, DriverW
;
6600 asciitounicode(&NameW
, pName
);
6601 asciitounicode(&EnvW
, pEnvironment
);
6602 asciitounicode(&DriverW
, pDriverName
);
6604 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6606 RtlFreeUnicodeString(&DriverW
);
6607 RtlFreeUnicodeString(&EnvW
);
6608 RtlFreeUnicodeString(&NameW
);
6613 /******************************************************************************
6614 * DeletePrinterDataExW (WINSPOOL.@)
6616 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6619 FIXME("%p %s %s\n", hPrinter
,
6620 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6621 return ERROR_INVALID_PARAMETER
;
6624 /******************************************************************************
6625 * DeletePrinterDataExA (WINSPOOL.@)
6627 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6630 FIXME("%p %s %s\n", hPrinter
,
6631 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6632 return ERROR_INVALID_PARAMETER
;
6635 /******************************************************************************
6636 * DeletePrintProcessorA (WINSPOOL.@)
6638 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6640 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6641 debugstr_a(pPrintProcessorName
));
6645 /******************************************************************************
6646 * DeletePrintProcessorW (WINSPOOL.@)
6648 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6650 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6651 debugstr_w(pPrintProcessorName
));
6655 /******************************************************************************
6656 * DeletePrintProvidorA (WINSPOOL.@)
6658 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6660 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6661 debugstr_a(pPrintProviderName
));
6665 /******************************************************************************
6666 * DeletePrintProvidorW (WINSPOOL.@)
6668 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6670 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6671 debugstr_w(pPrintProviderName
));
6675 /******************************************************************************
6676 * EnumFormsA (WINSPOOL.@)
6678 BOOL WINAPI
EnumFormsA( HANDLE printer
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
, DWORD
*count
)
6680 const DWORD
*string_info
= form_string_info( level
);
6684 if (!string_info
) return FALSE
;
6686 ret
= EnumFormsW( printer
, level
, form
, size
, needed
, count
);
6688 for (i
= 0; i
< *count
; i
++)
6689 packed_struct_WtoA( form
+ i
* string_info
[0], string_info
);
6694 /******************************************************************************
6695 * EnumFormsW (WINSPOOL.@)
6697 BOOL WINAPI
EnumFormsW( HANDLE printer
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
, DWORD
*count
)
6699 HANDLE handle
= get_backend_handle( printer
);
6701 TRACE( "(%p, %ld, %p, %ld, %p, %p)\n", printer
, level
, form
, size
, needed
, count
);
6705 SetLastError( ERROR_INVALID_HANDLE
);
6709 if (!needed
|| !count
)
6711 SetLastError( RPC_X_NULL_REF_POINTER
);
6717 SetLastError( ERROR_INVALID_USER_BUFFER
);
6721 return backend
->fpEnumForms( handle
, level
, form
, size
, needed
, count
);
6724 /*****************************************************************************
6725 * EnumMonitorsA [WINSPOOL.@]
6727 * See EnumMonitorsW.
6730 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6731 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6734 LPBYTE bufferW
= NULL
;
6735 LPWSTR nameW
= NULL
;
6737 DWORD numentries
= 0;
6740 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6741 cbBuf
, pcbNeeded
, pcReturned
);
6743 /* convert servername to unicode */
6745 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6746 nameW
= malloc(len
* sizeof(WCHAR
));
6747 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6749 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6750 needed
= cbBuf
* sizeof(WCHAR
);
6751 if (needed
) bufferW
= malloc(needed
);
6752 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6754 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6755 if (pcbNeeded
) needed
= *pcbNeeded
;
6756 /* HeapReAlloc return NULL, when bufferW was NULL */
6757 bufferW
= (bufferW
) ? realloc(bufferW
, needed
) : malloc(needed
);
6759 /* Try again with the large Buffer */
6760 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6762 numentries
= pcReturned
? *pcReturned
: 0;
6765 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6766 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6769 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6770 DWORD entrysize
= 0;
6773 LPMONITOR_INFO_2W mi2w
;
6774 LPMONITOR_INFO_2A mi2a
;
6776 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6777 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6779 /* First pass: calculate the size for all Entries */
6780 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6781 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6783 while (index
< numentries
) {
6785 needed
+= entrysize
; /* MONITOR_INFO_?A */
6786 TRACE("%p: parsing #%ld (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6788 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6789 NULL
, 0, NULL
, NULL
);
6791 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6792 NULL
, 0, NULL
, NULL
);
6793 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6794 NULL
, 0, NULL
, NULL
);
6796 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6797 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6798 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6801 /* check for errors and quit on failure */
6802 if (cbBuf
< needed
) {
6803 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6807 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6808 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6809 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6810 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6811 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6813 /* Second Pass: Fill the User Buffer (if we have one) */
6814 while ((index
< numentries
) && pMonitors
) {
6816 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a
, Level
, index
);
6818 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6819 ptr
, cbBuf
, NULL
, NULL
);
6823 mi2a
->pEnvironment
= ptr
;
6824 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6825 ptr
, cbBuf
, NULL
, NULL
);
6829 mi2a
->pDLLName
= ptr
;
6830 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6831 ptr
, cbBuf
, NULL
, NULL
);
6835 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6836 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6837 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6841 if (pcbNeeded
) *pcbNeeded
= needed
;
6842 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6847 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
6848 (res
), GetLastError(), needed
, numentries
);
6854 /*****************************************************************************
6855 * EnumMonitorsW [WINSPOOL.@]
6857 * Enumerate available Port-Monitors
6860 * pName [I] Servername or NULL (local Computer)
6861 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6862 * pMonitors [O] PTR to Buffer that receives the Result
6863 * cbBuf [I] Size of Buffer at pMonitors
6864 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6865 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6869 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6872 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6873 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6876 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6877 cbBuf
, pcbNeeded
, pcReturned
);
6879 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6881 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6882 SetLastError(RPC_X_NULL_REF_POINTER
);
6886 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6889 /******************************************************************************
6890 * SpoolerInit (WINSPOOL.@)
6892 * Initialize the Spooler
6899 * The function fails on windows, when the spooler service is not running
6902 BOOL WINAPI
SpoolerInit(void)
6905 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6909 /******************************************************************************
6910 * XcvDataW (WINSPOOL.@)
6912 * Execute commands in the Printmonitor DLL
6915 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6916 * pszDataName [i] Name of the command to execute
6917 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6918 * cbInputData [i] Size in Bytes of Buffer at pInputData
6919 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6920 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6921 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6922 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6929 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6930 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6932 * Minimal List of commands, that a Printmonitor DLL should support:
6934 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6935 *| "AddPort" : Add a Port
6936 *| "DeletePort": Delete a Port
6938 * Many Printmonitors support additional commands. Examples for localspl.dll:
6939 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6940 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6943 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6944 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6945 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6947 opened_printer_t
*printer
;
6949 TRACE("(%p, %s, %p, %ld, %p, %ld, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6950 pInputData
, cbInputData
, pOutputData
,
6951 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6953 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6955 printer
= get_opened_printer(hXcv
);
6956 if (!printer
|| (!printer
->backend_printer
)) {
6957 SetLastError(ERROR_INVALID_HANDLE
);
6961 if (!pcbOutputNeeded
) {
6962 SetLastError(ERROR_INVALID_PARAMETER
);
6966 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6967 SetLastError(RPC_X_NULL_REF_POINTER
);
6971 *pcbOutputNeeded
= 0;
6973 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
6974 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6978 /*****************************************************************************
6979 * EnumPrinterDataA [WINSPOOL.@]
6982 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6983 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6984 DWORD cbData
, LPDWORD pcbData
)
6986 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
6987 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6988 return ERROR_NO_MORE_ITEMS
;
6991 /*****************************************************************************
6992 * EnumPrinterDataW [WINSPOOL.@]
6995 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6996 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6997 DWORD cbData
, LPDWORD pcbData
)
6999 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
7000 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7001 return ERROR_NO_MORE_ITEMS
;
7004 /*****************************************************************************
7005 * EnumPrinterKeyA [WINSPOOL.@]
7008 DWORD WINAPI
EnumPrinterKeyA(HANDLE printer
, const CHAR
*key
, CHAR
*subkey
, DWORD size
, DWORD
*needed
)
7010 FIXME("%p %s %p %lx %p\n", printer
, debugstr_a(key
), subkey
, size
, needed
);
7011 return ERROR_CALL_NOT_IMPLEMENTED
;
7014 /*****************************************************************************
7015 * EnumPrinterKeyW [WINSPOOL.@]
7018 DWORD WINAPI
EnumPrinterKeyW(HANDLE printer
, const WCHAR
*key
, WCHAR
*subkey
, DWORD size
, DWORD
*needed
)
7020 FIXME("%p %s %p %lx %p\n", printer
, debugstr_w(key
), subkey
, size
, needed
);
7021 return ERROR_CALL_NOT_IMPLEMENTED
;
7024 /*****************************************************************************
7025 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7028 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7029 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7030 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7032 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName
),
7033 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7034 pcbNeeded
, pcReturned
);
7038 /*****************************************************************************
7039 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7042 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7043 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7044 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7046 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
7047 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7048 pcbNeeded
, pcReturned
);
7052 /*****************************************************************************
7053 * EnumPrintProcessorsA [WINSPOOL.@]
7055 * See EnumPrintProcessorsW.
7058 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7059 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7062 LPBYTE bufferW
= NULL
;
7063 LPWSTR nameW
= NULL
;
7066 DWORD numentries
= 0;
7069 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7070 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7072 /* convert names to unicode */
7074 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7075 nameW
= malloc(len
* sizeof(WCHAR
));
7076 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7079 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7080 envW
= malloc(len
* sizeof(WCHAR
));
7081 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7084 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7085 needed
= cbBuf
* sizeof(WCHAR
);
7086 if (needed
) bufferW
= malloc(needed
);
7087 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7089 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7090 if (pcbNeeded
) needed
= *pcbNeeded
;
7091 /* HeapReAlloc return NULL, when bufferW was NULL */
7092 bufferW
= (bufferW
) ? realloc(bufferW
, needed
) : malloc(needed
);
7094 /* Try again with the large Buffer */
7095 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7097 numentries
= pcReturned
? *pcReturned
: 0;
7101 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7104 PPRINTPROCESSOR_INFO_1W ppiw
;
7105 PPRINTPROCESSOR_INFO_1A ppia
;
7107 /* First pass: calculate the size for all Entries */
7108 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7109 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7111 while (index
< numentries
) {
7113 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7114 TRACE("%p: parsing #%ld (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7116 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7117 NULL
, 0, NULL
, NULL
);
7119 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7120 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7123 /* check for errors and quit on failure */
7124 if (cbBuf
< needed
) {
7125 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7130 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7131 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7132 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7133 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7134 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7136 /* Second Pass: Fill the User Buffer (if we have one) */
7137 while ((index
< numentries
) && pPPInfo
) {
7139 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%ld\n", ppia
, index
);
7141 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7142 ptr
, cbBuf
, NULL
, NULL
);
7146 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7147 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7152 if (pcbNeeded
) *pcbNeeded
= needed
;
7153 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7159 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
7160 (res
), GetLastError(), needed
, numentries
);
7165 /*****************************************************************************
7166 * EnumPrintProcessorsW [WINSPOOL.@]
7168 * Enumerate available Print Processors
7171 * pName [I] Servername or NULL (local Computer)
7172 * pEnvironment [I] Printing-Environment or NULL (Default)
7173 * Level [I] Structure-Level (Only 1 is allowed)
7174 * pPPInfo [O] PTR to Buffer that receives the Result
7175 * cbBuf [I] Size of Buffer at pPPInfo
7176 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7177 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7181 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7184 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7185 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7188 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7189 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7191 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7193 if (!pcbNeeded
|| !pcReturned
) {
7194 SetLastError(RPC_X_NULL_REF_POINTER
);
7198 if (!pPPInfo
&& (cbBuf
> 0)) {
7199 SetLastError(ERROR_INVALID_USER_BUFFER
);
7203 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7204 cbBuf
, pcbNeeded
, pcReturned
);
7207 /*****************************************************************************
7208 * ExtDeviceMode [WINSPOOL.@]
7211 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7212 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7215 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd
, hInst
, pDevModeOutput
,
7216 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7217 debugstr_a(pProfile
), fMode
);
7221 /*****************************************************************************
7222 * FindClosePrinterChangeNotification [WINSPOOL.@]
7225 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7227 FIXME("Stub: %p\n", hChange
);
7231 /*****************************************************************************
7232 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7235 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7236 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7238 FIXME("Stub: %p %lx %lx %p\n",
7239 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7240 return INVALID_HANDLE_VALUE
;
7243 /*****************************************************************************
7244 * FindNextPrinterChangeNotification [WINSPOOL.@]
7247 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7248 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7250 FIXME("Stub: %p %p %p %p\n",
7251 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7255 /*****************************************************************************
7256 * FreePrinterNotifyInfo [WINSPOOL.@]
7259 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7261 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7265 static inline const DWORD
*job_string_info(DWORD level
)
7267 static const DWORD info_1
[] =
7269 sizeof(JOB_INFO_1W
),
7270 FIELD_OFFSET(JOB_INFO_1W
, pPrinterName
),
7271 FIELD_OFFSET(JOB_INFO_1W
, pMachineName
),
7272 FIELD_OFFSET(JOB_INFO_1W
, pUserName
),
7273 FIELD_OFFSET(JOB_INFO_1W
, pDocument
),
7274 FIELD_OFFSET(JOB_INFO_1W
, pDatatype
),
7275 FIELD_OFFSET(JOB_INFO_1W
, pStatus
),
7278 static const DWORD info_2
[] =
7280 sizeof(JOB_INFO_2W
),
7281 FIELD_OFFSET(JOB_INFO_2W
, pPrinterName
),
7282 FIELD_OFFSET(JOB_INFO_2W
, pMachineName
),
7283 FIELD_OFFSET(JOB_INFO_2W
, pUserName
),
7284 FIELD_OFFSET(JOB_INFO_2W
, pDocument
),
7285 FIELD_OFFSET(JOB_INFO_2W
, pNotifyName
),
7286 FIELD_OFFSET(JOB_INFO_2W
, pDatatype
),
7287 FIELD_OFFSET(JOB_INFO_2W
, pPrintProcessor
),
7288 FIELD_OFFSET(JOB_INFO_2W
, pParameters
),
7289 FIELD_OFFSET(JOB_INFO_2W
, pDriverName
),
7290 FIELD_OFFSET(JOB_INFO_2W
, pStatus
),
7293 static const DWORD info_3
[] =
7301 case 1: return info_1
;
7302 case 2: return info_2
;
7303 case 3: return info_3
;
7306 SetLastError( ERROR_INVALID_LEVEL
);
7310 /*****************************************************************************
7311 * GetJobA [WINSPOOL.@]
7314 BOOL WINAPI
GetJobA(HANDLE printer
, DWORD job_id
, DWORD level
, BYTE
*data
,
7315 DWORD size
, DWORD
*needed
)
7317 const DWORD
*string_info
= job_string_info(level
);
7322 if (!GetJobW(printer
, job_id
, level
, data
, size
, needed
))
7324 packed_struct_WtoA(data
, string_info
);
7326 DEVMODEWtoA(((JOB_INFO_2W
*)data
)->pDevMode
, ((JOB_INFO_2A
*)data
)->pDevMode
);
7330 /*****************************************************************************
7331 * GetJobW [WINSPOOL.@]
7334 BOOL WINAPI
GetJobW(HANDLE printer
, DWORD job_id
, DWORD level
, BYTE
*data
,
7335 DWORD size
, DWORD
*needed
)
7337 HANDLE handle
= get_backend_handle(printer
);
7339 TRACE("(%p, %ld, %ld, %p, %ld, %p)\n", printer
, job_id
, level
, data
, size
, needed
);
7343 SetLastError(ERROR_INVALID_HANDLE
);
7347 return backend
->fpGetJob(handle
, job_id
, level
, data
, size
, needed
);
7350 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7357 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7361 if(HIWORD(wparam
) == BN_CLICKED
)
7363 if(LOWORD(wparam
) == IDOK
)
7366 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7369 filename
= malloc((len
+ 1) * sizeof(WCHAR
));
7370 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7372 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7374 WCHAR caption
[200], message
[200];
7377 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
7378 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, ARRAY_SIZE(message
));
7379 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7380 if(mb_ret
== IDCANCEL
)
7386 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7387 if(hf
== INVALID_HANDLE_VALUE
)
7389 WCHAR caption
[200], message
[200];
7391 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
7392 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, ARRAY_SIZE(message
));
7393 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7398 DeleteFileW(filename
);
7399 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7401 EndDialog(hwnd
, IDOK
);
7404 if(LOWORD(wparam
) == IDCANCEL
)
7406 EndDialog(hwnd
, IDCANCEL
);
7415 /*****************************************************************************
7418 static BOOL
get_filename(LPWSTR
*filename
)
7420 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7421 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7424 /*****************************************************************************
7425 * ScheduleJob [WINSPOOL.@]
7428 BOOL WINAPI
ScheduleJob(HANDLE printer
, DWORD job_id
)
7430 HANDLE handle
= get_backend_handle(printer
);
7432 TRACE("(%p, %lx)\n", printer
, job_id
);
7436 SetLastError(ERROR_INVALID_HANDLE
);
7440 return backend
->fpScheduleJob(handle
, job_id
);
7443 /*****************************************************************************
7444 * StartDocDlgA [WINSPOOL.@]
7446 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7448 UNICODE_STRING usBuffer
;
7449 DOCINFOW docW
= { 0 };
7451 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7454 docW
.cbSize
= sizeof(docW
);
7455 if (doc
->lpszDocName
)
7457 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7458 if (!(docW
.lpszDocName
= docnameW
)) goto failed
;
7460 if (doc
->lpszOutput
)
7462 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7463 if (!(docW
.lpszOutput
= outputW
)) goto failed
;
7465 if (doc
->lpszDatatype
)
7467 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7468 if (!(docW
.lpszDatatype
= datatypeW
)) goto failed
;
7470 docW
.fwType
= doc
->fwType
;
7472 retW
= StartDocDlgW(hPrinter
, &docW
);
7476 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7477 ret
= heap_alloc(len
);
7478 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7490 static BOOL
is_port(const WCHAR
*port_list
, const WCHAR
*output
)
7497 if (wcschr(output
, ':'))
7500 len
= wcslen(output
);
7501 while (port_list
&& *port_list
)
7503 if (!wcsncmp(output
, port_list
, len
) && (!port_list
[len
] || port_list
[len
] == ','))
7506 port_list
= wcschr(port_list
, ',');
7507 if (port_list
) port_list
++;
7512 /*****************************************************************************
7513 * StartDocDlgW [WINSPOOL.@]
7515 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7516 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7517 * port is "FILE:". Also returns the full path if passed a relative path.
7519 * The caller should free the returned string from the process heap.
7521 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7523 PRINTER_INFO_5W
*pi5
;
7528 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7529 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7532 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7534 /* Check whether default port is FILE: */
7535 b
= !doc
->lpszOutput
&& (!pi5
->pPortName
|| wcscmp( pi5
->pPortName
, L
"FILE:" ));
7537 b
= is_port(pi5
->pPortName
, doc
->lpszOutput
);
7542 if(doc
->lpszOutput
== NULL
|| !wcscmp( doc
->lpszOutput
, L
"FILE:" ))
7546 if (get_filename(&name
))
7548 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7553 ret
= heap_alloc(len
* sizeof(WCHAR
));
7554 GetFullPathNameW(name
, len
, ret
, NULL
);
7560 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7563 ret
= heap_alloc(len
* sizeof(WCHAR
));
7564 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7566 attr
= GetFileAttributesW(ret
);
7567 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7575 /*****************************************************************************
7576 * UploadPrinterDriverPackageA [WINSPOOL.@]
7578 HRESULT WINAPI
UploadPrinterDriverPackageA( LPCSTR server
, LPCSTR path
, LPCSTR env
,
7579 DWORD flags
, HWND hwnd
, LPSTR dst
, PULONG dstlen
)
7581 FIXME("%s, %s, %s, %lx, %p, %p, %p\n", debugstr_a(server
), debugstr_a(path
), debugstr_a(env
),
7582 flags
, hwnd
, dst
, dstlen
);
7586 /*****************************************************************************
7587 * UploadPrinterDriverPackageW [WINSPOOL.@]
7589 HRESULT WINAPI
UploadPrinterDriverPackageW( LPCWSTR server
, LPCWSTR path
, LPCWSTR env
,
7590 DWORD flags
, HWND hwnd
, LPWSTR dst
, PULONG dstlen
)
7592 FIXME("%s, %s, %s, %lx, %p, %p, %p\n", debugstr_w(server
), debugstr_w(path
), debugstr_w(env
),
7593 flags
, hwnd
, dst
, dstlen
);
7597 /*****************************************************************************
7598 * PerfOpen [WINSPOOL.@]
7600 DWORD WINAPI
PerfOpen(LPWSTR context
)
7602 FIXME("%s: stub\n", debugstr_w(context
));
7603 return ERROR_SUCCESS
;
7606 /*****************************************************************************
7607 * PerfClose [WINSPOOL.@]
7609 DWORD WINAPI
PerfClose(void)
7612 return ERROR_SUCCESS
;
7615 /*****************************************************************************
7616 * PerfCollect [WINSPOOL.@]
7618 DWORD WINAPI
PerfCollect(LPWSTR query
, LPVOID
*data
, LPDWORD size
, LPDWORD obj_count
)
7620 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query
), data
, size
, obj_count
);
7623 return ERROR_SUCCESS
;
7626 /*****************************************************************************
7627 * GetSpoolFileHandle [WINSPOOL.@]
7629 HANDLE WINAPI
GetSpoolFileHandle( HANDLE printer
)
7631 FIXME( "%p: stub\n", printer
);
7632 return INVALID_HANDLE_VALUE
;
7635 /*****************************************************************************
7636 * SeekPrinter [WINSPOOL.@]
7638 BOOL WINAPI
SeekPrinter(HANDLE printer
, LARGE_INTEGER distance
,
7639 LARGE_INTEGER
*pos
, DWORD method
, BOOL bwrite
)
7641 HANDLE handle
= get_backend_handle(printer
);
7643 TRACE("(%p %I64d %p %lx %x)\n", printer
, distance
.QuadPart
, pos
, method
, bwrite
);
7647 SetLastError(ERROR_INVALID_HANDLE
);
7650 return backend
->fpSeekPrinter(handle
, distance
, pos
, method
, bwrite
);