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
108 #include "wine/library.h"
112 #include "winerror.h"
115 #include "winspool.h"
116 #include "winternl.h"
117 #include "wine/windef16.h"
118 #include "wine/unicode.h"
119 #include "wine/debug.h"
120 #include "wine/list.h"
123 #include "ddk/winsplp.h"
126 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
128 /* ############################### */
130 static CRITICAL_SECTION printer_handles_cs
;
131 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
133 0, 0, &printer_handles_cs
,
134 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
135 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
137 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
139 /* ############################### */
154 HANDLE backend_printer
;
165 WCHAR
*document_title
;
175 LPCWSTR versionregpath
;
176 LPCWSTR versionsubdir
;
179 /* ############################### */
181 static opened_printer_t
**printer_handles
;
182 static UINT nb_printer_handles
;
183 static LONG next_job_id
= 1;
185 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
186 WORD fwCapability
, LPSTR lpszOutput
,
188 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
189 LPSTR lpszDevice
, LPSTR lpszPort
,
190 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
193 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
194 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
195 'c','o','n','t','r','o','l','\\',
196 'P','r','i','n','t','\\',
197 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
198 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
200 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
201 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
202 'C','o','n','t','r','o','l','\\',
203 'P','r','i','n','t','\\',
204 'P','r','i','n','t','e','r','s',0};
206 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
207 'M','i','c','r','o','s','o','f','t','\\',
208 'W','i','n','d','o','w','s',' ','N','T','\\',
209 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
210 'W','i','n','d','o','w','s',0};
212 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
213 'M','i','c','r','o','s','o','f','t','\\',
214 'W','i','n','d','o','w','s',' ','N','T','\\',
215 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
216 'D','e','v','i','c','e','s',0};
218 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
219 'M','i','c','r','o','s','o','f','t','\\',
220 'W','i','n','d','o','w','s',' ','N','T','\\',
221 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
222 'P','r','i','n','t','e','r','P','o','r','t','s',0};
224 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
225 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
226 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
227 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
228 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
229 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
230 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
231 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
232 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
233 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
235 static const WCHAR AttributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0};
236 static const WCHAR backslashW
[] = {'\\',0};
237 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
238 'i','o','n',' ','F','i','l','e',0};
239 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
240 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
241 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
242 static const WCHAR Default_PriorityW
[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
243 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
244 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
245 static const WCHAR dnsTimeoutW
[] = {'d','n','s','T','i','m','e','o','u','t',0};
246 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
247 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
248 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
249 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
250 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
251 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
252 static const WCHAR NameW
[] = {'N','a','m','e',0};
253 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
254 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
255 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
256 static const WCHAR PortW
[] = {'P','o','r','t',0};
257 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
258 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
259 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
260 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
261 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',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 devicesW
[] = {'d','e','v','i','c','e','s',0};
273 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
274 static WCHAR rawW
[] = {'R','A','W',0};
275 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
276 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
277 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
278 static const WCHAR commaW
[] = {',',0};
279 static WCHAR emptyStringW
[] = {0};
281 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
283 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
284 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
285 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
287 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
288 'D','o','c','u','m','e','n','t',0};
290 static const WCHAR PPD_Overrides
[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
291 static const WCHAR DefaultPageSize
[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
293 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
294 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
295 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
296 0, sizeof(DRIVER_INFO_8W
)};
299 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
300 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
301 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
302 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
303 sizeof(PRINTER_INFO_9W
)};
305 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
306 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
307 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
309 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
311 /******************************************************************
312 * validate the user-supplied printing-environment [internal]
315 * env [I] PTR to Environment-String or NULL
319 * Success: PTR to printenv_t
322 * An empty string is handled the same way as NULL.
323 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
327 static const printenv_t
* validate_envW(LPCWSTR env
)
329 const printenv_t
*result
= NULL
;
332 TRACE("testing %s\n", debugstr_w(env
));
335 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
337 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
339 result
= all_printenv
[i
];
344 if (result
== NULL
) {
345 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
346 SetLastError(ERROR_INVALID_ENVIRONMENT
);
348 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
352 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
354 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
360 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
361 if passed a NULL string. This returns NULLs to the result.
363 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
367 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
368 return usBufferPtr
->Buffer
;
370 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
374 static LPWSTR
strdupW(LPCWSTR p
)
380 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
381 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
386 static LPSTR
strdupWtoA( LPCWSTR str
)
391 if (!str
) return NULL
;
392 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
393 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
394 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
398 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
402 if (!dm
) return NULL
;
403 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
404 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
408 /***********************************************************
410 * Creates an ansi copy of supplied devmode
412 static DEVMODEA
*DEVMODEdupWtoA( const DEVMODEW
*dmW
)
417 if (!dmW
) return NULL
;
418 size
= dmW
->dmSize
- CCHDEVICENAME
-
419 ((dmW
->dmSize
> FIELD_OFFSET( DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
421 dmA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
422 if (!dmA
) return NULL
;
424 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmDeviceName
, -1,
425 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
427 if (FIELD_OFFSET( DEVMODEW
, dmFormName
) >= dmW
->dmSize
)
429 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
430 dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
434 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
435 FIELD_OFFSET( DEVMODEW
, dmFormName
) - FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
436 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmFormName
, -1,
437 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
439 memcpy( &dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmLogPixels
) );
443 memcpy( (char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
448 /******************************************************************
449 * verify, that the filename is a local file
452 static inline BOOL
is_local_file(LPWSTR name
)
454 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
457 /* ################################ */
459 static int multi_sz_lenA(const char *str
)
461 const char *ptr
= str
;
465 ptr
+= lstrlenA(ptr
) + 1;
468 return ptr
- str
+ 1;
471 /*****************************************************************************
474 * Return DWORD associated with name from hkey.
476 static DWORD
get_dword_from_reg( HKEY hkey
, const WCHAR
*name
)
478 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
481 ret
= RegQueryValueExW( hkey
, name
, 0, &type
, (LPBYTE
)&value
, &sz
);
483 if (ret
!= ERROR_SUCCESS
)
485 WARN( "Got ret = %d on name %s\n", ret
, debugstr_w(name
) );
488 if (type
!= REG_DWORD
)
490 ERR( "Got type %d\n", type
);
496 static inline DWORD
set_reg_DWORD( HKEY hkey
, const WCHAR
*keyname
, const DWORD value
)
498 return RegSetValueExW( hkey
, keyname
, 0, REG_DWORD
, (const BYTE
*)&value
, sizeof(value
) );
501 /******************************************************************
503 * Get the pointer to the opened printer referred by the handle
505 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
507 UINT_PTR idx
= (UINT_PTR
)hprn
;
508 opened_printer_t
*ret
= NULL
;
510 EnterCriticalSection(&printer_handles_cs
);
512 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
513 ret
= printer_handles
[idx
- 1];
515 LeaveCriticalSection(&printer_handles_cs
);
519 /******************************************************************
520 * get_opened_printer_name
521 * Get the pointer to the opened printer name referred by the handle
523 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
525 opened_printer_t
*printer
= get_opened_printer(hprn
);
526 if(!printer
) return NULL
;
527 return printer
->name
;
530 static DWORD
open_printer_reg_key( const WCHAR
*name
, HKEY
*key
)
536 err
= RegCreateKeyW( HKEY_LOCAL_MACHINE
, PrintersW
, &printers
);
539 err
= RegOpenKeyW( printers
, name
, key
);
540 if (err
) err
= ERROR_INVALID_PRINTER_NAME
;
541 RegCloseKey( printers
);
545 /******************************************************************
546 * WINSPOOL_GetOpenedPrinterRegKey
549 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
551 LPCWSTR name
= get_opened_printer_name(hPrinter
);
553 if(!name
) return ERROR_INVALID_HANDLE
;
554 return open_printer_reg_key( name
, phkey
);
558 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
561 /* If forcing, or no profile string entry for device yet, set the entry
563 * The always change entry if not WINEPS yet is discussable.
566 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
568 !strstr(qbuf
,"WINEPS.DRV")
570 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
573 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
574 WriteProfileStringA("windows","device",buf
);
575 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
576 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
579 HeapFree(GetProcessHeap(),0,buf
);
583 static BOOL
add_printer_driver(const WCHAR
*name
, WCHAR
*ppd
)
589 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
591 di3
.pName
= (WCHAR
*)name
;
592 di3
.pDriverPath
= driver_nt
;
594 di3
.pConfigFile
= driver_nt
;
595 di3
.pDefaultDataType
= rawW
;
597 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
599 di3
.pEnvironment
= (WCHAR
*) all_printenv
[i
]->envname
;
600 if (all_printenv
[i
]->envname
== envname_win40W
)
602 /* We use wineps16.drv as driver for 16 bit */
603 di3
.pDriverPath
= driver_9x
;
604 di3
.pConfigFile
= driver_9x
;
606 res
= AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
);
607 TRACE("got %d and %d for %s (%s)\n", res
, GetLastError(), debugstr_w(name
), debugstr_w(di3
.pEnvironment
));
609 if (!res
& (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
611 ERR("failed with %u for %s (%s) %s\n", GetLastError(), debugstr_w(name
),
612 debugstr_w(di3
.pEnvironment
), debugstr_w(di3
.pDriverPath
));
620 static inline char *expand_env_string( char *str
, DWORD type
)
622 if (type
== REG_EXPAND_SZ
)
625 DWORD needed
= ExpandEnvironmentStringsA( str
, NULL
, 0 );
626 tmp
= HeapAlloc( GetProcessHeap(), 0, needed
);
629 ExpandEnvironmentStringsA( str
, tmp
, needed
);
630 HeapFree( GetProcessHeap(), 0, str
);
637 static char *get_fallback_ppd_name( const char *printer_name
)
639 static const WCHAR ppds_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
640 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
645 if (RegOpenKeyW( HKEY_CURRENT_USER
, ppds_key
, &hkey
) == ERROR_SUCCESS
)
647 const char *value_name
= NULL
;
649 if (RegQueryValueExA( hkey
, printer_name
, 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
650 value_name
= printer_name
;
651 else if (RegQueryValueExA( hkey
, "generic", 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
652 value_name
= "generic";
656 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
657 if (!ret
) return NULL
;
658 RegQueryValueExA( hkey
, value_name
, 0, &type
, (BYTE
*)ret
, &needed
);
661 if (ret
) return expand_env_string( ret
, type
);
666 static BOOL
copy_file( const char *src
, const char *dst
)
668 int fds
[2] = {-1, -1}, num
;
672 fds
[0] = open( src
, O_RDONLY
);
673 fds
[1] = open( dst
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666 );
674 if (fds
[0] == -1 || fds
[1] == -1) goto fail
;
676 while ((num
= read( fds
[0], buf
, sizeof(buf
) )) != 0)
678 if (num
== -1) goto fail
;
679 if (write( fds
[1], buf
, num
) != num
) goto fail
;
684 if (fds
[1] != -1) close( fds
[1] );
685 if (fds
[0] != -1) close( fds
[0] );
689 static BOOL
get_internal_fallback_ppd( const WCHAR
*ppd
)
691 static const WCHAR typeW
[] = {'P','P','D','F','I','L','E',0};
697 HRSRC res
= FindResourceW( WINSPOOL_hInstance
, MAKEINTRESOURCEW(1), typeW
);
699 if (!res
|| !(ptr
= LoadResource( WINSPOOL_hInstance
, res
))) return FALSE
;
700 size
= SizeofResource( WINSPOOL_hInstance
, res
);
701 end
= memchr( ptr
, 0, size
); /* resource file may contain additional nulls */
702 if (end
) size
= end
- ptr
;
703 file
= CreateFileW( ppd
, GENERIC_WRITE
, FILE_SHARE_READ
, NULL
, CREATE_ALWAYS
, 0, 0 );
704 if (file
== INVALID_HANDLE_VALUE
) return FALSE
;
705 ret
= WriteFile( file
, ptr
, size
, &written
, NULL
) && written
== size
;
707 if (ret
) TRACE( "using internal fallback for %s\n", debugstr_w( ppd
));
708 else DeleteFileW( ppd
);
712 static BOOL
get_fallback_ppd( const char *printer_name
, const WCHAR
*ppd
)
714 char *dst
, *src
= get_fallback_ppd_name( printer_name
);
717 if (!src
) return get_internal_fallback_ppd( ppd
);
719 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name
), debugstr_w(ppd
), debugstr_a(src
) );
721 if (!(dst
= wine_get_unix_file_name( ppd
))) goto fail
;
723 if (symlink( src
, dst
) == -1)
724 if (errno
!= ENOSYS
|| !copy_file( src
, dst
))
729 HeapFree( GetProcessHeap(), 0, dst
);
730 HeapFree( GetProcessHeap(), 0, src
);
734 static WCHAR
*get_ppd_filename( const WCHAR
*dir
, const WCHAR
*file_name
)
736 static const WCHAR dot_ppd
[] = {'.','p','p','d',0};
737 int len
= (strlenW( dir
) + strlenW( file_name
)) * sizeof(WCHAR
) + sizeof(dot_ppd
);
738 WCHAR
*ppd
= HeapAlloc( GetProcessHeap(), 0, len
);
740 if (!ppd
) return NULL
;
742 strcatW( ppd
, file_name
);
743 strcatW( ppd
, dot_ppd
);
748 static WCHAR
*get_ppd_dir( void )
750 static const WCHAR wine_ppds
[] = {'w','i','n','e','_','p','p','d','s','\\',0};
752 WCHAR
*dir
, tmp_path
[MAX_PATH
];
755 len
= GetTempPathW( sizeof(tmp_path
) / sizeof(tmp_path
[0]), tmp_path
);
756 if (!len
) return NULL
;
757 dir
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) + sizeof(wine_ppds
) ) ;
758 if (!dir
) return NULL
;
760 memcpy( dir
, tmp_path
, len
* sizeof(WCHAR
) );
761 memcpy( dir
+ len
, wine_ppds
, sizeof(wine_ppds
) );
762 res
= CreateDirectoryW( dir
, NULL
);
763 if (!res
&& GetLastError() != ERROR_ALREADY_EXISTS
)
765 HeapFree( GetProcessHeap(), 0, dir
);
768 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir
) );
772 static void unlink_ppd( const WCHAR
*ppd
)
774 char *unix_name
= wine_get_unix_file_name( ppd
);
776 HeapFree( GetProcessHeap(), 0, unix_name
);
779 #ifdef SONAME_LIBCUPS
781 static void *cupshandle
;
784 DO_FUNC(cupsAddOption); \
785 DO_FUNC(cupsFreeDests); \
786 DO_FUNC(cupsFreeOptions); \
787 DO_FUNC(cupsGetDests); \
788 DO_FUNC(cupsGetOption); \
789 DO_FUNC(cupsGetPPD); \
790 DO_FUNC(cupsParseOptions); \
791 DO_FUNC(cupsPrintFile)
792 #define CUPS_OPT_FUNCS \
793 DO_FUNC(cupsGetNamedDest); \
794 DO_FUNC(cupsGetPPD3); \
795 DO_FUNC(cupsLastErrorString)
797 #define DO_FUNC(f) static typeof(f) *p##f
800 static cups_dest_t
* (*pcupsGetNamedDest
)(http_t
*, const char *, const char *);
801 static http_status_t (*pcupsGetPPD3
)(http_t
*, const char *, time_t *, char *, size_t);
802 static const char * (*pcupsLastErrorString
)(void);
804 static http_status_t
cupsGetPPD3_wrapper( http_t
*http
, const char *name
,
805 time_t *modtime
, char *buffer
,
810 if (pcupsGetPPD3
) return pcupsGetPPD3( http
, name
, modtime
, buffer
, bufsize
);
812 if (!pcupsGetPPD
) return HTTP_NOT_FOUND
;
814 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
817 ppd
= pcupsGetPPD( name
);
819 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd
) );
821 if (!ppd
) return HTTP_NOT_FOUND
;
823 if (rename( ppd
, buffer
) == -1)
825 BOOL res
= copy_file( ppd
, buffer
);
827 if (!res
) return HTTP_NOT_FOUND
;
832 static BOOL
get_cups_ppd( const char *printer_name
, const WCHAR
*ppd
)
835 http_status_t http_status
;
836 char *unix_name
= wine_get_unix_file_name( ppd
);
838 TRACE( "(%s, %s)\n", debugstr_a(printer_name
), debugstr_w(ppd
) );
840 if (!unix_name
) return FALSE
;
842 http_status
= cupsGetPPD3_wrapper( 0, printer_name
, &modtime
,
843 unix_name
, strlen( unix_name
) + 1 );
845 if (http_status
!= HTTP_OK
) unlink( unix_name
);
846 HeapFree( GetProcessHeap(), 0, unix_name
);
848 if (http_status
== HTTP_OK
) return TRUE
;
850 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
851 debugstr_a(printer_name
), http_status
);
852 return get_fallback_ppd( printer_name
, ppd
);
855 static WCHAR
*get_cups_option( const char *name
, int num_options
, cups_option_t
*options
)
861 value
= pcupsGetOption( name
, num_options
, options
);
862 if (!value
) return NULL
;
864 len
= MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, NULL
, 0 );
865 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
866 if (ret
) MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, ret
, len
);
871 static cups_ptype_t
get_cups_printer_type( const cups_dest_t
*dest
)
873 WCHAR
*type
= get_cups_option( "printer-type", dest
->num_options
, dest
->options
), *end
;
874 cups_ptype_t ret
= 0;
878 ret
= (cups_ptype_t
)strtoulW( type
, &end
, 10 );
881 HeapFree( GetProcessHeap(), 0, type
);
885 static void load_cups(void)
887 cupshandle
= wine_dlopen( SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0 );
888 if (!cupshandle
) return;
890 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
893 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
896 ERR("failed to load symbol %s\n", #x); \
902 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
907 static BOOL
CUPS_LoadPrinters(void)
910 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
913 WCHAR
*port
, *ppd_dir
= NULL
, *ppd
;
914 HKEY hkeyPrinter
, hkeyPrinters
;
915 WCHAR nameW
[MAX_PATH
];
916 HANDLE added_printer
;
917 cups_ptype_t printer_type
;
919 if (!cupshandle
) return FALSE
;
921 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
923 ERR("Can't create Printers key\n");
927 nrofdests
= pcupsGetDests(&dests
);
928 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
929 for (i
=0;i
<nrofdests
;i
++) {
930 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
931 printer_type
= get_cups_printer_type( dests
+ i
);
933 TRACE( "Printer %d: %s. printer_type %x\n", i
, debugstr_w(nameW
), printer_type
);
935 if (printer_type
& 0x2000000 /* CUPS_PRINTER_SCANNER */)
937 TRACE( "skipping scanner-only device\n" );
941 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
942 lstrcpyW(port
, CUPS_Port
);
943 lstrcatW(port
, nameW
);
945 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
946 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
947 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
949 TRACE("Printer already exists\n");
950 /* overwrite old LPR:* port */
951 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
952 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
953 /* flag that the PPD file should be checked for an update */
954 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
955 RegCloseKey(hkeyPrinter
);
957 BOOL added_driver
= FALSE
;
959 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir()))
961 HeapFree( GetProcessHeap(), 0, port
);
964 ppd
= get_ppd_filename( ppd_dir
, nameW
);
965 if (get_cups_ppd( dests
[i
].name
, ppd
))
967 added_driver
= add_printer_driver( nameW
, ppd
);
970 HeapFree( GetProcessHeap(), 0, ppd
);
973 HeapFree( GetProcessHeap(), 0, port
);
977 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
978 pi2
.pPrinterName
= nameW
;
979 pi2
.pDatatype
= rawW
;
980 pi2
.pPrintProcessor
= WinPrintW
;
981 pi2
.pDriverName
= nameW
;
982 pi2
.pComment
= get_cups_option( "printer-info", dests
[i
].num_options
, dests
[i
].options
);
983 pi2
.pLocation
= get_cups_option( "printer-location", dests
[i
].num_options
, dests
[i
].options
);
984 pi2
.pPortName
= port
;
985 pi2
.pParameters
= emptyStringW
;
986 pi2
.pShareName
= emptyStringW
;
987 pi2
.pSepFile
= emptyStringW
;
989 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
990 if (added_printer
) ClosePrinter( added_printer
);
991 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
992 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
994 HeapFree( GetProcessHeap(), 0, pi2
.pComment
);
995 HeapFree( GetProcessHeap(), 0, pi2
.pLocation
);
997 HeapFree( GetProcessHeap(), 0, port
);
1000 if (dests
[i
].is_default
) {
1001 SetDefaultPrinterW(nameW
);
1008 RemoveDirectoryW( ppd_dir
);
1009 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1012 if (hadprinter
&& !haddefault
) {
1013 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
1014 SetDefaultPrinterW(nameW
);
1016 pcupsFreeDests(nrofdests
, dests
);
1017 RegCloseKey(hkeyPrinters
);
1023 static char *get_queue_name( HANDLE printer
, BOOL
*cups
)
1025 WCHAR
*port
, *name
= NULL
;
1026 DWORD err
, needed
, type
;
1032 err
= WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
);
1033 if (err
) return NULL
;
1034 err
= RegQueryValueExW( key
, PortW
, 0, &type
, NULL
, &needed
);
1036 port
= HeapAlloc( GetProcessHeap(), 0, needed
);
1037 if (!port
) goto end
;
1038 RegQueryValueExW( key
, PortW
, 0, &type
, (BYTE
*)port
, &needed
);
1040 if (!strncmpW( port
, CUPS_Port
, sizeof(CUPS_Port
) / sizeof(WCHAR
) -1 ))
1042 name
= port
+ sizeof(CUPS_Port
) / sizeof(WCHAR
) - 1;
1045 else if (!strncmpW( port
, LPR_Port
, sizeof(LPR_Port
) / sizeof(WCHAR
) -1 ))
1046 name
= port
+ sizeof(LPR_Port
) / sizeof(WCHAR
) - 1;
1049 needed
= WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
1050 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
1051 if(ret
) WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, ret
, needed
, NULL
, NULL
);
1053 HeapFree( GetProcessHeap(), 0, port
);
1060 static void set_ppd_overrides( HANDLE printer
)
1064 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1066 PMPrintSession session
= NULL
;
1067 PMPageFormat format
= NULL
;
1069 CFStringRef paper_name
;
1072 status
= PMCreateSession( &session
);
1073 if (status
) goto end
;
1075 status
= PMCreatePageFormat( &format
);
1076 if (status
) goto end
;
1078 status
= PMSessionDefaultPageFormat( session
, format
);
1079 if (status
) goto end
;
1081 status
= PMGetPageFormatPaper( format
, &paper
);
1082 if (status
) goto end
;
1084 status
= PMPaperGetPPDPaperName( paper
, &paper_name
);
1085 if (status
) goto end
;
1088 range
.length
= CFStringGetLength( paper_name
);
1089 size
= (range
.length
+ 1) * sizeof(WCHAR
);
1091 wstr
= HeapAlloc( GetProcessHeap(), 0, size
);
1092 CFStringGetCharacters( paper_name
, range
, (UniChar
*)wstr
);
1093 wstr
[range
.length
] = 0;
1096 if (format
) PMRelease( format
);
1097 if (session
) PMRelease( session
);
1100 SetPrinterDataExW( printer
, PPD_Overrides
, DefaultPageSize
, REG_SZ
, (BYTE
*)wstr
, size
);
1101 HeapFree( GetProcessHeap(), 0, wstr
);
1104 static BOOL
update_driver( HANDLE printer
)
1107 const WCHAR
*name
= get_opened_printer_name( printer
);
1108 WCHAR
*ppd_dir
, *ppd
;
1111 if (!name
) return FALSE
;
1112 queue_name
= get_queue_name( printer
, &is_cups
);
1113 if (!queue_name
) return FALSE
;
1115 if (!(ppd_dir
= get_ppd_dir()))
1117 HeapFree( GetProcessHeap(), 0, queue_name
);
1120 ppd
= get_ppd_filename( ppd_dir
, name
);
1122 #ifdef SONAME_LIBCUPS
1124 ret
= get_cups_ppd( queue_name
, ppd
);
1127 ret
= get_fallback_ppd( queue_name
, ppd
);
1131 TRACE( "updating driver %s\n", debugstr_w( name
) );
1132 ret
= add_printer_driver( name
, ppd
);
1135 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1136 HeapFree( GetProcessHeap(), 0, ppd
);
1137 HeapFree( GetProcessHeap(), 0, queue_name
);
1139 set_ppd_overrides( printer
);
1141 /* call into the driver to update the devmode */
1142 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
1147 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
1149 PRINTER_INFO_2A pinfo2a
;
1152 char *e
,*s
,*name
,*prettyname
,*devname
;
1153 BOOL ret
= FALSE
, set_default
= FALSE
;
1154 char *port
= NULL
, *env_default
;
1155 HKEY hkeyPrinter
, hkeyPrinters
= NULL
;
1156 WCHAR devnameW
[MAX_PATH
], *ppd_dir
= NULL
, *ppd
;
1157 HANDLE added_printer
;
1159 while (isspace(*pent
)) pent
++;
1160 r
= strchr(pent
,':');
1162 name_len
= r
- pent
;
1164 name_len
= strlen(pent
);
1165 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
1166 memcpy(name
, pent
, name_len
);
1167 name
[name_len
] = '\0';
1173 TRACE("name=%s entry=%s\n",name
, pent
);
1175 if(ispunct(*name
)) { /* a tc entry, not a real printer */
1176 TRACE("skipping tc entry\n");
1180 if(strstr(pent
,":server")) { /* server only version so skip */
1181 TRACE("skipping server entry\n");
1185 /* Determine whether this is a postscript printer. */
1188 env_default
= getenv("PRINTER");
1190 /* Get longest name, usually the one at the right for later display. */
1191 while((s
=strchr(prettyname
,'|'))) {
1194 while(isspace(*--e
)) *e
= '\0';
1195 TRACE("\t%s\n", debugstr_a(prettyname
));
1196 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1197 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
1200 e
= prettyname
+ strlen(prettyname
);
1201 while(isspace(*--e
)) *e
= '\0';
1202 TRACE("\t%s\n", debugstr_a(prettyname
));
1203 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1205 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1206 * if it is too long, we use it as comment below. */
1207 devname
= prettyname
;
1208 if (strlen(devname
)>=CCHDEVICENAME
-1)
1210 if (strlen(devname
)>=CCHDEVICENAME
-1) {
1215 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
1216 sprintf(port
,"LPR:%s",name
);
1218 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1220 ERR("Can't create Printers key\n");
1225 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
1227 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1228 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1229 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1231 TRACE("Printer already exists\n");
1232 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1233 /* flag that the PPD file should be checked for an update */
1234 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1235 RegCloseKey(hkeyPrinter
);
1237 static CHAR data_type
[] = "RAW",
1238 print_proc
[] = "WinPrint",
1239 comment
[] = "WINEPS Printer using LPR",
1240 params
[] = "<parameters?>",
1241 share_name
[] = "<share name?>",
1242 sep_file
[] = "<sep file?>";
1243 BOOL added_driver
= FALSE
;
1245 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir())) goto end
;
1246 ppd
= get_ppd_filename( ppd_dir
, devnameW
);
1247 if (get_fallback_ppd( devname
, ppd
))
1249 added_driver
= add_printer_driver( devnameW
, ppd
);
1252 HeapFree( GetProcessHeap(), 0, ppd
);
1253 if (!added_driver
) goto end
;
1255 memset(&pinfo2a
,0,sizeof(pinfo2a
));
1256 pinfo2a
.pPrinterName
= devname
;
1257 pinfo2a
.pDatatype
= data_type
;
1258 pinfo2a
.pPrintProcessor
= print_proc
;
1259 pinfo2a
.pDriverName
= devname
;
1260 pinfo2a
.pComment
= comment
;
1261 pinfo2a
.pLocation
= prettyname
;
1262 pinfo2a
.pPortName
= port
;
1263 pinfo2a
.pParameters
= params
;
1264 pinfo2a
.pShareName
= share_name
;
1265 pinfo2a
.pSepFile
= sep_file
;
1267 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
1268 if (added_printer
) ClosePrinter( added_printer
);
1269 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1270 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
1273 if (isfirst
|| set_default
)
1274 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
1277 if (hkeyPrinters
) RegCloseKey( hkeyPrinters
);
1280 RemoveDirectoryW( ppd_dir
);
1281 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1283 HeapFree(GetProcessHeap(), 0, port
);
1284 HeapFree(GetProcessHeap(), 0, name
);
1289 PRINTCAP_LoadPrinters(void) {
1290 BOOL hadprinter
= FALSE
;
1294 BOOL had_bash
= FALSE
;
1296 f
= fopen("/etc/printcap","r");
1300 while(fgets(buf
,sizeof(buf
),f
)) {
1303 end
=strchr(buf
,'\n');
1307 while(isspace(*start
)) start
++;
1308 if(*start
== '#' || *start
== '\0')
1311 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
1312 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1313 HeapFree(GetProcessHeap(),0,pent
);
1317 if (end
&& *--end
== '\\') {
1324 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
1327 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
1333 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1334 HeapFree(GetProcessHeap(),0,pent
);
1340 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
1343 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
1344 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
1346 return ERROR_FILE_NOT_FOUND
;
1349 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
1351 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
1352 DWORD ret
= ERROR_FILE_NOT_FOUND
;
1354 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1355 and we support these drivers. NT writes DEVMODEW so somehow
1356 we'll need to distinguish between these when we support NT
1361 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
1362 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1363 HeapFree( GetProcessHeap(), 0, dmA
);
1369 /******************************************************************
1370 * get_servername_from_name (internal)
1372 * for an external server, a copy of the serverpart from the full name is returned
1375 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1379 WCHAR buffer
[MAX_PATH
];
1382 if (name
== NULL
) return NULL
;
1383 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1385 server
= strdupW(&name
[2]); /* skip over both backslash */
1386 if (server
== NULL
) return NULL
;
1388 /* strip '\' and the printername */
1389 ptr
= strchrW(server
, '\\');
1390 if (ptr
) ptr
[0] = '\0';
1392 TRACE("found %s\n", debugstr_w(server
));
1394 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1395 if (GetComputerNameW(buffer
, &len
)) {
1396 if (lstrcmpW(buffer
, server
) == 0) {
1397 /* The requested Servername is our computername */
1398 HeapFree(GetProcessHeap(), 0, server
);
1405 /******************************************************************
1406 * get_basename_from_name (internal)
1408 * skip over the serverpart from the full name
1411 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1413 if (name
== NULL
) return NULL
;
1414 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1415 /* skip over the servername and search for the following '\' */
1416 name
= strchrW(&name
[2], '\\');
1417 if ((name
) && (name
[1])) {
1418 /* found a separator ('\') followed by a name:
1419 skip over the separator and return the rest */
1424 /* no basename present (we found only a servername) */
1431 static void free_printer_entry( opened_printer_t
*printer
)
1433 /* the queue is shared, so don't free that here */
1434 HeapFree( GetProcessHeap(), 0, printer
->printername
);
1435 HeapFree( GetProcessHeap(), 0, printer
->name
);
1436 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
1437 HeapFree( GetProcessHeap(), 0, printer
);
1440 /******************************************************************
1441 * get_opened_printer_entry
1442 * Get the first place empty in the opened printer table
1445 * - pDefault is ignored
1447 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1449 UINT_PTR handle
= nb_printer_handles
, i
;
1450 jobqueue_t
*queue
= NULL
;
1451 opened_printer_t
*printer
= NULL
;
1453 LPCWSTR printername
;
1455 if ((backend
== NULL
) && !load_backend()) return NULL
;
1457 servername
= get_servername_from_name(name
);
1459 FIXME("server %s not supported\n", debugstr_w(servername
));
1460 HeapFree(GetProcessHeap(), 0, servername
);
1461 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1465 printername
= get_basename_from_name(name
);
1466 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1468 /* an empty printername is invalid */
1469 if (printername
&& (!printername
[0])) {
1470 SetLastError(ERROR_INVALID_PARAMETER
);
1474 EnterCriticalSection(&printer_handles_cs
);
1476 for (i
= 0; i
< nb_printer_handles
; i
++)
1478 if (!printer_handles
[i
])
1480 if(handle
== nb_printer_handles
)
1485 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1486 queue
= printer_handles
[i
]->queue
;
1490 if (handle
>= nb_printer_handles
)
1492 opened_printer_t
**new_array
;
1493 if (printer_handles
)
1494 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1495 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1497 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1498 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1505 printer_handles
= new_array
;
1506 nb_printer_handles
+= 16;
1509 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1515 /* get a printer handle from the backend */
1516 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1521 /* clone the base name. This is NULL for the printserver */
1522 printer
->printername
= strdupW(printername
);
1524 /* clone the full name */
1525 printer
->name
= strdupW(name
);
1526 if (name
&& (!printer
->name
)) {
1531 if (pDefault
&& pDefault
->pDevMode
)
1532 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
1535 printer
->queue
= queue
;
1538 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1539 if (!printer
->queue
) {
1543 list_init(&printer
->queue
->jobs
);
1544 printer
->queue
->ref
= 0;
1546 InterlockedIncrement(&printer
->queue
->ref
);
1548 printer_handles
[handle
] = printer
;
1551 LeaveCriticalSection(&printer_handles_cs
);
1552 if (!handle
&& printer
) {
1553 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1554 free_printer_entry( printer
);
1557 return (HANDLE
)handle
;
1560 static void old_printer_check( BOOL delete_phase
)
1562 PRINTER_INFO_5W
* pi
;
1563 DWORD needed
, type
, num
, delete, i
, size
;
1564 const DWORD one
= 1;
1568 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1569 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1571 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1572 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1573 for (i
= 0; i
< num
; i
++)
1575 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1576 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1579 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1583 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1589 size
= sizeof( delete );
1590 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1594 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1595 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1597 DeletePrinter( hprn
);
1598 ClosePrinter( hprn
);
1600 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1604 HeapFree(GetProcessHeap(), 0, pi
);
1607 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1608 'M','U','T','E','X','_','_','\0'};
1609 static HANDLE init_mutex
;
1611 void WINSPOOL_LoadSystemPrinters(void)
1613 HKEY hkey
, hkeyPrinters
;
1614 DWORD needed
, num
, i
;
1615 WCHAR PrinterName
[256];
1618 #ifdef SONAME_LIBCUPS
1622 /* FIXME: The init code should be moved to spoolsv.exe */
1623 init_mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1626 ERR( "Failed to create mutex\n" );
1629 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1631 WaitForSingleObject( init_mutex
, INFINITE
);
1632 ReleaseMutex( init_mutex
);
1633 TRACE( "Init already done\n" );
1637 /* This ensures that all printer entries have a valid Name value. If causes
1638 problems later if they don't. If one is found to be missed we create one
1639 and set it equal to the name of the key */
1640 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1641 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1642 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1643 for(i
= 0; i
< num
; i
++) {
1644 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1645 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1646 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1647 set_reg_szW(hkey
, NameW
, PrinterName
);
1654 RegCloseKey(hkeyPrinters
);
1657 old_printer_check( FALSE
);
1659 #ifdef SONAME_LIBCUPS
1660 done
= CUPS_LoadPrinters();
1663 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1664 PRINTCAP_LoadPrinters();
1666 old_printer_check( TRUE
);
1668 ReleaseMutex( init_mutex
);
1672 /******************************************************************
1675 * Get the pointer to the specified job.
1676 * Should hold the printer_handles_cs before calling.
1678 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1680 opened_printer_t
*printer
= get_opened_printer(hprn
);
1683 if(!printer
) return NULL
;
1684 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1686 if(job
->job_id
== JobId
)
1692 /***********************************************************
1695 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1698 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1701 Formname
= (dmA
->dmSize
> off_formname
);
1702 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1703 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1704 dmW
->dmDeviceName
, CCHDEVICENAME
);
1706 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1707 dmA
->dmSize
- CCHDEVICENAME
);
1709 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1710 off_formname
- CCHDEVICENAME
);
1711 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1712 dmW
->dmFormName
, CCHFORMNAME
);
1713 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1714 (off_formname
+ CCHFORMNAME
));
1717 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1718 dmA
->dmDriverExtra
);
1722 /******************************************************************
1723 * convert_printerinfo_W_to_A [internal]
1726 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1727 DWORD level
, DWORD outlen
, DWORD numentries
)
1733 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1735 len
= pi_sizeof
[level
] * numentries
;
1736 ptr
= (LPSTR
) out
+ len
;
1739 /* copy the numbers of all PRINTER_INFO_* first */
1740 memcpy(out
, pPrintersW
, len
);
1742 while (id
< numentries
) {
1746 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1747 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1749 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1750 if (piW
->pDescription
) {
1751 piA
->pDescription
= ptr
;
1752 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1753 ptr
, outlen
, NULL
, NULL
);
1759 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1760 ptr
, outlen
, NULL
, NULL
);
1764 if (piW
->pComment
) {
1765 piA
->pComment
= ptr
;
1766 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1767 ptr
, outlen
, NULL
, NULL
);
1776 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1777 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1780 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1781 if (piW
->pServerName
) {
1782 piA
->pServerName
= ptr
;
1783 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1784 ptr
, outlen
, NULL
, NULL
);
1788 if (piW
->pPrinterName
) {
1789 piA
->pPrinterName
= ptr
;
1790 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1791 ptr
, outlen
, NULL
, NULL
);
1795 if (piW
->pShareName
) {
1796 piA
->pShareName
= ptr
;
1797 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1798 ptr
, outlen
, NULL
, NULL
);
1802 if (piW
->pPortName
) {
1803 piA
->pPortName
= ptr
;
1804 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1805 ptr
, outlen
, NULL
, NULL
);
1809 if (piW
->pDriverName
) {
1810 piA
->pDriverName
= ptr
;
1811 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1812 ptr
, outlen
, NULL
, NULL
);
1816 if (piW
->pComment
) {
1817 piA
->pComment
= ptr
;
1818 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1819 ptr
, outlen
, NULL
, NULL
);
1823 if (piW
->pLocation
) {
1824 piA
->pLocation
= ptr
;
1825 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1826 ptr
, outlen
, NULL
, NULL
);
1831 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1833 /* align DEVMODEA to a DWORD boundary */
1834 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1838 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1839 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1840 memcpy(ptr
, dmA
, len
);
1841 HeapFree(GetProcessHeap(), 0, dmA
);
1847 if (piW
->pSepFile
) {
1848 piA
->pSepFile
= ptr
;
1849 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1850 ptr
, outlen
, NULL
, NULL
);
1854 if (piW
->pPrintProcessor
) {
1855 piA
->pPrintProcessor
= ptr
;
1856 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1857 ptr
, outlen
, NULL
, NULL
);
1861 if (piW
->pDatatype
) {
1862 piA
->pDatatype
= ptr
;
1863 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1864 ptr
, outlen
, NULL
, NULL
);
1868 if (piW
->pParameters
) {
1869 piA
->pParameters
= ptr
;
1870 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1871 ptr
, outlen
, NULL
, NULL
);
1875 if (piW
->pSecurityDescriptor
) {
1876 piA
->pSecurityDescriptor
= NULL
;
1877 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1884 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1885 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1887 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1889 if (piW
->pPrinterName
) {
1890 piA
->pPrinterName
= ptr
;
1891 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1892 ptr
, outlen
, NULL
, NULL
);
1896 if (piW
->pServerName
) {
1897 piA
->pServerName
= ptr
;
1898 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1899 ptr
, outlen
, NULL
, NULL
);
1908 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1909 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1911 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1913 if (piW
->pPrinterName
) {
1914 piA
->pPrinterName
= ptr
;
1915 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1916 ptr
, outlen
, NULL
, NULL
);
1920 if (piW
->pPortName
) {
1921 piA
->pPortName
= ptr
;
1922 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1923 ptr
, outlen
, NULL
, NULL
);
1930 case 6: /* 6A and 6W are the same structure */
1935 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1936 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1938 TRACE("(%u) #%u\n", level
, id
);
1939 if (piW
->pszObjectGUID
) {
1940 piA
->pszObjectGUID
= ptr
;
1941 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1942 ptr
, outlen
, NULL
, NULL
);
1952 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1953 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1956 TRACE("(%u) #%u\n", level
, id
);
1957 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1959 /* align DEVMODEA to a DWORD boundary */
1960 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1964 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1965 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1966 memcpy(ptr
, dmA
, len
);
1967 HeapFree(GetProcessHeap(), 0, dmA
);
1977 FIXME("for level %u\n", level
);
1979 pPrintersW
+= pi_sizeof
[level
];
1980 out
+= pi_sizeof
[level
];
1985 /******************************************************************
1986 * convert_driverinfo_W_to_A [internal]
1989 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1990 DWORD level
, DWORD outlen
, DWORD numentries
)
1996 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1998 len
= di_sizeof
[level
] * numentries
;
1999 ptr
= (LPSTR
) out
+ len
;
2002 /* copy the numbers of all PRINTER_INFO_* first */
2003 memcpy(out
, pDriversW
, len
);
2005 #define COPY_STRING(fld) \
2008 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2009 ptr += len; outlen -= len;\
2011 #define COPY_MULTIZ_STRING(fld) \
2012 { LPWSTR p = diW->fld; if (p){ \
2015 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2016 ptr += len; outlen -= len; p += len;\
2018 while(len > 1 && outlen > 0); \
2021 while (id
< numentries
)
2027 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
2028 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
2030 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2037 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
2038 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
2040 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2043 COPY_STRING(pEnvironment
);
2044 COPY_STRING(pDriverPath
);
2045 COPY_STRING(pDataFile
);
2046 COPY_STRING(pConfigFile
);
2051 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
2052 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
2054 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2057 COPY_STRING(pEnvironment
);
2058 COPY_STRING(pDriverPath
);
2059 COPY_STRING(pDataFile
);
2060 COPY_STRING(pConfigFile
);
2061 COPY_STRING(pHelpFile
);
2062 COPY_MULTIZ_STRING(pDependentFiles
);
2063 COPY_STRING(pMonitorName
);
2064 COPY_STRING(pDefaultDataType
);
2069 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
2070 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
2072 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2075 COPY_STRING(pEnvironment
);
2076 COPY_STRING(pDriverPath
);
2077 COPY_STRING(pDataFile
);
2078 COPY_STRING(pConfigFile
);
2079 COPY_STRING(pHelpFile
);
2080 COPY_MULTIZ_STRING(pDependentFiles
);
2081 COPY_STRING(pMonitorName
);
2082 COPY_STRING(pDefaultDataType
);
2083 COPY_MULTIZ_STRING(pszzPreviousNames
);
2088 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
2089 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
2091 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2094 COPY_STRING(pEnvironment
);
2095 COPY_STRING(pDriverPath
);
2096 COPY_STRING(pDataFile
);
2097 COPY_STRING(pConfigFile
);
2102 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
2103 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
2105 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2108 COPY_STRING(pEnvironment
);
2109 COPY_STRING(pDriverPath
);
2110 COPY_STRING(pDataFile
);
2111 COPY_STRING(pConfigFile
);
2112 COPY_STRING(pHelpFile
);
2113 COPY_MULTIZ_STRING(pDependentFiles
);
2114 COPY_STRING(pMonitorName
);
2115 COPY_STRING(pDefaultDataType
);
2116 COPY_MULTIZ_STRING(pszzPreviousNames
);
2117 COPY_STRING(pszMfgName
);
2118 COPY_STRING(pszOEMUrl
);
2119 COPY_STRING(pszHardwareID
);
2120 COPY_STRING(pszProvider
);
2125 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
2126 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
2128 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2131 COPY_STRING(pEnvironment
);
2132 COPY_STRING(pDriverPath
);
2133 COPY_STRING(pDataFile
);
2134 COPY_STRING(pConfigFile
);
2135 COPY_STRING(pHelpFile
);
2136 COPY_MULTIZ_STRING(pDependentFiles
);
2137 COPY_STRING(pMonitorName
);
2138 COPY_STRING(pDefaultDataType
);
2139 COPY_MULTIZ_STRING(pszzPreviousNames
);
2140 COPY_STRING(pszMfgName
);
2141 COPY_STRING(pszOEMUrl
);
2142 COPY_STRING(pszHardwareID
);
2143 COPY_STRING(pszProvider
);
2144 COPY_STRING(pszPrintProcessor
);
2145 COPY_STRING(pszVendorSetup
);
2146 COPY_MULTIZ_STRING(pszzColorProfiles
);
2147 COPY_STRING(pszInfPath
);
2148 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
2154 FIXME("for level %u\n", level
);
2157 pDriversW
+= di_sizeof
[level
];
2158 out
+= di_sizeof
[level
];
2163 #undef COPY_MULTIZ_STRING
2167 /***********************************************************
2170 static void *printer_info_AtoW( const void *data
, DWORD level
)
2173 UNICODE_STRING usBuffer
;
2175 if (!data
) return NULL
;
2177 if (level
< 1 || level
> 9) return NULL
;
2179 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
2180 if (!ret
) return NULL
;
2182 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
2188 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
2189 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
2191 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
2192 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
2193 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
2194 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
2195 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
2196 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
2197 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
2198 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2199 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
2200 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
2201 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
2202 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
2209 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
2210 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
2212 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2217 FIXME( "Unhandled level %d\n", level
);
2218 HeapFree( GetProcessHeap(), 0, ret
);
2225 /***********************************************************
2228 static void free_printer_info( void *data
, DWORD level
)
2236 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
2238 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
2239 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
2240 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
2241 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
2242 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
2243 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
2244 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
2245 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2246 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
2247 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
2248 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
2249 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
2256 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
2258 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2263 FIXME( "Unhandled level %d\n", level
);
2266 HeapFree( GetProcessHeap(), 0, data
);
2270 /******************************************************************
2271 * DeviceCapabilities [WINSPOOL.@]
2272 * DeviceCapabilitiesA [WINSPOOL.@]
2275 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
2276 LPSTR pOutput
, LPDEVMODEA lpdm
)
2280 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice
), debugstr_a(pPort
), cap
, pOutput
, lpdm
);
2282 if (!GDI_CallDeviceCapabilities16
)
2284 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2286 if (!GDI_CallDeviceCapabilities16
) return -1;
2288 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
2290 /* If DC_PAPERSIZE map POINT16s to POINTs */
2291 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
2292 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
2293 POINT
*pt
= (POINT
*)pOutput
;
2295 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
2296 for(i
= 0; i
< ret
; i
++, pt
++)
2301 HeapFree( GetProcessHeap(), 0, tmp
);
2307 /*****************************************************************************
2308 * DeviceCapabilitiesW [WINSPOOL.@]
2310 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2313 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2314 WORD fwCapability
, LPWSTR pOutput
,
2315 const DEVMODEW
*pDevMode
)
2317 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
2318 LPSTR pDeviceA
= strdupWtoA(pDevice
);
2319 LPSTR pPortA
= strdupWtoA(pPort
);
2322 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice
), debugstr_w(pPort
), fwCapability
, pOutput
, pDevMode
);
2324 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
2325 fwCapability
== DC_FILEDEPENDENCIES
||
2326 fwCapability
== DC_PAPERNAMES
)) {
2327 /* These need A -> W translation */
2330 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2334 switch(fwCapability
) {
2339 case DC_FILEDEPENDENCIES
:
2343 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2344 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2346 for(i
= 0; i
< ret
; i
++)
2347 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2348 pOutput
+ (i
* size
), size
);
2349 HeapFree(GetProcessHeap(), 0, pOutputA
);
2351 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2352 (LPSTR
)pOutput
, dmA
);
2354 HeapFree(GetProcessHeap(),0,pPortA
);
2355 HeapFree(GetProcessHeap(),0,pDeviceA
);
2356 HeapFree(GetProcessHeap(),0,dmA
);
2360 /******************************************************************
2361 * DocumentPropertiesA [WINSPOOL.@]
2363 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2365 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2366 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2367 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2369 LPSTR lpName
= pDeviceName
, dupname
= NULL
;
2370 static CHAR port
[] = "LPT1:";
2373 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2374 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2377 if(!pDeviceName
|| !*pDeviceName
) {
2378 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2380 ERR("no name from hPrinter?\n");
2381 SetLastError(ERROR_INVALID_HANDLE
);
2384 lpName
= dupname
= strdupWtoA(lpNameW
);
2387 if (!GDI_CallExtDeviceMode16
)
2389 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2391 if (!GDI_CallExtDeviceMode16
) {
2392 ERR("No CallExtDeviceMode16?\n");
2397 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2398 pDevModeInput
, NULL
, fMode
);
2401 HeapFree(GetProcessHeap(), 0, dupname
);
2406 /*****************************************************************************
2407 * DocumentPropertiesW (WINSPOOL.@)
2409 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2411 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2413 LPDEVMODEW pDevModeOutput
,
2414 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2417 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2418 LPDEVMODEA pDevModeInputA
;
2419 LPDEVMODEA pDevModeOutputA
= NULL
;
2422 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2423 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2425 if(pDevModeOutput
) {
2426 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2427 if(ret
< 0) return ret
;
2428 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2430 pDevModeInputA
= (fMode
& DM_IN_BUFFER
) ? DEVMODEdupWtoA(pDevModeInput
) : NULL
;
2431 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2432 pDevModeInputA
, fMode
);
2433 if(pDevModeOutput
) {
2434 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2435 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2437 if(fMode
== 0 && ret
> 0)
2438 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2439 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2440 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2444 /*****************************************************************************
2445 * IsValidDevmodeA [WINSPOOL.@]
2447 * Validate a DEVMODE structure and fix errors if possible.
2450 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
2452 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2460 /*****************************************************************************
2461 * IsValidDevmodeW [WINSPOOL.@]
2463 * Validate a DEVMODE structure and fix errors if possible.
2466 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
2468 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2476 /******************************************************************
2477 * OpenPrinterA [WINSPOOL.@]
2482 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2483 LPPRINTER_DEFAULTSA pDefault
)
2485 UNICODE_STRING lpPrinterNameW
;
2486 UNICODE_STRING usBuffer
;
2487 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2488 PWSTR pwstrPrinterNameW
;
2491 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName
), phPrinter
, pDefault
);
2493 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2496 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2497 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2498 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2499 pDefaultW
= &DefaultW
;
2501 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2503 RtlFreeUnicodeString(&usBuffer
);
2504 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2506 RtlFreeUnicodeString(&lpPrinterNameW
);
2510 /******************************************************************
2511 * OpenPrinterW [WINSPOOL.@]
2513 * Open a Printer / Printserver or a Printer-Object
2516 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2517 * phPrinter [O] The resulting Handle is stored here
2518 * pDefault [I] PTR to Default Printer Settings or NULL
2525 * lpPrinterName is one of:
2526 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2527 *| Printer: "PrinterName"
2528 *| Printer-Object: "PrinterName,Job xxx"
2529 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2530 *| XcvPort: "Servername,XcvPort PortName"
2533 *| Printer-Object not supported
2534 *| pDefaults is ignored
2537 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2541 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2544 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2545 SetLastError(ERROR_INVALID_PARAMETER
);
2549 /* Get the unique handle of the printer or Printserver */
2550 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2552 if (*phPrinter
&& WINSPOOL_GetOpenedPrinterRegKey( *phPrinter
, &key
) == ERROR_SUCCESS
)
2554 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2556 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2557 WaitForSingleObject( init_mutex
, INFINITE
);
2558 status
= get_dword_from_reg( key
, StatusW
);
2559 set_reg_DWORD( key
, StatusW
, status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2560 ReleaseMutex( init_mutex
);
2561 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2562 update_driver( *phPrinter
);
2566 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2567 return (*phPrinter
!= 0);
2570 /******************************************************************
2571 * AddMonitorA [WINSPOOL.@]
2576 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2578 LPWSTR nameW
= NULL
;
2581 LPMONITOR_INFO_2A mi2a
;
2582 MONITOR_INFO_2W mi2w
;
2584 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2585 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2586 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2587 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2588 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2591 SetLastError(ERROR_INVALID_LEVEL
);
2595 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2601 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2602 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2603 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2606 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2608 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2609 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2610 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2612 if (mi2a
->pEnvironment
) {
2613 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2614 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2615 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2617 if (mi2a
->pDLLName
) {
2618 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2619 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2620 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2623 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2625 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2626 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2627 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2629 HeapFree(GetProcessHeap(), 0, nameW
);
2633 /******************************************************************************
2634 * AddMonitorW [WINSPOOL.@]
2636 * Install a Printmonitor
2639 * pName [I] Servername or NULL (local Computer)
2640 * Level [I] Structure-Level (Must be 2)
2641 * pMonitors [I] PTR to MONITOR_INFO_2
2648 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2651 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2653 LPMONITOR_INFO_2W mi2w
;
2655 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2656 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2657 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2658 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2659 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2661 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2664 SetLastError(ERROR_INVALID_LEVEL
);
2668 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2673 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2676 /******************************************************************
2677 * DeletePrinterDriverA [WINSPOOL.@]
2680 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2682 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2685 /******************************************************************
2686 * DeletePrinterDriverW [WINSPOOL.@]
2689 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2691 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2694 /******************************************************************
2695 * DeleteMonitorA [WINSPOOL.@]
2697 * See DeleteMonitorW.
2700 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2702 LPWSTR nameW
= NULL
;
2703 LPWSTR EnvironmentW
= NULL
;
2704 LPWSTR MonitorNameW
= NULL
;
2709 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2710 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2711 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2715 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2716 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2717 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2720 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2721 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2722 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2725 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2727 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2728 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2729 HeapFree(GetProcessHeap(), 0, nameW
);
2733 /******************************************************************
2734 * DeleteMonitorW [WINSPOOL.@]
2736 * Delete a specific Printmonitor from a Printing-Environment
2739 * pName [I] Servername or NULL (local Computer)
2740 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2741 * pMonitorName [I] Name of the Monitor, that should be deleted
2748 * pEnvironment is ignored in Windows for the local Computer.
2751 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2754 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2755 debugstr_w(pMonitorName
));
2757 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2759 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2763 /******************************************************************
2764 * DeletePortA [WINSPOOL.@]
2769 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2771 LPWSTR nameW
= NULL
;
2772 LPWSTR portW
= NULL
;
2776 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2778 /* convert servername to unicode */
2780 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2781 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2782 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2785 /* convert portname to unicode */
2787 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2788 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2789 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2792 res
= DeletePortW(nameW
, hWnd
, portW
);
2793 HeapFree(GetProcessHeap(), 0, nameW
);
2794 HeapFree(GetProcessHeap(), 0, portW
);
2798 /******************************************************************
2799 * DeletePortW [WINSPOOL.@]
2801 * Delete a specific Port
2804 * pName [I] Servername or NULL (local Computer)
2805 * hWnd [I] Handle to parent Window for the Dialog-Box
2806 * pPortName [I] Name of the Port, that should be deleted
2813 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2815 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2817 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2820 SetLastError(RPC_X_NULL_REF_POINTER
);
2824 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2827 /******************************************************************************
2828 * WritePrinter [WINSPOOL.@]
2830 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2832 opened_printer_t
*printer
;
2835 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2837 EnterCriticalSection(&printer_handles_cs
);
2838 printer
= get_opened_printer(hPrinter
);
2841 SetLastError(ERROR_INVALID_HANDLE
);
2847 SetLastError(ERROR_SPL_NO_STARTDOC
);
2851 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2853 LeaveCriticalSection(&printer_handles_cs
);
2857 /*****************************************************************************
2858 * AddFormA [WINSPOOL.@]
2860 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2862 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2866 /*****************************************************************************
2867 * AddFormW [WINSPOOL.@]
2869 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2871 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2875 /*****************************************************************************
2876 * AddJobA [WINSPOOL.@]
2878 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2881 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2885 SetLastError(ERROR_INVALID_LEVEL
);
2889 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2892 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2893 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2894 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2895 if(*pcbNeeded
> cbBuf
) {
2896 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2899 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2900 addjobA
->JobId
= addjobW
->JobId
;
2901 addjobA
->Path
= (char *)(addjobA
+ 1);
2902 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2908 /*****************************************************************************
2909 * AddJobW [WINSPOOL.@]
2911 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2913 opened_printer_t
*printer
;
2916 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2917 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2918 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2920 ADDJOB_INFO_1W
*addjob
;
2922 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2924 EnterCriticalSection(&printer_handles_cs
);
2926 printer
= get_opened_printer(hPrinter
);
2929 SetLastError(ERROR_INVALID_HANDLE
);
2934 SetLastError(ERROR_INVALID_LEVEL
);
2938 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2942 job
->job_id
= InterlockedIncrement(&next_job_id
);
2944 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2945 if(path
[len
- 1] != '\\')
2947 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2948 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2950 len
= strlenW(filename
);
2951 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2952 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2953 job
->portname
= NULL
;
2954 job
->document_title
= strdupW(default_doc_title
);
2955 job
->printer_name
= strdupW(printer
->name
);
2956 job
->devmode
= dup_devmode( printer
->devmode
);
2957 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2959 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2960 if(*pcbNeeded
<= cbBuf
) {
2961 addjob
= (ADDJOB_INFO_1W
*)pData
;
2962 addjob
->JobId
= job
->job_id
;
2963 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2964 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2967 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2970 LeaveCriticalSection(&printer_handles_cs
);
2974 /*****************************************************************************
2975 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2977 * Return the PATH for the Print-Processors
2979 * See GetPrintProcessorDirectoryW.
2983 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2984 DWORD level
, LPBYTE Info
,
2985 DWORD cbBuf
, LPDWORD pcbNeeded
)
2987 LPWSTR serverW
= NULL
;
2992 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2993 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2997 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2998 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2999 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
3003 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
3004 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3005 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
3008 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3009 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3011 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
3014 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
3015 cbBuf
, NULL
, NULL
) > 0;
3018 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
3019 HeapFree(GetProcessHeap(), 0, envW
);
3020 HeapFree(GetProcessHeap(), 0, serverW
);
3024 /*****************************************************************************
3025 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3027 * Return the PATH for the Print-Processors
3030 * server [I] Servername (NT only) or NULL (local Computer)
3031 * env [I] Printing-Environment (see below) or NULL (Default)
3032 * level [I] Structure-Level (must be 1)
3033 * Info [O] PTR to Buffer that receives the Result
3034 * cbBuf [I] Size of Buffer at "Info"
3035 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3036 * required for the Buffer at "Info"
3039 * Success: TRUE and in pcbNeeded the Bytes used in Info
3040 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3041 * if cbBuf is too small
3043 * Native Values returned in Info on Success:
3044 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3045 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3046 *| win9x(Windows 4.0): "%winsysdir%"
3048 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3051 * Only NULL or "" is supported for server
3054 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
3055 DWORD level
, LPBYTE Info
,
3056 DWORD cbBuf
, LPDWORD pcbNeeded
)
3059 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
3060 Info
, cbBuf
, pcbNeeded
);
3062 if ((backend
== NULL
) && !load_backend()) return FALSE
;
3065 /* (Level != 1) is ignored in win9x */
3066 SetLastError(ERROR_INVALID_LEVEL
);
3070 if (pcbNeeded
== NULL
) {
3071 /* (pcbNeeded == NULL) is ignored in win9x */
3072 SetLastError(RPC_X_NULL_REF_POINTER
);
3076 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
3079 /*****************************************************************************
3080 * WINSPOOL_OpenDriverReg [internal]
3082 * opens the registry for the printer drivers depending on the given input
3083 * variable pEnvironment
3086 * the opened hkey on success
3089 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
3093 const printenv_t
* env
;
3095 TRACE("(%s)\n", debugstr_w(pEnvironment
));
3097 env
= validate_envW(pEnvironment
);
3098 if (!env
) return NULL
;
3100 buffer
= HeapAlloc( GetProcessHeap(), 0,
3101 (strlenW(DriversW
) + strlenW(env
->envname
) +
3102 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
3104 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
3105 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
3106 HeapFree(GetProcessHeap(), 0, buffer
);
3111 /*****************************************************************************
3112 * set_devices_and_printerports [internal]
3114 * set the [Devices] and [PrinterPorts] entries for a printer.
3117 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
3119 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
3123 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
3125 /* FIXME: the driver must change to "winspool" */
3126 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
3128 lstrcpyW(devline
, driver_nt
);
3129 lstrcatW(devline
, commaW
);
3130 lstrcatW(devline
, pi
->pPortName
);
3132 TRACE("using %s\n", debugstr_w(devline
));
3133 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
3134 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
3135 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3136 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3140 lstrcatW(devline
, timeout_15_45
);
3141 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
3142 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
3143 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3144 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3147 HeapFree(GetProcessHeap(), 0, devline
);
3151 /*****************************************************************************
3152 * AddPrinterW [WINSPOOL.@]
3154 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3156 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
3159 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
3162 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
3164 if(pName
&& *pName
) {
3165 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
3166 SetLastError(ERROR_INVALID_PARAMETER
);
3170 ERR("Level = %d, unsupported!\n", Level
);
3171 SetLastError(ERROR_INVALID_LEVEL
);
3175 SetLastError(ERROR_INVALID_PARAMETER
);
3178 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3180 ERR("Can't create Printers key\n");
3183 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3184 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
3185 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3186 RegCloseKey(hkeyPrinter
);
3187 RegCloseKey(hkeyPrinters
);
3190 RegCloseKey(hkeyPrinter
);
3192 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
3194 ERR("Can't create Drivers key\n");
3195 RegCloseKey(hkeyPrinters
);
3198 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3200 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3201 RegCloseKey(hkeyPrinters
);
3202 RegCloseKey(hkeyDrivers
);
3203 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3206 RegCloseKey(hkeyDriver
);
3207 RegCloseKey(hkeyDrivers
);
3209 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3210 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3211 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3212 RegCloseKey(hkeyPrinters
);
3216 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3218 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3219 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3220 RegCloseKey(hkeyPrinters
);
3224 set_devices_and_printerports(pi
);
3226 set_reg_DWORD(hkeyPrinter
, AttributesW
, pi
->Attributes
);
3227 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3228 set_reg_DWORD(hkeyPrinter
, Default_PriorityW
, pi
->DefaultPriority
);
3229 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3230 set_reg_DWORD(hkeyPrinter
, dnsTimeoutW
, 0);
3231 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3232 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3233 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3234 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3235 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3236 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3237 set_reg_DWORD(hkeyPrinter
, PriorityW
, pi
->Priority
);
3238 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3239 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3240 set_reg_DWORD(hkeyPrinter
, StartTimeW
, pi
->StartTime
);
3241 set_reg_DWORD(hkeyPrinter
, StatusW
, pi
->Status
);
3242 set_reg_DWORD(hkeyPrinter
, txTimeoutW
, 0);
3243 set_reg_DWORD(hkeyPrinter
, UntilTimeW
, pi
->UntilTime
);
3245 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3249 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3250 size
= sizeof(DEVMODEW
);
3256 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3258 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
3260 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3261 HeapFree( GetProcessHeap(), 0, dm
);
3266 /* set devmode to printer name */
3267 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3271 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
3272 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
3274 RegCloseKey(hkeyPrinter
);
3275 RegCloseKey(hkeyPrinters
);
3276 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3277 ERR("OpenPrinter failing\n");
3283 /*****************************************************************************
3284 * AddPrinterA [WINSPOOL.@]
3286 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3288 UNICODE_STRING pNameW
;
3290 PRINTER_INFO_2W
*piW
;
3291 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3294 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
3296 ERR("Level = %d, unsupported!\n", Level
);
3297 SetLastError(ERROR_INVALID_LEVEL
);
3300 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3301 piW
= printer_info_AtoW( piA
, Level
);
3303 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3305 free_printer_info( piW
, Level
);
3306 RtlFreeUnicodeString(&pNameW
);
3311 /*****************************************************************************
3312 * ClosePrinter [WINSPOOL.@]
3314 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3316 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3317 opened_printer_t
*printer
= NULL
;
3319 TRACE("(%p)\n", hPrinter
);
3321 EnterCriticalSection(&printer_handles_cs
);
3323 if ((i
> 0) && (i
<= nb_printer_handles
))
3324 printer
= printer_handles
[i
- 1];
3329 struct list
*cursor
, *cursor2
;
3331 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
3334 EndDocPrinter(hPrinter
);
3336 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3338 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3340 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3341 ScheduleJob(hPrinter
, job
->job_id
);
3343 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3346 if (printer
->backend_printer
) {
3347 backend
->fpClosePrinter(printer
->backend_printer
);
3350 free_printer_entry( printer
);
3351 printer_handles
[i
- 1] = NULL
;
3352 LeaveCriticalSection(&printer_handles_cs
);
3356 LeaveCriticalSection(&printer_handles_cs
);
3357 SetLastError(ERROR_INVALID_HANDLE
);
3361 /*****************************************************************************
3362 * DeleteFormA [WINSPOOL.@]
3364 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3366 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3370 /*****************************************************************************
3371 * DeleteFormW [WINSPOOL.@]
3373 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3375 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3379 /*****************************************************************************
3380 * DeletePrinter [WINSPOOL.@]
3382 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3384 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3385 HKEY hkeyPrinters
, hkey
;
3386 WCHAR def
[MAX_PATH
];
3387 DWORD size
= sizeof( def
) / sizeof( def
[0] );
3390 SetLastError(ERROR_INVALID_HANDLE
);
3393 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3394 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3395 RegCloseKey(hkeyPrinters
);
3397 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3398 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
3400 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3401 RegDeleteValueW(hkey
, lpNameW
);
3405 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3406 RegDeleteValueW(hkey
, lpNameW
);
3410 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
3412 WriteProfileStringW( windowsW
, deviceW
, NULL
);
3413 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
3415 RegDeleteValueW( hkey
, deviceW
);
3416 RegCloseKey( hkey
);
3418 SetDefaultPrinterW( NULL
);
3424 /*****************************************************************************
3425 * SetPrinterA [WINSPOOL.@]
3427 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3434 dataW
= printer_info_AtoW( data
, level
);
3435 if (!dataW
) return FALSE
;
3438 ret
= SetPrinterW( printer
, level
, dataW
, command
);
3440 if (dataW
!= data
) free_printer_info( dataW
, level
);
3445 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
3447 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
3448 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
3449 set_reg_szW( key
, PortW
, pi
->pPortName
);
3450 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
3451 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
3452 set_reg_szW( key
, LocationW
, pi
->pLocation
);
3455 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3457 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
3458 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
3459 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
3460 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
3462 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
3463 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
3464 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
3465 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
3466 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
3469 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
3471 if (!pi
->pDevMode
) return FALSE
;
3473 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3477 /******************************************************************************
3478 * SetPrinterW [WINSPOOL.@]
3480 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3485 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
3487 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
3489 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
3496 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
3497 set_printer_2( key
, pi2
);
3503 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3504 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3508 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
3509 ret
= set_printer_9( key
, pi
);
3514 FIXME( "Unimplemented level %d\n", level
);
3515 SetLastError( ERROR_INVALID_LEVEL
);
3522 /*****************************************************************************
3523 * SetJobA [WINSPOOL.@]
3525 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3526 LPBYTE pJob
, DWORD Command
)
3530 UNICODE_STRING usBuffer
;
3532 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3534 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3535 are all ignored by SetJob, so we don't bother copying them */
3543 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3544 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3546 JobW
= (LPBYTE
)info1W
;
3547 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3548 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3549 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3550 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3551 info1W
->Status
= info1A
->Status
;
3552 info1W
->Priority
= info1A
->Priority
;
3553 info1W
->Position
= info1A
->Position
;
3554 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3559 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3560 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3562 JobW
= (LPBYTE
)info2W
;
3563 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3564 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3565 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3566 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3567 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3568 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3569 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3570 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3571 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3572 info2W
->Status
= info2A
->Status
;
3573 info2W
->Priority
= info2A
->Priority
;
3574 info2W
->Position
= info2A
->Position
;
3575 info2W
->StartTime
= info2A
->StartTime
;
3576 info2W
->UntilTime
= info2A
->UntilTime
;
3577 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3581 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3582 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3585 SetLastError(ERROR_INVALID_LEVEL
);
3589 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3595 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3596 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3597 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3598 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3599 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3604 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3605 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3606 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3607 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3608 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3609 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3610 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3611 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3612 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3616 HeapFree(GetProcessHeap(), 0, JobW
);
3621 /*****************************************************************************
3622 * SetJobW [WINSPOOL.@]
3624 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3625 LPBYTE pJob
, DWORD Command
)
3630 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3631 FIXME("Ignoring everything other than document title\n");
3633 EnterCriticalSection(&printer_handles_cs
);
3634 job
= get_job(hPrinter
, JobId
);
3644 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3645 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3646 job
->document_title
= strdupW(info1
->pDocument
);
3651 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3652 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3653 job
->document_title
= strdupW(info2
->pDocument
);
3654 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3655 job
->devmode
= dup_devmode( info2
->pDevMode
);
3661 SetLastError(ERROR_INVALID_LEVEL
);
3666 LeaveCriticalSection(&printer_handles_cs
);
3670 /*****************************************************************************
3671 * EndDocPrinter [WINSPOOL.@]
3673 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3675 opened_printer_t
*printer
;
3677 TRACE("(%p)\n", hPrinter
);
3679 EnterCriticalSection(&printer_handles_cs
);
3681 printer
= get_opened_printer(hPrinter
);
3684 SetLastError(ERROR_INVALID_HANDLE
);
3690 SetLastError(ERROR_SPL_NO_STARTDOC
);
3694 CloseHandle(printer
->doc
->hf
);
3695 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3696 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3697 printer
->doc
= NULL
;
3700 LeaveCriticalSection(&printer_handles_cs
);
3704 /*****************************************************************************
3705 * EndPagePrinter [WINSPOOL.@]
3707 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3709 FIXME("(%p): stub\n", hPrinter
);
3713 /*****************************************************************************
3714 * StartDocPrinterA [WINSPOOL.@]
3716 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3718 UNICODE_STRING usBuffer
;
3720 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3723 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3724 or one (DOC_INFO_3) extra DWORDs */
3728 doc2W
.JobId
= doc2
->JobId
;
3731 doc2W
.dwMode
= doc2
->dwMode
;
3734 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3735 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3736 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3740 SetLastError(ERROR_INVALID_LEVEL
);
3744 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3746 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3747 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3748 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3753 /*****************************************************************************
3754 * StartDocPrinterW [WINSPOOL.@]
3756 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3758 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3759 opened_printer_t
*printer
;
3760 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3761 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3762 JOB_INFO_1W job_info
;
3763 DWORD needed
, ret
= 0;
3768 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3769 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3770 debugstr_w(doc
->pDatatype
));
3772 if(Level
< 1 || Level
> 3)
3774 SetLastError(ERROR_INVALID_LEVEL
);
3778 EnterCriticalSection(&printer_handles_cs
);
3779 printer
= get_opened_printer(hPrinter
);
3782 SetLastError(ERROR_INVALID_HANDLE
);
3788 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3792 /* Even if we're printing to a file we still add a print job, we'll
3793 just ignore the spool file name */
3795 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3797 ERR("AddJob failed gle %u\n", GetLastError());
3801 /* use pOutputFile only, when it is a real filename */
3802 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3803 filename
= doc
->pOutputFile
;
3805 filename
= addjob
->Path
;
3807 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3808 if(hf
== INVALID_HANDLE_VALUE
)
3811 memset(&job_info
, 0, sizeof(job_info
));
3812 job_info
.pDocument
= doc
->pDocName
;
3813 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3815 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3816 printer
->doc
->hf
= hf
;
3817 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3818 job
= get_job(hPrinter
, ret
);
3819 job
->portname
= strdupW(doc
->pOutputFile
);
3822 LeaveCriticalSection(&printer_handles_cs
);
3827 /*****************************************************************************
3828 * StartPagePrinter [WINSPOOL.@]
3830 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3832 FIXME("(%p): stub\n", hPrinter
);
3836 /*****************************************************************************
3837 * GetFormA [WINSPOOL.@]
3839 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3840 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3842 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3843 Level
,pForm
,cbBuf
,pcbNeeded
);
3847 /*****************************************************************************
3848 * GetFormW [WINSPOOL.@]
3850 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3851 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3853 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3854 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3858 /*****************************************************************************
3859 * SetFormA [WINSPOOL.@]
3861 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3864 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3868 /*****************************************************************************
3869 * SetFormW [WINSPOOL.@]
3871 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3874 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3878 /*****************************************************************************
3879 * ReadPrinter [WINSPOOL.@]
3881 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3882 LPDWORD pNoBytesRead
)
3884 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3888 /*****************************************************************************
3889 * ResetPrinterA [WINSPOOL.@]
3891 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3893 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3897 /*****************************************************************************
3898 * ResetPrinterW [WINSPOOL.@]
3900 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3902 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3906 /*****************************************************************************
3907 * get_filename_from_reg [internal]
3909 * Get ValueName from hkey storing result in out
3910 * when the Value in the registry has only a filename, use driverdir as prefix
3911 * outlen is space left in out
3912 * String is stored either as unicode or ascii
3916 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3917 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3919 WCHAR filename
[MAX_PATH
];
3923 LPWSTR buffer
= filename
;
3927 size
= sizeof(filename
);
3929 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3930 if (ret
== ERROR_MORE_DATA
) {
3931 TRACE("need dynamic buffer: %u\n", size
);
3932 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3934 /* No Memory is bad */
3938 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3941 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3942 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3948 /* do we have a full path ? */
3949 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3950 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3953 /* we must build the full Path */
3955 if ((out
) && (outlen
> dirlen
)) {
3956 lstrcpyW((LPWSTR
)out
, driverdir
);
3964 /* write the filename */
3965 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3966 if ((out
) && (outlen
>= size
)) {
3967 lstrcpyW((LPWSTR
)out
, ptr
);
3974 ptr
+= lstrlenW(ptr
)+1;
3975 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3978 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3980 /* write the multisz-termination */
3981 if (type
== REG_MULTI_SZ
) {
3982 size
= sizeof(WCHAR
);
3985 if (out
&& (outlen
>= size
)) {
3986 memset (out
, 0, size
);
3992 /*****************************************************************************
3993 * WINSPOOL_GetStringFromReg
3995 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3996 * String is stored as unicode.
3998 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3999 DWORD buflen
, DWORD
*needed
)
4001 DWORD sz
= buflen
, type
;
4004 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4005 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
4006 WARN("Got ret = %d\n", ret
);
4010 /* add space for terminating '\0' */
4011 sz
+= sizeof(WCHAR
);
4015 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
4020 /*****************************************************************************
4021 * WINSPOOL_GetDefaultDevMode
4023 * Get a default DevMode values for wineps.
4025 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr
, DWORD buflen
, DWORD
*needed
)
4027 static const WCHAR winepsW
[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4029 if (buflen
>= sizeof(DEVMODEW
))
4031 DEVMODEW
*dm
= (DEVMODEW
*)ptr
;
4033 /* the driver will update registry with real values */
4034 memset(dm
, 0, sizeof(*dm
));
4035 dm
->dmSize
= sizeof(*dm
);
4036 lstrcpyW(dm
->dmDeviceName
, winepsW
);
4038 *needed
= sizeof(DEVMODEW
);
4041 /*****************************************************************************
4042 * WINSPOOL_GetDevModeFromReg
4044 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4045 * DevMode is stored either as unicode or ascii.
4047 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
4049 DWORD buflen
, DWORD
*needed
)
4051 DWORD sz
= buflen
, type
;
4054 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
4055 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4056 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
4057 if (sz
< sizeof(DEVMODEA
))
4059 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
4062 /* ensures that dmSize is not erratically bogus if registry is invalid */
4063 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
4064 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
4065 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
4066 if (ptr
&& (buflen
>= sz
)) {
4067 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
4068 memcpy(ptr
, dmW
, sz
);
4069 HeapFree(GetProcessHeap(),0,dmW
);
4075 /*********************************************************************
4076 * WINSPOOL_GetPrinter_1
4078 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4080 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
4081 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4083 DWORD size
, left
= cbBuf
;
4084 BOOL space
= (cbBuf
> 0);
4089 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4090 if(space
&& size
<= left
) {
4091 pi1
->pName
= (LPWSTR
)ptr
;
4099 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4100 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4101 if(space
&& size
<= left
) {
4102 pi1
->pDescription
= (LPWSTR
)ptr
;
4110 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4111 if(space
&& size
<= left
) {
4112 pi1
->pComment
= (LPWSTR
)ptr
;
4120 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
4122 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
4123 memset(pi1
, 0, sizeof(*pi1
));
4127 /*********************************************************************
4128 * WINSPOOL_GetPrinter_2
4130 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4132 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
4133 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4135 DWORD size
, left
= cbBuf
;
4136 BOOL space
= (cbBuf
> 0);
4141 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4142 if(space
&& size
<= left
) {
4143 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4150 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
4151 if(space
&& size
<= left
) {
4152 pi2
->pShareName
= (LPWSTR
)ptr
;
4159 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4160 if(space
&& size
<= left
) {
4161 pi2
->pPortName
= (LPWSTR
)ptr
;
4168 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
4169 if(space
&& size
<= left
) {
4170 pi2
->pDriverName
= (LPWSTR
)ptr
;
4177 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4178 if(space
&& size
<= left
) {
4179 pi2
->pComment
= (LPWSTR
)ptr
;
4186 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
4187 if(space
&& size
<= left
) {
4188 pi2
->pLocation
= (LPWSTR
)ptr
;
4195 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
4196 if(space
&& size
<= left
) {
4197 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4206 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
4207 if(space
&& size
<= left
) {
4208 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4215 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
4216 if(space
&& size
<= left
) {
4217 pi2
->pSepFile
= (LPWSTR
)ptr
;
4224 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
4225 if(space
&& size
<= left
) {
4226 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4233 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
4234 if(space
&& size
<= left
) {
4235 pi2
->pDatatype
= (LPWSTR
)ptr
;
4242 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
4243 if(space
&& size
<= left
) {
4244 pi2
->pParameters
= (LPWSTR
)ptr
;
4252 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4253 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
4254 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
4255 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
4256 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
4259 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4260 memset(pi2
, 0, sizeof(*pi2
));
4265 /*********************************************************************
4266 * WINSPOOL_GetPrinter_4
4268 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4270 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4271 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4273 DWORD size
, left
= cbBuf
;
4274 BOOL space
= (cbBuf
> 0);
4279 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4280 if(space
&& size
<= left
) {
4281 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4289 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4292 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4293 memset(pi4
, 0, sizeof(*pi4
));
4298 /*********************************************************************
4299 * WINSPOOL_GetPrinter_5
4301 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4303 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
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 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4321 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4322 if(space
&& size
<= left
) {
4323 pi5
->pPortName
= (LPWSTR
)ptr
;
4331 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4332 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
4333 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
4336 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4337 memset(pi5
, 0, sizeof(*pi5
));
4342 /*********************************************************************
4343 * WINSPOOL_GetPrinter_7
4345 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4347 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4348 DWORD cbBuf
, LPDWORD pcbNeeded
)
4350 DWORD size
, left
= cbBuf
;
4351 BOOL space
= (cbBuf
> 0);
4356 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
4359 size
= sizeof(pi7
->pszObjectGUID
);
4361 if (space
&& size
<= left
) {
4362 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4369 /* We do not have a Directory Service */
4370 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4373 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4374 memset(pi7
, 0, sizeof(*pi7
));
4379 /*********************************************************************
4380 * WINSPOOL_GetPrinter_9
4382 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4384 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4385 DWORD cbBuf
, LPDWORD pcbNeeded
)
4388 BOOL space
= (cbBuf
> 0);
4392 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
4393 if(space
&& size
<= cbBuf
) {
4394 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4401 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
4402 if(space
&& size
<= cbBuf
) {
4403 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4409 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4410 memset(pi9
, 0, sizeof(*pi9
));
4415 /*****************************************************************************
4416 * GetPrinterW [WINSPOOL.@]
4418 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4419 DWORD cbBuf
, LPDWORD pcbNeeded
)
4421 DWORD size
, needed
= 0, err
;
4426 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4428 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
4431 SetLastError( err
);
4438 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4440 size
= sizeof(PRINTER_INFO_2W
);
4442 ptr
= pPrinter
+ size
;
4444 memset(pPrinter
, 0, size
);
4449 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
4456 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4458 size
= sizeof(PRINTER_INFO_4W
);
4460 ptr
= pPrinter
+ size
;
4462 memset(pPrinter
, 0, size
);
4467 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
4475 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4477 size
= sizeof(PRINTER_INFO_5W
);
4479 ptr
= pPrinter
+ size
;
4481 memset(pPrinter
, 0, size
);
4487 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4495 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4497 size
= sizeof(PRINTER_INFO_6
);
4498 if (size
<= cbBuf
) {
4499 /* FIXME: We do not update the status yet */
4500 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4512 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4514 size
= sizeof(PRINTER_INFO_7W
);
4515 if (size
<= cbBuf
) {
4516 ptr
= pPrinter
+ size
;
4518 memset(pPrinter
, 0, size
);
4524 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4531 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4532 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4536 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4538 size
= sizeof(PRINTER_INFO_9W
);
4540 ptr
= pPrinter
+ size
;
4542 memset(pPrinter
, 0, size
);
4548 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4555 FIXME("Unimplemented level %d\n", Level
);
4556 SetLastError(ERROR_INVALID_LEVEL
);
4557 RegCloseKey(hkeyPrinter
);
4561 RegCloseKey(hkeyPrinter
);
4563 TRACE("returning %d needed = %d\n", ret
, needed
);
4564 if(pcbNeeded
) *pcbNeeded
= needed
;
4566 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4570 /*****************************************************************************
4571 * GetPrinterA [WINSPOOL.@]
4573 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4574 DWORD cbBuf
, LPDWORD pcbNeeded
)
4580 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4582 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4584 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4585 HeapFree(GetProcessHeap(), 0, buf
);
4590 /*****************************************************************************
4591 * WINSPOOL_EnumPrintersW
4593 * Implementation of EnumPrintersW
4595 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4596 DWORD dwLevel
, LPBYTE lpbPrinters
,
4597 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4598 LPDWORD lpdwReturned
)
4601 HKEY hkeyPrinters
, hkeyPrinter
;
4602 WCHAR PrinterName
[255];
4603 DWORD needed
= 0, number
= 0;
4604 DWORD used
, i
, left
;
4608 memset(lpbPrinters
, 0, cbBuf
);
4614 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4615 if(dwType
== PRINTER_ENUM_DEFAULT
)
4618 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4619 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4620 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4622 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4628 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4629 FIXME("dwType = %08x\n", dwType
);
4630 SetLastError(ERROR_INVALID_FLAGS
);
4634 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4636 ERR("Can't create Printers key\n");
4640 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4641 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4642 RegCloseKey(hkeyPrinters
);
4643 ERR("Can't query Printers key\n");
4646 TRACE("Found %d printers\n", number
);
4650 used
= number
* sizeof(PRINTER_INFO_1W
);
4653 used
= number
* sizeof(PRINTER_INFO_2W
);
4656 used
= number
* sizeof(PRINTER_INFO_4W
);
4659 used
= number
* sizeof(PRINTER_INFO_5W
);
4663 SetLastError(ERROR_INVALID_LEVEL
);
4664 RegCloseKey(hkeyPrinters
);
4667 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4669 for(i
= 0; i
< number
; i
++) {
4670 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4672 ERR("Can't enum key number %d\n", i
);
4673 RegCloseKey(hkeyPrinters
);
4676 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4677 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4679 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4680 RegCloseKey(hkeyPrinters
);
4685 buf
= lpbPrinters
+ used
;
4686 left
= cbBuf
- used
;
4694 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4697 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4700 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4703 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4706 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4709 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4712 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4715 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4718 ERR("Shouldn't be here!\n");
4719 RegCloseKey(hkeyPrinter
);
4720 RegCloseKey(hkeyPrinters
);
4723 RegCloseKey(hkeyPrinter
);
4725 RegCloseKey(hkeyPrinters
);
4732 memset(lpbPrinters
, 0, cbBuf
);
4733 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4737 *lpdwReturned
= number
;
4738 SetLastError(ERROR_SUCCESS
);
4743 /******************************************************************
4744 * EnumPrintersW [WINSPOOL.@]
4746 * Enumerates the available printers, print servers and print
4747 * providers, depending on the specified flags, name and level.
4751 * If level is set to 1:
4752 * Returns an array of PRINTER_INFO_1 data structures in the
4753 * lpbPrinters buffer.
4755 * If level is set to 2:
4756 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4757 * Returns an array of PRINTER_INFO_2 data structures in the
4758 * lpbPrinters buffer. Note that according to MSDN also an
4759 * OpenPrinter should be performed on every remote printer.
4761 * If level is set to 4 (officially WinNT only):
4762 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4763 * Fast: Only the registry is queried to retrieve printer names,
4764 * no connection to the driver is made.
4765 * Returns an array of PRINTER_INFO_4 data structures in the
4766 * lpbPrinters buffer.
4768 * If level is set to 5 (officially WinNT4/Win9x only):
4769 * Fast: Only the registry is queried to retrieve printer names,
4770 * no connection to the driver is made.
4771 * Returns an array of PRINTER_INFO_5 data structures in the
4772 * lpbPrinters buffer.
4774 * If level set to 3 or 6+:
4775 * returns zero (failure!)
4777 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4781 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4782 * - Only levels 2, 4 and 5 are implemented at the moment.
4783 * - 16-bit printer drivers are not enumerated.
4784 * - Returned amount of bytes used/needed does not match the real Windoze
4785 * implementation (as in this implementation, all strings are part
4786 * of the buffer, whereas Win32 keeps them somewhere else)
4787 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4790 * - In a regular Wine installation, no registry settings for printers
4791 * exist, which makes this function return an empty list.
4793 BOOL WINAPI
EnumPrintersW(
4794 DWORD dwType
, /* [in] Types of print objects to enumerate */
4795 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4796 DWORD dwLevel
, /* [in] type of printer info structure */
4797 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4798 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4799 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4800 LPDWORD lpdwReturned
/* [out] number of entries returned */
4803 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4804 lpdwNeeded
, lpdwReturned
);
4807 /******************************************************************
4808 * EnumPrintersA [WINSPOOL.@]
4813 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4814 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4817 UNICODE_STRING pNameU
;
4821 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4822 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4824 pNameW
= asciitounicode(&pNameU
, pName
);
4826 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4827 MS Office need this */
4828 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4830 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4832 RtlFreeUnicodeString(&pNameU
);
4834 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4836 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4840 /*****************************************************************************
4841 * WINSPOOL_GetDriverInfoFromReg [internal]
4843 * Enters the information from the registry into the DRIVER_INFO struct
4846 * zero if the printer driver does not exist in the registry
4847 * (only if Level > 1) otherwise nonzero
4849 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4852 const printenv_t
* env
,
4854 LPBYTE ptr
, /* DRIVER_INFO */
4855 LPBYTE pDriverStrings
, /* strings buffer */
4856 DWORD cbBuf
, /* size of string buffer */
4857 LPDWORD pcbNeeded
) /* space needed for str. */
4861 WCHAR driverdir
[MAX_PATH
];
4863 LPBYTE strPtr
= pDriverStrings
;
4864 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4866 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4867 debugstr_w(DriverName
), env
,
4868 Level
, di
, pDriverStrings
, cbBuf
);
4870 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4872 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4873 if (*pcbNeeded
<= cbBuf
)
4874 strcpyW((LPWSTR
)strPtr
, DriverName
);
4876 /* pName for level 1 has a different offset! */
4878 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4882 /* .cVersion and .pName for level > 1 */
4884 di
->cVersion
= env
->driverversion
;
4885 di
->pName
= (LPWSTR
) strPtr
;
4886 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4889 /* Reserve Space for the largest subdir and a Backslash*/
4890 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4891 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4892 /* Should never Fail */
4895 lstrcatW(driverdir
, env
->versionsubdir
);
4896 lstrcatW(driverdir
, backslashW
);
4898 /* dirlen must not include the terminating zero */
4899 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4901 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4902 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4903 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4908 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4911 if (*pcbNeeded
<= cbBuf
) {
4912 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4913 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4914 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4917 /* .pDriverPath is the Graphics rendering engine.
4918 The full Path is required to avoid a crash in some apps */
4919 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4921 if (*pcbNeeded
<= cbBuf
)
4922 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4924 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4925 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4928 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4929 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4931 if (*pcbNeeded
<= cbBuf
)
4932 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4934 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4935 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4938 /* .pConfigFile is the Driver user Interface */
4939 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4941 if (*pcbNeeded
<= cbBuf
)
4942 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4944 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4945 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4949 RegCloseKey(hkeyDriver
);
4950 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4955 RegCloseKey(hkeyDriver
);
4956 FIXME("level 5: incomplete\n");
4961 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4963 if (*pcbNeeded
<= cbBuf
)
4964 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4966 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4967 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4970 /* .pDependentFiles */
4971 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4973 if (*pcbNeeded
<= cbBuf
)
4974 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4976 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4977 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4979 else if (GetVersion() & 0x80000000) {
4980 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4981 size
= 2 * sizeof(WCHAR
);
4983 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4985 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4986 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4989 /* .pMonitorName is the optional Language Monitor */
4990 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4992 if (*pcbNeeded
<= cbBuf
)
4993 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4995 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4996 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4999 /* .pDefaultDataType */
5000 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
5002 if(*pcbNeeded
<= cbBuf
)
5003 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
5005 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
5006 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5010 RegCloseKey(hkeyDriver
);
5011 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5015 /* .pszzPreviousNames */
5016 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
5018 if(*pcbNeeded
<= cbBuf
)
5019 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
5021 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
5022 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5026 RegCloseKey(hkeyDriver
);
5027 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5031 /* support is missing, but not important enough for a FIXME */
5032 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
5035 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
5037 if(*pcbNeeded
<= cbBuf
)
5038 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
5040 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
5041 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5045 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
5047 if(*pcbNeeded
<= cbBuf
)
5048 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
5050 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
5051 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5054 /* .pszHardwareID */
5055 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
5057 if(*pcbNeeded
<= cbBuf
)
5058 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
5060 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
5061 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5065 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
5067 if(*pcbNeeded
<= cbBuf
)
5068 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
5070 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
5071 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5075 RegCloseKey(hkeyDriver
);
5079 /* support is missing, but not important enough for a FIXME */
5080 TRACE("level 8: incomplete\n");
5082 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5083 RegCloseKey(hkeyDriver
);
5087 /*****************************************************************************
5088 * GetPrinterDriverW [WINSPOOL.@]
5090 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5091 DWORD Level
, LPBYTE pDriverInfo
,
5092 DWORD cbBuf
, LPDWORD pcbNeeded
)
5095 WCHAR DriverName
[100];
5096 DWORD ret
, type
, size
, needed
= 0;
5098 HKEY hkeyPrinter
, hkeyDrivers
;
5099 const printenv_t
* env
;
5101 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
5102 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
5105 ZeroMemory(pDriverInfo
, cbBuf
);
5107 if (!(name
= get_opened_printer_name(hPrinter
))) {
5108 SetLastError(ERROR_INVALID_HANDLE
);
5112 if (Level
< 1 || Level
== 7 || Level
> 8) {
5113 SetLastError(ERROR_INVALID_LEVEL
);
5117 env
= validate_envW(pEnvironment
);
5118 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5120 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
5123 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
5124 SetLastError( ret
);
5128 size
= sizeof(DriverName
);
5130 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5131 (LPBYTE
)DriverName
, &size
);
5132 RegCloseKey(hkeyPrinter
);
5133 if(ret
!= ERROR_SUCCESS
) {
5134 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5138 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5140 ERR("Can't create Drivers key\n");
5144 size
= di_sizeof
[Level
];
5145 if ((size
<= cbBuf
) && pDriverInfo
)
5146 ptr
= pDriverInfo
+ size
;
5148 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5149 env
, Level
, pDriverInfo
, ptr
,
5150 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5152 RegCloseKey(hkeyDrivers
);
5156 RegCloseKey(hkeyDrivers
);
5158 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5159 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5160 if(cbBuf
>= size
+ needed
) return TRUE
;
5161 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5165 /*****************************************************************************
5166 * GetPrinterDriverA [WINSPOOL.@]
5168 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5169 DWORD Level
, LPBYTE pDriverInfo
,
5170 DWORD cbBuf
, LPDWORD pcbNeeded
)
5173 UNICODE_STRING pEnvW
;
5179 ZeroMemory(pDriverInfo
, cbBuf
);
5180 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5183 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5184 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5187 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5189 HeapFree(GetProcessHeap(), 0, buf
);
5191 RtlFreeUnicodeString(&pEnvW
);
5195 /*****************************************************************************
5196 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5198 * Return the PATH for the Printer-Drivers (UNICODE)
5201 * pName [I] Servername (NT only) or NULL (local Computer)
5202 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5203 * Level [I] Structure-Level (must be 1)
5204 * pDriverDirectory [O] PTR to Buffer that receives the Result
5205 * cbBuf [I] Size of Buffer at pDriverDirectory
5206 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5207 * required for pDriverDirectory
5210 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5211 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5212 * if cbBuf is too small
5214 * Native Values returned in pDriverDirectory on Success:
5215 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5216 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5217 *| win9x(Windows 4.0): "%winsysdir%"
5219 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5222 *- Only NULL or "" is supported for pName
5225 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5226 DWORD Level
, LPBYTE pDriverDirectory
,
5227 DWORD cbBuf
, LPDWORD pcbNeeded
)
5229 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5230 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5232 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5235 /* (Level != 1) is ignored in win9x */
5236 SetLastError(ERROR_INVALID_LEVEL
);
5239 if (pcbNeeded
== NULL
) {
5240 /* (pcbNeeded == NULL) is ignored in win9x */
5241 SetLastError(RPC_X_NULL_REF_POINTER
);
5245 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5246 pDriverDirectory
, cbBuf
, pcbNeeded
);
5251 /*****************************************************************************
5252 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5254 * Return the PATH for the Printer-Drivers (ANSI)
5256 * See GetPrinterDriverDirectoryW.
5259 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5262 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5263 DWORD Level
, LPBYTE pDriverDirectory
,
5264 DWORD cbBuf
, LPDWORD pcbNeeded
)
5266 UNICODE_STRING nameW
, environmentW
;
5269 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5270 WCHAR
*driverDirectoryW
= NULL
;
5272 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5273 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5275 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5277 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5278 else nameW
.Buffer
= NULL
;
5279 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5280 else environmentW
.Buffer
= NULL
;
5282 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5283 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5286 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5287 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5289 *pcbNeeded
= needed
;
5290 ret
= needed
<= cbBuf
;
5292 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5294 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5296 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5297 RtlFreeUnicodeString(&environmentW
);
5298 RtlFreeUnicodeString(&nameW
);
5303 /*****************************************************************************
5304 * AddPrinterDriverA [WINSPOOL.@]
5306 * See AddPrinterDriverW.
5309 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5311 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5312 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5315 /******************************************************************************
5316 * AddPrinterDriverW (WINSPOOL.@)
5318 * Install a Printer Driver
5321 * pName [I] Servername or NULL (local Computer)
5322 * level [I] Level for the supplied DRIVER_INFO_*W struct
5323 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5330 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5332 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5333 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5336 /*****************************************************************************
5337 * AddPrintProcessorA [WINSPOOL.@]
5339 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5340 LPSTR pPrintProcessorName
)
5342 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5343 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5347 /*****************************************************************************
5348 * AddPrintProcessorW [WINSPOOL.@]
5350 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5351 LPWSTR pPrintProcessorName
)
5353 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5354 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5358 /*****************************************************************************
5359 * AddPrintProvidorA [WINSPOOL.@]
5361 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5363 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5367 /*****************************************************************************
5368 * AddPrintProvidorW [WINSPOOL.@]
5370 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5372 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5376 /*****************************************************************************
5377 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5379 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5380 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5382 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5383 pDevModeOutput
, pDevModeInput
);
5387 /*****************************************************************************
5388 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5390 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5391 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5393 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5394 pDevModeOutput
, pDevModeInput
);
5398 /*****************************************************************************
5399 * PrinterProperties [WINSPOOL.@]
5401 * Displays a dialog to set the properties of the printer.
5404 * nonzero on success or zero on failure
5407 * implemented as stub only
5409 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5410 HANDLE hPrinter
/* [in] handle to printer object */
5412 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5413 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5417 /*****************************************************************************
5418 * EnumJobsA [WINSPOOL.@]
5421 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5422 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5425 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5426 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5428 if(pcbNeeded
) *pcbNeeded
= 0;
5429 if(pcReturned
) *pcReturned
= 0;
5434 /*****************************************************************************
5435 * EnumJobsW [WINSPOOL.@]
5438 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5439 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5442 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5443 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5445 if(pcbNeeded
) *pcbNeeded
= 0;
5446 if(pcReturned
) *pcReturned
= 0;
5450 /*****************************************************************************
5451 * WINSPOOL_EnumPrinterDrivers [internal]
5453 * Delivers information about all printer drivers installed on the
5454 * localhost or a given server
5457 * nonzero on success or zero on failure. If the buffer for the returned
5458 * information is too small the function will return an error
5461 * - only implemented for localhost, foreign hosts will return an error
5463 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5464 DWORD Level
, LPBYTE pDriverInfo
,
5466 DWORD cbBuf
, LPDWORD pcbNeeded
,
5467 LPDWORD pcFound
, DWORD data_offset
)
5471 const printenv_t
* env
;
5473 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5474 debugstr_w(pName
), debugstr_w(pEnvironment
),
5475 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5477 env
= validate_envW(pEnvironment
);
5478 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5482 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5484 ERR("Can't open Drivers key\n");
5488 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5489 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5490 RegCloseKey(hkeyDrivers
);
5491 ERR("Can't query Drivers key\n");
5494 TRACE("Found %d Drivers\n", *pcFound
);
5496 /* get size of single struct
5497 * unicode and ascii structure have the same size
5499 size
= di_sizeof
[Level
];
5501 if (data_offset
== 0)
5502 data_offset
= size
* (*pcFound
);
5503 *pcbNeeded
= data_offset
;
5505 for( i
= 0; i
< *pcFound
; i
++) {
5506 WCHAR DriverNameW
[255];
5507 PBYTE table_ptr
= NULL
;
5508 PBYTE data_ptr
= NULL
;
5511 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5513 ERR("Can't enum key number %d\n", i
);
5514 RegCloseKey(hkeyDrivers
);
5518 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5519 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5520 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5521 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5523 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5524 env
, Level
, table_ptr
, data_ptr
,
5525 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5527 RegCloseKey(hkeyDrivers
);
5531 *pcbNeeded
+= needed
;
5534 RegCloseKey(hkeyDrivers
);
5536 if(cbBuf
< *pcbNeeded
){
5537 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5544 /*****************************************************************************
5545 * EnumPrinterDriversW [WINSPOOL.@]
5547 * see function EnumPrinterDrivers for RETURNS, BUGS
5549 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5550 LPBYTE pDriverInfo
, DWORD cbBuf
,
5551 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5553 static const WCHAR allW
[] = {'a','l','l',0};
5557 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5559 SetLastError(RPC_X_NULL_REF_POINTER
);
5563 /* check for local drivers */
5564 if((pName
) && (pName
[0])) {
5565 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5566 SetLastError(ERROR_ACCESS_DENIED
);
5570 /* check input parameter */
5571 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5572 SetLastError(ERROR_INVALID_LEVEL
);
5576 if(pDriverInfo
&& cbBuf
> 0)
5577 memset( pDriverInfo
, 0, cbBuf
);
5579 /* Exception: pull all printers */
5580 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5582 DWORD i
, needed
, bufsize
= cbBuf
;
5583 DWORD total_found
= 0;
5586 /* Precompute the overall total; we need this to know
5587 where pointers end and data begins (i.e. data_offset) */
5588 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5591 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5592 NULL
, 0, 0, &needed
, &found
, 0);
5593 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5594 total_found
+= found
;
5597 data_offset
= di_sizeof
[Level
] * total_found
;
5602 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5605 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5606 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5607 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5609 *pcReturned
+= found
;
5610 *pcbNeeded
= needed
;
5611 data_offset
= needed
;
5612 total_found
+= found
;
5617 /* Normal behavior */
5618 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5619 0, cbBuf
, pcbNeeded
, &found
, 0);
5621 *pcReturned
= found
;
5626 /*****************************************************************************
5627 * EnumPrinterDriversA [WINSPOOL.@]
5629 * see function EnumPrinterDrivers for RETURNS, BUGS
5631 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5632 LPBYTE pDriverInfo
, DWORD cbBuf
,
5633 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5636 UNICODE_STRING pNameW
, pEnvironmentW
;
5637 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5641 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5643 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5644 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5646 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5647 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5649 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5651 HeapFree(GetProcessHeap(), 0, buf
);
5653 RtlFreeUnicodeString(&pNameW
);
5654 RtlFreeUnicodeString(&pEnvironmentW
);
5659 /******************************************************************************
5660 * EnumPortsA (WINSPOOL.@)
5665 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5666 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5669 LPBYTE bufferW
= NULL
;
5670 LPWSTR nameW
= NULL
;
5672 DWORD numentries
= 0;
5675 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5676 cbBuf
, pcbNeeded
, pcReturned
);
5678 /* convert servername to unicode */
5680 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5681 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5682 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5684 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5685 needed
= cbBuf
* sizeof(WCHAR
);
5686 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5687 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5689 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5690 if (pcbNeeded
) needed
= *pcbNeeded
;
5691 /* HeapReAlloc return NULL, when bufferW was NULL */
5692 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5693 HeapAlloc(GetProcessHeap(), 0, needed
);
5695 /* Try again with the large Buffer */
5696 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5698 needed
= pcbNeeded
? *pcbNeeded
: 0;
5699 numentries
= pcReturned
? *pcReturned
: 0;
5702 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5703 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5706 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5707 DWORD entrysize
= 0;
5710 LPPORT_INFO_2W pi2w
;
5711 LPPORT_INFO_2A pi2a
;
5714 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5716 /* First pass: calculate the size for all Entries */
5717 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5718 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5720 while (index
< numentries
) {
5722 needed
+= entrysize
; /* PORT_INFO_?A */
5723 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5725 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5726 NULL
, 0, NULL
, NULL
);
5728 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5729 NULL
, 0, NULL
, NULL
);
5730 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5731 NULL
, 0, NULL
, NULL
);
5733 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5734 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5735 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5738 /* check for errors and quit on failure */
5739 if (cbBuf
< needed
) {
5740 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5744 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5745 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5746 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5747 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5748 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5750 /* Second Pass: Fill the User Buffer (if we have one) */
5751 while ((index
< numentries
) && pPorts
) {
5753 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5754 pi2a
->pPortName
= ptr
;
5755 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5756 ptr
, cbBuf
, NULL
, NULL
);
5760 pi2a
->pMonitorName
= ptr
;
5761 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5762 ptr
, cbBuf
, NULL
, NULL
);
5766 pi2a
->pDescription
= ptr
;
5767 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5768 ptr
, cbBuf
, NULL
, NULL
);
5772 pi2a
->fPortType
= pi2w
->fPortType
;
5773 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5776 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5777 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5778 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5783 if (pcbNeeded
) *pcbNeeded
= needed
;
5784 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5786 HeapFree(GetProcessHeap(), 0, nameW
);
5787 HeapFree(GetProcessHeap(), 0, bufferW
);
5789 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5790 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5796 /******************************************************************************
5797 * EnumPortsW (WINSPOOL.@)
5799 * Enumerate available Ports
5802 * pName [I] Servername or NULL (local Computer)
5803 * Level [I] Structure-Level (1 or 2)
5804 * pPorts [O] PTR to Buffer that receives the Result
5805 * cbBuf [I] Size of Buffer at pPorts
5806 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5807 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5811 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5814 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5817 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5818 cbBuf
, pcbNeeded
, pcReturned
);
5820 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5822 /* Level is not checked in win9x */
5823 if (!Level
|| (Level
> 2)) {
5824 WARN("level (%d) is ignored in win9x\n", Level
);
5825 SetLastError(ERROR_INVALID_LEVEL
);
5828 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5829 SetLastError(RPC_X_NULL_REF_POINTER
);
5833 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5836 /******************************************************************************
5837 * GetDefaultPrinterW (WINSPOOL.@)
5840 * This function must read the value from data 'device' of key
5841 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5843 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5847 WCHAR
*buffer
, *ptr
;
5851 SetLastError(ERROR_INVALID_PARAMETER
);
5855 /* make the buffer big enough for the stuff from the profile/registry,
5856 * the content must fit into the local buffer to compute the correct
5857 * size even if the extern buffer is too small or not given.
5858 * (20 for ,driver,port) */
5860 len
= max(100, (insize
+ 20));
5861 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5863 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5865 SetLastError (ERROR_FILE_NOT_FOUND
);
5869 TRACE("%s\n", debugstr_w(buffer
));
5871 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5873 SetLastError(ERROR_INVALID_NAME
);
5879 *namesize
= strlenW(buffer
) + 1;
5880 if(!name
|| (*namesize
> insize
))
5882 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5886 strcpyW(name
, buffer
);
5889 HeapFree( GetProcessHeap(), 0, buffer
);
5894 /******************************************************************************
5895 * GetDefaultPrinterA (WINSPOOL.@)
5897 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5901 WCHAR
*bufferW
= NULL
;
5905 SetLastError(ERROR_INVALID_PARAMETER
);
5909 if(name
&& *namesize
) {
5911 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5914 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5919 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5923 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5926 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5929 HeapFree( GetProcessHeap(), 0, bufferW
);
5934 /******************************************************************************
5935 * SetDefaultPrinterW (WINSPOOL.204)
5937 * Set the Name of the Default Printer
5940 * pszPrinter [I] Name of the Printer or NULL
5947 * When the Parameter is NULL or points to an Empty String and
5948 * a Default Printer was already present, then this Function changes nothing.
5949 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5950 * the First enumerated local Printer is used.
5953 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5955 WCHAR default_printer
[MAX_PATH
];
5956 LPWSTR buffer
= NULL
;
5962 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5963 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5965 default_printer
[0] = '\0';
5966 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5968 /* if we have a default Printer, do nothing. */
5969 if (GetDefaultPrinterW(default_printer
, &size
))
5973 /* we have no default Printer: search local Printers and use the first */
5974 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5976 default_printer
[0] = '\0';
5977 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5978 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5980 pszPrinter
= default_printer
;
5981 TRACE("using %s\n", debugstr_w(pszPrinter
));
5986 if (pszPrinter
== NULL
) {
5987 TRACE("no local printer found\n");
5988 SetLastError(ERROR_FILE_NOT_FOUND
);
5993 /* "pszPrinter" is never empty or NULL here. */
5994 namelen
= lstrlenW(pszPrinter
);
5995 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5996 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5998 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5999 HeapFree(GetProcessHeap(), 0, buffer
);
6000 SetLastError(ERROR_FILE_NOT_FOUND
);
6004 /* read the devices entry for the printer (driver,port) to build the string for the
6005 default device entry (printer,driver,port) */
6006 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
6007 buffer
[namelen
] = ',';
6008 namelen
++; /* move index to the start of the driver */
6010 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
6011 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
6013 TRACE("set device to %s\n", debugstr_w(buffer
));
6015 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
6016 TRACE("failed to set the device entry: %d\n", GetLastError());
6017 lres
= ERROR_INVALID_PRINTER_NAME
;
6020 /* remove the next section, when INIFileMapping is implemented */
6023 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
6024 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
6031 if (lres
!= ERROR_FILE_NOT_FOUND
)
6032 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
6034 SetLastError(ERROR_INVALID_PRINTER_NAME
);
6038 HeapFree(GetProcessHeap(), 0, buffer
);
6039 return (lres
== ERROR_SUCCESS
);
6042 /******************************************************************************
6043 * SetDefaultPrinterA (WINSPOOL.202)
6045 * See SetDefaultPrinterW.
6048 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
6050 LPWSTR bufferW
= NULL
;
6053 TRACE("(%s)\n", debugstr_a(pszPrinter
));
6055 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
6056 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6057 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
6059 res
= SetDefaultPrinterW(bufferW
);
6060 HeapFree(GetProcessHeap(), 0, bufferW
);
6064 /******************************************************************************
6065 * SetPrinterDataExA (WINSPOOL.@)
6067 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6068 LPCSTR pValueName
, DWORD Type
,
6069 LPBYTE pData
, DWORD cbData
)
6071 HKEY hkeyPrinter
, hkeySubkey
;
6074 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
6075 debugstr_a(pValueName
), Type
, pData
, cbData
);
6077 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6081 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6083 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
6084 RegCloseKey(hkeyPrinter
);
6087 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6088 RegCloseKey(hkeySubkey
);
6089 RegCloseKey(hkeyPrinter
);
6093 /******************************************************************************
6094 * SetPrinterDataExW (WINSPOOL.@)
6096 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6097 LPCWSTR pValueName
, DWORD Type
,
6098 LPBYTE pData
, DWORD cbData
)
6100 HKEY hkeyPrinter
, hkeySubkey
;
6103 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
6104 debugstr_w(pValueName
), Type
, pData
, cbData
);
6106 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6110 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6112 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
6113 RegCloseKey(hkeyPrinter
);
6116 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6117 RegCloseKey(hkeySubkey
);
6118 RegCloseKey(hkeyPrinter
);
6122 /******************************************************************************
6123 * SetPrinterDataA (WINSPOOL.@)
6125 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
6126 LPBYTE pData
, DWORD cbData
)
6128 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
6132 /******************************************************************************
6133 * SetPrinterDataW (WINSPOOL.@)
6135 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
6136 LPBYTE pData
, DWORD cbData
)
6138 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6142 /******************************************************************************
6143 * GetPrinterDataExA (WINSPOOL.@)
6145 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6146 LPCSTR pValueName
, LPDWORD pType
,
6147 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6149 opened_printer_t
*printer
;
6150 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6153 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6154 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6156 printer
= get_opened_printer(hPrinter
);
6157 if(!printer
) return ERROR_INVALID_HANDLE
;
6159 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6160 if (ret
) return ret
;
6162 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6164 if (printer
->name
) {
6166 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6168 RegCloseKey(hkeyPrinters
);
6171 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6172 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6173 RegCloseKey(hkeyPrinter
);
6174 RegCloseKey(hkeyPrinters
);
6179 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6180 0, pType
, pData
, pcbNeeded
);
6182 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6184 RegCloseKey(hkeySubkey
);
6185 RegCloseKey(hkeyPrinter
);
6186 RegCloseKey(hkeyPrinters
);
6188 TRACE("--> %d\n", ret
);
6192 /******************************************************************************
6193 * GetPrinterDataExW (WINSPOOL.@)
6195 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6196 LPCWSTR pValueName
, LPDWORD pType
,
6197 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6199 opened_printer_t
*printer
;
6200 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6203 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6204 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6206 printer
= get_opened_printer(hPrinter
);
6207 if(!printer
) return ERROR_INVALID_HANDLE
;
6209 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6210 if (ret
) return ret
;
6212 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6214 if (printer
->name
) {
6216 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6218 RegCloseKey(hkeyPrinters
);
6221 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6222 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6223 RegCloseKey(hkeyPrinter
);
6224 RegCloseKey(hkeyPrinters
);
6229 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6230 0, pType
, pData
, pcbNeeded
);
6232 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6234 RegCloseKey(hkeySubkey
);
6235 RegCloseKey(hkeyPrinter
);
6236 RegCloseKey(hkeyPrinters
);
6238 TRACE("--> %d\n", ret
);
6242 /******************************************************************************
6243 * GetPrinterDataA (WINSPOOL.@)
6245 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6246 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6248 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6249 pData
, nSize
, pcbNeeded
);
6252 /******************************************************************************
6253 * GetPrinterDataW (WINSPOOL.@)
6255 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6256 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6258 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6259 pData
, nSize
, pcbNeeded
);
6262 /*******************************************************************************
6263 * EnumPrinterDataExW [WINSPOOL.@]
6265 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6266 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6267 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6269 HKEY hkPrinter
, hkSubKey
;
6270 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6271 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6276 PPRINTER_ENUM_VALUESW ppev
;
6278 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6280 if (pKeyName
== NULL
|| *pKeyName
== 0)
6281 return ERROR_INVALID_PARAMETER
;
6283 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6284 if (ret
!= ERROR_SUCCESS
)
6286 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6291 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6292 if (ret
!= ERROR_SUCCESS
)
6294 r
= RegCloseKey (hkPrinter
);
6295 if (r
!= ERROR_SUCCESS
)
6296 WARN ("RegCloseKey returned %i\n", r
);
6297 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6298 debugstr_w (pKeyName
), ret
);
6302 ret
= RegCloseKey (hkPrinter
);
6303 if (ret
!= ERROR_SUCCESS
)
6305 ERR ("RegCloseKey returned %i\n", ret
);
6306 r
= RegCloseKey (hkSubKey
);
6307 if (r
!= ERROR_SUCCESS
)
6308 WARN ("RegCloseKey returned %i\n", r
);
6312 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6313 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6314 if (ret
!= ERROR_SUCCESS
)
6316 r
= RegCloseKey (hkSubKey
);
6317 if (r
!= ERROR_SUCCESS
)
6318 WARN ("RegCloseKey returned %i\n", r
);
6319 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6323 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6324 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6326 if (cValues
== 0) /* empty key */
6328 r
= RegCloseKey (hkSubKey
);
6329 if (r
!= ERROR_SUCCESS
)
6330 WARN ("RegCloseKey returned %i\n", r
);
6331 *pcbEnumValues
= *pnEnumValues
= 0;
6332 return ERROR_SUCCESS
;
6335 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6337 hHeap
= GetProcessHeap ();
6340 ERR ("GetProcessHeap failed\n");
6341 r
= RegCloseKey (hkSubKey
);
6342 if (r
!= ERROR_SUCCESS
)
6343 WARN ("RegCloseKey returned %i\n", r
);
6344 return ERROR_OUTOFMEMORY
;
6347 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6348 if (lpValueName
== NULL
)
6350 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6351 r
= RegCloseKey (hkSubKey
);
6352 if (r
!= ERROR_SUCCESS
)
6353 WARN ("RegCloseKey returned %i\n", r
);
6354 return ERROR_OUTOFMEMORY
;
6357 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6358 if (lpValue
== NULL
)
6360 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6361 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6362 WARN ("HeapFree failed with code %i\n", GetLastError ());
6363 r
= RegCloseKey (hkSubKey
);
6364 if (r
!= ERROR_SUCCESS
)
6365 WARN ("RegCloseKey returned %i\n", r
);
6366 return ERROR_OUTOFMEMORY
;
6369 TRACE ("pass 1: calculating buffer required for all names and values\n");
6371 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6373 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6375 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6377 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6378 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6379 NULL
, NULL
, lpValue
, &cbValueLen
);
6380 if (ret
!= ERROR_SUCCESS
)
6382 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6383 WARN ("HeapFree failed with code %i\n", GetLastError ());
6384 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6385 WARN ("HeapFree failed with code %i\n", GetLastError ());
6386 r
= RegCloseKey (hkSubKey
);
6387 if (r
!= ERROR_SUCCESS
)
6388 WARN ("RegCloseKey returned %i\n", r
);
6389 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6393 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6394 debugstr_w (lpValueName
), dwIndex
,
6395 cbValueNameLen
+ 1, cbValueLen
);
6397 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6398 cbBufSize
+= cbValueLen
;
6401 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6403 *pcbEnumValues
= cbBufSize
;
6404 *pnEnumValues
= cValues
;
6406 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6408 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6409 WARN ("HeapFree failed with code %i\n", GetLastError ());
6410 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6411 WARN ("HeapFree failed with code %i\n", GetLastError ());
6412 r
= RegCloseKey (hkSubKey
);
6413 if (r
!= ERROR_SUCCESS
)
6414 WARN ("RegCloseKey returned %i\n", r
);
6415 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6416 return ERROR_MORE_DATA
;
6419 TRACE ("pass 2: copying all names and values to buffer\n");
6421 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6422 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6424 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6426 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6427 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6428 NULL
, &dwType
, lpValue
, &cbValueLen
);
6429 if (ret
!= ERROR_SUCCESS
)
6431 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6432 WARN ("HeapFree failed with code %i\n", GetLastError ());
6433 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6434 WARN ("HeapFree failed with code %i\n", GetLastError ());
6435 r
= RegCloseKey (hkSubKey
);
6436 if (r
!= ERROR_SUCCESS
)
6437 WARN ("RegCloseKey returned %i\n", r
);
6438 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6442 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6443 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6444 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6445 pEnumValues
+= cbValueNameLen
;
6447 /* return # of *bytes* (including trailing \0), not # of chars */
6448 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6450 ppev
[dwIndex
].dwType
= dwType
;
6452 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6453 ppev
[dwIndex
].pData
= pEnumValues
;
6454 pEnumValues
+= cbValueLen
;
6456 ppev
[dwIndex
].cbData
= cbValueLen
;
6458 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6459 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6462 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6464 ret
= GetLastError ();
6465 ERR ("HeapFree failed with code %i\n", ret
);
6466 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6467 WARN ("HeapFree failed with code %i\n", GetLastError ());
6468 r
= RegCloseKey (hkSubKey
);
6469 if (r
!= ERROR_SUCCESS
)
6470 WARN ("RegCloseKey returned %i\n", r
);
6474 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6476 ret
= GetLastError ();
6477 ERR ("HeapFree failed with code %i\n", ret
);
6478 r
= RegCloseKey (hkSubKey
);
6479 if (r
!= ERROR_SUCCESS
)
6480 WARN ("RegCloseKey returned %i\n", r
);
6484 ret
= RegCloseKey (hkSubKey
);
6485 if (ret
!= ERROR_SUCCESS
)
6487 ERR ("RegCloseKey returned %i\n", ret
);
6491 return ERROR_SUCCESS
;
6494 /*******************************************************************************
6495 * EnumPrinterDataExA [WINSPOOL.@]
6497 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6498 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6499 * what Windows 2000 SP1 does.
6502 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6503 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6504 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6508 DWORD ret
, dwIndex
, dwBufSize
;
6512 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6514 if (pKeyName
== NULL
|| *pKeyName
== 0)
6515 return ERROR_INVALID_PARAMETER
;
6517 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6520 ret
= GetLastError ();
6521 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6525 hHeap
= GetProcessHeap ();
6528 ERR ("GetProcessHeap failed\n");
6529 return ERROR_OUTOFMEMORY
;
6532 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6533 if (pKeyNameW
== NULL
)
6535 ERR ("Failed to allocate %i bytes from process heap\n",
6536 (LONG
)(len
* sizeof (WCHAR
)));
6537 return ERROR_OUTOFMEMORY
;
6540 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6542 ret
= GetLastError ();
6543 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6544 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6545 WARN ("HeapFree failed with code %i\n", GetLastError ());
6549 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6550 pcbEnumValues
, pnEnumValues
);
6551 if (ret
!= ERROR_SUCCESS
)
6553 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6554 WARN ("HeapFree failed with code %i\n", GetLastError ());
6555 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6559 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6561 ret
= GetLastError ();
6562 ERR ("HeapFree failed with code %i\n", ret
);
6566 if (*pnEnumValues
== 0) /* empty key */
6567 return ERROR_SUCCESS
;
6570 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6572 PPRINTER_ENUM_VALUESW ppev
=
6573 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6575 if (dwBufSize
< ppev
->cbValueName
)
6576 dwBufSize
= ppev
->cbValueName
;
6578 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6579 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6580 dwBufSize
= ppev
->cbData
;
6583 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6585 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6586 if (pBuffer
== NULL
)
6588 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6589 return ERROR_OUTOFMEMORY
;
6592 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6594 PPRINTER_ENUM_VALUESW ppev
=
6595 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6597 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6598 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6602 ret
= GetLastError ();
6603 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6604 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6605 WARN ("HeapFree failed with code %i\n", GetLastError ());
6609 memcpy (ppev
->pValueName
, pBuffer
, len
);
6611 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6613 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6614 ppev
->dwType
!= REG_MULTI_SZ
)
6617 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6618 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6621 ret
= GetLastError ();
6622 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6623 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6624 WARN ("HeapFree failed with code %i\n", GetLastError ());
6628 memcpy (ppev
->pData
, pBuffer
, len
);
6630 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6631 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6634 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6636 ret
= GetLastError ();
6637 ERR ("HeapFree failed with code %i\n", ret
);
6641 return ERROR_SUCCESS
;
6644 /******************************************************************************
6645 * AbortPrinter (WINSPOOL.@)
6647 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6649 FIXME("(%p), stub!\n", hPrinter
);
6653 /******************************************************************************
6654 * AddPortA (WINSPOOL.@)
6659 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6661 LPWSTR nameW
= NULL
;
6662 LPWSTR monitorW
= NULL
;
6666 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6669 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6670 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6671 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6675 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6676 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6677 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6679 res
= AddPortW(nameW
, hWnd
, monitorW
);
6680 HeapFree(GetProcessHeap(), 0, nameW
);
6681 HeapFree(GetProcessHeap(), 0, monitorW
);
6685 /******************************************************************************
6686 * AddPortW (WINSPOOL.@)
6688 * Add a Port for a specific Monitor
6691 * pName [I] Servername or NULL (local Computer)
6692 * hWnd [I] Handle to parent Window for the Dialog-Box
6693 * pMonitorName [I] Name of the Monitor that manage the Port
6700 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6702 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6704 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6706 if (!pMonitorName
) {
6707 SetLastError(RPC_X_NULL_REF_POINTER
);
6711 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6714 /******************************************************************************
6715 * AddPortExA (WINSPOOL.@)
6720 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6723 PORT_INFO_2A
* pi2A
;
6724 LPWSTR nameW
= NULL
;
6725 LPWSTR monitorW
= NULL
;
6729 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6731 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6732 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6734 if ((level
< 1) || (level
> 2)) {
6735 SetLastError(ERROR_INVALID_LEVEL
);
6740 SetLastError(ERROR_INVALID_PARAMETER
);
6745 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6746 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6747 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6751 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6752 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6753 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6756 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6758 if (pi2A
->pPortName
) {
6759 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6760 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6761 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6765 if (pi2A
->pMonitorName
) {
6766 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6767 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6768 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6771 if (pi2A
->pDescription
) {
6772 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6773 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6774 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6776 pi2W
.fPortType
= pi2A
->fPortType
;
6777 pi2W
.Reserved
= pi2A
->Reserved
;
6780 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6782 HeapFree(GetProcessHeap(), 0, nameW
);
6783 HeapFree(GetProcessHeap(), 0, monitorW
);
6784 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6785 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6786 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6791 /******************************************************************************
6792 * AddPortExW (WINSPOOL.@)
6794 * Add a Port for a specific Monitor, without presenting a user interface
6797 * pName [I] Servername or NULL (local Computer)
6798 * level [I] Structure-Level (1 or 2) for pBuffer
6799 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6800 * pMonitorName [I] Name of the Monitor that manage the Port
6807 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6811 pi2
= (PORT_INFO_2W
*) pBuffer
;
6813 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6814 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6815 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6816 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6818 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6820 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6821 SetLastError(ERROR_INVALID_PARAMETER
);
6825 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6828 /******************************************************************************
6829 * AddPrinterConnectionA (WINSPOOL.@)
6831 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6833 FIXME("%s\n", debugstr_a(pName
));
6837 /******************************************************************************
6838 * AddPrinterConnectionW (WINSPOOL.@)
6840 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6842 FIXME("%s\n", debugstr_w(pName
));
6846 /******************************************************************************
6847 * AddPrinterDriverExW (WINSPOOL.@)
6849 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6852 * pName [I] Servername or NULL (local Computer)
6853 * level [I] Level for the supplied DRIVER_INFO_*W struct
6854 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6855 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6862 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6864 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6866 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6868 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6869 SetLastError(ERROR_INVALID_LEVEL
);
6874 SetLastError(ERROR_INVALID_PARAMETER
);
6878 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6881 /******************************************************************************
6882 * AddPrinterDriverExA (WINSPOOL.@)
6884 * See AddPrinterDriverExW.
6887 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6889 DRIVER_INFO_8A
*diA
;
6891 LPWSTR nameW
= NULL
;
6896 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6898 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6899 ZeroMemory(&diW
, sizeof(diW
));
6901 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6902 SetLastError(ERROR_INVALID_LEVEL
);
6907 SetLastError(ERROR_INVALID_PARAMETER
);
6911 /* convert servername to unicode */
6913 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6914 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6915 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6919 diW
.cVersion
= diA
->cVersion
;
6922 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6923 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6924 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6927 if (diA
->pEnvironment
) {
6928 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6929 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6930 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6933 if (diA
->pDriverPath
) {
6934 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6935 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6936 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6939 if (diA
->pDataFile
) {
6940 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6941 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6942 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6945 if (diA
->pConfigFile
) {
6946 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6947 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6948 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6951 if ((Level
> 2) && diA
->pHelpFile
) {
6952 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, NULL
, 0);
6953 diW
.pHelpFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6954 MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, diW
.pHelpFile
, len
);
6957 if ((Level
> 2) && diA
->pDependentFiles
) {
6958 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6959 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6960 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6961 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6964 if ((Level
> 2) && diA
->pMonitorName
) {
6965 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6966 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6967 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6970 if ((Level
> 2) && diA
->pDefaultDataType
) {
6971 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6972 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6973 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6976 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6977 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6978 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6979 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6980 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6984 diW
.ftDriverDate
= diA
->ftDriverDate
;
6985 diW
.dwlDriverVersion
= diA
->dwlDriverVersion
;
6988 if ((Level
> 5) && diA
->pszMfgName
) {
6989 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6990 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6991 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6994 if ((Level
> 5) && diA
->pszOEMUrl
) {
6995 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6996 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6997 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
7000 if ((Level
> 5) && diA
->pszHardwareID
) {
7001 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
7002 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7003 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
7006 if ((Level
> 5) && diA
->pszProvider
) {
7007 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
7008 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7009 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
7012 if ((Level
> 7) && diA
->pszPrintProcessor
) {
7013 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, NULL
, 0);
7014 diW
.pszPrintProcessor
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7015 MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, diW
.pszPrintProcessor
, len
);
7018 if ((Level
> 7) && diA
->pszVendorSetup
) {
7019 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, NULL
, 0);
7020 diW
.pszVendorSetup
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7021 MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, diW
.pszVendorSetup
, len
);
7024 if ((Level
> 7) && diA
->pszzColorProfiles
) {
7025 lenA
= multi_sz_lenA(diA
->pszzColorProfiles
);
7026 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, NULL
, 0);
7027 diW
.pszzColorProfiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7028 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, diW
.pszzColorProfiles
, len
);
7031 if ((Level
> 7) && diA
->pszInfPath
) {
7032 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, NULL
, 0);
7033 diW
.pszInfPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7034 MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, diW
.pszInfPath
, len
);
7037 if ((Level
> 7) && diA
->pszzCoreDriverDependencies
) {
7038 lenA
= multi_sz_lenA(diA
->pszzCoreDriverDependencies
);
7039 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, NULL
, 0);
7040 diW
.pszzCoreDriverDependencies
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7041 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, diW
.pszzCoreDriverDependencies
, len
);
7045 diW
.dwPrinterDriverAttributes
= diA
->dwPrinterDriverAttributes
;
7046 diW
.ftMinInboxDriverVerDate
= diA
->ftMinInboxDriverVerDate
;
7047 diW
.dwlMinInboxDriverVerVersion
= diA
->dwlMinInboxDriverVerVersion
;
7050 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
7051 TRACE("got %u with %u\n", res
, GetLastError());
7052 HeapFree(GetProcessHeap(), 0, nameW
);
7053 HeapFree(GetProcessHeap(), 0, diW
.pName
);
7054 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
7055 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
7056 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
7057 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
7058 HeapFree(GetProcessHeap(), 0, diW
.pHelpFile
);
7059 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
7060 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
7061 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
7062 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
7063 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
7064 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
7065 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
7066 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
7067 HeapFree(GetProcessHeap(), 0, diW
.pszPrintProcessor
);
7068 HeapFree(GetProcessHeap(), 0, diW
.pszVendorSetup
);
7069 HeapFree(GetProcessHeap(), 0, diW
.pszzColorProfiles
);
7070 HeapFree(GetProcessHeap(), 0, diW
.pszInfPath
);
7071 HeapFree(GetProcessHeap(), 0, diW
.pszzCoreDriverDependencies
);
7073 TRACE("=> %u with %u\n", res
, GetLastError());
7077 /******************************************************************************
7078 * ConfigurePortA (WINSPOOL.@)
7080 * See ConfigurePortW.
7083 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
7085 LPWSTR nameW
= NULL
;
7086 LPWSTR portW
= NULL
;
7090 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
7092 /* convert servername to unicode */
7094 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7095 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7096 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7099 /* convert portname to unicode */
7101 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
7102 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7103 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
7106 res
= ConfigurePortW(nameW
, hWnd
, portW
);
7107 HeapFree(GetProcessHeap(), 0, nameW
);
7108 HeapFree(GetProcessHeap(), 0, portW
);
7112 /******************************************************************************
7113 * ConfigurePortW (WINSPOOL.@)
7115 * Display the Configuration-Dialog for a specific Port
7118 * pName [I] Servername or NULL (local Computer)
7119 * hWnd [I] Handle to parent Window for the Dialog-Box
7120 * pPortName [I] Name of the Port, that should be configured
7127 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
7130 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
7132 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7135 SetLastError(RPC_X_NULL_REF_POINTER
);
7139 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
7142 /******************************************************************************
7143 * ConnectToPrinterDlg (WINSPOOL.@)
7145 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
7147 FIXME("%p %x\n", hWnd
, Flags
);
7151 /******************************************************************************
7152 * DeletePrinterConnectionA (WINSPOOL.@)
7154 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
7156 FIXME("%s\n", debugstr_a(pName
));
7160 /******************************************************************************
7161 * DeletePrinterConnectionW (WINSPOOL.@)
7163 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
7165 FIXME("%s\n", debugstr_w(pName
));
7169 /******************************************************************************
7170 * DeletePrinterDriverExW (WINSPOOL.@)
7172 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
7173 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7178 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7179 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
7181 if(pName
&& pName
[0])
7183 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
7184 SetLastError(ERROR_INVALID_PARAMETER
);
7190 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7191 SetLastError(ERROR_INVALID_PARAMETER
);
7195 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7199 ERR("Can't open drivers key\n");
7203 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7206 RegCloseKey(hkey_drivers
);
7211 /******************************************************************************
7212 * DeletePrinterDriverExA (WINSPOOL.@)
7214 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7215 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7217 UNICODE_STRING NameW
, EnvW
, DriverW
;
7220 asciitounicode(&NameW
, pName
);
7221 asciitounicode(&EnvW
, pEnvironment
);
7222 asciitounicode(&DriverW
, pDriverName
);
7224 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7226 RtlFreeUnicodeString(&DriverW
);
7227 RtlFreeUnicodeString(&EnvW
);
7228 RtlFreeUnicodeString(&NameW
);
7233 /******************************************************************************
7234 * DeletePrinterDataExW (WINSPOOL.@)
7236 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7239 FIXME("%p %s %s\n", hPrinter
,
7240 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7241 return ERROR_INVALID_PARAMETER
;
7244 /******************************************************************************
7245 * DeletePrinterDataExA (WINSPOOL.@)
7247 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7250 FIXME("%p %s %s\n", hPrinter
,
7251 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7252 return ERROR_INVALID_PARAMETER
;
7255 /******************************************************************************
7256 * DeletePrintProcessorA (WINSPOOL.@)
7258 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7260 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7261 debugstr_a(pPrintProcessorName
));
7265 /******************************************************************************
7266 * DeletePrintProcessorW (WINSPOOL.@)
7268 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7270 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7271 debugstr_w(pPrintProcessorName
));
7275 /******************************************************************************
7276 * DeletePrintProvidorA (WINSPOOL.@)
7278 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7280 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7281 debugstr_a(pPrintProviderName
));
7285 /******************************************************************************
7286 * DeletePrintProvidorW (WINSPOOL.@)
7288 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7290 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7291 debugstr_w(pPrintProviderName
));
7295 /******************************************************************************
7296 * EnumFormsA (WINSPOOL.@)
7298 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7299 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7301 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7302 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7306 /******************************************************************************
7307 * EnumFormsW (WINSPOOL.@)
7309 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7310 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7312 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7313 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7317 /*****************************************************************************
7318 * EnumMonitorsA [WINSPOOL.@]
7320 * See EnumMonitorsW.
7323 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7324 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7327 LPBYTE bufferW
= NULL
;
7328 LPWSTR nameW
= NULL
;
7330 DWORD numentries
= 0;
7333 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7334 cbBuf
, pcbNeeded
, pcReturned
);
7336 /* convert servername to unicode */
7338 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7339 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7340 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7342 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7343 needed
= cbBuf
* sizeof(WCHAR
);
7344 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7345 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7347 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7348 if (pcbNeeded
) needed
= *pcbNeeded
;
7349 /* HeapReAlloc return NULL, when bufferW was NULL */
7350 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7351 HeapAlloc(GetProcessHeap(), 0, needed
);
7353 /* Try again with the large Buffer */
7354 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7356 numentries
= pcReturned
? *pcReturned
: 0;
7359 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7360 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7363 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7364 DWORD entrysize
= 0;
7367 LPMONITOR_INFO_2W mi2w
;
7368 LPMONITOR_INFO_2A mi2a
;
7370 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7371 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7373 /* First pass: calculate the size for all Entries */
7374 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7375 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7377 while (index
< numentries
) {
7379 needed
+= entrysize
; /* MONITOR_INFO_?A */
7380 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7382 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7383 NULL
, 0, NULL
, NULL
);
7385 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7386 NULL
, 0, NULL
, NULL
);
7387 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7388 NULL
, 0, NULL
, NULL
);
7390 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7391 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7392 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7395 /* check for errors and quit on failure */
7396 if (cbBuf
< needed
) {
7397 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7401 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7402 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7403 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7404 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7405 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7407 /* Second Pass: Fill the User Buffer (if we have one) */
7408 while ((index
< numentries
) && pMonitors
) {
7410 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7412 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7413 ptr
, cbBuf
, NULL
, NULL
);
7417 mi2a
->pEnvironment
= ptr
;
7418 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7419 ptr
, cbBuf
, NULL
, NULL
);
7423 mi2a
->pDLLName
= ptr
;
7424 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7425 ptr
, cbBuf
, NULL
, NULL
);
7429 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7430 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7431 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7435 if (pcbNeeded
) *pcbNeeded
= needed
;
7436 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7438 HeapFree(GetProcessHeap(), 0, nameW
);
7439 HeapFree(GetProcessHeap(), 0, bufferW
);
7441 TRACE("returning %d with %d (%d byte for %d entries)\n",
7442 (res
), GetLastError(), needed
, numentries
);
7448 /*****************************************************************************
7449 * EnumMonitorsW [WINSPOOL.@]
7451 * Enumerate available Port-Monitors
7454 * pName [I] Servername or NULL (local Computer)
7455 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7456 * pMonitors [O] PTR to Buffer that receives the Result
7457 * cbBuf [I] Size of Buffer at pMonitors
7458 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7459 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7463 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7466 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7467 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7470 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7471 cbBuf
, pcbNeeded
, pcReturned
);
7473 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7475 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7476 SetLastError(RPC_X_NULL_REF_POINTER
);
7480 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7483 /******************************************************************************
7484 * SpoolerInit (WINSPOOL.@)
7486 * Initialize the Spooler
7493 * The function fails on windows, when the spooler service is not running
7496 BOOL WINAPI
SpoolerInit(void)
7499 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7503 /******************************************************************************
7504 * XcvDataW (WINSPOOL.@)
7506 * Execute commands in the Printmonitor DLL
7509 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7510 * pszDataName [i] Name of the command to execute
7511 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7512 * cbInputData [i] Size in Bytes of Buffer at pInputData
7513 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7514 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7515 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7516 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7523 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7524 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7526 * Minimal List of commands, that a Printmonitor DLL should support:
7528 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7529 *| "AddPort" : Add a Port
7530 *| "DeletePort": Delete a Port
7532 * Many Printmonitors support additional commands. Examples for localspl.dll:
7533 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7534 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7537 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7538 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7539 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7541 opened_printer_t
*printer
;
7543 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7544 pInputData
, cbInputData
, pOutputData
,
7545 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7547 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7549 printer
= get_opened_printer(hXcv
);
7550 if (!printer
|| (!printer
->backend_printer
)) {
7551 SetLastError(ERROR_INVALID_HANDLE
);
7555 if (!pcbOutputNeeded
) {
7556 SetLastError(ERROR_INVALID_PARAMETER
);
7560 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7561 SetLastError(RPC_X_NULL_REF_POINTER
);
7565 *pcbOutputNeeded
= 0;
7567 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7568 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7572 /*****************************************************************************
7573 * EnumPrinterDataA [WINSPOOL.@]
7576 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7577 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7578 DWORD cbData
, LPDWORD pcbData
)
7580 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7581 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7582 return ERROR_NO_MORE_ITEMS
;
7585 /*****************************************************************************
7586 * EnumPrinterDataW [WINSPOOL.@]
7589 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7590 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7591 DWORD cbData
, LPDWORD pcbData
)
7593 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7594 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7595 return ERROR_NO_MORE_ITEMS
;
7598 /*****************************************************************************
7599 * EnumPrinterKeyA [WINSPOOL.@]
7602 DWORD WINAPI
EnumPrinterKeyA(HANDLE printer
, const CHAR
*key
, CHAR
*subkey
, DWORD size
, DWORD
*needed
)
7604 FIXME("%p %s %p %x %p\n", printer
, debugstr_a(key
), subkey
, size
, needed
);
7605 return ERROR_CALL_NOT_IMPLEMENTED
;
7608 /*****************************************************************************
7609 * EnumPrinterKeyW [WINSPOOL.@]
7612 DWORD WINAPI
EnumPrinterKeyW(HANDLE printer
, const WCHAR
*key
, WCHAR
*subkey
, DWORD size
, DWORD
*needed
)
7614 FIXME("%p %s %p %x %p\n", printer
, debugstr_w(key
), subkey
, size
, needed
);
7615 return ERROR_CALL_NOT_IMPLEMENTED
;
7618 /*****************************************************************************
7619 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7622 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7623 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7624 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7626 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7627 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7628 pcbNeeded
, pcReturned
);
7632 /*****************************************************************************
7633 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7636 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7637 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7638 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7640 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7641 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7642 pcbNeeded
, pcReturned
);
7646 /*****************************************************************************
7647 * EnumPrintProcessorsA [WINSPOOL.@]
7649 * See EnumPrintProcessorsW.
7652 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7653 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7656 LPBYTE bufferW
= NULL
;
7657 LPWSTR nameW
= NULL
;
7660 DWORD numentries
= 0;
7663 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7664 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7666 /* convert names to unicode */
7668 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7669 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7670 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7673 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7674 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7675 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7678 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7679 needed
= cbBuf
* sizeof(WCHAR
);
7680 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7681 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7683 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7684 if (pcbNeeded
) needed
= *pcbNeeded
;
7685 /* HeapReAlloc return NULL, when bufferW was NULL */
7686 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7687 HeapAlloc(GetProcessHeap(), 0, needed
);
7689 /* Try again with the large Buffer */
7690 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7692 numentries
= pcReturned
? *pcReturned
: 0;
7696 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7699 PPRINTPROCESSOR_INFO_1W ppiw
;
7700 PPRINTPROCESSOR_INFO_1A ppia
;
7702 /* First pass: calculate the size for all Entries */
7703 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7704 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7706 while (index
< numentries
) {
7708 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7709 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7711 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7712 NULL
, 0, NULL
, NULL
);
7714 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7715 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7718 /* check for errors and quit on failure */
7719 if (cbBuf
< needed
) {
7720 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7725 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7726 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7727 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7728 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7729 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7731 /* Second Pass: Fill the User Buffer (if we have one) */
7732 while ((index
< numentries
) && pPPInfo
) {
7734 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7736 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7737 ptr
, cbBuf
, NULL
, NULL
);
7741 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7742 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7747 if (pcbNeeded
) *pcbNeeded
= needed
;
7748 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7750 HeapFree(GetProcessHeap(), 0, nameW
);
7751 HeapFree(GetProcessHeap(), 0, envW
);
7752 HeapFree(GetProcessHeap(), 0, bufferW
);
7754 TRACE("returning %d with %d (%d byte for %d entries)\n",
7755 (res
), GetLastError(), needed
, numentries
);
7760 /*****************************************************************************
7761 * EnumPrintProcessorsW [WINSPOOL.@]
7763 * Enumerate available Print Processors
7766 * pName [I] Servername or NULL (local Computer)
7767 * pEnvironment [I] Printing-Environment or NULL (Default)
7768 * Level [I] Structure-Level (Only 1 is allowed)
7769 * pPPInfo [O] PTR to Buffer that receives the Result
7770 * cbBuf [I] Size of Buffer at pPPInfo
7771 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7772 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7776 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7779 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7780 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7783 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7784 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7786 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7788 if (!pcbNeeded
|| !pcReturned
) {
7789 SetLastError(RPC_X_NULL_REF_POINTER
);
7793 if (!pPPInfo
&& (cbBuf
> 0)) {
7794 SetLastError(ERROR_INVALID_USER_BUFFER
);
7798 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7799 cbBuf
, pcbNeeded
, pcReturned
);
7802 /*****************************************************************************
7803 * ExtDeviceMode [WINSPOOL.@]
7806 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7807 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7810 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7811 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7812 debugstr_a(pProfile
), fMode
);
7816 /*****************************************************************************
7817 * FindClosePrinterChangeNotification [WINSPOOL.@]
7820 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7822 FIXME("Stub: %p\n", hChange
);
7826 /*****************************************************************************
7827 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7830 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7831 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7833 FIXME("Stub: %p %x %x %p\n",
7834 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7835 return INVALID_HANDLE_VALUE
;
7838 /*****************************************************************************
7839 * FindNextPrinterChangeNotification [WINSPOOL.@]
7842 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7843 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7845 FIXME("Stub: %p %p %p %p\n",
7846 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7850 /*****************************************************************************
7851 * FreePrinterNotifyInfo [WINSPOOL.@]
7854 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7856 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7860 /*****************************************************************************
7863 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7864 * ansi depending on the unicode parameter.
7866 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7876 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7879 memcpy(ptr
, str
, *size
);
7886 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7889 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7896 /*****************************************************************************
7899 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7900 LPDWORD pcbNeeded
, BOOL unicode
)
7902 DWORD size
, left
= cbBuf
;
7903 BOOL space
= (cbBuf
> 0);
7910 ji1
->JobId
= job
->job_id
;
7913 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7914 if(space
&& size
<= left
)
7916 ji1
->pDocument
= (LPWSTR
)ptr
;
7924 if (job
->printer_name
)
7926 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7927 if(space
&& size
<= left
)
7929 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7941 /*****************************************************************************
7944 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7945 LPDWORD pcbNeeded
, BOOL unicode
)
7947 DWORD size
, left
= cbBuf
;
7949 BOOL space
= (cbBuf
> 0);
7951 LPDEVMODEA dmA
= NULL
;
7958 ji2
->JobId
= job
->job_id
;
7961 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7962 if(space
&& size
<= left
)
7964 ji2
->pDocument
= (LPWSTR
)ptr
;
7972 if (job
->printer_name
)
7974 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7975 if(space
&& size
<= left
)
7977 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7990 dmA
= DEVMODEdupWtoA(job
->devmode
);
7991 devmode
= (LPDEVMODEW
) dmA
;
7992 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7996 devmode
= job
->devmode
;
7997 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
8001 FIXME("Can't convert DEVMODE W to A\n");
8004 /* align DEVMODE to a DWORD boundary */
8005 shift
= (4 - (*pcbNeeded
& 3)) & 3;
8011 memcpy(ptr
, devmode
, size
-shift
);
8012 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
8013 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
8026 /*****************************************************************************
8029 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8030 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
8033 DWORD needed
= 0, size
;
8037 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
8039 EnterCriticalSection(&printer_handles_cs
);
8040 job
= get_job(hPrinter
, JobId
);
8047 size
= sizeof(JOB_INFO_1W
);
8052 memset(pJob
, 0, size
);
8056 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8061 size
= sizeof(JOB_INFO_2W
);
8066 memset(pJob
, 0, size
);
8070 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8075 size
= sizeof(JOB_INFO_3
);
8079 memset(pJob
, 0, size
);
8088 SetLastError(ERROR_INVALID_LEVEL
);
8092 *pcbNeeded
= needed
;
8094 LeaveCriticalSection(&printer_handles_cs
);
8098 /*****************************************************************************
8099 * GetJobA [WINSPOOL.@]
8102 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8103 DWORD cbBuf
, LPDWORD pcbNeeded
)
8105 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
8108 /*****************************************************************************
8109 * GetJobW [WINSPOOL.@]
8112 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8113 DWORD cbBuf
, LPDWORD pcbNeeded
)
8115 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
8118 /*****************************************************************************
8121 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
8124 char *unixname
, *cmdA
;
8126 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
8132 if(!(unixname
= wine_get_unix_file_name(filename
)))
8135 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
8136 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
8137 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
8139 TRACE("printing with: %s\n", cmdA
);
8141 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
8146 ERR("pipe() failed!\n");
8150 if ((pid
= fork()) == 0)
8156 /* reset signals that we previously set to SIG_IGN */
8157 signal(SIGPIPE
, SIG_DFL
);
8159 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
8164 ERR("fork() failed!\n");
8170 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
8171 write(fds
[1], buf
, no_read
);
8178 wret
= waitpid(pid
, &status
, 0);
8179 } while (wret
< 0 && errno
== EINTR
);
8182 ERR("waitpid() failed!\n");
8185 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
8187 ERR("child process failed! %d\n", status
);
8194 if(file_fd
!= -1) close(file_fd
);
8195 if(fds
[0] != -1) close(fds
[0]);
8196 if(fds
[1] != -1) close(fds
[1]);
8198 HeapFree(GetProcessHeap(), 0, cmdA
);
8199 HeapFree(GetProcessHeap(), 0, unixname
);
8206 /*****************************************************************************
8209 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8212 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8215 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8216 sprintfW(cmd
, fmtW
, printer_name
);
8218 r
= schedule_pipe(cmd
, filename
);
8220 HeapFree(GetProcessHeap(), 0, cmd
);
8224 #ifdef SONAME_LIBCUPS
8225 /*****************************************************************************
8226 * get_cups_jobs_ticket_options
8228 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8229 * The CUPS scheduler only looks for these in Print-File requests, and since
8230 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8233 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8235 FILE *fp
= fopen( file
, "r" );
8236 char buf
[257]; /* DSC max of 256 + '\0' */
8237 const char *ps_adobe
= "%!PS-Adobe-";
8238 const char *cups_job
= "%cupsJobTicket:";
8240 if (!fp
) return num_options
;
8241 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8242 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8243 while (fgets( buf
, sizeof(buf
), fp
))
8245 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8246 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8254 static int get_cups_default_options( const char *printer
, int num_options
, cups_option_t
**options
)
8259 if (!pcupsGetNamedDest
) return num_options
;
8261 dest
= pcupsGetNamedDest( NULL
, printer
, NULL
);
8262 if (!dest
) return num_options
;
8264 for (i
= 0; i
< dest
->num_options
; i
++)
8266 if (!pcupsGetOption( dest
->options
[i
].name
, num_options
, *options
))
8267 num_options
= pcupsAddOption( dest
->options
[i
].name
, dest
->options
[i
].value
,
8268 num_options
, options
);
8271 pcupsFreeDests( 1, dest
);
8276 /*****************************************************************************
8279 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8281 #ifdef SONAME_LIBCUPS
8284 char *unixname
, *queue
, *unix_doc_title
;
8287 int num_options
= 0, i
;
8288 cups_option_t
*options
= NULL
;
8290 if(!(unixname
= wine_get_unix_file_name(filename
)))
8293 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8294 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8295 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8297 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8298 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8299 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8301 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8302 num_options
= get_cups_default_options( queue
, num_options
, &options
);
8304 TRACE( "printing via cups with options:\n" );
8305 for (i
= 0; i
< num_options
; i
++)
8306 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8308 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8309 if (ret
== 0 && pcupsLastErrorString
)
8310 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8312 pcupsFreeOptions( num_options
, options
);
8314 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8315 HeapFree(GetProcessHeap(), 0, queue
);
8316 HeapFree(GetProcessHeap(), 0, unixname
);
8322 return schedule_lpr(printer_name
, filename
);
8326 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8333 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8337 if(HIWORD(wparam
) == BN_CLICKED
)
8339 if(LOWORD(wparam
) == IDOK
)
8342 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8345 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8346 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8348 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8350 WCHAR caption
[200], message
[200];
8353 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8354 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
8355 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8356 if(mb_ret
== IDCANCEL
)
8358 HeapFree(GetProcessHeap(), 0, filename
);
8362 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8363 if(hf
== INVALID_HANDLE_VALUE
)
8365 WCHAR caption
[200], message
[200];
8367 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8368 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
8369 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8370 HeapFree(GetProcessHeap(), 0, filename
);
8374 DeleteFileW(filename
);
8375 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8377 EndDialog(hwnd
, IDOK
);
8380 if(LOWORD(wparam
) == IDCANCEL
)
8382 EndDialog(hwnd
, IDCANCEL
);
8391 /*****************************************************************************
8394 static BOOL
get_filename(LPWSTR
*filename
)
8396 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8397 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8400 /*****************************************************************************
8403 static BOOL
schedule_file(LPCWSTR filename
)
8405 LPWSTR output
= NULL
;
8407 if(get_filename(&output
))
8410 TRACE("copy to %s\n", debugstr_w(output
));
8411 r
= CopyFileW(filename
, output
, FALSE
);
8412 HeapFree(GetProcessHeap(), 0, output
);
8418 /*****************************************************************************
8421 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8423 int in_fd
, out_fd
, no_read
;
8426 char *unixname
, *outputA
;
8429 if(!(unixname
= wine_get_unix_file_name(filename
)))
8432 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8433 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8434 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8436 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8437 in_fd
= open(unixname
, O_RDONLY
);
8438 if(out_fd
== -1 || in_fd
== -1)
8441 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8442 write(out_fd
, buf
, no_read
);
8446 if(in_fd
!= -1) close(in_fd
);
8447 if(out_fd
!= -1) close(out_fd
);
8448 HeapFree(GetProcessHeap(), 0, outputA
);
8449 HeapFree(GetProcessHeap(), 0, unixname
);
8453 /*****************************************************************************
8454 * ScheduleJob [WINSPOOL.@]
8457 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8459 opened_printer_t
*printer
;
8461 struct list
*cursor
, *cursor2
;
8463 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8464 EnterCriticalSection(&printer_handles_cs
);
8465 printer
= get_opened_printer(hPrinter
);
8469 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8471 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8474 if(job
->job_id
!= dwJobID
) continue;
8476 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8477 if(hf
!= INVALID_HANDLE_VALUE
)
8479 PRINTER_INFO_5W
*pi5
= NULL
;
8480 LPWSTR portname
= job
->portname
;
8484 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8485 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8489 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8490 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8491 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8492 portname
= pi5
->pPortName
;
8494 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8495 debugstr_w(portname
));
8499 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8500 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8502 DWORD type
, count
= sizeof(output
);
8503 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8506 if(output
[0] == '|')
8508 ret
= schedule_pipe(output
+ 1, job
->filename
);
8512 ret
= schedule_unixfile(output
, job
->filename
);
8514 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8516 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8518 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8520 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8522 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8524 ret
= schedule_file(job
->filename
);
8526 else if(isalpha(portname
[0]) && portname
[1] == ':')
8528 TRACE("copying to %s\n", debugstr_w(portname
));
8529 ret
= CopyFileW(job
->filename
, portname
, FALSE
);
8533 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8535 HeapFree(GetProcessHeap(), 0, pi5
);
8537 DeleteFileW(job
->filename
);
8539 list_remove(cursor
);
8540 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8541 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8542 HeapFree(GetProcessHeap(), 0, job
->portname
);
8543 HeapFree(GetProcessHeap(), 0, job
->filename
);
8544 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8545 HeapFree(GetProcessHeap(), 0, job
);
8549 LeaveCriticalSection(&printer_handles_cs
);
8553 /*****************************************************************************
8554 * StartDocDlgA [WINSPOOL.@]
8556 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8558 UNICODE_STRING usBuffer
;
8559 DOCINFOW docW
= { 0 };
8561 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8564 docW
.cbSize
= sizeof(docW
);
8565 if (doc
->lpszDocName
)
8567 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8568 if (!(docW
.lpszDocName
= docnameW
)) goto failed
;
8570 if (doc
->lpszOutput
)
8572 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8573 if (!(docW
.lpszOutput
= outputW
)) goto failed
;
8575 if (doc
->lpszDatatype
)
8577 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8578 if (!(docW
.lpszDatatype
= datatypeW
)) goto failed
;
8580 docW
.fwType
= doc
->fwType
;
8582 retW
= StartDocDlgW(hPrinter
, &docW
);
8586 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8587 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8588 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8589 HeapFree(GetProcessHeap(), 0, retW
);
8593 HeapFree(GetProcessHeap(), 0, datatypeW
);
8594 HeapFree(GetProcessHeap(), 0, outputW
);
8595 HeapFree(GetProcessHeap(), 0, docnameW
);
8600 /*****************************************************************************
8601 * StartDocDlgW [WINSPOOL.@]
8603 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8604 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8605 * port is "FILE:". Also returns the full path if passed a relative path.
8607 * The caller should free the returned string from the process heap.
8609 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8614 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8616 PRINTER_INFO_5W
*pi5
;
8617 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8618 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8620 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8621 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8622 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8624 HeapFree(GetProcessHeap(), 0, pi5
);
8627 HeapFree(GetProcessHeap(), 0, pi5
);
8630 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8634 if (get_filename(&name
))
8636 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8638 HeapFree(GetProcessHeap(), 0, name
);
8641 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8642 GetFullPathNameW(name
, len
, ret
, NULL
);
8643 HeapFree(GetProcessHeap(), 0, name
);
8648 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8651 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8652 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8654 attr
= GetFileAttributesW(ret
);
8655 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8657 HeapFree(GetProcessHeap(), 0, ret
);
8663 /*****************************************************************************
8664 * UploadPrinterDriverPackageA [WINSPOOL.@]
8666 HRESULT WINAPI
UploadPrinterDriverPackageA( LPCSTR server
, LPCSTR path
, LPCSTR env
,
8667 DWORD flags
, HWND hwnd
, LPSTR dst
, PULONG dstlen
)
8669 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server
), debugstr_a(path
), debugstr_a(env
),
8670 flags
, hwnd
, dst
, dstlen
);
8674 /*****************************************************************************
8675 * UploadPrinterDriverPackageW [WINSPOOL.@]
8677 HRESULT WINAPI
UploadPrinterDriverPackageW( LPCWSTR server
, LPCWSTR path
, LPCWSTR env
,
8678 DWORD flags
, HWND hwnd
, LPWSTR dst
, PULONG dstlen
)
8680 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server
), debugstr_w(path
), debugstr_w(env
),
8681 flags
, hwnd
, dst
, dstlen
);