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
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
47 #ifdef HAVE_CUPS_PPD_H
48 # include <cups/ppd.h>
51 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
52 #define GetCurrentProcess GetCurrentProcess_Mac
53 #define GetCurrentThread GetCurrentThread_Mac
54 #define LoadResource LoadResource_Mac
55 #define AnimatePalette AnimatePalette_Mac
56 #define EqualRgn EqualRgn_Mac
57 #define FillRgn FillRgn_Mac
58 #define FrameRgn FrameRgn_Mac
59 #define GetPixel GetPixel_Mac
60 #define InvertRgn InvertRgn_Mac
61 #define LineTo LineTo_Mac
62 #define OffsetRgn OffsetRgn_Mac
63 #define PaintRgn PaintRgn_Mac
64 #define Polygon Polygon_Mac
65 #define ResizePalette ResizePalette_Mac
66 #define SetRectRgn SetRectRgn_Mac
67 #define EqualRect EqualRect_Mac
68 #define FillRect FillRect_Mac
69 #define FrameRect FrameRect_Mac
70 #define GetCursor GetCursor_Mac
71 #define InvertRect InvertRect_Mac
72 #define OffsetRect OffsetRect_Mac
73 #define PtInRect PtInRect_Mac
74 #define SetCursor SetCursor_Mac
75 #define SetRect SetRect_Mac
76 #define ShowCursor ShowCursor_Mac
77 #define UnionRect UnionRect_Mac
78 #include <ApplicationServices/ApplicationServices.h>
79 #undef GetCurrentProcess
80 #undef GetCurrentThread
107 #define NONAMELESSSTRUCT
108 #define NONAMELESSUNION
113 #include "winerror.h"
116 #include "winspool.h"
117 #include "winternl.h"
118 #include "wine/windef16.h"
119 #include "wine/unicode.h"
120 #include "wine/debug.h"
121 #include "wine/list.h"
122 #include "wine/rbtree.h"
123 #include "wine/heap.h"
126 #include "ddk/winsplp.h"
129 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
131 /* ############################### */
133 static CRITICAL_SECTION printer_handles_cs
;
134 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
136 0, 0, &printer_handles_cs
,
137 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
138 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
140 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
142 /* ############################### */
157 HANDLE backend_printer
;
168 WCHAR
*document_title
;
178 LPCWSTR versionregpath
;
179 LPCWSTR versionsubdir
;
184 struct wine_rb_entry entry
;
189 DWORD (WINAPI
*pDrvDeviceCapabilities
)(HANDLE
, const WCHAR
*, WORD
, void *, const DEVMODEW
*);
190 INT (WINAPI
*pDrvDocumentProperties
)(HWND
, const WCHAR
*, DEVMODEW
*, DEVMODEW
*, DWORD
);
195 /* ############################### */
197 static opened_printer_t
**printer_handles
;
198 static UINT nb_printer_handles
;
199 static LONG next_job_id
= 1;
201 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
202 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
203 'c','o','n','t','r','o','l','\\',
204 'P','r','i','n','t','\\',
205 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
206 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
208 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
209 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
210 'C','o','n','t','r','o','l','\\',
211 'P','r','i','n','t','\\',
212 'P','r','i','n','t','e','r','s',0};
214 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
215 'M','i','c','r','o','s','o','f','t','\\',
216 'W','i','n','d','o','w','s',' ','N','T','\\',
217 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
218 'W','i','n','d','o','w','s',0};
220 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
221 'M','i','c','r','o','s','o','f','t','\\',
222 'W','i','n','d','o','w','s',' ','N','T','\\',
223 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
224 'D','e','v','i','c','e','s',0};
226 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
227 'M','i','c','r','o','s','o','f','t','\\',
228 'W','i','n','d','o','w','s',' ','N','T','\\',
229 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
230 'P','r','i','n','t','e','r','P','o','r','t','s',0};
232 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
233 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
234 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
235 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
236 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
237 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
238 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
239 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
240 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
241 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
243 static const WCHAR AttributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0};
244 static const WCHAR backslashW
[] = {'\\',0};
245 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
246 'i','o','n',' ','F','i','l','e',0};
247 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
248 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
249 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
250 static const WCHAR Default_PriorityW
[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
251 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
252 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
253 static const WCHAR dnsTimeoutW
[] = {'d','n','s','T','i','m','e','o','u','t',0};
254 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
255 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
256 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
257 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
258 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
259 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
260 static const WCHAR NameW
[] = {'N','a','m','e',0};
261 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
262 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
263 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
264 static const WCHAR PortW
[] = {'P','o','r','t',0};
265 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
266 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
267 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
268 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
269 static const WCHAR PriorityW
[] = {'P','r','i','o','r','i','t','y',0};
270 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
271 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
272 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
273 static const WCHAR StartTimeW
[] = {'S','t','a','r','t','T','i','m','e',0};
274 static const WCHAR StatusW
[] = {'S','t','a','t','u','s',0};
275 static const WCHAR txTimeoutW
[] = {'t','x','T','i','m','e','o','u','t',0};
276 static const WCHAR UntilTimeW
[] = {'U','n','t','i','l','T','i','m','e',0};
277 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
278 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
279 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
280 static WCHAR rawW
[] = {'R','A','W',0};
281 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
282 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
283 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
284 static const WCHAR commaW
[] = {',',0};
285 static WCHAR emptyStringW
[] = {0};
287 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
289 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
290 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
291 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
293 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
294 'D','o','c','u','m','e','n','t',0};
296 static const WCHAR PPD_Overrides
[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
297 static const WCHAR DefaultPageSize
[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
299 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
300 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
301 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
302 0, sizeof(DRIVER_INFO_8W
)};
305 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
306 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
307 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
308 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
309 sizeof(PRINTER_INFO_9W
)};
311 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
312 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
313 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
315 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
317 /******************************************************************
318 * validate the user-supplied printing-environment [internal]
321 * env [I] PTR to Environment-String or NULL
325 * Success: PTR to printenv_t
328 * An empty string is handled the same way as NULL.
329 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
333 static const printenv_t
* validate_envW(LPCWSTR env
)
335 const printenv_t
*result
= NULL
;
338 TRACE("testing %s\n", debugstr_w(env
));
341 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
343 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
345 result
= all_printenv
[i
];
350 if (result
== NULL
) {
351 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
352 SetLastError(ERROR_INVALID_ENVIRONMENT
);
354 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
358 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
360 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
366 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
367 if passed a NULL string. This returns NULLs to the result.
369 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
373 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
374 return usBufferPtr
->Buffer
;
376 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
380 static LPWSTR
strdupW(LPCWSTR p
)
386 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
387 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
392 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
396 if (!dm
) return NULL
;
397 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
398 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
402 /***********************************************************
404 * Creates an ansi copy of supplied devmode
406 static DEVMODEA
*DEVMODEdupWtoA( const DEVMODEW
*dmW
)
411 if (!dmW
) return NULL
;
412 size
= dmW
->dmSize
- CCHDEVICENAME
-
413 ((dmW
->dmSize
> FIELD_OFFSET( DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
415 dmA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
416 if (!dmA
) return NULL
;
418 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmDeviceName
, -1,
419 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
421 if (FIELD_OFFSET( DEVMODEW
, dmFormName
) >= dmW
->dmSize
)
423 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
424 dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
428 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
429 FIELD_OFFSET( DEVMODEW
, dmFormName
) - FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
430 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmFormName
, -1,
431 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
433 memcpy( &dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmLogPixels
) );
437 memcpy( (char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
441 static void packed_string_WtoA( WCHAR
*strW
)
443 DWORD len
= strlenW( strW
), size
= (len
+ 1) * sizeof(WCHAR
), ret
;
447 str
= heap_alloc( size
);
448 ret
= WideCharToMultiByte( CP_ACP
, 0, strW
, len
, str
, size
- 1, NULL
, NULL
);
449 memcpy( strW
, str
, ret
);
450 memset( (BYTE
*)strW
+ ret
, 0, size
- ret
);
454 /*********************************************************************
457 * Convert a packed struct from W to A overwriting the unicode strings
458 * with their ansi equivalents.
460 static void packed_struct_WtoA( BYTE
*data
, const DWORD
*string_info
)
464 string_info
++; /* sizeof */
465 while (*string_info
!= ~0u)
467 strW
= *(WCHAR
**)(data
+ *string_info
);
468 if (strW
) packed_string_WtoA( strW
);
473 static inline const DWORD
*form_string_info( DWORD level
)
475 static const DWORD info_1
[] =
477 sizeof( FORM_INFO_1W
),
478 FIELD_OFFSET( FORM_INFO_1W
, pName
),
481 static const DWORD info_2
[] =
483 sizeof( FORM_INFO_2W
),
484 FIELD_OFFSET( FORM_INFO_2W
, pName
),
485 FIELD_OFFSET( FORM_INFO_2W
, pMuiDll
),
486 FIELD_OFFSET( FORM_INFO_2W
, pDisplayName
),
490 if (level
== 1) return info_1
;
491 if (level
== 2) return info_2
;
493 SetLastError( ERROR_INVALID_LEVEL
);
497 /*****************************************************************************
498 * WINSPOOL_OpenDriverReg [internal]
500 * opens the registry for the printer drivers depending on the given input
501 * variable pEnvironment
504 * the opened hkey on success
507 static HKEY
WINSPOOL_OpenDriverReg(const void *pEnvironment
)
511 const printenv_t
*env
;
513 TRACE("(%s)\n", debugstr_w(pEnvironment
));
515 env
= validate_envW(pEnvironment
);
516 if (!env
) return NULL
;
518 buffer
= HeapAlloc( GetProcessHeap(), 0,
519 (strlenW(DriversW
) + strlenW(env
->envname
) +
520 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
522 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
523 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
524 HeapFree(GetProcessHeap(), 0, buffer
);
529 static CRITICAL_SECTION config_modules_cs
;
530 static CRITICAL_SECTION_DEBUG config_modules_cs_debug
=
532 0, 0, &config_modules_cs
,
533 { &config_modules_cs_debug
.ProcessLocksList
, &config_modules_cs_debug
.ProcessLocksList
},
534 0, 0, { (DWORD_PTR
)(__FILE__
": config_modules_cs") }
536 static CRITICAL_SECTION config_modules_cs
= { &config_modules_cs_debug
, -1, 0, 0, 0, 0 };
538 static int compare_config_modules(const void *key
, const struct wine_rb_entry
*entry
)
540 config_module_t
*module
= WINE_RB_ENTRY_VALUE(entry
, config_module_t
, entry
);
541 return lstrcmpiW(key
, module
->name
);
544 static struct wine_rb_tree config_modules
= { compare_config_modules
};
546 static void release_config_module(config_module_t
*config_module
)
548 if (InterlockedDecrement(&config_module
->ref
)) return;
549 FreeLibrary(config_module
->module
);
550 HeapFree(GetProcessHeap(), 0, config_module
);
553 static config_module_t
*get_config_module(const WCHAR
*device
, BOOL grab
)
555 WCHAR driver
[MAX_PATH
];
557 HKEY driver_key
, device_key
;
558 HMODULE driver_module
;
559 config_module_t
*ret
= NULL
;
560 struct wine_rb_entry
*entry
;
564 EnterCriticalSection(&config_modules_cs
);
565 entry
= wine_rb_get(&config_modules
, device
);
567 ret
= WINE_RB_ENTRY_VALUE(entry
, config_module_t
, entry
);
568 if (grab
) InterlockedIncrement(&ret
->ref
);
573 if (!(driver_key
= WINSPOOL_OpenDriverReg(NULL
))) goto ret
;
575 res
= RegOpenKeyW(driver_key
, device
, &device_key
);
576 RegCloseKey(driver_key
);
578 WARN("Device %s key not found\n", debugstr_w(device
));
582 size
= sizeof(driver
);
583 if (!GetPrinterDriverDirectoryW(NULL
, NULL
, 1, (LPBYTE
)driver
, size
, &size
)) goto ret
;
585 len
= size
/ sizeof(WCHAR
) - 1;
586 driver
[len
++] = '\\';
588 driver
[len
++] = '\\';
589 size
= sizeof(driver
) - len
* sizeof(WCHAR
);
590 res
= RegQueryValueExW(device_key
, Configuration_FileW
, NULL
, &type
,
591 (BYTE
*)(driver
+ len
), &size
);
592 RegCloseKey(device_key
);
593 if (res
|| type
!= REG_SZ
) {
594 WARN("no configuration file: %u\n", res
);
598 if (!(driver_module
= LoadLibraryW(driver
))) {
599 WARN("Could not load %s\n", debugstr_w(driver
));
603 len
= lstrlenW(device
);
604 if (!(ret
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(config_module_t
, name
[len
+ 1]))))
607 ret
->ref
= 2; /* one for config_module and one for the caller */
608 ret
->module
= driver_module
;
609 ret
->pDrvDeviceCapabilities
= (void *)GetProcAddress(driver_module
, "DrvDeviceCapabilities");
610 ret
->pDrvDocumentProperties
= (void *)GetProcAddress(driver_module
, "DrvDocumentProperties");
611 lstrcpyW(ret
->name
, device
);
613 wine_rb_put(&config_modules
, ret
->name
, &ret
->entry
);
615 LeaveCriticalSection(&config_modules_cs
);
619 /******************************************************************
620 * verify, that the filename is a local file
623 static inline BOOL
is_local_file(LPWSTR name
)
625 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
628 /* ################################ */
630 static int multi_sz_lenA(const char *str
)
632 const char *ptr
= str
;
636 ptr
+= lstrlenA(ptr
) + 1;
639 return ptr
- str
+ 1;
642 /*****************************************************************************
645 * Return DWORD associated with name from hkey.
647 static DWORD
get_dword_from_reg( HKEY hkey
, const WCHAR
*name
)
649 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
652 ret
= RegQueryValueExW( hkey
, name
, 0, &type
, (LPBYTE
)&value
, &sz
);
654 if (ret
!= ERROR_SUCCESS
)
656 WARN( "Got ret = %d on name %s\n", ret
, debugstr_w(name
) );
659 if (type
!= REG_DWORD
)
661 ERR( "Got type %d\n", type
);
667 static inline DWORD
set_reg_DWORD( HKEY hkey
, const WCHAR
*keyname
, const DWORD value
)
669 return RegSetValueExW( hkey
, keyname
, 0, REG_DWORD
, (const BYTE
*)&value
, sizeof(value
) );
672 /******************************************************************
674 * Get the pointer to the opened printer referred by the handle
676 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
678 UINT_PTR idx
= (UINT_PTR
)hprn
;
679 opened_printer_t
*ret
= NULL
;
681 EnterCriticalSection(&printer_handles_cs
);
683 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
684 ret
= printer_handles
[idx
- 1];
686 LeaveCriticalSection(&printer_handles_cs
);
690 /******************************************************************
691 * get_opened_printer_name
692 * Get the pointer to the opened printer name referred by the handle
694 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
696 opened_printer_t
*printer
= get_opened_printer(hprn
);
697 if(!printer
) return NULL
;
698 return printer
->name
;
701 static HANDLE
get_backend_handle( HANDLE hprn
)
703 opened_printer_t
*printer
= get_opened_printer( hprn
);
704 if (!printer
) return NULL
;
705 return printer
->backend_printer
;
708 static DWORD
open_printer_reg_key( const WCHAR
*name
, HKEY
*key
)
714 err
= RegCreateKeyW( HKEY_LOCAL_MACHINE
, PrintersW
, &printers
);
717 err
= RegOpenKeyW( printers
, name
, key
);
718 if (err
) err
= ERROR_INVALID_PRINTER_NAME
;
719 RegCloseKey( printers
);
723 /******************************************************************
724 * WINSPOOL_GetOpenedPrinterRegKey
727 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
729 LPCWSTR name
= get_opened_printer_name(hPrinter
);
731 if(!name
) return ERROR_INVALID_HANDLE
;
732 return open_printer_reg_key( name
, phkey
);
735 static void set_default_printer(const char *devname
, const char *name
)
737 char *buf
= HeapAlloc(GetProcessHeap(), 0, strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
740 sprintf(buf
, "%s,WINEPS.DRV,LPR:%s", devname
, name
);
741 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
743 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (BYTE
*)buf
, strlen(buf
) + 1);
746 HeapFree(GetProcessHeap(), 0, buf
);
749 static BOOL
add_printer_driver(const WCHAR
*name
, WCHAR
*ppd
)
755 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
757 di3
.pName
= (WCHAR
*)name
;
758 di3
.pDriverPath
= driver_nt
;
760 di3
.pConfigFile
= driver_nt
;
761 di3
.pDefaultDataType
= rawW
;
763 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
765 di3
.pEnvironment
= (WCHAR
*) all_printenv
[i
]->envname
;
766 if (all_printenv
[i
]->envname
== envname_win40W
)
768 /* We use wineps16.drv as driver for 16 bit */
769 di3
.pDriverPath
= driver_9x
;
770 di3
.pConfigFile
= driver_9x
;
772 res
= AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
);
773 TRACE("got %d and %d for %s (%s)\n", res
, GetLastError(), debugstr_w(name
), debugstr_w(di3
.pEnvironment
));
775 if (!res
&& (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
777 ERR("failed with %u for %s (%s) %s\n", GetLastError(), debugstr_w(name
),
778 debugstr_w(di3
.pEnvironment
), debugstr_w(di3
.pDriverPath
));
786 static inline char *expand_env_string( char *str
, DWORD type
)
788 if (type
== REG_EXPAND_SZ
)
791 DWORD needed
= ExpandEnvironmentStringsA( str
, NULL
, 0 );
792 tmp
= HeapAlloc( GetProcessHeap(), 0, needed
);
795 ExpandEnvironmentStringsA( str
, tmp
, needed
);
796 HeapFree( GetProcessHeap(), 0, str
);
803 static char *get_fallback_ppd_name( const char *printer_name
)
805 static const WCHAR ppds_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
806 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
811 if (RegOpenKeyW( HKEY_CURRENT_USER
, ppds_key
, &hkey
) == ERROR_SUCCESS
)
813 const char *value_name
= NULL
;
815 if (RegQueryValueExA( hkey
, printer_name
, 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
816 value_name
= printer_name
;
817 else if (RegQueryValueExA( hkey
, "generic", 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
818 value_name
= "generic";
822 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
823 if (!ret
) return NULL
;
824 RegQueryValueExA( hkey
, value_name
, 0, &type
, (BYTE
*)ret
, &needed
);
827 if (ret
) return expand_env_string( ret
, type
);
832 static BOOL
copy_file( const char *src
, const char *dst
)
834 int fds
[2] = {-1, -1}, num
;
838 fds
[0] = open( src
, O_RDONLY
);
839 fds
[1] = open( dst
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666 );
840 if (fds
[0] == -1 || fds
[1] == -1) goto fail
;
842 while ((num
= read( fds
[0], buf
, sizeof(buf
) )) != 0)
844 if (num
== -1) goto fail
;
845 if (write( fds
[1], buf
, num
) != num
) goto fail
;
850 if (fds
[1] != -1) close( fds
[1] );
851 if (fds
[0] != -1) close( fds
[0] );
855 static BOOL
get_internal_fallback_ppd( const WCHAR
*ppd
)
857 static const WCHAR typeW
[] = {'P','P','D','F','I','L','E',0};
863 HRSRC res
= FindResourceW( WINSPOOL_hInstance
, MAKEINTRESOURCEW(1), typeW
);
865 if (!res
|| !(ptr
= LoadResource( WINSPOOL_hInstance
, res
))) return FALSE
;
866 size
= SizeofResource( WINSPOOL_hInstance
, res
);
867 end
= memchr( ptr
, 0, size
); /* resource file may contain additional nulls */
868 if (end
) size
= end
- ptr
;
869 file
= CreateFileW( ppd
, GENERIC_WRITE
, FILE_SHARE_READ
, NULL
, CREATE_ALWAYS
, 0, 0 );
870 if (file
== INVALID_HANDLE_VALUE
) return FALSE
;
871 ret
= WriteFile( file
, ptr
, size
, &written
, NULL
) && written
== size
;
873 if (ret
) TRACE( "using internal fallback for %s\n", debugstr_w( ppd
));
874 else DeleteFileW( ppd
);
878 static BOOL
get_fallback_ppd( const char *printer_name
, const WCHAR
*ppd
)
880 char *dst
, *src
= get_fallback_ppd_name( printer_name
);
883 if (!src
) return get_internal_fallback_ppd( ppd
);
885 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name
), debugstr_w(ppd
), debugstr_a(src
) );
887 if (!(dst
= wine_get_unix_file_name( ppd
))) goto fail
;
889 if (symlink( src
, dst
) == -1)
890 if (errno
!= ENOSYS
|| !copy_file( src
, dst
))
895 HeapFree( GetProcessHeap(), 0, dst
);
896 HeapFree( GetProcessHeap(), 0, src
);
900 static WCHAR
*get_ppd_filename( const WCHAR
*dir
, const WCHAR
*file_name
)
902 static const WCHAR dot_ppd
[] = {'.','p','p','d',0};
903 static const WCHAR invalid_chars
[] = {'*','?','<','>','|','"','/','\\',0};
904 int dir_len
= strlenW( dir
), file_len
= strlenW( file_name
);
905 int len
= (dir_len
+ file_len
+ ARRAY_SIZE( dot_ppd
)) * sizeof(WCHAR
);
906 WCHAR
*ppd
= HeapAlloc( GetProcessHeap(), 0, len
), *p
;
908 if (!ppd
) return NULL
;
909 memcpy( ppd
, dir
, dir_len
* sizeof(WCHAR
) );
910 memcpy( ppd
+ dir_len
, file_name
, file_len
* sizeof(WCHAR
) );
911 memcpy( ppd
+ dir_len
+ file_len
, dot_ppd
, sizeof(dot_ppd
) );
914 while ((p
= strpbrkW( p
, invalid_chars
))) *p
++ = '_';
919 static WCHAR
*get_ppd_dir( void )
921 static const WCHAR wine_ppds
[] = {'w','i','n','e','_','p','p','d','s','\\',0};
923 WCHAR
*dir
, tmp_path
[MAX_PATH
];
926 len
= GetTempPathW( ARRAY_SIZE( tmp_path
), tmp_path
);
927 if (!len
) return NULL
;
928 dir
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) + sizeof(wine_ppds
) ) ;
929 if (!dir
) return NULL
;
931 memcpy( dir
, tmp_path
, len
* sizeof(WCHAR
) );
932 memcpy( dir
+ len
, wine_ppds
, sizeof(wine_ppds
) );
933 res
= CreateDirectoryW( dir
, NULL
);
934 if (!res
&& GetLastError() != ERROR_ALREADY_EXISTS
)
936 HeapFree( GetProcessHeap(), 0, dir
);
939 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir
) );
943 static void unlink_ppd( const WCHAR
*ppd
)
945 char *unix_name
= wine_get_unix_file_name( ppd
);
947 HeapFree( GetProcessHeap(), 0, unix_name
);
950 #ifdef SONAME_LIBCUPS
952 static void *cupshandle
;
955 DO_FUNC(cupsAddOption); \
956 DO_FUNC(cupsFreeDests); \
957 DO_FUNC(cupsFreeOptions); \
958 DO_FUNC(cupsGetDests); \
959 DO_FUNC(cupsGetOption); \
960 DO_FUNC(cupsParseOptions); \
961 DO_FUNC(cupsPrintFile)
962 #define CUPS_OPT_FUNCS \
963 DO_FUNC(cupsGetNamedDest); \
964 DO_FUNC(cupsGetPPD); \
965 DO_FUNC(cupsGetPPD3); \
966 DO_FUNC(cupsLastErrorString)
968 #define DO_FUNC(f) static typeof(f) *p##f
971 static cups_dest_t
* (*pcupsGetNamedDest
)(http_t
*, const char *, const char *);
972 static const char * (*pcupsGetPPD
)(const char *);
973 static http_status_t (*pcupsGetPPD3
)(http_t
*, const char *, time_t *, char *, size_t);
974 static const char * (*pcupsLastErrorString
)(void);
976 static http_status_t
cupsGetPPD3_wrapper( http_t
*http
, const char *name
,
977 time_t *modtime
, char *buffer
,
982 if (pcupsGetPPD3
) return pcupsGetPPD3( http
, name
, modtime
, buffer
, bufsize
);
984 if (!pcupsGetPPD
) return HTTP_NOT_FOUND
;
986 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
989 ppd
= pcupsGetPPD( name
);
991 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd
) );
993 if (!ppd
) return HTTP_NOT_FOUND
;
995 if (rename( ppd
, buffer
) == -1)
997 BOOL res
= copy_file( ppd
, buffer
);
999 if (!res
) return HTTP_NOT_FOUND
;
1004 static BOOL
get_cups_ppd( const char *printer_name
, const WCHAR
*ppd
)
1007 http_status_t http_status
;
1008 char *unix_name
= wine_get_unix_file_name( ppd
);
1010 TRACE( "(%s, %s)\n", debugstr_a(printer_name
), debugstr_w(ppd
) );
1012 if (!unix_name
) return FALSE
;
1014 http_status
= cupsGetPPD3_wrapper( 0, printer_name
, &modtime
,
1015 unix_name
, strlen( unix_name
) + 1 );
1017 if (http_status
!= HTTP_OK
) unlink( unix_name
);
1018 HeapFree( GetProcessHeap(), 0, unix_name
);
1020 if (http_status
== HTTP_OK
) return TRUE
;
1022 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
1023 debugstr_a(printer_name
), http_status
);
1024 return get_fallback_ppd( printer_name
, ppd
);
1027 static WCHAR
*get_cups_option( const char *name
, int num_options
, cups_option_t
*options
)
1033 value
= pcupsGetOption( name
, num_options
, options
);
1034 if (!value
) return NULL
;
1036 len
= MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, NULL
, 0 );
1037 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1038 if (ret
) MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, ret
, len
);
1043 static cups_ptype_t
get_cups_printer_type( const cups_dest_t
*dest
)
1045 WCHAR
*type
= get_cups_option( "printer-type", dest
->num_options
, dest
->options
), *end
;
1046 cups_ptype_t ret
= 0;
1050 ret
= (cups_ptype_t
)strtoulW( type
, &end
, 10 );
1053 HeapFree( GetProcessHeap(), 0, type
);
1057 static void load_cups(void)
1059 cupshandle
= dlopen( SONAME_LIBCUPS
, RTLD_NOW
);
1060 if (!cupshandle
) return;
1062 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
1064 #define DO_FUNC(x) \
1065 p##x = dlsym( cupshandle, #x ); \
1068 ERR("failed to load symbol %s\n", #x); \
1069 cupshandle = NULL; \
1074 #define DO_FUNC(x) p##x = dlsym( cupshandle, #x )
1079 static BOOL
CUPS_LoadPrinters(void)
1082 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
1084 PRINTER_INFO_2W pi2
;
1085 WCHAR
*port
, *ppd_dir
= NULL
, *ppd
;
1086 HKEY hkeyPrinter
, hkeyPrinters
;
1087 WCHAR nameW
[MAX_PATH
];
1088 HANDLE added_printer
;
1089 cups_ptype_t printer_type
;
1091 if (!cupshandle
) return FALSE
;
1093 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1095 ERR("Can't create Printers key\n");
1099 nrofdests
= pcupsGetDests(&dests
);
1100 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
1101 for (i
=0;i
<nrofdests
;i
++) {
1102 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, ARRAY_SIZE(nameW
));
1103 printer_type
= get_cups_printer_type( dests
+ i
);
1105 TRACE( "Printer %d: %s. printer_type %x\n", i
, debugstr_w(nameW
), printer_type
);
1107 if (printer_type
& 0x2000000 /* CUPS_PRINTER_SCANNER */)
1109 TRACE( "skipping scanner-only device\n" );
1113 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
1114 lstrcpyW(port
, CUPS_Port
);
1115 lstrcatW(port
, nameW
);
1117 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1118 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1119 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1121 TRACE("Printer already exists\n");
1122 /* overwrite old LPR:* port */
1123 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
1124 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1125 /* flag that the PPD file should be checked for an update */
1126 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1127 RegCloseKey(hkeyPrinter
);
1129 BOOL added_driver
= FALSE
;
1131 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir()))
1133 HeapFree( GetProcessHeap(), 0, port
);
1136 ppd
= get_ppd_filename( ppd_dir
, nameW
);
1137 if (get_cups_ppd( dests
[i
].name
, ppd
))
1139 added_driver
= add_printer_driver( nameW
, ppd
);
1142 HeapFree( GetProcessHeap(), 0, ppd
);
1145 HeapFree( GetProcessHeap(), 0, port
);
1149 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
1150 pi2
.pPrinterName
= nameW
;
1151 pi2
.pDatatype
= rawW
;
1152 pi2
.pPrintProcessor
= WinPrintW
;
1153 pi2
.pDriverName
= nameW
;
1154 pi2
.pComment
= get_cups_option( "printer-info", dests
[i
].num_options
, dests
[i
].options
);
1155 pi2
.pLocation
= get_cups_option( "printer-location", dests
[i
].num_options
, dests
[i
].options
);
1156 pi2
.pPortName
= port
;
1157 pi2
.pParameters
= emptyStringW
;
1158 pi2
.pShareName
= emptyStringW
;
1159 pi2
.pSepFile
= emptyStringW
;
1161 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
1162 if (added_printer
) ClosePrinter( added_printer
);
1163 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1164 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
1166 HeapFree( GetProcessHeap(), 0, pi2
.pComment
);
1167 HeapFree( GetProcessHeap(), 0, pi2
.pLocation
);
1169 HeapFree( GetProcessHeap(), 0, port
);
1172 if (dests
[i
].is_default
) {
1173 SetDefaultPrinterW(nameW
);
1180 RemoveDirectoryW( ppd_dir
);
1181 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1184 if (hadprinter
&& !haddefault
) {
1185 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, ARRAY_SIZE(nameW
));
1186 SetDefaultPrinterW(nameW
);
1188 pcupsFreeDests(nrofdests
, dests
);
1189 RegCloseKey(hkeyPrinters
);
1195 static char *get_queue_name( HANDLE printer
, BOOL
*cups
)
1197 WCHAR
*port
, *name
= NULL
;
1198 DWORD err
, needed
, type
;
1204 err
= WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
);
1205 if (err
) return NULL
;
1206 err
= RegQueryValueExW( key
, PortW
, 0, &type
, NULL
, &needed
);
1208 port
= HeapAlloc( GetProcessHeap(), 0, needed
);
1209 if (!port
) goto end
;
1210 RegQueryValueExW( key
, PortW
, 0, &type
, (BYTE
*)port
, &needed
);
1212 if (!strncmpW( port
, CUPS_Port
, ARRAY_SIZE( CUPS_Port
) -1 ))
1214 name
= port
+ ARRAY_SIZE( CUPS_Port
) - 1;
1217 else if (!strncmpW( port
, LPR_Port
, ARRAY_SIZE( LPR_Port
) -1 ))
1218 name
= port
+ ARRAY_SIZE( LPR_Port
) - 1;
1221 needed
= WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
1222 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
1223 if(ret
) WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, ret
, needed
, NULL
, NULL
);
1225 HeapFree( GetProcessHeap(), 0, port
);
1232 static void set_ppd_overrides( HANDLE printer
)
1236 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1238 PMPrintSession session
= NULL
;
1239 PMPageFormat format
= NULL
;
1241 CFStringRef paper_name
;
1244 status
= PMCreateSession( &session
);
1245 if (status
) goto end
;
1247 status
= PMCreatePageFormat( &format
);
1248 if (status
) goto end
;
1250 status
= PMSessionDefaultPageFormat( session
, format
);
1251 if (status
) goto end
;
1253 status
= PMGetPageFormatPaper( format
, &paper
);
1254 if (status
) goto end
;
1256 status
= PMPaperGetPPDPaperName( paper
, &paper_name
);
1257 if (status
) goto end
;
1260 range
.length
= CFStringGetLength( paper_name
);
1261 size
= (range
.length
+ 1) * sizeof(WCHAR
);
1263 wstr
= HeapAlloc( GetProcessHeap(), 0, size
);
1264 CFStringGetCharacters( paper_name
, range
, (UniChar
*)wstr
);
1265 wstr
[range
.length
] = 0;
1268 if (format
) PMRelease( format
);
1269 if (session
) PMRelease( session
);
1272 SetPrinterDataExW( printer
, PPD_Overrides
, DefaultPageSize
, REG_SZ
, (BYTE
*)wstr
, size
);
1273 HeapFree( GetProcessHeap(), 0, wstr
);
1276 static BOOL
update_driver( HANDLE printer
)
1279 const WCHAR
*name
= get_opened_printer_name( printer
);
1280 WCHAR
*ppd_dir
, *ppd
;
1283 if (!name
) return FALSE
;
1284 queue_name
= get_queue_name( printer
, &is_cups
);
1285 if (!queue_name
) return FALSE
;
1287 if (!(ppd_dir
= get_ppd_dir()))
1289 HeapFree( GetProcessHeap(), 0, queue_name
);
1292 ppd
= get_ppd_filename( ppd_dir
, name
);
1294 #ifdef SONAME_LIBCUPS
1296 ret
= get_cups_ppd( queue_name
, ppd
);
1299 ret
= get_fallback_ppd( queue_name
, ppd
);
1303 TRACE( "updating driver %s\n", debugstr_w( name
) );
1304 ret
= add_printer_driver( name
, ppd
);
1307 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1308 HeapFree( GetProcessHeap(), 0, ppd
);
1309 HeapFree( GetProcessHeap(), 0, queue_name
);
1311 set_ppd_overrides( printer
);
1313 /* call into the driver to update the devmode */
1314 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
1319 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
1321 PRINTER_INFO_2A pinfo2a
;
1324 char *e
,*s
,*name
,*prettyname
,*devname
;
1325 BOOL ret
= FALSE
, set_default
= FALSE
;
1326 char *port
= NULL
, *env_default
;
1327 HKEY hkeyPrinter
, hkeyPrinters
= NULL
;
1328 WCHAR devnameW
[MAX_PATH
], *ppd_dir
= NULL
, *ppd
;
1329 HANDLE added_printer
;
1331 while (isspace(*pent
)) pent
++;
1332 r
= strchr(pent
,':');
1334 name_len
= r
- pent
;
1336 name_len
= strlen(pent
);
1337 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
1338 memcpy(name
, pent
, name_len
);
1339 name
[name_len
] = '\0';
1345 TRACE("name=%s entry=%s\n",name
, pent
);
1347 if(ispunct(*name
)) { /* a tc entry, not a real printer */
1348 TRACE("skipping tc entry\n");
1352 if(strstr(pent
,":server")) { /* server only version so skip */
1353 TRACE("skipping server entry\n");
1357 /* Determine whether this is a postscript printer. */
1360 env_default
= getenv("PRINTER");
1362 /* Get longest name, usually the one at the right for later display. */
1363 while((s
=strchr(prettyname
,'|'))) {
1366 while(isspace(*--e
)) *e
= '\0';
1367 TRACE("\t%s\n", debugstr_a(prettyname
));
1368 if(env_default
&& !_strnicmp(prettyname
, env_default
, -1)) set_default
= TRUE
;
1369 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
1372 e
= prettyname
+ strlen(prettyname
);
1373 while(isspace(*--e
)) *e
= '\0';
1374 TRACE("\t%s\n", debugstr_a(prettyname
));
1375 if(env_default
&& !_strnicmp(prettyname
, env_default
, -1)) set_default
= TRUE
;
1377 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1378 * if it is too long, we use it as comment below. */
1379 devname
= prettyname
;
1380 if (strlen(devname
)>=CCHDEVICENAME
-1)
1382 if (strlen(devname
)>=CCHDEVICENAME
-1) {
1387 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
1388 sprintf(port
,"LPR:%s",name
);
1390 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1392 ERR("Can't create Printers key\n");
1397 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, ARRAY_SIZE(devnameW
));
1399 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1400 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1401 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1403 TRACE("Printer already exists\n");
1404 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1405 /* flag that the PPD file should be checked for an update */
1406 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1407 RegCloseKey(hkeyPrinter
);
1409 static CHAR data_type
[] = "RAW",
1410 print_proc
[] = "WinPrint",
1411 comment
[] = "WINEPS Printer using LPR",
1412 params
[] = "<parameters?>",
1413 share_name
[] = "<share name?>",
1414 sep_file
[] = "<sep file?>";
1415 BOOL added_driver
= FALSE
;
1417 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir())) goto end
;
1418 ppd
= get_ppd_filename( ppd_dir
, devnameW
);
1419 if (get_fallback_ppd( devname
, ppd
))
1421 added_driver
= add_printer_driver( devnameW
, ppd
);
1424 HeapFree( GetProcessHeap(), 0, ppd
);
1425 if (!added_driver
) goto end
;
1427 memset(&pinfo2a
,0,sizeof(pinfo2a
));
1428 pinfo2a
.pPrinterName
= devname
;
1429 pinfo2a
.pDatatype
= data_type
;
1430 pinfo2a
.pPrintProcessor
= print_proc
;
1431 pinfo2a
.pDriverName
= devname
;
1432 pinfo2a
.pComment
= comment
;
1433 pinfo2a
.pLocation
= prettyname
;
1434 pinfo2a
.pPortName
= port
;
1435 pinfo2a
.pParameters
= params
;
1436 pinfo2a
.pShareName
= share_name
;
1437 pinfo2a
.pSepFile
= sep_file
;
1439 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
1440 if (added_printer
) ClosePrinter( added_printer
);
1441 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1442 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
1445 if (isfirst
|| set_default
)
1446 set_default_printer(devname
, name
);
1449 if (hkeyPrinters
) RegCloseKey( hkeyPrinters
);
1452 RemoveDirectoryW( ppd_dir
);
1453 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1455 HeapFree(GetProcessHeap(), 0, port
);
1456 HeapFree(GetProcessHeap(), 0, name
);
1461 PRINTCAP_LoadPrinters(void) {
1462 BOOL hadprinter
= FALSE
;
1466 BOOL had_bash
= FALSE
;
1468 f
= fopen("/etc/printcap","r");
1472 while(fgets(buf
,sizeof(buf
),f
)) {
1475 end
=strchr(buf
,'\n');
1479 while(isspace(*start
)) start
++;
1480 if(*start
== '#' || *start
== '\0')
1483 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
1484 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1485 HeapFree(GetProcessHeap(),0,pent
);
1489 if (end
&& *--end
== '\\') {
1496 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
1499 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
1505 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1506 HeapFree(GetProcessHeap(),0,pent
);
1512 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
1515 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
1516 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
1518 return ERROR_FILE_NOT_FOUND
;
1521 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
1523 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
1524 DWORD ret
= ERROR_FILE_NOT_FOUND
;
1526 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1527 and we support these drivers. NT writes DEVMODEW so somehow
1528 we'll need to distinguish between these when we support NT
1533 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
1534 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1535 HeapFree( GetProcessHeap(), 0, dmA
);
1541 /******************************************************************
1542 * get_servername_from_name (internal)
1544 * for an external server, a copy of the serverpart from the full name is returned
1547 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1551 WCHAR buffer
[MAX_PATH
];
1554 if (name
== NULL
) return NULL
;
1555 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1557 server
= strdupW(&name
[2]); /* skip over both backslash */
1558 if (server
== NULL
) return NULL
;
1560 /* strip '\' and the printername */
1561 ptr
= strchrW(server
, '\\');
1562 if (ptr
) ptr
[0] = '\0';
1564 TRACE("found %s\n", debugstr_w(server
));
1566 len
= ARRAY_SIZE(buffer
);
1567 if (GetComputerNameW(buffer
, &len
)) {
1568 if (lstrcmpW(buffer
, server
) == 0) {
1569 /* The requested Servername is our computername */
1570 HeapFree(GetProcessHeap(), 0, server
);
1577 /******************************************************************
1578 * get_basename_from_name (internal)
1580 * skip over the serverpart from the full name
1583 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1585 if (name
== NULL
) return NULL
;
1586 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1587 /* skip over the servername and search for the following '\' */
1588 name
= strchrW(&name
[2], '\\');
1589 if ((name
) && (name
[1])) {
1590 /* found a separator ('\') followed by a name:
1591 skip over the separator and return the rest */
1596 /* no basename present (we found only a servername) */
1603 static void free_printer_entry( opened_printer_t
*printer
)
1605 /* the queue is shared, so don't free that here */
1606 HeapFree( GetProcessHeap(), 0, printer
->printername
);
1607 HeapFree( GetProcessHeap(), 0, printer
->name
);
1608 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
1609 HeapFree( GetProcessHeap(), 0, printer
);
1612 /******************************************************************
1613 * get_opened_printer_entry
1614 * Get the first place empty in the opened printer table
1617 * - pDefault is ignored
1619 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1621 UINT_PTR handle
= nb_printer_handles
, i
;
1622 jobqueue_t
*queue
= NULL
;
1623 opened_printer_t
*printer
= NULL
;
1625 LPCWSTR printername
;
1627 if ((backend
== NULL
) && !load_backend()) return NULL
;
1629 servername
= get_servername_from_name(name
);
1631 FIXME("server %s not supported\n", debugstr_w(servername
));
1632 HeapFree(GetProcessHeap(), 0, servername
);
1633 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1637 printername
= get_basename_from_name(name
);
1638 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1640 /* an empty printername is invalid */
1641 if (printername
&& (!printername
[0])) {
1642 SetLastError(ERROR_INVALID_PARAMETER
);
1646 EnterCriticalSection(&printer_handles_cs
);
1648 for (i
= 0; i
< nb_printer_handles
; i
++)
1650 if (!printer_handles
[i
])
1652 if(handle
== nb_printer_handles
)
1657 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1658 queue
= printer_handles
[i
]->queue
;
1662 if (handle
>= nb_printer_handles
)
1664 opened_printer_t
**new_array
;
1665 if (printer_handles
)
1666 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1667 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1669 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1670 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1677 printer_handles
= new_array
;
1678 nb_printer_handles
+= 16;
1681 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1687 /* get a printer handle from the backend */
1688 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1693 /* clone the base name. This is NULL for the printserver */
1694 printer
->printername
= strdupW(printername
);
1696 /* clone the full name */
1697 printer
->name
= strdupW(name
);
1698 if (name
&& (!printer
->name
)) {
1703 if (pDefault
&& pDefault
->pDevMode
)
1704 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
1707 printer
->queue
= queue
;
1710 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1711 if (!printer
->queue
) {
1715 list_init(&printer
->queue
->jobs
);
1716 printer
->queue
->ref
= 0;
1718 InterlockedIncrement(&printer
->queue
->ref
);
1720 printer_handles
[handle
] = printer
;
1723 LeaveCriticalSection(&printer_handles_cs
);
1724 if (!handle
&& printer
) {
1725 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1726 free_printer_entry( printer
);
1729 return (HANDLE
)handle
;
1732 static void old_printer_check( BOOL delete_phase
)
1734 PRINTER_INFO_5W
* pi
;
1735 DWORD needed
, type
, num
, delete, i
, size
;
1736 const DWORD one
= 1;
1740 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1741 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1743 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1744 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1745 for (i
= 0; i
< num
; i
++)
1747 if (!pi
[i
].pPortName
) continue;
1749 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1750 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1753 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1757 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1763 size
= sizeof( delete );
1764 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1768 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1769 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1771 DeletePrinter( hprn
);
1772 ClosePrinter( hprn
);
1774 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1778 HeapFree(GetProcessHeap(), 0, pi
);
1781 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1782 'M','U','T','E','X','_','_','\0'};
1783 static HANDLE init_mutex
;
1785 void WINSPOOL_LoadSystemPrinters(void)
1787 HKEY hkey
, hkeyPrinters
;
1788 DWORD needed
, num
, i
;
1789 WCHAR PrinterName
[256];
1792 #ifdef SONAME_LIBCUPS
1796 /* FIXME: The init code should be moved to spoolsv.exe */
1797 init_mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1800 ERR( "Failed to create mutex\n" );
1803 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1805 WaitForSingleObject( init_mutex
, INFINITE
);
1806 ReleaseMutex( init_mutex
);
1807 TRACE( "Init already done\n" );
1811 /* This ensures that all printer entries have a valid Name value. If causes
1812 problems later if they don't. If one is found to be missed we create one
1813 and set it equal to the name of the key */
1814 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1815 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1816 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1817 for(i
= 0; i
< num
; i
++) {
1818 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, ARRAY_SIZE(PrinterName
)) == ERROR_SUCCESS
) {
1819 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1820 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1821 set_reg_szW(hkey
, NameW
, PrinterName
);
1828 RegCloseKey(hkeyPrinters
);
1831 old_printer_check( FALSE
);
1833 #ifdef SONAME_LIBCUPS
1834 done
= CUPS_LoadPrinters();
1837 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1838 PRINTCAP_LoadPrinters();
1840 old_printer_check( TRUE
);
1842 ReleaseMutex( init_mutex
);
1846 /******************************************************************
1849 * Get the pointer to the specified job.
1850 * Should hold the printer_handles_cs before calling.
1852 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1854 opened_printer_t
*printer
= get_opened_printer(hprn
);
1857 if(!printer
) return NULL
;
1858 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1860 if(job
->job_id
== JobId
)
1866 /******************************************************************
1867 * convert_printerinfo_W_to_A [internal]
1870 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1871 DWORD level
, DWORD outlen
, DWORD numentries
)
1877 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1879 len
= pi_sizeof
[level
] * numentries
;
1880 ptr
= (LPSTR
) out
+ len
;
1883 /* copy the numbers of all PRINTER_INFO_* first */
1884 memcpy(out
, pPrintersW
, len
);
1886 while (id
< numentries
) {
1890 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1891 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1893 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1894 if (piW
->pDescription
) {
1895 piA
->pDescription
= ptr
;
1896 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1897 ptr
, outlen
, NULL
, NULL
);
1903 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1904 ptr
, outlen
, NULL
, NULL
);
1908 if (piW
->pComment
) {
1909 piA
->pComment
= ptr
;
1910 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1911 ptr
, outlen
, NULL
, NULL
);
1920 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1921 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1924 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1925 if (piW
->pServerName
) {
1926 piA
->pServerName
= ptr
;
1927 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1928 ptr
, outlen
, NULL
, NULL
);
1932 if (piW
->pPrinterName
) {
1933 piA
->pPrinterName
= ptr
;
1934 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1935 ptr
, outlen
, NULL
, NULL
);
1939 if (piW
->pShareName
) {
1940 piA
->pShareName
= ptr
;
1941 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1942 ptr
, outlen
, NULL
, NULL
);
1946 if (piW
->pPortName
) {
1947 piA
->pPortName
= ptr
;
1948 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1949 ptr
, outlen
, NULL
, NULL
);
1953 if (piW
->pDriverName
) {
1954 piA
->pDriverName
= ptr
;
1955 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1956 ptr
, outlen
, NULL
, NULL
);
1960 if (piW
->pComment
) {
1961 piA
->pComment
= ptr
;
1962 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1963 ptr
, outlen
, NULL
, NULL
);
1967 if (piW
->pLocation
) {
1968 piA
->pLocation
= ptr
;
1969 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1970 ptr
, outlen
, NULL
, NULL
);
1975 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1977 /* align DEVMODEA to a DWORD boundary */
1978 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1982 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1983 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1984 memcpy(ptr
, dmA
, len
);
1985 HeapFree(GetProcessHeap(), 0, dmA
);
1991 if (piW
->pSepFile
) {
1992 piA
->pSepFile
= ptr
;
1993 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1994 ptr
, outlen
, NULL
, NULL
);
1998 if (piW
->pPrintProcessor
) {
1999 piA
->pPrintProcessor
= ptr
;
2000 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
2001 ptr
, outlen
, NULL
, NULL
);
2005 if (piW
->pDatatype
) {
2006 piA
->pDatatype
= ptr
;
2007 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
2008 ptr
, outlen
, NULL
, NULL
);
2012 if (piW
->pParameters
) {
2013 piA
->pParameters
= ptr
;
2014 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
2015 ptr
, outlen
, NULL
, NULL
);
2019 if (piW
->pSecurityDescriptor
) {
2020 piA
->pSecurityDescriptor
= NULL
;
2021 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
2028 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
2029 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
2031 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
2033 if (piW
->pPrinterName
) {
2034 piA
->pPrinterName
= ptr
;
2035 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
2036 ptr
, outlen
, NULL
, NULL
);
2040 if (piW
->pServerName
) {
2041 piA
->pServerName
= ptr
;
2042 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
2043 ptr
, outlen
, NULL
, NULL
);
2052 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
2053 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
2055 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
2057 if (piW
->pPrinterName
) {
2058 piA
->pPrinterName
= ptr
;
2059 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
2060 ptr
, outlen
, NULL
, NULL
);
2064 if (piW
->pPortName
) {
2065 piA
->pPortName
= ptr
;
2066 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
2067 ptr
, outlen
, NULL
, NULL
);
2074 case 6: /* 6A and 6W are the same structure */
2079 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
2080 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
2082 TRACE("(%u) #%u\n", level
, id
);
2083 if (piW
->pszObjectGUID
) {
2084 piA
->pszObjectGUID
= ptr
;
2085 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
2086 ptr
, outlen
, NULL
, NULL
);
2096 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
2097 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
2100 TRACE("(%u) #%u\n", level
, id
);
2101 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
2103 /* align DEVMODEA to a DWORD boundary */
2104 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
2108 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
2109 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
2110 memcpy(ptr
, dmA
, len
);
2111 HeapFree(GetProcessHeap(), 0, dmA
);
2121 FIXME("for level %u\n", level
);
2123 pPrintersW
+= pi_sizeof
[level
];
2124 out
+= pi_sizeof
[level
];
2129 /******************************************************************
2130 * convert_driverinfo_W_to_A [internal]
2133 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
2134 DWORD level
, DWORD outlen
, DWORD numentries
)
2140 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
2142 len
= di_sizeof
[level
] * numentries
;
2143 ptr
= (LPSTR
) out
+ len
;
2146 /* copy the numbers of all PRINTER_INFO_* first */
2147 memcpy(out
, pDriversW
, len
);
2149 #define COPY_STRING(fld) \
2152 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2153 ptr += len; outlen -= len;\
2155 #define COPY_MULTIZ_STRING(fld) \
2156 { LPWSTR p = diW->fld; if (p){ \
2159 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2160 ptr += len; outlen -= len; p += len;\
2162 while(len > 1 && outlen > 0); \
2165 while (id
< numentries
)
2171 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
2172 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
2174 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2181 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
2182 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
2184 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2187 COPY_STRING(pEnvironment
);
2188 COPY_STRING(pDriverPath
);
2189 COPY_STRING(pDataFile
);
2190 COPY_STRING(pConfigFile
);
2195 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
2196 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
2198 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2201 COPY_STRING(pEnvironment
);
2202 COPY_STRING(pDriverPath
);
2203 COPY_STRING(pDataFile
);
2204 COPY_STRING(pConfigFile
);
2205 COPY_STRING(pHelpFile
);
2206 COPY_MULTIZ_STRING(pDependentFiles
);
2207 COPY_STRING(pMonitorName
);
2208 COPY_STRING(pDefaultDataType
);
2213 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
2214 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
2216 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2219 COPY_STRING(pEnvironment
);
2220 COPY_STRING(pDriverPath
);
2221 COPY_STRING(pDataFile
);
2222 COPY_STRING(pConfigFile
);
2223 COPY_STRING(pHelpFile
);
2224 COPY_MULTIZ_STRING(pDependentFiles
);
2225 COPY_STRING(pMonitorName
);
2226 COPY_STRING(pDefaultDataType
);
2227 COPY_MULTIZ_STRING(pszzPreviousNames
);
2232 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
2233 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
2235 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2238 COPY_STRING(pEnvironment
);
2239 COPY_STRING(pDriverPath
);
2240 COPY_STRING(pDataFile
);
2241 COPY_STRING(pConfigFile
);
2246 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
2247 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
2249 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2252 COPY_STRING(pEnvironment
);
2253 COPY_STRING(pDriverPath
);
2254 COPY_STRING(pDataFile
);
2255 COPY_STRING(pConfigFile
);
2256 COPY_STRING(pHelpFile
);
2257 COPY_MULTIZ_STRING(pDependentFiles
);
2258 COPY_STRING(pMonitorName
);
2259 COPY_STRING(pDefaultDataType
);
2260 COPY_MULTIZ_STRING(pszzPreviousNames
);
2261 COPY_STRING(pszMfgName
);
2262 COPY_STRING(pszOEMUrl
);
2263 COPY_STRING(pszHardwareID
);
2264 COPY_STRING(pszProvider
);
2269 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
2270 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
2272 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2275 COPY_STRING(pEnvironment
);
2276 COPY_STRING(pDriverPath
);
2277 COPY_STRING(pDataFile
);
2278 COPY_STRING(pConfigFile
);
2279 COPY_STRING(pHelpFile
);
2280 COPY_MULTIZ_STRING(pDependentFiles
);
2281 COPY_STRING(pMonitorName
);
2282 COPY_STRING(pDefaultDataType
);
2283 COPY_MULTIZ_STRING(pszzPreviousNames
);
2284 COPY_STRING(pszMfgName
);
2285 COPY_STRING(pszOEMUrl
);
2286 COPY_STRING(pszHardwareID
);
2287 COPY_STRING(pszProvider
);
2288 COPY_STRING(pszPrintProcessor
);
2289 COPY_STRING(pszVendorSetup
);
2290 COPY_MULTIZ_STRING(pszzColorProfiles
);
2291 COPY_STRING(pszInfPath
);
2292 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
2298 FIXME("for level %u\n", level
);
2301 pDriversW
+= di_sizeof
[level
];
2302 out
+= di_sizeof
[level
];
2307 #undef COPY_MULTIZ_STRING
2311 /***********************************************************
2314 static void *printer_info_AtoW( const void *data
, DWORD level
)
2317 UNICODE_STRING usBuffer
;
2319 if (!data
) return NULL
;
2321 if (level
< 1 || level
> 9) return NULL
;
2323 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
2324 if (!ret
) return NULL
;
2326 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
2332 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
2333 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
2335 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
2336 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
2337 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
2338 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
2339 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
2340 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
2341 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
2342 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2343 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
2344 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
2345 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
2346 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
2353 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
2354 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
2356 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2361 FIXME( "Unhandled level %d\n", level
);
2362 HeapFree( GetProcessHeap(), 0, ret
);
2369 /***********************************************************
2372 static void free_printer_info( void *data
, DWORD level
)
2380 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
2382 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
2383 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
2384 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
2385 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
2386 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
2387 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
2388 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
2389 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2390 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
2391 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
2392 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
2393 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
2400 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
2402 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2407 FIXME( "Unhandled level %d\n", level
);
2410 HeapFree( GetProcessHeap(), 0, data
);
2414 /******************************************************************
2415 * DeviceCapabilities [WINSPOOL.@]
2416 * DeviceCapabilitiesA [WINSPOOL.@]
2419 INT WINAPI
DeviceCapabilitiesA(const char *device
, const char *portA
, WORD cap
,
2420 char *output
, DEVMODEA
*devmodeA
)
2422 WCHAR
*device_name
= NULL
, *port
= NULL
;
2423 DEVMODEW
*devmode
= NULL
;
2426 len
= MultiByteToWideChar(CP_ACP
, 0, device
, -1, NULL
, 0);
2428 device_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2429 MultiByteToWideChar(CP_ACP
, 0, device
, -1, device_name
, len
);
2432 len
= MultiByteToWideChar(CP_ACP
, 0, portA
, -1, NULL
, 0);
2434 port
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2435 MultiByteToWideChar(CP_ACP
, 0, portA
, -1, port
, len
);
2438 if (devmodeA
) devmode
= GdiConvertToDevmodeW( devmodeA
);
2440 if (output
&& (cap
== DC_BINNAMES
|| cap
== DC_FILEDEPENDENCIES
|| cap
== DC_PAPERNAMES
)) {
2441 /* These need A -> W translation */
2442 unsigned int size
= 0, i
;
2445 ret
= DeviceCapabilitiesW(device_name
, port
, cap
, NULL
, devmode
);
2446 if (ret
== -1) return ret
;
2453 case DC_FILEDEPENDENCIES
:
2457 outputW
= HeapAlloc(GetProcessHeap(), 0, size
* ret
* sizeof(WCHAR
));
2458 ret
= DeviceCapabilitiesW(device_name
, port
, cap
, outputW
, devmode
);
2459 for (i
= 0; i
< ret
; i
++)
2460 WideCharToMultiByte(CP_ACP
, 0, outputW
+ (i
* size
), -1,
2461 output
+ (i
* size
), size
, NULL
, NULL
);
2462 HeapFree(GetProcessHeap(), 0, outputW
);
2464 ret
= DeviceCapabilitiesW(device_name
, port
, cap
, (WCHAR
*)output
, devmode
);
2466 HeapFree(GetProcessHeap(), 0, device_name
);
2467 HeapFree(GetProcessHeap(), 0, devmode
);
2468 HeapFree(GetProcessHeap(), 0, port
);
2472 /*****************************************************************************
2473 * DeviceCapabilitiesW [WINSPOOL.@]
2476 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2477 WORD fwCapability
, LPWSTR pOutput
,
2478 const DEVMODEW
*pDevMode
)
2480 config_module_t
*config
;
2483 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice
), debugstr_w(pPort
), fwCapability
,
2486 if (!(config
= get_config_module(pDevice
, TRUE
))) {
2487 WARN("Could not load config module for %s\n", debugstr_w(pDevice
));
2491 ret
= config
->pDrvDeviceCapabilities(NULL
/* FIXME */, pDevice
, fwCapability
,
2493 release_config_module(config
);
2497 /******************************************************************
2498 * DocumentPropertiesA [WINSPOOL.@]
2500 LONG WINAPI
DocumentPropertiesA(HWND hwnd
, HANDLE printer
, char *device_name
, DEVMODEA
*output
,
2501 DEVMODEA
*input
, DWORD mode
)
2503 DEVMODEW
*outputW
= NULL
, *inputW
= NULL
;
2504 WCHAR
*device
= NULL
;
2508 TRACE("(%p,%p,%s,%p,%p,%d)\n", hwnd
, printer
, debugstr_a(device_name
), output
, input
, mode
);
2510 len
= MultiByteToWideChar(CP_ACP
, 0, device_name
, -1, NULL
, 0);
2512 device
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2513 MultiByteToWideChar(CP_ACP
, 0, device_name
, -1, device
, len
);
2516 if (output
&& (mode
& (DM_COPY
| DM_UPDATE
))) {
2517 ret
= DocumentPropertiesW(hwnd
, printer
, device
, NULL
, NULL
, 0);
2519 HeapFree(GetProcessHeap(), 0, device
);
2522 outputW
= HeapAlloc(GetProcessHeap(), 0, ret
);
2525 if (input
) inputW
= GdiConvertToDevmodeW(input
);
2527 ret
= DocumentPropertiesW(hwnd
, printer
, device
, outputW
, inputW
, mode
);
2529 if (ret
>= 0 && outputW
&& (mode
& (DM_COPY
| DM_UPDATE
))) {
2530 DEVMODEA
*dmA
= DEVMODEdupWtoA( outputW
);
2531 if (dmA
) memcpy(output
, dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2532 HeapFree(GetProcessHeap(), 0, dmA
);
2535 HeapFree(GetProcessHeap(), 0, device
);
2536 HeapFree(GetProcessHeap(), 0, inputW
);
2537 HeapFree(GetProcessHeap(), 0, outputW
);
2539 if (!mode
&& ret
> 0) ret
-= CCHDEVICENAME
+ CCHFORMNAME
;
2544 /*****************************************************************************
2545 * DocumentPropertiesW (WINSPOOL.@)
2547 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2549 LPDEVMODEW pDevModeOutput
,
2550 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2552 config_module_t
*config
= NULL
;
2553 const WCHAR
*device
= NULL
;
2556 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2557 hWnd
, hPrinter
, debugstr_w(pDeviceName
), pDevModeOutput
, pDevModeInput
, fMode
);
2559 device
= pDeviceName
&& pDeviceName
[0] ? pDeviceName
: get_opened_printer_name(hPrinter
);
2561 ERR("no device name\n");
2565 config
= get_config_module(device
, TRUE
);
2567 ERR("Could not load config module for %s\n", debugstr_w(device
));
2571 /* FIXME: This uses Wine-specific config file entry point.
2572 * We should use DrvDevicePropertySheets instead (requires CPSUI support first).
2574 ret
= config
->pDrvDocumentProperties(hWnd
, device
, pDevModeOutput
, pDevModeInput
, fMode
);
2575 release_config_module(config
);
2579 /*****************************************************************************
2580 * IsValidDevmodeA [WINSPOOL.@]
2582 * Validate a DEVMODE structure and fix errors if possible.
2585 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA pDevMode
, SIZE_T size
)
2587 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2595 /*****************************************************************************
2596 * IsValidDevmodeW [WINSPOOL.@]
2598 * Validate a DEVMODE structure and fix errors if possible.
2601 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW dm
, SIZE_T size
)
2609 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
2610 { DM_ORIENTATION
, F_SIZE(u1
.s1
.dmOrientation
) },
2611 { DM_PAPERSIZE
, F_SIZE(u1
.s1
.dmPaperSize
) },
2612 { DM_PAPERLENGTH
, F_SIZE(u1
.s1
.dmPaperLength
) },
2613 { DM_PAPERWIDTH
, F_SIZE(u1
.s1
.dmPaperWidth
) },
2614 { DM_SCALE
, F_SIZE(u1
.s1
.dmScale
) },
2615 { DM_COPIES
, F_SIZE(u1
.s1
.dmCopies
) },
2616 { DM_DEFAULTSOURCE
, F_SIZE(u1
.s1
.dmDefaultSource
) },
2617 { DM_PRINTQUALITY
, F_SIZE(u1
.s1
.dmPrintQuality
) },
2618 { DM_POSITION
, F_SIZE(u1
.s2
.dmPosition
) },
2619 { DM_DISPLAYORIENTATION
, F_SIZE(u1
.s2
.dmDisplayOrientation
) },
2620 { DM_DISPLAYFIXEDOUTPUT
, F_SIZE(u1
.s2
.dmDisplayFixedOutput
) },
2621 { DM_COLOR
, F_SIZE(dmColor
) },
2622 { DM_DUPLEX
, F_SIZE(dmDuplex
) },
2623 { DM_YRESOLUTION
, F_SIZE(dmYResolution
) },
2624 { DM_TTOPTION
, F_SIZE(dmTTOption
) },
2625 { DM_COLLATE
, F_SIZE(dmCollate
) },
2626 { DM_FORMNAME
, F_SIZE(dmFormName
) },
2627 { DM_LOGPIXELS
, F_SIZE(dmLogPixels
) },
2628 { DM_BITSPERPEL
, F_SIZE(dmBitsPerPel
) },
2629 { DM_PELSWIDTH
, F_SIZE(dmPelsWidth
) },
2630 { DM_PELSHEIGHT
, F_SIZE(dmPelsHeight
) },
2631 { DM_DISPLAYFLAGS
, F_SIZE(u2
.dmDisplayFlags
) },
2632 { DM_NUP
, F_SIZE(u2
.dmNup
) },
2633 { DM_DISPLAYFREQUENCY
, F_SIZE(dmDisplayFrequency
) },
2634 { DM_ICMMETHOD
, F_SIZE(dmICMMethod
) },
2635 { DM_ICMINTENT
, F_SIZE(dmICMIntent
) },
2636 { DM_MEDIATYPE
, F_SIZE(dmMediaType
) },
2637 { DM_DITHERTYPE
, F_SIZE(dmDitherType
) },
2638 { DM_PANNINGWIDTH
, F_SIZE(dmPanningWidth
) },
2639 { DM_PANNINGHEIGHT
, F_SIZE(dmPanningHeight
) }
2644 if (!dm
) return FALSE
;
2645 if (size
< FIELD_OFFSET(DEVMODEW
, dmFields
) + sizeof(dm
->dmFields
)) return FALSE
;
2647 for (i
= 0; i
< ARRAY_SIZE(map
); i
++)
2648 if ((dm
->dmFields
& map
[i
].flag
) && size
< map
[i
].size
)
2654 /******************************************************************
2655 * OpenPrinterA [WINSPOOL.@]
2660 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2661 LPPRINTER_DEFAULTSA pDefault
)
2663 UNICODE_STRING lpPrinterNameW
;
2664 UNICODE_STRING usBuffer
;
2665 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2666 PWSTR pwstrPrinterNameW
;
2669 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName
), phPrinter
, pDefault
);
2671 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2674 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2675 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2676 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2677 pDefaultW
= &DefaultW
;
2679 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2681 RtlFreeUnicodeString(&usBuffer
);
2682 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2684 RtlFreeUnicodeString(&lpPrinterNameW
);
2688 /******************************************************************
2689 * OpenPrinterW [WINSPOOL.@]
2691 * Open a Printer / Printserver or a Printer-Object
2694 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2695 * phPrinter [O] The resulting Handle is stored here
2696 * pDefault [I] PTR to Default Printer Settings or NULL
2703 * lpPrinterName is one of:
2704 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2705 *| Printer: "PrinterName"
2706 *| Printer-Object: "PrinterName,Job xxx"
2707 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2708 *| XcvPort: "Servername,XcvPort PortName"
2711 *| Printer-Object not supported
2712 *| pDefaults is ignored
2715 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2719 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2722 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2723 SetLastError(ERROR_INVALID_PARAMETER
);
2727 /* Get the unique handle of the printer or Printserver */
2728 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2730 if (*phPrinter
&& WINSPOOL_GetOpenedPrinterRegKey( *phPrinter
, &key
) == ERROR_SUCCESS
)
2732 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2734 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2735 WaitForSingleObject( init_mutex
, INFINITE
);
2736 status
= get_dword_from_reg( key
, StatusW
);
2737 set_reg_DWORD( key
, StatusW
, status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2738 ReleaseMutex( init_mutex
);
2739 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2740 update_driver( *phPrinter
);
2744 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2745 return (*phPrinter
!= 0);
2748 /******************************************************************
2749 * AddMonitorA [WINSPOOL.@]
2754 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2756 LPWSTR nameW
= NULL
;
2759 LPMONITOR_INFO_2A mi2a
;
2760 MONITOR_INFO_2W mi2w
;
2762 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2763 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2764 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2765 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2766 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2769 SetLastError(ERROR_INVALID_LEVEL
);
2773 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2779 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2780 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2781 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2784 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2786 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2787 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2788 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2790 if (mi2a
->pEnvironment
) {
2791 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2792 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2793 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2795 if (mi2a
->pDLLName
) {
2796 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2797 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2798 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2801 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2803 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2804 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2805 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2807 HeapFree(GetProcessHeap(), 0, nameW
);
2811 /******************************************************************************
2812 * AddMonitorW [WINSPOOL.@]
2814 * Install a Printmonitor
2817 * pName [I] Servername or NULL (local Computer)
2818 * Level [I] Structure-Level (Must be 2)
2819 * pMonitors [I] PTR to MONITOR_INFO_2
2826 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2829 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2831 LPMONITOR_INFO_2W mi2w
;
2833 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2834 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2835 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2836 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2837 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2839 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2842 SetLastError(ERROR_INVALID_LEVEL
);
2846 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2851 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2854 /******************************************************************
2855 * DeletePrinterDriverA [WINSPOOL.@]
2858 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2860 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2863 /******************************************************************
2864 * DeletePrinterDriverW [WINSPOOL.@]
2867 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2869 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2872 /******************************************************************
2873 * DeleteMonitorA [WINSPOOL.@]
2875 * See DeleteMonitorW.
2878 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2880 LPWSTR nameW
= NULL
;
2881 LPWSTR EnvironmentW
= NULL
;
2882 LPWSTR MonitorNameW
= NULL
;
2887 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2888 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2889 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2893 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2894 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2895 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2898 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2899 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2900 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2903 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2905 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2906 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2907 HeapFree(GetProcessHeap(), 0, nameW
);
2911 /******************************************************************
2912 * DeleteMonitorW [WINSPOOL.@]
2914 * Delete a specific Printmonitor from a Printing-Environment
2917 * pName [I] Servername or NULL (local Computer)
2918 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2919 * pMonitorName [I] Name of the Monitor, that should be deleted
2926 * pEnvironment is ignored in Windows for the local Computer.
2929 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2932 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2933 debugstr_w(pMonitorName
));
2935 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2937 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2941 /******************************************************************
2942 * DeletePortA [WINSPOOL.@]
2947 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2949 LPWSTR nameW
= NULL
;
2950 LPWSTR portW
= NULL
;
2954 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2956 /* convert servername to unicode */
2958 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2959 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2960 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2963 /* convert portname to unicode */
2965 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2966 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2967 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2970 res
= DeletePortW(nameW
, hWnd
, portW
);
2971 HeapFree(GetProcessHeap(), 0, nameW
);
2972 HeapFree(GetProcessHeap(), 0, portW
);
2976 /******************************************************************
2977 * DeletePortW [WINSPOOL.@]
2979 * Delete a specific Port
2982 * pName [I] Servername or NULL (local Computer)
2983 * hWnd [I] Handle to parent Window for the Dialog-Box
2984 * pPortName [I] Name of the Port, that should be deleted
2991 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2993 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2995 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2998 SetLastError(RPC_X_NULL_REF_POINTER
);
3002 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
3005 /******************************************************************************
3006 * WritePrinter [WINSPOOL.@]
3008 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
3010 opened_printer_t
*printer
;
3013 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
3015 EnterCriticalSection(&printer_handles_cs
);
3016 printer
= get_opened_printer(hPrinter
);
3019 SetLastError(ERROR_INVALID_HANDLE
);
3025 SetLastError(ERROR_SPL_NO_STARTDOC
);
3029 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
3031 LeaveCriticalSection(&printer_handles_cs
);
3035 /*****************************************************************************
3036 * AddFormA [WINSPOOL.@]
3038 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
3040 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
3044 /*****************************************************************************
3045 * AddFormW [WINSPOOL.@]
3047 BOOL WINAPI
AddFormW( HANDLE printer
, DWORD level
, BYTE
*form
)
3049 HANDLE handle
= get_backend_handle( printer
);
3051 TRACE( "(%p, %d, %p)\n", printer
, level
, form
);
3055 SetLastError( ERROR_INVALID_HANDLE
);
3059 return backend
->fpAddForm( handle
, level
, form
);
3062 /*****************************************************************************
3063 * AddJobA [WINSPOOL.@]
3065 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3068 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3072 SetLastError(ERROR_INVALID_LEVEL
);
3076 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
3079 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
3080 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
3081 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
3082 if(*pcbNeeded
> cbBuf
) {
3083 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3086 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
3087 addjobA
->JobId
= addjobW
->JobId
;
3088 addjobA
->Path
= (char *)(addjobA
+ 1);
3089 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
3095 /*****************************************************************************
3096 * AddJobW [WINSPOOL.@]
3098 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3100 opened_printer_t
*printer
;
3103 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
3104 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
3105 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
3107 ADDJOB_INFO_1W
*addjob
;
3109 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
3111 EnterCriticalSection(&printer_handles_cs
);
3113 printer
= get_opened_printer(hPrinter
);
3116 SetLastError(ERROR_INVALID_HANDLE
);
3121 SetLastError(ERROR_INVALID_LEVEL
);
3125 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
3129 job
->job_id
= InterlockedIncrement(&next_job_id
);
3131 len
= GetSystemDirectoryW(path
, ARRAY_SIZE(path
));
3132 if(path
[len
- 1] != '\\')
3134 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
3135 sprintfW(filename
, fmtW
, path
, job
->job_id
);
3137 len
= strlenW(filename
);
3138 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
3139 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
3140 job
->portname
= NULL
;
3141 job
->document_title
= strdupW(default_doc_title
);
3142 job
->printer_name
= strdupW(printer
->name
);
3143 job
->devmode
= dup_devmode( printer
->devmode
);
3144 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
3146 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
3147 if(*pcbNeeded
<= cbBuf
) {
3148 addjob
= (ADDJOB_INFO_1W
*)pData
;
3149 addjob
->JobId
= job
->job_id
;
3150 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
3151 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
3154 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3157 LeaveCriticalSection(&printer_handles_cs
);
3161 /*****************************************************************************
3162 * GetPrintProcessorDirectoryA [WINSPOOL.@]
3164 * Return the PATH for the Print-Processors
3166 * See GetPrintProcessorDirectoryW.
3170 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
3171 DWORD level
, LPBYTE Info
,
3172 DWORD cbBuf
, LPDWORD pcbNeeded
)
3174 LPWSTR serverW
= NULL
;
3179 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
3180 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
3184 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
3185 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3186 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
3190 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
3191 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3192 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
3195 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3196 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3198 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
3201 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
3202 cbBuf
, NULL
, NULL
) > 0;
3205 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
3206 HeapFree(GetProcessHeap(), 0, envW
);
3207 HeapFree(GetProcessHeap(), 0, serverW
);
3211 /*****************************************************************************
3212 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3214 * Return the PATH for the Print-Processors
3217 * server [I] Servername (NT only) or NULL (local Computer)
3218 * env [I] Printing-Environment (see below) or NULL (Default)
3219 * level [I] Structure-Level (must be 1)
3220 * Info [O] PTR to Buffer that receives the Result
3221 * cbBuf [I] Size of Buffer at "Info"
3222 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3223 * required for the Buffer at "Info"
3226 * Success: TRUE and in pcbNeeded the Bytes used in Info
3227 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3228 * if cbBuf is too small
3230 * Native Values returned in Info on Success:
3231 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3232 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3233 *| win9x(Windows 4.0): "%winsysdir%"
3235 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3238 * Only NULL or "" is supported for server
3241 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
3242 DWORD level
, LPBYTE Info
,
3243 DWORD cbBuf
, LPDWORD pcbNeeded
)
3246 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
3247 Info
, cbBuf
, pcbNeeded
);
3249 if ((backend
== NULL
) && !load_backend()) return FALSE
;
3252 /* (Level != 1) is ignored in win9x */
3253 SetLastError(ERROR_INVALID_LEVEL
);
3257 if (pcbNeeded
== NULL
) {
3258 /* (pcbNeeded == NULL) is ignored in win9x */
3259 SetLastError(RPC_X_NULL_REF_POINTER
);
3263 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
3266 /*****************************************************************************
3267 * set_devices_and_printerports [internal]
3269 * set the [Devices] and [PrinterPorts] entries for a printer.
3272 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
3274 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
3278 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
3280 /* FIXME: the driver must change to "winspool" */
3281 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
3283 lstrcpyW(devline
, driver_nt
);
3284 lstrcatW(devline
, commaW
);
3285 lstrcatW(devline
, pi
->pPortName
);
3287 TRACE("using %s\n", debugstr_w(devline
));
3288 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
3289 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3290 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3294 lstrcatW(devline
, timeout_15_45
);
3295 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
3296 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3297 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3300 HeapFree(GetProcessHeap(), 0, devline
);
3304 /*****************************************************************************
3305 * AddPrinterW [WINSPOOL.@]
3307 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3309 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
3312 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
3315 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
3317 if(pName
&& *pName
) {
3318 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
3319 SetLastError(ERROR_INVALID_PARAMETER
);
3323 ERR("Level = %d, unsupported!\n", Level
);
3324 SetLastError(ERROR_INVALID_LEVEL
);
3328 SetLastError(ERROR_INVALID_PARAMETER
);
3331 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3333 ERR("Can't create Printers key\n");
3336 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3337 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
3338 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3339 RegCloseKey(hkeyPrinter
);
3340 RegCloseKey(hkeyPrinters
);
3343 RegCloseKey(hkeyPrinter
);
3345 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
3347 ERR("Can't create Drivers key\n");
3348 RegCloseKey(hkeyPrinters
);
3351 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3353 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3354 RegCloseKey(hkeyPrinters
);
3355 RegCloseKey(hkeyDrivers
);
3356 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3359 RegCloseKey(hkeyDriver
);
3360 RegCloseKey(hkeyDrivers
);
3362 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3363 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3364 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3365 RegCloseKey(hkeyPrinters
);
3369 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3371 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3372 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3373 RegCloseKey(hkeyPrinters
);
3377 set_devices_and_printerports(pi
);
3379 set_reg_DWORD(hkeyPrinter
, AttributesW
, pi
->Attributes
);
3380 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3381 set_reg_DWORD(hkeyPrinter
, Default_PriorityW
, pi
->DefaultPriority
);
3382 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3383 set_reg_DWORD(hkeyPrinter
, dnsTimeoutW
, 0);
3384 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3385 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3386 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3387 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3388 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3389 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3390 set_reg_DWORD(hkeyPrinter
, PriorityW
, pi
->Priority
);
3391 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3392 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3393 set_reg_DWORD(hkeyPrinter
, StartTimeW
, pi
->StartTime
);
3394 set_reg_DWORD(hkeyPrinter
, StatusW
, pi
->Status
);
3395 set_reg_DWORD(hkeyPrinter
, txTimeoutW
, 0);
3396 set_reg_DWORD(hkeyPrinter
, UntilTimeW
, pi
->UntilTime
);
3398 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3402 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3403 size
= sizeof(DEVMODEW
);
3409 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3411 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
3413 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3414 HeapFree( GetProcessHeap(), 0, dm
);
3419 /* set devmode to printer name */
3420 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3424 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
3425 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
3427 RegCloseKey(hkeyPrinter
);
3428 RegCloseKey(hkeyPrinters
);
3429 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3430 ERR("OpenPrinter failing\n");
3436 /*****************************************************************************
3437 * AddPrinterA [WINSPOOL.@]
3439 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3441 UNICODE_STRING pNameW
;
3443 PRINTER_INFO_2W
*piW
;
3444 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3447 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
3449 ERR("Level = %d, unsupported!\n", Level
);
3450 SetLastError(ERROR_INVALID_LEVEL
);
3453 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3454 piW
= printer_info_AtoW( piA
, Level
);
3456 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3458 free_printer_info( piW
, Level
);
3459 RtlFreeUnicodeString(&pNameW
);
3464 /*****************************************************************************
3465 * ClosePrinter [WINSPOOL.@]
3467 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3469 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3470 opened_printer_t
*printer
= NULL
;
3472 TRACE("(%p)\n", hPrinter
);
3474 EnterCriticalSection(&printer_handles_cs
);
3476 if ((i
> 0) && (i
<= nb_printer_handles
))
3477 printer
= printer_handles
[i
- 1];
3482 struct list
*cursor
, *cursor2
;
3484 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
3487 EndDocPrinter(hPrinter
);
3489 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3491 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3493 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3494 ScheduleJob(hPrinter
, job
->job_id
);
3496 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3499 if (printer
->backend_printer
) {
3500 backend
->fpClosePrinter(printer
->backend_printer
);
3503 free_printer_entry( printer
);
3504 printer_handles
[i
- 1] = NULL
;
3505 LeaveCriticalSection(&printer_handles_cs
);
3509 LeaveCriticalSection(&printer_handles_cs
);
3510 SetLastError(ERROR_INVALID_HANDLE
);
3514 /*****************************************************************************
3515 * DeleteFormA [WINSPOOL.@]
3517 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3519 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3523 /*****************************************************************************
3524 * DeleteFormW [WINSPOOL.@]
3526 BOOL WINAPI
DeleteFormW( HANDLE printer
, WCHAR
*name
)
3528 HANDLE handle
= get_backend_handle( printer
);
3530 TRACE( "(%p, %s)\n", printer
, debugstr_w( name
) );
3534 SetLastError( ERROR_INVALID_HANDLE
);
3538 return backend
->fpDeleteForm( handle
, name
);
3541 /*****************************************************************************
3542 * DeletePrinter [WINSPOOL.@]
3544 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3546 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3547 config_module_t
*config_module
;
3548 HKEY hkeyPrinters
, hkey
;
3549 WCHAR def
[MAX_PATH
];
3550 DWORD size
= ARRAY_SIZE(def
);
3553 SetLastError(ERROR_INVALID_HANDLE
);
3557 EnterCriticalSection(&config_modules_cs
);
3558 if ((config_module
= get_config_module(lpNameW
, FALSE
))) {
3559 wine_rb_remove(&config_modules
, &config_module
->entry
);
3560 release_config_module(config_module
);
3562 LeaveCriticalSection(&config_modules_cs
);
3564 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3565 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3566 RegCloseKey(hkeyPrinters
);
3569 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3570 RegDeleteValueW(hkey
, lpNameW
);
3574 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3575 RegDeleteValueW(hkey
, lpNameW
);
3579 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
3581 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
3583 RegDeleteValueW( hkey
, deviceW
);
3584 RegCloseKey( hkey
);
3586 SetDefaultPrinterW( NULL
);
3592 /*****************************************************************************
3593 * SetPrinterA [WINSPOOL.@]
3595 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3602 dataW
= printer_info_AtoW( data
, level
);
3603 if (!dataW
) return FALSE
;
3606 ret
= SetPrinterW( printer
, level
, dataW
, command
);
3608 if (dataW
!= data
) free_printer_info( dataW
, level
);
3613 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
3615 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
3616 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
3617 set_reg_szW( key
, PortW
, pi
->pPortName
);
3618 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
3619 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
3620 set_reg_szW( key
, LocationW
, pi
->pLocation
);
3623 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3625 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
3626 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
3627 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
3628 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
3630 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
3631 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
3632 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
3633 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
3634 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
3637 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
3639 if (!pi
->pDevMode
) return FALSE
;
3641 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3645 /******************************************************************************
3646 * SetPrinterW [WINSPOOL.@]
3648 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3653 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
3655 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
3657 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
3664 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
3665 set_printer_2( key
, pi2
);
3671 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3672 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3676 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
3677 ret
= set_printer_9( key
, pi
);
3682 FIXME( "Unimplemented level %d\n", level
);
3683 SetLastError( ERROR_INVALID_LEVEL
);
3690 /*****************************************************************************
3691 * SetJobA [WINSPOOL.@]
3693 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3694 LPBYTE pJob
, DWORD Command
)
3698 UNICODE_STRING usBuffer
;
3700 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3702 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3703 are all ignored by SetJob, so we don't bother copying them */
3711 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3712 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3714 JobW
= (LPBYTE
)info1W
;
3715 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3716 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3717 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3718 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3719 info1W
->Status
= info1A
->Status
;
3720 info1W
->Priority
= info1A
->Priority
;
3721 info1W
->Position
= info1A
->Position
;
3722 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3727 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3728 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3730 JobW
= (LPBYTE
)info2W
;
3731 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3732 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3733 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3734 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3735 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3736 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3737 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3738 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3739 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3740 info2W
->Status
= info2A
->Status
;
3741 info2W
->Priority
= info2A
->Priority
;
3742 info2W
->Position
= info2A
->Position
;
3743 info2W
->StartTime
= info2A
->StartTime
;
3744 info2W
->UntilTime
= info2A
->UntilTime
;
3745 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3749 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3750 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3753 SetLastError(ERROR_INVALID_LEVEL
);
3757 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3763 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3764 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3765 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3766 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3767 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3772 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3773 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3774 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3775 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3776 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3777 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3778 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3779 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3780 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3784 HeapFree(GetProcessHeap(), 0, JobW
);
3789 /*****************************************************************************
3790 * SetJobW [WINSPOOL.@]
3792 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3793 LPBYTE pJob
, DWORD Command
)
3798 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3799 FIXME("Ignoring everything other than document title\n");
3801 EnterCriticalSection(&printer_handles_cs
);
3802 job
= get_job(hPrinter
, JobId
);
3812 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3813 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3814 job
->document_title
= strdupW(info1
->pDocument
);
3819 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3820 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3821 job
->document_title
= strdupW(info2
->pDocument
);
3822 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3823 job
->devmode
= dup_devmode( info2
->pDevMode
);
3829 SetLastError(ERROR_INVALID_LEVEL
);
3834 LeaveCriticalSection(&printer_handles_cs
);
3838 /*****************************************************************************
3839 * EndDocPrinter [WINSPOOL.@]
3841 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3843 opened_printer_t
*printer
;
3845 TRACE("(%p)\n", hPrinter
);
3847 EnterCriticalSection(&printer_handles_cs
);
3849 printer
= get_opened_printer(hPrinter
);
3852 SetLastError(ERROR_INVALID_HANDLE
);
3858 SetLastError(ERROR_SPL_NO_STARTDOC
);
3862 CloseHandle(printer
->doc
->hf
);
3863 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3864 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3865 printer
->doc
= NULL
;
3868 LeaveCriticalSection(&printer_handles_cs
);
3872 /*****************************************************************************
3873 * EndPagePrinter [WINSPOOL.@]
3875 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3877 FIXME("(%p): stub\n", hPrinter
);
3881 /*****************************************************************************
3882 * StartDocPrinterA [WINSPOOL.@]
3884 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3886 UNICODE_STRING usBuffer
;
3888 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3891 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3892 or one (DOC_INFO_3) extra DWORDs */
3896 doc2W
.JobId
= doc2
->JobId
;
3899 doc2W
.dwMode
= doc2
->dwMode
;
3902 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3903 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3904 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3908 SetLastError(ERROR_INVALID_LEVEL
);
3912 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3914 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3915 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3916 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3921 /*****************************************************************************
3922 * StartDocPrinterW [WINSPOOL.@]
3924 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3926 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3927 opened_printer_t
*printer
;
3928 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3929 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3930 JOB_INFO_1W job_info
;
3931 DWORD needed
, ret
= 0;
3936 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3937 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3938 debugstr_w(doc
->pDatatype
));
3940 if(Level
< 1 || Level
> 3)
3942 SetLastError(ERROR_INVALID_LEVEL
);
3946 EnterCriticalSection(&printer_handles_cs
);
3947 printer
= get_opened_printer(hPrinter
);
3950 SetLastError(ERROR_INVALID_HANDLE
);
3956 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3960 /* Even if we're printing to a file we still add a print job, we'll
3961 just ignore the spool file name */
3963 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3965 ERR("AddJob failed gle %u\n", GetLastError());
3969 /* use pOutputFile only, when it is a real filename */
3970 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3971 filename
= doc
->pOutputFile
;
3973 filename
= addjob
->Path
;
3975 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3976 if(hf
== INVALID_HANDLE_VALUE
)
3979 memset(&job_info
, 0, sizeof(job_info
));
3980 job_info
.pDocument
= doc
->pDocName
;
3981 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3983 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3984 printer
->doc
->hf
= hf
;
3985 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3986 job
= get_job(hPrinter
, ret
);
3987 job
->portname
= strdupW(doc
->pOutputFile
);
3990 LeaveCriticalSection(&printer_handles_cs
);
3995 /*****************************************************************************
3996 * StartPagePrinter [WINSPOOL.@]
3998 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
4000 FIXME("(%p): stub\n", hPrinter
);
4004 /*****************************************************************************
4005 * GetFormA [WINSPOOL.@]
4007 BOOL WINAPI
GetFormA( HANDLE printer
, char *name
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
)
4009 UNICODE_STRING nameW
;
4010 const DWORD
*string_info
= form_string_info( level
);
4013 if (!string_info
) return FALSE
;
4015 asciitounicode( &nameW
, name
);
4017 ret
= GetFormW( printer
, nameW
.Buffer
, level
, form
, size
, needed
);
4018 if (ret
) packed_struct_WtoA( form
, string_info
);
4020 RtlFreeUnicodeString( &nameW
);
4024 /*****************************************************************************
4025 * GetFormW [WINSPOOL.@]
4027 BOOL WINAPI
GetFormW( HANDLE printer
, WCHAR
*name
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
)
4029 HANDLE handle
= get_backend_handle( printer
);
4031 TRACE( "(%p, %s, %d, %p, %d, %p)\n", printer
, debugstr_w( name
), level
, form
, size
, needed
);
4035 SetLastError( ERROR_INVALID_HANDLE
);
4039 return backend
->fpGetForm( handle
, name
, level
, form
, size
, needed
);
4042 /*****************************************************************************
4043 * SetFormA [WINSPOOL.@]
4045 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
4048 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
4052 /*****************************************************************************
4053 * SetFormW [WINSPOOL.@]
4055 BOOL WINAPI
SetFormW( HANDLE printer
, WCHAR
*name
, DWORD level
, BYTE
*form
)
4057 HANDLE handle
= get_backend_handle( printer
);
4059 TRACE( "(%p, %s, %d, %p)\n", printer
, debugstr_w( name
), level
, form
);
4063 SetLastError( ERROR_INVALID_HANDLE
);
4067 return backend
->fpSetForm( handle
, name
, level
, form
);
4070 /*****************************************************************************
4071 * ReadPrinter [WINSPOOL.@]
4073 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
4074 LPDWORD pNoBytesRead
)
4076 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
4080 /*****************************************************************************
4081 * ResetPrinterA [WINSPOOL.@]
4083 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
4085 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
4089 /*****************************************************************************
4090 * ResetPrinterW [WINSPOOL.@]
4092 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
4094 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
4098 /*****************************************************************************
4099 * get_filename_from_reg [internal]
4101 * Get ValueName from hkey storing result in out
4102 * when the Value in the registry has only a filename, use driverdir as prefix
4103 * outlen is space left in out
4104 * String is stored either as unicode or ansi
4108 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
4109 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
4111 WCHAR filename
[MAX_PATH
];
4115 LPWSTR buffer
= filename
;
4119 size
= sizeof(filename
);
4121 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
4122 if (ret
== ERROR_MORE_DATA
) {
4123 TRACE("need dynamic buffer: %u\n", size
);
4124 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
4126 /* No Memory is bad */
4130 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
4133 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
4134 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
4140 /* do we have a full path ? */
4141 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
4142 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
4145 /* we must build the full Path */
4147 if ((out
) && (outlen
> dirlen
)) {
4148 lstrcpyW((LPWSTR
)out
, driverdir
);
4156 /* write the filename */
4157 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
4158 if ((out
) && (outlen
>= size
)) {
4159 lstrcpyW((LPWSTR
)out
, ptr
);
4166 ptr
+= lstrlenW(ptr
)+1;
4167 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
4170 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
4172 /* write the multisz-termination */
4173 if (type
== REG_MULTI_SZ
) {
4174 size
= sizeof(WCHAR
);
4177 if (out
&& (outlen
>= size
)) {
4178 memset (out
, 0, size
);
4184 /*****************************************************************************
4185 * WINSPOOL_GetStringFromReg
4187 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4188 * String is stored as unicode.
4190 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
4191 DWORD buflen
, DWORD
*needed
)
4193 DWORD sz
= buflen
, type
;
4196 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4197 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
4198 WARN("Got ret = %d\n", ret
);
4202 /* add space for terminating '\0' */
4203 sz
+= sizeof(WCHAR
);
4207 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
4212 /*****************************************************************************
4213 * WINSPOOL_GetDefaultDevMode
4215 * Get a default DevMode values for wineps.
4217 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr
, DWORD buflen
, DWORD
*needed
)
4219 static const WCHAR winepsW
[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4221 if (buflen
>= sizeof(DEVMODEW
))
4223 DEVMODEW
*dm
= (DEVMODEW
*)ptr
;
4225 /* the driver will update registry with real values */
4226 memset(dm
, 0, sizeof(*dm
));
4227 dm
->dmSize
= sizeof(*dm
);
4228 lstrcpyW(dm
->dmDeviceName
, winepsW
);
4230 *needed
= sizeof(DEVMODEW
);
4233 /*****************************************************************************
4234 * WINSPOOL_GetDevModeFromReg
4236 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4237 * DevMode is stored either as unicode or ansi.
4239 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
4241 DWORD buflen
, DWORD
*needed
)
4243 DWORD sz
= buflen
, type
;
4246 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
4247 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4248 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
4249 if (sz
< sizeof(DEVMODEA
))
4251 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
4254 /* ensures that dmSize is not erratically bogus if registry is invalid */
4255 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
4256 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
4257 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
4258 if (ptr
&& (buflen
>= sz
)) {
4259 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
4260 memcpy(ptr
, dmW
, sz
);
4261 HeapFree(GetProcessHeap(),0,dmW
);
4267 /*********************************************************************
4268 * WINSPOOL_GetPrinter_1
4270 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4272 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
4273 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4275 DWORD size
, left
= cbBuf
;
4276 BOOL space
= (cbBuf
> 0);
4281 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4282 if(space
&& size
<= left
) {
4283 pi1
->pName
= (LPWSTR
)ptr
;
4291 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4292 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4293 if(space
&& size
<= left
) {
4294 pi1
->pDescription
= (LPWSTR
)ptr
;
4302 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4303 if(space
&& size
<= left
) {
4304 pi1
->pComment
= (LPWSTR
)ptr
;
4312 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
4314 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
4315 memset(pi1
, 0, sizeof(*pi1
));
4319 /*********************************************************************
4320 * WINSPOOL_GetPrinter_2
4322 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4324 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
4325 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4327 DWORD size
, left
= cbBuf
;
4328 BOOL space
= (cbBuf
> 0);
4333 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4334 if(space
&& size
<= left
) {
4335 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4342 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
4343 if(space
&& size
<= left
) {
4344 pi2
->pShareName
= (LPWSTR
)ptr
;
4351 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4352 if(space
&& size
<= left
) {
4353 pi2
->pPortName
= (LPWSTR
)ptr
;
4360 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
4361 if(space
&& size
<= left
) {
4362 pi2
->pDriverName
= (LPWSTR
)ptr
;
4369 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4370 if(space
&& size
<= left
) {
4371 pi2
->pComment
= (LPWSTR
)ptr
;
4378 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
4379 if(space
&& size
<= left
) {
4380 pi2
->pLocation
= (LPWSTR
)ptr
;
4387 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
4388 if(space
&& size
<= left
) {
4389 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4398 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
4399 if(space
&& size
<= left
) {
4400 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4407 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
4408 if(space
&& size
<= left
) {
4409 pi2
->pSepFile
= (LPWSTR
)ptr
;
4416 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
4417 if(space
&& size
<= left
) {
4418 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4425 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
4426 if(space
&& size
<= left
) {
4427 pi2
->pDatatype
= (LPWSTR
)ptr
;
4434 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
4435 if(space
&& size
<= left
) {
4436 pi2
->pParameters
= (LPWSTR
)ptr
;
4444 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4445 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
4446 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
4447 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
4448 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
4451 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4452 memset(pi2
, 0, sizeof(*pi2
));
4457 /*********************************************************************
4458 * WINSPOOL_GetPrinter_4
4460 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4462 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4463 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4465 DWORD size
, left
= cbBuf
;
4466 BOOL space
= (cbBuf
> 0);
4471 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4472 if(space
&& size
<= left
) {
4473 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4481 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4484 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4485 memset(pi4
, 0, sizeof(*pi4
));
4490 /*********************************************************************
4491 * WINSPOOL_GetPrinter_5
4493 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4495 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4496 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4498 DWORD size
, left
= cbBuf
;
4499 BOOL space
= (cbBuf
> 0);
4504 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4505 if(space
&& size
<= left
) {
4506 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4513 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4514 if(space
&& size
<= left
) {
4515 pi5
->pPortName
= (LPWSTR
)ptr
;
4523 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4524 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
4525 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
4528 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4529 memset(pi5
, 0, sizeof(*pi5
));
4534 /*********************************************************************
4535 * WINSPOOL_GetPrinter_7
4537 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4539 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4540 DWORD cbBuf
, LPDWORD pcbNeeded
)
4542 DWORD size
, left
= cbBuf
;
4543 BOOL space
= (cbBuf
> 0);
4548 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
4551 size
= sizeof(pi7
->pszObjectGUID
);
4553 if (space
&& size
<= left
) {
4554 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4561 /* We do not have a Directory Service */
4562 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4565 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4566 memset(pi7
, 0, sizeof(*pi7
));
4571 /*********************************************************************
4572 * WINSPOOL_GetPrinter_9
4574 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4576 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4577 DWORD cbBuf
, LPDWORD pcbNeeded
)
4580 BOOL space
= (cbBuf
> 0);
4584 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
4585 if(space
&& size
<= cbBuf
) {
4586 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4593 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
4594 if(space
&& size
<= cbBuf
) {
4595 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4601 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4602 memset(pi9
, 0, sizeof(*pi9
));
4607 /*****************************************************************************
4608 * GetPrinterW [WINSPOOL.@]
4610 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4611 DWORD cbBuf
, LPDWORD pcbNeeded
)
4613 DWORD size
, needed
= 0, err
;
4618 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4620 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
4623 SetLastError( err
);
4630 PRINTER_INFO_1W
*pi1
= (PRINTER_INFO_1W
*)pPrinter
;
4632 size
= sizeof(PRINTER_INFO_1W
);
4633 if (size
<= cbBuf
) {
4634 ptr
= pPrinter
+ size
;
4636 memset(pPrinter
, 0, size
);
4641 ret
= WINSPOOL_GetPrinter_1(hkeyPrinter
, pi1
, ptr
, cbBuf
, &needed
);
4648 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4650 size
= sizeof(PRINTER_INFO_2W
);
4652 ptr
= pPrinter
+ size
;
4654 memset(pPrinter
, 0, size
);
4659 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
4666 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4668 size
= sizeof(PRINTER_INFO_4W
);
4670 ptr
= pPrinter
+ size
;
4672 memset(pPrinter
, 0, size
);
4677 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
4685 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4687 size
= sizeof(PRINTER_INFO_5W
);
4689 ptr
= pPrinter
+ size
;
4691 memset(pPrinter
, 0, size
);
4697 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4705 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4707 size
= sizeof(PRINTER_INFO_6
);
4708 if (size
<= cbBuf
) {
4709 /* FIXME: We do not update the status yet */
4710 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4722 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4724 size
= sizeof(PRINTER_INFO_7W
);
4725 if (size
<= cbBuf
) {
4726 ptr
= pPrinter
+ size
;
4728 memset(pPrinter
, 0, size
);
4734 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4741 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4742 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4746 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4748 size
= sizeof(PRINTER_INFO_9W
);
4750 ptr
= pPrinter
+ size
;
4752 memset(pPrinter
, 0, size
);
4758 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4765 FIXME("Unimplemented level %d\n", Level
);
4766 SetLastError(ERROR_INVALID_LEVEL
);
4767 RegCloseKey(hkeyPrinter
);
4771 RegCloseKey(hkeyPrinter
);
4773 TRACE("returning %d needed = %d\n", ret
, needed
);
4774 if(pcbNeeded
) *pcbNeeded
= needed
;
4776 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4780 /*****************************************************************************
4781 * GetPrinterA [WINSPOOL.@]
4783 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4784 DWORD cbBuf
, LPDWORD pcbNeeded
)
4790 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4792 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4794 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4795 HeapFree(GetProcessHeap(), 0, buf
);
4800 /*****************************************************************************
4801 * WINSPOOL_EnumPrintersW
4803 * Implementation of EnumPrintersW
4805 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4806 DWORD dwLevel
, LPBYTE lpbPrinters
,
4807 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4808 LPDWORD lpdwReturned
)
4811 HKEY hkeyPrinters
, hkeyPrinter
;
4812 WCHAR PrinterName
[255];
4813 DWORD needed
= 0, number
= 0;
4814 DWORD used
, i
, left
;
4818 memset(lpbPrinters
, 0, cbBuf
);
4824 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4825 if(dwType
== PRINTER_ENUM_DEFAULT
)
4828 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4829 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4830 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4832 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4838 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4839 FIXME("dwType = %08x\n", dwType
);
4840 SetLastError(ERROR_INVALID_FLAGS
);
4844 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4846 ERR("Can't create Printers key\n");
4850 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4851 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4852 RegCloseKey(hkeyPrinters
);
4853 ERR("Can't query Printers key\n");
4856 TRACE("Found %d printers\n", number
);
4860 used
= number
* sizeof(PRINTER_INFO_1W
);
4863 used
= number
* sizeof(PRINTER_INFO_2W
);
4866 used
= number
* sizeof(PRINTER_INFO_4W
);
4869 used
= number
* sizeof(PRINTER_INFO_5W
);
4873 SetLastError(ERROR_INVALID_LEVEL
);
4874 RegCloseKey(hkeyPrinters
);
4877 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4879 for(i
= 0; i
< number
; i
++) {
4880 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, ARRAY_SIZE(PrinterName
)) != ERROR_SUCCESS
) {
4881 ERR("Can't enum key number %d\n", i
);
4882 RegCloseKey(hkeyPrinters
);
4885 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4886 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4888 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4889 RegCloseKey(hkeyPrinters
);
4894 buf
= lpbPrinters
+ used
;
4895 left
= cbBuf
- used
;
4903 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4906 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4909 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4912 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4915 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4918 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4921 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4924 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4927 ERR("Shouldn't be here!\n");
4928 RegCloseKey(hkeyPrinter
);
4929 RegCloseKey(hkeyPrinters
);
4932 RegCloseKey(hkeyPrinter
);
4934 RegCloseKey(hkeyPrinters
);
4941 memset(lpbPrinters
, 0, cbBuf
);
4942 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4946 *lpdwReturned
= number
;
4947 SetLastError(ERROR_SUCCESS
);
4952 /******************************************************************
4953 * EnumPrintersW [WINSPOOL.@]
4955 * Enumerates the available printers, print servers and print
4956 * providers, depending on the specified flags, name and level.
4960 * If level is set to 1:
4961 * Returns an array of PRINTER_INFO_1 data structures in the
4962 * lpbPrinters buffer.
4964 * If level is set to 2:
4965 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4966 * Returns an array of PRINTER_INFO_2 data structures in the
4967 * lpbPrinters buffer. Note that according to MSDN also an
4968 * OpenPrinter should be performed on every remote printer.
4970 * If level is set to 4 (officially WinNT only):
4971 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4972 * Fast: Only the registry is queried to retrieve printer names,
4973 * no connection to the driver is made.
4974 * Returns an array of PRINTER_INFO_4 data structures in the
4975 * lpbPrinters buffer.
4977 * If level is set to 5 (officially WinNT4/Win9x only):
4978 * Fast: Only the registry is queried to retrieve printer names,
4979 * no connection to the driver is made.
4980 * Returns an array of PRINTER_INFO_5 data structures in the
4981 * lpbPrinters buffer.
4983 * If level set to 3 or 6+:
4984 * returns zero (failure!)
4986 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4990 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4991 * - Only levels 2, 4 and 5 are implemented at the moment.
4992 * - 16-bit printer drivers are not enumerated.
4993 * - Returned amount of bytes used/needed does not match the real Windoze
4994 * implementation (as in this implementation, all strings are part
4995 * of the buffer, whereas Win32 keeps them somewhere else)
4996 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4999 * - In a regular Wine installation, no registry settings for printers
5000 * exist, which makes this function return an empty list.
5002 BOOL WINAPI
EnumPrintersW(
5003 DWORD dwType
, /* [in] Types of print objects to enumerate */
5004 LPWSTR lpszName
, /* [in] name of objects to enumerate */
5005 DWORD dwLevel
, /* [in] type of printer info structure */
5006 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
5007 DWORD cbBuf
, /* [in] max size of buffer in bytes */
5008 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
5009 LPDWORD lpdwReturned
/* [out] number of entries returned */
5012 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
5013 lpdwNeeded
, lpdwReturned
);
5016 /******************************************************************
5017 * EnumPrintersA [WINSPOOL.@]
5022 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
5023 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5026 UNICODE_STRING pNameU
;
5030 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
5031 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
5033 pNameW
= asciitounicode(&pNameU
, pName
);
5035 /* Request a buffer with a size, that is big enough for EnumPrintersW.
5036 MS Office need this */
5037 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
5039 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
5041 RtlFreeUnicodeString(&pNameU
);
5043 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
5045 HeapFree(GetProcessHeap(), 0, pPrintersW
);
5049 /*****************************************************************************
5050 * WINSPOOL_GetDriverInfoFromReg [internal]
5052 * Enters the information from the registry into the DRIVER_INFO struct
5055 * zero if the printer driver does not exist in the registry
5056 * (only if Level > 1) otherwise nonzero
5058 static BOOL
WINSPOOL_GetDriverInfoFromReg(
5061 const printenv_t
* env
,
5063 LPBYTE ptr
, /* DRIVER_INFO */
5064 LPBYTE pDriverStrings
, /* strings buffer */
5065 DWORD cbBuf
, /* size of string buffer */
5066 LPDWORD pcbNeeded
) /* space needed for str. */
5070 WCHAR driverdir
[MAX_PATH
];
5072 LPBYTE strPtr
= pDriverStrings
;
5073 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
5075 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
5076 debugstr_w(DriverName
), env
,
5077 Level
, di
, pDriverStrings
, cbBuf
);
5079 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
5081 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
5082 if (*pcbNeeded
<= cbBuf
)
5083 strcpyW((LPWSTR
)strPtr
, DriverName
);
5085 /* pName for level 1 has a different offset! */
5087 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
5091 /* .cVersion and .pName for level > 1 */
5093 di
->cVersion
= env
->driverversion
;
5094 di
->pName
= (LPWSTR
) strPtr
;
5095 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
5098 /* Reserve Space for the largest subdir and a Backslash*/
5099 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
5100 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
5101 /* Should never Fail */
5104 lstrcatW(driverdir
, env
->versionsubdir
);
5105 lstrcatW(driverdir
, backslashW
);
5107 /* dirlen must not include the terminating zero */
5108 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
5110 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
5111 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
5112 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
5117 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
5120 if (*pcbNeeded
<= cbBuf
) {
5121 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
5122 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
5123 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
5126 /* .pDriverPath is the Graphics rendering engine.
5127 The full Path is required to avoid a crash in some apps */
5128 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
5130 if (*pcbNeeded
<= cbBuf
)
5131 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
5133 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
5134 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
5137 /* .pDataFile: For postscript-drivers, this is the ppd-file */
5138 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
5140 if (*pcbNeeded
<= cbBuf
)
5141 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
5143 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
5144 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5147 /* .pConfigFile is the Driver user Interface */
5148 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
5150 if (*pcbNeeded
<= cbBuf
)
5151 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
5153 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
5154 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5158 RegCloseKey(hkeyDriver
);
5159 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5164 RegCloseKey(hkeyDriver
);
5165 FIXME("level 5: incomplete\n");
5170 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
5172 if (*pcbNeeded
<= cbBuf
)
5173 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
5175 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
5176 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5179 /* .pDependentFiles */
5180 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
5182 if (*pcbNeeded
<= cbBuf
)
5183 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
5185 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
5186 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5188 else if (GetVersion() & 0x80000000) {
5189 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
5190 size
= 2 * sizeof(WCHAR
);
5192 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
5194 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
5195 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5198 /* .pMonitorName is the optional Language Monitor */
5199 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
5201 if (*pcbNeeded
<= cbBuf
)
5202 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
5204 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
5205 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5208 /* .pDefaultDataType */
5209 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
5211 if(*pcbNeeded
<= cbBuf
)
5212 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
5214 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
5215 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5219 RegCloseKey(hkeyDriver
);
5220 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5224 /* .pszzPreviousNames */
5225 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
5227 if(*pcbNeeded
<= cbBuf
)
5228 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
5230 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
5231 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5235 RegCloseKey(hkeyDriver
);
5236 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5240 /* support is missing, but not important enough for a FIXME */
5241 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
5244 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
5246 if(*pcbNeeded
<= cbBuf
)
5247 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
5249 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
5250 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5254 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
5256 if(*pcbNeeded
<= cbBuf
)
5257 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
5259 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
5260 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5263 /* .pszHardwareID */
5264 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
5266 if(*pcbNeeded
<= cbBuf
)
5267 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
5269 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
5270 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5274 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
5276 if(*pcbNeeded
<= cbBuf
)
5277 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
5279 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
5280 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5284 RegCloseKey(hkeyDriver
);
5288 /* support is missing, but not important enough for a FIXME */
5289 TRACE("level 8: incomplete\n");
5291 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5292 RegCloseKey(hkeyDriver
);
5296 /*****************************************************************************
5297 * GetPrinterDriverW [WINSPOOL.@]
5299 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5300 DWORD Level
, LPBYTE pDriverInfo
,
5301 DWORD cbBuf
, LPDWORD pcbNeeded
)
5304 WCHAR DriverName
[100];
5305 DWORD ret
, type
, size
, needed
= 0;
5307 HKEY hkeyPrinter
, hkeyDrivers
;
5308 const printenv_t
* env
;
5310 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
5311 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
5314 ZeroMemory(pDriverInfo
, cbBuf
);
5316 if (!(name
= get_opened_printer_name(hPrinter
))) {
5317 SetLastError(ERROR_INVALID_HANDLE
);
5321 if (Level
< 1 || Level
== 7 || Level
> 8) {
5322 SetLastError(ERROR_INVALID_LEVEL
);
5326 env
= validate_envW(pEnvironment
);
5327 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5329 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
5332 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
5333 SetLastError( ret
);
5337 size
= sizeof(DriverName
);
5339 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5340 (LPBYTE
)DriverName
, &size
);
5341 RegCloseKey(hkeyPrinter
);
5342 if(ret
!= ERROR_SUCCESS
) {
5343 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5347 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5349 ERR("Can't create Drivers key\n");
5353 size
= di_sizeof
[Level
];
5354 if ((size
<= cbBuf
) && pDriverInfo
)
5355 ptr
= pDriverInfo
+ size
;
5357 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5358 env
, Level
, pDriverInfo
, ptr
,
5359 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5361 RegCloseKey(hkeyDrivers
);
5365 RegCloseKey(hkeyDrivers
);
5367 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5368 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5369 if(cbBuf
>= size
+ needed
) return TRUE
;
5370 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5374 /*****************************************************************************
5375 * GetPrinterDriverA [WINSPOOL.@]
5377 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5378 DWORD Level
, LPBYTE pDriverInfo
,
5379 DWORD cbBuf
, LPDWORD pcbNeeded
)
5382 UNICODE_STRING pEnvW
;
5388 ZeroMemory(pDriverInfo
, cbBuf
);
5389 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5392 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5393 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5396 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5398 HeapFree(GetProcessHeap(), 0, buf
);
5400 RtlFreeUnicodeString(&pEnvW
);
5404 /*****************************************************************************
5405 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5407 * Return the PATH for the Printer-Drivers (UNICODE)
5410 * pName [I] Servername (NT only) or NULL (local Computer)
5411 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5412 * Level [I] Structure-Level (must be 1)
5413 * pDriverDirectory [O] PTR to Buffer that receives the Result
5414 * cbBuf [I] Size of Buffer at pDriverDirectory
5415 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5416 * required for pDriverDirectory
5419 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5420 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5421 * if cbBuf is too small
5423 * Native Values returned in pDriverDirectory on Success:
5424 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5425 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5426 *| win9x(Windows 4.0): "%winsysdir%"
5428 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5431 *- Only NULL or "" is supported for pName
5434 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5435 DWORD Level
, LPBYTE pDriverDirectory
,
5436 DWORD cbBuf
, LPDWORD pcbNeeded
)
5438 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5439 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5441 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5444 /* (Level != 1) is ignored in win9x */
5445 SetLastError(ERROR_INVALID_LEVEL
);
5448 if (pcbNeeded
== NULL
) {
5449 /* (pcbNeeded == NULL) is ignored in win9x */
5450 SetLastError(RPC_X_NULL_REF_POINTER
);
5454 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5455 pDriverDirectory
, cbBuf
, pcbNeeded
);
5460 /*****************************************************************************
5461 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5463 * Return the PATH for the Printer-Drivers (ANSI)
5465 * See GetPrinterDriverDirectoryW.
5468 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5471 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5472 DWORD Level
, LPBYTE pDriverDirectory
,
5473 DWORD cbBuf
, LPDWORD pcbNeeded
)
5475 UNICODE_STRING nameW
, environmentW
;
5478 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5479 WCHAR
*driverDirectoryW
= NULL
;
5481 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5482 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5484 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5486 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5487 else nameW
.Buffer
= NULL
;
5488 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5489 else environmentW
.Buffer
= NULL
;
5491 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5492 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5495 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5496 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5498 *pcbNeeded
= needed
;
5499 ret
= needed
<= cbBuf
;
5501 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5503 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5505 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5506 RtlFreeUnicodeString(&environmentW
);
5507 RtlFreeUnicodeString(&nameW
);
5512 /*****************************************************************************
5513 * AddPrinterDriverA [WINSPOOL.@]
5515 * See AddPrinterDriverW.
5518 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5520 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5521 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5524 /******************************************************************************
5525 * AddPrinterDriverW (WINSPOOL.@)
5527 * Install a Printer Driver
5530 * pName [I] Servername or NULL (local Computer)
5531 * level [I] Level for the supplied DRIVER_INFO_*W struct
5532 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5539 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5541 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5542 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5545 /*****************************************************************************
5546 * AddPrintProcessorA [WINSPOOL.@]
5548 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5549 LPSTR pPrintProcessorName
)
5551 UNICODE_STRING NameW
, EnvW
, PathW
, ProcessorW
;
5554 TRACE("(%s,%s,%s,%s)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5555 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5557 asciitounicode(&NameW
, pName
);
5558 asciitounicode(&EnvW
, pEnvironment
);
5559 asciitounicode(&PathW
, pPathName
);
5560 asciitounicode(&ProcessorW
, pPrintProcessorName
);
5562 ret
= AddPrintProcessorW(NameW
.Buffer
, EnvW
.Buffer
, PathW
.Buffer
, ProcessorW
.Buffer
);
5564 RtlFreeUnicodeString(&ProcessorW
);
5565 RtlFreeUnicodeString(&PathW
);
5566 RtlFreeUnicodeString(&EnvW
);
5567 RtlFreeUnicodeString(&NameW
);
5572 /*****************************************************************************
5573 * AddPrintProcessorW [WINSPOOL.@]
5575 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5576 LPWSTR pPrintProcessorName
)
5578 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5579 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5583 /*****************************************************************************
5584 * AddPrintProvidorA [WINSPOOL.@]
5586 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5588 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5592 /*****************************************************************************
5593 * AddPrintProvidorW [WINSPOOL.@]
5595 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5597 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5601 /*****************************************************************************
5602 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5604 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5605 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5607 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5608 pDevModeOutput
, pDevModeInput
);
5612 /*****************************************************************************
5613 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5615 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5616 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5618 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5619 pDevModeOutput
, pDevModeInput
);
5623 /*****************************************************************************
5624 * PrinterProperties [WINSPOOL.@]
5626 * Displays a dialog to set the properties of the printer.
5629 * nonzero on success or zero on failure
5632 * implemented as stub only
5634 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5635 HANDLE hPrinter
/* [in] handle to printer object */
5637 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5638 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5642 /*****************************************************************************
5643 * EnumJobsA [WINSPOOL.@]
5646 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5647 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5650 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5651 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5653 if(pcbNeeded
) *pcbNeeded
= 0;
5654 if(pcReturned
) *pcReturned
= 0;
5659 /*****************************************************************************
5660 * EnumJobsW [WINSPOOL.@]
5663 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5664 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5667 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5668 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5670 if(pcbNeeded
) *pcbNeeded
= 0;
5671 if(pcReturned
) *pcReturned
= 0;
5675 /*****************************************************************************
5676 * WINSPOOL_EnumPrinterDrivers [internal]
5678 * Delivers information about all printer drivers installed on the
5679 * localhost or a given server
5682 * nonzero on success or zero on failure. If the buffer for the returned
5683 * information is too small the function will return an error
5686 * - only implemented for localhost, foreign hosts will return an error
5688 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5689 DWORD Level
, LPBYTE pDriverInfo
,
5691 DWORD cbBuf
, LPDWORD pcbNeeded
,
5692 LPDWORD pcFound
, DWORD data_offset
)
5696 const printenv_t
* env
;
5698 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5699 debugstr_w(pName
), debugstr_w(pEnvironment
),
5700 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5702 env
= validate_envW(pEnvironment
);
5703 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5707 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5709 ERR("Can't open Drivers key\n");
5713 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5714 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5715 RegCloseKey(hkeyDrivers
);
5716 ERR("Can't query Drivers key\n");
5719 TRACE("Found %d Drivers\n", *pcFound
);
5721 /* get size of single struct
5722 * unicode and ascii structure have the same size
5724 size
= di_sizeof
[Level
];
5726 if (data_offset
== 0)
5727 data_offset
= size
* (*pcFound
);
5728 *pcbNeeded
= data_offset
;
5730 for( i
= 0; i
< *pcFound
; i
++) {
5731 WCHAR DriverNameW
[255];
5732 PBYTE table_ptr
= NULL
;
5733 PBYTE data_ptr
= NULL
;
5736 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, ARRAY_SIZE(DriverNameW
)) != ERROR_SUCCESS
) {
5737 ERR("Can't enum key number %d\n", i
);
5738 RegCloseKey(hkeyDrivers
);
5742 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5743 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5744 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5745 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5747 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5748 env
, Level
, table_ptr
, data_ptr
,
5749 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5751 RegCloseKey(hkeyDrivers
);
5755 *pcbNeeded
+= needed
;
5758 RegCloseKey(hkeyDrivers
);
5760 if(cbBuf
< *pcbNeeded
){
5761 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5768 /*****************************************************************************
5769 * EnumPrinterDriversW [WINSPOOL.@]
5771 * see function EnumPrinterDrivers for RETURNS, BUGS
5773 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5774 LPBYTE pDriverInfo
, DWORD cbBuf
,
5775 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5777 static const WCHAR allW
[] = {'a','l','l',0};
5781 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5783 SetLastError(RPC_X_NULL_REF_POINTER
);
5787 /* check for local drivers */
5788 if((pName
) && (pName
[0])) {
5789 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5790 SetLastError(ERROR_ACCESS_DENIED
);
5794 /* check input parameter */
5795 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5796 SetLastError(ERROR_INVALID_LEVEL
);
5800 if(pDriverInfo
&& cbBuf
> 0)
5801 memset( pDriverInfo
, 0, cbBuf
);
5803 /* Exception: pull all printers */
5804 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5806 DWORD i
, needed
, bufsize
= cbBuf
;
5807 DWORD total_found
= 0;
5810 /* Precompute the overall total; we need this to know
5811 where pointers end and data begins (i.e. data_offset) */
5812 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5815 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5816 NULL
, 0, 0, &needed
, &found
, 0);
5817 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5818 total_found
+= found
;
5821 data_offset
= di_sizeof
[Level
] * total_found
;
5826 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5829 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5830 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5831 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5833 *pcReturned
+= found
;
5834 *pcbNeeded
= needed
;
5835 data_offset
= needed
;
5836 total_found
+= found
;
5841 /* Normal behavior */
5842 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5843 0, cbBuf
, pcbNeeded
, &found
, 0);
5845 *pcReturned
= found
;
5850 /*****************************************************************************
5851 * EnumPrinterDriversA [WINSPOOL.@]
5853 * see function EnumPrinterDrivers for RETURNS, BUGS
5855 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5856 LPBYTE pDriverInfo
, DWORD cbBuf
,
5857 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5860 UNICODE_STRING pNameW
, pEnvironmentW
;
5861 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5865 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5867 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5868 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5870 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5871 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5873 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5875 HeapFree(GetProcessHeap(), 0, buf
);
5877 RtlFreeUnicodeString(&pNameW
);
5878 RtlFreeUnicodeString(&pEnvironmentW
);
5883 /******************************************************************************
5884 * EnumPortsA (WINSPOOL.@)
5889 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5890 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5893 LPBYTE bufferW
= NULL
;
5894 LPWSTR nameW
= NULL
;
5896 DWORD numentries
= 0;
5899 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5900 cbBuf
, pcbNeeded
, pcReturned
);
5902 /* convert servername to unicode */
5904 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5905 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5906 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5908 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5909 needed
= cbBuf
* sizeof(WCHAR
);
5910 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5911 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5913 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5914 if (pcbNeeded
) needed
= *pcbNeeded
;
5915 /* HeapReAlloc return NULL, when bufferW was NULL */
5916 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5917 HeapAlloc(GetProcessHeap(), 0, needed
);
5919 /* Try again with the large Buffer */
5920 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5922 needed
= pcbNeeded
? *pcbNeeded
: 0;
5923 numentries
= pcReturned
? *pcReturned
: 0;
5926 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5927 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5930 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5931 DWORD entrysize
= 0;
5934 LPPORT_INFO_2W pi2w
;
5935 LPPORT_INFO_2A pi2a
;
5938 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5940 /* First pass: calculate the size for all Entries */
5941 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5942 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5944 while (index
< numentries
) {
5946 needed
+= entrysize
; /* PORT_INFO_?A */
5947 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5949 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5950 NULL
, 0, NULL
, NULL
);
5952 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5953 NULL
, 0, NULL
, NULL
);
5954 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5955 NULL
, 0, NULL
, NULL
);
5957 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5958 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5959 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5962 /* check for errors and quit on failure */
5963 if (cbBuf
< needed
) {
5964 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5968 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5969 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5970 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5971 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5972 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5974 /* Second Pass: Fill the User Buffer (if we have one) */
5975 while ((index
< numentries
) && pPorts
) {
5977 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5978 pi2a
->pPortName
= ptr
;
5979 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5980 ptr
, cbBuf
, NULL
, NULL
);
5984 pi2a
->pMonitorName
= ptr
;
5985 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5986 ptr
, cbBuf
, NULL
, NULL
);
5990 pi2a
->pDescription
= ptr
;
5991 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5992 ptr
, cbBuf
, NULL
, NULL
);
5996 pi2a
->fPortType
= pi2w
->fPortType
;
5997 pi2a
->Reserved
= 0; /* documented: "must be zero" */
6000 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
6001 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
6002 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
6007 if (pcbNeeded
) *pcbNeeded
= needed
;
6008 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6010 HeapFree(GetProcessHeap(), 0, nameW
);
6011 HeapFree(GetProcessHeap(), 0, bufferW
);
6013 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
6014 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
6020 /******************************************************************************
6021 * EnumPortsW (WINSPOOL.@)
6023 * Enumerate available Ports
6026 * pName [I] Servername or NULL (local Computer)
6027 * Level [I] Structure-Level (1 or 2)
6028 * pPorts [O] PTR to Buffer that receives the Result
6029 * cbBuf [I] Size of Buffer at pPorts
6030 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
6031 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
6035 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
6038 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6041 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
6042 cbBuf
, pcbNeeded
, pcReturned
);
6044 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6046 /* Level is not checked in win9x */
6047 if (!Level
|| (Level
> 2)) {
6048 WARN("level (%d) is ignored in win9x\n", Level
);
6049 SetLastError(ERROR_INVALID_LEVEL
);
6052 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
6053 SetLastError(RPC_X_NULL_REF_POINTER
);
6057 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
6060 /******************************************************************************
6061 * GetDefaultPrinterW (WINSPOOL.@)
6064 * This function must read the value from data 'device' of key
6065 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
6067 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
6071 WCHAR
*buffer
, *ptr
;
6075 SetLastError(ERROR_INVALID_PARAMETER
);
6079 /* make the buffer big enough for the stuff from the profile/registry,
6080 * the content must fit into the local buffer to compute the correct
6081 * size even if the extern buffer is too small or not given.
6082 * (20 for ,driver,port) */
6084 len
= max(100, (insize
+ 20));
6085 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6087 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
6089 SetLastError (ERROR_FILE_NOT_FOUND
);
6093 TRACE("%s\n", debugstr_w(buffer
));
6095 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
6097 SetLastError(ERROR_INVALID_NAME
);
6103 *namesize
= strlenW(buffer
) + 1;
6104 if(!name
|| (*namesize
> insize
))
6106 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6110 strcpyW(name
, buffer
);
6113 HeapFree( GetProcessHeap(), 0, buffer
);
6118 /******************************************************************************
6119 * GetDefaultPrinterA (WINSPOOL.@)
6121 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
6125 WCHAR
*bufferW
= NULL
;
6129 SetLastError(ERROR_INVALID_PARAMETER
);
6133 if(name
&& *namesize
) {
6135 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
6138 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
6143 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
6147 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
6150 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
6153 HeapFree( GetProcessHeap(), 0, bufferW
);
6158 /******************************************************************************
6159 * SetDefaultPrinterW (WINSPOOL.204)
6161 * Set the Name of the Default Printer
6164 * pszPrinter [I] Name of the Printer or NULL
6171 * When the Parameter is NULL or points to an Empty String and
6172 * a Default Printer was already present, then this Function changes nothing.
6173 * Without a Default Printer and NULL (or an Empty String) as Parameter,
6174 * the First enumerated local Printer is used.
6177 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
6179 WCHAR default_printer
[MAX_PATH
];
6180 LPWSTR buffer
= NULL
;
6186 TRACE("(%s)\n", debugstr_w(pszPrinter
));
6187 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
6189 default_printer
[0] = '\0';
6190 size
= ARRAY_SIZE(default_printer
);
6192 /* if we have a default Printer, do nothing. */
6193 if (GetDefaultPrinterW(default_printer
, &size
))
6197 /* we have no default Printer: search local Printers and use the first */
6198 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
6200 default_printer
[0] = '\0';
6201 size
= ARRAY_SIZE(default_printer
);
6202 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
6204 pszPrinter
= default_printer
;
6205 TRACE("using %s\n", debugstr_w(pszPrinter
));
6210 if (pszPrinter
== NULL
) {
6211 TRACE("no local printer found\n");
6212 SetLastError(ERROR_FILE_NOT_FOUND
);
6217 /* "pszPrinter" is never empty or NULL here. */
6218 namelen
= lstrlenW(pszPrinter
);
6219 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
6220 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
6222 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
6223 HeapFree(GetProcessHeap(), 0, buffer
);
6224 SetLastError(ERROR_FILE_NOT_FOUND
);
6228 /* read the devices entry for the printer (driver,port) to build the string for the
6229 default device entry (printer,driver,port) */
6230 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
6231 buffer
[namelen
] = ',';
6232 namelen
++; /* move index to the start of the driver */
6234 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
6235 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
6239 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
))
6241 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (BYTE
*)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
6247 if (lres
!= ERROR_FILE_NOT_FOUND
)
6248 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
6250 SetLastError(ERROR_INVALID_PRINTER_NAME
);
6254 HeapFree(GetProcessHeap(), 0, buffer
);
6255 return (lres
== ERROR_SUCCESS
);
6258 /******************************************************************************
6259 * SetDefaultPrinterA (WINSPOOL.202)
6261 * See SetDefaultPrinterW.
6264 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
6266 LPWSTR bufferW
= NULL
;
6269 TRACE("(%s)\n", debugstr_a(pszPrinter
));
6271 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
6272 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6273 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
6275 res
= SetDefaultPrinterW(bufferW
);
6276 HeapFree(GetProcessHeap(), 0, bufferW
);
6280 /******************************************************************************
6281 * SetPrinterDataExA (WINSPOOL.@)
6283 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6284 LPCSTR pValueName
, DWORD Type
,
6285 LPBYTE pData
, DWORD cbData
)
6287 HKEY hkeyPrinter
, hkeySubkey
;
6290 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
6291 debugstr_a(pValueName
), Type
, pData
, cbData
);
6293 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6297 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6299 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
6300 RegCloseKey(hkeyPrinter
);
6303 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6304 RegCloseKey(hkeySubkey
);
6305 RegCloseKey(hkeyPrinter
);
6309 /******************************************************************************
6310 * SetPrinterDataExW (WINSPOOL.@)
6312 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6313 LPCWSTR pValueName
, DWORD Type
,
6314 LPBYTE pData
, DWORD cbData
)
6316 HKEY hkeyPrinter
, hkeySubkey
;
6319 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
6320 debugstr_w(pValueName
), Type
, pData
, cbData
);
6322 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6326 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6328 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
6329 RegCloseKey(hkeyPrinter
);
6332 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6333 RegCloseKey(hkeySubkey
);
6334 RegCloseKey(hkeyPrinter
);
6338 /******************************************************************************
6339 * SetPrinterDataA (WINSPOOL.@)
6341 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
6342 LPBYTE pData
, DWORD cbData
)
6344 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
6348 /******************************************************************************
6349 * SetPrinterDataW (WINSPOOL.@)
6351 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
6352 LPBYTE pData
, DWORD cbData
)
6354 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6358 /******************************************************************************
6359 * GetPrinterDataExA (WINSPOOL.@)
6361 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6362 LPCSTR pValueName
, LPDWORD pType
,
6363 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6365 opened_printer_t
*printer
;
6366 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6369 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6370 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6372 printer
= get_opened_printer(hPrinter
);
6373 if(!printer
) return ERROR_INVALID_HANDLE
;
6375 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6376 if (ret
) return ret
;
6378 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6380 if (printer
->name
) {
6382 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6384 RegCloseKey(hkeyPrinters
);
6387 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6388 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6389 RegCloseKey(hkeyPrinter
);
6390 RegCloseKey(hkeyPrinters
);
6395 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6396 0, pType
, pData
, pcbNeeded
);
6398 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6400 RegCloseKey(hkeySubkey
);
6401 RegCloseKey(hkeyPrinter
);
6402 RegCloseKey(hkeyPrinters
);
6404 TRACE("--> %d\n", ret
);
6408 /******************************************************************************
6409 * GetPrinterDataExW (WINSPOOL.@)
6411 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6412 LPCWSTR pValueName
, LPDWORD pType
,
6413 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6415 opened_printer_t
*printer
;
6416 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6419 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6420 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6422 printer
= get_opened_printer(hPrinter
);
6423 if(!printer
) return ERROR_INVALID_HANDLE
;
6425 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6426 if (ret
) return ret
;
6428 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6430 if (printer
->name
) {
6432 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6434 RegCloseKey(hkeyPrinters
);
6437 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6438 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6439 RegCloseKey(hkeyPrinter
);
6440 RegCloseKey(hkeyPrinters
);
6445 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6446 0, pType
, pData
, pcbNeeded
);
6448 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6450 RegCloseKey(hkeySubkey
);
6451 RegCloseKey(hkeyPrinter
);
6452 RegCloseKey(hkeyPrinters
);
6454 TRACE("--> %d\n", ret
);
6458 /******************************************************************************
6459 * GetPrinterDataA (WINSPOOL.@)
6461 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6462 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6464 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6465 pData
, nSize
, pcbNeeded
);
6468 /******************************************************************************
6469 * GetPrinterDataW (WINSPOOL.@)
6471 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6472 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6474 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6475 pData
, nSize
, pcbNeeded
);
6478 /*******************************************************************************
6479 * EnumPrinterDataExW [WINSPOOL.@]
6481 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6482 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6483 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6485 HKEY hkPrinter
, hkSubKey
;
6486 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6487 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6492 PPRINTER_ENUM_VALUESW ppev
;
6494 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6496 if (pKeyName
== NULL
|| *pKeyName
== 0)
6497 return ERROR_INVALID_PARAMETER
;
6499 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6500 if (ret
!= ERROR_SUCCESS
)
6502 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6507 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6508 if (ret
!= ERROR_SUCCESS
)
6510 r
= RegCloseKey (hkPrinter
);
6511 if (r
!= ERROR_SUCCESS
)
6512 WARN ("RegCloseKey returned %i\n", r
);
6513 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6514 debugstr_w (pKeyName
), ret
);
6518 ret
= RegCloseKey (hkPrinter
);
6519 if (ret
!= ERROR_SUCCESS
)
6521 ERR ("RegCloseKey returned %i\n", ret
);
6522 r
= RegCloseKey (hkSubKey
);
6523 if (r
!= ERROR_SUCCESS
)
6524 WARN ("RegCloseKey returned %i\n", r
);
6528 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6529 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6530 if (ret
!= ERROR_SUCCESS
)
6532 r
= RegCloseKey (hkSubKey
);
6533 if (r
!= ERROR_SUCCESS
)
6534 WARN ("RegCloseKey returned %i\n", r
);
6535 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6539 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6540 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6542 if (cValues
== 0) /* empty key */
6544 r
= RegCloseKey (hkSubKey
);
6545 if (r
!= ERROR_SUCCESS
)
6546 WARN ("RegCloseKey returned %i\n", r
);
6547 *pcbEnumValues
= *pnEnumValues
= 0;
6548 return ERROR_SUCCESS
;
6551 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6553 hHeap
= GetProcessHeap ();
6556 ERR ("GetProcessHeap failed\n");
6557 r
= RegCloseKey (hkSubKey
);
6558 if (r
!= ERROR_SUCCESS
)
6559 WARN ("RegCloseKey returned %i\n", r
);
6560 return ERROR_OUTOFMEMORY
;
6563 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6564 if (lpValueName
== NULL
)
6566 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6567 r
= RegCloseKey (hkSubKey
);
6568 if (r
!= ERROR_SUCCESS
)
6569 WARN ("RegCloseKey returned %i\n", r
);
6570 return ERROR_OUTOFMEMORY
;
6573 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6574 if (lpValue
== NULL
)
6576 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6577 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6578 WARN ("HeapFree failed with code %i\n", GetLastError ());
6579 r
= RegCloseKey (hkSubKey
);
6580 if (r
!= ERROR_SUCCESS
)
6581 WARN ("RegCloseKey returned %i\n", r
);
6582 return ERROR_OUTOFMEMORY
;
6585 TRACE ("pass 1: calculating buffer required for all names and values\n");
6587 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6589 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6591 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6593 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6594 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6595 NULL
, NULL
, lpValue
, &cbValueLen
);
6596 if (ret
!= ERROR_SUCCESS
)
6598 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6599 WARN ("HeapFree failed with code %i\n", GetLastError ());
6600 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6601 WARN ("HeapFree failed with code %i\n", GetLastError ());
6602 r
= RegCloseKey (hkSubKey
);
6603 if (r
!= ERROR_SUCCESS
)
6604 WARN ("RegCloseKey returned %i\n", r
);
6605 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6609 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6610 debugstr_w (lpValueName
), dwIndex
,
6611 cbValueNameLen
+ 1, cbValueLen
);
6613 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6614 cbBufSize
+= cbValueLen
;
6617 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6619 *pcbEnumValues
= cbBufSize
;
6620 *pnEnumValues
= cValues
;
6622 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6624 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6625 WARN ("HeapFree failed with code %i\n", GetLastError ());
6626 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6627 WARN ("HeapFree failed with code %i\n", GetLastError ());
6628 r
= RegCloseKey (hkSubKey
);
6629 if (r
!= ERROR_SUCCESS
)
6630 WARN ("RegCloseKey returned %i\n", r
);
6631 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6632 return ERROR_MORE_DATA
;
6635 TRACE ("pass 2: copying all names and values to buffer\n");
6637 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6638 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6640 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6642 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6643 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6644 NULL
, &dwType
, lpValue
, &cbValueLen
);
6645 if (ret
!= ERROR_SUCCESS
)
6647 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6648 WARN ("HeapFree failed with code %i\n", GetLastError ());
6649 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6650 WARN ("HeapFree failed with code %i\n", GetLastError ());
6651 r
= RegCloseKey (hkSubKey
);
6652 if (r
!= ERROR_SUCCESS
)
6653 WARN ("RegCloseKey returned %i\n", r
);
6654 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6658 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6659 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6660 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6661 pEnumValues
+= cbValueNameLen
;
6663 /* return # of *bytes* (including trailing \0), not # of chars */
6664 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6666 ppev
[dwIndex
].dwType
= dwType
;
6668 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6669 ppev
[dwIndex
].pData
= pEnumValues
;
6670 pEnumValues
+= cbValueLen
;
6672 ppev
[dwIndex
].cbData
= cbValueLen
;
6674 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6675 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6678 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6680 ret
= GetLastError ();
6681 ERR ("HeapFree failed with code %i\n", ret
);
6682 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6683 WARN ("HeapFree failed with code %i\n", GetLastError ());
6684 r
= RegCloseKey (hkSubKey
);
6685 if (r
!= ERROR_SUCCESS
)
6686 WARN ("RegCloseKey returned %i\n", r
);
6690 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6692 ret
= GetLastError ();
6693 ERR ("HeapFree failed with code %i\n", ret
);
6694 r
= RegCloseKey (hkSubKey
);
6695 if (r
!= ERROR_SUCCESS
)
6696 WARN ("RegCloseKey returned %i\n", r
);
6700 ret
= RegCloseKey (hkSubKey
);
6701 if (ret
!= ERROR_SUCCESS
)
6703 ERR ("RegCloseKey returned %i\n", ret
);
6707 return ERROR_SUCCESS
;
6710 /*******************************************************************************
6711 * EnumPrinterDataExA [WINSPOOL.@]
6713 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6714 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6715 * what Windows 2000 SP1 does.
6718 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6719 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6720 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6724 DWORD ret
, dwIndex
, dwBufSize
;
6728 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6730 if (pKeyName
== NULL
|| *pKeyName
== 0)
6731 return ERROR_INVALID_PARAMETER
;
6733 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6736 ret
= GetLastError ();
6737 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6741 hHeap
= GetProcessHeap ();
6744 ERR ("GetProcessHeap failed\n");
6745 return ERROR_OUTOFMEMORY
;
6748 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6749 if (pKeyNameW
== NULL
)
6751 ERR ("Failed to allocate %i bytes from process heap\n",
6752 (LONG
)(len
* sizeof (WCHAR
)));
6753 return ERROR_OUTOFMEMORY
;
6756 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6758 ret
= GetLastError ();
6759 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6760 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6761 WARN ("HeapFree failed with code %i\n", GetLastError ());
6765 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6766 pcbEnumValues
, pnEnumValues
);
6767 if (ret
!= ERROR_SUCCESS
)
6769 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6770 WARN ("HeapFree failed with code %i\n", GetLastError ());
6771 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6775 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6777 ret
= GetLastError ();
6778 ERR ("HeapFree failed with code %i\n", ret
);
6782 if (*pnEnumValues
== 0) /* empty key */
6783 return ERROR_SUCCESS
;
6786 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6788 PPRINTER_ENUM_VALUESW ppev
=
6789 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6791 if (dwBufSize
< ppev
->cbValueName
)
6792 dwBufSize
= ppev
->cbValueName
;
6794 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6795 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6796 dwBufSize
= ppev
->cbData
;
6799 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6801 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6802 if (pBuffer
== NULL
)
6804 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6805 return ERROR_OUTOFMEMORY
;
6808 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6810 PPRINTER_ENUM_VALUESW ppev
=
6811 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6813 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6814 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6818 ret
= GetLastError ();
6819 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6820 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6821 WARN ("HeapFree failed with code %i\n", GetLastError ());
6825 memcpy (ppev
->pValueName
, pBuffer
, len
);
6827 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer
);
6829 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6830 ppev
->dwType
!= REG_MULTI_SZ
)
6833 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6834 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6837 ret
= GetLastError ();
6838 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6839 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6840 WARN ("HeapFree failed with code %i\n", GetLastError ());
6844 memcpy (ppev
->pData
, pBuffer
, len
);
6846 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer
);
6847 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6850 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6852 ret
= GetLastError ();
6853 ERR ("HeapFree failed with code %i\n", ret
);
6857 return ERROR_SUCCESS
;
6860 /******************************************************************************
6861 * AbortPrinter (WINSPOOL.@)
6863 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6865 FIXME("(%p), stub!\n", hPrinter
);
6869 /******************************************************************************
6870 * AddPortA (WINSPOOL.@)
6875 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6877 LPWSTR nameW
= NULL
;
6878 LPWSTR monitorW
= NULL
;
6882 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6885 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6886 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6887 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6891 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6892 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6893 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6895 res
= AddPortW(nameW
, hWnd
, monitorW
);
6896 HeapFree(GetProcessHeap(), 0, nameW
);
6897 HeapFree(GetProcessHeap(), 0, monitorW
);
6901 /******************************************************************************
6902 * AddPortW (WINSPOOL.@)
6904 * Add a Port for a specific Monitor
6907 * pName [I] Servername or NULL (local Computer)
6908 * hWnd [I] Handle to parent Window for the Dialog-Box
6909 * pMonitorName [I] Name of the Monitor that manage the Port
6916 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6918 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6920 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6922 if (!pMonitorName
) {
6923 SetLastError(RPC_X_NULL_REF_POINTER
);
6927 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6930 /******************************************************************************
6931 * AddPortExA (WINSPOOL.@)
6936 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6939 PORT_INFO_2A
* pi2A
;
6940 LPWSTR nameW
= NULL
;
6941 LPWSTR monitorW
= NULL
;
6945 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6947 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6948 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6950 if ((level
< 1) || (level
> 2)) {
6951 SetLastError(ERROR_INVALID_LEVEL
);
6956 SetLastError(ERROR_INVALID_PARAMETER
);
6961 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6962 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6963 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6967 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6968 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6969 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6972 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6974 if (pi2A
->pPortName
) {
6975 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6976 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6977 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6981 if (pi2A
->pMonitorName
) {
6982 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6983 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6984 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6987 if (pi2A
->pDescription
) {
6988 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6989 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6990 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6992 pi2W
.fPortType
= pi2A
->fPortType
;
6993 pi2W
.Reserved
= pi2A
->Reserved
;
6996 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6998 HeapFree(GetProcessHeap(), 0, nameW
);
6999 HeapFree(GetProcessHeap(), 0, monitorW
);
7000 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
7001 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
7002 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
7007 /******************************************************************************
7008 * AddPortExW (WINSPOOL.@)
7010 * Add a Port for a specific Monitor, without presenting a user interface
7013 * pName [I] Servername or NULL (local Computer)
7014 * level [I] Structure-Level (1 or 2) for pBuffer
7015 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
7016 * pMonitorName [I] Name of the Monitor that manage the Port
7023 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
7027 pi2
= (PORT_INFO_2W
*) pBuffer
;
7029 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
7030 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
7031 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
7032 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
7034 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7036 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
7037 SetLastError(ERROR_INVALID_PARAMETER
);
7041 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
7044 /******************************************************************************
7045 * AddPrinterConnectionA (WINSPOOL.@)
7047 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
7049 FIXME("%s\n", debugstr_a(pName
));
7053 /******************************************************************************
7054 * AddPrinterConnectionW (WINSPOOL.@)
7056 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
7058 FIXME("%s\n", debugstr_w(pName
));
7062 /******************************************************************************
7063 * AddPrinterDriverExW (WINSPOOL.@)
7065 * Install a Printer Driver with the Option to upgrade / downgrade the Files
7068 * pName [I] Servername or NULL (local Computer)
7069 * level [I] Level for the supplied DRIVER_INFO_*W struct
7070 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
7071 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
7078 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
7080 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
7082 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7084 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
7085 SetLastError(ERROR_INVALID_LEVEL
);
7090 SetLastError(ERROR_INVALID_PARAMETER
);
7094 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
7097 /******************************************************************************
7098 * AddPrinterDriverExA (WINSPOOL.@)
7100 * See AddPrinterDriverExW.
7103 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
7105 DRIVER_INFO_8A
*diA
;
7107 LPWSTR nameW
= NULL
;
7112 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
7114 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
7115 ZeroMemory(&diW
, sizeof(diW
));
7117 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
7118 SetLastError(ERROR_INVALID_LEVEL
);
7123 SetLastError(ERROR_INVALID_PARAMETER
);
7127 /* convert servername to unicode */
7129 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7130 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7131 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7135 diW
.cVersion
= diA
->cVersion
;
7138 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
7139 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7140 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
7143 if (diA
->pEnvironment
) {
7144 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
7145 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7146 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
7149 if (diA
->pDriverPath
) {
7150 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
7151 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7152 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
7155 if (diA
->pDataFile
) {
7156 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
7157 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7158 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
7161 if (diA
->pConfigFile
) {
7162 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
7163 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7164 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
7167 if ((Level
> 2) && diA
->pHelpFile
) {
7168 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, NULL
, 0);
7169 diW
.pHelpFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7170 MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, diW
.pHelpFile
, len
);
7173 if ((Level
> 2) && diA
->pDependentFiles
) {
7174 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
7175 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
7176 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7177 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
7180 if ((Level
> 2) && diA
->pMonitorName
) {
7181 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
7182 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7183 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
7186 if ((Level
> 2) && diA
->pDefaultDataType
) {
7187 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
7188 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7189 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
7192 if ((Level
> 3) && diA
->pszzPreviousNames
) {
7193 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
7194 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
7195 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7196 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
7200 diW
.ftDriverDate
= diA
->ftDriverDate
;
7201 diW
.dwlDriverVersion
= diA
->dwlDriverVersion
;
7204 if ((Level
> 5) && diA
->pszMfgName
) {
7205 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
7206 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7207 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
7210 if ((Level
> 5) && diA
->pszOEMUrl
) {
7211 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
7212 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7213 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
7216 if ((Level
> 5) && diA
->pszHardwareID
) {
7217 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
7218 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7219 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
7222 if ((Level
> 5) && diA
->pszProvider
) {
7223 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
7224 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7225 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
7228 if ((Level
> 7) && diA
->pszPrintProcessor
) {
7229 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, NULL
, 0);
7230 diW
.pszPrintProcessor
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7231 MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, diW
.pszPrintProcessor
, len
);
7234 if ((Level
> 7) && diA
->pszVendorSetup
) {
7235 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, NULL
, 0);
7236 diW
.pszVendorSetup
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7237 MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, diW
.pszVendorSetup
, len
);
7240 if ((Level
> 7) && diA
->pszzColorProfiles
) {
7241 lenA
= multi_sz_lenA(diA
->pszzColorProfiles
);
7242 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, NULL
, 0);
7243 diW
.pszzColorProfiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7244 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, diW
.pszzColorProfiles
, len
);
7247 if ((Level
> 7) && diA
->pszInfPath
) {
7248 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, NULL
, 0);
7249 diW
.pszInfPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7250 MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, diW
.pszInfPath
, len
);
7253 if ((Level
> 7) && diA
->pszzCoreDriverDependencies
) {
7254 lenA
= multi_sz_lenA(diA
->pszzCoreDriverDependencies
);
7255 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, NULL
, 0);
7256 diW
.pszzCoreDriverDependencies
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7257 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, diW
.pszzCoreDriverDependencies
, len
);
7261 diW
.dwPrinterDriverAttributes
= diA
->dwPrinterDriverAttributes
;
7262 diW
.ftMinInboxDriverVerDate
= diA
->ftMinInboxDriverVerDate
;
7263 diW
.dwlMinInboxDriverVerVersion
= diA
->dwlMinInboxDriverVerVersion
;
7266 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
7267 TRACE("got %u with %u\n", res
, GetLastError());
7268 HeapFree(GetProcessHeap(), 0, nameW
);
7269 HeapFree(GetProcessHeap(), 0, diW
.pName
);
7270 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
7271 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
7272 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
7273 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
7274 HeapFree(GetProcessHeap(), 0, diW
.pHelpFile
);
7275 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
7276 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
7277 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
7278 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
7279 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
7280 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
7281 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
7282 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
7283 HeapFree(GetProcessHeap(), 0, diW
.pszPrintProcessor
);
7284 HeapFree(GetProcessHeap(), 0, diW
.pszVendorSetup
);
7285 HeapFree(GetProcessHeap(), 0, diW
.pszzColorProfiles
);
7286 HeapFree(GetProcessHeap(), 0, diW
.pszInfPath
);
7287 HeapFree(GetProcessHeap(), 0, diW
.pszzCoreDriverDependencies
);
7289 TRACE("=> %u with %u\n", res
, GetLastError());
7293 /******************************************************************************
7294 * ConfigurePortA (WINSPOOL.@)
7296 * See ConfigurePortW.
7299 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
7301 LPWSTR nameW
= NULL
;
7302 LPWSTR portW
= NULL
;
7306 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
7308 /* convert servername to unicode */
7310 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7311 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7312 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7315 /* convert portname to unicode */
7317 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
7318 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7319 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
7322 res
= ConfigurePortW(nameW
, hWnd
, portW
);
7323 HeapFree(GetProcessHeap(), 0, nameW
);
7324 HeapFree(GetProcessHeap(), 0, portW
);
7328 /******************************************************************************
7329 * ConfigurePortW (WINSPOOL.@)
7331 * Display the Configuration-Dialog for a specific Port
7334 * pName [I] Servername or NULL (local Computer)
7335 * hWnd [I] Handle to parent Window for the Dialog-Box
7336 * pPortName [I] Name of the Port, that should be configured
7343 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
7346 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
7348 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7351 SetLastError(RPC_X_NULL_REF_POINTER
);
7355 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
7358 /******************************************************************************
7359 * ConnectToPrinterDlg (WINSPOOL.@)
7361 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
7363 FIXME("%p %x\n", hWnd
, Flags
);
7367 /******************************************************************************
7368 * DeletePrinterConnectionA (WINSPOOL.@)
7370 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
7372 FIXME("%s\n", debugstr_a(pName
));
7376 /******************************************************************************
7377 * DeletePrinterConnectionW (WINSPOOL.@)
7379 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
7381 FIXME("%s\n", debugstr_w(pName
));
7385 /******************************************************************************
7386 * DeletePrinterDriverExW (WINSPOOL.@)
7388 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
7389 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7394 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7395 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
7397 if(pName
&& pName
[0])
7399 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
7400 SetLastError(ERROR_INVALID_PARAMETER
);
7406 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7407 SetLastError(ERROR_INVALID_PARAMETER
);
7411 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7415 ERR("Can't open drivers key\n");
7419 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7422 RegCloseKey(hkey_drivers
);
7427 /******************************************************************************
7428 * DeletePrinterDriverExA (WINSPOOL.@)
7430 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7431 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7433 UNICODE_STRING NameW
, EnvW
, DriverW
;
7436 asciitounicode(&NameW
, pName
);
7437 asciitounicode(&EnvW
, pEnvironment
);
7438 asciitounicode(&DriverW
, pDriverName
);
7440 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7442 RtlFreeUnicodeString(&DriverW
);
7443 RtlFreeUnicodeString(&EnvW
);
7444 RtlFreeUnicodeString(&NameW
);
7449 /******************************************************************************
7450 * DeletePrinterDataExW (WINSPOOL.@)
7452 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7455 FIXME("%p %s %s\n", hPrinter
,
7456 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7457 return ERROR_INVALID_PARAMETER
;
7460 /******************************************************************************
7461 * DeletePrinterDataExA (WINSPOOL.@)
7463 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7466 FIXME("%p %s %s\n", hPrinter
,
7467 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7468 return ERROR_INVALID_PARAMETER
;
7471 /******************************************************************************
7472 * DeletePrintProcessorA (WINSPOOL.@)
7474 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7476 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7477 debugstr_a(pPrintProcessorName
));
7481 /******************************************************************************
7482 * DeletePrintProcessorW (WINSPOOL.@)
7484 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7486 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7487 debugstr_w(pPrintProcessorName
));
7491 /******************************************************************************
7492 * DeletePrintProvidorA (WINSPOOL.@)
7494 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7496 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7497 debugstr_a(pPrintProviderName
));
7501 /******************************************************************************
7502 * DeletePrintProvidorW (WINSPOOL.@)
7504 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7506 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7507 debugstr_w(pPrintProviderName
));
7511 /******************************************************************************
7512 * EnumFormsA (WINSPOOL.@)
7514 BOOL WINAPI
EnumFormsA( HANDLE printer
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
, DWORD
*count
)
7516 const DWORD
*string_info
= form_string_info( level
);
7520 if (!string_info
) return FALSE
;
7522 ret
= EnumFormsW( printer
, level
, form
, size
, needed
, count
);
7524 for (i
= 0; i
< *count
; i
++)
7525 packed_struct_WtoA( form
+ i
* string_info
[0], string_info
);
7530 /******************************************************************************
7531 * EnumFormsW (WINSPOOL.@)
7533 BOOL WINAPI
EnumFormsW( HANDLE printer
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
, DWORD
*count
)
7535 HANDLE handle
= get_backend_handle( printer
);
7537 TRACE( "(%p, %d, %p, %d, %p, %p)\n", printer
, level
, form
, size
, needed
, count
);
7541 SetLastError( ERROR_INVALID_HANDLE
);
7545 if (!needed
|| !count
)
7547 SetLastError( RPC_X_NULL_REF_POINTER
);
7553 SetLastError( ERROR_INVALID_USER_BUFFER
);
7557 return backend
->fpEnumForms( handle
, level
, form
, size
, needed
, count
);
7560 /*****************************************************************************
7561 * EnumMonitorsA [WINSPOOL.@]
7563 * See EnumMonitorsW.
7566 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7567 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7570 LPBYTE bufferW
= NULL
;
7571 LPWSTR nameW
= NULL
;
7573 DWORD numentries
= 0;
7576 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7577 cbBuf
, pcbNeeded
, pcReturned
);
7579 /* convert servername to unicode */
7581 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7582 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7583 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7585 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7586 needed
= cbBuf
* sizeof(WCHAR
);
7587 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7588 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7590 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7591 if (pcbNeeded
) needed
= *pcbNeeded
;
7592 /* HeapReAlloc return NULL, when bufferW was NULL */
7593 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7594 HeapAlloc(GetProcessHeap(), 0, needed
);
7596 /* Try again with the large Buffer */
7597 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7599 numentries
= pcReturned
? *pcReturned
: 0;
7602 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7603 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7606 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7607 DWORD entrysize
= 0;
7610 LPMONITOR_INFO_2W mi2w
;
7611 LPMONITOR_INFO_2A mi2a
;
7613 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7614 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7616 /* First pass: calculate the size for all Entries */
7617 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7618 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7620 while (index
< numentries
) {
7622 needed
+= entrysize
; /* MONITOR_INFO_?A */
7623 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7625 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7626 NULL
, 0, NULL
, NULL
);
7628 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7629 NULL
, 0, NULL
, NULL
);
7630 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7631 NULL
, 0, NULL
, NULL
);
7633 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7634 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7635 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7638 /* check for errors and quit on failure */
7639 if (cbBuf
< needed
) {
7640 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7644 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7645 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7646 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7647 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7648 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7650 /* Second Pass: Fill the User Buffer (if we have one) */
7651 while ((index
< numentries
) && pMonitors
) {
7653 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7655 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7656 ptr
, cbBuf
, NULL
, NULL
);
7660 mi2a
->pEnvironment
= ptr
;
7661 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7662 ptr
, cbBuf
, NULL
, NULL
);
7666 mi2a
->pDLLName
= ptr
;
7667 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7668 ptr
, cbBuf
, NULL
, NULL
);
7672 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7673 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7674 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7678 if (pcbNeeded
) *pcbNeeded
= needed
;
7679 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7681 HeapFree(GetProcessHeap(), 0, nameW
);
7682 HeapFree(GetProcessHeap(), 0, bufferW
);
7684 TRACE("returning %d with %d (%d byte for %d entries)\n",
7685 (res
), GetLastError(), needed
, numentries
);
7691 /*****************************************************************************
7692 * EnumMonitorsW [WINSPOOL.@]
7694 * Enumerate available Port-Monitors
7697 * pName [I] Servername or NULL (local Computer)
7698 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7699 * pMonitors [O] PTR to Buffer that receives the Result
7700 * cbBuf [I] Size of Buffer at pMonitors
7701 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7702 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7706 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7709 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7710 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7713 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7714 cbBuf
, pcbNeeded
, pcReturned
);
7716 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7718 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7719 SetLastError(RPC_X_NULL_REF_POINTER
);
7723 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7726 /******************************************************************************
7727 * SpoolerInit (WINSPOOL.@)
7729 * Initialize the Spooler
7736 * The function fails on windows, when the spooler service is not running
7739 BOOL WINAPI
SpoolerInit(void)
7742 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7746 /******************************************************************************
7747 * XcvDataW (WINSPOOL.@)
7749 * Execute commands in the Printmonitor DLL
7752 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7753 * pszDataName [i] Name of the command to execute
7754 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7755 * cbInputData [i] Size in Bytes of Buffer at pInputData
7756 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7757 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7758 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7759 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7766 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7767 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7769 * Minimal List of commands, that a Printmonitor DLL should support:
7771 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7772 *| "AddPort" : Add a Port
7773 *| "DeletePort": Delete a Port
7775 * Many Printmonitors support additional commands. Examples for localspl.dll:
7776 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7777 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7780 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7781 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7782 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7784 opened_printer_t
*printer
;
7786 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7787 pInputData
, cbInputData
, pOutputData
,
7788 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7790 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7792 printer
= get_opened_printer(hXcv
);
7793 if (!printer
|| (!printer
->backend_printer
)) {
7794 SetLastError(ERROR_INVALID_HANDLE
);
7798 if (!pcbOutputNeeded
) {
7799 SetLastError(ERROR_INVALID_PARAMETER
);
7803 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7804 SetLastError(RPC_X_NULL_REF_POINTER
);
7808 *pcbOutputNeeded
= 0;
7810 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7811 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7815 /*****************************************************************************
7816 * EnumPrinterDataA [WINSPOOL.@]
7819 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7820 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7821 DWORD cbData
, LPDWORD pcbData
)
7823 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7824 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7825 return ERROR_NO_MORE_ITEMS
;
7828 /*****************************************************************************
7829 * EnumPrinterDataW [WINSPOOL.@]
7832 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7833 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7834 DWORD cbData
, LPDWORD pcbData
)
7836 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7837 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7838 return ERROR_NO_MORE_ITEMS
;
7841 /*****************************************************************************
7842 * EnumPrinterKeyA [WINSPOOL.@]
7845 DWORD WINAPI
EnumPrinterKeyA(HANDLE printer
, const CHAR
*key
, CHAR
*subkey
, DWORD size
, DWORD
*needed
)
7847 FIXME("%p %s %p %x %p\n", printer
, debugstr_a(key
), subkey
, size
, needed
);
7848 return ERROR_CALL_NOT_IMPLEMENTED
;
7851 /*****************************************************************************
7852 * EnumPrinterKeyW [WINSPOOL.@]
7855 DWORD WINAPI
EnumPrinterKeyW(HANDLE printer
, const WCHAR
*key
, WCHAR
*subkey
, DWORD size
, DWORD
*needed
)
7857 FIXME("%p %s %p %x %p\n", printer
, debugstr_w(key
), subkey
, size
, needed
);
7858 return ERROR_CALL_NOT_IMPLEMENTED
;
7861 /*****************************************************************************
7862 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7865 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7866 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7867 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7869 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7870 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7871 pcbNeeded
, pcReturned
);
7875 /*****************************************************************************
7876 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7879 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7880 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7881 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7883 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7884 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7885 pcbNeeded
, pcReturned
);
7889 /*****************************************************************************
7890 * EnumPrintProcessorsA [WINSPOOL.@]
7892 * See EnumPrintProcessorsW.
7895 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7896 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7899 LPBYTE bufferW
= NULL
;
7900 LPWSTR nameW
= NULL
;
7903 DWORD numentries
= 0;
7906 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7907 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7909 /* convert names to unicode */
7911 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7912 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7913 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7916 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7917 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7918 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7921 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7922 needed
= cbBuf
* sizeof(WCHAR
);
7923 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7924 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7926 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7927 if (pcbNeeded
) needed
= *pcbNeeded
;
7928 /* HeapReAlloc return NULL, when bufferW was NULL */
7929 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7930 HeapAlloc(GetProcessHeap(), 0, needed
);
7932 /* Try again with the large Buffer */
7933 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7935 numentries
= pcReturned
? *pcReturned
: 0;
7939 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7942 PPRINTPROCESSOR_INFO_1W ppiw
;
7943 PPRINTPROCESSOR_INFO_1A ppia
;
7945 /* First pass: calculate the size for all Entries */
7946 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7947 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7949 while (index
< numentries
) {
7951 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7952 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7954 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7955 NULL
, 0, NULL
, NULL
);
7957 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7958 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7961 /* check for errors and quit on failure */
7962 if (cbBuf
< needed
) {
7963 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7968 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7969 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7970 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7971 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7972 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7974 /* Second Pass: Fill the User Buffer (if we have one) */
7975 while ((index
< numentries
) && pPPInfo
) {
7977 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7979 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7980 ptr
, cbBuf
, NULL
, NULL
);
7984 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7985 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7990 if (pcbNeeded
) *pcbNeeded
= needed
;
7991 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7993 HeapFree(GetProcessHeap(), 0, nameW
);
7994 HeapFree(GetProcessHeap(), 0, envW
);
7995 HeapFree(GetProcessHeap(), 0, bufferW
);
7997 TRACE("returning %d with %d (%d byte for %d entries)\n",
7998 (res
), GetLastError(), needed
, numentries
);
8003 /*****************************************************************************
8004 * EnumPrintProcessorsW [WINSPOOL.@]
8006 * Enumerate available Print Processors
8009 * pName [I] Servername or NULL (local Computer)
8010 * pEnvironment [I] Printing-Environment or NULL (Default)
8011 * Level [I] Structure-Level (Only 1 is allowed)
8012 * pPPInfo [O] PTR to Buffer that receives the Result
8013 * cbBuf [I] Size of Buffer at pPPInfo
8014 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
8015 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
8019 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
8022 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
8023 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
8026 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
8027 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
8029 if ((backend
== NULL
) && !load_backend()) return FALSE
;
8031 if (!pcbNeeded
|| !pcReturned
) {
8032 SetLastError(RPC_X_NULL_REF_POINTER
);
8036 if (!pPPInfo
&& (cbBuf
> 0)) {
8037 SetLastError(ERROR_INVALID_USER_BUFFER
);
8041 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
8042 cbBuf
, pcbNeeded
, pcReturned
);
8045 /*****************************************************************************
8046 * ExtDeviceMode [WINSPOOL.@]
8049 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
8050 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
8053 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
8054 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
8055 debugstr_a(pProfile
), fMode
);
8059 /*****************************************************************************
8060 * FindClosePrinterChangeNotification [WINSPOOL.@]
8063 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
8065 FIXME("Stub: %p\n", hChange
);
8069 /*****************************************************************************
8070 * FindFirstPrinterChangeNotification [WINSPOOL.@]
8073 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
8074 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
8076 FIXME("Stub: %p %x %x %p\n",
8077 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
8078 return INVALID_HANDLE_VALUE
;
8081 /*****************************************************************************
8082 * FindNextPrinterChangeNotification [WINSPOOL.@]
8085 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
8086 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
8088 FIXME("Stub: %p %p %p %p\n",
8089 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
8093 /*****************************************************************************
8094 * FreePrinterNotifyInfo [WINSPOOL.@]
8097 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
8099 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
8103 /*****************************************************************************
8106 * Copies a unicode string into a buffer. The buffer will either contain unicode or
8107 * ansi depending on the unicode parameter.
8109 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
8119 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
8122 memcpy(ptr
, str
, *size
);
8129 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
8132 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
8139 /*****************************************************************************
8142 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
8143 LPDWORD pcbNeeded
, BOOL unicode
)
8145 DWORD size
, left
= cbBuf
;
8146 BOOL space
= (cbBuf
> 0);
8153 ji1
->JobId
= job
->job_id
;
8156 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
8157 if(space
&& size
<= left
)
8159 ji1
->pDocument
= (LPWSTR
)ptr
;
8167 if (job
->printer_name
)
8169 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
8170 if(space
&& size
<= left
)
8172 ji1
->pPrinterName
= (LPWSTR
)ptr
;
8184 /*****************************************************************************
8187 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
8188 LPDWORD pcbNeeded
, BOOL unicode
)
8190 DWORD size
, left
= cbBuf
;
8192 BOOL space
= (cbBuf
> 0);
8194 LPDEVMODEA dmA
= NULL
;
8201 ji2
->JobId
= job
->job_id
;
8204 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
8205 if(space
&& size
<= left
)
8207 ji2
->pDocument
= (LPWSTR
)ptr
;
8215 if (job
->printer_name
)
8217 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
8218 if(space
&& size
<= left
)
8220 ji2
->pPrinterName
= (LPWSTR
)ptr
;
8233 dmA
= DEVMODEdupWtoA(job
->devmode
);
8234 devmode
= (LPDEVMODEW
) dmA
;
8235 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
8239 devmode
= job
->devmode
;
8240 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
8244 FIXME("Can't convert DEVMODE W to A\n");
8247 /* align DEVMODE to a DWORD boundary */
8248 shift
= (4 - (*pcbNeeded
& 3)) & 3;
8254 memcpy(ptr
, devmode
, size
-shift
);
8255 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
8256 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
8269 /*****************************************************************************
8272 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8273 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
8276 DWORD needed
= 0, size
;
8280 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
8282 EnterCriticalSection(&printer_handles_cs
);
8283 job
= get_job(hPrinter
, JobId
);
8290 size
= sizeof(JOB_INFO_1W
);
8295 memset(pJob
, 0, size
);
8299 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8304 size
= sizeof(JOB_INFO_2W
);
8309 memset(pJob
, 0, size
);
8313 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8318 size
= sizeof(JOB_INFO_3
);
8322 memset(pJob
, 0, size
);
8331 SetLastError(ERROR_INVALID_LEVEL
);
8335 *pcbNeeded
= needed
;
8337 LeaveCriticalSection(&printer_handles_cs
);
8341 /*****************************************************************************
8342 * GetJobA [WINSPOOL.@]
8345 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8346 DWORD cbBuf
, LPDWORD pcbNeeded
)
8348 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
8351 /*****************************************************************************
8352 * GetJobW [WINSPOOL.@]
8355 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8356 DWORD cbBuf
, LPDWORD pcbNeeded
)
8358 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
8361 /*****************************************************************************
8364 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
8367 char *unixname
, *cmdA
;
8369 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
8375 if(!(unixname
= wine_get_unix_file_name(filename
)))
8378 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
8379 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
8380 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
8382 TRACE("printing with: %s\n", cmdA
);
8384 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
8389 ERR("pipe() failed!\n");
8393 if ((pid
= fork()) == 0)
8399 /* reset signals that we previously set to SIG_IGN */
8400 signal(SIGPIPE
, SIG_DFL
);
8402 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
8407 ERR("fork() failed!\n");
8413 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
8414 write(fds
[1], buf
, no_read
);
8421 wret
= waitpid(pid
, &status
, 0);
8422 } while (wret
< 0 && errno
== EINTR
);
8425 ERR("waitpid() failed!\n");
8428 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
8430 ERR("child process failed! %d\n", status
);
8437 if(file_fd
!= -1) close(file_fd
);
8438 if(fds
[0] != -1) close(fds
[0]);
8439 if(fds
[1] != -1) close(fds
[1]);
8441 HeapFree(GetProcessHeap(), 0, cmdA
);
8442 HeapFree(GetProcessHeap(), 0, unixname
);
8449 /*****************************************************************************
8452 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8454 static const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8458 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8459 sprintfW(cmd
, fmtW
, printer_name
);
8461 r
= schedule_pipe(cmd
, filename
);
8463 HeapFree(GetProcessHeap(), 0, cmd
);
8467 #ifdef SONAME_LIBCUPS
8468 /*****************************************************************************
8469 * get_cups_jobs_ticket_options
8471 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8472 * The CUPS scheduler only looks for these in Print-File requests, and since
8473 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8476 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8478 FILE *fp
= fopen( file
, "r" );
8479 char buf
[257]; /* DSC max of 256 + '\0' */
8480 const char *ps_adobe
= "%!PS-Adobe-";
8481 const char *cups_job
= "%cupsJobTicket:";
8483 if (!fp
) return num_options
;
8484 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8485 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8486 while (fgets( buf
, sizeof(buf
), fp
))
8488 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8489 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8497 static int get_cups_default_options( const char *printer
, int num_options
, cups_option_t
**options
)
8502 if (!pcupsGetNamedDest
) return num_options
;
8504 dest
= pcupsGetNamedDest( NULL
, printer
, NULL
);
8505 if (!dest
) return num_options
;
8507 for (i
= 0; i
< dest
->num_options
; i
++)
8509 if (!pcupsGetOption( dest
->options
[i
].name
, num_options
, *options
))
8510 num_options
= pcupsAddOption( dest
->options
[i
].name
, dest
->options
[i
].value
,
8511 num_options
, options
);
8514 pcupsFreeDests( 1, dest
);
8519 /*****************************************************************************
8522 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8524 #ifdef SONAME_LIBCUPS
8527 char *unixname
, *queue
, *unix_doc_title
;
8530 int num_options
= 0, i
;
8531 cups_option_t
*options
= NULL
;
8533 if(!(unixname
= wine_get_unix_file_name(filename
)))
8536 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8537 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8538 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8540 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8541 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8542 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8544 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8545 num_options
= get_cups_default_options( queue
, num_options
, &options
);
8547 TRACE( "printing via cups with options:\n" );
8548 for (i
= 0; i
< num_options
; i
++)
8549 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8551 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8552 if (ret
== 0 && pcupsLastErrorString
)
8553 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8555 pcupsFreeOptions( num_options
, options
);
8557 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8558 HeapFree(GetProcessHeap(), 0, queue
);
8559 HeapFree(GetProcessHeap(), 0, unixname
);
8565 return schedule_lpr(printer_name
, filename
);
8569 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8576 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8580 if(HIWORD(wparam
) == BN_CLICKED
)
8582 if(LOWORD(wparam
) == IDOK
)
8585 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8588 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8589 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8591 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8593 WCHAR caption
[200], message
[200];
8596 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
8597 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, ARRAY_SIZE(message
));
8598 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8599 if(mb_ret
== IDCANCEL
)
8601 HeapFree(GetProcessHeap(), 0, filename
);
8605 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8606 if(hf
== INVALID_HANDLE_VALUE
)
8608 WCHAR caption
[200], message
[200];
8610 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
8611 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, ARRAY_SIZE(message
));
8612 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8613 HeapFree(GetProcessHeap(), 0, filename
);
8617 DeleteFileW(filename
);
8618 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8620 EndDialog(hwnd
, IDOK
);
8623 if(LOWORD(wparam
) == IDCANCEL
)
8625 EndDialog(hwnd
, IDCANCEL
);
8634 /*****************************************************************************
8637 static BOOL
get_filename(LPWSTR
*filename
)
8639 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8640 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8643 /*****************************************************************************
8646 static BOOL
schedule_file(LPCWSTR filename
)
8648 LPWSTR output
= NULL
;
8650 if(get_filename(&output
))
8653 TRACE("copy to %s\n", debugstr_w(output
));
8654 r
= CopyFileW(filename
, output
, FALSE
);
8655 HeapFree(GetProcessHeap(), 0, output
);
8661 /*****************************************************************************
8664 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8666 int in_fd
, out_fd
, no_read
;
8669 char *unixname
, *outputA
;
8672 if(!(unixname
= wine_get_unix_file_name(filename
)))
8675 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8676 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8677 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8679 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8680 in_fd
= open(unixname
, O_RDONLY
);
8681 if(out_fd
== -1 || in_fd
== -1)
8684 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8685 write(out_fd
, buf
, no_read
);
8689 if(in_fd
!= -1) close(in_fd
);
8690 if(out_fd
!= -1) close(out_fd
);
8691 HeapFree(GetProcessHeap(), 0, outputA
);
8692 HeapFree(GetProcessHeap(), 0, unixname
);
8696 /*****************************************************************************
8697 * ScheduleJob [WINSPOOL.@]
8700 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8702 opened_printer_t
*printer
;
8704 struct list
*cursor
, *cursor2
;
8706 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8707 EnterCriticalSection(&printer_handles_cs
);
8708 printer
= get_opened_printer(hPrinter
);
8712 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8714 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8717 if(job
->job_id
!= dwJobID
) continue;
8719 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8720 if(hf
!= INVALID_HANDLE_VALUE
)
8722 PRINTER_INFO_5W
*pi5
= NULL
;
8723 LPWSTR portname
= job
->portname
;
8727 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8728 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8732 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8733 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8734 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8735 portname
= pi5
->pPortName
;
8737 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8738 debugstr_w(portname
));
8742 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8743 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8745 DWORD type
, count
= sizeof(output
);
8746 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8749 if(output
[0] == '|')
8751 ret
= schedule_pipe(output
+ 1, job
->filename
);
8755 ret
= schedule_unixfile(output
, job
->filename
);
8757 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8759 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8761 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8763 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8765 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8767 ret
= schedule_file(job
->filename
);
8769 else if(isalpha(portname
[0]) && portname
[1] == ':')
8771 TRACE("copying to %s\n", debugstr_w(portname
));
8772 ret
= CopyFileW(job
->filename
, portname
, FALSE
);
8776 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8778 HeapFree(GetProcessHeap(), 0, pi5
);
8780 DeleteFileW(job
->filename
);
8782 list_remove(cursor
);
8783 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8784 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8785 HeapFree(GetProcessHeap(), 0, job
->portname
);
8786 HeapFree(GetProcessHeap(), 0, job
->filename
);
8787 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8788 HeapFree(GetProcessHeap(), 0, job
);
8792 LeaveCriticalSection(&printer_handles_cs
);
8796 /*****************************************************************************
8797 * StartDocDlgA [WINSPOOL.@]
8799 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8801 UNICODE_STRING usBuffer
;
8802 DOCINFOW docW
= { 0 };
8804 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8807 docW
.cbSize
= sizeof(docW
);
8808 if (doc
->lpszDocName
)
8810 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8811 if (!(docW
.lpszDocName
= docnameW
)) goto failed
;
8813 if (doc
->lpszOutput
)
8815 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8816 if (!(docW
.lpszOutput
= outputW
)) goto failed
;
8818 if (doc
->lpszDatatype
)
8820 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8821 if (!(docW
.lpszDatatype
= datatypeW
)) goto failed
;
8823 docW
.fwType
= doc
->fwType
;
8825 retW
= StartDocDlgW(hPrinter
, &docW
);
8829 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8830 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8831 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8832 HeapFree(GetProcessHeap(), 0, retW
);
8836 HeapFree(GetProcessHeap(), 0, datatypeW
);
8837 HeapFree(GetProcessHeap(), 0, outputW
);
8838 HeapFree(GetProcessHeap(), 0, docnameW
);
8843 /*****************************************************************************
8844 * StartDocDlgW [WINSPOOL.@]
8846 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8847 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8848 * port is "FILE:". Also returns the full path if passed a relative path.
8850 * The caller should free the returned string from the process heap.
8852 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8857 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8859 PRINTER_INFO_5W
*pi5
;
8860 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8861 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8863 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8864 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8865 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8867 HeapFree(GetProcessHeap(), 0, pi5
);
8870 HeapFree(GetProcessHeap(), 0, pi5
);
8873 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8877 if (get_filename(&name
))
8879 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8881 HeapFree(GetProcessHeap(), 0, name
);
8884 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8885 GetFullPathNameW(name
, len
, ret
, NULL
);
8886 HeapFree(GetProcessHeap(), 0, name
);
8891 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8894 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8895 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8897 attr
= GetFileAttributesW(ret
);
8898 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8900 HeapFree(GetProcessHeap(), 0, ret
);
8906 /*****************************************************************************
8907 * UploadPrinterDriverPackageA [WINSPOOL.@]
8909 HRESULT WINAPI
UploadPrinterDriverPackageA( LPCSTR server
, LPCSTR path
, LPCSTR env
,
8910 DWORD flags
, HWND hwnd
, LPSTR dst
, PULONG dstlen
)
8912 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server
), debugstr_a(path
), debugstr_a(env
),
8913 flags
, hwnd
, dst
, dstlen
);
8917 /*****************************************************************************
8918 * UploadPrinterDriverPackageW [WINSPOOL.@]
8920 HRESULT WINAPI
UploadPrinterDriverPackageW( LPCWSTR server
, LPCWSTR path
, LPCWSTR env
,
8921 DWORD flags
, HWND hwnd
, LPWSTR dst
, PULONG dstlen
)
8923 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server
), debugstr_w(path
), debugstr_w(env
),
8924 flags
, hwnd
, dst
, dstlen
);
8928 /*****************************************************************************
8929 * PerfOpen [WINSPOOL.@]
8931 DWORD WINAPI
PerfOpen(LPWSTR context
)
8933 FIXME("%s: stub\n", debugstr_w(context
));
8934 return ERROR_SUCCESS
;
8937 /*****************************************************************************
8938 * PerfClose [WINSPOOL.@]
8940 DWORD WINAPI
PerfClose(void)
8943 return ERROR_SUCCESS
;
8946 /*****************************************************************************
8947 * PerfCollect [WINSPOOL.@]
8949 DWORD WINAPI
PerfCollect(LPWSTR query
, LPVOID
*data
, LPDWORD size
, LPDWORD obj_count
)
8951 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query
), data
, size
, obj_count
);
8954 return ERROR_SUCCESS
;