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
< ARRAY_SIZE(all_printenv
); 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
< ARRAY_SIZE(all_printenv
); 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( ARRAY_SIZE( tmp_path
), 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
, ARRAY_SIZE(nameW
));
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
, ARRAY_SIZE(nameW
));
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
, ARRAY_SIZE( CUPS_Port
) -1 ))
1042 name
= port
+ ARRAY_SIZE( CUPS_Port
) - 1;
1045 else if (!strncmpW( port
, LPR_Port
, ARRAY_SIZE( LPR_Port
) -1 ))
1046 name
= port
+ ARRAY_SIZE( LPR_Port
) - 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
, ARRAY_SIZE(devnameW
));
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
= ARRAY_SIZE(buffer
);
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
, ARRAY_SIZE(PrinterName
)) == 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
, ARRAY_SIZE(path
));
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
= ARRAY_SIZE(def
);
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
, ARRAY_SIZE(PrinterName
)) != ERROR_SUCCESS
) {
4671 ERR("Can't enum key number %d\n", i
);
4672 RegCloseKey(hkeyPrinters
);
4675 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4676 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4678 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4679 RegCloseKey(hkeyPrinters
);
4684 buf
= lpbPrinters
+ used
;
4685 left
= cbBuf
- used
;
4693 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4696 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4699 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4702 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4705 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4708 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4711 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4714 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4717 ERR("Shouldn't be here!\n");
4718 RegCloseKey(hkeyPrinter
);
4719 RegCloseKey(hkeyPrinters
);
4722 RegCloseKey(hkeyPrinter
);
4724 RegCloseKey(hkeyPrinters
);
4731 memset(lpbPrinters
, 0, cbBuf
);
4732 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4736 *lpdwReturned
= number
;
4737 SetLastError(ERROR_SUCCESS
);
4742 /******************************************************************
4743 * EnumPrintersW [WINSPOOL.@]
4745 * Enumerates the available printers, print servers and print
4746 * providers, depending on the specified flags, name and level.
4750 * If level is set to 1:
4751 * Returns an array of PRINTER_INFO_1 data structures in the
4752 * lpbPrinters buffer.
4754 * If level is set to 2:
4755 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4756 * Returns an array of PRINTER_INFO_2 data structures in the
4757 * lpbPrinters buffer. Note that according to MSDN also an
4758 * OpenPrinter should be performed on every remote printer.
4760 * If level is set to 4 (officially WinNT only):
4761 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4762 * Fast: Only the registry is queried to retrieve printer names,
4763 * no connection to the driver is made.
4764 * Returns an array of PRINTER_INFO_4 data structures in the
4765 * lpbPrinters buffer.
4767 * If level is set to 5 (officially WinNT4/Win9x only):
4768 * Fast: Only the registry is queried to retrieve printer names,
4769 * no connection to the driver is made.
4770 * Returns an array of PRINTER_INFO_5 data structures in the
4771 * lpbPrinters buffer.
4773 * If level set to 3 or 6+:
4774 * returns zero (failure!)
4776 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4780 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4781 * - Only levels 2, 4 and 5 are implemented at the moment.
4782 * - 16-bit printer drivers are not enumerated.
4783 * - Returned amount of bytes used/needed does not match the real Windoze
4784 * implementation (as in this implementation, all strings are part
4785 * of the buffer, whereas Win32 keeps them somewhere else)
4786 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4789 * - In a regular Wine installation, no registry settings for printers
4790 * exist, which makes this function return an empty list.
4792 BOOL WINAPI
EnumPrintersW(
4793 DWORD dwType
, /* [in] Types of print objects to enumerate */
4794 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4795 DWORD dwLevel
, /* [in] type of printer info structure */
4796 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4797 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4798 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4799 LPDWORD lpdwReturned
/* [out] number of entries returned */
4802 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4803 lpdwNeeded
, lpdwReturned
);
4806 /******************************************************************
4807 * EnumPrintersA [WINSPOOL.@]
4812 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4813 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4816 UNICODE_STRING pNameU
;
4820 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4821 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4823 pNameW
= asciitounicode(&pNameU
, pName
);
4825 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4826 MS Office need this */
4827 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4829 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4831 RtlFreeUnicodeString(&pNameU
);
4833 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4835 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4839 /*****************************************************************************
4840 * WINSPOOL_GetDriverInfoFromReg [internal]
4842 * Enters the information from the registry into the DRIVER_INFO struct
4845 * zero if the printer driver does not exist in the registry
4846 * (only if Level > 1) otherwise nonzero
4848 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4851 const printenv_t
* env
,
4853 LPBYTE ptr
, /* DRIVER_INFO */
4854 LPBYTE pDriverStrings
, /* strings buffer */
4855 DWORD cbBuf
, /* size of string buffer */
4856 LPDWORD pcbNeeded
) /* space needed for str. */
4860 WCHAR driverdir
[MAX_PATH
];
4862 LPBYTE strPtr
= pDriverStrings
;
4863 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4865 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4866 debugstr_w(DriverName
), env
,
4867 Level
, di
, pDriverStrings
, cbBuf
);
4869 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4871 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4872 if (*pcbNeeded
<= cbBuf
)
4873 strcpyW((LPWSTR
)strPtr
, DriverName
);
4875 /* pName for level 1 has a different offset! */
4877 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4881 /* .cVersion and .pName for level > 1 */
4883 di
->cVersion
= env
->driverversion
;
4884 di
->pName
= (LPWSTR
) strPtr
;
4885 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4888 /* Reserve Space for the largest subdir and a Backslash*/
4889 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4890 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4891 /* Should never Fail */
4894 lstrcatW(driverdir
, env
->versionsubdir
);
4895 lstrcatW(driverdir
, backslashW
);
4897 /* dirlen must not include the terminating zero */
4898 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4900 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4901 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4902 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4907 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4910 if (*pcbNeeded
<= cbBuf
) {
4911 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4912 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4913 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4916 /* .pDriverPath is the Graphics rendering engine.
4917 The full Path is required to avoid a crash in some apps */
4918 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4920 if (*pcbNeeded
<= cbBuf
)
4921 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4923 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4924 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4927 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4928 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4930 if (*pcbNeeded
<= cbBuf
)
4931 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4933 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4934 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4937 /* .pConfigFile is the Driver user Interface */
4938 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4940 if (*pcbNeeded
<= cbBuf
)
4941 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4943 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4944 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4948 RegCloseKey(hkeyDriver
);
4949 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4954 RegCloseKey(hkeyDriver
);
4955 FIXME("level 5: incomplete\n");
4960 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4962 if (*pcbNeeded
<= cbBuf
)
4963 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4965 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4966 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4969 /* .pDependentFiles */
4970 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4972 if (*pcbNeeded
<= cbBuf
)
4973 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4975 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4976 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4978 else if (GetVersion() & 0x80000000) {
4979 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4980 size
= 2 * sizeof(WCHAR
);
4982 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4984 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4985 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4988 /* .pMonitorName is the optional Language Monitor */
4989 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4991 if (*pcbNeeded
<= cbBuf
)
4992 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4994 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4995 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4998 /* .pDefaultDataType */
4999 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
5001 if(*pcbNeeded
<= cbBuf
)
5002 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
5004 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
5005 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5009 RegCloseKey(hkeyDriver
);
5010 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5014 /* .pszzPreviousNames */
5015 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
5017 if(*pcbNeeded
<= cbBuf
)
5018 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
5020 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
5021 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5025 RegCloseKey(hkeyDriver
);
5026 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5030 /* support is missing, but not important enough for a FIXME */
5031 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
5034 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
5036 if(*pcbNeeded
<= cbBuf
)
5037 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
5039 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
5040 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5044 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
5046 if(*pcbNeeded
<= cbBuf
)
5047 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
5049 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
5050 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5053 /* .pszHardwareID */
5054 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
5056 if(*pcbNeeded
<= cbBuf
)
5057 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
5059 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
5060 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5064 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
5066 if(*pcbNeeded
<= cbBuf
)
5067 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
5069 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
5070 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5074 RegCloseKey(hkeyDriver
);
5078 /* support is missing, but not important enough for a FIXME */
5079 TRACE("level 8: incomplete\n");
5081 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5082 RegCloseKey(hkeyDriver
);
5086 /*****************************************************************************
5087 * GetPrinterDriverW [WINSPOOL.@]
5089 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5090 DWORD Level
, LPBYTE pDriverInfo
,
5091 DWORD cbBuf
, LPDWORD pcbNeeded
)
5094 WCHAR DriverName
[100];
5095 DWORD ret
, type
, size
, needed
= 0;
5097 HKEY hkeyPrinter
, hkeyDrivers
;
5098 const printenv_t
* env
;
5100 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
5101 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
5104 ZeroMemory(pDriverInfo
, cbBuf
);
5106 if (!(name
= get_opened_printer_name(hPrinter
))) {
5107 SetLastError(ERROR_INVALID_HANDLE
);
5111 if (Level
< 1 || Level
== 7 || Level
> 8) {
5112 SetLastError(ERROR_INVALID_LEVEL
);
5116 env
= validate_envW(pEnvironment
);
5117 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5119 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
5122 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
5123 SetLastError( ret
);
5127 size
= sizeof(DriverName
);
5129 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5130 (LPBYTE
)DriverName
, &size
);
5131 RegCloseKey(hkeyPrinter
);
5132 if(ret
!= ERROR_SUCCESS
) {
5133 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5137 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5139 ERR("Can't create Drivers key\n");
5143 size
= di_sizeof
[Level
];
5144 if ((size
<= cbBuf
) && pDriverInfo
)
5145 ptr
= pDriverInfo
+ size
;
5147 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5148 env
, Level
, pDriverInfo
, ptr
,
5149 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5151 RegCloseKey(hkeyDrivers
);
5155 RegCloseKey(hkeyDrivers
);
5157 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5158 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5159 if(cbBuf
>= size
+ needed
) return TRUE
;
5160 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5164 /*****************************************************************************
5165 * GetPrinterDriverA [WINSPOOL.@]
5167 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5168 DWORD Level
, LPBYTE pDriverInfo
,
5169 DWORD cbBuf
, LPDWORD pcbNeeded
)
5172 UNICODE_STRING pEnvW
;
5178 ZeroMemory(pDriverInfo
, cbBuf
);
5179 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5182 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5183 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5186 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5188 HeapFree(GetProcessHeap(), 0, buf
);
5190 RtlFreeUnicodeString(&pEnvW
);
5194 /*****************************************************************************
5195 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5197 * Return the PATH for the Printer-Drivers (UNICODE)
5200 * pName [I] Servername (NT only) or NULL (local Computer)
5201 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5202 * Level [I] Structure-Level (must be 1)
5203 * pDriverDirectory [O] PTR to Buffer that receives the Result
5204 * cbBuf [I] Size of Buffer at pDriverDirectory
5205 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5206 * required for pDriverDirectory
5209 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5210 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5211 * if cbBuf is too small
5213 * Native Values returned in pDriverDirectory on Success:
5214 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5215 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5216 *| win9x(Windows 4.0): "%winsysdir%"
5218 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5221 *- Only NULL or "" is supported for pName
5224 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5225 DWORD Level
, LPBYTE pDriverDirectory
,
5226 DWORD cbBuf
, LPDWORD pcbNeeded
)
5228 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5229 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5231 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5234 /* (Level != 1) is ignored in win9x */
5235 SetLastError(ERROR_INVALID_LEVEL
);
5238 if (pcbNeeded
== NULL
) {
5239 /* (pcbNeeded == NULL) is ignored in win9x */
5240 SetLastError(RPC_X_NULL_REF_POINTER
);
5244 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5245 pDriverDirectory
, cbBuf
, pcbNeeded
);
5250 /*****************************************************************************
5251 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5253 * Return the PATH for the Printer-Drivers (ANSI)
5255 * See GetPrinterDriverDirectoryW.
5258 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5261 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5262 DWORD Level
, LPBYTE pDriverDirectory
,
5263 DWORD cbBuf
, LPDWORD pcbNeeded
)
5265 UNICODE_STRING nameW
, environmentW
;
5268 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5269 WCHAR
*driverDirectoryW
= NULL
;
5271 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5272 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5274 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5276 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5277 else nameW
.Buffer
= NULL
;
5278 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5279 else environmentW
.Buffer
= NULL
;
5281 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5282 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5285 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5286 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5288 *pcbNeeded
= needed
;
5289 ret
= needed
<= cbBuf
;
5291 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5293 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5295 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5296 RtlFreeUnicodeString(&environmentW
);
5297 RtlFreeUnicodeString(&nameW
);
5302 /*****************************************************************************
5303 * AddPrinterDriverA [WINSPOOL.@]
5305 * See AddPrinterDriverW.
5308 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5310 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5311 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5314 /******************************************************************************
5315 * AddPrinterDriverW (WINSPOOL.@)
5317 * Install a Printer Driver
5320 * pName [I] Servername or NULL (local Computer)
5321 * level [I] Level for the supplied DRIVER_INFO_*W struct
5322 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5329 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5331 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5332 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5335 /*****************************************************************************
5336 * AddPrintProcessorA [WINSPOOL.@]
5338 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5339 LPSTR pPrintProcessorName
)
5341 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5342 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5346 /*****************************************************************************
5347 * AddPrintProcessorW [WINSPOOL.@]
5349 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5350 LPWSTR pPrintProcessorName
)
5352 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5353 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5357 /*****************************************************************************
5358 * AddPrintProvidorA [WINSPOOL.@]
5360 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5362 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5366 /*****************************************************************************
5367 * AddPrintProvidorW [WINSPOOL.@]
5369 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5371 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5375 /*****************************************************************************
5376 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5378 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5379 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5381 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5382 pDevModeOutput
, pDevModeInput
);
5386 /*****************************************************************************
5387 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5389 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5390 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5392 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5393 pDevModeOutput
, pDevModeInput
);
5397 /*****************************************************************************
5398 * PrinterProperties [WINSPOOL.@]
5400 * Displays a dialog to set the properties of the printer.
5403 * nonzero on success or zero on failure
5406 * implemented as stub only
5408 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5409 HANDLE hPrinter
/* [in] handle to printer object */
5411 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5412 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5416 /*****************************************************************************
5417 * EnumJobsA [WINSPOOL.@]
5420 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5421 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5424 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5425 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5427 if(pcbNeeded
) *pcbNeeded
= 0;
5428 if(pcReturned
) *pcReturned
= 0;
5433 /*****************************************************************************
5434 * EnumJobsW [WINSPOOL.@]
5437 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5438 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5441 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5442 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5444 if(pcbNeeded
) *pcbNeeded
= 0;
5445 if(pcReturned
) *pcReturned
= 0;
5449 /*****************************************************************************
5450 * WINSPOOL_EnumPrinterDrivers [internal]
5452 * Delivers information about all printer drivers installed on the
5453 * localhost or a given server
5456 * nonzero on success or zero on failure. If the buffer for the returned
5457 * information is too small the function will return an error
5460 * - only implemented for localhost, foreign hosts will return an error
5462 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5463 DWORD Level
, LPBYTE pDriverInfo
,
5465 DWORD cbBuf
, LPDWORD pcbNeeded
,
5466 LPDWORD pcFound
, DWORD data_offset
)
5470 const printenv_t
* env
;
5472 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5473 debugstr_w(pName
), debugstr_w(pEnvironment
),
5474 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5476 env
= validate_envW(pEnvironment
);
5477 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5481 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5483 ERR("Can't open Drivers key\n");
5487 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5488 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5489 RegCloseKey(hkeyDrivers
);
5490 ERR("Can't query Drivers key\n");
5493 TRACE("Found %d Drivers\n", *pcFound
);
5495 /* get size of single struct
5496 * unicode and ascii structure have the same size
5498 size
= di_sizeof
[Level
];
5500 if (data_offset
== 0)
5501 data_offset
= size
* (*pcFound
);
5502 *pcbNeeded
= data_offset
;
5504 for( i
= 0; i
< *pcFound
; i
++) {
5505 WCHAR DriverNameW
[255];
5506 PBYTE table_ptr
= NULL
;
5507 PBYTE data_ptr
= NULL
;
5510 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, ARRAY_SIZE(DriverNameW
)) != ERROR_SUCCESS
) {
5511 ERR("Can't enum key number %d\n", i
);
5512 RegCloseKey(hkeyDrivers
);
5516 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5517 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5518 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5519 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5521 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5522 env
, Level
, table_ptr
, data_ptr
,
5523 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5525 RegCloseKey(hkeyDrivers
);
5529 *pcbNeeded
+= needed
;
5532 RegCloseKey(hkeyDrivers
);
5534 if(cbBuf
< *pcbNeeded
){
5535 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5542 /*****************************************************************************
5543 * EnumPrinterDriversW [WINSPOOL.@]
5545 * see function EnumPrinterDrivers for RETURNS, BUGS
5547 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5548 LPBYTE pDriverInfo
, DWORD cbBuf
,
5549 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5551 static const WCHAR allW
[] = {'a','l','l',0};
5555 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5557 SetLastError(RPC_X_NULL_REF_POINTER
);
5561 /* check for local drivers */
5562 if((pName
) && (pName
[0])) {
5563 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5564 SetLastError(ERROR_ACCESS_DENIED
);
5568 /* check input parameter */
5569 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5570 SetLastError(ERROR_INVALID_LEVEL
);
5574 if(pDriverInfo
&& cbBuf
> 0)
5575 memset( pDriverInfo
, 0, cbBuf
);
5577 /* Exception: pull all printers */
5578 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5580 DWORD i
, needed
, bufsize
= cbBuf
;
5581 DWORD total_found
= 0;
5584 /* Precompute the overall total; we need this to know
5585 where pointers end and data begins (i.e. data_offset) */
5586 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5589 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5590 NULL
, 0, 0, &needed
, &found
, 0);
5591 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5592 total_found
+= found
;
5595 data_offset
= di_sizeof
[Level
] * total_found
;
5600 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5603 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5604 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5605 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5607 *pcReturned
+= found
;
5608 *pcbNeeded
= needed
;
5609 data_offset
= needed
;
5610 total_found
+= found
;
5615 /* Normal behavior */
5616 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5617 0, cbBuf
, pcbNeeded
, &found
, 0);
5619 *pcReturned
= found
;
5624 /*****************************************************************************
5625 * EnumPrinterDriversA [WINSPOOL.@]
5627 * see function EnumPrinterDrivers for RETURNS, BUGS
5629 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5630 LPBYTE pDriverInfo
, DWORD cbBuf
,
5631 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5634 UNICODE_STRING pNameW
, pEnvironmentW
;
5635 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5639 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5641 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5642 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5644 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5645 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5647 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5649 HeapFree(GetProcessHeap(), 0, buf
);
5651 RtlFreeUnicodeString(&pNameW
);
5652 RtlFreeUnicodeString(&pEnvironmentW
);
5657 /******************************************************************************
5658 * EnumPortsA (WINSPOOL.@)
5663 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5664 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5667 LPBYTE bufferW
= NULL
;
5668 LPWSTR nameW
= NULL
;
5670 DWORD numentries
= 0;
5673 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5674 cbBuf
, pcbNeeded
, pcReturned
);
5676 /* convert servername to unicode */
5678 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5679 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5680 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5682 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5683 needed
= cbBuf
* sizeof(WCHAR
);
5684 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5685 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5687 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5688 if (pcbNeeded
) needed
= *pcbNeeded
;
5689 /* HeapReAlloc return NULL, when bufferW was NULL */
5690 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5691 HeapAlloc(GetProcessHeap(), 0, needed
);
5693 /* Try again with the large Buffer */
5694 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5696 needed
= pcbNeeded
? *pcbNeeded
: 0;
5697 numentries
= pcReturned
? *pcReturned
: 0;
5700 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5701 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5704 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5705 DWORD entrysize
= 0;
5708 LPPORT_INFO_2W pi2w
;
5709 LPPORT_INFO_2A pi2a
;
5712 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5714 /* First pass: calculate the size for all Entries */
5715 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5716 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5718 while (index
< numentries
) {
5720 needed
+= entrysize
; /* PORT_INFO_?A */
5721 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5723 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5724 NULL
, 0, NULL
, NULL
);
5726 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5727 NULL
, 0, NULL
, NULL
);
5728 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5729 NULL
, 0, NULL
, NULL
);
5731 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5732 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5733 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5736 /* check for errors and quit on failure */
5737 if (cbBuf
< needed
) {
5738 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5742 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5743 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5744 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5745 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5746 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5748 /* Second Pass: Fill the User Buffer (if we have one) */
5749 while ((index
< numentries
) && pPorts
) {
5751 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5752 pi2a
->pPortName
= ptr
;
5753 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5754 ptr
, cbBuf
, NULL
, NULL
);
5758 pi2a
->pMonitorName
= ptr
;
5759 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5760 ptr
, cbBuf
, NULL
, NULL
);
5764 pi2a
->pDescription
= ptr
;
5765 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5766 ptr
, cbBuf
, NULL
, NULL
);
5770 pi2a
->fPortType
= pi2w
->fPortType
;
5771 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5774 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5775 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5776 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5781 if (pcbNeeded
) *pcbNeeded
= needed
;
5782 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5784 HeapFree(GetProcessHeap(), 0, nameW
);
5785 HeapFree(GetProcessHeap(), 0, bufferW
);
5787 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5788 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5794 /******************************************************************************
5795 * EnumPortsW (WINSPOOL.@)
5797 * Enumerate available Ports
5800 * pName [I] Servername or NULL (local Computer)
5801 * Level [I] Structure-Level (1 or 2)
5802 * pPorts [O] PTR to Buffer that receives the Result
5803 * cbBuf [I] Size of Buffer at pPorts
5804 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5805 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5809 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5812 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5815 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5816 cbBuf
, pcbNeeded
, pcReturned
);
5818 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5820 /* Level is not checked in win9x */
5821 if (!Level
|| (Level
> 2)) {
5822 WARN("level (%d) is ignored in win9x\n", Level
);
5823 SetLastError(ERROR_INVALID_LEVEL
);
5826 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5827 SetLastError(RPC_X_NULL_REF_POINTER
);
5831 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5834 /******************************************************************************
5835 * GetDefaultPrinterW (WINSPOOL.@)
5838 * This function must read the value from data 'device' of key
5839 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5841 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5845 WCHAR
*buffer
, *ptr
;
5849 SetLastError(ERROR_INVALID_PARAMETER
);
5853 /* make the buffer big enough for the stuff from the profile/registry,
5854 * the content must fit into the local buffer to compute the correct
5855 * size even if the extern buffer is too small or not given.
5856 * (20 for ,driver,port) */
5858 len
= max(100, (insize
+ 20));
5859 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5861 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5863 SetLastError (ERROR_FILE_NOT_FOUND
);
5867 TRACE("%s\n", debugstr_w(buffer
));
5869 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5871 SetLastError(ERROR_INVALID_NAME
);
5877 *namesize
= strlenW(buffer
) + 1;
5878 if(!name
|| (*namesize
> insize
))
5880 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5884 strcpyW(name
, buffer
);
5887 HeapFree( GetProcessHeap(), 0, buffer
);
5892 /******************************************************************************
5893 * GetDefaultPrinterA (WINSPOOL.@)
5895 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5899 WCHAR
*bufferW
= NULL
;
5903 SetLastError(ERROR_INVALID_PARAMETER
);
5907 if(name
&& *namesize
) {
5909 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5912 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5917 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5921 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5924 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5927 HeapFree( GetProcessHeap(), 0, bufferW
);
5932 /******************************************************************************
5933 * SetDefaultPrinterW (WINSPOOL.204)
5935 * Set the Name of the Default Printer
5938 * pszPrinter [I] Name of the Printer or NULL
5945 * When the Parameter is NULL or points to an Empty String and
5946 * a Default Printer was already present, then this Function changes nothing.
5947 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5948 * the First enumerated local Printer is used.
5951 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5953 WCHAR default_printer
[MAX_PATH
];
5954 LPWSTR buffer
= NULL
;
5960 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5961 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5963 default_printer
[0] = '\0';
5964 size
= ARRAY_SIZE(default_printer
);
5966 /* if we have a default Printer, do nothing. */
5967 if (GetDefaultPrinterW(default_printer
, &size
))
5971 /* we have no default Printer: search local Printers and use the first */
5972 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5974 default_printer
[0] = '\0';
5975 size
= ARRAY_SIZE(default_printer
);
5976 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5978 pszPrinter
= default_printer
;
5979 TRACE("using %s\n", debugstr_w(pszPrinter
));
5984 if (pszPrinter
== NULL
) {
5985 TRACE("no local printer found\n");
5986 SetLastError(ERROR_FILE_NOT_FOUND
);
5991 /* "pszPrinter" is never empty or NULL here. */
5992 namelen
= lstrlenW(pszPrinter
);
5993 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5994 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5996 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5997 HeapFree(GetProcessHeap(), 0, buffer
);
5998 SetLastError(ERROR_FILE_NOT_FOUND
);
6002 /* read the devices entry for the printer (driver,port) to build the string for the
6003 default device entry (printer,driver,port) */
6004 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
6005 buffer
[namelen
] = ',';
6006 namelen
++; /* move index to the start of the driver */
6008 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
6009 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
6011 TRACE("set device to %s\n", debugstr_w(buffer
));
6013 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
6014 TRACE("failed to set the device entry: %d\n", GetLastError());
6015 lres
= ERROR_INVALID_PRINTER_NAME
;
6018 /* remove the next section, when INIFileMapping is implemented */
6021 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
6022 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
6029 if (lres
!= ERROR_FILE_NOT_FOUND
)
6030 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
6032 SetLastError(ERROR_INVALID_PRINTER_NAME
);
6036 HeapFree(GetProcessHeap(), 0, buffer
);
6037 return (lres
== ERROR_SUCCESS
);
6040 /******************************************************************************
6041 * SetDefaultPrinterA (WINSPOOL.202)
6043 * See SetDefaultPrinterW.
6046 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
6048 LPWSTR bufferW
= NULL
;
6051 TRACE("(%s)\n", debugstr_a(pszPrinter
));
6053 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
6054 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6055 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
6057 res
= SetDefaultPrinterW(bufferW
);
6058 HeapFree(GetProcessHeap(), 0, bufferW
);
6062 /******************************************************************************
6063 * SetPrinterDataExA (WINSPOOL.@)
6065 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6066 LPCSTR pValueName
, DWORD Type
,
6067 LPBYTE pData
, DWORD cbData
)
6069 HKEY hkeyPrinter
, hkeySubkey
;
6072 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
6073 debugstr_a(pValueName
), Type
, pData
, cbData
);
6075 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6079 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6081 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
6082 RegCloseKey(hkeyPrinter
);
6085 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6086 RegCloseKey(hkeySubkey
);
6087 RegCloseKey(hkeyPrinter
);
6091 /******************************************************************************
6092 * SetPrinterDataExW (WINSPOOL.@)
6094 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6095 LPCWSTR pValueName
, DWORD Type
,
6096 LPBYTE pData
, DWORD cbData
)
6098 HKEY hkeyPrinter
, hkeySubkey
;
6101 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
6102 debugstr_w(pValueName
), Type
, pData
, cbData
);
6104 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6108 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6110 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
6111 RegCloseKey(hkeyPrinter
);
6114 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6115 RegCloseKey(hkeySubkey
);
6116 RegCloseKey(hkeyPrinter
);
6120 /******************************************************************************
6121 * SetPrinterDataA (WINSPOOL.@)
6123 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
6124 LPBYTE pData
, DWORD cbData
)
6126 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
6130 /******************************************************************************
6131 * SetPrinterDataW (WINSPOOL.@)
6133 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
6134 LPBYTE pData
, DWORD cbData
)
6136 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6140 /******************************************************************************
6141 * GetPrinterDataExA (WINSPOOL.@)
6143 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6144 LPCSTR pValueName
, LPDWORD pType
,
6145 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6147 opened_printer_t
*printer
;
6148 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6151 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6152 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6154 printer
= get_opened_printer(hPrinter
);
6155 if(!printer
) return ERROR_INVALID_HANDLE
;
6157 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6158 if (ret
) return ret
;
6160 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6162 if (printer
->name
) {
6164 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6166 RegCloseKey(hkeyPrinters
);
6169 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6170 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6171 RegCloseKey(hkeyPrinter
);
6172 RegCloseKey(hkeyPrinters
);
6177 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6178 0, pType
, pData
, pcbNeeded
);
6180 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6182 RegCloseKey(hkeySubkey
);
6183 RegCloseKey(hkeyPrinter
);
6184 RegCloseKey(hkeyPrinters
);
6186 TRACE("--> %d\n", ret
);
6190 /******************************************************************************
6191 * GetPrinterDataExW (WINSPOOL.@)
6193 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6194 LPCWSTR pValueName
, LPDWORD pType
,
6195 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6197 opened_printer_t
*printer
;
6198 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6201 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6202 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6204 printer
= get_opened_printer(hPrinter
);
6205 if(!printer
) return ERROR_INVALID_HANDLE
;
6207 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6208 if (ret
) return ret
;
6210 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6212 if (printer
->name
) {
6214 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6216 RegCloseKey(hkeyPrinters
);
6219 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6220 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6221 RegCloseKey(hkeyPrinter
);
6222 RegCloseKey(hkeyPrinters
);
6227 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6228 0, pType
, pData
, pcbNeeded
);
6230 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6232 RegCloseKey(hkeySubkey
);
6233 RegCloseKey(hkeyPrinter
);
6234 RegCloseKey(hkeyPrinters
);
6236 TRACE("--> %d\n", ret
);
6240 /******************************************************************************
6241 * GetPrinterDataA (WINSPOOL.@)
6243 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6244 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6246 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6247 pData
, nSize
, pcbNeeded
);
6250 /******************************************************************************
6251 * GetPrinterDataW (WINSPOOL.@)
6253 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6254 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6256 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6257 pData
, nSize
, pcbNeeded
);
6260 /*******************************************************************************
6261 * EnumPrinterDataExW [WINSPOOL.@]
6263 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6264 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6265 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6267 HKEY hkPrinter
, hkSubKey
;
6268 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6269 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6274 PPRINTER_ENUM_VALUESW ppev
;
6276 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6278 if (pKeyName
== NULL
|| *pKeyName
== 0)
6279 return ERROR_INVALID_PARAMETER
;
6281 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6282 if (ret
!= ERROR_SUCCESS
)
6284 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6289 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6290 if (ret
!= ERROR_SUCCESS
)
6292 r
= RegCloseKey (hkPrinter
);
6293 if (r
!= ERROR_SUCCESS
)
6294 WARN ("RegCloseKey returned %i\n", r
);
6295 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6296 debugstr_w (pKeyName
), ret
);
6300 ret
= RegCloseKey (hkPrinter
);
6301 if (ret
!= ERROR_SUCCESS
)
6303 ERR ("RegCloseKey returned %i\n", ret
);
6304 r
= RegCloseKey (hkSubKey
);
6305 if (r
!= ERROR_SUCCESS
)
6306 WARN ("RegCloseKey returned %i\n", r
);
6310 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6311 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6312 if (ret
!= ERROR_SUCCESS
)
6314 r
= RegCloseKey (hkSubKey
);
6315 if (r
!= ERROR_SUCCESS
)
6316 WARN ("RegCloseKey returned %i\n", r
);
6317 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6321 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6322 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6324 if (cValues
== 0) /* empty key */
6326 r
= RegCloseKey (hkSubKey
);
6327 if (r
!= ERROR_SUCCESS
)
6328 WARN ("RegCloseKey returned %i\n", r
);
6329 *pcbEnumValues
= *pnEnumValues
= 0;
6330 return ERROR_SUCCESS
;
6333 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6335 hHeap
= GetProcessHeap ();
6338 ERR ("GetProcessHeap failed\n");
6339 r
= RegCloseKey (hkSubKey
);
6340 if (r
!= ERROR_SUCCESS
)
6341 WARN ("RegCloseKey returned %i\n", r
);
6342 return ERROR_OUTOFMEMORY
;
6345 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6346 if (lpValueName
== NULL
)
6348 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6349 r
= RegCloseKey (hkSubKey
);
6350 if (r
!= ERROR_SUCCESS
)
6351 WARN ("RegCloseKey returned %i\n", r
);
6352 return ERROR_OUTOFMEMORY
;
6355 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6356 if (lpValue
== NULL
)
6358 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6359 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6360 WARN ("HeapFree failed with code %i\n", GetLastError ());
6361 r
= RegCloseKey (hkSubKey
);
6362 if (r
!= ERROR_SUCCESS
)
6363 WARN ("RegCloseKey returned %i\n", r
);
6364 return ERROR_OUTOFMEMORY
;
6367 TRACE ("pass 1: calculating buffer required for all names and values\n");
6369 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6371 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6373 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6375 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6376 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6377 NULL
, NULL
, lpValue
, &cbValueLen
);
6378 if (ret
!= ERROR_SUCCESS
)
6380 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6381 WARN ("HeapFree failed with code %i\n", GetLastError ());
6382 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6383 WARN ("HeapFree failed with code %i\n", GetLastError ());
6384 r
= RegCloseKey (hkSubKey
);
6385 if (r
!= ERROR_SUCCESS
)
6386 WARN ("RegCloseKey returned %i\n", r
);
6387 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6391 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6392 debugstr_w (lpValueName
), dwIndex
,
6393 cbValueNameLen
+ 1, cbValueLen
);
6395 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6396 cbBufSize
+= cbValueLen
;
6399 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6401 *pcbEnumValues
= cbBufSize
;
6402 *pnEnumValues
= cValues
;
6404 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6406 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6407 WARN ("HeapFree failed with code %i\n", GetLastError ());
6408 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6409 WARN ("HeapFree failed with code %i\n", GetLastError ());
6410 r
= RegCloseKey (hkSubKey
);
6411 if (r
!= ERROR_SUCCESS
)
6412 WARN ("RegCloseKey returned %i\n", r
);
6413 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6414 return ERROR_MORE_DATA
;
6417 TRACE ("pass 2: copying all names and values to buffer\n");
6419 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6420 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6422 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6424 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6425 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6426 NULL
, &dwType
, lpValue
, &cbValueLen
);
6427 if (ret
!= ERROR_SUCCESS
)
6429 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6430 WARN ("HeapFree failed with code %i\n", GetLastError ());
6431 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6432 WARN ("HeapFree failed with code %i\n", GetLastError ());
6433 r
= RegCloseKey (hkSubKey
);
6434 if (r
!= ERROR_SUCCESS
)
6435 WARN ("RegCloseKey returned %i\n", r
);
6436 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6440 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6441 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6442 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6443 pEnumValues
+= cbValueNameLen
;
6445 /* return # of *bytes* (including trailing \0), not # of chars */
6446 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6448 ppev
[dwIndex
].dwType
= dwType
;
6450 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6451 ppev
[dwIndex
].pData
= pEnumValues
;
6452 pEnumValues
+= cbValueLen
;
6454 ppev
[dwIndex
].cbData
= cbValueLen
;
6456 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6457 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6460 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6462 ret
= GetLastError ();
6463 ERR ("HeapFree failed with code %i\n", ret
);
6464 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6465 WARN ("HeapFree failed with code %i\n", GetLastError ());
6466 r
= RegCloseKey (hkSubKey
);
6467 if (r
!= ERROR_SUCCESS
)
6468 WARN ("RegCloseKey returned %i\n", r
);
6472 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6474 ret
= GetLastError ();
6475 ERR ("HeapFree failed with code %i\n", ret
);
6476 r
= RegCloseKey (hkSubKey
);
6477 if (r
!= ERROR_SUCCESS
)
6478 WARN ("RegCloseKey returned %i\n", r
);
6482 ret
= RegCloseKey (hkSubKey
);
6483 if (ret
!= ERROR_SUCCESS
)
6485 ERR ("RegCloseKey returned %i\n", ret
);
6489 return ERROR_SUCCESS
;
6492 /*******************************************************************************
6493 * EnumPrinterDataExA [WINSPOOL.@]
6495 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6496 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6497 * what Windows 2000 SP1 does.
6500 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6501 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6502 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6506 DWORD ret
, dwIndex
, dwBufSize
;
6510 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6512 if (pKeyName
== NULL
|| *pKeyName
== 0)
6513 return ERROR_INVALID_PARAMETER
;
6515 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6518 ret
= GetLastError ();
6519 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6523 hHeap
= GetProcessHeap ();
6526 ERR ("GetProcessHeap failed\n");
6527 return ERROR_OUTOFMEMORY
;
6530 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6531 if (pKeyNameW
== NULL
)
6533 ERR ("Failed to allocate %i bytes from process heap\n",
6534 (LONG
)(len
* sizeof (WCHAR
)));
6535 return ERROR_OUTOFMEMORY
;
6538 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6540 ret
= GetLastError ();
6541 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6542 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6543 WARN ("HeapFree failed with code %i\n", GetLastError ());
6547 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6548 pcbEnumValues
, pnEnumValues
);
6549 if (ret
!= ERROR_SUCCESS
)
6551 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6552 WARN ("HeapFree failed with code %i\n", GetLastError ());
6553 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6557 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6559 ret
= GetLastError ();
6560 ERR ("HeapFree failed with code %i\n", ret
);
6564 if (*pnEnumValues
== 0) /* empty key */
6565 return ERROR_SUCCESS
;
6568 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6570 PPRINTER_ENUM_VALUESW ppev
=
6571 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6573 if (dwBufSize
< ppev
->cbValueName
)
6574 dwBufSize
= ppev
->cbValueName
;
6576 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6577 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6578 dwBufSize
= ppev
->cbData
;
6581 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6583 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6584 if (pBuffer
== NULL
)
6586 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6587 return ERROR_OUTOFMEMORY
;
6590 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6592 PPRINTER_ENUM_VALUESW ppev
=
6593 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6595 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6596 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6600 ret
= GetLastError ();
6601 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6602 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6603 WARN ("HeapFree failed with code %i\n", GetLastError ());
6607 memcpy (ppev
->pValueName
, pBuffer
, len
);
6609 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6611 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6612 ppev
->dwType
!= REG_MULTI_SZ
)
6615 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6616 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6619 ret
= GetLastError ();
6620 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6621 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6622 WARN ("HeapFree failed with code %i\n", GetLastError ());
6626 memcpy (ppev
->pData
, pBuffer
, len
);
6628 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6629 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6632 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6634 ret
= GetLastError ();
6635 ERR ("HeapFree failed with code %i\n", ret
);
6639 return ERROR_SUCCESS
;
6642 /******************************************************************************
6643 * AbortPrinter (WINSPOOL.@)
6645 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6647 FIXME("(%p), stub!\n", hPrinter
);
6651 /******************************************************************************
6652 * AddPortA (WINSPOOL.@)
6657 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6659 LPWSTR nameW
= NULL
;
6660 LPWSTR monitorW
= NULL
;
6664 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6667 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6668 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6669 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6673 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6674 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6675 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6677 res
= AddPortW(nameW
, hWnd
, monitorW
);
6678 HeapFree(GetProcessHeap(), 0, nameW
);
6679 HeapFree(GetProcessHeap(), 0, monitorW
);
6683 /******************************************************************************
6684 * AddPortW (WINSPOOL.@)
6686 * Add a Port for a specific Monitor
6689 * pName [I] Servername or NULL (local Computer)
6690 * hWnd [I] Handle to parent Window for the Dialog-Box
6691 * pMonitorName [I] Name of the Monitor that manage the Port
6698 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6700 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6702 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6704 if (!pMonitorName
) {
6705 SetLastError(RPC_X_NULL_REF_POINTER
);
6709 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6712 /******************************************************************************
6713 * AddPortExA (WINSPOOL.@)
6718 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6721 PORT_INFO_2A
* pi2A
;
6722 LPWSTR nameW
= NULL
;
6723 LPWSTR monitorW
= NULL
;
6727 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6729 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6730 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6732 if ((level
< 1) || (level
> 2)) {
6733 SetLastError(ERROR_INVALID_LEVEL
);
6738 SetLastError(ERROR_INVALID_PARAMETER
);
6743 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6744 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6745 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6749 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6750 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6751 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6754 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6756 if (pi2A
->pPortName
) {
6757 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6758 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6759 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6763 if (pi2A
->pMonitorName
) {
6764 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6765 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6766 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6769 if (pi2A
->pDescription
) {
6770 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6771 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6772 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6774 pi2W
.fPortType
= pi2A
->fPortType
;
6775 pi2W
.Reserved
= pi2A
->Reserved
;
6778 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6780 HeapFree(GetProcessHeap(), 0, nameW
);
6781 HeapFree(GetProcessHeap(), 0, monitorW
);
6782 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6783 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6784 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6789 /******************************************************************************
6790 * AddPortExW (WINSPOOL.@)
6792 * Add a Port for a specific Monitor, without presenting a user interface
6795 * pName [I] Servername or NULL (local Computer)
6796 * level [I] Structure-Level (1 or 2) for pBuffer
6797 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6798 * pMonitorName [I] Name of the Monitor that manage the Port
6805 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6809 pi2
= (PORT_INFO_2W
*) pBuffer
;
6811 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6812 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6813 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6814 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6816 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6818 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6819 SetLastError(ERROR_INVALID_PARAMETER
);
6823 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6826 /******************************************************************************
6827 * AddPrinterConnectionA (WINSPOOL.@)
6829 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6831 FIXME("%s\n", debugstr_a(pName
));
6835 /******************************************************************************
6836 * AddPrinterConnectionW (WINSPOOL.@)
6838 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6840 FIXME("%s\n", debugstr_w(pName
));
6844 /******************************************************************************
6845 * AddPrinterDriverExW (WINSPOOL.@)
6847 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6850 * pName [I] Servername or NULL (local Computer)
6851 * level [I] Level for the supplied DRIVER_INFO_*W struct
6852 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6853 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6860 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6862 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6864 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6866 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6867 SetLastError(ERROR_INVALID_LEVEL
);
6872 SetLastError(ERROR_INVALID_PARAMETER
);
6876 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6879 /******************************************************************************
6880 * AddPrinterDriverExA (WINSPOOL.@)
6882 * See AddPrinterDriverExW.
6885 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6887 DRIVER_INFO_8A
*diA
;
6889 LPWSTR nameW
= NULL
;
6894 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6896 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6897 ZeroMemory(&diW
, sizeof(diW
));
6899 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6900 SetLastError(ERROR_INVALID_LEVEL
);
6905 SetLastError(ERROR_INVALID_PARAMETER
);
6909 /* convert servername to unicode */
6911 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6912 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6913 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6917 diW
.cVersion
= diA
->cVersion
;
6920 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6921 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6922 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6925 if (diA
->pEnvironment
) {
6926 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6927 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6928 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6931 if (diA
->pDriverPath
) {
6932 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6933 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6934 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6937 if (diA
->pDataFile
) {
6938 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6939 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6940 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6943 if (diA
->pConfigFile
) {
6944 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6945 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6946 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6949 if ((Level
> 2) && diA
->pHelpFile
) {
6950 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, NULL
, 0);
6951 diW
.pHelpFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6952 MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, diW
.pHelpFile
, len
);
6955 if ((Level
> 2) && diA
->pDependentFiles
) {
6956 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6957 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6958 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6959 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6962 if ((Level
> 2) && diA
->pMonitorName
) {
6963 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6964 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6965 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6968 if ((Level
> 2) && diA
->pDefaultDataType
) {
6969 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6970 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6971 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6974 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6975 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6976 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6977 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6978 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6982 diW
.ftDriverDate
= diA
->ftDriverDate
;
6983 diW
.dwlDriverVersion
= diA
->dwlDriverVersion
;
6986 if ((Level
> 5) && diA
->pszMfgName
) {
6987 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6988 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6989 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6992 if ((Level
> 5) && diA
->pszOEMUrl
) {
6993 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6994 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6995 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6998 if ((Level
> 5) && diA
->pszHardwareID
) {
6999 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
7000 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7001 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
7004 if ((Level
> 5) && diA
->pszProvider
) {
7005 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
7006 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7007 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
7010 if ((Level
> 7) && diA
->pszPrintProcessor
) {
7011 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, NULL
, 0);
7012 diW
.pszPrintProcessor
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7013 MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, diW
.pszPrintProcessor
, len
);
7016 if ((Level
> 7) && diA
->pszVendorSetup
) {
7017 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, NULL
, 0);
7018 diW
.pszVendorSetup
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7019 MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, diW
.pszVendorSetup
, len
);
7022 if ((Level
> 7) && diA
->pszzColorProfiles
) {
7023 lenA
= multi_sz_lenA(diA
->pszzColorProfiles
);
7024 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, NULL
, 0);
7025 diW
.pszzColorProfiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7026 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, diW
.pszzColorProfiles
, len
);
7029 if ((Level
> 7) && diA
->pszInfPath
) {
7030 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, NULL
, 0);
7031 diW
.pszInfPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7032 MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, diW
.pszInfPath
, len
);
7035 if ((Level
> 7) && diA
->pszzCoreDriverDependencies
) {
7036 lenA
= multi_sz_lenA(diA
->pszzCoreDriverDependencies
);
7037 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, NULL
, 0);
7038 diW
.pszzCoreDriverDependencies
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7039 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, diW
.pszzCoreDriverDependencies
, len
);
7043 diW
.dwPrinterDriverAttributes
= diA
->dwPrinterDriverAttributes
;
7044 diW
.ftMinInboxDriverVerDate
= diA
->ftMinInboxDriverVerDate
;
7045 diW
.dwlMinInboxDriverVerVersion
= diA
->dwlMinInboxDriverVerVersion
;
7048 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
7049 TRACE("got %u with %u\n", res
, GetLastError());
7050 HeapFree(GetProcessHeap(), 0, nameW
);
7051 HeapFree(GetProcessHeap(), 0, diW
.pName
);
7052 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
7053 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
7054 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
7055 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
7056 HeapFree(GetProcessHeap(), 0, diW
.pHelpFile
);
7057 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
7058 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
7059 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
7060 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
7061 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
7062 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
7063 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
7064 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
7065 HeapFree(GetProcessHeap(), 0, diW
.pszPrintProcessor
);
7066 HeapFree(GetProcessHeap(), 0, diW
.pszVendorSetup
);
7067 HeapFree(GetProcessHeap(), 0, diW
.pszzColorProfiles
);
7068 HeapFree(GetProcessHeap(), 0, diW
.pszInfPath
);
7069 HeapFree(GetProcessHeap(), 0, diW
.pszzCoreDriverDependencies
);
7071 TRACE("=> %u with %u\n", res
, GetLastError());
7075 /******************************************************************************
7076 * ConfigurePortA (WINSPOOL.@)
7078 * See ConfigurePortW.
7081 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
7083 LPWSTR nameW
= NULL
;
7084 LPWSTR portW
= NULL
;
7088 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
7090 /* convert servername to unicode */
7092 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7093 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7094 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7097 /* convert portname to unicode */
7099 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
7100 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7101 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
7104 res
= ConfigurePortW(nameW
, hWnd
, portW
);
7105 HeapFree(GetProcessHeap(), 0, nameW
);
7106 HeapFree(GetProcessHeap(), 0, portW
);
7110 /******************************************************************************
7111 * ConfigurePortW (WINSPOOL.@)
7113 * Display the Configuration-Dialog for a specific Port
7116 * pName [I] Servername or NULL (local Computer)
7117 * hWnd [I] Handle to parent Window for the Dialog-Box
7118 * pPortName [I] Name of the Port, that should be configured
7125 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
7128 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
7130 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7133 SetLastError(RPC_X_NULL_REF_POINTER
);
7137 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
7140 /******************************************************************************
7141 * ConnectToPrinterDlg (WINSPOOL.@)
7143 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
7145 FIXME("%p %x\n", hWnd
, Flags
);
7149 /******************************************************************************
7150 * DeletePrinterConnectionA (WINSPOOL.@)
7152 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
7154 FIXME("%s\n", debugstr_a(pName
));
7158 /******************************************************************************
7159 * DeletePrinterConnectionW (WINSPOOL.@)
7161 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
7163 FIXME("%s\n", debugstr_w(pName
));
7167 /******************************************************************************
7168 * DeletePrinterDriverExW (WINSPOOL.@)
7170 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
7171 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7176 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7177 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
7179 if(pName
&& pName
[0])
7181 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
7182 SetLastError(ERROR_INVALID_PARAMETER
);
7188 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7189 SetLastError(ERROR_INVALID_PARAMETER
);
7193 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7197 ERR("Can't open drivers key\n");
7201 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7204 RegCloseKey(hkey_drivers
);
7209 /******************************************************************************
7210 * DeletePrinterDriverExA (WINSPOOL.@)
7212 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7213 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7215 UNICODE_STRING NameW
, EnvW
, DriverW
;
7218 asciitounicode(&NameW
, pName
);
7219 asciitounicode(&EnvW
, pEnvironment
);
7220 asciitounicode(&DriverW
, pDriverName
);
7222 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7224 RtlFreeUnicodeString(&DriverW
);
7225 RtlFreeUnicodeString(&EnvW
);
7226 RtlFreeUnicodeString(&NameW
);
7231 /******************************************************************************
7232 * DeletePrinterDataExW (WINSPOOL.@)
7234 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7237 FIXME("%p %s %s\n", hPrinter
,
7238 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7239 return ERROR_INVALID_PARAMETER
;
7242 /******************************************************************************
7243 * DeletePrinterDataExA (WINSPOOL.@)
7245 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7248 FIXME("%p %s %s\n", hPrinter
,
7249 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7250 return ERROR_INVALID_PARAMETER
;
7253 /******************************************************************************
7254 * DeletePrintProcessorA (WINSPOOL.@)
7256 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7258 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7259 debugstr_a(pPrintProcessorName
));
7263 /******************************************************************************
7264 * DeletePrintProcessorW (WINSPOOL.@)
7266 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7268 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7269 debugstr_w(pPrintProcessorName
));
7273 /******************************************************************************
7274 * DeletePrintProvidorA (WINSPOOL.@)
7276 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7278 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7279 debugstr_a(pPrintProviderName
));
7283 /******************************************************************************
7284 * DeletePrintProvidorW (WINSPOOL.@)
7286 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7288 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7289 debugstr_w(pPrintProviderName
));
7293 /******************************************************************************
7294 * EnumFormsA (WINSPOOL.@)
7296 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7297 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7299 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7300 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7304 /******************************************************************************
7305 * EnumFormsW (WINSPOOL.@)
7307 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7308 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7310 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7311 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7315 /*****************************************************************************
7316 * EnumMonitorsA [WINSPOOL.@]
7318 * See EnumMonitorsW.
7321 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7322 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7325 LPBYTE bufferW
= NULL
;
7326 LPWSTR nameW
= NULL
;
7328 DWORD numentries
= 0;
7331 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7332 cbBuf
, pcbNeeded
, pcReturned
);
7334 /* convert servername to unicode */
7336 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7337 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7338 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7340 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7341 needed
= cbBuf
* sizeof(WCHAR
);
7342 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7343 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7345 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7346 if (pcbNeeded
) needed
= *pcbNeeded
;
7347 /* HeapReAlloc return NULL, when bufferW was NULL */
7348 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7349 HeapAlloc(GetProcessHeap(), 0, needed
);
7351 /* Try again with the large Buffer */
7352 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7354 numentries
= pcReturned
? *pcReturned
: 0;
7357 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7358 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7361 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7362 DWORD entrysize
= 0;
7365 LPMONITOR_INFO_2W mi2w
;
7366 LPMONITOR_INFO_2A mi2a
;
7368 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7369 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7371 /* First pass: calculate the size for all Entries */
7372 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7373 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7375 while (index
< numentries
) {
7377 needed
+= entrysize
; /* MONITOR_INFO_?A */
7378 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7380 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7381 NULL
, 0, NULL
, NULL
);
7383 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7384 NULL
, 0, NULL
, NULL
);
7385 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7386 NULL
, 0, NULL
, NULL
);
7388 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7389 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7390 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7393 /* check for errors and quit on failure */
7394 if (cbBuf
< needed
) {
7395 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7399 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7400 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7401 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7402 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7403 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7405 /* Second Pass: Fill the User Buffer (if we have one) */
7406 while ((index
< numentries
) && pMonitors
) {
7408 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7410 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7411 ptr
, cbBuf
, NULL
, NULL
);
7415 mi2a
->pEnvironment
= ptr
;
7416 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7417 ptr
, cbBuf
, NULL
, NULL
);
7421 mi2a
->pDLLName
= ptr
;
7422 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7423 ptr
, cbBuf
, NULL
, NULL
);
7427 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7428 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7429 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7433 if (pcbNeeded
) *pcbNeeded
= needed
;
7434 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7436 HeapFree(GetProcessHeap(), 0, nameW
);
7437 HeapFree(GetProcessHeap(), 0, bufferW
);
7439 TRACE("returning %d with %d (%d byte for %d entries)\n",
7440 (res
), GetLastError(), needed
, numentries
);
7446 /*****************************************************************************
7447 * EnumMonitorsW [WINSPOOL.@]
7449 * Enumerate available Port-Monitors
7452 * pName [I] Servername or NULL (local Computer)
7453 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7454 * pMonitors [O] PTR to Buffer that receives the Result
7455 * cbBuf [I] Size of Buffer at pMonitors
7456 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7457 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7461 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7464 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7465 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7468 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7469 cbBuf
, pcbNeeded
, pcReturned
);
7471 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7473 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7474 SetLastError(RPC_X_NULL_REF_POINTER
);
7478 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7481 /******************************************************************************
7482 * SpoolerInit (WINSPOOL.@)
7484 * Initialize the Spooler
7491 * The function fails on windows, when the spooler service is not running
7494 BOOL WINAPI
SpoolerInit(void)
7497 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7501 /******************************************************************************
7502 * XcvDataW (WINSPOOL.@)
7504 * Execute commands in the Printmonitor DLL
7507 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7508 * pszDataName [i] Name of the command to execute
7509 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7510 * cbInputData [i] Size in Bytes of Buffer at pInputData
7511 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7512 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7513 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7514 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7521 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7522 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7524 * Minimal List of commands, that a Printmonitor DLL should support:
7526 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7527 *| "AddPort" : Add a Port
7528 *| "DeletePort": Delete a Port
7530 * Many Printmonitors support additional commands. Examples for localspl.dll:
7531 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7532 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7535 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7536 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7537 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7539 opened_printer_t
*printer
;
7541 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7542 pInputData
, cbInputData
, pOutputData
,
7543 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7545 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7547 printer
= get_opened_printer(hXcv
);
7548 if (!printer
|| (!printer
->backend_printer
)) {
7549 SetLastError(ERROR_INVALID_HANDLE
);
7553 if (!pcbOutputNeeded
) {
7554 SetLastError(ERROR_INVALID_PARAMETER
);
7558 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7559 SetLastError(RPC_X_NULL_REF_POINTER
);
7563 *pcbOutputNeeded
= 0;
7565 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7566 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7570 /*****************************************************************************
7571 * EnumPrinterDataA [WINSPOOL.@]
7574 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7575 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7576 DWORD cbData
, LPDWORD pcbData
)
7578 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7579 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7580 return ERROR_NO_MORE_ITEMS
;
7583 /*****************************************************************************
7584 * EnumPrinterDataW [WINSPOOL.@]
7587 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7588 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7589 DWORD cbData
, LPDWORD pcbData
)
7591 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7592 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7593 return ERROR_NO_MORE_ITEMS
;
7596 /*****************************************************************************
7597 * EnumPrinterKeyA [WINSPOOL.@]
7600 DWORD WINAPI
EnumPrinterKeyA(HANDLE printer
, const CHAR
*key
, CHAR
*subkey
, DWORD size
, DWORD
*needed
)
7602 FIXME("%p %s %p %x %p\n", printer
, debugstr_a(key
), subkey
, size
, needed
);
7603 return ERROR_CALL_NOT_IMPLEMENTED
;
7606 /*****************************************************************************
7607 * EnumPrinterKeyW [WINSPOOL.@]
7610 DWORD WINAPI
EnumPrinterKeyW(HANDLE printer
, const WCHAR
*key
, WCHAR
*subkey
, DWORD size
, DWORD
*needed
)
7612 FIXME("%p %s %p %x %p\n", printer
, debugstr_w(key
), subkey
, size
, needed
);
7613 return ERROR_CALL_NOT_IMPLEMENTED
;
7616 /*****************************************************************************
7617 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7620 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7621 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7622 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7624 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7625 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7626 pcbNeeded
, pcReturned
);
7630 /*****************************************************************************
7631 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7634 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7635 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7636 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7638 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7639 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7640 pcbNeeded
, pcReturned
);
7644 /*****************************************************************************
7645 * EnumPrintProcessorsA [WINSPOOL.@]
7647 * See EnumPrintProcessorsW.
7650 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7651 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7654 LPBYTE bufferW
= NULL
;
7655 LPWSTR nameW
= NULL
;
7658 DWORD numentries
= 0;
7661 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7662 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7664 /* convert names to unicode */
7666 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7667 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7668 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7671 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7672 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7673 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7676 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7677 needed
= cbBuf
* sizeof(WCHAR
);
7678 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7679 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7681 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7682 if (pcbNeeded
) needed
= *pcbNeeded
;
7683 /* HeapReAlloc return NULL, when bufferW was NULL */
7684 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7685 HeapAlloc(GetProcessHeap(), 0, needed
);
7687 /* Try again with the large Buffer */
7688 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7690 numentries
= pcReturned
? *pcReturned
: 0;
7694 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7697 PPRINTPROCESSOR_INFO_1W ppiw
;
7698 PPRINTPROCESSOR_INFO_1A ppia
;
7700 /* First pass: calculate the size for all Entries */
7701 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7702 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7704 while (index
< numentries
) {
7706 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7707 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7709 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7710 NULL
, 0, NULL
, NULL
);
7712 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7713 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7716 /* check for errors and quit on failure */
7717 if (cbBuf
< needed
) {
7718 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7723 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7724 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7725 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7726 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7727 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7729 /* Second Pass: Fill the User Buffer (if we have one) */
7730 while ((index
< numentries
) && pPPInfo
) {
7732 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7734 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7735 ptr
, cbBuf
, NULL
, NULL
);
7739 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7740 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7745 if (pcbNeeded
) *pcbNeeded
= needed
;
7746 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7748 HeapFree(GetProcessHeap(), 0, nameW
);
7749 HeapFree(GetProcessHeap(), 0, envW
);
7750 HeapFree(GetProcessHeap(), 0, bufferW
);
7752 TRACE("returning %d with %d (%d byte for %d entries)\n",
7753 (res
), GetLastError(), needed
, numentries
);
7758 /*****************************************************************************
7759 * EnumPrintProcessorsW [WINSPOOL.@]
7761 * Enumerate available Print Processors
7764 * pName [I] Servername or NULL (local Computer)
7765 * pEnvironment [I] Printing-Environment or NULL (Default)
7766 * Level [I] Structure-Level (Only 1 is allowed)
7767 * pPPInfo [O] PTR to Buffer that receives the Result
7768 * cbBuf [I] Size of Buffer at pPPInfo
7769 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7770 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7774 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7777 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7778 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7781 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7782 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7784 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7786 if (!pcbNeeded
|| !pcReturned
) {
7787 SetLastError(RPC_X_NULL_REF_POINTER
);
7791 if (!pPPInfo
&& (cbBuf
> 0)) {
7792 SetLastError(ERROR_INVALID_USER_BUFFER
);
7796 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7797 cbBuf
, pcbNeeded
, pcReturned
);
7800 /*****************************************************************************
7801 * ExtDeviceMode [WINSPOOL.@]
7804 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7805 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7808 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7809 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7810 debugstr_a(pProfile
), fMode
);
7814 /*****************************************************************************
7815 * FindClosePrinterChangeNotification [WINSPOOL.@]
7818 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7820 FIXME("Stub: %p\n", hChange
);
7824 /*****************************************************************************
7825 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7828 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7829 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7831 FIXME("Stub: %p %x %x %p\n",
7832 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7833 return INVALID_HANDLE_VALUE
;
7836 /*****************************************************************************
7837 * FindNextPrinterChangeNotification [WINSPOOL.@]
7840 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7841 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7843 FIXME("Stub: %p %p %p %p\n",
7844 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7848 /*****************************************************************************
7849 * FreePrinterNotifyInfo [WINSPOOL.@]
7852 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7854 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7858 /*****************************************************************************
7861 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7862 * ansi depending on the unicode parameter.
7864 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7874 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7877 memcpy(ptr
, str
, *size
);
7884 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7887 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7894 /*****************************************************************************
7897 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7898 LPDWORD pcbNeeded
, BOOL unicode
)
7900 DWORD size
, left
= cbBuf
;
7901 BOOL space
= (cbBuf
> 0);
7908 ji1
->JobId
= job
->job_id
;
7911 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7912 if(space
&& size
<= left
)
7914 ji1
->pDocument
= (LPWSTR
)ptr
;
7922 if (job
->printer_name
)
7924 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7925 if(space
&& size
<= left
)
7927 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7939 /*****************************************************************************
7942 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7943 LPDWORD pcbNeeded
, BOOL unicode
)
7945 DWORD size
, left
= cbBuf
;
7947 BOOL space
= (cbBuf
> 0);
7949 LPDEVMODEA dmA
= NULL
;
7956 ji2
->JobId
= job
->job_id
;
7959 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7960 if(space
&& size
<= left
)
7962 ji2
->pDocument
= (LPWSTR
)ptr
;
7970 if (job
->printer_name
)
7972 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7973 if(space
&& size
<= left
)
7975 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7988 dmA
= DEVMODEdupWtoA(job
->devmode
);
7989 devmode
= (LPDEVMODEW
) dmA
;
7990 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7994 devmode
= job
->devmode
;
7995 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7999 FIXME("Can't convert DEVMODE W to A\n");
8002 /* align DEVMODE to a DWORD boundary */
8003 shift
= (4 - (*pcbNeeded
& 3)) & 3;
8009 memcpy(ptr
, devmode
, size
-shift
);
8010 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
8011 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
8024 /*****************************************************************************
8027 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8028 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
8031 DWORD needed
= 0, size
;
8035 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
8037 EnterCriticalSection(&printer_handles_cs
);
8038 job
= get_job(hPrinter
, JobId
);
8045 size
= sizeof(JOB_INFO_1W
);
8050 memset(pJob
, 0, size
);
8054 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8059 size
= sizeof(JOB_INFO_2W
);
8064 memset(pJob
, 0, size
);
8068 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8073 size
= sizeof(JOB_INFO_3
);
8077 memset(pJob
, 0, size
);
8086 SetLastError(ERROR_INVALID_LEVEL
);
8090 *pcbNeeded
= needed
;
8092 LeaveCriticalSection(&printer_handles_cs
);
8096 /*****************************************************************************
8097 * GetJobA [WINSPOOL.@]
8100 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8101 DWORD cbBuf
, LPDWORD pcbNeeded
)
8103 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
8106 /*****************************************************************************
8107 * GetJobW [WINSPOOL.@]
8110 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8111 DWORD cbBuf
, LPDWORD pcbNeeded
)
8113 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
8116 /*****************************************************************************
8119 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
8122 char *unixname
, *cmdA
;
8124 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
8130 if(!(unixname
= wine_get_unix_file_name(filename
)))
8133 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
8134 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
8135 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
8137 TRACE("printing with: %s\n", cmdA
);
8139 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
8144 ERR("pipe() failed!\n");
8148 if ((pid
= fork()) == 0)
8154 /* reset signals that we previously set to SIG_IGN */
8155 signal(SIGPIPE
, SIG_DFL
);
8157 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
8162 ERR("fork() failed!\n");
8168 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
8169 write(fds
[1], buf
, no_read
);
8176 wret
= waitpid(pid
, &status
, 0);
8177 } while (wret
< 0 && errno
== EINTR
);
8180 ERR("waitpid() failed!\n");
8183 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
8185 ERR("child process failed! %d\n", status
);
8192 if(file_fd
!= -1) close(file_fd
);
8193 if(fds
[0] != -1) close(fds
[0]);
8194 if(fds
[1] != -1) close(fds
[1]);
8196 HeapFree(GetProcessHeap(), 0, cmdA
);
8197 HeapFree(GetProcessHeap(), 0, unixname
);
8204 /*****************************************************************************
8207 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8210 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8213 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8214 sprintfW(cmd
, fmtW
, printer_name
);
8216 r
= schedule_pipe(cmd
, filename
);
8218 HeapFree(GetProcessHeap(), 0, cmd
);
8222 #ifdef SONAME_LIBCUPS
8223 /*****************************************************************************
8224 * get_cups_jobs_ticket_options
8226 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8227 * The CUPS scheduler only looks for these in Print-File requests, and since
8228 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8231 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8233 FILE *fp
= fopen( file
, "r" );
8234 char buf
[257]; /* DSC max of 256 + '\0' */
8235 const char *ps_adobe
= "%!PS-Adobe-";
8236 const char *cups_job
= "%cupsJobTicket:";
8238 if (!fp
) return num_options
;
8239 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8240 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8241 while (fgets( buf
, sizeof(buf
), fp
))
8243 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8244 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8252 static int get_cups_default_options( const char *printer
, int num_options
, cups_option_t
**options
)
8257 if (!pcupsGetNamedDest
) return num_options
;
8259 dest
= pcupsGetNamedDest( NULL
, printer
, NULL
);
8260 if (!dest
) return num_options
;
8262 for (i
= 0; i
< dest
->num_options
; i
++)
8264 if (!pcupsGetOption( dest
->options
[i
].name
, num_options
, *options
))
8265 num_options
= pcupsAddOption( dest
->options
[i
].name
, dest
->options
[i
].value
,
8266 num_options
, options
);
8269 pcupsFreeDests( 1, dest
);
8274 /*****************************************************************************
8277 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8279 #ifdef SONAME_LIBCUPS
8282 char *unixname
, *queue
, *unix_doc_title
;
8285 int num_options
= 0, i
;
8286 cups_option_t
*options
= NULL
;
8288 if(!(unixname
= wine_get_unix_file_name(filename
)))
8291 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8292 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8293 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8295 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8296 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8297 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8299 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8300 num_options
= get_cups_default_options( queue
, num_options
, &options
);
8302 TRACE( "printing via cups with options:\n" );
8303 for (i
= 0; i
< num_options
; i
++)
8304 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8306 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8307 if (ret
== 0 && pcupsLastErrorString
)
8308 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8310 pcupsFreeOptions( num_options
, options
);
8312 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8313 HeapFree(GetProcessHeap(), 0, queue
);
8314 HeapFree(GetProcessHeap(), 0, unixname
);
8320 return schedule_lpr(printer_name
, filename
);
8324 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8331 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8335 if(HIWORD(wparam
) == BN_CLICKED
)
8337 if(LOWORD(wparam
) == IDOK
)
8340 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8343 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8344 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8346 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8348 WCHAR caption
[200], message
[200];
8351 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
8352 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, ARRAY_SIZE(message
));
8353 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8354 if(mb_ret
== IDCANCEL
)
8356 HeapFree(GetProcessHeap(), 0, filename
);
8360 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8361 if(hf
== INVALID_HANDLE_VALUE
)
8363 WCHAR caption
[200], message
[200];
8365 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
8366 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, ARRAY_SIZE(message
));
8367 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8368 HeapFree(GetProcessHeap(), 0, filename
);
8372 DeleteFileW(filename
);
8373 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8375 EndDialog(hwnd
, IDOK
);
8378 if(LOWORD(wparam
) == IDCANCEL
)
8380 EndDialog(hwnd
, IDCANCEL
);
8389 /*****************************************************************************
8392 static BOOL
get_filename(LPWSTR
*filename
)
8394 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8395 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8398 /*****************************************************************************
8401 static BOOL
schedule_file(LPCWSTR filename
)
8403 LPWSTR output
= NULL
;
8405 if(get_filename(&output
))
8408 TRACE("copy to %s\n", debugstr_w(output
));
8409 r
= CopyFileW(filename
, output
, FALSE
);
8410 HeapFree(GetProcessHeap(), 0, output
);
8416 /*****************************************************************************
8419 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8421 int in_fd
, out_fd
, no_read
;
8424 char *unixname
, *outputA
;
8427 if(!(unixname
= wine_get_unix_file_name(filename
)))
8430 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8431 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8432 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8434 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8435 in_fd
= open(unixname
, O_RDONLY
);
8436 if(out_fd
== -1 || in_fd
== -1)
8439 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8440 write(out_fd
, buf
, no_read
);
8444 if(in_fd
!= -1) close(in_fd
);
8445 if(out_fd
!= -1) close(out_fd
);
8446 HeapFree(GetProcessHeap(), 0, outputA
);
8447 HeapFree(GetProcessHeap(), 0, unixname
);
8451 /*****************************************************************************
8452 * ScheduleJob [WINSPOOL.@]
8455 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8457 opened_printer_t
*printer
;
8459 struct list
*cursor
, *cursor2
;
8461 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8462 EnterCriticalSection(&printer_handles_cs
);
8463 printer
= get_opened_printer(hPrinter
);
8467 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8469 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8472 if(job
->job_id
!= dwJobID
) continue;
8474 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8475 if(hf
!= INVALID_HANDLE_VALUE
)
8477 PRINTER_INFO_5W
*pi5
= NULL
;
8478 LPWSTR portname
= job
->portname
;
8482 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8483 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8487 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8488 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8489 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8490 portname
= pi5
->pPortName
;
8492 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8493 debugstr_w(portname
));
8497 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8498 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8500 DWORD type
, count
= sizeof(output
);
8501 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8504 if(output
[0] == '|')
8506 ret
= schedule_pipe(output
+ 1, job
->filename
);
8510 ret
= schedule_unixfile(output
, job
->filename
);
8512 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8514 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8516 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8518 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8520 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8522 ret
= schedule_file(job
->filename
);
8524 else if(isalpha(portname
[0]) && portname
[1] == ':')
8526 TRACE("copying to %s\n", debugstr_w(portname
));
8527 ret
= CopyFileW(job
->filename
, portname
, FALSE
);
8531 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8533 HeapFree(GetProcessHeap(), 0, pi5
);
8535 DeleteFileW(job
->filename
);
8537 list_remove(cursor
);
8538 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8539 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8540 HeapFree(GetProcessHeap(), 0, job
->portname
);
8541 HeapFree(GetProcessHeap(), 0, job
->filename
);
8542 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8543 HeapFree(GetProcessHeap(), 0, job
);
8547 LeaveCriticalSection(&printer_handles_cs
);
8551 /*****************************************************************************
8552 * StartDocDlgA [WINSPOOL.@]
8554 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8556 UNICODE_STRING usBuffer
;
8557 DOCINFOW docW
= { 0 };
8559 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8562 docW
.cbSize
= sizeof(docW
);
8563 if (doc
->lpszDocName
)
8565 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8566 if (!(docW
.lpszDocName
= docnameW
)) goto failed
;
8568 if (doc
->lpszOutput
)
8570 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8571 if (!(docW
.lpszOutput
= outputW
)) goto failed
;
8573 if (doc
->lpszDatatype
)
8575 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8576 if (!(docW
.lpszDatatype
= datatypeW
)) goto failed
;
8578 docW
.fwType
= doc
->fwType
;
8580 retW
= StartDocDlgW(hPrinter
, &docW
);
8584 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8585 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8586 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8587 HeapFree(GetProcessHeap(), 0, retW
);
8591 HeapFree(GetProcessHeap(), 0, datatypeW
);
8592 HeapFree(GetProcessHeap(), 0, outputW
);
8593 HeapFree(GetProcessHeap(), 0, docnameW
);
8598 /*****************************************************************************
8599 * StartDocDlgW [WINSPOOL.@]
8601 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8602 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8603 * port is "FILE:". Also returns the full path if passed a relative path.
8605 * The caller should free the returned string from the process heap.
8607 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8612 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8614 PRINTER_INFO_5W
*pi5
;
8615 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8616 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8618 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8619 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8620 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8622 HeapFree(GetProcessHeap(), 0, pi5
);
8625 HeapFree(GetProcessHeap(), 0, pi5
);
8628 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8632 if (get_filename(&name
))
8634 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8636 HeapFree(GetProcessHeap(), 0, name
);
8639 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8640 GetFullPathNameW(name
, len
, ret
, NULL
);
8641 HeapFree(GetProcessHeap(), 0, name
);
8646 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8649 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8650 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8652 attr
= GetFileAttributesW(ret
);
8653 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8655 HeapFree(GetProcessHeap(), 0, ret
);
8661 /*****************************************************************************
8662 * UploadPrinterDriverPackageA [WINSPOOL.@]
8664 HRESULT WINAPI
UploadPrinterDriverPackageA( LPCSTR server
, LPCSTR path
, LPCSTR env
,
8665 DWORD flags
, HWND hwnd
, LPSTR dst
, PULONG dstlen
)
8667 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server
), debugstr_a(path
), debugstr_a(env
),
8668 flags
, hwnd
, dst
, dstlen
);
8672 /*****************************************************************************
8673 * UploadPrinterDriverPackageW [WINSPOOL.@]
8675 HRESULT WINAPI
UploadPrinterDriverPackageW( LPCWSTR server
, LPCWSTR path
, LPCWSTR env
,
8676 DWORD flags
, HWND hwnd
, LPWSTR dst
, PULONG dstlen
)
8678 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server
), debugstr_w(path
), debugstr_w(env
),
8679 flags
, hwnd
, dst
, dstlen
);
8683 /*****************************************************************************
8684 * PerfOpen [WINSPOOL.@]
8686 DWORD WINAPI
PerfOpen(LPWSTR context
)
8688 FIXME("%s: stub\n", debugstr_w(context
));
8689 return ERROR_SUCCESS
;
8692 /*****************************************************************************
8693 * PerfClose [WINSPOOL.@]
8695 DWORD WINAPI
PerfClose(void)
8698 return ERROR_SUCCESS
;
8701 /*****************************************************************************
8702 * PerfCollect [WINSPOOL.@]
8704 DWORD WINAPI
PerfCollect(LPWSTR query
, LPVOID
*data
, LPDWORD size
, LPDWORD obj_count
)
8706 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query
), data
, size
, obj_count
);
8709 return ERROR_SUCCESS
;