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 static const WCHAR invalid_chars
[] = {'*','?','<','>','|','"','/','\\',0};
725 int dir_len
= strlenW( dir
), file_len
= strlenW( file_name
);
726 int len
= (dir_len
+ file_len
+ ARRAY_SIZE( dot_ppd
)) * sizeof(WCHAR
);
727 WCHAR
*ppd
= HeapAlloc( GetProcessHeap(), 0, len
), *p
;
729 if (!ppd
) return NULL
;
730 memcpy( ppd
, dir
, dir_len
* sizeof(WCHAR
) );
731 memcpy( ppd
+ dir_len
, file_name
, file_len
* sizeof(WCHAR
) );
732 memcpy( ppd
+ dir_len
+ file_len
, dot_ppd
, sizeof(dot_ppd
) );
735 while ((p
= strpbrkW( p
, invalid_chars
))) *p
++ = '_';
740 static WCHAR
*get_ppd_dir( void )
742 static const WCHAR wine_ppds
[] = {'w','i','n','e','_','p','p','d','s','\\',0};
744 WCHAR
*dir
, tmp_path
[MAX_PATH
];
747 len
= GetTempPathW( ARRAY_SIZE( tmp_path
), tmp_path
);
748 if (!len
) return NULL
;
749 dir
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) + sizeof(wine_ppds
) ) ;
750 if (!dir
) return NULL
;
752 memcpy( dir
, tmp_path
, len
* sizeof(WCHAR
) );
753 memcpy( dir
+ len
, wine_ppds
, sizeof(wine_ppds
) );
754 res
= CreateDirectoryW( dir
, NULL
);
755 if (!res
&& GetLastError() != ERROR_ALREADY_EXISTS
)
757 HeapFree( GetProcessHeap(), 0, dir
);
760 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir
) );
764 static void unlink_ppd( const WCHAR
*ppd
)
766 char *unix_name
= wine_get_unix_file_name( ppd
);
768 HeapFree( GetProcessHeap(), 0, unix_name
);
771 #ifdef SONAME_LIBCUPS
773 static void *cupshandle
;
776 DO_FUNC(cupsAddOption); \
777 DO_FUNC(cupsFreeDests); \
778 DO_FUNC(cupsFreeOptions); \
779 DO_FUNC(cupsGetDests); \
780 DO_FUNC(cupsGetOption); \
781 DO_FUNC(cupsParseOptions); \
782 DO_FUNC(cupsPrintFile)
783 #define CUPS_OPT_FUNCS \
784 DO_FUNC(cupsGetNamedDest); \
785 DO_FUNC(cupsGetPPD); \
786 DO_FUNC(cupsGetPPD3); \
787 DO_FUNC(cupsLastErrorString)
789 #define DO_FUNC(f) static typeof(f) *p##f
792 static cups_dest_t
* (*pcupsGetNamedDest
)(http_t
*, const char *, const char *);
793 static const char * (*pcupsGetPPD
)(const char *);
794 static http_status_t (*pcupsGetPPD3
)(http_t
*, const char *, time_t *, char *, size_t);
795 static const char * (*pcupsLastErrorString
)(void);
797 static http_status_t
cupsGetPPD3_wrapper( http_t
*http
, const char *name
,
798 time_t *modtime
, char *buffer
,
803 if (pcupsGetPPD3
) return pcupsGetPPD3( http
, name
, modtime
, buffer
, bufsize
);
805 if (!pcupsGetPPD
) return HTTP_NOT_FOUND
;
807 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
810 ppd
= pcupsGetPPD( name
);
812 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd
) );
814 if (!ppd
) return HTTP_NOT_FOUND
;
816 if (rename( ppd
, buffer
) == -1)
818 BOOL res
= copy_file( ppd
, buffer
);
820 if (!res
) return HTTP_NOT_FOUND
;
825 static BOOL
get_cups_ppd( const char *printer_name
, const WCHAR
*ppd
)
828 http_status_t http_status
;
829 char *unix_name
= wine_get_unix_file_name( ppd
);
831 TRACE( "(%s, %s)\n", debugstr_a(printer_name
), debugstr_w(ppd
) );
833 if (!unix_name
) return FALSE
;
835 http_status
= cupsGetPPD3_wrapper( 0, printer_name
, &modtime
,
836 unix_name
, strlen( unix_name
) + 1 );
838 if (http_status
!= HTTP_OK
) unlink( unix_name
);
839 HeapFree( GetProcessHeap(), 0, unix_name
);
841 if (http_status
== HTTP_OK
) return TRUE
;
843 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
844 debugstr_a(printer_name
), http_status
);
845 return get_fallback_ppd( printer_name
, ppd
);
848 static WCHAR
*get_cups_option( const char *name
, int num_options
, cups_option_t
*options
)
854 value
= pcupsGetOption( name
, num_options
, options
);
855 if (!value
) return NULL
;
857 len
= MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, NULL
, 0 );
858 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
859 if (ret
) MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, ret
, len
);
864 static cups_ptype_t
get_cups_printer_type( const cups_dest_t
*dest
)
866 WCHAR
*type
= get_cups_option( "printer-type", dest
->num_options
, dest
->options
), *end
;
867 cups_ptype_t ret
= 0;
871 ret
= (cups_ptype_t
)strtoulW( type
, &end
, 10 );
874 HeapFree( GetProcessHeap(), 0, type
);
878 static void load_cups(void)
880 cupshandle
= dlopen( SONAME_LIBCUPS
, RTLD_NOW
);
881 if (!cupshandle
) return;
883 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
886 p##x = dlsym( cupshandle, #x ); \
889 ERR("failed to load symbol %s\n", #x); \
895 #define DO_FUNC(x) p##x = dlsym( cupshandle, #x )
900 static BOOL
CUPS_LoadPrinters(void)
903 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
906 WCHAR
*port
, *ppd_dir
= NULL
, *ppd
;
907 HKEY hkeyPrinter
, hkeyPrinters
;
908 WCHAR nameW
[MAX_PATH
];
909 HANDLE added_printer
;
910 cups_ptype_t printer_type
;
912 if (!cupshandle
) return FALSE
;
914 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
916 ERR("Can't create Printers key\n");
920 nrofdests
= pcupsGetDests(&dests
);
921 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
922 for (i
=0;i
<nrofdests
;i
++) {
923 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, ARRAY_SIZE(nameW
));
924 printer_type
= get_cups_printer_type( dests
+ i
);
926 TRACE( "Printer %d: %s. printer_type %x\n", i
, debugstr_w(nameW
), printer_type
);
928 if (printer_type
& 0x2000000 /* CUPS_PRINTER_SCANNER */)
930 TRACE( "skipping scanner-only device\n" );
934 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
935 lstrcpyW(port
, CUPS_Port
);
936 lstrcatW(port
, nameW
);
938 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
939 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
940 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
942 TRACE("Printer already exists\n");
943 /* overwrite old LPR:* port */
944 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
945 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
946 /* flag that the PPD file should be checked for an update */
947 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
948 RegCloseKey(hkeyPrinter
);
950 BOOL added_driver
= FALSE
;
952 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir()))
954 HeapFree( GetProcessHeap(), 0, port
);
957 ppd
= get_ppd_filename( ppd_dir
, nameW
);
958 if (get_cups_ppd( dests
[i
].name
, ppd
))
960 added_driver
= add_printer_driver( nameW
, ppd
);
963 HeapFree( GetProcessHeap(), 0, ppd
);
966 HeapFree( GetProcessHeap(), 0, port
);
970 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
971 pi2
.pPrinterName
= nameW
;
972 pi2
.pDatatype
= rawW
;
973 pi2
.pPrintProcessor
= WinPrintW
;
974 pi2
.pDriverName
= nameW
;
975 pi2
.pComment
= get_cups_option( "printer-info", dests
[i
].num_options
, dests
[i
].options
);
976 pi2
.pLocation
= get_cups_option( "printer-location", dests
[i
].num_options
, dests
[i
].options
);
977 pi2
.pPortName
= port
;
978 pi2
.pParameters
= emptyStringW
;
979 pi2
.pShareName
= emptyStringW
;
980 pi2
.pSepFile
= emptyStringW
;
982 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
983 if (added_printer
) ClosePrinter( added_printer
);
984 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
985 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
987 HeapFree( GetProcessHeap(), 0, pi2
.pComment
);
988 HeapFree( GetProcessHeap(), 0, pi2
.pLocation
);
990 HeapFree( GetProcessHeap(), 0, port
);
993 if (dests
[i
].is_default
) {
994 SetDefaultPrinterW(nameW
);
1001 RemoveDirectoryW( ppd_dir
);
1002 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1005 if (hadprinter
&& !haddefault
) {
1006 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, ARRAY_SIZE(nameW
));
1007 SetDefaultPrinterW(nameW
);
1009 pcupsFreeDests(nrofdests
, dests
);
1010 RegCloseKey(hkeyPrinters
);
1016 static char *get_queue_name( HANDLE printer
, BOOL
*cups
)
1018 WCHAR
*port
, *name
= NULL
;
1019 DWORD err
, needed
, type
;
1025 err
= WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
);
1026 if (err
) return NULL
;
1027 err
= RegQueryValueExW( key
, PortW
, 0, &type
, NULL
, &needed
);
1029 port
= HeapAlloc( GetProcessHeap(), 0, needed
);
1030 if (!port
) goto end
;
1031 RegQueryValueExW( key
, PortW
, 0, &type
, (BYTE
*)port
, &needed
);
1033 if (!strncmpW( port
, CUPS_Port
, ARRAY_SIZE( CUPS_Port
) -1 ))
1035 name
= port
+ ARRAY_SIZE( CUPS_Port
) - 1;
1038 else if (!strncmpW( port
, LPR_Port
, ARRAY_SIZE( LPR_Port
) -1 ))
1039 name
= port
+ ARRAY_SIZE( LPR_Port
) - 1;
1042 needed
= WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
1043 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
1044 if(ret
) WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, ret
, needed
, NULL
, NULL
);
1046 HeapFree( GetProcessHeap(), 0, port
);
1053 static void set_ppd_overrides( HANDLE printer
)
1057 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1059 PMPrintSession session
= NULL
;
1060 PMPageFormat format
= NULL
;
1062 CFStringRef paper_name
;
1065 status
= PMCreateSession( &session
);
1066 if (status
) goto end
;
1068 status
= PMCreatePageFormat( &format
);
1069 if (status
) goto end
;
1071 status
= PMSessionDefaultPageFormat( session
, format
);
1072 if (status
) goto end
;
1074 status
= PMGetPageFormatPaper( format
, &paper
);
1075 if (status
) goto end
;
1077 status
= PMPaperGetPPDPaperName( paper
, &paper_name
);
1078 if (status
) goto end
;
1081 range
.length
= CFStringGetLength( paper_name
);
1082 size
= (range
.length
+ 1) * sizeof(WCHAR
);
1084 wstr
= HeapAlloc( GetProcessHeap(), 0, size
);
1085 CFStringGetCharacters( paper_name
, range
, (UniChar
*)wstr
);
1086 wstr
[range
.length
] = 0;
1089 if (format
) PMRelease( format
);
1090 if (session
) PMRelease( session
);
1093 SetPrinterDataExW( printer
, PPD_Overrides
, DefaultPageSize
, REG_SZ
, (BYTE
*)wstr
, size
);
1094 HeapFree( GetProcessHeap(), 0, wstr
);
1097 static BOOL
update_driver( HANDLE printer
)
1100 const WCHAR
*name
= get_opened_printer_name( printer
);
1101 WCHAR
*ppd_dir
, *ppd
;
1104 if (!name
) return FALSE
;
1105 queue_name
= get_queue_name( printer
, &is_cups
);
1106 if (!queue_name
) return FALSE
;
1108 if (!(ppd_dir
= get_ppd_dir()))
1110 HeapFree( GetProcessHeap(), 0, queue_name
);
1113 ppd
= get_ppd_filename( ppd_dir
, name
);
1115 #ifdef SONAME_LIBCUPS
1117 ret
= get_cups_ppd( queue_name
, ppd
);
1120 ret
= get_fallback_ppd( queue_name
, ppd
);
1124 TRACE( "updating driver %s\n", debugstr_w( name
) );
1125 ret
= add_printer_driver( name
, ppd
);
1128 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1129 HeapFree( GetProcessHeap(), 0, ppd
);
1130 HeapFree( GetProcessHeap(), 0, queue_name
);
1132 set_ppd_overrides( printer
);
1134 /* call into the driver to update the devmode */
1135 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
1140 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
1142 PRINTER_INFO_2A pinfo2a
;
1145 char *e
,*s
,*name
,*prettyname
,*devname
;
1146 BOOL ret
= FALSE
, set_default
= FALSE
;
1147 char *port
= NULL
, *env_default
;
1148 HKEY hkeyPrinter
, hkeyPrinters
= NULL
;
1149 WCHAR devnameW
[MAX_PATH
], *ppd_dir
= NULL
, *ppd
;
1150 HANDLE added_printer
;
1152 while (isspace(*pent
)) pent
++;
1153 r
= strchr(pent
,':');
1155 name_len
= r
- pent
;
1157 name_len
= strlen(pent
);
1158 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
1159 memcpy(name
, pent
, name_len
);
1160 name
[name_len
] = '\0';
1166 TRACE("name=%s entry=%s\n",name
, pent
);
1168 if(ispunct(*name
)) { /* a tc entry, not a real printer */
1169 TRACE("skipping tc entry\n");
1173 if(strstr(pent
,":server")) { /* server only version so skip */
1174 TRACE("skipping server entry\n");
1178 /* Determine whether this is a postscript printer. */
1181 env_default
= getenv("PRINTER");
1183 /* Get longest name, usually the one at the right for later display. */
1184 while((s
=strchr(prettyname
,'|'))) {
1187 while(isspace(*--e
)) *e
= '\0';
1188 TRACE("\t%s\n", debugstr_a(prettyname
));
1189 if(env_default
&& !_strnicmp(prettyname
, env_default
, -1)) set_default
= TRUE
;
1190 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
1193 e
= prettyname
+ strlen(prettyname
);
1194 while(isspace(*--e
)) *e
= '\0';
1195 TRACE("\t%s\n", debugstr_a(prettyname
));
1196 if(env_default
&& !_strnicmp(prettyname
, env_default
, -1)) set_default
= TRUE
;
1198 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1199 * if it is too long, we use it as comment below. */
1200 devname
= prettyname
;
1201 if (strlen(devname
)>=CCHDEVICENAME
-1)
1203 if (strlen(devname
)>=CCHDEVICENAME
-1) {
1208 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
1209 sprintf(port
,"LPR:%s",name
);
1211 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1213 ERR("Can't create Printers key\n");
1218 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, ARRAY_SIZE(devnameW
));
1220 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1221 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1222 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1224 TRACE("Printer already exists\n");
1225 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1226 /* flag that the PPD file should be checked for an update */
1227 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1228 RegCloseKey(hkeyPrinter
);
1230 static CHAR data_type
[] = "RAW",
1231 print_proc
[] = "WinPrint",
1232 comment
[] = "WINEPS Printer using LPR",
1233 params
[] = "<parameters?>",
1234 share_name
[] = "<share name?>",
1235 sep_file
[] = "<sep file?>";
1236 BOOL added_driver
= FALSE
;
1238 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir())) goto end
;
1239 ppd
= get_ppd_filename( ppd_dir
, devnameW
);
1240 if (get_fallback_ppd( devname
, ppd
))
1242 added_driver
= add_printer_driver( devnameW
, ppd
);
1245 HeapFree( GetProcessHeap(), 0, ppd
);
1246 if (!added_driver
) goto end
;
1248 memset(&pinfo2a
,0,sizeof(pinfo2a
));
1249 pinfo2a
.pPrinterName
= devname
;
1250 pinfo2a
.pDatatype
= data_type
;
1251 pinfo2a
.pPrintProcessor
= print_proc
;
1252 pinfo2a
.pDriverName
= devname
;
1253 pinfo2a
.pComment
= comment
;
1254 pinfo2a
.pLocation
= prettyname
;
1255 pinfo2a
.pPortName
= port
;
1256 pinfo2a
.pParameters
= params
;
1257 pinfo2a
.pShareName
= share_name
;
1258 pinfo2a
.pSepFile
= sep_file
;
1260 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
1261 if (added_printer
) ClosePrinter( added_printer
);
1262 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1263 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
1266 if (isfirst
|| set_default
)
1267 set_default_printer(devname
, name
);
1270 if (hkeyPrinters
) RegCloseKey( hkeyPrinters
);
1273 RemoveDirectoryW( ppd_dir
);
1274 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1276 HeapFree(GetProcessHeap(), 0, port
);
1277 HeapFree(GetProcessHeap(), 0, name
);
1282 PRINTCAP_LoadPrinters(void) {
1283 BOOL hadprinter
= FALSE
;
1287 BOOL had_bash
= FALSE
;
1289 f
= fopen("/etc/printcap","r");
1293 while(fgets(buf
,sizeof(buf
),f
)) {
1296 end
=strchr(buf
,'\n');
1300 while(isspace(*start
)) start
++;
1301 if(*start
== '#' || *start
== '\0')
1304 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
1305 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1306 HeapFree(GetProcessHeap(),0,pent
);
1310 if (end
&& *--end
== '\\') {
1317 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
1320 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
1326 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1327 HeapFree(GetProcessHeap(),0,pent
);
1333 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
1336 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
1337 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
1339 return ERROR_FILE_NOT_FOUND
;
1342 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
1344 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
1345 DWORD ret
= ERROR_FILE_NOT_FOUND
;
1347 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1348 and we support these drivers. NT writes DEVMODEW so somehow
1349 we'll need to distinguish between these when we support NT
1354 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
1355 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1356 HeapFree( GetProcessHeap(), 0, dmA
);
1362 /******************************************************************
1363 * get_servername_from_name (internal)
1365 * for an external server, a copy of the serverpart from the full name is returned
1368 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1372 WCHAR buffer
[MAX_PATH
];
1375 if (name
== NULL
) return NULL
;
1376 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1378 server
= strdupW(&name
[2]); /* skip over both backslash */
1379 if (server
== NULL
) return NULL
;
1381 /* strip '\' and the printername */
1382 ptr
= strchrW(server
, '\\');
1383 if (ptr
) ptr
[0] = '\0';
1385 TRACE("found %s\n", debugstr_w(server
));
1387 len
= ARRAY_SIZE(buffer
);
1388 if (GetComputerNameW(buffer
, &len
)) {
1389 if (lstrcmpW(buffer
, server
) == 0) {
1390 /* The requested Servername is our computername */
1391 HeapFree(GetProcessHeap(), 0, server
);
1398 /******************************************************************
1399 * get_basename_from_name (internal)
1401 * skip over the serverpart from the full name
1404 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1406 if (name
== NULL
) return NULL
;
1407 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1408 /* skip over the servername and search for the following '\' */
1409 name
= strchrW(&name
[2], '\\');
1410 if ((name
) && (name
[1])) {
1411 /* found a separator ('\') followed by a name:
1412 skip over the separator and return the rest */
1417 /* no basename present (we found only a servername) */
1424 static void free_printer_entry( opened_printer_t
*printer
)
1426 /* the queue is shared, so don't free that here */
1427 HeapFree( GetProcessHeap(), 0, printer
->printername
);
1428 HeapFree( GetProcessHeap(), 0, printer
->name
);
1429 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
1430 HeapFree( GetProcessHeap(), 0, printer
);
1433 /******************************************************************
1434 * get_opened_printer_entry
1435 * Get the first place empty in the opened printer table
1438 * - pDefault is ignored
1440 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1442 UINT_PTR handle
= nb_printer_handles
, i
;
1443 jobqueue_t
*queue
= NULL
;
1444 opened_printer_t
*printer
= NULL
;
1446 LPCWSTR printername
;
1448 if ((backend
== NULL
) && !load_backend()) return NULL
;
1450 servername
= get_servername_from_name(name
);
1452 FIXME("server %s not supported\n", debugstr_w(servername
));
1453 HeapFree(GetProcessHeap(), 0, servername
);
1454 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1458 printername
= get_basename_from_name(name
);
1459 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1461 /* an empty printername is invalid */
1462 if (printername
&& (!printername
[0])) {
1463 SetLastError(ERROR_INVALID_PARAMETER
);
1467 EnterCriticalSection(&printer_handles_cs
);
1469 for (i
= 0; i
< nb_printer_handles
; i
++)
1471 if (!printer_handles
[i
])
1473 if(handle
== nb_printer_handles
)
1478 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1479 queue
= printer_handles
[i
]->queue
;
1483 if (handle
>= nb_printer_handles
)
1485 opened_printer_t
**new_array
;
1486 if (printer_handles
)
1487 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1488 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1490 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1491 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1498 printer_handles
= new_array
;
1499 nb_printer_handles
+= 16;
1502 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1508 /* get a printer handle from the backend */
1509 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1514 /* clone the base name. This is NULL for the printserver */
1515 printer
->printername
= strdupW(printername
);
1517 /* clone the full name */
1518 printer
->name
= strdupW(name
);
1519 if (name
&& (!printer
->name
)) {
1524 if (pDefault
&& pDefault
->pDevMode
)
1525 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
1528 printer
->queue
= queue
;
1531 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1532 if (!printer
->queue
) {
1536 list_init(&printer
->queue
->jobs
);
1537 printer
->queue
->ref
= 0;
1539 InterlockedIncrement(&printer
->queue
->ref
);
1541 printer_handles
[handle
] = printer
;
1544 LeaveCriticalSection(&printer_handles_cs
);
1545 if (!handle
&& printer
) {
1546 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1547 free_printer_entry( printer
);
1550 return (HANDLE
)handle
;
1553 static void old_printer_check( BOOL delete_phase
)
1555 PRINTER_INFO_5W
* pi
;
1556 DWORD needed
, type
, num
, delete, i
, size
;
1557 const DWORD one
= 1;
1561 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1562 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1564 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1565 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1566 for (i
= 0; i
< num
; i
++)
1568 if (!pi
[i
].pPortName
) continue;
1570 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1571 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1574 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1578 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1584 size
= sizeof( delete );
1585 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1589 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1590 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1592 DeletePrinter( hprn
);
1593 ClosePrinter( hprn
);
1595 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1599 HeapFree(GetProcessHeap(), 0, pi
);
1602 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1603 'M','U','T','E','X','_','_','\0'};
1604 static HANDLE init_mutex
;
1606 void WINSPOOL_LoadSystemPrinters(void)
1608 HKEY hkey
, hkeyPrinters
;
1609 DWORD needed
, num
, i
;
1610 WCHAR PrinterName
[256];
1613 #ifdef SONAME_LIBCUPS
1617 /* FIXME: The init code should be moved to spoolsv.exe */
1618 init_mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1621 ERR( "Failed to create mutex\n" );
1624 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1626 WaitForSingleObject( init_mutex
, INFINITE
);
1627 ReleaseMutex( init_mutex
);
1628 TRACE( "Init already done\n" );
1632 /* This ensures that all printer entries have a valid Name value. If causes
1633 problems later if they don't. If one is found to be missed we create one
1634 and set it equal to the name of the key */
1635 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1636 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1637 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1638 for(i
= 0; i
< num
; i
++) {
1639 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, ARRAY_SIZE(PrinterName
)) == ERROR_SUCCESS
) {
1640 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1641 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1642 set_reg_szW(hkey
, NameW
, PrinterName
);
1649 RegCloseKey(hkeyPrinters
);
1652 old_printer_check( FALSE
);
1654 #ifdef SONAME_LIBCUPS
1655 done
= CUPS_LoadPrinters();
1658 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1659 PRINTCAP_LoadPrinters();
1661 old_printer_check( TRUE
);
1663 ReleaseMutex( init_mutex
);
1667 /******************************************************************
1670 * Get the pointer to the specified job.
1671 * Should hold the printer_handles_cs before calling.
1673 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1675 opened_printer_t
*printer
= get_opened_printer(hprn
);
1678 if(!printer
) return NULL
;
1679 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1681 if(job
->job_id
== JobId
)
1687 /***********************************************************
1690 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1693 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1696 Formname
= (dmA
->dmSize
> off_formname
);
1697 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1698 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1699 dmW
->dmDeviceName
, CCHDEVICENAME
);
1701 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1702 dmA
->dmSize
- CCHDEVICENAME
);
1704 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1705 off_formname
- CCHDEVICENAME
);
1706 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1707 dmW
->dmFormName
, CCHFORMNAME
);
1708 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1709 (off_formname
+ CCHFORMNAME
));
1712 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1713 dmA
->dmDriverExtra
);
1717 /******************************************************************
1718 * convert_printerinfo_W_to_A [internal]
1721 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1722 DWORD level
, DWORD outlen
, DWORD numentries
)
1728 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1730 len
= pi_sizeof
[level
] * numentries
;
1731 ptr
= (LPSTR
) out
+ len
;
1734 /* copy the numbers of all PRINTER_INFO_* first */
1735 memcpy(out
, pPrintersW
, len
);
1737 while (id
< numentries
) {
1741 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1742 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1744 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1745 if (piW
->pDescription
) {
1746 piA
->pDescription
= ptr
;
1747 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1748 ptr
, outlen
, NULL
, NULL
);
1754 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1755 ptr
, outlen
, NULL
, NULL
);
1759 if (piW
->pComment
) {
1760 piA
->pComment
= ptr
;
1761 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1762 ptr
, outlen
, NULL
, NULL
);
1771 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1772 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1775 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1776 if (piW
->pServerName
) {
1777 piA
->pServerName
= ptr
;
1778 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1779 ptr
, outlen
, NULL
, NULL
);
1783 if (piW
->pPrinterName
) {
1784 piA
->pPrinterName
= ptr
;
1785 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1786 ptr
, outlen
, NULL
, NULL
);
1790 if (piW
->pShareName
) {
1791 piA
->pShareName
= ptr
;
1792 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1793 ptr
, outlen
, NULL
, NULL
);
1797 if (piW
->pPortName
) {
1798 piA
->pPortName
= ptr
;
1799 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1800 ptr
, outlen
, NULL
, NULL
);
1804 if (piW
->pDriverName
) {
1805 piA
->pDriverName
= ptr
;
1806 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1807 ptr
, outlen
, NULL
, NULL
);
1811 if (piW
->pComment
) {
1812 piA
->pComment
= ptr
;
1813 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1814 ptr
, outlen
, NULL
, NULL
);
1818 if (piW
->pLocation
) {
1819 piA
->pLocation
= ptr
;
1820 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1821 ptr
, outlen
, NULL
, NULL
);
1826 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1828 /* align DEVMODEA to a DWORD boundary */
1829 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1833 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1834 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1835 memcpy(ptr
, dmA
, len
);
1836 HeapFree(GetProcessHeap(), 0, dmA
);
1842 if (piW
->pSepFile
) {
1843 piA
->pSepFile
= ptr
;
1844 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1845 ptr
, outlen
, NULL
, NULL
);
1849 if (piW
->pPrintProcessor
) {
1850 piA
->pPrintProcessor
= ptr
;
1851 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1852 ptr
, outlen
, NULL
, NULL
);
1856 if (piW
->pDatatype
) {
1857 piA
->pDatatype
= ptr
;
1858 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1859 ptr
, outlen
, NULL
, NULL
);
1863 if (piW
->pParameters
) {
1864 piA
->pParameters
= ptr
;
1865 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1866 ptr
, outlen
, NULL
, NULL
);
1870 if (piW
->pSecurityDescriptor
) {
1871 piA
->pSecurityDescriptor
= NULL
;
1872 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1879 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1880 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1882 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1884 if (piW
->pPrinterName
) {
1885 piA
->pPrinterName
= ptr
;
1886 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1887 ptr
, outlen
, NULL
, NULL
);
1891 if (piW
->pServerName
) {
1892 piA
->pServerName
= ptr
;
1893 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1894 ptr
, outlen
, NULL
, NULL
);
1903 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1904 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1906 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1908 if (piW
->pPrinterName
) {
1909 piA
->pPrinterName
= ptr
;
1910 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1911 ptr
, outlen
, NULL
, NULL
);
1915 if (piW
->pPortName
) {
1916 piA
->pPortName
= ptr
;
1917 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1918 ptr
, outlen
, NULL
, NULL
);
1925 case 6: /* 6A and 6W are the same structure */
1930 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1931 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1933 TRACE("(%u) #%u\n", level
, id
);
1934 if (piW
->pszObjectGUID
) {
1935 piA
->pszObjectGUID
= ptr
;
1936 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1937 ptr
, outlen
, NULL
, NULL
);
1947 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1948 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1951 TRACE("(%u) #%u\n", level
, id
);
1952 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1954 /* align DEVMODEA to a DWORD boundary */
1955 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1959 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1960 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1961 memcpy(ptr
, dmA
, len
);
1962 HeapFree(GetProcessHeap(), 0, dmA
);
1972 FIXME("for level %u\n", level
);
1974 pPrintersW
+= pi_sizeof
[level
];
1975 out
+= pi_sizeof
[level
];
1980 /******************************************************************
1981 * convert_driverinfo_W_to_A [internal]
1984 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1985 DWORD level
, DWORD outlen
, DWORD numentries
)
1991 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1993 len
= di_sizeof
[level
] * numentries
;
1994 ptr
= (LPSTR
) out
+ len
;
1997 /* copy the numbers of all PRINTER_INFO_* first */
1998 memcpy(out
, pDriversW
, len
);
2000 #define COPY_STRING(fld) \
2003 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2004 ptr += len; outlen -= len;\
2006 #define COPY_MULTIZ_STRING(fld) \
2007 { LPWSTR p = diW->fld; if (p){ \
2010 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2011 ptr += len; outlen -= len; p += len;\
2013 while(len > 1 && outlen > 0); \
2016 while (id
< numentries
)
2022 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
2023 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
2025 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2032 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
2033 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
2035 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2038 COPY_STRING(pEnvironment
);
2039 COPY_STRING(pDriverPath
);
2040 COPY_STRING(pDataFile
);
2041 COPY_STRING(pConfigFile
);
2046 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
2047 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
2049 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2052 COPY_STRING(pEnvironment
);
2053 COPY_STRING(pDriverPath
);
2054 COPY_STRING(pDataFile
);
2055 COPY_STRING(pConfigFile
);
2056 COPY_STRING(pHelpFile
);
2057 COPY_MULTIZ_STRING(pDependentFiles
);
2058 COPY_STRING(pMonitorName
);
2059 COPY_STRING(pDefaultDataType
);
2064 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
2065 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
2067 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2070 COPY_STRING(pEnvironment
);
2071 COPY_STRING(pDriverPath
);
2072 COPY_STRING(pDataFile
);
2073 COPY_STRING(pConfigFile
);
2074 COPY_STRING(pHelpFile
);
2075 COPY_MULTIZ_STRING(pDependentFiles
);
2076 COPY_STRING(pMonitorName
);
2077 COPY_STRING(pDefaultDataType
);
2078 COPY_MULTIZ_STRING(pszzPreviousNames
);
2083 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
2084 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
2086 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2089 COPY_STRING(pEnvironment
);
2090 COPY_STRING(pDriverPath
);
2091 COPY_STRING(pDataFile
);
2092 COPY_STRING(pConfigFile
);
2097 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
2098 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
2100 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2103 COPY_STRING(pEnvironment
);
2104 COPY_STRING(pDriverPath
);
2105 COPY_STRING(pDataFile
);
2106 COPY_STRING(pConfigFile
);
2107 COPY_STRING(pHelpFile
);
2108 COPY_MULTIZ_STRING(pDependentFiles
);
2109 COPY_STRING(pMonitorName
);
2110 COPY_STRING(pDefaultDataType
);
2111 COPY_MULTIZ_STRING(pszzPreviousNames
);
2112 COPY_STRING(pszMfgName
);
2113 COPY_STRING(pszOEMUrl
);
2114 COPY_STRING(pszHardwareID
);
2115 COPY_STRING(pszProvider
);
2120 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
2121 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
2123 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2126 COPY_STRING(pEnvironment
);
2127 COPY_STRING(pDriverPath
);
2128 COPY_STRING(pDataFile
);
2129 COPY_STRING(pConfigFile
);
2130 COPY_STRING(pHelpFile
);
2131 COPY_MULTIZ_STRING(pDependentFiles
);
2132 COPY_STRING(pMonitorName
);
2133 COPY_STRING(pDefaultDataType
);
2134 COPY_MULTIZ_STRING(pszzPreviousNames
);
2135 COPY_STRING(pszMfgName
);
2136 COPY_STRING(pszOEMUrl
);
2137 COPY_STRING(pszHardwareID
);
2138 COPY_STRING(pszProvider
);
2139 COPY_STRING(pszPrintProcessor
);
2140 COPY_STRING(pszVendorSetup
);
2141 COPY_MULTIZ_STRING(pszzColorProfiles
);
2142 COPY_STRING(pszInfPath
);
2143 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
2149 FIXME("for level %u\n", level
);
2152 pDriversW
+= di_sizeof
[level
];
2153 out
+= di_sizeof
[level
];
2158 #undef COPY_MULTIZ_STRING
2162 /***********************************************************
2165 static void *printer_info_AtoW( const void *data
, DWORD level
)
2168 UNICODE_STRING usBuffer
;
2170 if (!data
) return NULL
;
2172 if (level
< 1 || level
> 9) return NULL
;
2174 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
2175 if (!ret
) return NULL
;
2177 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
2183 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
2184 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
2186 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
2187 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
2188 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
2189 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
2190 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
2191 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
2192 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
2193 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2194 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
2195 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
2196 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
2197 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
2204 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
2205 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
2207 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2212 FIXME( "Unhandled level %d\n", level
);
2213 HeapFree( GetProcessHeap(), 0, ret
);
2220 /***********************************************************
2223 static void free_printer_info( void *data
, DWORD level
)
2231 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
2233 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
2234 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
2235 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
2236 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
2237 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
2238 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
2239 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
2240 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2241 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
2242 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
2243 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
2244 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
2251 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
2253 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2258 FIXME( "Unhandled level %d\n", level
);
2261 HeapFree( GetProcessHeap(), 0, data
);
2265 /******************************************************************
2266 * DeviceCapabilities [WINSPOOL.@]
2267 * DeviceCapabilitiesA [WINSPOOL.@]
2270 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
2271 LPSTR pOutput
, LPDEVMODEA lpdm
)
2275 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice
), debugstr_a(pPort
), cap
, pOutput
, lpdm
);
2277 if (!GDI_CallDeviceCapabilities16
)
2279 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2281 if (!GDI_CallDeviceCapabilities16
) return -1;
2283 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
2285 /* If DC_PAPERSIZE map POINT16s to POINTs */
2286 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
2287 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
2288 POINT
*pt
= (POINT
*)pOutput
;
2290 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
2291 for(i
= 0; i
< ret
; i
++, pt
++)
2296 HeapFree( GetProcessHeap(), 0, tmp
);
2302 /*****************************************************************************
2303 * DeviceCapabilitiesW [WINSPOOL.@]
2305 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2308 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2309 WORD fwCapability
, LPWSTR pOutput
,
2310 const DEVMODEW
*pDevMode
)
2312 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
2313 LPSTR pDeviceA
= strdupWtoA(pDevice
);
2314 LPSTR pPortA
= strdupWtoA(pPort
);
2317 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice
), debugstr_w(pPort
), fwCapability
, pOutput
, pDevMode
);
2319 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
2320 fwCapability
== DC_FILEDEPENDENCIES
||
2321 fwCapability
== DC_PAPERNAMES
)) {
2322 /* These need A -> W translation */
2325 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2329 switch(fwCapability
) {
2334 case DC_FILEDEPENDENCIES
:
2338 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2339 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2341 for(i
= 0; i
< ret
; i
++)
2342 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2343 pOutput
+ (i
* size
), size
);
2344 HeapFree(GetProcessHeap(), 0, pOutputA
);
2346 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2347 (LPSTR
)pOutput
, dmA
);
2349 HeapFree(GetProcessHeap(),0,pPortA
);
2350 HeapFree(GetProcessHeap(),0,pDeviceA
);
2351 HeapFree(GetProcessHeap(),0,dmA
);
2355 /******************************************************************
2356 * DocumentPropertiesA [WINSPOOL.@]
2358 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2360 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2361 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2362 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2364 LPSTR lpName
= pDeviceName
, dupname
= NULL
;
2365 static CHAR port
[] = "LPT1:";
2368 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2369 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2372 if(!pDeviceName
|| !*pDeviceName
) {
2373 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2375 ERR("no name from hPrinter?\n");
2376 SetLastError(ERROR_INVALID_HANDLE
);
2379 lpName
= dupname
= strdupWtoA(lpNameW
);
2382 if (!GDI_CallExtDeviceMode16
)
2384 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2386 if (!GDI_CallExtDeviceMode16
) {
2387 ERR("No CallExtDeviceMode16?\n");
2392 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2393 pDevModeInput
, NULL
, fMode
);
2396 HeapFree(GetProcessHeap(), 0, dupname
);
2401 /*****************************************************************************
2402 * DocumentPropertiesW (WINSPOOL.@)
2404 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2406 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2408 LPDEVMODEW pDevModeOutput
,
2409 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2412 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2413 LPDEVMODEA pDevModeInputA
;
2414 LPDEVMODEA pDevModeOutputA
= NULL
;
2417 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2418 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2420 if(pDevModeOutput
) {
2421 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2422 if(ret
< 0) return ret
;
2423 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2425 pDevModeInputA
= (fMode
& DM_IN_BUFFER
) ? DEVMODEdupWtoA(pDevModeInput
) : NULL
;
2426 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2427 pDevModeInputA
, fMode
);
2428 if(pDevModeOutput
) {
2429 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2430 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2432 if(fMode
== 0 && ret
> 0)
2433 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2434 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2435 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2439 /*****************************************************************************
2440 * IsValidDevmodeA [WINSPOOL.@]
2442 * Validate a DEVMODE structure and fix errors if possible.
2445 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA pDevMode
, SIZE_T size
)
2447 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2455 /*****************************************************************************
2456 * IsValidDevmodeW [WINSPOOL.@]
2458 * Validate a DEVMODE structure and fix errors if possible.
2461 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW dm
, SIZE_T size
)
2469 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
2470 { DM_ORIENTATION
, F_SIZE(u1
.s1
.dmOrientation
) },
2471 { DM_PAPERSIZE
, F_SIZE(u1
.s1
.dmPaperSize
) },
2472 { DM_PAPERLENGTH
, F_SIZE(u1
.s1
.dmPaperLength
) },
2473 { DM_PAPERWIDTH
, F_SIZE(u1
.s1
.dmPaperWidth
) },
2474 { DM_SCALE
, F_SIZE(u1
.s1
.dmScale
) },
2475 { DM_COPIES
, F_SIZE(u1
.s1
.dmCopies
) },
2476 { DM_DEFAULTSOURCE
, F_SIZE(u1
.s1
.dmDefaultSource
) },
2477 { DM_PRINTQUALITY
, F_SIZE(u1
.s1
.dmPrintQuality
) },
2478 { DM_POSITION
, F_SIZE(u1
.s2
.dmPosition
) },
2479 { DM_DISPLAYORIENTATION
, F_SIZE(u1
.s2
.dmDisplayOrientation
) },
2480 { DM_DISPLAYFIXEDOUTPUT
, F_SIZE(u1
.s2
.dmDisplayFixedOutput
) },
2481 { DM_COLOR
, F_SIZE(dmColor
) },
2482 { DM_DUPLEX
, F_SIZE(dmDuplex
) },
2483 { DM_YRESOLUTION
, F_SIZE(dmYResolution
) },
2484 { DM_TTOPTION
, F_SIZE(dmTTOption
) },
2485 { DM_COLLATE
, F_SIZE(dmCollate
) },
2486 { DM_FORMNAME
, F_SIZE(dmFormName
) },
2487 { DM_LOGPIXELS
, F_SIZE(dmLogPixels
) },
2488 { DM_BITSPERPEL
, F_SIZE(dmBitsPerPel
) },
2489 { DM_PELSWIDTH
, F_SIZE(dmPelsWidth
) },
2490 { DM_PELSHEIGHT
, F_SIZE(dmPelsHeight
) },
2491 { DM_DISPLAYFLAGS
, F_SIZE(u2
.dmDisplayFlags
) },
2492 { DM_NUP
, F_SIZE(u2
.dmNup
) },
2493 { DM_DISPLAYFREQUENCY
, F_SIZE(dmDisplayFrequency
) },
2494 { DM_ICMMETHOD
, F_SIZE(dmICMMethod
) },
2495 { DM_ICMINTENT
, F_SIZE(dmICMIntent
) },
2496 { DM_MEDIATYPE
, F_SIZE(dmMediaType
) },
2497 { DM_DITHERTYPE
, F_SIZE(dmDitherType
) },
2498 { DM_PANNINGWIDTH
, F_SIZE(dmPanningWidth
) },
2499 { DM_PANNINGHEIGHT
, F_SIZE(dmPanningHeight
) }
2504 if (!dm
) return FALSE
;
2505 if (size
< FIELD_OFFSET(DEVMODEW
, dmFields
) + sizeof(dm
->dmFields
)) return FALSE
;
2507 for (i
= 0; i
< ARRAY_SIZE(map
); i
++)
2508 if ((dm
->dmFields
& map
[i
].flag
) && size
< map
[i
].size
)
2514 /******************************************************************
2515 * OpenPrinterA [WINSPOOL.@]
2520 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2521 LPPRINTER_DEFAULTSA pDefault
)
2523 UNICODE_STRING lpPrinterNameW
;
2524 UNICODE_STRING usBuffer
;
2525 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2526 PWSTR pwstrPrinterNameW
;
2529 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName
), phPrinter
, pDefault
);
2531 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2534 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2535 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2536 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2537 pDefaultW
= &DefaultW
;
2539 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2541 RtlFreeUnicodeString(&usBuffer
);
2542 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2544 RtlFreeUnicodeString(&lpPrinterNameW
);
2548 /******************************************************************
2549 * OpenPrinterW [WINSPOOL.@]
2551 * Open a Printer / Printserver or a Printer-Object
2554 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2555 * phPrinter [O] The resulting Handle is stored here
2556 * pDefault [I] PTR to Default Printer Settings or NULL
2563 * lpPrinterName is one of:
2564 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2565 *| Printer: "PrinterName"
2566 *| Printer-Object: "PrinterName,Job xxx"
2567 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2568 *| XcvPort: "Servername,XcvPort PortName"
2571 *| Printer-Object not supported
2572 *| pDefaults is ignored
2575 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2579 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2582 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2583 SetLastError(ERROR_INVALID_PARAMETER
);
2587 /* Get the unique handle of the printer or Printserver */
2588 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2590 if (*phPrinter
&& WINSPOOL_GetOpenedPrinterRegKey( *phPrinter
, &key
) == ERROR_SUCCESS
)
2592 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2594 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2595 WaitForSingleObject( init_mutex
, INFINITE
);
2596 status
= get_dword_from_reg( key
, StatusW
);
2597 set_reg_DWORD( key
, StatusW
, status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2598 ReleaseMutex( init_mutex
);
2599 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2600 update_driver( *phPrinter
);
2604 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2605 return (*phPrinter
!= 0);
2608 /******************************************************************
2609 * AddMonitorA [WINSPOOL.@]
2614 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2616 LPWSTR nameW
= NULL
;
2619 LPMONITOR_INFO_2A mi2a
;
2620 MONITOR_INFO_2W mi2w
;
2622 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2623 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2624 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2625 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2626 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2629 SetLastError(ERROR_INVALID_LEVEL
);
2633 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2639 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2640 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2641 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2644 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2646 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2647 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2648 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2650 if (mi2a
->pEnvironment
) {
2651 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2652 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2653 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2655 if (mi2a
->pDLLName
) {
2656 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2657 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2658 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2661 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2663 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2664 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2665 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2667 HeapFree(GetProcessHeap(), 0, nameW
);
2671 /******************************************************************************
2672 * AddMonitorW [WINSPOOL.@]
2674 * Install a Printmonitor
2677 * pName [I] Servername or NULL (local Computer)
2678 * Level [I] Structure-Level (Must be 2)
2679 * pMonitors [I] PTR to MONITOR_INFO_2
2686 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2689 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2691 LPMONITOR_INFO_2W mi2w
;
2693 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2694 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2695 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2696 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2697 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2699 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2702 SetLastError(ERROR_INVALID_LEVEL
);
2706 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2711 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2714 /******************************************************************
2715 * DeletePrinterDriverA [WINSPOOL.@]
2718 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2720 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2723 /******************************************************************
2724 * DeletePrinterDriverW [WINSPOOL.@]
2727 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2729 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2732 /******************************************************************
2733 * DeleteMonitorA [WINSPOOL.@]
2735 * See DeleteMonitorW.
2738 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2740 LPWSTR nameW
= NULL
;
2741 LPWSTR EnvironmentW
= NULL
;
2742 LPWSTR MonitorNameW
= NULL
;
2747 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2748 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2749 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2753 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2754 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2755 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2758 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2759 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2760 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2763 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2765 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2766 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2767 HeapFree(GetProcessHeap(), 0, nameW
);
2771 /******************************************************************
2772 * DeleteMonitorW [WINSPOOL.@]
2774 * Delete a specific Printmonitor from a Printing-Environment
2777 * pName [I] Servername or NULL (local Computer)
2778 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2779 * pMonitorName [I] Name of the Monitor, that should be deleted
2786 * pEnvironment is ignored in Windows for the local Computer.
2789 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2792 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2793 debugstr_w(pMonitorName
));
2795 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2797 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2801 /******************************************************************
2802 * DeletePortA [WINSPOOL.@]
2807 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2809 LPWSTR nameW
= NULL
;
2810 LPWSTR portW
= NULL
;
2814 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2816 /* convert servername to unicode */
2818 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2819 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2820 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2823 /* convert portname to unicode */
2825 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2826 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2827 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2830 res
= DeletePortW(nameW
, hWnd
, portW
);
2831 HeapFree(GetProcessHeap(), 0, nameW
);
2832 HeapFree(GetProcessHeap(), 0, portW
);
2836 /******************************************************************
2837 * DeletePortW [WINSPOOL.@]
2839 * Delete a specific Port
2842 * pName [I] Servername or NULL (local Computer)
2843 * hWnd [I] Handle to parent Window for the Dialog-Box
2844 * pPortName [I] Name of the Port, that should be deleted
2851 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2853 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2855 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2858 SetLastError(RPC_X_NULL_REF_POINTER
);
2862 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2865 /******************************************************************************
2866 * WritePrinter [WINSPOOL.@]
2868 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2870 opened_printer_t
*printer
;
2873 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2875 EnterCriticalSection(&printer_handles_cs
);
2876 printer
= get_opened_printer(hPrinter
);
2879 SetLastError(ERROR_INVALID_HANDLE
);
2885 SetLastError(ERROR_SPL_NO_STARTDOC
);
2889 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2891 LeaveCriticalSection(&printer_handles_cs
);
2895 /*****************************************************************************
2896 * AddFormA [WINSPOOL.@]
2898 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2900 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2904 /*****************************************************************************
2905 * AddFormW [WINSPOOL.@]
2907 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2909 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2913 /*****************************************************************************
2914 * AddJobA [WINSPOOL.@]
2916 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2919 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2923 SetLastError(ERROR_INVALID_LEVEL
);
2927 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2930 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2931 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2932 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2933 if(*pcbNeeded
> cbBuf
) {
2934 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2937 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2938 addjobA
->JobId
= addjobW
->JobId
;
2939 addjobA
->Path
= (char *)(addjobA
+ 1);
2940 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2946 /*****************************************************************************
2947 * AddJobW [WINSPOOL.@]
2949 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2951 opened_printer_t
*printer
;
2954 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2955 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2956 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2958 ADDJOB_INFO_1W
*addjob
;
2960 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2962 EnterCriticalSection(&printer_handles_cs
);
2964 printer
= get_opened_printer(hPrinter
);
2967 SetLastError(ERROR_INVALID_HANDLE
);
2972 SetLastError(ERROR_INVALID_LEVEL
);
2976 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2980 job
->job_id
= InterlockedIncrement(&next_job_id
);
2982 len
= GetSystemDirectoryW(path
, ARRAY_SIZE(path
));
2983 if(path
[len
- 1] != '\\')
2985 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2986 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2988 len
= strlenW(filename
);
2989 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2990 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2991 job
->portname
= NULL
;
2992 job
->document_title
= strdupW(default_doc_title
);
2993 job
->printer_name
= strdupW(printer
->name
);
2994 job
->devmode
= dup_devmode( printer
->devmode
);
2995 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2997 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2998 if(*pcbNeeded
<= cbBuf
) {
2999 addjob
= (ADDJOB_INFO_1W
*)pData
;
3000 addjob
->JobId
= job
->job_id
;
3001 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
3002 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
3005 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3008 LeaveCriticalSection(&printer_handles_cs
);
3012 /*****************************************************************************
3013 * GetPrintProcessorDirectoryA [WINSPOOL.@]
3015 * Return the PATH for the Print-Processors
3017 * See GetPrintProcessorDirectoryW.
3021 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
3022 DWORD level
, LPBYTE Info
,
3023 DWORD cbBuf
, LPDWORD pcbNeeded
)
3025 LPWSTR serverW
= NULL
;
3030 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
3031 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
3035 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
3036 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3037 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
3041 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
3042 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3043 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
3046 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3047 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3049 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
3052 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
3053 cbBuf
, NULL
, NULL
) > 0;
3056 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
3057 HeapFree(GetProcessHeap(), 0, envW
);
3058 HeapFree(GetProcessHeap(), 0, serverW
);
3062 /*****************************************************************************
3063 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3065 * Return the PATH for the Print-Processors
3068 * server [I] Servername (NT only) or NULL (local Computer)
3069 * env [I] Printing-Environment (see below) or NULL (Default)
3070 * level [I] Structure-Level (must be 1)
3071 * Info [O] PTR to Buffer that receives the Result
3072 * cbBuf [I] Size of Buffer at "Info"
3073 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3074 * required for the Buffer at "Info"
3077 * Success: TRUE and in pcbNeeded the Bytes used in Info
3078 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3079 * if cbBuf is too small
3081 * Native Values returned in Info on Success:
3082 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3083 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3084 *| win9x(Windows 4.0): "%winsysdir%"
3086 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3089 * Only NULL or "" is supported for server
3092 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
3093 DWORD level
, LPBYTE Info
,
3094 DWORD cbBuf
, LPDWORD pcbNeeded
)
3097 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
3098 Info
, cbBuf
, pcbNeeded
);
3100 if ((backend
== NULL
) && !load_backend()) return FALSE
;
3103 /* (Level != 1) is ignored in win9x */
3104 SetLastError(ERROR_INVALID_LEVEL
);
3108 if (pcbNeeded
== NULL
) {
3109 /* (pcbNeeded == NULL) is ignored in win9x */
3110 SetLastError(RPC_X_NULL_REF_POINTER
);
3114 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
3117 /*****************************************************************************
3118 * WINSPOOL_OpenDriverReg [internal]
3120 * opens the registry for the printer drivers depending on the given input
3121 * variable pEnvironment
3124 * the opened hkey on success
3127 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
3131 const printenv_t
* env
;
3133 TRACE("(%s)\n", debugstr_w(pEnvironment
));
3135 env
= validate_envW(pEnvironment
);
3136 if (!env
) return NULL
;
3138 buffer
= HeapAlloc( GetProcessHeap(), 0,
3139 (strlenW(DriversW
) + strlenW(env
->envname
) +
3140 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
3142 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
3143 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
3144 HeapFree(GetProcessHeap(), 0, buffer
);
3149 /*****************************************************************************
3150 * set_devices_and_printerports [internal]
3152 * set the [Devices] and [PrinterPorts] entries for a printer.
3155 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
3157 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
3161 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
3163 /* FIXME: the driver must change to "winspool" */
3164 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
3166 lstrcpyW(devline
, driver_nt
);
3167 lstrcatW(devline
, commaW
);
3168 lstrcatW(devline
, pi
->pPortName
);
3170 TRACE("using %s\n", debugstr_w(devline
));
3171 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
3172 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3173 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3177 lstrcatW(devline
, timeout_15_45
);
3178 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
3179 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3180 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3183 HeapFree(GetProcessHeap(), 0, devline
);
3187 /*****************************************************************************
3188 * AddPrinterW [WINSPOOL.@]
3190 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3192 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
3195 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
3198 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
3200 if(pName
&& *pName
) {
3201 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
3202 SetLastError(ERROR_INVALID_PARAMETER
);
3206 ERR("Level = %d, unsupported!\n", Level
);
3207 SetLastError(ERROR_INVALID_LEVEL
);
3211 SetLastError(ERROR_INVALID_PARAMETER
);
3214 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3216 ERR("Can't create Printers key\n");
3219 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3220 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
3221 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3222 RegCloseKey(hkeyPrinter
);
3223 RegCloseKey(hkeyPrinters
);
3226 RegCloseKey(hkeyPrinter
);
3228 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
3230 ERR("Can't create Drivers key\n");
3231 RegCloseKey(hkeyPrinters
);
3234 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3236 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3237 RegCloseKey(hkeyPrinters
);
3238 RegCloseKey(hkeyDrivers
);
3239 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3242 RegCloseKey(hkeyDriver
);
3243 RegCloseKey(hkeyDrivers
);
3245 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3246 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3247 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3248 RegCloseKey(hkeyPrinters
);
3252 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3254 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3255 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3256 RegCloseKey(hkeyPrinters
);
3260 set_devices_and_printerports(pi
);
3262 set_reg_DWORD(hkeyPrinter
, AttributesW
, pi
->Attributes
);
3263 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3264 set_reg_DWORD(hkeyPrinter
, Default_PriorityW
, pi
->DefaultPriority
);
3265 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3266 set_reg_DWORD(hkeyPrinter
, dnsTimeoutW
, 0);
3267 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3268 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3269 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3270 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3271 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3272 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3273 set_reg_DWORD(hkeyPrinter
, PriorityW
, pi
->Priority
);
3274 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3275 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3276 set_reg_DWORD(hkeyPrinter
, StartTimeW
, pi
->StartTime
);
3277 set_reg_DWORD(hkeyPrinter
, StatusW
, pi
->Status
);
3278 set_reg_DWORD(hkeyPrinter
, txTimeoutW
, 0);
3279 set_reg_DWORD(hkeyPrinter
, UntilTimeW
, pi
->UntilTime
);
3281 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3285 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3286 size
= sizeof(DEVMODEW
);
3292 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3294 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
3296 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3297 HeapFree( GetProcessHeap(), 0, dm
);
3302 /* set devmode to printer name */
3303 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3307 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
3308 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
3310 RegCloseKey(hkeyPrinter
);
3311 RegCloseKey(hkeyPrinters
);
3312 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3313 ERR("OpenPrinter failing\n");
3319 /*****************************************************************************
3320 * AddPrinterA [WINSPOOL.@]
3322 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3324 UNICODE_STRING pNameW
;
3326 PRINTER_INFO_2W
*piW
;
3327 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3330 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
3332 ERR("Level = %d, unsupported!\n", Level
);
3333 SetLastError(ERROR_INVALID_LEVEL
);
3336 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3337 piW
= printer_info_AtoW( piA
, Level
);
3339 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3341 free_printer_info( piW
, Level
);
3342 RtlFreeUnicodeString(&pNameW
);
3347 /*****************************************************************************
3348 * ClosePrinter [WINSPOOL.@]
3350 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3352 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3353 opened_printer_t
*printer
= NULL
;
3355 TRACE("(%p)\n", hPrinter
);
3357 EnterCriticalSection(&printer_handles_cs
);
3359 if ((i
> 0) && (i
<= nb_printer_handles
))
3360 printer
= printer_handles
[i
- 1];
3365 struct list
*cursor
, *cursor2
;
3367 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
3370 EndDocPrinter(hPrinter
);
3372 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3374 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3376 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3377 ScheduleJob(hPrinter
, job
->job_id
);
3379 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3382 if (printer
->backend_printer
) {
3383 backend
->fpClosePrinter(printer
->backend_printer
);
3386 free_printer_entry( printer
);
3387 printer_handles
[i
- 1] = NULL
;
3388 LeaveCriticalSection(&printer_handles_cs
);
3392 LeaveCriticalSection(&printer_handles_cs
);
3393 SetLastError(ERROR_INVALID_HANDLE
);
3397 /*****************************************************************************
3398 * DeleteFormA [WINSPOOL.@]
3400 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3402 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3406 /*****************************************************************************
3407 * DeleteFormW [WINSPOOL.@]
3409 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3411 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3415 /*****************************************************************************
3416 * DeletePrinter [WINSPOOL.@]
3418 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3420 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3421 HKEY hkeyPrinters
, hkey
;
3422 WCHAR def
[MAX_PATH
];
3423 DWORD size
= ARRAY_SIZE(def
);
3426 SetLastError(ERROR_INVALID_HANDLE
);
3429 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3430 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3431 RegCloseKey(hkeyPrinters
);
3434 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3435 RegDeleteValueW(hkey
, lpNameW
);
3439 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3440 RegDeleteValueW(hkey
, lpNameW
);
3444 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
3446 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
3448 RegDeleteValueW( hkey
, deviceW
);
3449 RegCloseKey( hkey
);
3451 SetDefaultPrinterW( NULL
);
3457 /*****************************************************************************
3458 * SetPrinterA [WINSPOOL.@]
3460 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3467 dataW
= printer_info_AtoW( data
, level
);
3468 if (!dataW
) return FALSE
;
3471 ret
= SetPrinterW( printer
, level
, dataW
, command
);
3473 if (dataW
!= data
) free_printer_info( dataW
, level
);
3478 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
3480 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
3481 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
3482 set_reg_szW( key
, PortW
, pi
->pPortName
);
3483 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
3484 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
3485 set_reg_szW( key
, LocationW
, pi
->pLocation
);
3488 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3490 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
3491 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
3492 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
3493 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
3495 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
3496 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
3497 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
3498 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
3499 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
3502 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
3504 if (!pi
->pDevMode
) return FALSE
;
3506 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3510 /******************************************************************************
3511 * SetPrinterW [WINSPOOL.@]
3513 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3518 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
3520 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
3522 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
3529 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
3530 set_printer_2( key
, pi2
);
3536 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3537 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3541 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
3542 ret
= set_printer_9( key
, pi
);
3547 FIXME( "Unimplemented level %d\n", level
);
3548 SetLastError( ERROR_INVALID_LEVEL
);
3555 /*****************************************************************************
3556 * SetJobA [WINSPOOL.@]
3558 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3559 LPBYTE pJob
, DWORD Command
)
3563 UNICODE_STRING usBuffer
;
3565 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3567 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3568 are all ignored by SetJob, so we don't bother copying them */
3576 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3577 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3579 JobW
= (LPBYTE
)info1W
;
3580 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3581 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3582 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3583 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3584 info1W
->Status
= info1A
->Status
;
3585 info1W
->Priority
= info1A
->Priority
;
3586 info1W
->Position
= info1A
->Position
;
3587 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3592 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3593 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3595 JobW
= (LPBYTE
)info2W
;
3596 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3597 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3598 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3599 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3600 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3601 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3602 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3603 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3604 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3605 info2W
->Status
= info2A
->Status
;
3606 info2W
->Priority
= info2A
->Priority
;
3607 info2W
->Position
= info2A
->Position
;
3608 info2W
->StartTime
= info2A
->StartTime
;
3609 info2W
->UntilTime
= info2A
->UntilTime
;
3610 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3614 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3615 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3618 SetLastError(ERROR_INVALID_LEVEL
);
3622 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3628 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3629 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3630 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3631 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3632 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3637 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3638 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3639 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3640 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3641 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3642 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3643 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3644 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3645 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3649 HeapFree(GetProcessHeap(), 0, JobW
);
3654 /*****************************************************************************
3655 * SetJobW [WINSPOOL.@]
3657 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3658 LPBYTE pJob
, DWORD Command
)
3663 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3664 FIXME("Ignoring everything other than document title\n");
3666 EnterCriticalSection(&printer_handles_cs
);
3667 job
= get_job(hPrinter
, JobId
);
3677 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3678 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3679 job
->document_title
= strdupW(info1
->pDocument
);
3684 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3685 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3686 job
->document_title
= strdupW(info2
->pDocument
);
3687 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3688 job
->devmode
= dup_devmode( info2
->pDevMode
);
3694 SetLastError(ERROR_INVALID_LEVEL
);
3699 LeaveCriticalSection(&printer_handles_cs
);
3703 /*****************************************************************************
3704 * EndDocPrinter [WINSPOOL.@]
3706 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3708 opened_printer_t
*printer
;
3710 TRACE("(%p)\n", hPrinter
);
3712 EnterCriticalSection(&printer_handles_cs
);
3714 printer
= get_opened_printer(hPrinter
);
3717 SetLastError(ERROR_INVALID_HANDLE
);
3723 SetLastError(ERROR_SPL_NO_STARTDOC
);
3727 CloseHandle(printer
->doc
->hf
);
3728 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3729 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3730 printer
->doc
= NULL
;
3733 LeaveCriticalSection(&printer_handles_cs
);
3737 /*****************************************************************************
3738 * EndPagePrinter [WINSPOOL.@]
3740 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3742 FIXME("(%p): stub\n", hPrinter
);
3746 /*****************************************************************************
3747 * StartDocPrinterA [WINSPOOL.@]
3749 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3751 UNICODE_STRING usBuffer
;
3753 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3756 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3757 or one (DOC_INFO_3) extra DWORDs */
3761 doc2W
.JobId
= doc2
->JobId
;
3764 doc2W
.dwMode
= doc2
->dwMode
;
3767 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3768 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3769 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3773 SetLastError(ERROR_INVALID_LEVEL
);
3777 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3779 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3780 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3781 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3786 /*****************************************************************************
3787 * StartDocPrinterW [WINSPOOL.@]
3789 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3791 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3792 opened_printer_t
*printer
;
3793 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3794 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3795 JOB_INFO_1W job_info
;
3796 DWORD needed
, ret
= 0;
3801 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3802 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3803 debugstr_w(doc
->pDatatype
));
3805 if(Level
< 1 || Level
> 3)
3807 SetLastError(ERROR_INVALID_LEVEL
);
3811 EnterCriticalSection(&printer_handles_cs
);
3812 printer
= get_opened_printer(hPrinter
);
3815 SetLastError(ERROR_INVALID_HANDLE
);
3821 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3825 /* Even if we're printing to a file we still add a print job, we'll
3826 just ignore the spool file name */
3828 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3830 ERR("AddJob failed gle %u\n", GetLastError());
3834 /* use pOutputFile only, when it is a real filename */
3835 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3836 filename
= doc
->pOutputFile
;
3838 filename
= addjob
->Path
;
3840 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3841 if(hf
== INVALID_HANDLE_VALUE
)
3844 memset(&job_info
, 0, sizeof(job_info
));
3845 job_info
.pDocument
= doc
->pDocName
;
3846 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3848 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3849 printer
->doc
->hf
= hf
;
3850 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3851 job
= get_job(hPrinter
, ret
);
3852 job
->portname
= strdupW(doc
->pOutputFile
);
3855 LeaveCriticalSection(&printer_handles_cs
);
3860 /*****************************************************************************
3861 * StartPagePrinter [WINSPOOL.@]
3863 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3865 FIXME("(%p): stub\n", hPrinter
);
3869 /*****************************************************************************
3870 * GetFormA [WINSPOOL.@]
3872 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3873 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3875 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3876 Level
,pForm
,cbBuf
,pcbNeeded
);
3880 /*****************************************************************************
3881 * GetFormW [WINSPOOL.@]
3883 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3884 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3886 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3887 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3891 /*****************************************************************************
3892 * SetFormA [WINSPOOL.@]
3894 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3897 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3901 /*****************************************************************************
3902 * SetFormW [WINSPOOL.@]
3904 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3907 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3911 /*****************************************************************************
3912 * ReadPrinter [WINSPOOL.@]
3914 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3915 LPDWORD pNoBytesRead
)
3917 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3921 /*****************************************************************************
3922 * ResetPrinterA [WINSPOOL.@]
3924 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3926 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3930 /*****************************************************************************
3931 * ResetPrinterW [WINSPOOL.@]
3933 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3935 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3939 /*****************************************************************************
3940 * get_filename_from_reg [internal]
3942 * Get ValueName from hkey storing result in out
3943 * when the Value in the registry has only a filename, use driverdir as prefix
3944 * outlen is space left in out
3945 * String is stored either as unicode or ascii
3949 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3950 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3952 WCHAR filename
[MAX_PATH
];
3956 LPWSTR buffer
= filename
;
3960 size
= sizeof(filename
);
3962 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3963 if (ret
== ERROR_MORE_DATA
) {
3964 TRACE("need dynamic buffer: %u\n", size
);
3965 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3967 /* No Memory is bad */
3971 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3974 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3975 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3981 /* do we have a full path ? */
3982 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3983 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3986 /* we must build the full Path */
3988 if ((out
) && (outlen
> dirlen
)) {
3989 lstrcpyW((LPWSTR
)out
, driverdir
);
3997 /* write the filename */
3998 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3999 if ((out
) && (outlen
>= size
)) {
4000 lstrcpyW((LPWSTR
)out
, ptr
);
4007 ptr
+= lstrlenW(ptr
)+1;
4008 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
4011 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
4013 /* write the multisz-termination */
4014 if (type
== REG_MULTI_SZ
) {
4015 size
= sizeof(WCHAR
);
4018 if (out
&& (outlen
>= size
)) {
4019 memset (out
, 0, size
);
4025 /*****************************************************************************
4026 * WINSPOOL_GetStringFromReg
4028 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4029 * String is stored as unicode.
4031 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
4032 DWORD buflen
, DWORD
*needed
)
4034 DWORD sz
= buflen
, type
;
4037 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4038 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
4039 WARN("Got ret = %d\n", ret
);
4043 /* add space for terminating '\0' */
4044 sz
+= sizeof(WCHAR
);
4048 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
4053 /*****************************************************************************
4054 * WINSPOOL_GetDefaultDevMode
4056 * Get a default DevMode values for wineps.
4058 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr
, DWORD buflen
, DWORD
*needed
)
4060 static const WCHAR winepsW
[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4062 if (buflen
>= sizeof(DEVMODEW
))
4064 DEVMODEW
*dm
= (DEVMODEW
*)ptr
;
4066 /* the driver will update registry with real values */
4067 memset(dm
, 0, sizeof(*dm
));
4068 dm
->dmSize
= sizeof(*dm
);
4069 lstrcpyW(dm
->dmDeviceName
, winepsW
);
4071 *needed
= sizeof(DEVMODEW
);
4074 /*****************************************************************************
4075 * WINSPOOL_GetDevModeFromReg
4077 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4078 * DevMode is stored either as unicode or ascii.
4080 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
4082 DWORD buflen
, DWORD
*needed
)
4084 DWORD sz
= buflen
, type
;
4087 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
4088 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4089 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
4090 if (sz
< sizeof(DEVMODEA
))
4092 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
4095 /* ensures that dmSize is not erratically bogus if registry is invalid */
4096 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
4097 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
4098 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
4099 if (ptr
&& (buflen
>= sz
)) {
4100 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
4101 memcpy(ptr
, dmW
, sz
);
4102 HeapFree(GetProcessHeap(),0,dmW
);
4108 /*********************************************************************
4109 * WINSPOOL_GetPrinter_1
4111 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4113 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
4114 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4116 DWORD size
, left
= cbBuf
;
4117 BOOL space
= (cbBuf
> 0);
4122 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4123 if(space
&& size
<= left
) {
4124 pi1
->pName
= (LPWSTR
)ptr
;
4132 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4133 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4134 if(space
&& size
<= left
) {
4135 pi1
->pDescription
= (LPWSTR
)ptr
;
4143 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4144 if(space
&& size
<= left
) {
4145 pi1
->pComment
= (LPWSTR
)ptr
;
4153 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
4155 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
4156 memset(pi1
, 0, sizeof(*pi1
));
4160 /*********************************************************************
4161 * WINSPOOL_GetPrinter_2
4163 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4165 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
4166 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4168 DWORD size
, left
= cbBuf
;
4169 BOOL space
= (cbBuf
> 0);
4174 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4175 if(space
&& size
<= left
) {
4176 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4183 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
4184 if(space
&& size
<= left
) {
4185 pi2
->pShareName
= (LPWSTR
)ptr
;
4192 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4193 if(space
&& size
<= left
) {
4194 pi2
->pPortName
= (LPWSTR
)ptr
;
4201 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
4202 if(space
&& size
<= left
) {
4203 pi2
->pDriverName
= (LPWSTR
)ptr
;
4210 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4211 if(space
&& size
<= left
) {
4212 pi2
->pComment
= (LPWSTR
)ptr
;
4219 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
4220 if(space
&& size
<= left
) {
4221 pi2
->pLocation
= (LPWSTR
)ptr
;
4228 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
4229 if(space
&& size
<= left
) {
4230 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4239 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
4240 if(space
&& size
<= left
) {
4241 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4248 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
4249 if(space
&& size
<= left
) {
4250 pi2
->pSepFile
= (LPWSTR
)ptr
;
4257 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
4258 if(space
&& size
<= left
) {
4259 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4266 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
4267 if(space
&& size
<= left
) {
4268 pi2
->pDatatype
= (LPWSTR
)ptr
;
4275 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
4276 if(space
&& size
<= left
) {
4277 pi2
->pParameters
= (LPWSTR
)ptr
;
4285 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4286 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
4287 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
4288 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
4289 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
4292 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4293 memset(pi2
, 0, sizeof(*pi2
));
4298 /*********************************************************************
4299 * WINSPOOL_GetPrinter_4
4301 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4303 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4304 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4306 DWORD size
, left
= cbBuf
;
4307 BOOL space
= (cbBuf
> 0);
4312 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4313 if(space
&& size
<= left
) {
4314 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4322 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4325 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4326 memset(pi4
, 0, sizeof(*pi4
));
4331 /*********************************************************************
4332 * WINSPOOL_GetPrinter_5
4334 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4336 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4337 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4339 DWORD size
, left
= cbBuf
;
4340 BOOL space
= (cbBuf
> 0);
4345 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4346 if(space
&& size
<= left
) {
4347 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4354 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4355 if(space
&& size
<= left
) {
4356 pi5
->pPortName
= (LPWSTR
)ptr
;
4364 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4365 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
4366 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
4369 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4370 memset(pi5
, 0, sizeof(*pi5
));
4375 /*********************************************************************
4376 * WINSPOOL_GetPrinter_7
4378 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4380 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4381 DWORD cbBuf
, LPDWORD pcbNeeded
)
4383 DWORD size
, left
= cbBuf
;
4384 BOOL space
= (cbBuf
> 0);
4389 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
4392 size
= sizeof(pi7
->pszObjectGUID
);
4394 if (space
&& size
<= left
) {
4395 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4402 /* We do not have a Directory Service */
4403 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4406 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4407 memset(pi7
, 0, sizeof(*pi7
));
4412 /*********************************************************************
4413 * WINSPOOL_GetPrinter_9
4415 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4417 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4418 DWORD cbBuf
, LPDWORD pcbNeeded
)
4421 BOOL space
= (cbBuf
> 0);
4425 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
4426 if(space
&& size
<= cbBuf
) {
4427 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4434 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
4435 if(space
&& size
<= cbBuf
) {
4436 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4442 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4443 memset(pi9
, 0, sizeof(*pi9
));
4448 /*****************************************************************************
4449 * GetPrinterW [WINSPOOL.@]
4451 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4452 DWORD cbBuf
, LPDWORD pcbNeeded
)
4454 DWORD size
, needed
= 0, err
;
4459 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4461 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
4464 SetLastError( err
);
4471 PRINTER_INFO_1W
*pi1
= (PRINTER_INFO_1W
*)pPrinter
;
4473 size
= sizeof(PRINTER_INFO_1W
);
4474 if (size
<= cbBuf
) {
4475 ptr
= pPrinter
+ size
;
4477 memset(pPrinter
, 0, size
);
4482 ret
= WINSPOOL_GetPrinter_1(hkeyPrinter
, pi1
, ptr
, cbBuf
, &needed
);
4489 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4491 size
= sizeof(PRINTER_INFO_2W
);
4493 ptr
= pPrinter
+ size
;
4495 memset(pPrinter
, 0, size
);
4500 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
4507 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4509 size
= sizeof(PRINTER_INFO_4W
);
4511 ptr
= pPrinter
+ size
;
4513 memset(pPrinter
, 0, size
);
4518 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
4526 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4528 size
= sizeof(PRINTER_INFO_5W
);
4530 ptr
= pPrinter
+ size
;
4532 memset(pPrinter
, 0, size
);
4538 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4546 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4548 size
= sizeof(PRINTER_INFO_6
);
4549 if (size
<= cbBuf
) {
4550 /* FIXME: We do not update the status yet */
4551 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4563 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4565 size
= sizeof(PRINTER_INFO_7W
);
4566 if (size
<= cbBuf
) {
4567 ptr
= pPrinter
+ size
;
4569 memset(pPrinter
, 0, size
);
4575 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4582 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4583 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4587 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4589 size
= sizeof(PRINTER_INFO_9W
);
4591 ptr
= pPrinter
+ size
;
4593 memset(pPrinter
, 0, size
);
4599 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4606 FIXME("Unimplemented level %d\n", Level
);
4607 SetLastError(ERROR_INVALID_LEVEL
);
4608 RegCloseKey(hkeyPrinter
);
4612 RegCloseKey(hkeyPrinter
);
4614 TRACE("returning %d needed = %d\n", ret
, needed
);
4615 if(pcbNeeded
) *pcbNeeded
= needed
;
4617 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4621 /*****************************************************************************
4622 * GetPrinterA [WINSPOOL.@]
4624 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4625 DWORD cbBuf
, LPDWORD pcbNeeded
)
4631 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4633 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4635 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4636 HeapFree(GetProcessHeap(), 0, buf
);
4641 /*****************************************************************************
4642 * WINSPOOL_EnumPrintersW
4644 * Implementation of EnumPrintersW
4646 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4647 DWORD dwLevel
, LPBYTE lpbPrinters
,
4648 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4649 LPDWORD lpdwReturned
)
4652 HKEY hkeyPrinters
, hkeyPrinter
;
4653 WCHAR PrinterName
[255];
4654 DWORD needed
= 0, number
= 0;
4655 DWORD used
, i
, left
;
4659 memset(lpbPrinters
, 0, cbBuf
);
4665 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4666 if(dwType
== PRINTER_ENUM_DEFAULT
)
4669 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4670 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4671 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4673 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4679 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4680 FIXME("dwType = %08x\n", dwType
);
4681 SetLastError(ERROR_INVALID_FLAGS
);
4685 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4687 ERR("Can't create Printers key\n");
4691 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4692 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4693 RegCloseKey(hkeyPrinters
);
4694 ERR("Can't query Printers key\n");
4697 TRACE("Found %d printers\n", number
);
4701 used
= number
* sizeof(PRINTER_INFO_1W
);
4704 used
= number
* sizeof(PRINTER_INFO_2W
);
4707 used
= number
* sizeof(PRINTER_INFO_4W
);
4710 used
= number
* sizeof(PRINTER_INFO_5W
);
4714 SetLastError(ERROR_INVALID_LEVEL
);
4715 RegCloseKey(hkeyPrinters
);
4718 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4720 for(i
= 0; i
< number
; i
++) {
4721 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, ARRAY_SIZE(PrinterName
)) != ERROR_SUCCESS
) {
4722 ERR("Can't enum key number %d\n", i
);
4723 RegCloseKey(hkeyPrinters
);
4726 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4727 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4729 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4730 RegCloseKey(hkeyPrinters
);
4735 buf
= lpbPrinters
+ used
;
4736 left
= cbBuf
- used
;
4744 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4747 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4750 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4753 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4756 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4759 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4762 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4765 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4768 ERR("Shouldn't be here!\n");
4769 RegCloseKey(hkeyPrinter
);
4770 RegCloseKey(hkeyPrinters
);
4773 RegCloseKey(hkeyPrinter
);
4775 RegCloseKey(hkeyPrinters
);
4782 memset(lpbPrinters
, 0, cbBuf
);
4783 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4787 *lpdwReturned
= number
;
4788 SetLastError(ERROR_SUCCESS
);
4793 /******************************************************************
4794 * EnumPrintersW [WINSPOOL.@]
4796 * Enumerates the available printers, print servers and print
4797 * providers, depending on the specified flags, name and level.
4801 * If level is set to 1:
4802 * Returns an array of PRINTER_INFO_1 data structures in the
4803 * lpbPrinters buffer.
4805 * If level is set to 2:
4806 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4807 * Returns an array of PRINTER_INFO_2 data structures in the
4808 * lpbPrinters buffer. Note that according to MSDN also an
4809 * OpenPrinter should be performed on every remote printer.
4811 * If level is set to 4 (officially WinNT only):
4812 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4813 * Fast: Only the registry is queried to retrieve printer names,
4814 * no connection to the driver is made.
4815 * Returns an array of PRINTER_INFO_4 data structures in the
4816 * lpbPrinters buffer.
4818 * If level is set to 5 (officially WinNT4/Win9x only):
4819 * Fast: Only the registry is queried to retrieve printer names,
4820 * no connection to the driver is made.
4821 * Returns an array of PRINTER_INFO_5 data structures in the
4822 * lpbPrinters buffer.
4824 * If level set to 3 or 6+:
4825 * returns zero (failure!)
4827 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4831 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4832 * - Only levels 2, 4 and 5 are implemented at the moment.
4833 * - 16-bit printer drivers are not enumerated.
4834 * - Returned amount of bytes used/needed does not match the real Windoze
4835 * implementation (as in this implementation, all strings are part
4836 * of the buffer, whereas Win32 keeps them somewhere else)
4837 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4840 * - In a regular Wine installation, no registry settings for printers
4841 * exist, which makes this function return an empty list.
4843 BOOL WINAPI
EnumPrintersW(
4844 DWORD dwType
, /* [in] Types of print objects to enumerate */
4845 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4846 DWORD dwLevel
, /* [in] type of printer info structure */
4847 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4848 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4849 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4850 LPDWORD lpdwReturned
/* [out] number of entries returned */
4853 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4854 lpdwNeeded
, lpdwReturned
);
4857 /******************************************************************
4858 * EnumPrintersA [WINSPOOL.@]
4863 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4864 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4867 UNICODE_STRING pNameU
;
4871 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4872 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4874 pNameW
= asciitounicode(&pNameU
, pName
);
4876 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4877 MS Office need this */
4878 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4880 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4882 RtlFreeUnicodeString(&pNameU
);
4884 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4886 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4890 /*****************************************************************************
4891 * WINSPOOL_GetDriverInfoFromReg [internal]
4893 * Enters the information from the registry into the DRIVER_INFO struct
4896 * zero if the printer driver does not exist in the registry
4897 * (only if Level > 1) otherwise nonzero
4899 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4902 const printenv_t
* env
,
4904 LPBYTE ptr
, /* DRIVER_INFO */
4905 LPBYTE pDriverStrings
, /* strings buffer */
4906 DWORD cbBuf
, /* size of string buffer */
4907 LPDWORD pcbNeeded
) /* space needed for str. */
4911 WCHAR driverdir
[MAX_PATH
];
4913 LPBYTE strPtr
= pDriverStrings
;
4914 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4916 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4917 debugstr_w(DriverName
), env
,
4918 Level
, di
, pDriverStrings
, cbBuf
);
4920 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4922 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4923 if (*pcbNeeded
<= cbBuf
)
4924 strcpyW((LPWSTR
)strPtr
, DriverName
);
4926 /* pName for level 1 has a different offset! */
4928 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4932 /* .cVersion and .pName for level > 1 */
4934 di
->cVersion
= env
->driverversion
;
4935 di
->pName
= (LPWSTR
) strPtr
;
4936 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4939 /* Reserve Space for the largest subdir and a Backslash*/
4940 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4941 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4942 /* Should never Fail */
4945 lstrcatW(driverdir
, env
->versionsubdir
);
4946 lstrcatW(driverdir
, backslashW
);
4948 /* dirlen must not include the terminating zero */
4949 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4951 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4952 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4953 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4958 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4961 if (*pcbNeeded
<= cbBuf
) {
4962 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4963 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4964 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4967 /* .pDriverPath is the Graphics rendering engine.
4968 The full Path is required to avoid a crash in some apps */
4969 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4971 if (*pcbNeeded
<= cbBuf
)
4972 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4974 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4975 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4978 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4979 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4981 if (*pcbNeeded
<= cbBuf
)
4982 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4984 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4985 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4988 /* .pConfigFile is the Driver user Interface */
4989 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4991 if (*pcbNeeded
<= cbBuf
)
4992 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4994 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4995 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4999 RegCloseKey(hkeyDriver
);
5000 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5005 RegCloseKey(hkeyDriver
);
5006 FIXME("level 5: incomplete\n");
5011 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
5013 if (*pcbNeeded
<= cbBuf
)
5014 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
5016 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
5017 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5020 /* .pDependentFiles */
5021 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
5023 if (*pcbNeeded
<= cbBuf
)
5024 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
5026 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
5027 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5029 else if (GetVersion() & 0x80000000) {
5030 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
5031 size
= 2 * sizeof(WCHAR
);
5033 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
5035 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
5036 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5039 /* .pMonitorName is the optional Language Monitor */
5040 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
5042 if (*pcbNeeded
<= cbBuf
)
5043 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
5045 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
5046 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5049 /* .pDefaultDataType */
5050 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
5052 if(*pcbNeeded
<= cbBuf
)
5053 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
5055 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
5056 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5060 RegCloseKey(hkeyDriver
);
5061 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5065 /* .pszzPreviousNames */
5066 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
5068 if(*pcbNeeded
<= cbBuf
)
5069 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
5071 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
5072 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5076 RegCloseKey(hkeyDriver
);
5077 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5081 /* support is missing, but not important enough for a FIXME */
5082 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
5085 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
5087 if(*pcbNeeded
<= cbBuf
)
5088 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
5090 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
5091 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5095 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
5097 if(*pcbNeeded
<= cbBuf
)
5098 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
5100 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
5101 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5104 /* .pszHardwareID */
5105 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
5107 if(*pcbNeeded
<= cbBuf
)
5108 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
5110 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
5111 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5115 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
5117 if(*pcbNeeded
<= cbBuf
)
5118 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
5120 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
5121 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5125 RegCloseKey(hkeyDriver
);
5129 /* support is missing, but not important enough for a FIXME */
5130 TRACE("level 8: incomplete\n");
5132 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5133 RegCloseKey(hkeyDriver
);
5137 /*****************************************************************************
5138 * GetPrinterDriverW [WINSPOOL.@]
5140 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5141 DWORD Level
, LPBYTE pDriverInfo
,
5142 DWORD cbBuf
, LPDWORD pcbNeeded
)
5145 WCHAR DriverName
[100];
5146 DWORD ret
, type
, size
, needed
= 0;
5148 HKEY hkeyPrinter
, hkeyDrivers
;
5149 const printenv_t
* env
;
5151 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
5152 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
5155 ZeroMemory(pDriverInfo
, cbBuf
);
5157 if (!(name
= get_opened_printer_name(hPrinter
))) {
5158 SetLastError(ERROR_INVALID_HANDLE
);
5162 if (Level
< 1 || Level
== 7 || Level
> 8) {
5163 SetLastError(ERROR_INVALID_LEVEL
);
5167 env
= validate_envW(pEnvironment
);
5168 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5170 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
5173 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
5174 SetLastError( ret
);
5178 size
= sizeof(DriverName
);
5180 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5181 (LPBYTE
)DriverName
, &size
);
5182 RegCloseKey(hkeyPrinter
);
5183 if(ret
!= ERROR_SUCCESS
) {
5184 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5188 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5190 ERR("Can't create Drivers key\n");
5194 size
= di_sizeof
[Level
];
5195 if ((size
<= cbBuf
) && pDriverInfo
)
5196 ptr
= pDriverInfo
+ size
;
5198 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5199 env
, Level
, pDriverInfo
, ptr
,
5200 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5202 RegCloseKey(hkeyDrivers
);
5206 RegCloseKey(hkeyDrivers
);
5208 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5209 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5210 if(cbBuf
>= size
+ needed
) return TRUE
;
5211 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5215 /*****************************************************************************
5216 * GetPrinterDriverA [WINSPOOL.@]
5218 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5219 DWORD Level
, LPBYTE pDriverInfo
,
5220 DWORD cbBuf
, LPDWORD pcbNeeded
)
5223 UNICODE_STRING pEnvW
;
5229 ZeroMemory(pDriverInfo
, cbBuf
);
5230 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5233 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5234 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5237 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5239 HeapFree(GetProcessHeap(), 0, buf
);
5241 RtlFreeUnicodeString(&pEnvW
);
5245 /*****************************************************************************
5246 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5248 * Return the PATH for the Printer-Drivers (UNICODE)
5251 * pName [I] Servername (NT only) or NULL (local Computer)
5252 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5253 * Level [I] Structure-Level (must be 1)
5254 * pDriverDirectory [O] PTR to Buffer that receives the Result
5255 * cbBuf [I] Size of Buffer at pDriverDirectory
5256 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5257 * required for pDriverDirectory
5260 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5261 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5262 * if cbBuf is too small
5264 * Native Values returned in pDriverDirectory on Success:
5265 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5266 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5267 *| win9x(Windows 4.0): "%winsysdir%"
5269 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5272 *- Only NULL or "" is supported for pName
5275 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5276 DWORD Level
, LPBYTE pDriverDirectory
,
5277 DWORD cbBuf
, LPDWORD pcbNeeded
)
5279 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5280 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5282 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5285 /* (Level != 1) is ignored in win9x */
5286 SetLastError(ERROR_INVALID_LEVEL
);
5289 if (pcbNeeded
== NULL
) {
5290 /* (pcbNeeded == NULL) is ignored in win9x */
5291 SetLastError(RPC_X_NULL_REF_POINTER
);
5295 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5296 pDriverDirectory
, cbBuf
, pcbNeeded
);
5301 /*****************************************************************************
5302 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5304 * Return the PATH for the Printer-Drivers (ANSI)
5306 * See GetPrinterDriverDirectoryW.
5309 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5312 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5313 DWORD Level
, LPBYTE pDriverDirectory
,
5314 DWORD cbBuf
, LPDWORD pcbNeeded
)
5316 UNICODE_STRING nameW
, environmentW
;
5319 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5320 WCHAR
*driverDirectoryW
= NULL
;
5322 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5323 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5325 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5327 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5328 else nameW
.Buffer
= NULL
;
5329 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5330 else environmentW
.Buffer
= NULL
;
5332 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5333 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5336 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5337 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5339 *pcbNeeded
= needed
;
5340 ret
= needed
<= cbBuf
;
5342 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5344 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5346 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5347 RtlFreeUnicodeString(&environmentW
);
5348 RtlFreeUnicodeString(&nameW
);
5353 /*****************************************************************************
5354 * AddPrinterDriverA [WINSPOOL.@]
5356 * See AddPrinterDriverW.
5359 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5361 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5362 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5365 /******************************************************************************
5366 * AddPrinterDriverW (WINSPOOL.@)
5368 * Install a Printer Driver
5371 * pName [I] Servername or NULL (local Computer)
5372 * level [I] Level for the supplied DRIVER_INFO_*W struct
5373 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5380 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5382 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5383 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5386 /*****************************************************************************
5387 * AddPrintProcessorA [WINSPOOL.@]
5389 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5390 LPSTR pPrintProcessorName
)
5392 UNICODE_STRING NameW
, EnvW
, PathW
, ProcessorW
;
5395 TRACE("(%s,%s,%s,%s)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5396 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5398 asciitounicode(&NameW
, pName
);
5399 asciitounicode(&EnvW
, pEnvironment
);
5400 asciitounicode(&PathW
, pPathName
);
5401 asciitounicode(&ProcessorW
, pPrintProcessorName
);
5403 ret
= AddPrintProcessorW(NameW
.Buffer
, EnvW
.Buffer
, PathW
.Buffer
, ProcessorW
.Buffer
);
5405 RtlFreeUnicodeString(&ProcessorW
);
5406 RtlFreeUnicodeString(&PathW
);
5407 RtlFreeUnicodeString(&EnvW
);
5408 RtlFreeUnicodeString(&NameW
);
5413 /*****************************************************************************
5414 * AddPrintProcessorW [WINSPOOL.@]
5416 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5417 LPWSTR pPrintProcessorName
)
5419 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5420 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5424 /*****************************************************************************
5425 * AddPrintProvidorA [WINSPOOL.@]
5427 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5429 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5433 /*****************************************************************************
5434 * AddPrintProvidorW [WINSPOOL.@]
5436 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5438 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5442 /*****************************************************************************
5443 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5445 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5446 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5448 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5449 pDevModeOutput
, pDevModeInput
);
5453 /*****************************************************************************
5454 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5456 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5457 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5459 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5460 pDevModeOutput
, pDevModeInput
);
5464 /*****************************************************************************
5465 * PrinterProperties [WINSPOOL.@]
5467 * Displays a dialog to set the properties of the printer.
5470 * nonzero on success or zero on failure
5473 * implemented as stub only
5475 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5476 HANDLE hPrinter
/* [in] handle to printer object */
5478 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5479 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5483 /*****************************************************************************
5484 * EnumJobsA [WINSPOOL.@]
5487 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5488 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5491 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5492 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5494 if(pcbNeeded
) *pcbNeeded
= 0;
5495 if(pcReturned
) *pcReturned
= 0;
5500 /*****************************************************************************
5501 * EnumJobsW [WINSPOOL.@]
5504 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5505 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5508 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5509 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5511 if(pcbNeeded
) *pcbNeeded
= 0;
5512 if(pcReturned
) *pcReturned
= 0;
5516 /*****************************************************************************
5517 * WINSPOOL_EnumPrinterDrivers [internal]
5519 * Delivers information about all printer drivers installed on the
5520 * localhost or a given server
5523 * nonzero on success or zero on failure. If the buffer for the returned
5524 * information is too small the function will return an error
5527 * - only implemented for localhost, foreign hosts will return an error
5529 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5530 DWORD Level
, LPBYTE pDriverInfo
,
5532 DWORD cbBuf
, LPDWORD pcbNeeded
,
5533 LPDWORD pcFound
, DWORD data_offset
)
5537 const printenv_t
* env
;
5539 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5540 debugstr_w(pName
), debugstr_w(pEnvironment
),
5541 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5543 env
= validate_envW(pEnvironment
);
5544 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5548 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5550 ERR("Can't open Drivers key\n");
5554 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5555 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5556 RegCloseKey(hkeyDrivers
);
5557 ERR("Can't query Drivers key\n");
5560 TRACE("Found %d Drivers\n", *pcFound
);
5562 /* get size of single struct
5563 * unicode and ascii structure have the same size
5565 size
= di_sizeof
[Level
];
5567 if (data_offset
== 0)
5568 data_offset
= size
* (*pcFound
);
5569 *pcbNeeded
= data_offset
;
5571 for( i
= 0; i
< *pcFound
; i
++) {
5572 WCHAR DriverNameW
[255];
5573 PBYTE table_ptr
= NULL
;
5574 PBYTE data_ptr
= NULL
;
5577 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, ARRAY_SIZE(DriverNameW
)) != ERROR_SUCCESS
) {
5578 ERR("Can't enum key number %d\n", i
);
5579 RegCloseKey(hkeyDrivers
);
5583 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5584 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5585 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5586 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5588 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5589 env
, Level
, table_ptr
, data_ptr
,
5590 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5592 RegCloseKey(hkeyDrivers
);
5596 *pcbNeeded
+= needed
;
5599 RegCloseKey(hkeyDrivers
);
5601 if(cbBuf
< *pcbNeeded
){
5602 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5609 /*****************************************************************************
5610 * EnumPrinterDriversW [WINSPOOL.@]
5612 * see function EnumPrinterDrivers for RETURNS, BUGS
5614 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5615 LPBYTE pDriverInfo
, DWORD cbBuf
,
5616 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5618 static const WCHAR allW
[] = {'a','l','l',0};
5622 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5624 SetLastError(RPC_X_NULL_REF_POINTER
);
5628 /* check for local drivers */
5629 if((pName
) && (pName
[0])) {
5630 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5631 SetLastError(ERROR_ACCESS_DENIED
);
5635 /* check input parameter */
5636 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5637 SetLastError(ERROR_INVALID_LEVEL
);
5641 if(pDriverInfo
&& cbBuf
> 0)
5642 memset( pDriverInfo
, 0, cbBuf
);
5644 /* Exception: pull all printers */
5645 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5647 DWORD i
, needed
, bufsize
= cbBuf
;
5648 DWORD total_found
= 0;
5651 /* Precompute the overall total; we need this to know
5652 where pointers end and data begins (i.e. data_offset) */
5653 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5656 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5657 NULL
, 0, 0, &needed
, &found
, 0);
5658 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5659 total_found
+= found
;
5662 data_offset
= di_sizeof
[Level
] * total_found
;
5667 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5670 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5671 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5672 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5674 *pcReturned
+= found
;
5675 *pcbNeeded
= needed
;
5676 data_offset
= needed
;
5677 total_found
+= found
;
5682 /* Normal behavior */
5683 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5684 0, cbBuf
, pcbNeeded
, &found
, 0);
5686 *pcReturned
= found
;
5691 /*****************************************************************************
5692 * EnumPrinterDriversA [WINSPOOL.@]
5694 * see function EnumPrinterDrivers for RETURNS, BUGS
5696 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5697 LPBYTE pDriverInfo
, DWORD cbBuf
,
5698 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5701 UNICODE_STRING pNameW
, pEnvironmentW
;
5702 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5706 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5708 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5709 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5711 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5712 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5714 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5716 HeapFree(GetProcessHeap(), 0, buf
);
5718 RtlFreeUnicodeString(&pNameW
);
5719 RtlFreeUnicodeString(&pEnvironmentW
);
5724 /******************************************************************************
5725 * EnumPortsA (WINSPOOL.@)
5730 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5731 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5734 LPBYTE bufferW
= NULL
;
5735 LPWSTR nameW
= NULL
;
5737 DWORD numentries
= 0;
5740 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5741 cbBuf
, pcbNeeded
, pcReturned
);
5743 /* convert servername to unicode */
5745 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5746 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5747 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5749 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5750 needed
= cbBuf
* sizeof(WCHAR
);
5751 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5752 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5754 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5755 if (pcbNeeded
) needed
= *pcbNeeded
;
5756 /* HeapReAlloc return NULL, when bufferW was NULL */
5757 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5758 HeapAlloc(GetProcessHeap(), 0, needed
);
5760 /* Try again with the large Buffer */
5761 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5763 needed
= pcbNeeded
? *pcbNeeded
: 0;
5764 numentries
= pcReturned
? *pcReturned
: 0;
5767 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5768 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5771 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5772 DWORD entrysize
= 0;
5775 LPPORT_INFO_2W pi2w
;
5776 LPPORT_INFO_2A pi2a
;
5779 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5781 /* First pass: calculate the size for all Entries */
5782 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5783 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5785 while (index
< numentries
) {
5787 needed
+= entrysize
; /* PORT_INFO_?A */
5788 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5790 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5791 NULL
, 0, NULL
, NULL
);
5793 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5794 NULL
, 0, NULL
, NULL
);
5795 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5796 NULL
, 0, NULL
, NULL
);
5798 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5799 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5800 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5803 /* check for errors and quit on failure */
5804 if (cbBuf
< needed
) {
5805 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5809 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5810 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5811 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5812 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5813 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5815 /* Second Pass: Fill the User Buffer (if we have one) */
5816 while ((index
< numentries
) && pPorts
) {
5818 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5819 pi2a
->pPortName
= ptr
;
5820 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5821 ptr
, cbBuf
, NULL
, NULL
);
5825 pi2a
->pMonitorName
= ptr
;
5826 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5827 ptr
, cbBuf
, NULL
, NULL
);
5831 pi2a
->pDescription
= ptr
;
5832 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5833 ptr
, cbBuf
, NULL
, NULL
);
5837 pi2a
->fPortType
= pi2w
->fPortType
;
5838 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5841 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5842 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5843 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5848 if (pcbNeeded
) *pcbNeeded
= needed
;
5849 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5851 HeapFree(GetProcessHeap(), 0, nameW
);
5852 HeapFree(GetProcessHeap(), 0, bufferW
);
5854 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5855 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5861 /******************************************************************************
5862 * EnumPortsW (WINSPOOL.@)
5864 * Enumerate available Ports
5867 * pName [I] Servername or NULL (local Computer)
5868 * Level [I] Structure-Level (1 or 2)
5869 * pPorts [O] PTR to Buffer that receives the Result
5870 * cbBuf [I] Size of Buffer at pPorts
5871 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5872 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5876 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5879 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5882 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5883 cbBuf
, pcbNeeded
, pcReturned
);
5885 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5887 /* Level is not checked in win9x */
5888 if (!Level
|| (Level
> 2)) {
5889 WARN("level (%d) is ignored in win9x\n", Level
);
5890 SetLastError(ERROR_INVALID_LEVEL
);
5893 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5894 SetLastError(RPC_X_NULL_REF_POINTER
);
5898 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5901 /******************************************************************************
5902 * GetDefaultPrinterW (WINSPOOL.@)
5905 * This function must read the value from data 'device' of key
5906 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5908 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5912 WCHAR
*buffer
, *ptr
;
5916 SetLastError(ERROR_INVALID_PARAMETER
);
5920 /* make the buffer big enough for the stuff from the profile/registry,
5921 * the content must fit into the local buffer to compute the correct
5922 * size even if the extern buffer is too small or not given.
5923 * (20 for ,driver,port) */
5925 len
= max(100, (insize
+ 20));
5926 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5928 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5930 SetLastError (ERROR_FILE_NOT_FOUND
);
5934 TRACE("%s\n", debugstr_w(buffer
));
5936 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5938 SetLastError(ERROR_INVALID_NAME
);
5944 *namesize
= strlenW(buffer
) + 1;
5945 if(!name
|| (*namesize
> insize
))
5947 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5951 strcpyW(name
, buffer
);
5954 HeapFree( GetProcessHeap(), 0, buffer
);
5959 /******************************************************************************
5960 * GetDefaultPrinterA (WINSPOOL.@)
5962 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5966 WCHAR
*bufferW
= NULL
;
5970 SetLastError(ERROR_INVALID_PARAMETER
);
5974 if(name
&& *namesize
) {
5976 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5979 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5984 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5988 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5991 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5994 HeapFree( GetProcessHeap(), 0, bufferW
);
5999 /******************************************************************************
6000 * SetDefaultPrinterW (WINSPOOL.204)
6002 * Set the Name of the Default Printer
6005 * pszPrinter [I] Name of the Printer or NULL
6012 * When the Parameter is NULL or points to an Empty String and
6013 * a Default Printer was already present, then this Function changes nothing.
6014 * Without a Default Printer and NULL (or an Empty String) as Parameter,
6015 * the First enumerated local Printer is used.
6018 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
6020 WCHAR default_printer
[MAX_PATH
];
6021 LPWSTR buffer
= NULL
;
6027 TRACE("(%s)\n", debugstr_w(pszPrinter
));
6028 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
6030 default_printer
[0] = '\0';
6031 size
= ARRAY_SIZE(default_printer
);
6033 /* if we have a default Printer, do nothing. */
6034 if (GetDefaultPrinterW(default_printer
, &size
))
6038 /* we have no default Printer: search local Printers and use the first */
6039 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
6041 default_printer
[0] = '\0';
6042 size
= ARRAY_SIZE(default_printer
);
6043 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
6045 pszPrinter
= default_printer
;
6046 TRACE("using %s\n", debugstr_w(pszPrinter
));
6051 if (pszPrinter
== NULL
) {
6052 TRACE("no local printer found\n");
6053 SetLastError(ERROR_FILE_NOT_FOUND
);
6058 /* "pszPrinter" is never empty or NULL here. */
6059 namelen
= lstrlenW(pszPrinter
);
6060 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
6061 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
6063 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
6064 HeapFree(GetProcessHeap(), 0, buffer
);
6065 SetLastError(ERROR_FILE_NOT_FOUND
);
6069 /* read the devices entry for the printer (driver,port) to build the string for the
6070 default device entry (printer,driver,port) */
6071 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
6072 buffer
[namelen
] = ',';
6073 namelen
++; /* move index to the start of the driver */
6075 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
6076 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
6080 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
))
6082 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (BYTE
*)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
6088 if (lres
!= ERROR_FILE_NOT_FOUND
)
6089 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
6091 SetLastError(ERROR_INVALID_PRINTER_NAME
);
6095 HeapFree(GetProcessHeap(), 0, buffer
);
6096 return (lres
== ERROR_SUCCESS
);
6099 /******************************************************************************
6100 * SetDefaultPrinterA (WINSPOOL.202)
6102 * See SetDefaultPrinterW.
6105 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
6107 LPWSTR bufferW
= NULL
;
6110 TRACE("(%s)\n", debugstr_a(pszPrinter
));
6112 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
6113 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6114 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
6116 res
= SetDefaultPrinterW(bufferW
);
6117 HeapFree(GetProcessHeap(), 0, bufferW
);
6121 /******************************************************************************
6122 * SetPrinterDataExA (WINSPOOL.@)
6124 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6125 LPCSTR pValueName
, DWORD Type
,
6126 LPBYTE pData
, DWORD cbData
)
6128 HKEY hkeyPrinter
, hkeySubkey
;
6131 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
6132 debugstr_a(pValueName
), Type
, pData
, cbData
);
6134 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6138 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6140 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
6141 RegCloseKey(hkeyPrinter
);
6144 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6145 RegCloseKey(hkeySubkey
);
6146 RegCloseKey(hkeyPrinter
);
6150 /******************************************************************************
6151 * SetPrinterDataExW (WINSPOOL.@)
6153 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6154 LPCWSTR pValueName
, DWORD Type
,
6155 LPBYTE pData
, DWORD cbData
)
6157 HKEY hkeyPrinter
, hkeySubkey
;
6160 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
6161 debugstr_w(pValueName
), Type
, pData
, cbData
);
6163 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6167 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6169 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
6170 RegCloseKey(hkeyPrinter
);
6173 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6174 RegCloseKey(hkeySubkey
);
6175 RegCloseKey(hkeyPrinter
);
6179 /******************************************************************************
6180 * SetPrinterDataA (WINSPOOL.@)
6182 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
6183 LPBYTE pData
, DWORD cbData
)
6185 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
6189 /******************************************************************************
6190 * SetPrinterDataW (WINSPOOL.@)
6192 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
6193 LPBYTE pData
, DWORD cbData
)
6195 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6199 /******************************************************************************
6200 * GetPrinterDataExA (WINSPOOL.@)
6202 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6203 LPCSTR pValueName
, LPDWORD pType
,
6204 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6206 opened_printer_t
*printer
;
6207 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6210 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6211 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6213 printer
= get_opened_printer(hPrinter
);
6214 if(!printer
) return ERROR_INVALID_HANDLE
;
6216 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6217 if (ret
) return ret
;
6219 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6221 if (printer
->name
) {
6223 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6225 RegCloseKey(hkeyPrinters
);
6228 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6229 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6230 RegCloseKey(hkeyPrinter
);
6231 RegCloseKey(hkeyPrinters
);
6236 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6237 0, pType
, pData
, pcbNeeded
);
6239 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6241 RegCloseKey(hkeySubkey
);
6242 RegCloseKey(hkeyPrinter
);
6243 RegCloseKey(hkeyPrinters
);
6245 TRACE("--> %d\n", ret
);
6249 /******************************************************************************
6250 * GetPrinterDataExW (WINSPOOL.@)
6252 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6253 LPCWSTR pValueName
, LPDWORD pType
,
6254 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6256 opened_printer_t
*printer
;
6257 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6260 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6261 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6263 printer
= get_opened_printer(hPrinter
);
6264 if(!printer
) return ERROR_INVALID_HANDLE
;
6266 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6267 if (ret
) return ret
;
6269 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6271 if (printer
->name
) {
6273 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6275 RegCloseKey(hkeyPrinters
);
6278 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6279 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6280 RegCloseKey(hkeyPrinter
);
6281 RegCloseKey(hkeyPrinters
);
6286 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6287 0, pType
, pData
, pcbNeeded
);
6289 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6291 RegCloseKey(hkeySubkey
);
6292 RegCloseKey(hkeyPrinter
);
6293 RegCloseKey(hkeyPrinters
);
6295 TRACE("--> %d\n", ret
);
6299 /******************************************************************************
6300 * GetPrinterDataA (WINSPOOL.@)
6302 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6303 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6305 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6306 pData
, nSize
, pcbNeeded
);
6309 /******************************************************************************
6310 * GetPrinterDataW (WINSPOOL.@)
6312 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6313 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6315 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6316 pData
, nSize
, pcbNeeded
);
6319 /*******************************************************************************
6320 * EnumPrinterDataExW [WINSPOOL.@]
6322 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6323 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6324 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6326 HKEY hkPrinter
, hkSubKey
;
6327 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6328 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6333 PPRINTER_ENUM_VALUESW ppev
;
6335 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6337 if (pKeyName
== NULL
|| *pKeyName
== 0)
6338 return ERROR_INVALID_PARAMETER
;
6340 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6341 if (ret
!= ERROR_SUCCESS
)
6343 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6348 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6349 if (ret
!= ERROR_SUCCESS
)
6351 r
= RegCloseKey (hkPrinter
);
6352 if (r
!= ERROR_SUCCESS
)
6353 WARN ("RegCloseKey returned %i\n", r
);
6354 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6355 debugstr_w (pKeyName
), ret
);
6359 ret
= RegCloseKey (hkPrinter
);
6360 if (ret
!= ERROR_SUCCESS
)
6362 ERR ("RegCloseKey returned %i\n", ret
);
6363 r
= RegCloseKey (hkSubKey
);
6364 if (r
!= ERROR_SUCCESS
)
6365 WARN ("RegCloseKey returned %i\n", r
);
6369 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6370 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6371 if (ret
!= ERROR_SUCCESS
)
6373 r
= RegCloseKey (hkSubKey
);
6374 if (r
!= ERROR_SUCCESS
)
6375 WARN ("RegCloseKey returned %i\n", r
);
6376 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6380 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6381 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6383 if (cValues
== 0) /* empty key */
6385 r
= RegCloseKey (hkSubKey
);
6386 if (r
!= ERROR_SUCCESS
)
6387 WARN ("RegCloseKey returned %i\n", r
);
6388 *pcbEnumValues
= *pnEnumValues
= 0;
6389 return ERROR_SUCCESS
;
6392 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6394 hHeap
= GetProcessHeap ();
6397 ERR ("GetProcessHeap failed\n");
6398 r
= RegCloseKey (hkSubKey
);
6399 if (r
!= ERROR_SUCCESS
)
6400 WARN ("RegCloseKey returned %i\n", r
);
6401 return ERROR_OUTOFMEMORY
;
6404 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6405 if (lpValueName
== NULL
)
6407 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6408 r
= RegCloseKey (hkSubKey
);
6409 if (r
!= ERROR_SUCCESS
)
6410 WARN ("RegCloseKey returned %i\n", r
);
6411 return ERROR_OUTOFMEMORY
;
6414 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6415 if (lpValue
== NULL
)
6417 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6418 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6419 WARN ("HeapFree failed with code %i\n", GetLastError ());
6420 r
= RegCloseKey (hkSubKey
);
6421 if (r
!= ERROR_SUCCESS
)
6422 WARN ("RegCloseKey returned %i\n", r
);
6423 return ERROR_OUTOFMEMORY
;
6426 TRACE ("pass 1: calculating buffer required for all names and values\n");
6428 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6430 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6432 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6434 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6435 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6436 NULL
, NULL
, lpValue
, &cbValueLen
);
6437 if (ret
!= ERROR_SUCCESS
)
6439 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6440 WARN ("HeapFree failed with code %i\n", GetLastError ());
6441 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6442 WARN ("HeapFree failed with code %i\n", GetLastError ());
6443 r
= RegCloseKey (hkSubKey
);
6444 if (r
!= ERROR_SUCCESS
)
6445 WARN ("RegCloseKey returned %i\n", r
);
6446 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6450 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6451 debugstr_w (lpValueName
), dwIndex
,
6452 cbValueNameLen
+ 1, cbValueLen
);
6454 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6455 cbBufSize
+= cbValueLen
;
6458 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6460 *pcbEnumValues
= cbBufSize
;
6461 *pnEnumValues
= cValues
;
6463 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6465 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6466 WARN ("HeapFree failed with code %i\n", GetLastError ());
6467 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6468 WARN ("HeapFree failed with code %i\n", GetLastError ());
6469 r
= RegCloseKey (hkSubKey
);
6470 if (r
!= ERROR_SUCCESS
)
6471 WARN ("RegCloseKey returned %i\n", r
);
6472 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6473 return ERROR_MORE_DATA
;
6476 TRACE ("pass 2: copying all names and values to buffer\n");
6478 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6479 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6481 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6483 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6484 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6485 NULL
, &dwType
, lpValue
, &cbValueLen
);
6486 if (ret
!= ERROR_SUCCESS
)
6488 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6489 WARN ("HeapFree failed with code %i\n", GetLastError ());
6490 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6491 WARN ("HeapFree failed with code %i\n", GetLastError ());
6492 r
= RegCloseKey (hkSubKey
);
6493 if (r
!= ERROR_SUCCESS
)
6494 WARN ("RegCloseKey returned %i\n", r
);
6495 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6499 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6500 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6501 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6502 pEnumValues
+= cbValueNameLen
;
6504 /* return # of *bytes* (including trailing \0), not # of chars */
6505 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6507 ppev
[dwIndex
].dwType
= dwType
;
6509 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6510 ppev
[dwIndex
].pData
= pEnumValues
;
6511 pEnumValues
+= cbValueLen
;
6513 ppev
[dwIndex
].cbData
= cbValueLen
;
6515 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6516 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6519 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6521 ret
= GetLastError ();
6522 ERR ("HeapFree failed with code %i\n", ret
);
6523 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6524 WARN ("HeapFree failed with code %i\n", GetLastError ());
6525 r
= RegCloseKey (hkSubKey
);
6526 if (r
!= ERROR_SUCCESS
)
6527 WARN ("RegCloseKey returned %i\n", r
);
6531 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6533 ret
= GetLastError ();
6534 ERR ("HeapFree failed with code %i\n", ret
);
6535 r
= RegCloseKey (hkSubKey
);
6536 if (r
!= ERROR_SUCCESS
)
6537 WARN ("RegCloseKey returned %i\n", r
);
6541 ret
= RegCloseKey (hkSubKey
);
6542 if (ret
!= ERROR_SUCCESS
)
6544 ERR ("RegCloseKey returned %i\n", ret
);
6548 return ERROR_SUCCESS
;
6551 /*******************************************************************************
6552 * EnumPrinterDataExA [WINSPOOL.@]
6554 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6555 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6556 * what Windows 2000 SP1 does.
6559 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6560 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6561 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6565 DWORD ret
, dwIndex
, dwBufSize
;
6569 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6571 if (pKeyName
== NULL
|| *pKeyName
== 0)
6572 return ERROR_INVALID_PARAMETER
;
6574 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6577 ret
= GetLastError ();
6578 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6582 hHeap
= GetProcessHeap ();
6585 ERR ("GetProcessHeap failed\n");
6586 return ERROR_OUTOFMEMORY
;
6589 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6590 if (pKeyNameW
== NULL
)
6592 ERR ("Failed to allocate %i bytes from process heap\n",
6593 (LONG
)(len
* sizeof (WCHAR
)));
6594 return ERROR_OUTOFMEMORY
;
6597 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6599 ret
= GetLastError ();
6600 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6601 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6602 WARN ("HeapFree failed with code %i\n", GetLastError ());
6606 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6607 pcbEnumValues
, pnEnumValues
);
6608 if (ret
!= ERROR_SUCCESS
)
6610 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6611 WARN ("HeapFree failed with code %i\n", GetLastError ());
6612 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6616 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6618 ret
= GetLastError ();
6619 ERR ("HeapFree failed with code %i\n", ret
);
6623 if (*pnEnumValues
== 0) /* empty key */
6624 return ERROR_SUCCESS
;
6627 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6629 PPRINTER_ENUM_VALUESW ppev
=
6630 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6632 if (dwBufSize
< ppev
->cbValueName
)
6633 dwBufSize
= ppev
->cbValueName
;
6635 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6636 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6637 dwBufSize
= ppev
->cbData
;
6640 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6642 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6643 if (pBuffer
== NULL
)
6645 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6646 return ERROR_OUTOFMEMORY
;
6649 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6651 PPRINTER_ENUM_VALUESW ppev
=
6652 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6654 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6655 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6659 ret
= GetLastError ();
6660 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6661 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6662 WARN ("HeapFree failed with code %i\n", GetLastError ());
6666 memcpy (ppev
->pValueName
, pBuffer
, len
);
6668 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6670 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6671 ppev
->dwType
!= REG_MULTI_SZ
)
6674 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6675 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6678 ret
= GetLastError ();
6679 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6680 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6681 WARN ("HeapFree failed with code %i\n", GetLastError ());
6685 memcpy (ppev
->pData
, pBuffer
, len
);
6687 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6688 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6691 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6693 ret
= GetLastError ();
6694 ERR ("HeapFree failed with code %i\n", ret
);
6698 return ERROR_SUCCESS
;
6701 /******************************************************************************
6702 * AbortPrinter (WINSPOOL.@)
6704 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6706 FIXME("(%p), stub!\n", hPrinter
);
6710 /******************************************************************************
6711 * AddPortA (WINSPOOL.@)
6716 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6718 LPWSTR nameW
= NULL
;
6719 LPWSTR monitorW
= NULL
;
6723 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6726 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6727 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6728 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6732 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6733 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6734 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6736 res
= AddPortW(nameW
, hWnd
, monitorW
);
6737 HeapFree(GetProcessHeap(), 0, nameW
);
6738 HeapFree(GetProcessHeap(), 0, monitorW
);
6742 /******************************************************************************
6743 * AddPortW (WINSPOOL.@)
6745 * Add a Port for a specific Monitor
6748 * pName [I] Servername or NULL (local Computer)
6749 * hWnd [I] Handle to parent Window for the Dialog-Box
6750 * pMonitorName [I] Name of the Monitor that manage the Port
6757 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6759 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6761 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6763 if (!pMonitorName
) {
6764 SetLastError(RPC_X_NULL_REF_POINTER
);
6768 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6771 /******************************************************************************
6772 * AddPortExA (WINSPOOL.@)
6777 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6780 PORT_INFO_2A
* pi2A
;
6781 LPWSTR nameW
= NULL
;
6782 LPWSTR monitorW
= NULL
;
6786 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6788 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6789 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6791 if ((level
< 1) || (level
> 2)) {
6792 SetLastError(ERROR_INVALID_LEVEL
);
6797 SetLastError(ERROR_INVALID_PARAMETER
);
6802 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6803 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6804 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6808 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6809 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6810 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6813 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6815 if (pi2A
->pPortName
) {
6816 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6817 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6818 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6822 if (pi2A
->pMonitorName
) {
6823 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6824 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6825 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6828 if (pi2A
->pDescription
) {
6829 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6830 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6831 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6833 pi2W
.fPortType
= pi2A
->fPortType
;
6834 pi2W
.Reserved
= pi2A
->Reserved
;
6837 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6839 HeapFree(GetProcessHeap(), 0, nameW
);
6840 HeapFree(GetProcessHeap(), 0, monitorW
);
6841 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6842 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6843 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6848 /******************************************************************************
6849 * AddPortExW (WINSPOOL.@)
6851 * Add a Port for a specific Monitor, without presenting a user interface
6854 * pName [I] Servername or NULL (local Computer)
6855 * level [I] Structure-Level (1 or 2) for pBuffer
6856 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6857 * pMonitorName [I] Name of the Monitor that manage the Port
6864 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6868 pi2
= (PORT_INFO_2W
*) pBuffer
;
6870 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6871 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6872 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6873 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6875 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6877 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6878 SetLastError(ERROR_INVALID_PARAMETER
);
6882 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6885 /******************************************************************************
6886 * AddPrinterConnectionA (WINSPOOL.@)
6888 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6890 FIXME("%s\n", debugstr_a(pName
));
6894 /******************************************************************************
6895 * AddPrinterConnectionW (WINSPOOL.@)
6897 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6899 FIXME("%s\n", debugstr_w(pName
));
6903 /******************************************************************************
6904 * AddPrinterDriverExW (WINSPOOL.@)
6906 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6909 * pName [I] Servername or NULL (local Computer)
6910 * level [I] Level for the supplied DRIVER_INFO_*W struct
6911 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6912 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6919 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6921 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6923 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6925 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6926 SetLastError(ERROR_INVALID_LEVEL
);
6931 SetLastError(ERROR_INVALID_PARAMETER
);
6935 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6938 /******************************************************************************
6939 * AddPrinterDriverExA (WINSPOOL.@)
6941 * See AddPrinterDriverExW.
6944 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6946 DRIVER_INFO_8A
*diA
;
6948 LPWSTR nameW
= NULL
;
6953 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6955 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6956 ZeroMemory(&diW
, sizeof(diW
));
6958 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6959 SetLastError(ERROR_INVALID_LEVEL
);
6964 SetLastError(ERROR_INVALID_PARAMETER
);
6968 /* convert servername to unicode */
6970 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6971 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6972 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6976 diW
.cVersion
= diA
->cVersion
;
6979 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6980 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6981 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6984 if (diA
->pEnvironment
) {
6985 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6986 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6987 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6990 if (diA
->pDriverPath
) {
6991 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6992 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6993 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6996 if (diA
->pDataFile
) {
6997 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6998 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6999 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
7002 if (diA
->pConfigFile
) {
7003 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
7004 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7005 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
7008 if ((Level
> 2) && diA
->pHelpFile
) {
7009 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, NULL
, 0);
7010 diW
.pHelpFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7011 MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, diW
.pHelpFile
, len
);
7014 if ((Level
> 2) && diA
->pDependentFiles
) {
7015 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
7016 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
7017 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7018 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
7021 if ((Level
> 2) && diA
->pMonitorName
) {
7022 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
7023 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7024 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
7027 if ((Level
> 2) && diA
->pDefaultDataType
) {
7028 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
7029 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7030 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
7033 if ((Level
> 3) && diA
->pszzPreviousNames
) {
7034 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
7035 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
7036 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7037 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
7041 diW
.ftDriverDate
= diA
->ftDriverDate
;
7042 diW
.dwlDriverVersion
= diA
->dwlDriverVersion
;
7045 if ((Level
> 5) && diA
->pszMfgName
) {
7046 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
7047 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7048 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
7051 if ((Level
> 5) && diA
->pszOEMUrl
) {
7052 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
7053 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7054 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
7057 if ((Level
> 5) && diA
->pszHardwareID
) {
7058 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
7059 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7060 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
7063 if ((Level
> 5) && diA
->pszProvider
) {
7064 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
7065 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7066 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
7069 if ((Level
> 7) && diA
->pszPrintProcessor
) {
7070 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, NULL
, 0);
7071 diW
.pszPrintProcessor
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7072 MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, diW
.pszPrintProcessor
, len
);
7075 if ((Level
> 7) && diA
->pszVendorSetup
) {
7076 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, NULL
, 0);
7077 diW
.pszVendorSetup
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7078 MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, diW
.pszVendorSetup
, len
);
7081 if ((Level
> 7) && diA
->pszzColorProfiles
) {
7082 lenA
= multi_sz_lenA(diA
->pszzColorProfiles
);
7083 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, NULL
, 0);
7084 diW
.pszzColorProfiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7085 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, diW
.pszzColorProfiles
, len
);
7088 if ((Level
> 7) && diA
->pszInfPath
) {
7089 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, NULL
, 0);
7090 diW
.pszInfPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7091 MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, diW
.pszInfPath
, len
);
7094 if ((Level
> 7) && diA
->pszzCoreDriverDependencies
) {
7095 lenA
= multi_sz_lenA(diA
->pszzCoreDriverDependencies
);
7096 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, NULL
, 0);
7097 diW
.pszzCoreDriverDependencies
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7098 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, diW
.pszzCoreDriverDependencies
, len
);
7102 diW
.dwPrinterDriverAttributes
= diA
->dwPrinterDriverAttributes
;
7103 diW
.ftMinInboxDriverVerDate
= diA
->ftMinInboxDriverVerDate
;
7104 diW
.dwlMinInboxDriverVerVersion
= diA
->dwlMinInboxDriverVerVersion
;
7107 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
7108 TRACE("got %u with %u\n", res
, GetLastError());
7109 HeapFree(GetProcessHeap(), 0, nameW
);
7110 HeapFree(GetProcessHeap(), 0, diW
.pName
);
7111 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
7112 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
7113 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
7114 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
7115 HeapFree(GetProcessHeap(), 0, diW
.pHelpFile
);
7116 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
7117 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
7118 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
7119 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
7120 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
7121 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
7122 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
7123 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
7124 HeapFree(GetProcessHeap(), 0, diW
.pszPrintProcessor
);
7125 HeapFree(GetProcessHeap(), 0, diW
.pszVendorSetup
);
7126 HeapFree(GetProcessHeap(), 0, diW
.pszzColorProfiles
);
7127 HeapFree(GetProcessHeap(), 0, diW
.pszInfPath
);
7128 HeapFree(GetProcessHeap(), 0, diW
.pszzCoreDriverDependencies
);
7130 TRACE("=> %u with %u\n", res
, GetLastError());
7134 /******************************************************************************
7135 * ConfigurePortA (WINSPOOL.@)
7137 * See ConfigurePortW.
7140 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
7142 LPWSTR nameW
= NULL
;
7143 LPWSTR portW
= NULL
;
7147 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
7149 /* convert servername to unicode */
7151 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7152 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7153 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7156 /* convert portname to unicode */
7158 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
7159 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7160 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
7163 res
= ConfigurePortW(nameW
, hWnd
, portW
);
7164 HeapFree(GetProcessHeap(), 0, nameW
);
7165 HeapFree(GetProcessHeap(), 0, portW
);
7169 /******************************************************************************
7170 * ConfigurePortW (WINSPOOL.@)
7172 * Display the Configuration-Dialog for a specific Port
7175 * pName [I] Servername or NULL (local Computer)
7176 * hWnd [I] Handle to parent Window for the Dialog-Box
7177 * pPortName [I] Name of the Port, that should be configured
7184 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
7187 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
7189 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7192 SetLastError(RPC_X_NULL_REF_POINTER
);
7196 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
7199 /******************************************************************************
7200 * ConnectToPrinterDlg (WINSPOOL.@)
7202 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
7204 FIXME("%p %x\n", hWnd
, Flags
);
7208 /******************************************************************************
7209 * DeletePrinterConnectionA (WINSPOOL.@)
7211 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
7213 FIXME("%s\n", debugstr_a(pName
));
7217 /******************************************************************************
7218 * DeletePrinterConnectionW (WINSPOOL.@)
7220 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
7222 FIXME("%s\n", debugstr_w(pName
));
7226 /******************************************************************************
7227 * DeletePrinterDriverExW (WINSPOOL.@)
7229 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
7230 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7235 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7236 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
7238 if(pName
&& pName
[0])
7240 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
7241 SetLastError(ERROR_INVALID_PARAMETER
);
7247 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7248 SetLastError(ERROR_INVALID_PARAMETER
);
7252 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7256 ERR("Can't open drivers key\n");
7260 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7263 RegCloseKey(hkey_drivers
);
7268 /******************************************************************************
7269 * DeletePrinterDriverExA (WINSPOOL.@)
7271 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7272 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7274 UNICODE_STRING NameW
, EnvW
, DriverW
;
7277 asciitounicode(&NameW
, pName
);
7278 asciitounicode(&EnvW
, pEnvironment
);
7279 asciitounicode(&DriverW
, pDriverName
);
7281 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7283 RtlFreeUnicodeString(&DriverW
);
7284 RtlFreeUnicodeString(&EnvW
);
7285 RtlFreeUnicodeString(&NameW
);
7290 /******************************************************************************
7291 * DeletePrinterDataExW (WINSPOOL.@)
7293 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7296 FIXME("%p %s %s\n", hPrinter
,
7297 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7298 return ERROR_INVALID_PARAMETER
;
7301 /******************************************************************************
7302 * DeletePrinterDataExA (WINSPOOL.@)
7304 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7307 FIXME("%p %s %s\n", hPrinter
,
7308 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7309 return ERROR_INVALID_PARAMETER
;
7312 /******************************************************************************
7313 * DeletePrintProcessorA (WINSPOOL.@)
7315 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7317 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7318 debugstr_a(pPrintProcessorName
));
7322 /******************************************************************************
7323 * DeletePrintProcessorW (WINSPOOL.@)
7325 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7327 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7328 debugstr_w(pPrintProcessorName
));
7332 /******************************************************************************
7333 * DeletePrintProvidorA (WINSPOOL.@)
7335 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7337 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7338 debugstr_a(pPrintProviderName
));
7342 /******************************************************************************
7343 * DeletePrintProvidorW (WINSPOOL.@)
7345 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7347 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7348 debugstr_w(pPrintProviderName
));
7352 /******************************************************************************
7353 * EnumFormsA (WINSPOOL.@)
7355 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7356 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7358 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7359 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7363 /******************************************************************************
7364 * EnumFormsW (WINSPOOL.@)
7366 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7367 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7369 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7370 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7374 /*****************************************************************************
7375 * EnumMonitorsA [WINSPOOL.@]
7377 * See EnumMonitorsW.
7380 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7381 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7384 LPBYTE bufferW
= NULL
;
7385 LPWSTR nameW
= NULL
;
7387 DWORD numentries
= 0;
7390 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7391 cbBuf
, pcbNeeded
, pcReturned
);
7393 /* convert servername to unicode */
7395 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7396 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7397 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7399 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7400 needed
= cbBuf
* sizeof(WCHAR
);
7401 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7402 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7404 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7405 if (pcbNeeded
) needed
= *pcbNeeded
;
7406 /* HeapReAlloc return NULL, when bufferW was NULL */
7407 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7408 HeapAlloc(GetProcessHeap(), 0, needed
);
7410 /* Try again with the large Buffer */
7411 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7413 numentries
= pcReturned
? *pcReturned
: 0;
7416 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7417 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7420 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7421 DWORD entrysize
= 0;
7424 LPMONITOR_INFO_2W mi2w
;
7425 LPMONITOR_INFO_2A mi2a
;
7427 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7428 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7430 /* First pass: calculate the size for all Entries */
7431 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7432 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7434 while (index
< numentries
) {
7436 needed
+= entrysize
; /* MONITOR_INFO_?A */
7437 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7439 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7440 NULL
, 0, NULL
, NULL
);
7442 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7443 NULL
, 0, NULL
, NULL
);
7444 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7445 NULL
, 0, NULL
, NULL
);
7447 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7448 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7449 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7452 /* check for errors and quit on failure */
7453 if (cbBuf
< needed
) {
7454 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7458 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7459 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7460 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7461 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7462 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7464 /* Second Pass: Fill the User Buffer (if we have one) */
7465 while ((index
< numentries
) && pMonitors
) {
7467 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7469 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7470 ptr
, cbBuf
, NULL
, NULL
);
7474 mi2a
->pEnvironment
= ptr
;
7475 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7476 ptr
, cbBuf
, NULL
, NULL
);
7480 mi2a
->pDLLName
= ptr
;
7481 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7482 ptr
, cbBuf
, NULL
, NULL
);
7486 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7487 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7488 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7492 if (pcbNeeded
) *pcbNeeded
= needed
;
7493 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7495 HeapFree(GetProcessHeap(), 0, nameW
);
7496 HeapFree(GetProcessHeap(), 0, bufferW
);
7498 TRACE("returning %d with %d (%d byte for %d entries)\n",
7499 (res
), GetLastError(), needed
, numentries
);
7505 /*****************************************************************************
7506 * EnumMonitorsW [WINSPOOL.@]
7508 * Enumerate available Port-Monitors
7511 * pName [I] Servername or NULL (local Computer)
7512 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7513 * pMonitors [O] PTR to Buffer that receives the Result
7514 * cbBuf [I] Size of Buffer at pMonitors
7515 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7516 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7520 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7523 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7524 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7527 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7528 cbBuf
, pcbNeeded
, pcReturned
);
7530 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7532 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7533 SetLastError(RPC_X_NULL_REF_POINTER
);
7537 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7540 /******************************************************************************
7541 * SpoolerInit (WINSPOOL.@)
7543 * Initialize the Spooler
7550 * The function fails on windows, when the spooler service is not running
7553 BOOL WINAPI
SpoolerInit(void)
7556 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7560 /******************************************************************************
7561 * XcvDataW (WINSPOOL.@)
7563 * Execute commands in the Printmonitor DLL
7566 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7567 * pszDataName [i] Name of the command to execute
7568 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7569 * cbInputData [i] Size in Bytes of Buffer at pInputData
7570 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7571 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7572 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7573 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7580 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7581 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7583 * Minimal List of commands, that a Printmonitor DLL should support:
7585 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7586 *| "AddPort" : Add a Port
7587 *| "DeletePort": Delete a Port
7589 * Many Printmonitors support additional commands. Examples for localspl.dll:
7590 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7591 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7594 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7595 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7596 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7598 opened_printer_t
*printer
;
7600 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7601 pInputData
, cbInputData
, pOutputData
,
7602 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7604 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7606 printer
= get_opened_printer(hXcv
);
7607 if (!printer
|| (!printer
->backend_printer
)) {
7608 SetLastError(ERROR_INVALID_HANDLE
);
7612 if (!pcbOutputNeeded
) {
7613 SetLastError(ERROR_INVALID_PARAMETER
);
7617 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7618 SetLastError(RPC_X_NULL_REF_POINTER
);
7622 *pcbOutputNeeded
= 0;
7624 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7625 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7629 /*****************************************************************************
7630 * EnumPrinterDataA [WINSPOOL.@]
7633 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7634 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7635 DWORD cbData
, LPDWORD pcbData
)
7637 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7638 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7639 return ERROR_NO_MORE_ITEMS
;
7642 /*****************************************************************************
7643 * EnumPrinterDataW [WINSPOOL.@]
7646 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7647 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7648 DWORD cbData
, LPDWORD pcbData
)
7650 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7651 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7652 return ERROR_NO_MORE_ITEMS
;
7655 /*****************************************************************************
7656 * EnumPrinterKeyA [WINSPOOL.@]
7659 DWORD WINAPI
EnumPrinterKeyA(HANDLE printer
, const CHAR
*key
, CHAR
*subkey
, DWORD size
, DWORD
*needed
)
7661 FIXME("%p %s %p %x %p\n", printer
, debugstr_a(key
), subkey
, size
, needed
);
7662 return ERROR_CALL_NOT_IMPLEMENTED
;
7665 /*****************************************************************************
7666 * EnumPrinterKeyW [WINSPOOL.@]
7669 DWORD WINAPI
EnumPrinterKeyW(HANDLE printer
, const WCHAR
*key
, WCHAR
*subkey
, DWORD size
, DWORD
*needed
)
7671 FIXME("%p %s %p %x %p\n", printer
, debugstr_w(key
), subkey
, size
, needed
);
7672 return ERROR_CALL_NOT_IMPLEMENTED
;
7675 /*****************************************************************************
7676 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7679 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7680 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7681 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7683 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7684 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7685 pcbNeeded
, pcReturned
);
7689 /*****************************************************************************
7690 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7693 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7694 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7695 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7697 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7698 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7699 pcbNeeded
, pcReturned
);
7703 /*****************************************************************************
7704 * EnumPrintProcessorsA [WINSPOOL.@]
7706 * See EnumPrintProcessorsW.
7709 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7710 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7713 LPBYTE bufferW
= NULL
;
7714 LPWSTR nameW
= NULL
;
7717 DWORD numentries
= 0;
7720 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7721 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7723 /* convert names to unicode */
7725 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7726 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7727 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7730 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7731 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7732 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7735 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7736 needed
= cbBuf
* sizeof(WCHAR
);
7737 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7738 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7740 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7741 if (pcbNeeded
) needed
= *pcbNeeded
;
7742 /* HeapReAlloc return NULL, when bufferW was NULL */
7743 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7744 HeapAlloc(GetProcessHeap(), 0, needed
);
7746 /* Try again with the large Buffer */
7747 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7749 numentries
= pcReturned
? *pcReturned
: 0;
7753 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7756 PPRINTPROCESSOR_INFO_1W ppiw
;
7757 PPRINTPROCESSOR_INFO_1A ppia
;
7759 /* First pass: calculate the size for all Entries */
7760 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7761 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7763 while (index
< numentries
) {
7765 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7766 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7768 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7769 NULL
, 0, NULL
, NULL
);
7771 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7772 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7775 /* check for errors and quit on failure */
7776 if (cbBuf
< needed
) {
7777 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7782 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7783 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7784 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7785 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7786 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7788 /* Second Pass: Fill the User Buffer (if we have one) */
7789 while ((index
< numentries
) && pPPInfo
) {
7791 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7793 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7794 ptr
, cbBuf
, NULL
, NULL
);
7798 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7799 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7804 if (pcbNeeded
) *pcbNeeded
= needed
;
7805 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7807 HeapFree(GetProcessHeap(), 0, nameW
);
7808 HeapFree(GetProcessHeap(), 0, envW
);
7809 HeapFree(GetProcessHeap(), 0, bufferW
);
7811 TRACE("returning %d with %d (%d byte for %d entries)\n",
7812 (res
), GetLastError(), needed
, numentries
);
7817 /*****************************************************************************
7818 * EnumPrintProcessorsW [WINSPOOL.@]
7820 * Enumerate available Print Processors
7823 * pName [I] Servername or NULL (local Computer)
7824 * pEnvironment [I] Printing-Environment or NULL (Default)
7825 * Level [I] Structure-Level (Only 1 is allowed)
7826 * pPPInfo [O] PTR to Buffer that receives the Result
7827 * cbBuf [I] Size of Buffer at pPPInfo
7828 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7829 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7833 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7836 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7837 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7840 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7841 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7843 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7845 if (!pcbNeeded
|| !pcReturned
) {
7846 SetLastError(RPC_X_NULL_REF_POINTER
);
7850 if (!pPPInfo
&& (cbBuf
> 0)) {
7851 SetLastError(ERROR_INVALID_USER_BUFFER
);
7855 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7856 cbBuf
, pcbNeeded
, pcReturned
);
7859 /*****************************************************************************
7860 * ExtDeviceMode [WINSPOOL.@]
7863 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7864 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7867 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7868 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7869 debugstr_a(pProfile
), fMode
);
7873 /*****************************************************************************
7874 * FindClosePrinterChangeNotification [WINSPOOL.@]
7877 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7879 FIXME("Stub: %p\n", hChange
);
7883 /*****************************************************************************
7884 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7887 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7888 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7890 FIXME("Stub: %p %x %x %p\n",
7891 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7892 return INVALID_HANDLE_VALUE
;
7895 /*****************************************************************************
7896 * FindNextPrinterChangeNotification [WINSPOOL.@]
7899 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7900 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7902 FIXME("Stub: %p %p %p %p\n",
7903 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7907 /*****************************************************************************
7908 * FreePrinterNotifyInfo [WINSPOOL.@]
7911 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7913 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7917 /*****************************************************************************
7920 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7921 * ansi depending on the unicode parameter.
7923 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7933 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7936 memcpy(ptr
, str
, *size
);
7943 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7946 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7953 /*****************************************************************************
7956 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7957 LPDWORD pcbNeeded
, BOOL unicode
)
7959 DWORD size
, left
= cbBuf
;
7960 BOOL space
= (cbBuf
> 0);
7967 ji1
->JobId
= job
->job_id
;
7970 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7971 if(space
&& size
<= left
)
7973 ji1
->pDocument
= (LPWSTR
)ptr
;
7981 if (job
->printer_name
)
7983 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7984 if(space
&& size
<= left
)
7986 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7998 /*****************************************************************************
8001 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
8002 LPDWORD pcbNeeded
, BOOL unicode
)
8004 DWORD size
, left
= cbBuf
;
8006 BOOL space
= (cbBuf
> 0);
8008 LPDEVMODEA dmA
= NULL
;
8015 ji2
->JobId
= job
->job_id
;
8018 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
8019 if(space
&& size
<= left
)
8021 ji2
->pDocument
= (LPWSTR
)ptr
;
8029 if (job
->printer_name
)
8031 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
8032 if(space
&& size
<= left
)
8034 ji2
->pPrinterName
= (LPWSTR
)ptr
;
8047 dmA
= DEVMODEdupWtoA(job
->devmode
);
8048 devmode
= (LPDEVMODEW
) dmA
;
8049 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
8053 devmode
= job
->devmode
;
8054 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
8058 FIXME("Can't convert DEVMODE W to A\n");
8061 /* align DEVMODE to a DWORD boundary */
8062 shift
= (4 - (*pcbNeeded
& 3)) & 3;
8068 memcpy(ptr
, devmode
, size
-shift
);
8069 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
8070 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
8083 /*****************************************************************************
8086 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8087 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
8090 DWORD needed
= 0, size
;
8094 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
8096 EnterCriticalSection(&printer_handles_cs
);
8097 job
= get_job(hPrinter
, JobId
);
8104 size
= sizeof(JOB_INFO_1W
);
8109 memset(pJob
, 0, size
);
8113 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8118 size
= sizeof(JOB_INFO_2W
);
8123 memset(pJob
, 0, size
);
8127 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8132 size
= sizeof(JOB_INFO_3
);
8136 memset(pJob
, 0, size
);
8145 SetLastError(ERROR_INVALID_LEVEL
);
8149 *pcbNeeded
= needed
;
8151 LeaveCriticalSection(&printer_handles_cs
);
8155 /*****************************************************************************
8156 * GetJobA [WINSPOOL.@]
8159 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8160 DWORD cbBuf
, LPDWORD pcbNeeded
)
8162 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
8165 /*****************************************************************************
8166 * GetJobW [WINSPOOL.@]
8169 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8170 DWORD cbBuf
, LPDWORD pcbNeeded
)
8172 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
8175 /*****************************************************************************
8178 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
8181 char *unixname
, *cmdA
;
8183 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
8189 if(!(unixname
= wine_get_unix_file_name(filename
)))
8192 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
8193 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
8194 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
8196 TRACE("printing with: %s\n", cmdA
);
8198 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
8203 ERR("pipe() failed!\n");
8207 if ((pid
= fork()) == 0)
8213 /* reset signals that we previously set to SIG_IGN */
8214 signal(SIGPIPE
, SIG_DFL
);
8216 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
8221 ERR("fork() failed!\n");
8227 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
8228 write(fds
[1], buf
, no_read
);
8235 wret
= waitpid(pid
, &status
, 0);
8236 } while (wret
< 0 && errno
== EINTR
);
8239 ERR("waitpid() failed!\n");
8242 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
8244 ERR("child process failed! %d\n", status
);
8251 if(file_fd
!= -1) close(file_fd
);
8252 if(fds
[0] != -1) close(fds
[0]);
8253 if(fds
[1] != -1) close(fds
[1]);
8255 HeapFree(GetProcessHeap(), 0, cmdA
);
8256 HeapFree(GetProcessHeap(), 0, unixname
);
8263 /*****************************************************************************
8266 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8268 static const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8272 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8273 sprintfW(cmd
, fmtW
, printer_name
);
8275 r
= schedule_pipe(cmd
, filename
);
8277 HeapFree(GetProcessHeap(), 0, cmd
);
8281 #ifdef SONAME_LIBCUPS
8282 /*****************************************************************************
8283 * get_cups_jobs_ticket_options
8285 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8286 * The CUPS scheduler only looks for these in Print-File requests, and since
8287 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8290 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8292 FILE *fp
= fopen( file
, "r" );
8293 char buf
[257]; /* DSC max of 256 + '\0' */
8294 const char *ps_adobe
= "%!PS-Adobe-";
8295 const char *cups_job
= "%cupsJobTicket:";
8297 if (!fp
) return num_options
;
8298 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8299 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8300 while (fgets( buf
, sizeof(buf
), fp
))
8302 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8303 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8311 static int get_cups_default_options( const char *printer
, int num_options
, cups_option_t
**options
)
8316 if (!pcupsGetNamedDest
) return num_options
;
8318 dest
= pcupsGetNamedDest( NULL
, printer
, NULL
);
8319 if (!dest
) return num_options
;
8321 for (i
= 0; i
< dest
->num_options
; i
++)
8323 if (!pcupsGetOption( dest
->options
[i
].name
, num_options
, *options
))
8324 num_options
= pcupsAddOption( dest
->options
[i
].name
, dest
->options
[i
].value
,
8325 num_options
, options
);
8328 pcupsFreeDests( 1, dest
);
8333 /*****************************************************************************
8336 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8338 #ifdef SONAME_LIBCUPS
8341 char *unixname
, *queue
, *unix_doc_title
;
8344 int num_options
= 0, i
;
8345 cups_option_t
*options
= NULL
;
8347 if(!(unixname
= wine_get_unix_file_name(filename
)))
8350 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8351 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8352 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8354 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8355 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8356 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8358 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8359 num_options
= get_cups_default_options( queue
, num_options
, &options
);
8361 TRACE( "printing via cups with options:\n" );
8362 for (i
= 0; i
< num_options
; i
++)
8363 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8365 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8366 if (ret
== 0 && pcupsLastErrorString
)
8367 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8369 pcupsFreeOptions( num_options
, options
);
8371 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8372 HeapFree(GetProcessHeap(), 0, queue
);
8373 HeapFree(GetProcessHeap(), 0, unixname
);
8379 return schedule_lpr(printer_name
, filename
);
8383 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8390 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8394 if(HIWORD(wparam
) == BN_CLICKED
)
8396 if(LOWORD(wparam
) == IDOK
)
8399 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8402 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8403 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8405 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8407 WCHAR caption
[200], message
[200];
8410 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
8411 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, ARRAY_SIZE(message
));
8412 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8413 if(mb_ret
== IDCANCEL
)
8415 HeapFree(GetProcessHeap(), 0, filename
);
8419 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8420 if(hf
== INVALID_HANDLE_VALUE
)
8422 WCHAR caption
[200], message
[200];
8424 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
8425 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, ARRAY_SIZE(message
));
8426 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8427 HeapFree(GetProcessHeap(), 0, filename
);
8431 DeleteFileW(filename
);
8432 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8434 EndDialog(hwnd
, IDOK
);
8437 if(LOWORD(wparam
) == IDCANCEL
)
8439 EndDialog(hwnd
, IDCANCEL
);
8448 /*****************************************************************************
8451 static BOOL
get_filename(LPWSTR
*filename
)
8453 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8454 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8457 /*****************************************************************************
8460 static BOOL
schedule_file(LPCWSTR filename
)
8462 LPWSTR output
= NULL
;
8464 if(get_filename(&output
))
8467 TRACE("copy to %s\n", debugstr_w(output
));
8468 r
= CopyFileW(filename
, output
, FALSE
);
8469 HeapFree(GetProcessHeap(), 0, output
);
8475 /*****************************************************************************
8478 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8480 int in_fd
, out_fd
, no_read
;
8483 char *unixname
, *outputA
;
8486 if(!(unixname
= wine_get_unix_file_name(filename
)))
8489 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8490 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8491 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8493 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8494 in_fd
= open(unixname
, O_RDONLY
);
8495 if(out_fd
== -1 || in_fd
== -1)
8498 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8499 write(out_fd
, buf
, no_read
);
8503 if(in_fd
!= -1) close(in_fd
);
8504 if(out_fd
!= -1) close(out_fd
);
8505 HeapFree(GetProcessHeap(), 0, outputA
);
8506 HeapFree(GetProcessHeap(), 0, unixname
);
8510 /*****************************************************************************
8511 * ScheduleJob [WINSPOOL.@]
8514 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8516 opened_printer_t
*printer
;
8518 struct list
*cursor
, *cursor2
;
8520 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8521 EnterCriticalSection(&printer_handles_cs
);
8522 printer
= get_opened_printer(hPrinter
);
8526 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8528 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8531 if(job
->job_id
!= dwJobID
) continue;
8533 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8534 if(hf
!= INVALID_HANDLE_VALUE
)
8536 PRINTER_INFO_5W
*pi5
= NULL
;
8537 LPWSTR portname
= job
->portname
;
8541 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8542 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8546 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8547 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8548 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8549 portname
= pi5
->pPortName
;
8551 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8552 debugstr_w(portname
));
8556 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8557 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8559 DWORD type
, count
= sizeof(output
);
8560 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8563 if(output
[0] == '|')
8565 ret
= schedule_pipe(output
+ 1, job
->filename
);
8569 ret
= schedule_unixfile(output
, job
->filename
);
8571 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8573 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8575 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8577 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8579 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8581 ret
= schedule_file(job
->filename
);
8583 else if(isalpha(portname
[0]) && portname
[1] == ':')
8585 TRACE("copying to %s\n", debugstr_w(portname
));
8586 ret
= CopyFileW(job
->filename
, portname
, FALSE
);
8590 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8592 HeapFree(GetProcessHeap(), 0, pi5
);
8594 DeleteFileW(job
->filename
);
8596 list_remove(cursor
);
8597 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8598 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8599 HeapFree(GetProcessHeap(), 0, job
->portname
);
8600 HeapFree(GetProcessHeap(), 0, job
->filename
);
8601 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8602 HeapFree(GetProcessHeap(), 0, job
);
8606 LeaveCriticalSection(&printer_handles_cs
);
8610 /*****************************************************************************
8611 * StartDocDlgA [WINSPOOL.@]
8613 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8615 UNICODE_STRING usBuffer
;
8616 DOCINFOW docW
= { 0 };
8618 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8621 docW
.cbSize
= sizeof(docW
);
8622 if (doc
->lpszDocName
)
8624 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8625 if (!(docW
.lpszDocName
= docnameW
)) goto failed
;
8627 if (doc
->lpszOutput
)
8629 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8630 if (!(docW
.lpszOutput
= outputW
)) goto failed
;
8632 if (doc
->lpszDatatype
)
8634 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8635 if (!(docW
.lpszDatatype
= datatypeW
)) goto failed
;
8637 docW
.fwType
= doc
->fwType
;
8639 retW
= StartDocDlgW(hPrinter
, &docW
);
8643 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8644 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8645 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8646 HeapFree(GetProcessHeap(), 0, retW
);
8650 HeapFree(GetProcessHeap(), 0, datatypeW
);
8651 HeapFree(GetProcessHeap(), 0, outputW
);
8652 HeapFree(GetProcessHeap(), 0, docnameW
);
8657 /*****************************************************************************
8658 * StartDocDlgW [WINSPOOL.@]
8660 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8661 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8662 * port is "FILE:". Also returns the full path if passed a relative path.
8664 * The caller should free the returned string from the process heap.
8666 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8671 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8673 PRINTER_INFO_5W
*pi5
;
8674 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8675 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8677 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8678 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8679 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8681 HeapFree(GetProcessHeap(), 0, pi5
);
8684 HeapFree(GetProcessHeap(), 0, pi5
);
8687 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8691 if (get_filename(&name
))
8693 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8695 HeapFree(GetProcessHeap(), 0, name
);
8698 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8699 GetFullPathNameW(name
, len
, ret
, NULL
);
8700 HeapFree(GetProcessHeap(), 0, name
);
8705 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8708 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8709 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8711 attr
= GetFileAttributesW(ret
);
8712 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8714 HeapFree(GetProcessHeap(), 0, ret
);
8720 /*****************************************************************************
8721 * UploadPrinterDriverPackageA [WINSPOOL.@]
8723 HRESULT WINAPI
UploadPrinterDriverPackageA( LPCSTR server
, LPCSTR path
, LPCSTR env
,
8724 DWORD flags
, HWND hwnd
, LPSTR dst
, PULONG dstlen
)
8726 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server
), debugstr_a(path
), debugstr_a(env
),
8727 flags
, hwnd
, dst
, dstlen
);
8731 /*****************************************************************************
8732 * UploadPrinterDriverPackageW [WINSPOOL.@]
8734 HRESULT WINAPI
UploadPrinterDriverPackageW( LPCWSTR server
, LPCWSTR path
, LPCWSTR env
,
8735 DWORD flags
, HWND hwnd
, LPWSTR dst
, PULONG dstlen
)
8737 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server
), debugstr_w(path
), debugstr_w(env
),
8738 flags
, hwnd
, dst
, dstlen
);
8742 /*****************************************************************************
8743 * PerfOpen [WINSPOOL.@]
8745 DWORD WINAPI
PerfOpen(LPWSTR context
)
8747 FIXME("%s: stub\n", debugstr_w(context
));
8748 return ERROR_SUCCESS
;
8751 /*****************************************************************************
8752 * PerfClose [WINSPOOL.@]
8754 DWORD WINAPI
PerfClose(void)
8757 return ERROR_SUCCESS
;
8760 /*****************************************************************************
8761 * PerfCollect [WINSPOOL.@]
8763 DWORD WINAPI
PerfCollect(LPWSTR query
, LPVOID
*data
, LPDWORD size
, LPDWORD obj_count
)
8765 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query
), data
, size
, obj_count
);
8768 return ERROR_SUCCESS
;