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"
124 #include "ddk/winsplp.h"
127 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
129 /* ############################### */
131 static CRITICAL_SECTION printer_handles_cs
;
132 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
134 0, 0, &printer_handles_cs
,
135 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
136 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
138 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
140 /* ############################### */
155 HANDLE backend_printer
;
166 WCHAR
*document_title
;
176 LPCWSTR versionregpath
;
177 LPCWSTR versionsubdir
;
180 /* ############################### */
182 static opened_printer_t
**printer_handles
;
183 static UINT nb_printer_handles
;
184 static LONG next_job_id
= 1;
186 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
187 WORD fwCapability
, LPSTR lpszOutput
,
189 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
190 LPSTR lpszDevice
, LPSTR lpszPort
,
191 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
194 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
195 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
196 'c','o','n','t','r','o','l','\\',
197 'P','r','i','n','t','\\',
198 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
199 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
201 static const WCHAR PrintersW
[] = {'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 'P','r','i','n','t','e','r','s',0};
207 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
208 'M','i','c','r','o','s','o','f','t','\\',
209 'W','i','n','d','o','w','s',' ','N','T','\\',
210 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
211 'W','i','n','d','o','w','s',0};
213 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
214 'M','i','c','r','o','s','o','f','t','\\',
215 'W','i','n','d','o','w','s',' ','N','T','\\',
216 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
217 'D','e','v','i','c','e','s',0};
219 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
220 'M','i','c','r','o','s','o','f','t','\\',
221 'W','i','n','d','o','w','s',' ','N','T','\\',
222 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
223 'P','r','i','n','t','e','r','P','o','r','t','s',0};
225 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
226 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
227 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
228 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
229 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
230 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
231 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
232 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
233 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
234 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
236 static const WCHAR AttributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0};
237 static const WCHAR backslashW
[] = {'\\',0};
238 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
239 'i','o','n',' ','F','i','l','e',0};
240 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
241 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
242 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
243 static const WCHAR Default_PriorityW
[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
244 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
245 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
246 static const WCHAR dnsTimeoutW
[] = {'d','n','s','T','i','m','e','o','u','t',0};
247 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
248 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
249 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
250 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
251 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
252 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
253 static const WCHAR NameW
[] = {'N','a','m','e',0};
254 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
255 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
256 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
257 static const WCHAR PortW
[] = {'P','o','r','t',0};
258 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
259 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
260 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
261 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
262 static const WCHAR PriorityW
[] = {'P','r','i','o','r','i','t','y',0};
263 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
264 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
265 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
266 static const WCHAR StartTimeW
[] = {'S','t','a','r','t','T','i','m','e',0};
267 static const WCHAR StatusW
[] = {'S','t','a','t','u','s',0};
268 static const WCHAR txTimeoutW
[] = {'t','x','T','i','m','e','o','u','t',0};
269 static const WCHAR UntilTimeW
[] = {'U','n','t','i','l','T','i','m','e',0};
270 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
271 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
272 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
273 static WCHAR rawW
[] = {'R','A','W',0};
274 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
275 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
276 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
277 static const WCHAR commaW
[] = {',',0};
278 static WCHAR emptyStringW
[] = {0};
280 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
282 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
283 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
284 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
286 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
287 'D','o','c','u','m','e','n','t',0};
289 static const WCHAR PPD_Overrides
[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
290 static const WCHAR DefaultPageSize
[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
292 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
293 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
294 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
295 0, sizeof(DRIVER_INFO_8W
)};
298 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
299 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
300 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
301 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
302 sizeof(PRINTER_INFO_9W
)};
304 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
305 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
306 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
308 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
310 /******************************************************************
311 * validate the user-supplied printing-environment [internal]
314 * env [I] PTR to Environment-String or NULL
318 * Success: PTR to printenv_t
321 * An empty string is handled the same way as NULL.
322 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
326 static const printenv_t
* validate_envW(LPCWSTR env
)
328 const printenv_t
*result
= NULL
;
331 TRACE("testing %s\n", debugstr_w(env
));
334 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
336 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
338 result
= all_printenv
[i
];
343 if (result
== NULL
) {
344 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
345 SetLastError(ERROR_INVALID_ENVIRONMENT
);
347 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
351 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
353 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
359 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
360 if passed a NULL string. This returns NULLs to the result.
362 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
366 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
367 return usBufferPtr
->Buffer
;
369 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
373 static LPWSTR
strdupW(LPCWSTR p
)
379 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
380 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
385 static LPSTR
strdupWtoA( LPCWSTR str
)
390 if (!str
) return NULL
;
391 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
392 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
393 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
397 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
401 if (!dm
) return NULL
;
402 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
403 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
407 /***********************************************************
409 * Creates an ansi copy of supplied devmode
411 static DEVMODEA
*DEVMODEdupWtoA( const DEVMODEW
*dmW
)
416 if (!dmW
) return NULL
;
417 size
= dmW
->dmSize
- CCHDEVICENAME
-
418 ((dmW
->dmSize
> FIELD_OFFSET( DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
420 dmA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
421 if (!dmA
) return NULL
;
423 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmDeviceName
, -1,
424 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
426 if (FIELD_OFFSET( DEVMODEW
, dmFormName
) >= dmW
->dmSize
)
428 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
429 dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
433 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
434 FIELD_OFFSET( DEVMODEW
, dmFormName
) - FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
435 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmFormName
, -1,
436 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
438 memcpy( &dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmLogPixels
) );
442 memcpy( (char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
447 /******************************************************************
448 * verify, that the filename is a local file
451 static inline BOOL
is_local_file(LPWSTR name
)
453 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
456 /* ################################ */
458 static int multi_sz_lenA(const char *str
)
460 const char *ptr
= str
;
464 ptr
+= lstrlenA(ptr
) + 1;
467 return ptr
- str
+ 1;
470 /*****************************************************************************
473 * Return DWORD associated with name from hkey.
475 static DWORD
get_dword_from_reg( HKEY hkey
, const WCHAR
*name
)
477 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
480 ret
= RegQueryValueExW( hkey
, name
, 0, &type
, (LPBYTE
)&value
, &sz
);
482 if (ret
!= ERROR_SUCCESS
)
484 WARN( "Got ret = %d on name %s\n", ret
, debugstr_w(name
) );
487 if (type
!= REG_DWORD
)
489 ERR( "Got type %d\n", type
);
495 static inline DWORD
set_reg_DWORD( HKEY hkey
, const WCHAR
*keyname
, const DWORD value
)
497 return RegSetValueExW( hkey
, keyname
, 0, REG_DWORD
, (const BYTE
*)&value
, sizeof(value
) );
500 /******************************************************************
502 * Get the pointer to the opened printer referred by the handle
504 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
506 UINT_PTR idx
= (UINT_PTR
)hprn
;
507 opened_printer_t
*ret
= NULL
;
509 EnterCriticalSection(&printer_handles_cs
);
511 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
512 ret
= printer_handles
[idx
- 1];
514 LeaveCriticalSection(&printer_handles_cs
);
518 /******************************************************************
519 * get_opened_printer_name
520 * Get the pointer to the opened printer name referred by the handle
522 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
524 opened_printer_t
*printer
= get_opened_printer(hprn
);
525 if(!printer
) return NULL
;
526 return printer
->name
;
529 static DWORD
open_printer_reg_key( const WCHAR
*name
, HKEY
*key
)
535 err
= RegCreateKeyW( HKEY_LOCAL_MACHINE
, PrintersW
, &printers
);
538 err
= RegOpenKeyW( printers
, name
, key
);
539 if (err
) err
= ERROR_INVALID_PRINTER_NAME
;
540 RegCloseKey( printers
);
544 /******************************************************************
545 * WINSPOOL_GetOpenedPrinterRegKey
548 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
550 LPCWSTR name
= get_opened_printer_name(hPrinter
);
552 if(!name
) return ERROR_INVALID_HANDLE
;
553 return open_printer_reg_key( name
, phkey
);
556 static void set_default_printer(const char *devname
, const char *name
)
558 char *buf
= HeapAlloc(GetProcessHeap(), 0, strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
561 sprintf(buf
, "%s,WINEPS.DRV,LPR:%s", devname
, name
);
562 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
564 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (BYTE
*)buf
, strlen(buf
) + 1);
567 HeapFree(GetProcessHeap(), 0, buf
);
570 static BOOL
add_printer_driver(const WCHAR
*name
, WCHAR
*ppd
)
576 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
578 di3
.pName
= (WCHAR
*)name
;
579 di3
.pDriverPath
= driver_nt
;
581 di3
.pConfigFile
= driver_nt
;
582 di3
.pDefaultDataType
= rawW
;
584 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
586 di3
.pEnvironment
= (WCHAR
*) all_printenv
[i
]->envname
;
587 if (all_printenv
[i
]->envname
== envname_win40W
)
589 /* We use wineps16.drv as driver for 16 bit */
590 di3
.pDriverPath
= driver_9x
;
591 di3
.pConfigFile
= driver_9x
;
593 res
= AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
);
594 TRACE("got %d and %d for %s (%s)\n", res
, GetLastError(), debugstr_w(name
), debugstr_w(di3
.pEnvironment
));
596 if (!res
&& (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
598 ERR("failed with %u for %s (%s) %s\n", GetLastError(), debugstr_w(name
),
599 debugstr_w(di3
.pEnvironment
), debugstr_w(di3
.pDriverPath
));
607 static inline char *expand_env_string( char *str
, DWORD type
)
609 if (type
== REG_EXPAND_SZ
)
612 DWORD needed
= ExpandEnvironmentStringsA( str
, NULL
, 0 );
613 tmp
= HeapAlloc( GetProcessHeap(), 0, needed
);
616 ExpandEnvironmentStringsA( str
, tmp
, needed
);
617 HeapFree( GetProcessHeap(), 0, str
);
624 static char *get_fallback_ppd_name( const char *printer_name
)
626 static const WCHAR ppds_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
627 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
632 if (RegOpenKeyW( HKEY_CURRENT_USER
, ppds_key
, &hkey
) == ERROR_SUCCESS
)
634 const char *value_name
= NULL
;
636 if (RegQueryValueExA( hkey
, printer_name
, 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
637 value_name
= printer_name
;
638 else if (RegQueryValueExA( hkey
, "generic", 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
639 value_name
= "generic";
643 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
644 if (!ret
) return NULL
;
645 RegQueryValueExA( hkey
, value_name
, 0, &type
, (BYTE
*)ret
, &needed
);
648 if (ret
) return expand_env_string( ret
, type
);
653 static BOOL
copy_file( const char *src
, const char *dst
)
655 int fds
[2] = {-1, -1}, num
;
659 fds
[0] = open( src
, O_RDONLY
);
660 fds
[1] = open( dst
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666 );
661 if (fds
[0] == -1 || fds
[1] == -1) goto fail
;
663 while ((num
= read( fds
[0], buf
, sizeof(buf
) )) != 0)
665 if (num
== -1) goto fail
;
666 if (write( fds
[1], buf
, num
) != num
) goto fail
;
671 if (fds
[1] != -1) close( fds
[1] );
672 if (fds
[0] != -1) close( fds
[0] );
676 static BOOL
get_internal_fallback_ppd( const WCHAR
*ppd
)
678 static const WCHAR typeW
[] = {'P','P','D','F','I','L','E',0};
684 HRSRC res
= FindResourceW( WINSPOOL_hInstance
, MAKEINTRESOURCEW(1), typeW
);
686 if (!res
|| !(ptr
= LoadResource( WINSPOOL_hInstance
, res
))) return FALSE
;
687 size
= SizeofResource( WINSPOOL_hInstance
, res
);
688 end
= memchr( ptr
, 0, size
); /* resource file may contain additional nulls */
689 if (end
) size
= end
- ptr
;
690 file
= CreateFileW( ppd
, GENERIC_WRITE
, FILE_SHARE_READ
, NULL
, CREATE_ALWAYS
, 0, 0 );
691 if (file
== INVALID_HANDLE_VALUE
) return FALSE
;
692 ret
= WriteFile( file
, ptr
, size
, &written
, NULL
) && written
== size
;
694 if (ret
) TRACE( "using internal fallback for %s\n", debugstr_w( ppd
));
695 else DeleteFileW( ppd
);
699 static BOOL
get_fallback_ppd( const char *printer_name
, const WCHAR
*ppd
)
701 char *dst
, *src
= get_fallback_ppd_name( printer_name
);
704 if (!src
) return get_internal_fallback_ppd( ppd
);
706 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name
), debugstr_w(ppd
), debugstr_a(src
) );
708 if (!(dst
= wine_get_unix_file_name( ppd
))) goto fail
;
710 if (symlink( src
, dst
) == -1)
711 if (errno
!= ENOSYS
|| !copy_file( src
, dst
))
716 HeapFree( GetProcessHeap(), 0, dst
);
717 HeapFree( GetProcessHeap(), 0, src
);
721 static WCHAR
*get_ppd_filename( const WCHAR
*dir
, const WCHAR
*file_name
)
723 static const WCHAR dot_ppd
[] = {'.','p','p','d',0};
724 int len
= (strlenW( dir
) + strlenW( file_name
)) * sizeof(WCHAR
) + sizeof(dot_ppd
);
725 WCHAR
*ppd
= HeapAlloc( GetProcessHeap(), 0, len
);
727 if (!ppd
) return NULL
;
729 strcatW( ppd
, file_name
);
730 strcatW( ppd
, dot_ppd
);
735 static WCHAR
*get_ppd_dir( void )
737 static const WCHAR wine_ppds
[] = {'w','i','n','e','_','p','p','d','s','\\',0};
739 WCHAR
*dir
, tmp_path
[MAX_PATH
];
742 len
= GetTempPathW( ARRAY_SIZE( tmp_path
), tmp_path
);
743 if (!len
) return NULL
;
744 dir
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) + sizeof(wine_ppds
) ) ;
745 if (!dir
) return NULL
;
747 memcpy( dir
, tmp_path
, len
* sizeof(WCHAR
) );
748 memcpy( dir
+ len
, wine_ppds
, sizeof(wine_ppds
) );
749 res
= CreateDirectoryW( dir
, NULL
);
750 if (!res
&& GetLastError() != ERROR_ALREADY_EXISTS
)
752 HeapFree( GetProcessHeap(), 0, dir
);
755 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir
) );
759 static void unlink_ppd( const WCHAR
*ppd
)
761 char *unix_name
= wine_get_unix_file_name( ppd
);
763 HeapFree( GetProcessHeap(), 0, unix_name
);
766 #ifdef SONAME_LIBCUPS
768 static void *cupshandle
;
771 DO_FUNC(cupsAddOption); \
772 DO_FUNC(cupsFreeDests); \
773 DO_FUNC(cupsFreeOptions); \
774 DO_FUNC(cupsGetDests); \
775 DO_FUNC(cupsGetOption); \
776 DO_FUNC(cupsParseOptions); \
777 DO_FUNC(cupsPrintFile)
778 #define CUPS_OPT_FUNCS \
779 DO_FUNC(cupsGetNamedDest); \
780 DO_FUNC(cupsGetPPD); \
781 DO_FUNC(cupsGetPPD3); \
782 DO_FUNC(cupsLastErrorString)
784 #define DO_FUNC(f) static typeof(f) *p##f
787 static cups_dest_t
* (*pcupsGetNamedDest
)(http_t
*, const char *, const char *);
788 static const char * (*pcupsGetPPD
)(const char *);
789 static http_status_t (*pcupsGetPPD3
)(http_t
*, const char *, time_t *, char *, size_t);
790 static const char * (*pcupsLastErrorString
)(void);
792 static http_status_t
cupsGetPPD3_wrapper( http_t
*http
, const char *name
,
793 time_t *modtime
, char *buffer
,
798 if (pcupsGetPPD3
) return pcupsGetPPD3( http
, name
, modtime
, buffer
, bufsize
);
800 if (!pcupsGetPPD
) return HTTP_NOT_FOUND
;
802 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
805 ppd
= pcupsGetPPD( name
);
807 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd
) );
809 if (!ppd
) return HTTP_NOT_FOUND
;
811 if (rename( ppd
, buffer
) == -1)
813 BOOL res
= copy_file( ppd
, buffer
);
815 if (!res
) return HTTP_NOT_FOUND
;
820 static BOOL
get_cups_ppd( const char *printer_name
, const WCHAR
*ppd
)
823 http_status_t http_status
;
824 char *unix_name
= wine_get_unix_file_name( ppd
);
826 TRACE( "(%s, %s)\n", debugstr_a(printer_name
), debugstr_w(ppd
) );
828 if (!unix_name
) return FALSE
;
830 http_status
= cupsGetPPD3_wrapper( 0, printer_name
, &modtime
,
831 unix_name
, strlen( unix_name
) + 1 );
833 if (http_status
!= HTTP_OK
) unlink( unix_name
);
834 HeapFree( GetProcessHeap(), 0, unix_name
);
836 if (http_status
== HTTP_OK
) return TRUE
;
838 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
839 debugstr_a(printer_name
), http_status
);
840 return get_fallback_ppd( printer_name
, ppd
);
843 static WCHAR
*get_cups_option( const char *name
, int num_options
, cups_option_t
*options
)
849 value
= pcupsGetOption( name
, num_options
, options
);
850 if (!value
) return NULL
;
852 len
= MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, NULL
, 0 );
853 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
854 if (ret
) MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, ret
, len
);
859 static cups_ptype_t
get_cups_printer_type( const cups_dest_t
*dest
)
861 WCHAR
*type
= get_cups_option( "printer-type", dest
->num_options
, dest
->options
), *end
;
862 cups_ptype_t ret
= 0;
866 ret
= (cups_ptype_t
)strtoulW( type
, &end
, 10 );
869 HeapFree( GetProcessHeap(), 0, type
);
873 static void load_cups(void)
875 cupshandle
= dlopen( SONAME_LIBCUPS
, RTLD_NOW
);
876 if (!cupshandle
) return;
878 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
881 p##x = dlsym( cupshandle, #x ); \
884 ERR("failed to load symbol %s\n", #x); \
890 #define DO_FUNC(x) p##x = dlsym( cupshandle, #x )
895 static BOOL
CUPS_LoadPrinters(void)
898 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
901 WCHAR
*port
, *ppd_dir
= NULL
, *ppd
;
902 HKEY hkeyPrinter
, hkeyPrinters
;
903 WCHAR nameW
[MAX_PATH
];
904 HANDLE added_printer
;
905 cups_ptype_t printer_type
;
907 if (!cupshandle
) return FALSE
;
909 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
911 ERR("Can't create Printers key\n");
915 nrofdests
= pcupsGetDests(&dests
);
916 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
917 for (i
=0;i
<nrofdests
;i
++) {
918 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, ARRAY_SIZE(nameW
));
919 printer_type
= get_cups_printer_type( dests
+ i
);
921 TRACE( "Printer %d: %s. printer_type %x\n", i
, debugstr_w(nameW
), printer_type
);
923 if (printer_type
& 0x2000000 /* CUPS_PRINTER_SCANNER */)
925 TRACE( "skipping scanner-only device\n" );
929 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
930 lstrcpyW(port
, CUPS_Port
);
931 lstrcatW(port
, nameW
);
933 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
934 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
935 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
937 TRACE("Printer already exists\n");
938 /* overwrite old LPR:* port */
939 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
940 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
941 /* flag that the PPD file should be checked for an update */
942 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
943 RegCloseKey(hkeyPrinter
);
945 BOOL added_driver
= FALSE
;
947 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir()))
949 HeapFree( GetProcessHeap(), 0, port
);
952 ppd
= get_ppd_filename( ppd_dir
, nameW
);
953 if (get_cups_ppd( dests
[i
].name
, ppd
))
955 added_driver
= add_printer_driver( nameW
, ppd
);
958 HeapFree( GetProcessHeap(), 0, ppd
);
961 HeapFree( GetProcessHeap(), 0, port
);
965 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
966 pi2
.pPrinterName
= nameW
;
967 pi2
.pDatatype
= rawW
;
968 pi2
.pPrintProcessor
= WinPrintW
;
969 pi2
.pDriverName
= nameW
;
970 pi2
.pComment
= get_cups_option( "printer-info", dests
[i
].num_options
, dests
[i
].options
);
971 pi2
.pLocation
= get_cups_option( "printer-location", dests
[i
].num_options
, dests
[i
].options
);
972 pi2
.pPortName
= port
;
973 pi2
.pParameters
= emptyStringW
;
974 pi2
.pShareName
= emptyStringW
;
975 pi2
.pSepFile
= emptyStringW
;
977 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
978 if (added_printer
) ClosePrinter( added_printer
);
979 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
980 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
982 HeapFree( GetProcessHeap(), 0, pi2
.pComment
);
983 HeapFree( GetProcessHeap(), 0, pi2
.pLocation
);
985 HeapFree( GetProcessHeap(), 0, port
);
988 if (dests
[i
].is_default
) {
989 SetDefaultPrinterW(nameW
);
996 RemoveDirectoryW( ppd_dir
);
997 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1000 if (hadprinter
&& !haddefault
) {
1001 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, ARRAY_SIZE(nameW
));
1002 SetDefaultPrinterW(nameW
);
1004 pcupsFreeDests(nrofdests
, dests
);
1005 RegCloseKey(hkeyPrinters
);
1011 static char *get_queue_name( HANDLE printer
, BOOL
*cups
)
1013 WCHAR
*port
, *name
= NULL
;
1014 DWORD err
, needed
, type
;
1020 err
= WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
);
1021 if (err
) return NULL
;
1022 err
= RegQueryValueExW( key
, PortW
, 0, &type
, NULL
, &needed
);
1024 port
= HeapAlloc( GetProcessHeap(), 0, needed
);
1025 if (!port
) goto end
;
1026 RegQueryValueExW( key
, PortW
, 0, &type
, (BYTE
*)port
, &needed
);
1028 if (!strncmpW( port
, CUPS_Port
, ARRAY_SIZE( CUPS_Port
) -1 ))
1030 name
= port
+ ARRAY_SIZE( CUPS_Port
) - 1;
1033 else if (!strncmpW( port
, LPR_Port
, ARRAY_SIZE( LPR_Port
) -1 ))
1034 name
= port
+ ARRAY_SIZE( LPR_Port
) - 1;
1037 needed
= WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
1038 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
1039 if(ret
) WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, ret
, needed
, NULL
, NULL
);
1041 HeapFree( GetProcessHeap(), 0, port
);
1048 static void set_ppd_overrides( HANDLE printer
)
1052 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1054 PMPrintSession session
= NULL
;
1055 PMPageFormat format
= NULL
;
1057 CFStringRef paper_name
;
1060 status
= PMCreateSession( &session
);
1061 if (status
) goto end
;
1063 status
= PMCreatePageFormat( &format
);
1064 if (status
) goto end
;
1066 status
= PMSessionDefaultPageFormat( session
, format
);
1067 if (status
) goto end
;
1069 status
= PMGetPageFormatPaper( format
, &paper
);
1070 if (status
) goto end
;
1072 status
= PMPaperGetPPDPaperName( paper
, &paper_name
);
1073 if (status
) goto end
;
1076 range
.length
= CFStringGetLength( paper_name
);
1077 size
= (range
.length
+ 1) * sizeof(WCHAR
);
1079 wstr
= HeapAlloc( GetProcessHeap(), 0, size
);
1080 CFStringGetCharacters( paper_name
, range
, (UniChar
*)wstr
);
1081 wstr
[range
.length
] = 0;
1084 if (format
) PMRelease( format
);
1085 if (session
) PMRelease( session
);
1088 SetPrinterDataExW( printer
, PPD_Overrides
, DefaultPageSize
, REG_SZ
, (BYTE
*)wstr
, size
);
1089 HeapFree( GetProcessHeap(), 0, wstr
);
1092 static BOOL
update_driver( HANDLE printer
)
1095 const WCHAR
*name
= get_opened_printer_name( printer
);
1096 WCHAR
*ppd_dir
, *ppd
;
1099 if (!name
) return FALSE
;
1100 queue_name
= get_queue_name( printer
, &is_cups
);
1101 if (!queue_name
) return FALSE
;
1103 if (!(ppd_dir
= get_ppd_dir()))
1105 HeapFree( GetProcessHeap(), 0, queue_name
);
1108 ppd
= get_ppd_filename( ppd_dir
, name
);
1110 #ifdef SONAME_LIBCUPS
1112 ret
= get_cups_ppd( queue_name
, ppd
);
1115 ret
= get_fallback_ppd( queue_name
, ppd
);
1119 TRACE( "updating driver %s\n", debugstr_w( name
) );
1120 ret
= add_printer_driver( name
, ppd
);
1123 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1124 HeapFree( GetProcessHeap(), 0, ppd
);
1125 HeapFree( GetProcessHeap(), 0, queue_name
);
1127 set_ppd_overrides( printer
);
1129 /* call into the driver to update the devmode */
1130 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
1135 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
1137 PRINTER_INFO_2A pinfo2a
;
1140 char *e
,*s
,*name
,*prettyname
,*devname
;
1141 BOOL ret
= FALSE
, set_default
= FALSE
;
1142 char *port
= NULL
, *env_default
;
1143 HKEY hkeyPrinter
, hkeyPrinters
= NULL
;
1144 WCHAR devnameW
[MAX_PATH
], *ppd_dir
= NULL
, *ppd
;
1145 HANDLE added_printer
;
1147 while (isspace(*pent
)) pent
++;
1148 r
= strchr(pent
,':');
1150 name_len
= r
- pent
;
1152 name_len
= strlen(pent
);
1153 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
1154 memcpy(name
, pent
, name_len
);
1155 name
[name_len
] = '\0';
1161 TRACE("name=%s entry=%s\n",name
, pent
);
1163 if(ispunct(*name
)) { /* a tc entry, not a real printer */
1164 TRACE("skipping tc entry\n");
1168 if(strstr(pent
,":server")) { /* server only version so skip */
1169 TRACE("skipping server entry\n");
1173 /* Determine whether this is a postscript printer. */
1176 env_default
= getenv("PRINTER");
1178 /* Get longest name, usually the one at the right for later display. */
1179 while((s
=strchr(prettyname
,'|'))) {
1182 while(isspace(*--e
)) *e
= '\0';
1183 TRACE("\t%s\n", debugstr_a(prettyname
));
1184 if(env_default
&& !_strnicmp(prettyname
, env_default
, -1)) set_default
= TRUE
;
1185 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
1188 e
= prettyname
+ strlen(prettyname
);
1189 while(isspace(*--e
)) *e
= '\0';
1190 TRACE("\t%s\n", debugstr_a(prettyname
));
1191 if(env_default
&& !_strnicmp(prettyname
, env_default
, -1)) set_default
= TRUE
;
1193 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1194 * if it is too long, we use it as comment below. */
1195 devname
= prettyname
;
1196 if (strlen(devname
)>=CCHDEVICENAME
-1)
1198 if (strlen(devname
)>=CCHDEVICENAME
-1) {
1203 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
1204 sprintf(port
,"LPR:%s",name
);
1206 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1208 ERR("Can't create Printers key\n");
1213 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, ARRAY_SIZE(devnameW
));
1215 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1216 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1217 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1219 TRACE("Printer already exists\n");
1220 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1221 /* flag that the PPD file should be checked for an update */
1222 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1223 RegCloseKey(hkeyPrinter
);
1225 static CHAR data_type
[] = "RAW",
1226 print_proc
[] = "WinPrint",
1227 comment
[] = "WINEPS Printer using LPR",
1228 params
[] = "<parameters?>",
1229 share_name
[] = "<share name?>",
1230 sep_file
[] = "<sep file?>";
1231 BOOL added_driver
= FALSE
;
1233 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir())) goto end
;
1234 ppd
= get_ppd_filename( ppd_dir
, devnameW
);
1235 if (get_fallback_ppd( devname
, ppd
))
1237 added_driver
= add_printer_driver( devnameW
, ppd
);
1240 HeapFree( GetProcessHeap(), 0, ppd
);
1241 if (!added_driver
) goto end
;
1243 memset(&pinfo2a
,0,sizeof(pinfo2a
));
1244 pinfo2a
.pPrinterName
= devname
;
1245 pinfo2a
.pDatatype
= data_type
;
1246 pinfo2a
.pPrintProcessor
= print_proc
;
1247 pinfo2a
.pDriverName
= devname
;
1248 pinfo2a
.pComment
= comment
;
1249 pinfo2a
.pLocation
= prettyname
;
1250 pinfo2a
.pPortName
= port
;
1251 pinfo2a
.pParameters
= params
;
1252 pinfo2a
.pShareName
= share_name
;
1253 pinfo2a
.pSepFile
= sep_file
;
1255 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
1256 if (added_printer
) ClosePrinter( added_printer
);
1257 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1258 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
1261 if (isfirst
|| set_default
)
1262 set_default_printer(devname
, name
);
1265 if (hkeyPrinters
) RegCloseKey( hkeyPrinters
);
1268 RemoveDirectoryW( ppd_dir
);
1269 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1271 HeapFree(GetProcessHeap(), 0, port
);
1272 HeapFree(GetProcessHeap(), 0, name
);
1277 PRINTCAP_LoadPrinters(void) {
1278 BOOL hadprinter
= FALSE
;
1282 BOOL had_bash
= FALSE
;
1284 f
= fopen("/etc/printcap","r");
1288 while(fgets(buf
,sizeof(buf
),f
)) {
1291 end
=strchr(buf
,'\n');
1295 while(isspace(*start
)) start
++;
1296 if(*start
== '#' || *start
== '\0')
1299 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
1300 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1301 HeapFree(GetProcessHeap(),0,pent
);
1305 if (end
&& *--end
== '\\') {
1312 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
1315 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
1321 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1322 HeapFree(GetProcessHeap(),0,pent
);
1328 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
1331 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
1332 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
1334 return ERROR_FILE_NOT_FOUND
;
1337 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
1339 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
1340 DWORD ret
= ERROR_FILE_NOT_FOUND
;
1342 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1343 and we support these drivers. NT writes DEVMODEW so somehow
1344 we'll need to distinguish between these when we support NT
1349 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
1350 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1351 HeapFree( GetProcessHeap(), 0, dmA
);
1357 /******************************************************************
1358 * get_servername_from_name (internal)
1360 * for an external server, a copy of the serverpart from the full name is returned
1363 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1367 WCHAR buffer
[MAX_PATH
];
1370 if (name
== NULL
) return NULL
;
1371 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1373 server
= strdupW(&name
[2]); /* skip over both backslash */
1374 if (server
== NULL
) return NULL
;
1376 /* strip '\' and the printername */
1377 ptr
= strchrW(server
, '\\');
1378 if (ptr
) ptr
[0] = '\0';
1380 TRACE("found %s\n", debugstr_w(server
));
1382 len
= ARRAY_SIZE(buffer
);
1383 if (GetComputerNameW(buffer
, &len
)) {
1384 if (lstrcmpW(buffer
, server
) == 0) {
1385 /* The requested Servername is our computername */
1386 HeapFree(GetProcessHeap(), 0, server
);
1393 /******************************************************************
1394 * get_basename_from_name (internal)
1396 * skip over the serverpart from the full name
1399 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1401 if (name
== NULL
) return NULL
;
1402 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1403 /* skip over the servername and search for the following '\' */
1404 name
= strchrW(&name
[2], '\\');
1405 if ((name
) && (name
[1])) {
1406 /* found a separator ('\') followed by a name:
1407 skip over the separator and return the rest */
1412 /* no basename present (we found only a servername) */
1419 static void free_printer_entry( opened_printer_t
*printer
)
1421 /* the queue is shared, so don't free that here */
1422 HeapFree( GetProcessHeap(), 0, printer
->printername
);
1423 HeapFree( GetProcessHeap(), 0, printer
->name
);
1424 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
1425 HeapFree( GetProcessHeap(), 0, printer
);
1428 /******************************************************************
1429 * get_opened_printer_entry
1430 * Get the first place empty in the opened printer table
1433 * - pDefault is ignored
1435 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1437 UINT_PTR handle
= nb_printer_handles
, i
;
1438 jobqueue_t
*queue
= NULL
;
1439 opened_printer_t
*printer
= NULL
;
1441 LPCWSTR printername
;
1443 if ((backend
== NULL
) && !load_backend()) return NULL
;
1445 servername
= get_servername_from_name(name
);
1447 FIXME("server %s not supported\n", debugstr_w(servername
));
1448 HeapFree(GetProcessHeap(), 0, servername
);
1449 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1453 printername
= get_basename_from_name(name
);
1454 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1456 /* an empty printername is invalid */
1457 if (printername
&& (!printername
[0])) {
1458 SetLastError(ERROR_INVALID_PARAMETER
);
1462 EnterCriticalSection(&printer_handles_cs
);
1464 for (i
= 0; i
< nb_printer_handles
; i
++)
1466 if (!printer_handles
[i
])
1468 if(handle
== nb_printer_handles
)
1473 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1474 queue
= printer_handles
[i
]->queue
;
1478 if (handle
>= nb_printer_handles
)
1480 opened_printer_t
**new_array
;
1481 if (printer_handles
)
1482 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1483 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1485 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1486 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1493 printer_handles
= new_array
;
1494 nb_printer_handles
+= 16;
1497 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1503 /* get a printer handle from the backend */
1504 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1509 /* clone the base name. This is NULL for the printserver */
1510 printer
->printername
= strdupW(printername
);
1512 /* clone the full name */
1513 printer
->name
= strdupW(name
);
1514 if (name
&& (!printer
->name
)) {
1519 if (pDefault
&& pDefault
->pDevMode
)
1520 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
1523 printer
->queue
= queue
;
1526 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1527 if (!printer
->queue
) {
1531 list_init(&printer
->queue
->jobs
);
1532 printer
->queue
->ref
= 0;
1534 InterlockedIncrement(&printer
->queue
->ref
);
1536 printer_handles
[handle
] = printer
;
1539 LeaveCriticalSection(&printer_handles_cs
);
1540 if (!handle
&& printer
) {
1541 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1542 free_printer_entry( printer
);
1545 return (HANDLE
)handle
;
1548 static void old_printer_check( BOOL delete_phase
)
1550 PRINTER_INFO_5W
* pi
;
1551 DWORD needed
, type
, num
, delete, i
, size
;
1552 const DWORD one
= 1;
1556 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1557 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1559 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1560 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1561 for (i
= 0; i
< num
; i
++)
1563 if (!pi
[i
].pPortName
) continue;
1565 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1566 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1569 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1573 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1579 size
= sizeof( delete );
1580 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1584 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1585 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1587 DeletePrinter( hprn
);
1588 ClosePrinter( hprn
);
1590 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1594 HeapFree(GetProcessHeap(), 0, pi
);
1597 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1598 'M','U','T','E','X','_','_','\0'};
1599 static HANDLE init_mutex
;
1601 void WINSPOOL_LoadSystemPrinters(void)
1603 HKEY hkey
, hkeyPrinters
;
1604 DWORD needed
, num
, i
;
1605 WCHAR PrinterName
[256];
1608 #ifdef SONAME_LIBCUPS
1612 /* FIXME: The init code should be moved to spoolsv.exe */
1613 init_mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1616 ERR( "Failed to create mutex\n" );
1619 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1621 WaitForSingleObject( init_mutex
, INFINITE
);
1622 ReleaseMutex( init_mutex
);
1623 TRACE( "Init already done\n" );
1627 /* This ensures that all printer entries have a valid Name value. If causes
1628 problems later if they don't. If one is found to be missed we create one
1629 and set it equal to the name of the key */
1630 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1631 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1632 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1633 for(i
= 0; i
< num
; i
++) {
1634 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, ARRAY_SIZE(PrinterName
)) == ERROR_SUCCESS
) {
1635 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1636 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1637 set_reg_szW(hkey
, NameW
, PrinterName
);
1644 RegCloseKey(hkeyPrinters
);
1647 old_printer_check( FALSE
);
1649 #ifdef SONAME_LIBCUPS
1650 done
= CUPS_LoadPrinters();
1653 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1654 PRINTCAP_LoadPrinters();
1656 old_printer_check( TRUE
);
1658 ReleaseMutex( init_mutex
);
1662 /******************************************************************
1665 * Get the pointer to the specified job.
1666 * Should hold the printer_handles_cs before calling.
1668 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1670 opened_printer_t
*printer
= get_opened_printer(hprn
);
1673 if(!printer
) return NULL
;
1674 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1676 if(job
->job_id
== JobId
)
1682 /***********************************************************
1685 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1688 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1691 Formname
= (dmA
->dmSize
> off_formname
);
1692 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1693 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1694 dmW
->dmDeviceName
, CCHDEVICENAME
);
1696 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1697 dmA
->dmSize
- CCHDEVICENAME
);
1699 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1700 off_formname
- CCHDEVICENAME
);
1701 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1702 dmW
->dmFormName
, CCHFORMNAME
);
1703 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1704 (off_formname
+ CCHFORMNAME
));
1707 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1708 dmA
->dmDriverExtra
);
1712 /******************************************************************
1713 * convert_printerinfo_W_to_A [internal]
1716 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1717 DWORD level
, DWORD outlen
, DWORD numentries
)
1723 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1725 len
= pi_sizeof
[level
] * numentries
;
1726 ptr
= (LPSTR
) out
+ len
;
1729 /* copy the numbers of all PRINTER_INFO_* first */
1730 memcpy(out
, pPrintersW
, len
);
1732 while (id
< numentries
) {
1736 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1737 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1739 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1740 if (piW
->pDescription
) {
1741 piA
->pDescription
= ptr
;
1742 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1743 ptr
, outlen
, NULL
, NULL
);
1749 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1750 ptr
, outlen
, NULL
, NULL
);
1754 if (piW
->pComment
) {
1755 piA
->pComment
= ptr
;
1756 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1757 ptr
, outlen
, NULL
, NULL
);
1766 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1767 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1770 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1771 if (piW
->pServerName
) {
1772 piA
->pServerName
= ptr
;
1773 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1774 ptr
, outlen
, NULL
, NULL
);
1778 if (piW
->pPrinterName
) {
1779 piA
->pPrinterName
= ptr
;
1780 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1781 ptr
, outlen
, NULL
, NULL
);
1785 if (piW
->pShareName
) {
1786 piA
->pShareName
= ptr
;
1787 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1788 ptr
, outlen
, NULL
, NULL
);
1792 if (piW
->pPortName
) {
1793 piA
->pPortName
= ptr
;
1794 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1795 ptr
, outlen
, NULL
, NULL
);
1799 if (piW
->pDriverName
) {
1800 piA
->pDriverName
= ptr
;
1801 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1802 ptr
, outlen
, NULL
, NULL
);
1806 if (piW
->pComment
) {
1807 piA
->pComment
= ptr
;
1808 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1809 ptr
, outlen
, NULL
, NULL
);
1813 if (piW
->pLocation
) {
1814 piA
->pLocation
= ptr
;
1815 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1816 ptr
, outlen
, NULL
, NULL
);
1821 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1823 /* align DEVMODEA to a DWORD boundary */
1824 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1828 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1829 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1830 memcpy(ptr
, dmA
, len
);
1831 HeapFree(GetProcessHeap(), 0, dmA
);
1837 if (piW
->pSepFile
) {
1838 piA
->pSepFile
= ptr
;
1839 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1840 ptr
, outlen
, NULL
, NULL
);
1844 if (piW
->pPrintProcessor
) {
1845 piA
->pPrintProcessor
= ptr
;
1846 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1847 ptr
, outlen
, NULL
, NULL
);
1851 if (piW
->pDatatype
) {
1852 piA
->pDatatype
= ptr
;
1853 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1854 ptr
, outlen
, NULL
, NULL
);
1858 if (piW
->pParameters
) {
1859 piA
->pParameters
= ptr
;
1860 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1861 ptr
, outlen
, NULL
, NULL
);
1865 if (piW
->pSecurityDescriptor
) {
1866 piA
->pSecurityDescriptor
= NULL
;
1867 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1874 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1875 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1877 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1879 if (piW
->pPrinterName
) {
1880 piA
->pPrinterName
= ptr
;
1881 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1882 ptr
, outlen
, NULL
, NULL
);
1886 if (piW
->pServerName
) {
1887 piA
->pServerName
= ptr
;
1888 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1889 ptr
, outlen
, NULL
, NULL
);
1898 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1899 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1901 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1903 if (piW
->pPrinterName
) {
1904 piA
->pPrinterName
= ptr
;
1905 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1906 ptr
, outlen
, NULL
, NULL
);
1910 if (piW
->pPortName
) {
1911 piA
->pPortName
= ptr
;
1912 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1913 ptr
, outlen
, NULL
, NULL
);
1920 case 6: /* 6A and 6W are the same structure */
1925 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1926 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1928 TRACE("(%u) #%u\n", level
, id
);
1929 if (piW
->pszObjectGUID
) {
1930 piA
->pszObjectGUID
= ptr
;
1931 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1932 ptr
, outlen
, NULL
, NULL
);
1942 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1943 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1946 TRACE("(%u) #%u\n", level
, id
);
1947 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1949 /* align DEVMODEA to a DWORD boundary */
1950 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1954 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1955 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1956 memcpy(ptr
, dmA
, len
);
1957 HeapFree(GetProcessHeap(), 0, dmA
);
1967 FIXME("for level %u\n", level
);
1969 pPrintersW
+= pi_sizeof
[level
];
1970 out
+= pi_sizeof
[level
];
1975 /******************************************************************
1976 * convert_driverinfo_W_to_A [internal]
1979 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1980 DWORD level
, DWORD outlen
, DWORD numentries
)
1986 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1988 len
= di_sizeof
[level
] * numentries
;
1989 ptr
= (LPSTR
) out
+ len
;
1992 /* copy the numbers of all PRINTER_INFO_* first */
1993 memcpy(out
, pDriversW
, len
);
1995 #define COPY_STRING(fld) \
1998 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1999 ptr += len; outlen -= len;\
2001 #define COPY_MULTIZ_STRING(fld) \
2002 { LPWSTR p = diW->fld; if (p){ \
2005 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2006 ptr += len; outlen -= len; p += len;\
2008 while(len > 1 && outlen > 0); \
2011 while (id
< numentries
)
2017 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
2018 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
2020 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2027 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
2028 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
2030 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2033 COPY_STRING(pEnvironment
);
2034 COPY_STRING(pDriverPath
);
2035 COPY_STRING(pDataFile
);
2036 COPY_STRING(pConfigFile
);
2041 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
2042 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
2044 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2047 COPY_STRING(pEnvironment
);
2048 COPY_STRING(pDriverPath
);
2049 COPY_STRING(pDataFile
);
2050 COPY_STRING(pConfigFile
);
2051 COPY_STRING(pHelpFile
);
2052 COPY_MULTIZ_STRING(pDependentFiles
);
2053 COPY_STRING(pMonitorName
);
2054 COPY_STRING(pDefaultDataType
);
2059 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
2060 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
2062 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2065 COPY_STRING(pEnvironment
);
2066 COPY_STRING(pDriverPath
);
2067 COPY_STRING(pDataFile
);
2068 COPY_STRING(pConfigFile
);
2069 COPY_STRING(pHelpFile
);
2070 COPY_MULTIZ_STRING(pDependentFiles
);
2071 COPY_STRING(pMonitorName
);
2072 COPY_STRING(pDefaultDataType
);
2073 COPY_MULTIZ_STRING(pszzPreviousNames
);
2078 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
2079 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
2081 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2084 COPY_STRING(pEnvironment
);
2085 COPY_STRING(pDriverPath
);
2086 COPY_STRING(pDataFile
);
2087 COPY_STRING(pConfigFile
);
2092 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
2093 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
2095 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2098 COPY_STRING(pEnvironment
);
2099 COPY_STRING(pDriverPath
);
2100 COPY_STRING(pDataFile
);
2101 COPY_STRING(pConfigFile
);
2102 COPY_STRING(pHelpFile
);
2103 COPY_MULTIZ_STRING(pDependentFiles
);
2104 COPY_STRING(pMonitorName
);
2105 COPY_STRING(pDefaultDataType
);
2106 COPY_MULTIZ_STRING(pszzPreviousNames
);
2107 COPY_STRING(pszMfgName
);
2108 COPY_STRING(pszOEMUrl
);
2109 COPY_STRING(pszHardwareID
);
2110 COPY_STRING(pszProvider
);
2115 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
2116 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
2118 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2121 COPY_STRING(pEnvironment
);
2122 COPY_STRING(pDriverPath
);
2123 COPY_STRING(pDataFile
);
2124 COPY_STRING(pConfigFile
);
2125 COPY_STRING(pHelpFile
);
2126 COPY_MULTIZ_STRING(pDependentFiles
);
2127 COPY_STRING(pMonitorName
);
2128 COPY_STRING(pDefaultDataType
);
2129 COPY_MULTIZ_STRING(pszzPreviousNames
);
2130 COPY_STRING(pszMfgName
);
2131 COPY_STRING(pszOEMUrl
);
2132 COPY_STRING(pszHardwareID
);
2133 COPY_STRING(pszProvider
);
2134 COPY_STRING(pszPrintProcessor
);
2135 COPY_STRING(pszVendorSetup
);
2136 COPY_MULTIZ_STRING(pszzColorProfiles
);
2137 COPY_STRING(pszInfPath
);
2138 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
2144 FIXME("for level %u\n", level
);
2147 pDriversW
+= di_sizeof
[level
];
2148 out
+= di_sizeof
[level
];
2153 #undef COPY_MULTIZ_STRING
2157 /***********************************************************
2160 static void *printer_info_AtoW( const void *data
, DWORD level
)
2163 UNICODE_STRING usBuffer
;
2165 if (!data
) return NULL
;
2167 if (level
< 1 || level
> 9) return NULL
;
2169 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
2170 if (!ret
) return NULL
;
2172 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
2178 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
2179 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
2181 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
2182 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
2183 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
2184 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
2185 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
2186 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
2187 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
2188 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2189 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
2190 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
2191 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
2192 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
2199 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
2200 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
2202 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2207 FIXME( "Unhandled level %d\n", level
);
2208 HeapFree( GetProcessHeap(), 0, ret
);
2215 /***********************************************************
2218 static void free_printer_info( void *data
, DWORD level
)
2226 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
2228 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
2229 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
2230 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
2231 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
2232 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
2233 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
2234 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
2235 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2236 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
2237 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
2238 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
2239 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
2246 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
2248 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2253 FIXME( "Unhandled level %d\n", level
);
2256 HeapFree( GetProcessHeap(), 0, data
);
2260 /******************************************************************
2261 * DeviceCapabilities [WINSPOOL.@]
2262 * DeviceCapabilitiesA [WINSPOOL.@]
2265 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
2266 LPSTR pOutput
, LPDEVMODEA lpdm
)
2270 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice
), debugstr_a(pPort
), cap
, pOutput
, lpdm
);
2272 if (!GDI_CallDeviceCapabilities16
)
2274 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2276 if (!GDI_CallDeviceCapabilities16
) return -1;
2278 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
2280 /* If DC_PAPERSIZE map POINT16s to POINTs */
2281 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
2282 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
2283 POINT
*pt
= (POINT
*)pOutput
;
2285 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
2286 for(i
= 0; i
< ret
; i
++, pt
++)
2291 HeapFree( GetProcessHeap(), 0, tmp
);
2297 /*****************************************************************************
2298 * DeviceCapabilitiesW [WINSPOOL.@]
2300 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2303 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2304 WORD fwCapability
, LPWSTR pOutput
,
2305 const DEVMODEW
*pDevMode
)
2307 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
2308 LPSTR pDeviceA
= strdupWtoA(pDevice
);
2309 LPSTR pPortA
= strdupWtoA(pPort
);
2312 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice
), debugstr_w(pPort
), fwCapability
, pOutput
, pDevMode
);
2314 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
2315 fwCapability
== DC_FILEDEPENDENCIES
||
2316 fwCapability
== DC_PAPERNAMES
)) {
2317 /* These need A -> W translation */
2320 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2324 switch(fwCapability
) {
2329 case DC_FILEDEPENDENCIES
:
2333 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2334 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2336 for(i
= 0; i
< ret
; i
++)
2337 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2338 pOutput
+ (i
* size
), size
);
2339 HeapFree(GetProcessHeap(), 0, pOutputA
);
2341 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2342 (LPSTR
)pOutput
, dmA
);
2344 HeapFree(GetProcessHeap(),0,pPortA
);
2345 HeapFree(GetProcessHeap(),0,pDeviceA
);
2346 HeapFree(GetProcessHeap(),0,dmA
);
2350 /******************************************************************
2351 * DocumentPropertiesA [WINSPOOL.@]
2353 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2355 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2356 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2357 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2359 LPSTR lpName
= pDeviceName
, dupname
= NULL
;
2360 static CHAR port
[] = "LPT1:";
2363 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2364 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2367 if(!pDeviceName
|| !*pDeviceName
) {
2368 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2370 ERR("no name from hPrinter?\n");
2371 SetLastError(ERROR_INVALID_HANDLE
);
2374 lpName
= dupname
= strdupWtoA(lpNameW
);
2377 if (!GDI_CallExtDeviceMode16
)
2379 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2381 if (!GDI_CallExtDeviceMode16
) {
2382 ERR("No CallExtDeviceMode16?\n");
2387 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2388 pDevModeInput
, NULL
, fMode
);
2391 HeapFree(GetProcessHeap(), 0, dupname
);
2396 /*****************************************************************************
2397 * DocumentPropertiesW (WINSPOOL.@)
2399 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2401 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2403 LPDEVMODEW pDevModeOutput
,
2404 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2407 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2408 LPDEVMODEA pDevModeInputA
;
2409 LPDEVMODEA pDevModeOutputA
= NULL
;
2412 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2413 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2415 if(pDevModeOutput
) {
2416 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2417 if(ret
< 0) return ret
;
2418 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2420 pDevModeInputA
= (fMode
& DM_IN_BUFFER
) ? DEVMODEdupWtoA(pDevModeInput
) : NULL
;
2421 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2422 pDevModeInputA
, fMode
);
2423 if(pDevModeOutput
) {
2424 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2425 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2427 if(fMode
== 0 && ret
> 0)
2428 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2429 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2430 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2434 /*****************************************************************************
2435 * IsValidDevmodeA [WINSPOOL.@]
2437 * Validate a DEVMODE structure and fix errors if possible.
2440 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA pDevMode
, SIZE_T size
)
2442 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2450 /*****************************************************************************
2451 * IsValidDevmodeW [WINSPOOL.@]
2453 * Validate a DEVMODE structure and fix errors if possible.
2456 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW dm
, SIZE_T size
)
2464 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
2465 { DM_ORIENTATION
, F_SIZE(u1
.s1
.dmOrientation
) },
2466 { DM_PAPERSIZE
, F_SIZE(u1
.s1
.dmPaperSize
) },
2467 { DM_PAPERLENGTH
, F_SIZE(u1
.s1
.dmPaperLength
) },
2468 { DM_PAPERWIDTH
, F_SIZE(u1
.s1
.dmPaperWidth
) },
2469 { DM_SCALE
, F_SIZE(u1
.s1
.dmScale
) },
2470 { DM_COPIES
, F_SIZE(u1
.s1
.dmCopies
) },
2471 { DM_DEFAULTSOURCE
, F_SIZE(u1
.s1
.dmDefaultSource
) },
2472 { DM_PRINTQUALITY
, F_SIZE(u1
.s1
.dmPrintQuality
) },
2473 { DM_POSITION
, F_SIZE(u1
.s2
.dmPosition
) },
2474 { DM_DISPLAYORIENTATION
, F_SIZE(u1
.s2
.dmDisplayOrientation
) },
2475 { DM_DISPLAYFIXEDOUTPUT
, F_SIZE(u1
.s2
.dmDisplayFixedOutput
) },
2476 { DM_COLOR
, F_SIZE(dmColor
) },
2477 { DM_DUPLEX
, F_SIZE(dmDuplex
) },
2478 { DM_YRESOLUTION
, F_SIZE(dmYResolution
) },
2479 { DM_TTOPTION
, F_SIZE(dmTTOption
) },
2480 { DM_COLLATE
, F_SIZE(dmCollate
) },
2481 { DM_FORMNAME
, F_SIZE(dmFormName
) },
2482 { DM_LOGPIXELS
, F_SIZE(dmLogPixels
) },
2483 { DM_BITSPERPEL
, F_SIZE(dmBitsPerPel
) },
2484 { DM_PELSWIDTH
, F_SIZE(dmPelsWidth
) },
2485 { DM_PELSHEIGHT
, F_SIZE(dmPelsHeight
) },
2486 { DM_DISPLAYFLAGS
, F_SIZE(u2
.dmDisplayFlags
) },
2487 { DM_NUP
, F_SIZE(u2
.dmNup
) },
2488 { DM_DISPLAYFREQUENCY
, F_SIZE(dmDisplayFrequency
) },
2489 { DM_ICMMETHOD
, F_SIZE(dmICMMethod
) },
2490 { DM_ICMINTENT
, F_SIZE(dmICMIntent
) },
2491 { DM_MEDIATYPE
, F_SIZE(dmMediaType
) },
2492 { DM_DITHERTYPE
, F_SIZE(dmDitherType
) },
2493 { DM_PANNINGWIDTH
, F_SIZE(dmPanningWidth
) },
2494 { DM_PANNINGHEIGHT
, F_SIZE(dmPanningHeight
) }
2499 if (!dm
) return FALSE
;
2500 if (size
< FIELD_OFFSET(DEVMODEW
, dmFields
) + sizeof(dm
->dmFields
)) return FALSE
;
2502 for (i
= 0; i
< ARRAY_SIZE(map
); i
++)
2503 if ((dm
->dmFields
& map
[i
].flag
) && size
< map
[i
].size
)
2509 /******************************************************************
2510 * OpenPrinterA [WINSPOOL.@]
2515 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2516 LPPRINTER_DEFAULTSA pDefault
)
2518 UNICODE_STRING lpPrinterNameW
;
2519 UNICODE_STRING usBuffer
;
2520 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2521 PWSTR pwstrPrinterNameW
;
2524 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName
), phPrinter
, pDefault
);
2526 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2529 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2530 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2531 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2532 pDefaultW
= &DefaultW
;
2534 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2536 RtlFreeUnicodeString(&usBuffer
);
2537 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2539 RtlFreeUnicodeString(&lpPrinterNameW
);
2543 /******************************************************************
2544 * OpenPrinterW [WINSPOOL.@]
2546 * Open a Printer / Printserver or a Printer-Object
2549 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2550 * phPrinter [O] The resulting Handle is stored here
2551 * pDefault [I] PTR to Default Printer Settings or NULL
2558 * lpPrinterName is one of:
2559 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2560 *| Printer: "PrinterName"
2561 *| Printer-Object: "PrinterName,Job xxx"
2562 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2563 *| XcvPort: "Servername,XcvPort PortName"
2566 *| Printer-Object not supported
2567 *| pDefaults is ignored
2570 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2574 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2577 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2578 SetLastError(ERROR_INVALID_PARAMETER
);
2582 /* Get the unique handle of the printer or Printserver */
2583 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2585 if (*phPrinter
&& WINSPOOL_GetOpenedPrinterRegKey( *phPrinter
, &key
) == ERROR_SUCCESS
)
2587 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2589 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2590 WaitForSingleObject( init_mutex
, INFINITE
);
2591 status
= get_dword_from_reg( key
, StatusW
);
2592 set_reg_DWORD( key
, StatusW
, status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2593 ReleaseMutex( init_mutex
);
2594 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2595 update_driver( *phPrinter
);
2599 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2600 return (*phPrinter
!= 0);
2603 /******************************************************************
2604 * AddMonitorA [WINSPOOL.@]
2609 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2611 LPWSTR nameW
= NULL
;
2614 LPMONITOR_INFO_2A mi2a
;
2615 MONITOR_INFO_2W mi2w
;
2617 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2618 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2619 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2620 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2621 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2624 SetLastError(ERROR_INVALID_LEVEL
);
2628 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2634 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2635 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2636 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2639 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2641 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2642 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2643 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2645 if (mi2a
->pEnvironment
) {
2646 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2647 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2648 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2650 if (mi2a
->pDLLName
) {
2651 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2652 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2653 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2656 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2658 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2659 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2660 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2662 HeapFree(GetProcessHeap(), 0, nameW
);
2666 /******************************************************************************
2667 * AddMonitorW [WINSPOOL.@]
2669 * Install a Printmonitor
2672 * pName [I] Servername or NULL (local Computer)
2673 * Level [I] Structure-Level (Must be 2)
2674 * pMonitors [I] PTR to MONITOR_INFO_2
2681 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2684 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2686 LPMONITOR_INFO_2W mi2w
;
2688 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2689 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2690 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2691 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2692 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2694 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2697 SetLastError(ERROR_INVALID_LEVEL
);
2701 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2706 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2709 /******************************************************************
2710 * DeletePrinterDriverA [WINSPOOL.@]
2713 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2715 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2718 /******************************************************************
2719 * DeletePrinterDriverW [WINSPOOL.@]
2722 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2724 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2727 /******************************************************************
2728 * DeleteMonitorA [WINSPOOL.@]
2730 * See DeleteMonitorW.
2733 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2735 LPWSTR nameW
= NULL
;
2736 LPWSTR EnvironmentW
= NULL
;
2737 LPWSTR MonitorNameW
= NULL
;
2742 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2743 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2744 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2748 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2749 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2750 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2753 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2754 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2755 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2758 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2760 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2761 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2762 HeapFree(GetProcessHeap(), 0, nameW
);
2766 /******************************************************************
2767 * DeleteMonitorW [WINSPOOL.@]
2769 * Delete a specific Printmonitor from a Printing-Environment
2772 * pName [I] Servername or NULL (local Computer)
2773 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2774 * pMonitorName [I] Name of the Monitor, that should be deleted
2781 * pEnvironment is ignored in Windows for the local Computer.
2784 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2787 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2788 debugstr_w(pMonitorName
));
2790 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2792 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2796 /******************************************************************
2797 * DeletePortA [WINSPOOL.@]
2802 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2804 LPWSTR nameW
= NULL
;
2805 LPWSTR portW
= NULL
;
2809 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2811 /* convert servername to unicode */
2813 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2814 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2815 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2818 /* convert portname to unicode */
2820 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2821 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2822 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2825 res
= DeletePortW(nameW
, hWnd
, portW
);
2826 HeapFree(GetProcessHeap(), 0, nameW
);
2827 HeapFree(GetProcessHeap(), 0, portW
);
2831 /******************************************************************
2832 * DeletePortW [WINSPOOL.@]
2834 * Delete a specific Port
2837 * pName [I] Servername or NULL (local Computer)
2838 * hWnd [I] Handle to parent Window for the Dialog-Box
2839 * pPortName [I] Name of the Port, that should be deleted
2846 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2848 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2850 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2853 SetLastError(RPC_X_NULL_REF_POINTER
);
2857 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2860 /******************************************************************************
2861 * WritePrinter [WINSPOOL.@]
2863 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2865 opened_printer_t
*printer
;
2868 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2870 EnterCriticalSection(&printer_handles_cs
);
2871 printer
= get_opened_printer(hPrinter
);
2874 SetLastError(ERROR_INVALID_HANDLE
);
2880 SetLastError(ERROR_SPL_NO_STARTDOC
);
2884 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2886 LeaveCriticalSection(&printer_handles_cs
);
2890 /*****************************************************************************
2891 * AddFormA [WINSPOOL.@]
2893 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2895 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2899 /*****************************************************************************
2900 * AddFormW [WINSPOOL.@]
2902 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2904 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2908 /*****************************************************************************
2909 * AddJobA [WINSPOOL.@]
2911 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2914 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2918 SetLastError(ERROR_INVALID_LEVEL
);
2922 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2925 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2926 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2927 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2928 if(*pcbNeeded
> cbBuf
) {
2929 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2932 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2933 addjobA
->JobId
= addjobW
->JobId
;
2934 addjobA
->Path
= (char *)(addjobA
+ 1);
2935 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2941 /*****************************************************************************
2942 * AddJobW [WINSPOOL.@]
2944 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2946 opened_printer_t
*printer
;
2949 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2950 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2951 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2953 ADDJOB_INFO_1W
*addjob
;
2955 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2957 EnterCriticalSection(&printer_handles_cs
);
2959 printer
= get_opened_printer(hPrinter
);
2962 SetLastError(ERROR_INVALID_HANDLE
);
2967 SetLastError(ERROR_INVALID_LEVEL
);
2971 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2975 job
->job_id
= InterlockedIncrement(&next_job_id
);
2977 len
= GetSystemDirectoryW(path
, ARRAY_SIZE(path
));
2978 if(path
[len
- 1] != '\\')
2980 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2981 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2983 len
= strlenW(filename
);
2984 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2985 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2986 job
->portname
= NULL
;
2987 job
->document_title
= strdupW(default_doc_title
);
2988 job
->printer_name
= strdupW(printer
->name
);
2989 job
->devmode
= dup_devmode( printer
->devmode
);
2990 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2992 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2993 if(*pcbNeeded
<= cbBuf
) {
2994 addjob
= (ADDJOB_INFO_1W
*)pData
;
2995 addjob
->JobId
= job
->job_id
;
2996 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2997 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
3000 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3003 LeaveCriticalSection(&printer_handles_cs
);
3007 /*****************************************************************************
3008 * GetPrintProcessorDirectoryA [WINSPOOL.@]
3010 * Return the PATH for the Print-Processors
3012 * See GetPrintProcessorDirectoryW.
3016 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
3017 DWORD level
, LPBYTE Info
,
3018 DWORD cbBuf
, LPDWORD pcbNeeded
)
3020 LPWSTR serverW
= NULL
;
3025 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
3026 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
3030 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
3031 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3032 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
3036 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
3037 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3038 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
3041 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3042 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3044 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
3047 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
3048 cbBuf
, NULL
, NULL
) > 0;
3051 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
3052 HeapFree(GetProcessHeap(), 0, envW
);
3053 HeapFree(GetProcessHeap(), 0, serverW
);
3057 /*****************************************************************************
3058 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3060 * Return the PATH for the Print-Processors
3063 * server [I] Servername (NT only) or NULL (local Computer)
3064 * env [I] Printing-Environment (see below) or NULL (Default)
3065 * level [I] Structure-Level (must be 1)
3066 * Info [O] PTR to Buffer that receives the Result
3067 * cbBuf [I] Size of Buffer at "Info"
3068 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3069 * required for the Buffer at "Info"
3072 * Success: TRUE and in pcbNeeded the Bytes used in Info
3073 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3074 * if cbBuf is too small
3076 * Native Values returned in Info on Success:
3077 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3078 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3079 *| win9x(Windows 4.0): "%winsysdir%"
3081 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3084 * Only NULL or "" is supported for server
3087 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
3088 DWORD level
, LPBYTE Info
,
3089 DWORD cbBuf
, LPDWORD pcbNeeded
)
3092 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
3093 Info
, cbBuf
, pcbNeeded
);
3095 if ((backend
== NULL
) && !load_backend()) return FALSE
;
3098 /* (Level != 1) is ignored in win9x */
3099 SetLastError(ERROR_INVALID_LEVEL
);
3103 if (pcbNeeded
== NULL
) {
3104 /* (pcbNeeded == NULL) is ignored in win9x */
3105 SetLastError(RPC_X_NULL_REF_POINTER
);
3109 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
3112 /*****************************************************************************
3113 * WINSPOOL_OpenDriverReg [internal]
3115 * opens the registry for the printer drivers depending on the given input
3116 * variable pEnvironment
3119 * the opened hkey on success
3122 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
3126 const printenv_t
* env
;
3128 TRACE("(%s)\n", debugstr_w(pEnvironment
));
3130 env
= validate_envW(pEnvironment
);
3131 if (!env
) return NULL
;
3133 buffer
= HeapAlloc( GetProcessHeap(), 0,
3134 (strlenW(DriversW
) + strlenW(env
->envname
) +
3135 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
3137 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
3138 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
3139 HeapFree(GetProcessHeap(), 0, buffer
);
3144 /*****************************************************************************
3145 * set_devices_and_printerports [internal]
3147 * set the [Devices] and [PrinterPorts] entries for a printer.
3150 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
3152 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
3156 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
3158 /* FIXME: the driver must change to "winspool" */
3159 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
3161 lstrcpyW(devline
, driver_nt
);
3162 lstrcatW(devline
, commaW
);
3163 lstrcatW(devline
, pi
->pPortName
);
3165 TRACE("using %s\n", debugstr_w(devline
));
3166 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
3167 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3168 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3172 lstrcatW(devline
, timeout_15_45
);
3173 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
3174 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3175 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3178 HeapFree(GetProcessHeap(), 0, devline
);
3182 /*****************************************************************************
3183 * AddPrinterW [WINSPOOL.@]
3185 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3187 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
3190 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
3193 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
3195 if(pName
&& *pName
) {
3196 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
3197 SetLastError(ERROR_INVALID_PARAMETER
);
3201 ERR("Level = %d, unsupported!\n", Level
);
3202 SetLastError(ERROR_INVALID_LEVEL
);
3206 SetLastError(ERROR_INVALID_PARAMETER
);
3209 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3211 ERR("Can't create Printers key\n");
3214 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3215 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
3216 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3217 RegCloseKey(hkeyPrinter
);
3218 RegCloseKey(hkeyPrinters
);
3221 RegCloseKey(hkeyPrinter
);
3223 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
3225 ERR("Can't create Drivers key\n");
3226 RegCloseKey(hkeyPrinters
);
3229 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3231 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3232 RegCloseKey(hkeyPrinters
);
3233 RegCloseKey(hkeyDrivers
);
3234 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3237 RegCloseKey(hkeyDriver
);
3238 RegCloseKey(hkeyDrivers
);
3240 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3241 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3242 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3243 RegCloseKey(hkeyPrinters
);
3247 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3249 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3250 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3251 RegCloseKey(hkeyPrinters
);
3255 set_devices_and_printerports(pi
);
3257 set_reg_DWORD(hkeyPrinter
, AttributesW
, pi
->Attributes
);
3258 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3259 set_reg_DWORD(hkeyPrinter
, Default_PriorityW
, pi
->DefaultPriority
);
3260 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3261 set_reg_DWORD(hkeyPrinter
, dnsTimeoutW
, 0);
3262 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3263 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3264 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3265 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3266 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3267 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3268 set_reg_DWORD(hkeyPrinter
, PriorityW
, pi
->Priority
);
3269 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3270 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3271 set_reg_DWORD(hkeyPrinter
, StartTimeW
, pi
->StartTime
);
3272 set_reg_DWORD(hkeyPrinter
, StatusW
, pi
->Status
);
3273 set_reg_DWORD(hkeyPrinter
, txTimeoutW
, 0);
3274 set_reg_DWORD(hkeyPrinter
, UntilTimeW
, pi
->UntilTime
);
3276 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3280 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3281 size
= sizeof(DEVMODEW
);
3287 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3289 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
3291 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3292 HeapFree( GetProcessHeap(), 0, dm
);
3297 /* set devmode to printer name */
3298 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3302 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
3303 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
3305 RegCloseKey(hkeyPrinter
);
3306 RegCloseKey(hkeyPrinters
);
3307 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3308 ERR("OpenPrinter failing\n");
3314 /*****************************************************************************
3315 * AddPrinterA [WINSPOOL.@]
3317 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3319 UNICODE_STRING pNameW
;
3321 PRINTER_INFO_2W
*piW
;
3322 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3325 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
3327 ERR("Level = %d, unsupported!\n", Level
);
3328 SetLastError(ERROR_INVALID_LEVEL
);
3331 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3332 piW
= printer_info_AtoW( piA
, Level
);
3334 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3336 free_printer_info( piW
, Level
);
3337 RtlFreeUnicodeString(&pNameW
);
3342 /*****************************************************************************
3343 * ClosePrinter [WINSPOOL.@]
3345 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3347 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3348 opened_printer_t
*printer
= NULL
;
3350 TRACE("(%p)\n", hPrinter
);
3352 EnterCriticalSection(&printer_handles_cs
);
3354 if ((i
> 0) && (i
<= nb_printer_handles
))
3355 printer
= printer_handles
[i
- 1];
3360 struct list
*cursor
, *cursor2
;
3362 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
3365 EndDocPrinter(hPrinter
);
3367 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3369 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3371 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3372 ScheduleJob(hPrinter
, job
->job_id
);
3374 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3377 if (printer
->backend_printer
) {
3378 backend
->fpClosePrinter(printer
->backend_printer
);
3381 free_printer_entry( printer
);
3382 printer_handles
[i
- 1] = NULL
;
3383 LeaveCriticalSection(&printer_handles_cs
);
3387 LeaveCriticalSection(&printer_handles_cs
);
3388 SetLastError(ERROR_INVALID_HANDLE
);
3392 /*****************************************************************************
3393 * DeleteFormA [WINSPOOL.@]
3395 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3397 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3401 /*****************************************************************************
3402 * DeleteFormW [WINSPOOL.@]
3404 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3406 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3410 /*****************************************************************************
3411 * DeletePrinter [WINSPOOL.@]
3413 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3415 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3416 HKEY hkeyPrinters
, hkey
;
3417 WCHAR def
[MAX_PATH
];
3418 DWORD size
= ARRAY_SIZE(def
);
3421 SetLastError(ERROR_INVALID_HANDLE
);
3424 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3425 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3426 RegCloseKey(hkeyPrinters
);
3429 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3430 RegDeleteValueW(hkey
, lpNameW
);
3434 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3435 RegDeleteValueW(hkey
, lpNameW
);
3439 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
3441 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
3443 RegDeleteValueW( hkey
, deviceW
);
3444 RegCloseKey( hkey
);
3446 SetDefaultPrinterW( NULL
);
3452 /*****************************************************************************
3453 * SetPrinterA [WINSPOOL.@]
3455 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3462 dataW
= printer_info_AtoW( data
, level
);
3463 if (!dataW
) return FALSE
;
3466 ret
= SetPrinterW( printer
, level
, dataW
, command
);
3468 if (dataW
!= data
) free_printer_info( dataW
, level
);
3473 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
3475 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
3476 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
3477 set_reg_szW( key
, PortW
, pi
->pPortName
);
3478 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
3479 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
3480 set_reg_szW( key
, LocationW
, pi
->pLocation
);
3483 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3485 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
3486 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
3487 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
3488 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
3490 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
3491 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
3492 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
3493 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
3494 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
3497 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
3499 if (!pi
->pDevMode
) return FALSE
;
3501 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3505 /******************************************************************************
3506 * SetPrinterW [WINSPOOL.@]
3508 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3513 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
3515 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
3517 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
3524 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
3525 set_printer_2( key
, pi2
);
3531 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3532 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3536 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
3537 ret
= set_printer_9( key
, pi
);
3542 FIXME( "Unimplemented level %d\n", level
);
3543 SetLastError( ERROR_INVALID_LEVEL
);
3550 /*****************************************************************************
3551 * SetJobA [WINSPOOL.@]
3553 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3554 LPBYTE pJob
, DWORD Command
)
3558 UNICODE_STRING usBuffer
;
3560 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3562 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3563 are all ignored by SetJob, so we don't bother copying them */
3571 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3572 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3574 JobW
= (LPBYTE
)info1W
;
3575 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3576 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3577 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3578 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3579 info1W
->Status
= info1A
->Status
;
3580 info1W
->Priority
= info1A
->Priority
;
3581 info1W
->Position
= info1A
->Position
;
3582 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3587 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3588 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3590 JobW
= (LPBYTE
)info2W
;
3591 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3592 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3593 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3594 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3595 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3596 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3597 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3598 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3599 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3600 info2W
->Status
= info2A
->Status
;
3601 info2W
->Priority
= info2A
->Priority
;
3602 info2W
->Position
= info2A
->Position
;
3603 info2W
->StartTime
= info2A
->StartTime
;
3604 info2W
->UntilTime
= info2A
->UntilTime
;
3605 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3609 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3610 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3613 SetLastError(ERROR_INVALID_LEVEL
);
3617 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3623 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3624 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3625 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3626 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3627 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3632 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3633 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3634 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3635 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3636 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3637 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3638 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3639 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3640 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3644 HeapFree(GetProcessHeap(), 0, JobW
);
3649 /*****************************************************************************
3650 * SetJobW [WINSPOOL.@]
3652 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3653 LPBYTE pJob
, DWORD Command
)
3658 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3659 FIXME("Ignoring everything other than document title\n");
3661 EnterCriticalSection(&printer_handles_cs
);
3662 job
= get_job(hPrinter
, JobId
);
3672 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3673 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3674 job
->document_title
= strdupW(info1
->pDocument
);
3679 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3680 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3681 job
->document_title
= strdupW(info2
->pDocument
);
3682 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3683 job
->devmode
= dup_devmode( info2
->pDevMode
);
3689 SetLastError(ERROR_INVALID_LEVEL
);
3694 LeaveCriticalSection(&printer_handles_cs
);
3698 /*****************************************************************************
3699 * EndDocPrinter [WINSPOOL.@]
3701 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3703 opened_printer_t
*printer
;
3705 TRACE("(%p)\n", hPrinter
);
3707 EnterCriticalSection(&printer_handles_cs
);
3709 printer
= get_opened_printer(hPrinter
);
3712 SetLastError(ERROR_INVALID_HANDLE
);
3718 SetLastError(ERROR_SPL_NO_STARTDOC
);
3722 CloseHandle(printer
->doc
->hf
);
3723 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3724 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3725 printer
->doc
= NULL
;
3728 LeaveCriticalSection(&printer_handles_cs
);
3732 /*****************************************************************************
3733 * EndPagePrinter [WINSPOOL.@]
3735 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3737 FIXME("(%p): stub\n", hPrinter
);
3741 /*****************************************************************************
3742 * StartDocPrinterA [WINSPOOL.@]
3744 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3746 UNICODE_STRING usBuffer
;
3748 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3751 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3752 or one (DOC_INFO_3) extra DWORDs */
3756 doc2W
.JobId
= doc2
->JobId
;
3759 doc2W
.dwMode
= doc2
->dwMode
;
3762 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3763 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3764 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3768 SetLastError(ERROR_INVALID_LEVEL
);
3772 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3774 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3775 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3776 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3781 /*****************************************************************************
3782 * StartDocPrinterW [WINSPOOL.@]
3784 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3786 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3787 opened_printer_t
*printer
;
3788 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3789 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3790 JOB_INFO_1W job_info
;
3791 DWORD needed
, ret
= 0;
3796 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3797 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3798 debugstr_w(doc
->pDatatype
));
3800 if(Level
< 1 || Level
> 3)
3802 SetLastError(ERROR_INVALID_LEVEL
);
3806 EnterCriticalSection(&printer_handles_cs
);
3807 printer
= get_opened_printer(hPrinter
);
3810 SetLastError(ERROR_INVALID_HANDLE
);
3816 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3820 /* Even if we're printing to a file we still add a print job, we'll
3821 just ignore the spool file name */
3823 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3825 ERR("AddJob failed gle %u\n", GetLastError());
3829 /* use pOutputFile only, when it is a real filename */
3830 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3831 filename
= doc
->pOutputFile
;
3833 filename
= addjob
->Path
;
3835 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3836 if(hf
== INVALID_HANDLE_VALUE
)
3839 memset(&job_info
, 0, sizeof(job_info
));
3840 job_info
.pDocument
= doc
->pDocName
;
3841 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3843 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3844 printer
->doc
->hf
= hf
;
3845 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3846 job
= get_job(hPrinter
, ret
);
3847 job
->portname
= strdupW(doc
->pOutputFile
);
3850 LeaveCriticalSection(&printer_handles_cs
);
3855 /*****************************************************************************
3856 * StartPagePrinter [WINSPOOL.@]
3858 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3860 FIXME("(%p): stub\n", hPrinter
);
3864 /*****************************************************************************
3865 * GetFormA [WINSPOOL.@]
3867 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3868 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3870 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3871 Level
,pForm
,cbBuf
,pcbNeeded
);
3875 /*****************************************************************************
3876 * GetFormW [WINSPOOL.@]
3878 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3879 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3881 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3882 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3886 /*****************************************************************************
3887 * SetFormA [WINSPOOL.@]
3889 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3892 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3896 /*****************************************************************************
3897 * SetFormW [WINSPOOL.@]
3899 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3902 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3906 /*****************************************************************************
3907 * ReadPrinter [WINSPOOL.@]
3909 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3910 LPDWORD pNoBytesRead
)
3912 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3916 /*****************************************************************************
3917 * ResetPrinterA [WINSPOOL.@]
3919 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3921 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3925 /*****************************************************************************
3926 * ResetPrinterW [WINSPOOL.@]
3928 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3930 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3934 /*****************************************************************************
3935 * get_filename_from_reg [internal]
3937 * Get ValueName from hkey storing result in out
3938 * when the Value in the registry has only a filename, use driverdir as prefix
3939 * outlen is space left in out
3940 * String is stored either as unicode or ascii
3944 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3945 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3947 WCHAR filename
[MAX_PATH
];
3951 LPWSTR buffer
= filename
;
3955 size
= sizeof(filename
);
3957 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3958 if (ret
== ERROR_MORE_DATA
) {
3959 TRACE("need dynamic buffer: %u\n", size
);
3960 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3962 /* No Memory is bad */
3966 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3969 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3970 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3976 /* do we have a full path ? */
3977 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3978 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3981 /* we must build the full Path */
3983 if ((out
) && (outlen
> dirlen
)) {
3984 lstrcpyW((LPWSTR
)out
, driverdir
);
3992 /* write the filename */
3993 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3994 if ((out
) && (outlen
>= size
)) {
3995 lstrcpyW((LPWSTR
)out
, ptr
);
4002 ptr
+= lstrlenW(ptr
)+1;
4003 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
4006 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
4008 /* write the multisz-termination */
4009 if (type
== REG_MULTI_SZ
) {
4010 size
= sizeof(WCHAR
);
4013 if (out
&& (outlen
>= size
)) {
4014 memset (out
, 0, size
);
4020 /*****************************************************************************
4021 * WINSPOOL_GetStringFromReg
4023 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4024 * String is stored as unicode.
4026 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
4027 DWORD buflen
, DWORD
*needed
)
4029 DWORD sz
= buflen
, type
;
4032 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4033 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
4034 WARN("Got ret = %d\n", ret
);
4038 /* add space for terminating '\0' */
4039 sz
+= sizeof(WCHAR
);
4043 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
4048 /*****************************************************************************
4049 * WINSPOOL_GetDefaultDevMode
4051 * Get a default DevMode values for wineps.
4053 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr
, DWORD buflen
, DWORD
*needed
)
4055 static const WCHAR winepsW
[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4057 if (buflen
>= sizeof(DEVMODEW
))
4059 DEVMODEW
*dm
= (DEVMODEW
*)ptr
;
4061 /* the driver will update registry with real values */
4062 memset(dm
, 0, sizeof(*dm
));
4063 dm
->dmSize
= sizeof(*dm
);
4064 lstrcpyW(dm
->dmDeviceName
, winepsW
);
4066 *needed
= sizeof(DEVMODEW
);
4069 /*****************************************************************************
4070 * WINSPOOL_GetDevModeFromReg
4072 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4073 * DevMode is stored either as unicode or ascii.
4075 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
4077 DWORD buflen
, DWORD
*needed
)
4079 DWORD sz
= buflen
, type
;
4082 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
4083 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4084 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
4085 if (sz
< sizeof(DEVMODEA
))
4087 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
4090 /* ensures that dmSize is not erratically bogus if registry is invalid */
4091 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
4092 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
4093 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
4094 if (ptr
&& (buflen
>= sz
)) {
4095 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
4096 memcpy(ptr
, dmW
, sz
);
4097 HeapFree(GetProcessHeap(),0,dmW
);
4103 /*********************************************************************
4104 * WINSPOOL_GetPrinter_1
4106 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4108 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
4109 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4111 DWORD size
, left
= cbBuf
;
4112 BOOL space
= (cbBuf
> 0);
4117 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4118 if(space
&& size
<= left
) {
4119 pi1
->pName
= (LPWSTR
)ptr
;
4127 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4128 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4129 if(space
&& size
<= left
) {
4130 pi1
->pDescription
= (LPWSTR
)ptr
;
4138 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4139 if(space
&& size
<= left
) {
4140 pi1
->pComment
= (LPWSTR
)ptr
;
4148 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
4150 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
4151 memset(pi1
, 0, sizeof(*pi1
));
4155 /*********************************************************************
4156 * WINSPOOL_GetPrinter_2
4158 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4160 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
4161 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4163 DWORD size
, left
= cbBuf
;
4164 BOOL space
= (cbBuf
> 0);
4169 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4170 if(space
&& size
<= left
) {
4171 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4178 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
4179 if(space
&& size
<= left
) {
4180 pi2
->pShareName
= (LPWSTR
)ptr
;
4187 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4188 if(space
&& size
<= left
) {
4189 pi2
->pPortName
= (LPWSTR
)ptr
;
4196 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
4197 if(space
&& size
<= left
) {
4198 pi2
->pDriverName
= (LPWSTR
)ptr
;
4205 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4206 if(space
&& size
<= left
) {
4207 pi2
->pComment
= (LPWSTR
)ptr
;
4214 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
4215 if(space
&& size
<= left
) {
4216 pi2
->pLocation
= (LPWSTR
)ptr
;
4223 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
4224 if(space
&& size
<= left
) {
4225 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4234 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
4235 if(space
&& size
<= left
) {
4236 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4243 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
4244 if(space
&& size
<= left
) {
4245 pi2
->pSepFile
= (LPWSTR
)ptr
;
4252 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
4253 if(space
&& size
<= left
) {
4254 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4261 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
4262 if(space
&& size
<= left
) {
4263 pi2
->pDatatype
= (LPWSTR
)ptr
;
4270 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
4271 if(space
&& size
<= left
) {
4272 pi2
->pParameters
= (LPWSTR
)ptr
;
4280 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4281 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
4282 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
4283 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
4284 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
4287 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4288 memset(pi2
, 0, sizeof(*pi2
));
4293 /*********************************************************************
4294 * WINSPOOL_GetPrinter_4
4296 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4298 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4299 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4301 DWORD size
, left
= cbBuf
;
4302 BOOL space
= (cbBuf
> 0);
4307 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4308 if(space
&& size
<= left
) {
4309 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4317 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4320 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4321 memset(pi4
, 0, sizeof(*pi4
));
4326 /*********************************************************************
4327 * WINSPOOL_GetPrinter_5
4329 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4331 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4332 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4334 DWORD size
, left
= cbBuf
;
4335 BOOL space
= (cbBuf
> 0);
4340 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4341 if(space
&& size
<= left
) {
4342 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4349 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4350 if(space
&& size
<= left
) {
4351 pi5
->pPortName
= (LPWSTR
)ptr
;
4359 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4360 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
4361 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
4364 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4365 memset(pi5
, 0, sizeof(*pi5
));
4370 /*********************************************************************
4371 * WINSPOOL_GetPrinter_7
4373 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4375 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4376 DWORD cbBuf
, LPDWORD pcbNeeded
)
4378 DWORD size
, left
= cbBuf
;
4379 BOOL space
= (cbBuf
> 0);
4384 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
4387 size
= sizeof(pi7
->pszObjectGUID
);
4389 if (space
&& size
<= left
) {
4390 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4397 /* We do not have a Directory Service */
4398 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4401 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4402 memset(pi7
, 0, sizeof(*pi7
));
4407 /*********************************************************************
4408 * WINSPOOL_GetPrinter_9
4410 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4412 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4413 DWORD cbBuf
, LPDWORD pcbNeeded
)
4416 BOOL space
= (cbBuf
> 0);
4420 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
4421 if(space
&& size
<= cbBuf
) {
4422 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4429 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
4430 if(space
&& size
<= cbBuf
) {
4431 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4437 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4438 memset(pi9
, 0, sizeof(*pi9
));
4443 /*****************************************************************************
4444 * GetPrinterW [WINSPOOL.@]
4446 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4447 DWORD cbBuf
, LPDWORD pcbNeeded
)
4449 DWORD size
, needed
= 0, err
;
4454 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4456 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
4459 SetLastError( err
);
4466 PRINTER_INFO_1W
*pi1
= (PRINTER_INFO_1W
*)pPrinter
;
4468 size
= sizeof(PRINTER_INFO_1W
);
4469 if (size
<= cbBuf
) {
4470 ptr
= pPrinter
+ size
;
4472 memset(pPrinter
, 0, size
);
4477 ret
= WINSPOOL_GetPrinter_1(hkeyPrinter
, pi1
, ptr
, cbBuf
, &needed
);
4484 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4486 size
= sizeof(PRINTER_INFO_2W
);
4488 ptr
= pPrinter
+ size
;
4490 memset(pPrinter
, 0, size
);
4495 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
4502 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4504 size
= sizeof(PRINTER_INFO_4W
);
4506 ptr
= pPrinter
+ size
;
4508 memset(pPrinter
, 0, size
);
4513 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
4521 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4523 size
= sizeof(PRINTER_INFO_5W
);
4525 ptr
= pPrinter
+ size
;
4527 memset(pPrinter
, 0, size
);
4533 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4541 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4543 size
= sizeof(PRINTER_INFO_6
);
4544 if (size
<= cbBuf
) {
4545 /* FIXME: We do not update the status yet */
4546 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4558 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4560 size
= sizeof(PRINTER_INFO_7W
);
4561 if (size
<= cbBuf
) {
4562 ptr
= pPrinter
+ size
;
4564 memset(pPrinter
, 0, size
);
4570 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4577 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4578 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4582 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4584 size
= sizeof(PRINTER_INFO_9W
);
4586 ptr
= pPrinter
+ size
;
4588 memset(pPrinter
, 0, size
);
4594 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4601 FIXME("Unimplemented level %d\n", Level
);
4602 SetLastError(ERROR_INVALID_LEVEL
);
4603 RegCloseKey(hkeyPrinter
);
4607 RegCloseKey(hkeyPrinter
);
4609 TRACE("returning %d needed = %d\n", ret
, needed
);
4610 if(pcbNeeded
) *pcbNeeded
= needed
;
4612 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4616 /*****************************************************************************
4617 * GetPrinterA [WINSPOOL.@]
4619 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4620 DWORD cbBuf
, LPDWORD pcbNeeded
)
4626 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4628 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4630 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4631 HeapFree(GetProcessHeap(), 0, buf
);
4636 /*****************************************************************************
4637 * WINSPOOL_EnumPrintersW
4639 * Implementation of EnumPrintersW
4641 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4642 DWORD dwLevel
, LPBYTE lpbPrinters
,
4643 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4644 LPDWORD lpdwReturned
)
4647 HKEY hkeyPrinters
, hkeyPrinter
;
4648 WCHAR PrinterName
[255];
4649 DWORD needed
= 0, number
= 0;
4650 DWORD used
, i
, left
;
4654 memset(lpbPrinters
, 0, cbBuf
);
4660 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4661 if(dwType
== PRINTER_ENUM_DEFAULT
)
4664 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4665 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4666 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4668 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4674 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4675 FIXME("dwType = %08x\n", dwType
);
4676 SetLastError(ERROR_INVALID_FLAGS
);
4680 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4682 ERR("Can't create Printers key\n");
4686 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4687 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4688 RegCloseKey(hkeyPrinters
);
4689 ERR("Can't query Printers key\n");
4692 TRACE("Found %d printers\n", number
);
4696 used
= number
* sizeof(PRINTER_INFO_1W
);
4699 used
= number
* sizeof(PRINTER_INFO_2W
);
4702 used
= number
* sizeof(PRINTER_INFO_4W
);
4705 used
= number
* sizeof(PRINTER_INFO_5W
);
4709 SetLastError(ERROR_INVALID_LEVEL
);
4710 RegCloseKey(hkeyPrinters
);
4713 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4715 for(i
= 0; i
< number
; i
++) {
4716 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, ARRAY_SIZE(PrinterName
)) != ERROR_SUCCESS
) {
4717 ERR("Can't enum key number %d\n", i
);
4718 RegCloseKey(hkeyPrinters
);
4721 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4722 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4724 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4725 RegCloseKey(hkeyPrinters
);
4730 buf
= lpbPrinters
+ used
;
4731 left
= cbBuf
- used
;
4739 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4742 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4745 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4748 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4751 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4754 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4757 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4760 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4763 ERR("Shouldn't be here!\n");
4764 RegCloseKey(hkeyPrinter
);
4765 RegCloseKey(hkeyPrinters
);
4768 RegCloseKey(hkeyPrinter
);
4770 RegCloseKey(hkeyPrinters
);
4777 memset(lpbPrinters
, 0, cbBuf
);
4778 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4782 *lpdwReturned
= number
;
4783 SetLastError(ERROR_SUCCESS
);
4788 /******************************************************************
4789 * EnumPrintersW [WINSPOOL.@]
4791 * Enumerates the available printers, print servers and print
4792 * providers, depending on the specified flags, name and level.
4796 * If level is set to 1:
4797 * Returns an array of PRINTER_INFO_1 data structures in the
4798 * lpbPrinters buffer.
4800 * If level is set to 2:
4801 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4802 * Returns an array of PRINTER_INFO_2 data structures in the
4803 * lpbPrinters buffer. Note that according to MSDN also an
4804 * OpenPrinter should be performed on every remote printer.
4806 * If level is set to 4 (officially WinNT only):
4807 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4808 * Fast: Only the registry is queried to retrieve printer names,
4809 * no connection to the driver is made.
4810 * Returns an array of PRINTER_INFO_4 data structures in the
4811 * lpbPrinters buffer.
4813 * If level is set to 5 (officially WinNT4/Win9x only):
4814 * Fast: Only the registry is queried to retrieve printer names,
4815 * no connection to the driver is made.
4816 * Returns an array of PRINTER_INFO_5 data structures in the
4817 * lpbPrinters buffer.
4819 * If level set to 3 or 6+:
4820 * returns zero (failure!)
4822 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4826 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4827 * - Only levels 2, 4 and 5 are implemented at the moment.
4828 * - 16-bit printer drivers are not enumerated.
4829 * - Returned amount of bytes used/needed does not match the real Windoze
4830 * implementation (as in this implementation, all strings are part
4831 * of the buffer, whereas Win32 keeps them somewhere else)
4832 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4835 * - In a regular Wine installation, no registry settings for printers
4836 * exist, which makes this function return an empty list.
4838 BOOL WINAPI
EnumPrintersW(
4839 DWORD dwType
, /* [in] Types of print objects to enumerate */
4840 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4841 DWORD dwLevel
, /* [in] type of printer info structure */
4842 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4843 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4844 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4845 LPDWORD lpdwReturned
/* [out] number of entries returned */
4848 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4849 lpdwNeeded
, lpdwReturned
);
4852 /******************************************************************
4853 * EnumPrintersA [WINSPOOL.@]
4858 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4859 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4862 UNICODE_STRING pNameU
;
4866 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4867 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4869 pNameW
= asciitounicode(&pNameU
, pName
);
4871 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4872 MS Office need this */
4873 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4875 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4877 RtlFreeUnicodeString(&pNameU
);
4879 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4881 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4885 /*****************************************************************************
4886 * WINSPOOL_GetDriverInfoFromReg [internal]
4888 * Enters the information from the registry into the DRIVER_INFO struct
4891 * zero if the printer driver does not exist in the registry
4892 * (only if Level > 1) otherwise nonzero
4894 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4897 const printenv_t
* env
,
4899 LPBYTE ptr
, /* DRIVER_INFO */
4900 LPBYTE pDriverStrings
, /* strings buffer */
4901 DWORD cbBuf
, /* size of string buffer */
4902 LPDWORD pcbNeeded
) /* space needed for str. */
4906 WCHAR driverdir
[MAX_PATH
];
4908 LPBYTE strPtr
= pDriverStrings
;
4909 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4911 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4912 debugstr_w(DriverName
), env
,
4913 Level
, di
, pDriverStrings
, cbBuf
);
4915 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4917 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4918 if (*pcbNeeded
<= cbBuf
)
4919 strcpyW((LPWSTR
)strPtr
, DriverName
);
4921 /* pName for level 1 has a different offset! */
4923 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4927 /* .cVersion and .pName for level > 1 */
4929 di
->cVersion
= env
->driverversion
;
4930 di
->pName
= (LPWSTR
) strPtr
;
4931 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4934 /* Reserve Space for the largest subdir and a Backslash*/
4935 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4936 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4937 /* Should never Fail */
4940 lstrcatW(driverdir
, env
->versionsubdir
);
4941 lstrcatW(driverdir
, backslashW
);
4943 /* dirlen must not include the terminating zero */
4944 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4946 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4947 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4948 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4953 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4956 if (*pcbNeeded
<= cbBuf
) {
4957 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4958 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4959 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4962 /* .pDriverPath is the Graphics rendering engine.
4963 The full Path is required to avoid a crash in some apps */
4964 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4966 if (*pcbNeeded
<= cbBuf
)
4967 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4969 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4970 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4973 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4974 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4976 if (*pcbNeeded
<= cbBuf
)
4977 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4979 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4980 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4983 /* .pConfigFile is the Driver user Interface */
4984 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4986 if (*pcbNeeded
<= cbBuf
)
4987 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4989 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4990 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4994 RegCloseKey(hkeyDriver
);
4995 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5000 RegCloseKey(hkeyDriver
);
5001 FIXME("level 5: incomplete\n");
5006 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
5008 if (*pcbNeeded
<= cbBuf
)
5009 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
5011 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
5012 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5015 /* .pDependentFiles */
5016 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
5018 if (*pcbNeeded
<= cbBuf
)
5019 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
5021 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
5022 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5024 else if (GetVersion() & 0x80000000) {
5025 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
5026 size
= 2 * sizeof(WCHAR
);
5028 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
5030 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
5031 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5034 /* .pMonitorName is the optional Language Monitor */
5035 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
5037 if (*pcbNeeded
<= cbBuf
)
5038 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
5040 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
5041 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5044 /* .pDefaultDataType */
5045 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
5047 if(*pcbNeeded
<= cbBuf
)
5048 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
5050 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
5051 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5055 RegCloseKey(hkeyDriver
);
5056 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5060 /* .pszzPreviousNames */
5061 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
5063 if(*pcbNeeded
<= cbBuf
)
5064 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
5066 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
5067 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5071 RegCloseKey(hkeyDriver
);
5072 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5076 /* support is missing, but not important enough for a FIXME */
5077 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
5080 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
5082 if(*pcbNeeded
<= cbBuf
)
5083 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
5085 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
5086 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5090 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
5092 if(*pcbNeeded
<= cbBuf
)
5093 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
5095 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
5096 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5099 /* .pszHardwareID */
5100 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
5102 if(*pcbNeeded
<= cbBuf
)
5103 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
5105 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
5106 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5110 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
5112 if(*pcbNeeded
<= cbBuf
)
5113 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
5115 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
5116 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5120 RegCloseKey(hkeyDriver
);
5124 /* support is missing, but not important enough for a FIXME */
5125 TRACE("level 8: incomplete\n");
5127 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5128 RegCloseKey(hkeyDriver
);
5132 /*****************************************************************************
5133 * GetPrinterDriverW [WINSPOOL.@]
5135 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5136 DWORD Level
, LPBYTE pDriverInfo
,
5137 DWORD cbBuf
, LPDWORD pcbNeeded
)
5140 WCHAR DriverName
[100];
5141 DWORD ret
, type
, size
, needed
= 0;
5143 HKEY hkeyPrinter
, hkeyDrivers
;
5144 const printenv_t
* env
;
5146 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
5147 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
5150 ZeroMemory(pDriverInfo
, cbBuf
);
5152 if (!(name
= get_opened_printer_name(hPrinter
))) {
5153 SetLastError(ERROR_INVALID_HANDLE
);
5157 if (Level
< 1 || Level
== 7 || Level
> 8) {
5158 SetLastError(ERROR_INVALID_LEVEL
);
5162 env
= validate_envW(pEnvironment
);
5163 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5165 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
5168 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
5169 SetLastError( ret
);
5173 size
= sizeof(DriverName
);
5175 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5176 (LPBYTE
)DriverName
, &size
);
5177 RegCloseKey(hkeyPrinter
);
5178 if(ret
!= ERROR_SUCCESS
) {
5179 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5183 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5185 ERR("Can't create Drivers key\n");
5189 size
= di_sizeof
[Level
];
5190 if ((size
<= cbBuf
) && pDriverInfo
)
5191 ptr
= pDriverInfo
+ size
;
5193 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5194 env
, Level
, pDriverInfo
, ptr
,
5195 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5197 RegCloseKey(hkeyDrivers
);
5201 RegCloseKey(hkeyDrivers
);
5203 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5204 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5205 if(cbBuf
>= size
+ needed
) return TRUE
;
5206 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5210 /*****************************************************************************
5211 * GetPrinterDriverA [WINSPOOL.@]
5213 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5214 DWORD Level
, LPBYTE pDriverInfo
,
5215 DWORD cbBuf
, LPDWORD pcbNeeded
)
5218 UNICODE_STRING pEnvW
;
5224 ZeroMemory(pDriverInfo
, cbBuf
);
5225 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5228 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5229 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5232 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5234 HeapFree(GetProcessHeap(), 0, buf
);
5236 RtlFreeUnicodeString(&pEnvW
);
5240 /*****************************************************************************
5241 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5243 * Return the PATH for the Printer-Drivers (UNICODE)
5246 * pName [I] Servername (NT only) or NULL (local Computer)
5247 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5248 * Level [I] Structure-Level (must be 1)
5249 * pDriverDirectory [O] PTR to Buffer that receives the Result
5250 * cbBuf [I] Size of Buffer at pDriverDirectory
5251 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5252 * required for pDriverDirectory
5255 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5256 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5257 * if cbBuf is too small
5259 * Native Values returned in pDriverDirectory on Success:
5260 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5261 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5262 *| win9x(Windows 4.0): "%winsysdir%"
5264 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5267 *- Only NULL or "" is supported for pName
5270 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5271 DWORD Level
, LPBYTE pDriverDirectory
,
5272 DWORD cbBuf
, LPDWORD pcbNeeded
)
5274 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5275 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5277 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5280 /* (Level != 1) is ignored in win9x */
5281 SetLastError(ERROR_INVALID_LEVEL
);
5284 if (pcbNeeded
== NULL
) {
5285 /* (pcbNeeded == NULL) is ignored in win9x */
5286 SetLastError(RPC_X_NULL_REF_POINTER
);
5290 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5291 pDriverDirectory
, cbBuf
, pcbNeeded
);
5296 /*****************************************************************************
5297 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5299 * Return the PATH for the Printer-Drivers (ANSI)
5301 * See GetPrinterDriverDirectoryW.
5304 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5307 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5308 DWORD Level
, LPBYTE pDriverDirectory
,
5309 DWORD cbBuf
, LPDWORD pcbNeeded
)
5311 UNICODE_STRING nameW
, environmentW
;
5314 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5315 WCHAR
*driverDirectoryW
= NULL
;
5317 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5318 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5320 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5322 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5323 else nameW
.Buffer
= NULL
;
5324 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5325 else environmentW
.Buffer
= NULL
;
5327 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5328 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5331 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5332 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5334 *pcbNeeded
= needed
;
5335 ret
= needed
<= cbBuf
;
5337 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5339 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5341 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5342 RtlFreeUnicodeString(&environmentW
);
5343 RtlFreeUnicodeString(&nameW
);
5348 /*****************************************************************************
5349 * AddPrinterDriverA [WINSPOOL.@]
5351 * See AddPrinterDriverW.
5354 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5356 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5357 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5360 /******************************************************************************
5361 * AddPrinterDriverW (WINSPOOL.@)
5363 * Install a Printer Driver
5366 * pName [I] Servername or NULL (local Computer)
5367 * level [I] Level for the supplied DRIVER_INFO_*W struct
5368 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5375 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5377 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5378 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5381 /*****************************************************************************
5382 * AddPrintProcessorA [WINSPOOL.@]
5384 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5385 LPSTR pPrintProcessorName
)
5387 UNICODE_STRING NameW
, EnvW
, PathW
, ProcessorW
;
5390 TRACE("(%s,%s,%s,%s)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5391 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5393 asciitounicode(&NameW
, pName
);
5394 asciitounicode(&EnvW
, pEnvironment
);
5395 asciitounicode(&PathW
, pPathName
);
5396 asciitounicode(&ProcessorW
, pPrintProcessorName
);
5398 ret
= AddPrintProcessorW(NameW
.Buffer
, EnvW
.Buffer
, PathW
.Buffer
, ProcessorW
.Buffer
);
5400 RtlFreeUnicodeString(&ProcessorW
);
5401 RtlFreeUnicodeString(&PathW
);
5402 RtlFreeUnicodeString(&EnvW
);
5403 RtlFreeUnicodeString(&NameW
);
5408 /*****************************************************************************
5409 * AddPrintProcessorW [WINSPOOL.@]
5411 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5412 LPWSTR pPrintProcessorName
)
5414 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5415 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5419 /*****************************************************************************
5420 * AddPrintProvidorA [WINSPOOL.@]
5422 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5424 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5428 /*****************************************************************************
5429 * AddPrintProvidorW [WINSPOOL.@]
5431 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5433 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5437 /*****************************************************************************
5438 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5440 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5441 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5443 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5444 pDevModeOutput
, pDevModeInput
);
5448 /*****************************************************************************
5449 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5451 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5452 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5454 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5455 pDevModeOutput
, pDevModeInput
);
5459 /*****************************************************************************
5460 * PrinterProperties [WINSPOOL.@]
5462 * Displays a dialog to set the properties of the printer.
5465 * nonzero on success or zero on failure
5468 * implemented as stub only
5470 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5471 HANDLE hPrinter
/* [in] handle to printer object */
5473 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5474 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5478 /*****************************************************************************
5479 * EnumJobsA [WINSPOOL.@]
5482 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5483 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5486 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5487 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5489 if(pcbNeeded
) *pcbNeeded
= 0;
5490 if(pcReturned
) *pcReturned
= 0;
5495 /*****************************************************************************
5496 * EnumJobsW [WINSPOOL.@]
5499 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5500 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5503 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5504 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5506 if(pcbNeeded
) *pcbNeeded
= 0;
5507 if(pcReturned
) *pcReturned
= 0;
5511 /*****************************************************************************
5512 * WINSPOOL_EnumPrinterDrivers [internal]
5514 * Delivers information about all printer drivers installed on the
5515 * localhost or a given server
5518 * nonzero on success or zero on failure. If the buffer for the returned
5519 * information is too small the function will return an error
5522 * - only implemented for localhost, foreign hosts will return an error
5524 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5525 DWORD Level
, LPBYTE pDriverInfo
,
5527 DWORD cbBuf
, LPDWORD pcbNeeded
,
5528 LPDWORD pcFound
, DWORD data_offset
)
5532 const printenv_t
* env
;
5534 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5535 debugstr_w(pName
), debugstr_w(pEnvironment
),
5536 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5538 env
= validate_envW(pEnvironment
);
5539 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5543 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5545 ERR("Can't open Drivers key\n");
5549 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5550 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5551 RegCloseKey(hkeyDrivers
);
5552 ERR("Can't query Drivers key\n");
5555 TRACE("Found %d Drivers\n", *pcFound
);
5557 /* get size of single struct
5558 * unicode and ascii structure have the same size
5560 size
= di_sizeof
[Level
];
5562 if (data_offset
== 0)
5563 data_offset
= size
* (*pcFound
);
5564 *pcbNeeded
= data_offset
;
5566 for( i
= 0; i
< *pcFound
; i
++) {
5567 WCHAR DriverNameW
[255];
5568 PBYTE table_ptr
= NULL
;
5569 PBYTE data_ptr
= NULL
;
5572 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, ARRAY_SIZE(DriverNameW
)) != ERROR_SUCCESS
) {
5573 ERR("Can't enum key number %d\n", i
);
5574 RegCloseKey(hkeyDrivers
);
5578 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5579 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5580 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5581 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5583 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5584 env
, Level
, table_ptr
, data_ptr
,
5585 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5587 RegCloseKey(hkeyDrivers
);
5591 *pcbNeeded
+= needed
;
5594 RegCloseKey(hkeyDrivers
);
5596 if(cbBuf
< *pcbNeeded
){
5597 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5604 /*****************************************************************************
5605 * EnumPrinterDriversW [WINSPOOL.@]
5607 * see function EnumPrinterDrivers for RETURNS, BUGS
5609 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5610 LPBYTE pDriverInfo
, DWORD cbBuf
,
5611 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5613 static const WCHAR allW
[] = {'a','l','l',0};
5617 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5619 SetLastError(RPC_X_NULL_REF_POINTER
);
5623 /* check for local drivers */
5624 if((pName
) && (pName
[0])) {
5625 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5626 SetLastError(ERROR_ACCESS_DENIED
);
5630 /* check input parameter */
5631 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5632 SetLastError(ERROR_INVALID_LEVEL
);
5636 if(pDriverInfo
&& cbBuf
> 0)
5637 memset( pDriverInfo
, 0, cbBuf
);
5639 /* Exception: pull all printers */
5640 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5642 DWORD i
, needed
, bufsize
= cbBuf
;
5643 DWORD total_found
= 0;
5646 /* Precompute the overall total; we need this to know
5647 where pointers end and data begins (i.e. data_offset) */
5648 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5651 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5652 NULL
, 0, 0, &needed
, &found
, 0);
5653 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5654 total_found
+= found
;
5657 data_offset
= di_sizeof
[Level
] * total_found
;
5662 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5665 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5666 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5667 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5669 *pcReturned
+= found
;
5670 *pcbNeeded
= needed
;
5671 data_offset
= needed
;
5672 total_found
+= found
;
5677 /* Normal behavior */
5678 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5679 0, cbBuf
, pcbNeeded
, &found
, 0);
5681 *pcReturned
= found
;
5686 /*****************************************************************************
5687 * EnumPrinterDriversA [WINSPOOL.@]
5689 * see function EnumPrinterDrivers for RETURNS, BUGS
5691 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5692 LPBYTE pDriverInfo
, DWORD cbBuf
,
5693 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5696 UNICODE_STRING pNameW
, pEnvironmentW
;
5697 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5701 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5703 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5704 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5706 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5707 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5709 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5711 HeapFree(GetProcessHeap(), 0, buf
);
5713 RtlFreeUnicodeString(&pNameW
);
5714 RtlFreeUnicodeString(&pEnvironmentW
);
5719 /******************************************************************************
5720 * EnumPortsA (WINSPOOL.@)
5725 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5726 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5729 LPBYTE bufferW
= NULL
;
5730 LPWSTR nameW
= NULL
;
5732 DWORD numentries
= 0;
5735 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5736 cbBuf
, pcbNeeded
, pcReturned
);
5738 /* convert servername to unicode */
5740 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5741 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5742 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5744 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5745 needed
= cbBuf
* sizeof(WCHAR
);
5746 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5747 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5749 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5750 if (pcbNeeded
) needed
= *pcbNeeded
;
5751 /* HeapReAlloc return NULL, when bufferW was NULL */
5752 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5753 HeapAlloc(GetProcessHeap(), 0, needed
);
5755 /* Try again with the large Buffer */
5756 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5758 needed
= pcbNeeded
? *pcbNeeded
: 0;
5759 numentries
= pcReturned
? *pcReturned
: 0;
5762 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5763 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5766 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5767 DWORD entrysize
= 0;
5770 LPPORT_INFO_2W pi2w
;
5771 LPPORT_INFO_2A pi2a
;
5774 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5776 /* First pass: calculate the size for all Entries */
5777 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5778 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5780 while (index
< numentries
) {
5782 needed
+= entrysize
; /* PORT_INFO_?A */
5783 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5785 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5786 NULL
, 0, NULL
, NULL
);
5788 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5789 NULL
, 0, NULL
, NULL
);
5790 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5791 NULL
, 0, NULL
, NULL
);
5793 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5794 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5795 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5798 /* check for errors and quit on failure */
5799 if (cbBuf
< needed
) {
5800 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5804 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5805 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5806 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5807 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5808 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5810 /* Second Pass: Fill the User Buffer (if we have one) */
5811 while ((index
< numentries
) && pPorts
) {
5813 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5814 pi2a
->pPortName
= ptr
;
5815 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5816 ptr
, cbBuf
, NULL
, NULL
);
5820 pi2a
->pMonitorName
= ptr
;
5821 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5822 ptr
, cbBuf
, NULL
, NULL
);
5826 pi2a
->pDescription
= ptr
;
5827 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5828 ptr
, cbBuf
, NULL
, NULL
);
5832 pi2a
->fPortType
= pi2w
->fPortType
;
5833 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5836 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5837 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5838 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5843 if (pcbNeeded
) *pcbNeeded
= needed
;
5844 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5846 HeapFree(GetProcessHeap(), 0, nameW
);
5847 HeapFree(GetProcessHeap(), 0, bufferW
);
5849 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5850 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5856 /******************************************************************************
5857 * EnumPortsW (WINSPOOL.@)
5859 * Enumerate available Ports
5862 * pName [I] Servername or NULL (local Computer)
5863 * Level [I] Structure-Level (1 or 2)
5864 * pPorts [O] PTR to Buffer that receives the Result
5865 * cbBuf [I] Size of Buffer at pPorts
5866 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5867 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5871 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5874 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5877 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5878 cbBuf
, pcbNeeded
, pcReturned
);
5880 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5882 /* Level is not checked in win9x */
5883 if (!Level
|| (Level
> 2)) {
5884 WARN("level (%d) is ignored in win9x\n", Level
);
5885 SetLastError(ERROR_INVALID_LEVEL
);
5888 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5889 SetLastError(RPC_X_NULL_REF_POINTER
);
5893 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5896 /******************************************************************************
5897 * GetDefaultPrinterW (WINSPOOL.@)
5900 * This function must read the value from data 'device' of key
5901 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5903 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5907 WCHAR
*buffer
, *ptr
;
5911 SetLastError(ERROR_INVALID_PARAMETER
);
5915 /* make the buffer big enough for the stuff from the profile/registry,
5916 * the content must fit into the local buffer to compute the correct
5917 * size even if the extern buffer is too small or not given.
5918 * (20 for ,driver,port) */
5920 len
= max(100, (insize
+ 20));
5921 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5923 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5925 SetLastError (ERROR_FILE_NOT_FOUND
);
5929 TRACE("%s\n", debugstr_w(buffer
));
5931 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5933 SetLastError(ERROR_INVALID_NAME
);
5939 *namesize
= strlenW(buffer
) + 1;
5940 if(!name
|| (*namesize
> insize
))
5942 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5946 strcpyW(name
, buffer
);
5949 HeapFree( GetProcessHeap(), 0, buffer
);
5954 /******************************************************************************
5955 * GetDefaultPrinterA (WINSPOOL.@)
5957 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5961 WCHAR
*bufferW
= NULL
;
5965 SetLastError(ERROR_INVALID_PARAMETER
);
5969 if(name
&& *namesize
) {
5971 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5974 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5979 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5983 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5986 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5989 HeapFree( GetProcessHeap(), 0, bufferW
);
5994 /******************************************************************************
5995 * SetDefaultPrinterW (WINSPOOL.204)
5997 * Set the Name of the Default Printer
6000 * pszPrinter [I] Name of the Printer or NULL
6007 * When the Parameter is NULL or points to an Empty String and
6008 * a Default Printer was already present, then this Function changes nothing.
6009 * Without a Default Printer and NULL (or an Empty String) as Parameter,
6010 * the First enumerated local Printer is used.
6013 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
6015 WCHAR default_printer
[MAX_PATH
];
6016 LPWSTR buffer
= NULL
;
6022 TRACE("(%s)\n", debugstr_w(pszPrinter
));
6023 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
6025 default_printer
[0] = '\0';
6026 size
= ARRAY_SIZE(default_printer
);
6028 /* if we have a default Printer, do nothing. */
6029 if (GetDefaultPrinterW(default_printer
, &size
))
6033 /* we have no default Printer: search local Printers and use the first */
6034 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
6036 default_printer
[0] = '\0';
6037 size
= ARRAY_SIZE(default_printer
);
6038 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
6040 pszPrinter
= default_printer
;
6041 TRACE("using %s\n", debugstr_w(pszPrinter
));
6046 if (pszPrinter
== NULL
) {
6047 TRACE("no local printer found\n");
6048 SetLastError(ERROR_FILE_NOT_FOUND
);
6053 /* "pszPrinter" is never empty or NULL here. */
6054 namelen
= lstrlenW(pszPrinter
);
6055 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
6056 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
6058 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
6059 HeapFree(GetProcessHeap(), 0, buffer
);
6060 SetLastError(ERROR_FILE_NOT_FOUND
);
6064 /* read the devices entry for the printer (driver,port) to build the string for the
6065 default device entry (printer,driver,port) */
6066 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
6067 buffer
[namelen
] = ',';
6068 namelen
++; /* move index to the start of the driver */
6070 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
6071 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
6075 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
))
6077 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (BYTE
*)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
6083 if (lres
!= ERROR_FILE_NOT_FOUND
)
6084 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
6086 SetLastError(ERROR_INVALID_PRINTER_NAME
);
6090 HeapFree(GetProcessHeap(), 0, buffer
);
6091 return (lres
== ERROR_SUCCESS
);
6094 /******************************************************************************
6095 * SetDefaultPrinterA (WINSPOOL.202)
6097 * See SetDefaultPrinterW.
6100 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
6102 LPWSTR bufferW
= NULL
;
6105 TRACE("(%s)\n", debugstr_a(pszPrinter
));
6107 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
6108 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6109 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
6111 res
= SetDefaultPrinterW(bufferW
);
6112 HeapFree(GetProcessHeap(), 0, bufferW
);
6116 /******************************************************************************
6117 * SetPrinterDataExA (WINSPOOL.@)
6119 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6120 LPCSTR pValueName
, DWORD Type
,
6121 LPBYTE pData
, DWORD cbData
)
6123 HKEY hkeyPrinter
, hkeySubkey
;
6126 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
6127 debugstr_a(pValueName
), Type
, pData
, cbData
);
6129 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6133 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6135 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
6136 RegCloseKey(hkeyPrinter
);
6139 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6140 RegCloseKey(hkeySubkey
);
6141 RegCloseKey(hkeyPrinter
);
6145 /******************************************************************************
6146 * SetPrinterDataExW (WINSPOOL.@)
6148 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6149 LPCWSTR pValueName
, DWORD Type
,
6150 LPBYTE pData
, DWORD cbData
)
6152 HKEY hkeyPrinter
, hkeySubkey
;
6155 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
6156 debugstr_w(pValueName
), Type
, pData
, cbData
);
6158 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6162 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6164 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
6165 RegCloseKey(hkeyPrinter
);
6168 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6169 RegCloseKey(hkeySubkey
);
6170 RegCloseKey(hkeyPrinter
);
6174 /******************************************************************************
6175 * SetPrinterDataA (WINSPOOL.@)
6177 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
6178 LPBYTE pData
, DWORD cbData
)
6180 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
6184 /******************************************************************************
6185 * SetPrinterDataW (WINSPOOL.@)
6187 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
6188 LPBYTE pData
, DWORD cbData
)
6190 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6194 /******************************************************************************
6195 * GetPrinterDataExA (WINSPOOL.@)
6197 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6198 LPCSTR pValueName
, LPDWORD pType
,
6199 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6201 opened_printer_t
*printer
;
6202 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6205 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6206 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6208 printer
= get_opened_printer(hPrinter
);
6209 if(!printer
) return ERROR_INVALID_HANDLE
;
6211 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6212 if (ret
) return ret
;
6214 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6216 if (printer
->name
) {
6218 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6220 RegCloseKey(hkeyPrinters
);
6223 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6224 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6225 RegCloseKey(hkeyPrinter
);
6226 RegCloseKey(hkeyPrinters
);
6231 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6232 0, pType
, pData
, pcbNeeded
);
6234 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6236 RegCloseKey(hkeySubkey
);
6237 RegCloseKey(hkeyPrinter
);
6238 RegCloseKey(hkeyPrinters
);
6240 TRACE("--> %d\n", ret
);
6244 /******************************************************************************
6245 * GetPrinterDataExW (WINSPOOL.@)
6247 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6248 LPCWSTR pValueName
, LPDWORD pType
,
6249 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6251 opened_printer_t
*printer
;
6252 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6255 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6256 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6258 printer
= get_opened_printer(hPrinter
);
6259 if(!printer
) return ERROR_INVALID_HANDLE
;
6261 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6262 if (ret
) return ret
;
6264 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6266 if (printer
->name
) {
6268 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6270 RegCloseKey(hkeyPrinters
);
6273 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6274 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6275 RegCloseKey(hkeyPrinter
);
6276 RegCloseKey(hkeyPrinters
);
6281 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6282 0, pType
, pData
, pcbNeeded
);
6284 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6286 RegCloseKey(hkeySubkey
);
6287 RegCloseKey(hkeyPrinter
);
6288 RegCloseKey(hkeyPrinters
);
6290 TRACE("--> %d\n", ret
);
6294 /******************************************************************************
6295 * GetPrinterDataA (WINSPOOL.@)
6297 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6298 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6300 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6301 pData
, nSize
, pcbNeeded
);
6304 /******************************************************************************
6305 * GetPrinterDataW (WINSPOOL.@)
6307 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6308 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6310 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6311 pData
, nSize
, pcbNeeded
);
6314 /*******************************************************************************
6315 * EnumPrinterDataExW [WINSPOOL.@]
6317 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6318 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6319 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6321 HKEY hkPrinter
, hkSubKey
;
6322 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6323 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6328 PPRINTER_ENUM_VALUESW ppev
;
6330 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6332 if (pKeyName
== NULL
|| *pKeyName
== 0)
6333 return ERROR_INVALID_PARAMETER
;
6335 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6336 if (ret
!= ERROR_SUCCESS
)
6338 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6343 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6344 if (ret
!= ERROR_SUCCESS
)
6346 r
= RegCloseKey (hkPrinter
);
6347 if (r
!= ERROR_SUCCESS
)
6348 WARN ("RegCloseKey returned %i\n", r
);
6349 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6350 debugstr_w (pKeyName
), ret
);
6354 ret
= RegCloseKey (hkPrinter
);
6355 if (ret
!= ERROR_SUCCESS
)
6357 ERR ("RegCloseKey returned %i\n", ret
);
6358 r
= RegCloseKey (hkSubKey
);
6359 if (r
!= ERROR_SUCCESS
)
6360 WARN ("RegCloseKey returned %i\n", r
);
6364 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6365 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6366 if (ret
!= ERROR_SUCCESS
)
6368 r
= RegCloseKey (hkSubKey
);
6369 if (r
!= ERROR_SUCCESS
)
6370 WARN ("RegCloseKey returned %i\n", r
);
6371 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6375 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6376 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6378 if (cValues
== 0) /* empty key */
6380 r
= RegCloseKey (hkSubKey
);
6381 if (r
!= ERROR_SUCCESS
)
6382 WARN ("RegCloseKey returned %i\n", r
);
6383 *pcbEnumValues
= *pnEnumValues
= 0;
6384 return ERROR_SUCCESS
;
6387 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6389 hHeap
= GetProcessHeap ();
6392 ERR ("GetProcessHeap failed\n");
6393 r
= RegCloseKey (hkSubKey
);
6394 if (r
!= ERROR_SUCCESS
)
6395 WARN ("RegCloseKey returned %i\n", r
);
6396 return ERROR_OUTOFMEMORY
;
6399 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6400 if (lpValueName
== NULL
)
6402 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6403 r
= RegCloseKey (hkSubKey
);
6404 if (r
!= ERROR_SUCCESS
)
6405 WARN ("RegCloseKey returned %i\n", r
);
6406 return ERROR_OUTOFMEMORY
;
6409 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6410 if (lpValue
== NULL
)
6412 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6413 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6414 WARN ("HeapFree failed with code %i\n", GetLastError ());
6415 r
= RegCloseKey (hkSubKey
);
6416 if (r
!= ERROR_SUCCESS
)
6417 WARN ("RegCloseKey returned %i\n", r
);
6418 return ERROR_OUTOFMEMORY
;
6421 TRACE ("pass 1: calculating buffer required for all names and values\n");
6423 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6425 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6427 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6429 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6430 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6431 NULL
, NULL
, lpValue
, &cbValueLen
);
6432 if (ret
!= ERROR_SUCCESS
)
6434 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6435 WARN ("HeapFree failed with code %i\n", GetLastError ());
6436 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6437 WARN ("HeapFree failed with code %i\n", GetLastError ());
6438 r
= RegCloseKey (hkSubKey
);
6439 if (r
!= ERROR_SUCCESS
)
6440 WARN ("RegCloseKey returned %i\n", r
);
6441 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6445 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6446 debugstr_w (lpValueName
), dwIndex
,
6447 cbValueNameLen
+ 1, cbValueLen
);
6449 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6450 cbBufSize
+= cbValueLen
;
6453 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6455 *pcbEnumValues
= cbBufSize
;
6456 *pnEnumValues
= cValues
;
6458 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6460 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6461 WARN ("HeapFree failed with code %i\n", GetLastError ());
6462 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6463 WARN ("HeapFree failed with code %i\n", GetLastError ());
6464 r
= RegCloseKey (hkSubKey
);
6465 if (r
!= ERROR_SUCCESS
)
6466 WARN ("RegCloseKey returned %i\n", r
);
6467 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6468 return ERROR_MORE_DATA
;
6471 TRACE ("pass 2: copying all names and values to buffer\n");
6473 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6474 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6476 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6478 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6479 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6480 NULL
, &dwType
, lpValue
, &cbValueLen
);
6481 if (ret
!= ERROR_SUCCESS
)
6483 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6484 WARN ("HeapFree failed with code %i\n", GetLastError ());
6485 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6486 WARN ("HeapFree failed with code %i\n", GetLastError ());
6487 r
= RegCloseKey (hkSubKey
);
6488 if (r
!= ERROR_SUCCESS
)
6489 WARN ("RegCloseKey returned %i\n", r
);
6490 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6494 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6495 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6496 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6497 pEnumValues
+= cbValueNameLen
;
6499 /* return # of *bytes* (including trailing \0), not # of chars */
6500 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6502 ppev
[dwIndex
].dwType
= dwType
;
6504 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6505 ppev
[dwIndex
].pData
= pEnumValues
;
6506 pEnumValues
+= cbValueLen
;
6508 ppev
[dwIndex
].cbData
= cbValueLen
;
6510 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6511 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6514 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6516 ret
= GetLastError ();
6517 ERR ("HeapFree failed with code %i\n", ret
);
6518 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6519 WARN ("HeapFree failed with code %i\n", GetLastError ());
6520 r
= RegCloseKey (hkSubKey
);
6521 if (r
!= ERROR_SUCCESS
)
6522 WARN ("RegCloseKey returned %i\n", r
);
6526 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6528 ret
= GetLastError ();
6529 ERR ("HeapFree failed with code %i\n", ret
);
6530 r
= RegCloseKey (hkSubKey
);
6531 if (r
!= ERROR_SUCCESS
)
6532 WARN ("RegCloseKey returned %i\n", r
);
6536 ret
= RegCloseKey (hkSubKey
);
6537 if (ret
!= ERROR_SUCCESS
)
6539 ERR ("RegCloseKey returned %i\n", ret
);
6543 return ERROR_SUCCESS
;
6546 /*******************************************************************************
6547 * EnumPrinterDataExA [WINSPOOL.@]
6549 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6550 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6551 * what Windows 2000 SP1 does.
6554 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6555 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6556 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6560 DWORD ret
, dwIndex
, dwBufSize
;
6564 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6566 if (pKeyName
== NULL
|| *pKeyName
== 0)
6567 return ERROR_INVALID_PARAMETER
;
6569 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6572 ret
= GetLastError ();
6573 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6577 hHeap
= GetProcessHeap ();
6580 ERR ("GetProcessHeap failed\n");
6581 return ERROR_OUTOFMEMORY
;
6584 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6585 if (pKeyNameW
== NULL
)
6587 ERR ("Failed to allocate %i bytes from process heap\n",
6588 (LONG
)(len
* sizeof (WCHAR
)));
6589 return ERROR_OUTOFMEMORY
;
6592 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6594 ret
= GetLastError ();
6595 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6596 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6597 WARN ("HeapFree failed with code %i\n", GetLastError ());
6601 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6602 pcbEnumValues
, pnEnumValues
);
6603 if (ret
!= ERROR_SUCCESS
)
6605 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6606 WARN ("HeapFree failed with code %i\n", GetLastError ());
6607 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6611 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6613 ret
= GetLastError ();
6614 ERR ("HeapFree failed with code %i\n", ret
);
6618 if (*pnEnumValues
== 0) /* empty key */
6619 return ERROR_SUCCESS
;
6622 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6624 PPRINTER_ENUM_VALUESW ppev
=
6625 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6627 if (dwBufSize
< ppev
->cbValueName
)
6628 dwBufSize
= ppev
->cbValueName
;
6630 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6631 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6632 dwBufSize
= ppev
->cbData
;
6635 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6637 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6638 if (pBuffer
== NULL
)
6640 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6641 return ERROR_OUTOFMEMORY
;
6644 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6646 PPRINTER_ENUM_VALUESW ppev
=
6647 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6649 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6650 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6654 ret
= GetLastError ();
6655 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6656 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6657 WARN ("HeapFree failed with code %i\n", GetLastError ());
6661 memcpy (ppev
->pValueName
, pBuffer
, len
);
6663 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6665 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6666 ppev
->dwType
!= REG_MULTI_SZ
)
6669 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6670 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6673 ret
= GetLastError ();
6674 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6675 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6676 WARN ("HeapFree failed with code %i\n", GetLastError ());
6680 memcpy (ppev
->pData
, pBuffer
, len
);
6682 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6683 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6686 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6688 ret
= GetLastError ();
6689 ERR ("HeapFree failed with code %i\n", ret
);
6693 return ERROR_SUCCESS
;
6696 /******************************************************************************
6697 * AbortPrinter (WINSPOOL.@)
6699 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6701 FIXME("(%p), stub!\n", hPrinter
);
6705 /******************************************************************************
6706 * AddPortA (WINSPOOL.@)
6711 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6713 LPWSTR nameW
= NULL
;
6714 LPWSTR monitorW
= NULL
;
6718 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6721 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6722 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6723 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6727 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6728 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6729 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6731 res
= AddPortW(nameW
, hWnd
, monitorW
);
6732 HeapFree(GetProcessHeap(), 0, nameW
);
6733 HeapFree(GetProcessHeap(), 0, monitorW
);
6737 /******************************************************************************
6738 * AddPortW (WINSPOOL.@)
6740 * Add a Port for a specific Monitor
6743 * pName [I] Servername or NULL (local Computer)
6744 * hWnd [I] Handle to parent Window for the Dialog-Box
6745 * pMonitorName [I] Name of the Monitor that manage the Port
6752 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6754 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6756 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6758 if (!pMonitorName
) {
6759 SetLastError(RPC_X_NULL_REF_POINTER
);
6763 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6766 /******************************************************************************
6767 * AddPortExA (WINSPOOL.@)
6772 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6775 PORT_INFO_2A
* pi2A
;
6776 LPWSTR nameW
= NULL
;
6777 LPWSTR monitorW
= NULL
;
6781 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6783 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6784 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6786 if ((level
< 1) || (level
> 2)) {
6787 SetLastError(ERROR_INVALID_LEVEL
);
6792 SetLastError(ERROR_INVALID_PARAMETER
);
6797 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6798 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6799 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6803 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6804 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6805 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6808 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6810 if (pi2A
->pPortName
) {
6811 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6812 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6813 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6817 if (pi2A
->pMonitorName
) {
6818 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6819 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6820 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6823 if (pi2A
->pDescription
) {
6824 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6825 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6826 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6828 pi2W
.fPortType
= pi2A
->fPortType
;
6829 pi2W
.Reserved
= pi2A
->Reserved
;
6832 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6834 HeapFree(GetProcessHeap(), 0, nameW
);
6835 HeapFree(GetProcessHeap(), 0, monitorW
);
6836 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6837 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6838 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6843 /******************************************************************************
6844 * AddPortExW (WINSPOOL.@)
6846 * Add a Port for a specific Monitor, without presenting a user interface
6849 * pName [I] Servername or NULL (local Computer)
6850 * level [I] Structure-Level (1 or 2) for pBuffer
6851 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6852 * pMonitorName [I] Name of the Monitor that manage the Port
6859 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6863 pi2
= (PORT_INFO_2W
*) pBuffer
;
6865 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6866 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6867 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6868 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6870 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6872 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6873 SetLastError(ERROR_INVALID_PARAMETER
);
6877 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6880 /******************************************************************************
6881 * AddPrinterConnectionA (WINSPOOL.@)
6883 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6885 FIXME("%s\n", debugstr_a(pName
));
6889 /******************************************************************************
6890 * AddPrinterConnectionW (WINSPOOL.@)
6892 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6894 FIXME("%s\n", debugstr_w(pName
));
6898 /******************************************************************************
6899 * AddPrinterDriverExW (WINSPOOL.@)
6901 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6904 * pName [I] Servername or NULL (local Computer)
6905 * level [I] Level for the supplied DRIVER_INFO_*W struct
6906 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6907 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6914 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6916 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6918 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6920 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6921 SetLastError(ERROR_INVALID_LEVEL
);
6926 SetLastError(ERROR_INVALID_PARAMETER
);
6930 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6933 /******************************************************************************
6934 * AddPrinterDriverExA (WINSPOOL.@)
6936 * See AddPrinterDriverExW.
6939 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6941 DRIVER_INFO_8A
*diA
;
6943 LPWSTR nameW
= NULL
;
6948 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6950 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6951 ZeroMemory(&diW
, sizeof(diW
));
6953 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6954 SetLastError(ERROR_INVALID_LEVEL
);
6959 SetLastError(ERROR_INVALID_PARAMETER
);
6963 /* convert servername to unicode */
6965 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6966 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6967 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6971 diW
.cVersion
= diA
->cVersion
;
6974 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6975 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6976 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6979 if (diA
->pEnvironment
) {
6980 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6981 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6982 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6985 if (diA
->pDriverPath
) {
6986 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6987 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6988 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6991 if (diA
->pDataFile
) {
6992 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6993 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6994 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6997 if (diA
->pConfigFile
) {
6998 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6999 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7000 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
7003 if ((Level
> 2) && diA
->pHelpFile
) {
7004 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, NULL
, 0);
7005 diW
.pHelpFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7006 MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, diW
.pHelpFile
, len
);
7009 if ((Level
> 2) && diA
->pDependentFiles
) {
7010 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
7011 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
7012 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7013 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
7016 if ((Level
> 2) && diA
->pMonitorName
) {
7017 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
7018 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7019 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
7022 if ((Level
> 2) && diA
->pDefaultDataType
) {
7023 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
7024 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7025 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
7028 if ((Level
> 3) && diA
->pszzPreviousNames
) {
7029 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
7030 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
7031 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7032 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
7036 diW
.ftDriverDate
= diA
->ftDriverDate
;
7037 diW
.dwlDriverVersion
= diA
->dwlDriverVersion
;
7040 if ((Level
> 5) && diA
->pszMfgName
) {
7041 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
7042 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7043 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
7046 if ((Level
> 5) && diA
->pszOEMUrl
) {
7047 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
7048 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7049 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
7052 if ((Level
> 5) && diA
->pszHardwareID
) {
7053 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
7054 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7055 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
7058 if ((Level
> 5) && diA
->pszProvider
) {
7059 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
7060 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7061 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
7064 if ((Level
> 7) && diA
->pszPrintProcessor
) {
7065 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, NULL
, 0);
7066 diW
.pszPrintProcessor
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7067 MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, diW
.pszPrintProcessor
, len
);
7070 if ((Level
> 7) && diA
->pszVendorSetup
) {
7071 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, NULL
, 0);
7072 diW
.pszVendorSetup
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7073 MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, diW
.pszVendorSetup
, len
);
7076 if ((Level
> 7) && diA
->pszzColorProfiles
) {
7077 lenA
= multi_sz_lenA(diA
->pszzColorProfiles
);
7078 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, NULL
, 0);
7079 diW
.pszzColorProfiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7080 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, diW
.pszzColorProfiles
, len
);
7083 if ((Level
> 7) && diA
->pszInfPath
) {
7084 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, NULL
, 0);
7085 diW
.pszInfPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7086 MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, diW
.pszInfPath
, len
);
7089 if ((Level
> 7) && diA
->pszzCoreDriverDependencies
) {
7090 lenA
= multi_sz_lenA(diA
->pszzCoreDriverDependencies
);
7091 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, NULL
, 0);
7092 diW
.pszzCoreDriverDependencies
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7093 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, diW
.pszzCoreDriverDependencies
, len
);
7097 diW
.dwPrinterDriverAttributes
= diA
->dwPrinterDriverAttributes
;
7098 diW
.ftMinInboxDriverVerDate
= diA
->ftMinInboxDriverVerDate
;
7099 diW
.dwlMinInboxDriverVerVersion
= diA
->dwlMinInboxDriverVerVersion
;
7102 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
7103 TRACE("got %u with %u\n", res
, GetLastError());
7104 HeapFree(GetProcessHeap(), 0, nameW
);
7105 HeapFree(GetProcessHeap(), 0, diW
.pName
);
7106 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
7107 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
7108 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
7109 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
7110 HeapFree(GetProcessHeap(), 0, diW
.pHelpFile
);
7111 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
7112 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
7113 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
7114 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
7115 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
7116 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
7117 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
7118 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
7119 HeapFree(GetProcessHeap(), 0, diW
.pszPrintProcessor
);
7120 HeapFree(GetProcessHeap(), 0, diW
.pszVendorSetup
);
7121 HeapFree(GetProcessHeap(), 0, diW
.pszzColorProfiles
);
7122 HeapFree(GetProcessHeap(), 0, diW
.pszInfPath
);
7123 HeapFree(GetProcessHeap(), 0, diW
.pszzCoreDriverDependencies
);
7125 TRACE("=> %u with %u\n", res
, GetLastError());
7129 /******************************************************************************
7130 * ConfigurePortA (WINSPOOL.@)
7132 * See ConfigurePortW.
7135 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
7137 LPWSTR nameW
= NULL
;
7138 LPWSTR portW
= NULL
;
7142 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
7144 /* convert servername to unicode */
7146 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7147 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7148 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7151 /* convert portname to unicode */
7153 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
7154 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7155 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
7158 res
= ConfigurePortW(nameW
, hWnd
, portW
);
7159 HeapFree(GetProcessHeap(), 0, nameW
);
7160 HeapFree(GetProcessHeap(), 0, portW
);
7164 /******************************************************************************
7165 * ConfigurePortW (WINSPOOL.@)
7167 * Display the Configuration-Dialog for a specific Port
7170 * pName [I] Servername or NULL (local Computer)
7171 * hWnd [I] Handle to parent Window for the Dialog-Box
7172 * pPortName [I] Name of the Port, that should be configured
7179 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
7182 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
7184 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7187 SetLastError(RPC_X_NULL_REF_POINTER
);
7191 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
7194 /******************************************************************************
7195 * ConnectToPrinterDlg (WINSPOOL.@)
7197 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
7199 FIXME("%p %x\n", hWnd
, Flags
);
7203 /******************************************************************************
7204 * DeletePrinterConnectionA (WINSPOOL.@)
7206 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
7208 FIXME("%s\n", debugstr_a(pName
));
7212 /******************************************************************************
7213 * DeletePrinterConnectionW (WINSPOOL.@)
7215 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
7217 FIXME("%s\n", debugstr_w(pName
));
7221 /******************************************************************************
7222 * DeletePrinterDriverExW (WINSPOOL.@)
7224 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
7225 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7230 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7231 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
7233 if(pName
&& pName
[0])
7235 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
7236 SetLastError(ERROR_INVALID_PARAMETER
);
7242 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7243 SetLastError(ERROR_INVALID_PARAMETER
);
7247 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7251 ERR("Can't open drivers key\n");
7255 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7258 RegCloseKey(hkey_drivers
);
7263 /******************************************************************************
7264 * DeletePrinterDriverExA (WINSPOOL.@)
7266 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7267 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7269 UNICODE_STRING NameW
, EnvW
, DriverW
;
7272 asciitounicode(&NameW
, pName
);
7273 asciitounicode(&EnvW
, pEnvironment
);
7274 asciitounicode(&DriverW
, pDriverName
);
7276 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7278 RtlFreeUnicodeString(&DriverW
);
7279 RtlFreeUnicodeString(&EnvW
);
7280 RtlFreeUnicodeString(&NameW
);
7285 /******************************************************************************
7286 * DeletePrinterDataExW (WINSPOOL.@)
7288 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7291 FIXME("%p %s %s\n", hPrinter
,
7292 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7293 return ERROR_INVALID_PARAMETER
;
7296 /******************************************************************************
7297 * DeletePrinterDataExA (WINSPOOL.@)
7299 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7302 FIXME("%p %s %s\n", hPrinter
,
7303 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7304 return ERROR_INVALID_PARAMETER
;
7307 /******************************************************************************
7308 * DeletePrintProcessorA (WINSPOOL.@)
7310 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7312 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7313 debugstr_a(pPrintProcessorName
));
7317 /******************************************************************************
7318 * DeletePrintProcessorW (WINSPOOL.@)
7320 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7322 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7323 debugstr_w(pPrintProcessorName
));
7327 /******************************************************************************
7328 * DeletePrintProvidorA (WINSPOOL.@)
7330 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7332 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7333 debugstr_a(pPrintProviderName
));
7337 /******************************************************************************
7338 * DeletePrintProvidorW (WINSPOOL.@)
7340 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7342 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7343 debugstr_w(pPrintProviderName
));
7347 /******************************************************************************
7348 * EnumFormsA (WINSPOOL.@)
7350 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7351 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7353 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7354 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7358 /******************************************************************************
7359 * EnumFormsW (WINSPOOL.@)
7361 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7362 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7364 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7365 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7369 /*****************************************************************************
7370 * EnumMonitorsA [WINSPOOL.@]
7372 * See EnumMonitorsW.
7375 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7376 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7379 LPBYTE bufferW
= NULL
;
7380 LPWSTR nameW
= NULL
;
7382 DWORD numentries
= 0;
7385 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7386 cbBuf
, pcbNeeded
, pcReturned
);
7388 /* convert servername to unicode */
7390 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7391 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7392 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7394 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7395 needed
= cbBuf
* sizeof(WCHAR
);
7396 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7397 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7399 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7400 if (pcbNeeded
) needed
= *pcbNeeded
;
7401 /* HeapReAlloc return NULL, when bufferW was NULL */
7402 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7403 HeapAlloc(GetProcessHeap(), 0, needed
);
7405 /* Try again with the large Buffer */
7406 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7408 numentries
= pcReturned
? *pcReturned
: 0;
7411 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7412 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7415 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7416 DWORD entrysize
= 0;
7419 LPMONITOR_INFO_2W mi2w
;
7420 LPMONITOR_INFO_2A mi2a
;
7422 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7423 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7425 /* First pass: calculate the size for all Entries */
7426 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7427 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7429 while (index
< numentries
) {
7431 needed
+= entrysize
; /* MONITOR_INFO_?A */
7432 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7434 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7435 NULL
, 0, NULL
, NULL
);
7437 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7438 NULL
, 0, NULL
, NULL
);
7439 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7440 NULL
, 0, NULL
, NULL
);
7442 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7443 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7444 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7447 /* check for errors and quit on failure */
7448 if (cbBuf
< needed
) {
7449 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7453 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7454 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7455 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7456 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7457 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7459 /* Second Pass: Fill the User Buffer (if we have one) */
7460 while ((index
< numentries
) && pMonitors
) {
7462 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7464 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7465 ptr
, cbBuf
, NULL
, NULL
);
7469 mi2a
->pEnvironment
= ptr
;
7470 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7471 ptr
, cbBuf
, NULL
, NULL
);
7475 mi2a
->pDLLName
= ptr
;
7476 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7477 ptr
, cbBuf
, NULL
, NULL
);
7481 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7482 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7483 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7487 if (pcbNeeded
) *pcbNeeded
= needed
;
7488 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7490 HeapFree(GetProcessHeap(), 0, nameW
);
7491 HeapFree(GetProcessHeap(), 0, bufferW
);
7493 TRACE("returning %d with %d (%d byte for %d entries)\n",
7494 (res
), GetLastError(), needed
, numentries
);
7500 /*****************************************************************************
7501 * EnumMonitorsW [WINSPOOL.@]
7503 * Enumerate available Port-Monitors
7506 * pName [I] Servername or NULL (local Computer)
7507 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7508 * pMonitors [O] PTR to Buffer that receives the Result
7509 * cbBuf [I] Size of Buffer at pMonitors
7510 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7511 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7515 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7518 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7519 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7522 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7523 cbBuf
, pcbNeeded
, pcReturned
);
7525 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7527 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7528 SetLastError(RPC_X_NULL_REF_POINTER
);
7532 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7535 /******************************************************************************
7536 * SpoolerInit (WINSPOOL.@)
7538 * Initialize the Spooler
7545 * The function fails on windows, when the spooler service is not running
7548 BOOL WINAPI
SpoolerInit(void)
7551 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7555 /******************************************************************************
7556 * XcvDataW (WINSPOOL.@)
7558 * Execute commands in the Printmonitor DLL
7561 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7562 * pszDataName [i] Name of the command to execute
7563 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7564 * cbInputData [i] Size in Bytes of Buffer at pInputData
7565 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7566 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7567 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7568 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7575 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7576 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7578 * Minimal List of commands, that a Printmonitor DLL should support:
7580 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7581 *| "AddPort" : Add a Port
7582 *| "DeletePort": Delete a Port
7584 * Many Printmonitors support additional commands. Examples for localspl.dll:
7585 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7586 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7589 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7590 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7591 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7593 opened_printer_t
*printer
;
7595 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7596 pInputData
, cbInputData
, pOutputData
,
7597 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7599 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7601 printer
= get_opened_printer(hXcv
);
7602 if (!printer
|| (!printer
->backend_printer
)) {
7603 SetLastError(ERROR_INVALID_HANDLE
);
7607 if (!pcbOutputNeeded
) {
7608 SetLastError(ERROR_INVALID_PARAMETER
);
7612 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7613 SetLastError(RPC_X_NULL_REF_POINTER
);
7617 *pcbOutputNeeded
= 0;
7619 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7620 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7624 /*****************************************************************************
7625 * EnumPrinterDataA [WINSPOOL.@]
7628 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7629 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7630 DWORD cbData
, LPDWORD pcbData
)
7632 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7633 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7634 return ERROR_NO_MORE_ITEMS
;
7637 /*****************************************************************************
7638 * EnumPrinterDataW [WINSPOOL.@]
7641 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7642 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7643 DWORD cbData
, LPDWORD pcbData
)
7645 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7646 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7647 return ERROR_NO_MORE_ITEMS
;
7650 /*****************************************************************************
7651 * EnumPrinterKeyA [WINSPOOL.@]
7654 DWORD WINAPI
EnumPrinterKeyA(HANDLE printer
, const CHAR
*key
, CHAR
*subkey
, DWORD size
, DWORD
*needed
)
7656 FIXME("%p %s %p %x %p\n", printer
, debugstr_a(key
), subkey
, size
, needed
);
7657 return ERROR_CALL_NOT_IMPLEMENTED
;
7660 /*****************************************************************************
7661 * EnumPrinterKeyW [WINSPOOL.@]
7664 DWORD WINAPI
EnumPrinterKeyW(HANDLE printer
, const WCHAR
*key
, WCHAR
*subkey
, DWORD size
, DWORD
*needed
)
7666 FIXME("%p %s %p %x %p\n", printer
, debugstr_w(key
), subkey
, size
, needed
);
7667 return ERROR_CALL_NOT_IMPLEMENTED
;
7670 /*****************************************************************************
7671 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7674 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7675 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7676 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7678 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7679 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7680 pcbNeeded
, pcReturned
);
7684 /*****************************************************************************
7685 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7688 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7689 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7690 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7692 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7693 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7694 pcbNeeded
, pcReturned
);
7698 /*****************************************************************************
7699 * EnumPrintProcessorsA [WINSPOOL.@]
7701 * See EnumPrintProcessorsW.
7704 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7705 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7708 LPBYTE bufferW
= NULL
;
7709 LPWSTR nameW
= NULL
;
7712 DWORD numentries
= 0;
7715 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7716 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7718 /* convert names to unicode */
7720 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7721 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7722 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7725 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7726 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7727 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7730 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7731 needed
= cbBuf
* sizeof(WCHAR
);
7732 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7733 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7735 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7736 if (pcbNeeded
) needed
= *pcbNeeded
;
7737 /* HeapReAlloc return NULL, when bufferW was NULL */
7738 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7739 HeapAlloc(GetProcessHeap(), 0, needed
);
7741 /* Try again with the large Buffer */
7742 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7744 numentries
= pcReturned
? *pcReturned
: 0;
7748 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7751 PPRINTPROCESSOR_INFO_1W ppiw
;
7752 PPRINTPROCESSOR_INFO_1A ppia
;
7754 /* First pass: calculate the size for all Entries */
7755 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7756 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7758 while (index
< numentries
) {
7760 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7761 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7763 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7764 NULL
, 0, NULL
, NULL
);
7766 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7767 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7770 /* check for errors and quit on failure */
7771 if (cbBuf
< needed
) {
7772 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7777 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7778 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7779 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7780 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7781 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7783 /* Second Pass: Fill the User Buffer (if we have one) */
7784 while ((index
< numentries
) && pPPInfo
) {
7786 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7788 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7789 ptr
, cbBuf
, NULL
, NULL
);
7793 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7794 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7799 if (pcbNeeded
) *pcbNeeded
= needed
;
7800 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7802 HeapFree(GetProcessHeap(), 0, nameW
);
7803 HeapFree(GetProcessHeap(), 0, envW
);
7804 HeapFree(GetProcessHeap(), 0, bufferW
);
7806 TRACE("returning %d with %d (%d byte for %d entries)\n",
7807 (res
), GetLastError(), needed
, numentries
);
7812 /*****************************************************************************
7813 * EnumPrintProcessorsW [WINSPOOL.@]
7815 * Enumerate available Print Processors
7818 * pName [I] Servername or NULL (local Computer)
7819 * pEnvironment [I] Printing-Environment or NULL (Default)
7820 * Level [I] Structure-Level (Only 1 is allowed)
7821 * pPPInfo [O] PTR to Buffer that receives the Result
7822 * cbBuf [I] Size of Buffer at pPPInfo
7823 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7824 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7828 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7831 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7832 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7835 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7836 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7838 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7840 if (!pcbNeeded
|| !pcReturned
) {
7841 SetLastError(RPC_X_NULL_REF_POINTER
);
7845 if (!pPPInfo
&& (cbBuf
> 0)) {
7846 SetLastError(ERROR_INVALID_USER_BUFFER
);
7850 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7851 cbBuf
, pcbNeeded
, pcReturned
);
7854 /*****************************************************************************
7855 * ExtDeviceMode [WINSPOOL.@]
7858 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7859 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7862 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7863 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7864 debugstr_a(pProfile
), fMode
);
7868 /*****************************************************************************
7869 * FindClosePrinterChangeNotification [WINSPOOL.@]
7872 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7874 FIXME("Stub: %p\n", hChange
);
7878 /*****************************************************************************
7879 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7882 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7883 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7885 FIXME("Stub: %p %x %x %p\n",
7886 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7887 return INVALID_HANDLE_VALUE
;
7890 /*****************************************************************************
7891 * FindNextPrinterChangeNotification [WINSPOOL.@]
7894 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7895 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7897 FIXME("Stub: %p %p %p %p\n",
7898 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7902 /*****************************************************************************
7903 * FreePrinterNotifyInfo [WINSPOOL.@]
7906 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7908 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7912 /*****************************************************************************
7915 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7916 * ansi depending on the unicode parameter.
7918 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7928 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7931 memcpy(ptr
, str
, *size
);
7938 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7941 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7948 /*****************************************************************************
7951 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7952 LPDWORD pcbNeeded
, BOOL unicode
)
7954 DWORD size
, left
= cbBuf
;
7955 BOOL space
= (cbBuf
> 0);
7962 ji1
->JobId
= job
->job_id
;
7965 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7966 if(space
&& size
<= left
)
7968 ji1
->pDocument
= (LPWSTR
)ptr
;
7976 if (job
->printer_name
)
7978 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7979 if(space
&& size
<= left
)
7981 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7993 /*****************************************************************************
7996 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7997 LPDWORD pcbNeeded
, BOOL unicode
)
7999 DWORD size
, left
= cbBuf
;
8001 BOOL space
= (cbBuf
> 0);
8003 LPDEVMODEA dmA
= NULL
;
8010 ji2
->JobId
= job
->job_id
;
8013 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
8014 if(space
&& size
<= left
)
8016 ji2
->pDocument
= (LPWSTR
)ptr
;
8024 if (job
->printer_name
)
8026 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
8027 if(space
&& size
<= left
)
8029 ji2
->pPrinterName
= (LPWSTR
)ptr
;
8042 dmA
= DEVMODEdupWtoA(job
->devmode
);
8043 devmode
= (LPDEVMODEW
) dmA
;
8044 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
8048 devmode
= job
->devmode
;
8049 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
8053 FIXME("Can't convert DEVMODE W to A\n");
8056 /* align DEVMODE to a DWORD boundary */
8057 shift
= (4 - (*pcbNeeded
& 3)) & 3;
8063 memcpy(ptr
, devmode
, size
-shift
);
8064 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
8065 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
8078 /*****************************************************************************
8081 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8082 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
8085 DWORD needed
= 0, size
;
8089 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
8091 EnterCriticalSection(&printer_handles_cs
);
8092 job
= get_job(hPrinter
, JobId
);
8099 size
= sizeof(JOB_INFO_1W
);
8104 memset(pJob
, 0, size
);
8108 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8113 size
= sizeof(JOB_INFO_2W
);
8118 memset(pJob
, 0, size
);
8122 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8127 size
= sizeof(JOB_INFO_3
);
8131 memset(pJob
, 0, size
);
8140 SetLastError(ERROR_INVALID_LEVEL
);
8144 *pcbNeeded
= needed
;
8146 LeaveCriticalSection(&printer_handles_cs
);
8150 /*****************************************************************************
8151 * GetJobA [WINSPOOL.@]
8154 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8155 DWORD cbBuf
, LPDWORD pcbNeeded
)
8157 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
8160 /*****************************************************************************
8161 * GetJobW [WINSPOOL.@]
8164 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8165 DWORD cbBuf
, LPDWORD pcbNeeded
)
8167 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
8170 /*****************************************************************************
8173 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
8176 char *unixname
, *cmdA
;
8178 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
8184 if(!(unixname
= wine_get_unix_file_name(filename
)))
8187 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
8188 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
8189 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
8191 TRACE("printing with: %s\n", cmdA
);
8193 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
8198 ERR("pipe() failed!\n");
8202 if ((pid
= fork()) == 0)
8208 /* reset signals that we previously set to SIG_IGN */
8209 signal(SIGPIPE
, SIG_DFL
);
8211 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
8216 ERR("fork() failed!\n");
8222 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
8223 write(fds
[1], buf
, no_read
);
8230 wret
= waitpid(pid
, &status
, 0);
8231 } while (wret
< 0 && errno
== EINTR
);
8234 ERR("waitpid() failed!\n");
8237 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
8239 ERR("child process failed! %d\n", status
);
8246 if(file_fd
!= -1) close(file_fd
);
8247 if(fds
[0] != -1) close(fds
[0]);
8248 if(fds
[1] != -1) close(fds
[1]);
8250 HeapFree(GetProcessHeap(), 0, cmdA
);
8251 HeapFree(GetProcessHeap(), 0, unixname
);
8258 /*****************************************************************************
8261 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8263 static const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8267 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8268 sprintfW(cmd
, fmtW
, printer_name
);
8270 r
= schedule_pipe(cmd
, filename
);
8272 HeapFree(GetProcessHeap(), 0, cmd
);
8276 #ifdef SONAME_LIBCUPS
8277 /*****************************************************************************
8278 * get_cups_jobs_ticket_options
8280 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8281 * The CUPS scheduler only looks for these in Print-File requests, and since
8282 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8285 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8287 FILE *fp
= fopen( file
, "r" );
8288 char buf
[257]; /* DSC max of 256 + '\0' */
8289 const char *ps_adobe
= "%!PS-Adobe-";
8290 const char *cups_job
= "%cupsJobTicket:";
8292 if (!fp
) return num_options
;
8293 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8294 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8295 while (fgets( buf
, sizeof(buf
), fp
))
8297 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8298 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8306 static int get_cups_default_options( const char *printer
, int num_options
, cups_option_t
**options
)
8311 if (!pcupsGetNamedDest
) return num_options
;
8313 dest
= pcupsGetNamedDest( NULL
, printer
, NULL
);
8314 if (!dest
) return num_options
;
8316 for (i
= 0; i
< dest
->num_options
; i
++)
8318 if (!pcupsGetOption( dest
->options
[i
].name
, num_options
, *options
))
8319 num_options
= pcupsAddOption( dest
->options
[i
].name
, dest
->options
[i
].value
,
8320 num_options
, options
);
8323 pcupsFreeDests( 1, dest
);
8328 /*****************************************************************************
8331 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8333 #ifdef SONAME_LIBCUPS
8336 char *unixname
, *queue
, *unix_doc_title
;
8339 int num_options
= 0, i
;
8340 cups_option_t
*options
= NULL
;
8342 if(!(unixname
= wine_get_unix_file_name(filename
)))
8345 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8346 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8347 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8349 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8350 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8351 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8353 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8354 num_options
= get_cups_default_options( queue
, num_options
, &options
);
8356 TRACE( "printing via cups with options:\n" );
8357 for (i
= 0; i
< num_options
; i
++)
8358 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8360 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8361 if (ret
== 0 && pcupsLastErrorString
)
8362 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8364 pcupsFreeOptions( num_options
, options
);
8366 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8367 HeapFree(GetProcessHeap(), 0, queue
);
8368 HeapFree(GetProcessHeap(), 0, unixname
);
8374 return schedule_lpr(printer_name
, filename
);
8378 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8385 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8389 if(HIWORD(wparam
) == BN_CLICKED
)
8391 if(LOWORD(wparam
) == IDOK
)
8394 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8397 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8398 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8400 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8402 WCHAR caption
[200], message
[200];
8405 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
8406 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, ARRAY_SIZE(message
));
8407 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8408 if(mb_ret
== IDCANCEL
)
8410 HeapFree(GetProcessHeap(), 0, filename
);
8414 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8415 if(hf
== INVALID_HANDLE_VALUE
)
8417 WCHAR caption
[200], message
[200];
8419 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
8420 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, ARRAY_SIZE(message
));
8421 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8422 HeapFree(GetProcessHeap(), 0, filename
);
8426 DeleteFileW(filename
);
8427 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8429 EndDialog(hwnd
, IDOK
);
8432 if(LOWORD(wparam
) == IDCANCEL
)
8434 EndDialog(hwnd
, IDCANCEL
);
8443 /*****************************************************************************
8446 static BOOL
get_filename(LPWSTR
*filename
)
8448 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8449 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8452 /*****************************************************************************
8455 static BOOL
schedule_file(LPCWSTR filename
)
8457 LPWSTR output
= NULL
;
8459 if(get_filename(&output
))
8462 TRACE("copy to %s\n", debugstr_w(output
));
8463 r
= CopyFileW(filename
, output
, FALSE
);
8464 HeapFree(GetProcessHeap(), 0, output
);
8470 /*****************************************************************************
8473 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8475 int in_fd
, out_fd
, no_read
;
8478 char *unixname
, *outputA
;
8481 if(!(unixname
= wine_get_unix_file_name(filename
)))
8484 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8485 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8486 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8488 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8489 in_fd
= open(unixname
, O_RDONLY
);
8490 if(out_fd
== -1 || in_fd
== -1)
8493 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8494 write(out_fd
, buf
, no_read
);
8498 if(in_fd
!= -1) close(in_fd
);
8499 if(out_fd
!= -1) close(out_fd
);
8500 HeapFree(GetProcessHeap(), 0, outputA
);
8501 HeapFree(GetProcessHeap(), 0, unixname
);
8505 /*****************************************************************************
8506 * ScheduleJob [WINSPOOL.@]
8509 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8511 opened_printer_t
*printer
;
8513 struct list
*cursor
, *cursor2
;
8515 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8516 EnterCriticalSection(&printer_handles_cs
);
8517 printer
= get_opened_printer(hPrinter
);
8521 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8523 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8526 if(job
->job_id
!= dwJobID
) continue;
8528 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8529 if(hf
!= INVALID_HANDLE_VALUE
)
8531 PRINTER_INFO_5W
*pi5
= NULL
;
8532 LPWSTR portname
= job
->portname
;
8536 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8537 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8541 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8542 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8543 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8544 portname
= pi5
->pPortName
;
8546 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8547 debugstr_w(portname
));
8551 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8552 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8554 DWORD type
, count
= sizeof(output
);
8555 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8558 if(output
[0] == '|')
8560 ret
= schedule_pipe(output
+ 1, job
->filename
);
8564 ret
= schedule_unixfile(output
, job
->filename
);
8566 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8568 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8570 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8572 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8574 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8576 ret
= schedule_file(job
->filename
);
8578 else if(isalpha(portname
[0]) && portname
[1] == ':')
8580 TRACE("copying to %s\n", debugstr_w(portname
));
8581 ret
= CopyFileW(job
->filename
, portname
, FALSE
);
8585 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8587 HeapFree(GetProcessHeap(), 0, pi5
);
8589 DeleteFileW(job
->filename
);
8591 list_remove(cursor
);
8592 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8593 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8594 HeapFree(GetProcessHeap(), 0, job
->portname
);
8595 HeapFree(GetProcessHeap(), 0, job
->filename
);
8596 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8597 HeapFree(GetProcessHeap(), 0, job
);
8601 LeaveCriticalSection(&printer_handles_cs
);
8605 /*****************************************************************************
8606 * StartDocDlgA [WINSPOOL.@]
8608 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8610 UNICODE_STRING usBuffer
;
8611 DOCINFOW docW
= { 0 };
8613 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8616 docW
.cbSize
= sizeof(docW
);
8617 if (doc
->lpszDocName
)
8619 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8620 if (!(docW
.lpszDocName
= docnameW
)) goto failed
;
8622 if (doc
->lpszOutput
)
8624 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8625 if (!(docW
.lpszOutput
= outputW
)) goto failed
;
8627 if (doc
->lpszDatatype
)
8629 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8630 if (!(docW
.lpszDatatype
= datatypeW
)) goto failed
;
8632 docW
.fwType
= doc
->fwType
;
8634 retW
= StartDocDlgW(hPrinter
, &docW
);
8638 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8639 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8640 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8641 HeapFree(GetProcessHeap(), 0, retW
);
8645 HeapFree(GetProcessHeap(), 0, datatypeW
);
8646 HeapFree(GetProcessHeap(), 0, outputW
);
8647 HeapFree(GetProcessHeap(), 0, docnameW
);
8652 /*****************************************************************************
8653 * StartDocDlgW [WINSPOOL.@]
8655 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8656 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8657 * port is "FILE:". Also returns the full path if passed a relative path.
8659 * The caller should free the returned string from the process heap.
8661 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8666 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8668 PRINTER_INFO_5W
*pi5
;
8669 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8670 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8672 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8673 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8674 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8676 HeapFree(GetProcessHeap(), 0, pi5
);
8679 HeapFree(GetProcessHeap(), 0, pi5
);
8682 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8686 if (get_filename(&name
))
8688 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8690 HeapFree(GetProcessHeap(), 0, name
);
8693 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8694 GetFullPathNameW(name
, len
, ret
, NULL
);
8695 HeapFree(GetProcessHeap(), 0, name
);
8700 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8703 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8704 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8706 attr
= GetFileAttributesW(ret
);
8707 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8709 HeapFree(GetProcessHeap(), 0, ret
);
8715 /*****************************************************************************
8716 * UploadPrinterDriverPackageA [WINSPOOL.@]
8718 HRESULT WINAPI
UploadPrinterDriverPackageA( LPCSTR server
, LPCSTR path
, LPCSTR env
,
8719 DWORD flags
, HWND hwnd
, LPSTR dst
, PULONG dstlen
)
8721 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server
), debugstr_a(path
), debugstr_a(env
),
8722 flags
, hwnd
, dst
, dstlen
);
8726 /*****************************************************************************
8727 * UploadPrinterDriverPackageW [WINSPOOL.@]
8729 HRESULT WINAPI
UploadPrinterDriverPackageW( LPCWSTR server
, LPCWSTR path
, LPCWSTR env
,
8730 DWORD flags
, HWND hwnd
, LPWSTR dst
, PULONG dstlen
)
8732 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server
), debugstr_w(path
), debugstr_w(env
),
8733 flags
, hwnd
, dst
, dstlen
);
8737 /*****************************************************************************
8738 * PerfOpen [WINSPOOL.@]
8740 DWORD WINAPI
PerfOpen(LPWSTR context
)
8742 FIXME("%s: stub\n", debugstr_w(context
));
8743 return ERROR_SUCCESS
;
8746 /*****************************************************************************
8747 * PerfClose [WINSPOOL.@]
8749 DWORD WINAPI
PerfClose(void)
8752 return ERROR_SUCCESS
;
8755 /*****************************************************************************
8756 * PerfCollect [WINSPOOL.@]
8758 DWORD WINAPI
PerfCollect(LPWSTR query
, LPVOID
*data
, LPDWORD size
, LPDWORD obj_count
)
8760 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query
), data
, size
, obj_count
);
8763 return ERROR_SUCCESS
;