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>
48 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
49 #define GetCurrentProcess GetCurrentProcess_Mac
50 #define GetCurrentThread GetCurrentThread_Mac
51 #define LoadResource LoadResource_Mac
52 #define AnimatePalette AnimatePalette_Mac
53 #define EqualRgn EqualRgn_Mac
54 #define FillRgn FillRgn_Mac
55 #define FrameRgn FrameRgn_Mac
56 #define GetPixel GetPixel_Mac
57 #define InvertRgn InvertRgn_Mac
58 #define LineTo LineTo_Mac
59 #define OffsetRgn OffsetRgn_Mac
60 #define PaintRgn PaintRgn_Mac
61 #define Polygon Polygon_Mac
62 #define ResizePalette ResizePalette_Mac
63 #define SetRectRgn SetRectRgn_Mac
64 #define EqualRect EqualRect_Mac
65 #define FillRect FillRect_Mac
66 #define FrameRect FrameRect_Mac
67 #define GetCursor GetCursor_Mac
68 #define InvertRect InvertRect_Mac
69 #define OffsetRect OffsetRect_Mac
70 #define PtInRect PtInRect_Mac
71 #define SetCursor SetCursor_Mac
72 #define SetRect SetRect_Mac
73 #define ShowCursor ShowCursor_Mac
74 #define UnionRect UnionRect_Mac
75 #include <ApplicationServices/ApplicationServices.h>
76 #undef GetCurrentProcess
77 #undef GetCurrentThread
105 #define NONAMELESSUNION
106 #define NONAMELESSSTRUCT
107 #include "wine/library.h"
111 #include "winerror.h"
114 #include "winspool.h"
115 #include "winternl.h"
116 #include "wine/windef16.h"
117 #include "wine/unicode.h"
118 #include "wine/debug.h"
119 #include "wine/list.h"
122 #include "ddk/winsplp.h"
125 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
127 /* ############################### */
129 static CRITICAL_SECTION printer_handles_cs
;
130 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
132 0, 0, &printer_handles_cs
,
133 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
134 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
136 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
138 /* ############################### */
153 HANDLE backend_printer
;
164 WCHAR
*document_title
;
174 LPCWSTR versionregpath
;
175 LPCWSTR versionsubdir
;
178 /* ############################### */
180 static opened_printer_t
**printer_handles
;
181 static UINT nb_printer_handles
;
182 static LONG next_job_id
= 1;
184 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
185 WORD fwCapability
, LPSTR lpszOutput
,
187 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
188 LPSTR lpszDevice
, LPSTR lpszPort
,
189 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
192 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
193 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
194 'c','o','n','t','r','o','l','\\',
195 'P','r','i','n','t','\\',
196 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
197 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
199 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
200 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
201 'C','o','n','t','r','o','l','\\',
202 'P','r','i','n','t','\\',
203 'P','r','i','n','t','e','r','s',0};
205 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
206 'M','i','c','r','o','s','o','f','t','\\',
207 'W','i','n','d','o','w','s',' ','N','T','\\',
208 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
209 'W','i','n','d','o','w','s',0};
211 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
212 'M','i','c','r','o','s','o','f','t','\\',
213 'W','i','n','d','o','w','s',' ','N','T','\\',
214 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
215 'D','e','v','i','c','e','s',0};
217 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
218 'M','i','c','r','o','s','o','f','t','\\',
219 'W','i','n','d','o','w','s',' ','N','T','\\',
220 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
221 'P','r','i','n','t','e','r','P','o','r','t','s',0};
223 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
224 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
225 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
226 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
227 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
228 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
229 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
230 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
231 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
232 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
234 static const WCHAR AttributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0};
235 static const WCHAR backslashW
[] = {'\\',0};
236 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
237 'i','o','n',' ','F','i','l','e',0};
238 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
239 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
240 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
241 static const WCHAR Default_PriorityW
[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
242 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
243 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
244 static const WCHAR dnsTimeoutW
[] = {'d','n','s','T','i','m','e','o','u','t',0};
245 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
246 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
247 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
248 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
249 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
250 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
251 static const WCHAR NameW
[] = {'N','a','m','e',0};
252 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
253 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
254 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
255 static const WCHAR PortW
[] = {'P','o','r','t',0};
256 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
257 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
258 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
259 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
260 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
261 static const WCHAR PriorityW
[] = {'P','r','i','o','r','i','t','y',0};
262 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
263 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
264 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
265 static const WCHAR StartTimeW
[] = {'S','t','a','r','t','T','i','m','e',0};
266 static const WCHAR StatusW
[] = {'S','t','a','t','u','s',0};
267 static const WCHAR txTimeoutW
[] = {'t','x','T','i','m','e','o','u','t',0};
268 static const WCHAR UntilTimeW
[] = {'U','n','t','i','l','T','i','m','e',0};
269 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
270 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
271 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
272 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
273 static WCHAR rawW
[] = {'R','A','W',0};
274 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
275 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
276 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
277 static const WCHAR commaW
[] = {',',0};
278 static WCHAR emptyStringW
[] = {0};
280 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
282 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
283 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
284 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
286 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
287 'D','o','c','u','m','e','n','t',0};
289 static const WCHAR PPD_Overrides
[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
290 static const WCHAR DefaultPageSize
[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
292 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
293 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
294 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
295 0, sizeof(DRIVER_INFO_8W
)};
298 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
299 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
300 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
301 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
302 sizeof(PRINTER_INFO_9W
)};
304 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
305 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
306 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
308 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
310 /******************************************************************
311 * validate the user-supplied printing-environment [internal]
314 * env [I] PTR to Environment-String or NULL
318 * Success: PTR to printenv_t
321 * An empty string is handled the same way as NULL.
322 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
326 static const printenv_t
* validate_envW(LPCWSTR env
)
328 const printenv_t
*result
= NULL
;
331 TRACE("testing %s\n", debugstr_w(env
));
334 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
336 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
338 result
= all_printenv
[i
];
343 if (result
== NULL
) {
344 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
345 SetLastError(ERROR_INVALID_ENVIRONMENT
);
347 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
351 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
353 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
359 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
360 if passed a NULL string. This returns NULLs to the result.
362 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
366 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
367 return usBufferPtr
->Buffer
;
369 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
373 static LPWSTR
strdupW(LPCWSTR p
)
379 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
380 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
385 static LPSTR
strdupWtoA( LPCWSTR str
)
390 if (!str
) return NULL
;
391 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
392 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
393 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
397 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
401 if (!dm
) return NULL
;
402 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
403 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
407 /***********************************************************
409 * Creates an ansi copy of supplied devmode
411 static DEVMODEA
*DEVMODEdupWtoA( const DEVMODEW
*dmW
)
416 if (!dmW
) return NULL
;
417 size
= dmW
->dmSize
- CCHDEVICENAME
-
418 ((dmW
->dmSize
> FIELD_OFFSET( DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
420 dmA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
421 if (!dmA
) return NULL
;
423 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmDeviceName
, -1,
424 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
426 if (FIELD_OFFSET( DEVMODEW
, dmFormName
) >= dmW
->dmSize
)
428 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
429 dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
433 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
434 FIELD_OFFSET( DEVMODEW
, dmFormName
) - FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
435 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmFormName
, -1,
436 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
438 memcpy( &dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmLogPixels
) );
442 memcpy( (char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
447 /******************************************************************
448 * verify, that the filename is a local file
451 static inline BOOL
is_local_file(LPWSTR name
)
453 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
456 /* ################################ */
458 static int multi_sz_lenA(const char *str
)
460 const char *ptr
= str
;
464 ptr
+= lstrlenA(ptr
) + 1;
467 return ptr
- str
+ 1;
470 /*****************************************************************************
473 * Return DWORD associated with name from hkey.
475 static DWORD
get_dword_from_reg( HKEY hkey
, const WCHAR
*name
)
477 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
480 ret
= RegQueryValueExW( hkey
, name
, 0, &type
, (LPBYTE
)&value
, &sz
);
482 if (ret
!= ERROR_SUCCESS
)
484 WARN( "Got ret = %d on name %s\n", ret
, debugstr_w(name
) );
487 if (type
!= REG_DWORD
)
489 ERR( "Got type %d\n", type
);
495 static inline DWORD
set_reg_DWORD( HKEY hkey
, const WCHAR
*keyname
, const DWORD value
)
497 return RegSetValueExW( hkey
, keyname
, 0, REG_DWORD
, (const BYTE
*)&value
, sizeof(value
) );
500 /******************************************************************
502 * Get the pointer to the opened printer referred by the handle
504 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
506 UINT_PTR idx
= (UINT_PTR
)hprn
;
507 opened_printer_t
*ret
= NULL
;
509 EnterCriticalSection(&printer_handles_cs
);
511 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
512 ret
= printer_handles
[idx
- 1];
514 LeaveCriticalSection(&printer_handles_cs
);
518 /******************************************************************
519 * get_opened_printer_name
520 * Get the pointer to the opened printer name referred by the handle
522 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
524 opened_printer_t
*printer
= get_opened_printer(hprn
);
525 if(!printer
) return NULL
;
526 return printer
->name
;
529 static DWORD
open_printer_reg_key( const WCHAR
*name
, HKEY
*key
)
535 err
= RegCreateKeyW( HKEY_LOCAL_MACHINE
, PrintersW
, &printers
);
538 err
= RegOpenKeyW( printers
, name
, key
);
539 if (err
) err
= ERROR_INVALID_PRINTER_NAME
;
540 RegCloseKey( printers
);
544 /******************************************************************
545 * WINSPOOL_GetOpenedPrinterRegKey
548 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
550 LPCWSTR name
= get_opened_printer_name(hPrinter
);
552 if(!name
) return ERROR_INVALID_HANDLE
;
553 return open_printer_reg_key( name
, phkey
);
557 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
560 /* If forcing, or no profile string entry for device yet, set the entry
562 * The always change entry if not WINEPS yet is discussable.
565 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
567 !strstr(qbuf
,"WINEPS.DRV")
569 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
572 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
573 WriteProfileStringA("windows","device",buf
);
574 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
575 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
578 HeapFree(GetProcessHeap(),0,buf
);
582 static BOOL
add_printer_driver(const WCHAR
*name
, WCHAR
*ppd
)
586 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
588 di3
.pName
= (WCHAR
*)name
;
589 di3
.pEnvironment
= envname_x86W
;
590 di3
.pDriverPath
= driver_nt
;
592 di3
.pConfigFile
= driver_nt
;
593 di3
.pDefaultDataType
= rawW
;
595 if (AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
) ||
596 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
599 di3
.pEnvironment
= envname_win40W
;
600 di3
.pDriverPath
= driver_9x
;
601 di3
.pConfigFile
= driver_9x
;
602 if (AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
) ||
603 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
608 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3
.pDriverPath
), debugstr_w(di3
.pEnvironment
));
612 static inline char *expand_env_string( char *str
, DWORD type
)
614 if (type
== REG_EXPAND_SZ
)
617 DWORD needed
= ExpandEnvironmentStringsA( str
, NULL
, 0 );
618 tmp
= HeapAlloc( GetProcessHeap(), 0, needed
);
621 ExpandEnvironmentStringsA( str
, tmp
, needed
);
622 HeapFree( GetProcessHeap(), 0, str
);
629 static char *get_fallback_ppd_name( const char *printer_name
)
631 static const WCHAR ppds_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
632 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
637 if (RegOpenKeyW( HKEY_CURRENT_USER
, ppds_key
, &hkey
) == ERROR_SUCCESS
)
639 const char *value_name
= NULL
;
641 if (RegQueryValueExA( hkey
, printer_name
, 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
642 value_name
= printer_name
;
643 else if (RegQueryValueExA( hkey
, "generic", 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
644 value_name
= "generic";
648 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
649 if (!ret
) return NULL
;
650 RegQueryValueExA( hkey
, value_name
, 0, &type
, (BYTE
*)ret
, &needed
);
653 if (ret
) return expand_env_string( ret
, type
);
658 static BOOL
copy_file( const char *src
, const char *dst
)
660 int fds
[2] = {-1, -1}, num
;
664 fds
[0] = open( src
, O_RDONLY
);
665 fds
[1] = open( dst
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666 );
666 if (fds
[0] == -1 || fds
[1] == -1) goto fail
;
668 while ((num
= read( fds
[0], buf
, sizeof(buf
) )) != 0)
670 if (num
== -1) goto fail
;
671 if (write( fds
[1], buf
, num
) != num
) goto fail
;
676 if (fds
[1] != -1) close( fds
[1] );
677 if (fds
[0] != -1) close( fds
[0] );
681 static BOOL
get_internal_fallback_ppd( const WCHAR
*ppd
)
683 static const WCHAR typeW
[] = {'P','P','D','F','I','L','E',0};
689 HRSRC res
= FindResourceW( WINSPOOL_hInstance
, MAKEINTRESOURCEW(1), typeW
);
691 if (!res
|| !(ptr
= LoadResource( WINSPOOL_hInstance
, res
))) return FALSE
;
692 size
= SizeofResource( WINSPOOL_hInstance
, res
);
693 end
= memchr( ptr
, 0, size
); /* resource file may contain additional nulls */
694 if (end
) size
= end
- ptr
;
695 file
= CreateFileW( ppd
, GENERIC_WRITE
, FILE_SHARE_READ
, NULL
, CREATE_ALWAYS
, 0, 0 );
696 if (file
== INVALID_HANDLE_VALUE
) return FALSE
;
697 ret
= WriteFile( file
, ptr
, size
, &written
, NULL
) && written
== size
;
699 if (ret
) TRACE( "using internal fallback for %s\n", debugstr_w( ppd
));
700 else DeleteFileW( ppd
);
704 static BOOL
get_fallback_ppd( const char *printer_name
, const WCHAR
*ppd
)
706 char *dst
, *src
= get_fallback_ppd_name( printer_name
);
709 if (!src
) return get_internal_fallback_ppd( ppd
);
711 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name
), debugstr_w(ppd
), debugstr_a(src
) );
713 if (!(dst
= wine_get_unix_file_name( ppd
))) goto fail
;
715 if (symlink( src
, dst
) == -1)
716 if (errno
!= ENOSYS
|| !copy_file( src
, dst
))
721 HeapFree( GetProcessHeap(), 0, dst
);
722 HeapFree( GetProcessHeap(), 0, src
);
726 static WCHAR
*get_ppd_filename( const WCHAR
*dir
, const WCHAR
*file_name
)
728 static const WCHAR dot_ppd
[] = {'.','p','p','d',0};
729 int len
= (strlenW( dir
) + strlenW( file_name
)) * sizeof(WCHAR
) + sizeof(dot_ppd
);
730 WCHAR
*ppd
= HeapAlloc( GetProcessHeap(), 0, len
);
732 if (!ppd
) return NULL
;
734 strcatW( ppd
, file_name
);
735 strcatW( ppd
, dot_ppd
);
740 static WCHAR
*get_ppd_dir( void )
742 static const WCHAR wine_ppds
[] = {'w','i','n','e','_','p','p','d','s','\\',0};
744 WCHAR
*dir
, tmp_path
[MAX_PATH
];
747 len
= GetTempPathW( sizeof(tmp_path
) / sizeof(tmp_path
[0]), tmp_path
);
748 if (!len
) return NULL
;
749 dir
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) + sizeof(wine_ppds
) ) ;
750 if (!dir
) return NULL
;
752 memcpy( dir
, tmp_path
, len
* sizeof(WCHAR
) );
753 memcpy( dir
+ len
, wine_ppds
, sizeof(wine_ppds
) );
754 res
= CreateDirectoryW( dir
, NULL
);
755 if (!res
&& GetLastError() != ERROR_ALREADY_EXISTS
)
757 HeapFree( GetProcessHeap(), 0, dir
);
760 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir
) );
764 static void unlink_ppd( const WCHAR
*ppd
)
766 char *unix_name
= wine_get_unix_file_name( ppd
);
768 HeapFree( GetProcessHeap(), 0, unix_name
);
771 #ifdef SONAME_LIBCUPS
773 static void *cupshandle
;
776 DO_FUNC(cupsAddOption); \
777 DO_FUNC(cupsFreeDests); \
778 DO_FUNC(cupsFreeOptions); \
779 DO_FUNC(cupsGetDests); \
780 DO_FUNC(cupsGetOption); \
781 DO_FUNC(cupsGetPPD); \
782 DO_FUNC(cupsParseOptions); \
783 DO_FUNC(cupsPrintFile)
784 #define CUPS_OPT_FUNCS \
785 DO_FUNC(cupsGetNamedDest); \
788 #define DO_FUNC(f) static typeof(f) *p##f
791 static cups_dest_t
* (*pcupsGetNamedDest
)(http_t
*, const char *, const char *);
792 static http_status_t (*pcupsGetPPD3
)(http_t
*, const char *, time_t *, char *, size_t);
794 static http_status_t
cupsGetPPD3_wrapper( http_t
*http
, const char *name
,
795 time_t *modtime
, char *buffer
,
800 if (pcupsGetPPD3
) return pcupsGetPPD3( http
, name
, modtime
, buffer
, bufsize
);
802 if (!pcupsGetPPD
) return HTTP_NOT_FOUND
;
804 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
807 ppd
= pcupsGetPPD( name
);
809 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd
) );
811 if (!ppd
) return HTTP_NOT_FOUND
;
813 if (rename( ppd
, buffer
) == -1)
815 BOOL res
= copy_file( ppd
, buffer
);
817 if (!res
) return HTTP_NOT_FOUND
;
822 static BOOL
get_cups_ppd( const char *printer_name
, const WCHAR
*ppd
)
825 http_status_t http_status
;
826 char *unix_name
= wine_get_unix_file_name( ppd
);
828 TRACE( "(%s, %s)\n", debugstr_a(printer_name
), debugstr_w(ppd
) );
830 if (!unix_name
) return FALSE
;
832 http_status
= cupsGetPPD3_wrapper( 0, printer_name
, &modtime
,
833 unix_name
, strlen( unix_name
) + 1 );
835 if (http_status
!= HTTP_OK
) unlink( unix_name
);
836 HeapFree( GetProcessHeap(), 0, unix_name
);
838 if (http_status
== HTTP_OK
) return TRUE
;
840 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
841 debugstr_a(printer_name
), http_status
);
842 return get_fallback_ppd( printer_name
, ppd
);
845 static WCHAR
*get_cups_option( const char *name
, int num_options
, cups_option_t
*options
)
851 value
= pcupsGetOption( name
, num_options
, options
);
852 if (!value
) return NULL
;
854 len
= MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, NULL
, 0 );
855 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
856 if (ret
) MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, ret
, len
);
861 static cups_ptype_t
get_cups_printer_type( const cups_dest_t
*dest
)
863 WCHAR
*type
= get_cups_option( "printer-type", dest
->num_options
, dest
->options
), *end
;
864 cups_ptype_t ret
= 0;
868 ret
= (cups_ptype_t
)strtoulW( type
, &end
, 10 );
871 HeapFree( GetProcessHeap(), 0, type
);
875 static void load_cups(void)
877 cupshandle
= wine_dlopen( SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0 );
878 if (!cupshandle
) return;
880 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
883 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
886 ERR("failed to load symbol %s\n", #x); \
892 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
897 static BOOL
CUPS_LoadPrinters(void)
900 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
903 WCHAR
*port
, *ppd_dir
= NULL
, *ppd
;
904 HKEY hkeyPrinter
, hkeyPrinters
;
905 WCHAR nameW
[MAX_PATH
];
906 HANDLE added_printer
;
907 cups_ptype_t printer_type
;
909 if (!cupshandle
) return FALSE
;
911 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
913 ERR("Can't create Printers key\n");
917 nrofdests
= pcupsGetDests(&dests
);
918 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
919 for (i
=0;i
<nrofdests
;i
++) {
920 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
921 printer_type
= get_cups_printer_type( dests
+ i
);
923 TRACE( "Printer %d: %s. printer_type %x\n", i
, debugstr_w(nameW
), printer_type
);
925 if (printer_type
& 0x2000000 /* CUPS_PRINTER_SCANNER */)
927 TRACE( "skipping scanner-only device\n" );
931 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
932 lstrcpyW(port
, CUPS_Port
);
933 lstrcatW(port
, nameW
);
935 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
936 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
937 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
939 TRACE("Printer already exists\n");
940 /* overwrite old LPR:* port */
941 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
942 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
943 /* flag that the PPD file should be checked for an update */
944 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
945 RegCloseKey(hkeyPrinter
);
947 BOOL added_driver
= FALSE
;
949 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir()))
951 HeapFree( GetProcessHeap(), 0, port
);
954 ppd
= get_ppd_filename( ppd_dir
, nameW
);
955 if (get_cups_ppd( dests
[i
].name
, ppd
))
957 added_driver
= add_printer_driver( nameW
, ppd
);
960 HeapFree( GetProcessHeap(), 0, ppd
);
963 HeapFree( GetProcessHeap(), 0, port
);
967 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
968 pi2
.pPrinterName
= nameW
;
969 pi2
.pDatatype
= rawW
;
970 pi2
.pPrintProcessor
= WinPrintW
;
971 pi2
.pDriverName
= nameW
;
972 pi2
.pComment
= get_cups_option( "printer-info", dests
[i
].num_options
, dests
[i
].options
);
973 pi2
.pLocation
= get_cups_option( "printer-location", dests
[i
].num_options
, dests
[i
].options
);
974 pi2
.pPortName
= port
;
975 pi2
.pParameters
= emptyStringW
;
976 pi2
.pShareName
= emptyStringW
;
977 pi2
.pSepFile
= emptyStringW
;
979 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
980 if (added_printer
) ClosePrinter( added_printer
);
981 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
982 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
984 HeapFree( GetProcessHeap(), 0, pi2
.pComment
);
985 HeapFree( GetProcessHeap(), 0, pi2
.pLocation
);
987 HeapFree( GetProcessHeap(), 0, port
);
990 if (dests
[i
].is_default
) {
991 SetDefaultPrinterW(nameW
);
998 RemoveDirectoryW( ppd_dir
);
999 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1002 if (hadprinter
&& !haddefault
) {
1003 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
1004 SetDefaultPrinterW(nameW
);
1006 pcupsFreeDests(nrofdests
, dests
);
1007 RegCloseKey(hkeyPrinters
);
1013 static char *get_queue_name( HANDLE printer
, BOOL
*cups
)
1015 WCHAR
*port
, *name
= NULL
;
1016 DWORD err
, needed
, type
;
1022 err
= WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
);
1023 if (err
) return NULL
;
1024 err
= RegQueryValueExW( key
, PortW
, 0, &type
, NULL
, &needed
);
1026 port
= HeapAlloc( GetProcessHeap(), 0, needed
);
1027 if (!port
) goto end
;
1028 RegQueryValueExW( key
, PortW
, 0, &type
, (BYTE
*)port
, &needed
);
1030 if (!strncmpW( port
, CUPS_Port
, sizeof(CUPS_Port
) / sizeof(WCHAR
) -1 ))
1032 name
= port
+ sizeof(CUPS_Port
) / sizeof(WCHAR
) - 1;
1035 else if (!strncmpW( port
, LPR_Port
, sizeof(LPR_Port
) / sizeof(WCHAR
) -1 ))
1036 name
= port
+ sizeof(LPR_Port
) / sizeof(WCHAR
) - 1;
1039 needed
= WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
1040 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
1041 if(ret
) WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, ret
, needed
, NULL
, NULL
);
1043 HeapFree( GetProcessHeap(), 0, port
);
1050 static void set_ppd_overrides( HANDLE printer
)
1054 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1056 PMPrintSession session
= NULL
;
1057 PMPageFormat format
= NULL
;
1059 CFStringRef paper_name
;
1062 status
= PMCreateSession( &session
);
1063 if (status
) goto end
;
1065 status
= PMCreatePageFormat( &format
);
1066 if (status
) goto end
;
1068 status
= PMSessionDefaultPageFormat( session
, format
);
1069 if (status
) goto end
;
1071 status
= PMGetPageFormatPaper( format
, &paper
);
1072 if (status
) goto end
;
1074 status
= PMPaperGetPPDPaperName( paper
, &paper_name
);
1075 if (status
) goto end
;
1078 range
.length
= CFStringGetLength( paper_name
);
1079 size
= (range
.length
+ 1) * sizeof(WCHAR
);
1081 wstr
= HeapAlloc( GetProcessHeap(), 0, size
);
1082 CFStringGetCharacters( paper_name
, range
, (UniChar
*)wstr
);
1083 wstr
[range
.length
] = 0;
1086 if (format
) PMRelease( format
);
1087 if (session
) PMRelease( session
);
1090 SetPrinterDataExW( printer
, PPD_Overrides
, DefaultPageSize
, REG_SZ
, (BYTE
*)wstr
, size
);
1091 HeapFree( GetProcessHeap(), 0, wstr
);
1094 static BOOL
update_driver( HANDLE printer
)
1097 const WCHAR
*name
= get_opened_printer_name( printer
);
1098 WCHAR
*ppd_dir
, *ppd
;
1101 if (!name
) return FALSE
;
1102 queue_name
= get_queue_name( printer
, &is_cups
);
1103 if (!queue_name
) return FALSE
;
1105 if (!(ppd_dir
= get_ppd_dir()))
1107 HeapFree( GetProcessHeap(), 0, queue_name
);
1110 ppd
= get_ppd_filename( ppd_dir
, name
);
1112 #ifdef SONAME_LIBCUPS
1114 ret
= get_cups_ppd( queue_name
, ppd
);
1117 ret
= get_fallback_ppd( queue_name
, ppd
);
1121 TRACE( "updating driver %s\n", debugstr_w( name
) );
1122 ret
= add_printer_driver( name
, ppd
);
1125 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1126 HeapFree( GetProcessHeap(), 0, ppd
);
1127 HeapFree( GetProcessHeap(), 0, queue_name
);
1129 set_ppd_overrides( printer
);
1131 /* call into the driver to update the devmode */
1132 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
1137 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
1139 PRINTER_INFO_2A pinfo2a
;
1142 char *e
,*s
,*name
,*prettyname
,*devname
;
1143 BOOL ret
= FALSE
, set_default
= FALSE
;
1144 char *port
= NULL
, *env_default
;
1145 HKEY hkeyPrinter
, hkeyPrinters
= NULL
;
1146 WCHAR devnameW
[MAX_PATH
], *ppd_dir
= NULL
, *ppd
;
1147 HANDLE added_printer
;
1149 while (isspace(*pent
)) pent
++;
1150 r
= strchr(pent
,':');
1152 name_len
= r
- pent
;
1154 name_len
= strlen(pent
);
1155 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
1156 memcpy(name
, pent
, name_len
);
1157 name
[name_len
] = '\0';
1163 TRACE("name=%s entry=%s\n",name
, pent
);
1165 if(ispunct(*name
)) { /* a tc entry, not a real printer */
1166 TRACE("skipping tc entry\n");
1170 if(strstr(pent
,":server")) { /* server only version so skip */
1171 TRACE("skipping server entry\n");
1175 /* Determine whether this is a postscript printer. */
1178 env_default
= getenv("PRINTER");
1180 /* Get longest name, usually the one at the right for later display. */
1181 while((s
=strchr(prettyname
,'|'))) {
1184 while(isspace(*--e
)) *e
= '\0';
1185 TRACE("\t%s\n", debugstr_a(prettyname
));
1186 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1187 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
1190 e
= prettyname
+ strlen(prettyname
);
1191 while(isspace(*--e
)) *e
= '\0';
1192 TRACE("\t%s\n", debugstr_a(prettyname
));
1193 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1195 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1196 * if it is too long, we use it as comment below. */
1197 devname
= prettyname
;
1198 if (strlen(devname
)>=CCHDEVICENAME
-1)
1200 if (strlen(devname
)>=CCHDEVICENAME
-1) {
1205 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
1206 sprintf(port
,"LPR:%s",name
);
1208 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1210 ERR("Can't create Printers key\n");
1215 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
1217 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1218 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1219 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1221 TRACE("Printer already exists\n");
1222 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1223 /* flag that the PPD file should be checked for an update */
1224 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1225 RegCloseKey(hkeyPrinter
);
1227 static CHAR data_type
[] = "RAW",
1228 print_proc
[] = "WinPrint",
1229 comment
[] = "WINEPS Printer using LPR",
1230 params
[] = "<parameters?>",
1231 share_name
[] = "<share name?>",
1232 sep_file
[] = "<sep file?>";
1233 BOOL added_driver
= FALSE
;
1235 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir())) goto end
;
1236 ppd
= get_ppd_filename( ppd_dir
, devnameW
);
1237 if (get_fallback_ppd( devname
, ppd
))
1239 added_driver
= add_printer_driver( devnameW
, ppd
);
1242 HeapFree( GetProcessHeap(), 0, ppd
);
1243 if (!added_driver
) goto end
;
1245 memset(&pinfo2a
,0,sizeof(pinfo2a
));
1246 pinfo2a
.pPrinterName
= devname
;
1247 pinfo2a
.pDatatype
= data_type
;
1248 pinfo2a
.pPrintProcessor
= print_proc
;
1249 pinfo2a
.pDriverName
= devname
;
1250 pinfo2a
.pComment
= comment
;
1251 pinfo2a
.pLocation
= prettyname
;
1252 pinfo2a
.pPortName
= port
;
1253 pinfo2a
.pParameters
= params
;
1254 pinfo2a
.pShareName
= share_name
;
1255 pinfo2a
.pSepFile
= sep_file
;
1257 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
1258 if (added_printer
) ClosePrinter( added_printer
);
1259 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1260 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
1263 if (isfirst
|| set_default
)
1264 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
1267 if (hkeyPrinters
) RegCloseKey( hkeyPrinters
);
1270 RemoveDirectoryW( ppd_dir
);
1271 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1273 HeapFree(GetProcessHeap(), 0, port
);
1274 HeapFree(GetProcessHeap(), 0, name
);
1279 PRINTCAP_LoadPrinters(void) {
1280 BOOL hadprinter
= FALSE
;
1284 BOOL had_bash
= FALSE
;
1286 f
= fopen("/etc/printcap","r");
1290 while(fgets(buf
,sizeof(buf
),f
)) {
1293 end
=strchr(buf
,'\n');
1297 while(isspace(*start
)) start
++;
1298 if(*start
== '#' || *start
== '\0')
1301 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
1302 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1303 HeapFree(GetProcessHeap(),0,pent
);
1307 if (end
&& *--end
== '\\') {
1314 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
1317 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
1323 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1324 HeapFree(GetProcessHeap(),0,pent
);
1330 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
1333 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
1334 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
1336 return ERROR_FILE_NOT_FOUND
;
1339 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
1341 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
1342 DWORD ret
= ERROR_FILE_NOT_FOUND
;
1344 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1345 and we support these drivers. NT writes DEVMODEW so somehow
1346 we'll need to distinguish between these when we support NT
1351 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
1352 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1353 HeapFree( GetProcessHeap(), 0, dmA
);
1359 /******************************************************************
1360 * get_servername_from_name (internal)
1362 * for an external server, a copy of the serverpart from the full name is returned
1365 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1369 WCHAR buffer
[MAX_PATH
];
1372 if (name
== NULL
) return NULL
;
1373 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1375 server
= strdupW(&name
[2]); /* skip over both backslash */
1376 if (server
== NULL
) return NULL
;
1378 /* strip '\' and the printername */
1379 ptr
= strchrW(server
, '\\');
1380 if (ptr
) ptr
[0] = '\0';
1382 TRACE("found %s\n", debugstr_w(server
));
1384 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1385 if (GetComputerNameW(buffer
, &len
)) {
1386 if (lstrcmpW(buffer
, server
) == 0) {
1387 /* The requested Servername is our computername */
1388 HeapFree(GetProcessHeap(), 0, server
);
1395 /******************************************************************
1396 * get_basename_from_name (internal)
1398 * skip over the serverpart from the full name
1401 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1403 if (name
== NULL
) return NULL
;
1404 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1405 /* skip over the servername and search for the following '\' */
1406 name
= strchrW(&name
[2], '\\');
1407 if ((name
) && (name
[1])) {
1408 /* found a separator ('\') followed by a name:
1409 skip over the separator and return the rest */
1414 /* no basename present (we found only a servername) */
1421 static void free_printer_entry( opened_printer_t
*printer
)
1423 /* the queue is shared, so don't free that here */
1424 HeapFree( GetProcessHeap(), 0, printer
->printername
);
1425 HeapFree( GetProcessHeap(), 0, printer
->name
);
1426 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
1427 HeapFree( GetProcessHeap(), 0, printer
);
1430 /******************************************************************
1431 * get_opened_printer_entry
1432 * Get the first place empty in the opened printer table
1435 * - pDefault is ignored
1437 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1439 UINT_PTR handle
= nb_printer_handles
, i
;
1440 jobqueue_t
*queue
= NULL
;
1441 opened_printer_t
*printer
= NULL
;
1443 LPCWSTR printername
;
1445 if ((backend
== NULL
) && !load_backend()) return NULL
;
1447 servername
= get_servername_from_name(name
);
1449 FIXME("server %s not supported\n", debugstr_w(servername
));
1450 HeapFree(GetProcessHeap(), 0, servername
);
1451 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1455 printername
= get_basename_from_name(name
);
1456 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1458 /* an empty printername is invalid */
1459 if (printername
&& (!printername
[0])) {
1460 SetLastError(ERROR_INVALID_PARAMETER
);
1464 EnterCriticalSection(&printer_handles_cs
);
1466 for (i
= 0; i
< nb_printer_handles
; i
++)
1468 if (!printer_handles
[i
])
1470 if(handle
== nb_printer_handles
)
1475 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1476 queue
= printer_handles
[i
]->queue
;
1480 if (handle
>= nb_printer_handles
)
1482 opened_printer_t
**new_array
;
1483 if (printer_handles
)
1484 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1485 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1487 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1488 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1495 printer_handles
= new_array
;
1496 nb_printer_handles
+= 16;
1499 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1505 /* get a printer handle from the backend */
1506 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1511 /* clone the base name. This is NULL for the printserver */
1512 printer
->printername
= strdupW(printername
);
1514 /* clone the full name */
1515 printer
->name
= strdupW(name
);
1516 if (name
&& (!printer
->name
)) {
1521 if (pDefault
&& pDefault
->pDevMode
)
1522 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
1525 printer
->queue
= queue
;
1528 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1529 if (!printer
->queue
) {
1533 list_init(&printer
->queue
->jobs
);
1534 printer
->queue
->ref
= 0;
1536 InterlockedIncrement(&printer
->queue
->ref
);
1538 printer_handles
[handle
] = printer
;
1541 LeaveCriticalSection(&printer_handles_cs
);
1542 if (!handle
&& printer
) {
1543 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1544 free_printer_entry( printer
);
1547 return (HANDLE
)handle
;
1550 static void old_printer_check( BOOL delete_phase
)
1552 PRINTER_INFO_5W
* pi
;
1553 DWORD needed
, type
, num
, delete, i
, size
;
1554 const DWORD one
= 1;
1558 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1559 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1561 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1562 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1563 for (i
= 0; i
< num
; i
++)
1565 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1566 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1569 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1573 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1579 size
= sizeof( delete );
1580 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1584 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1585 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1587 DeletePrinter( hprn
);
1588 ClosePrinter( hprn
);
1590 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1594 HeapFree(GetProcessHeap(), 0, pi
);
1597 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1598 'M','U','T','E','X','_','_','\0'};
1599 static HANDLE init_mutex
;
1601 void WINSPOOL_LoadSystemPrinters(void)
1603 HKEY hkey
, hkeyPrinters
;
1604 DWORD needed
, num
, i
;
1605 WCHAR PrinterName
[256];
1608 #ifdef SONAME_LIBCUPS
1612 /* FIXME: The init code should be moved to spoolsv.exe */
1613 init_mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1616 ERR( "Failed to create mutex\n" );
1619 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1621 WaitForSingleObject( init_mutex
, INFINITE
);
1622 ReleaseMutex( init_mutex
);
1623 TRACE( "Init already done\n" );
1627 /* This ensures that all printer entries have a valid Name value. If causes
1628 problems later if they don't. If one is found to be missed we create one
1629 and set it equal to the name of the key */
1630 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1631 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1632 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1633 for(i
= 0; i
< num
; i
++) {
1634 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1635 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1636 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1637 set_reg_szW(hkey
, NameW
, PrinterName
);
1644 RegCloseKey(hkeyPrinters
);
1647 old_printer_check( FALSE
);
1649 #ifdef SONAME_LIBCUPS
1650 done
= CUPS_LoadPrinters();
1653 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1654 PRINTCAP_LoadPrinters();
1656 old_printer_check( TRUE
);
1658 ReleaseMutex( init_mutex
);
1662 /******************************************************************
1665 * Get the pointer to the specified job.
1666 * Should hold the printer_handles_cs before calling.
1668 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1670 opened_printer_t
*printer
= get_opened_printer(hprn
);
1673 if(!printer
) return NULL
;
1674 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1676 if(job
->job_id
== JobId
)
1682 /***********************************************************
1685 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1688 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1691 Formname
= (dmA
->dmSize
> off_formname
);
1692 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1693 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1694 dmW
->dmDeviceName
, CCHDEVICENAME
);
1696 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1697 dmA
->dmSize
- CCHDEVICENAME
);
1699 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1700 off_formname
- CCHDEVICENAME
);
1701 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1702 dmW
->dmFormName
, CCHFORMNAME
);
1703 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1704 (off_formname
+ CCHFORMNAME
));
1707 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1708 dmA
->dmDriverExtra
);
1712 /******************************************************************
1713 * convert_printerinfo_W_to_A [internal]
1716 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1717 DWORD level
, DWORD outlen
, DWORD numentries
)
1723 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1725 len
= pi_sizeof
[level
] * numentries
;
1726 ptr
= (LPSTR
) out
+ len
;
1729 /* copy the numbers of all PRINTER_INFO_* first */
1730 memcpy(out
, pPrintersW
, len
);
1732 while (id
< numentries
) {
1736 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1737 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1739 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1740 if (piW
->pDescription
) {
1741 piA
->pDescription
= ptr
;
1742 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1743 ptr
, outlen
, NULL
, NULL
);
1749 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1750 ptr
, outlen
, NULL
, NULL
);
1754 if (piW
->pComment
) {
1755 piA
->pComment
= ptr
;
1756 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1757 ptr
, outlen
, NULL
, NULL
);
1766 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1767 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1770 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1771 if (piW
->pServerName
) {
1772 piA
->pServerName
= ptr
;
1773 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1774 ptr
, outlen
, NULL
, NULL
);
1778 if (piW
->pPrinterName
) {
1779 piA
->pPrinterName
= ptr
;
1780 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1781 ptr
, outlen
, NULL
, NULL
);
1785 if (piW
->pShareName
) {
1786 piA
->pShareName
= ptr
;
1787 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1788 ptr
, outlen
, NULL
, NULL
);
1792 if (piW
->pPortName
) {
1793 piA
->pPortName
= ptr
;
1794 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1795 ptr
, outlen
, NULL
, NULL
);
1799 if (piW
->pDriverName
) {
1800 piA
->pDriverName
= ptr
;
1801 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1802 ptr
, outlen
, NULL
, NULL
);
1806 if (piW
->pComment
) {
1807 piA
->pComment
= ptr
;
1808 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1809 ptr
, outlen
, NULL
, NULL
);
1813 if (piW
->pLocation
) {
1814 piA
->pLocation
= ptr
;
1815 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1816 ptr
, outlen
, NULL
, NULL
);
1821 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1823 /* align DEVMODEA to a DWORD boundary */
1824 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1828 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1829 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1830 memcpy(ptr
, dmA
, len
);
1831 HeapFree(GetProcessHeap(), 0, dmA
);
1837 if (piW
->pSepFile
) {
1838 piA
->pSepFile
= ptr
;
1839 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1840 ptr
, outlen
, NULL
, NULL
);
1844 if (piW
->pPrintProcessor
) {
1845 piA
->pPrintProcessor
= ptr
;
1846 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1847 ptr
, outlen
, NULL
, NULL
);
1851 if (piW
->pDatatype
) {
1852 piA
->pDatatype
= ptr
;
1853 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1854 ptr
, outlen
, NULL
, NULL
);
1858 if (piW
->pParameters
) {
1859 piA
->pParameters
= ptr
;
1860 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1861 ptr
, outlen
, NULL
, NULL
);
1865 if (piW
->pSecurityDescriptor
) {
1866 piA
->pSecurityDescriptor
= NULL
;
1867 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1874 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1875 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1877 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1879 if (piW
->pPrinterName
) {
1880 piA
->pPrinterName
= ptr
;
1881 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1882 ptr
, outlen
, NULL
, NULL
);
1886 if (piW
->pServerName
) {
1887 piA
->pServerName
= ptr
;
1888 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1889 ptr
, outlen
, NULL
, NULL
);
1898 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1899 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1901 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1903 if (piW
->pPrinterName
) {
1904 piA
->pPrinterName
= ptr
;
1905 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1906 ptr
, outlen
, NULL
, NULL
);
1910 if (piW
->pPortName
) {
1911 piA
->pPortName
= ptr
;
1912 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1913 ptr
, outlen
, NULL
, NULL
);
1920 case 6: /* 6A and 6W are the same structure */
1925 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1926 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1928 TRACE("(%u) #%u\n", level
, id
);
1929 if (piW
->pszObjectGUID
) {
1930 piA
->pszObjectGUID
= ptr
;
1931 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1932 ptr
, outlen
, NULL
, NULL
);
1942 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1943 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1946 TRACE("(%u) #%u\n", level
, id
);
1947 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1949 /* align DEVMODEA to a DWORD boundary */
1950 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1954 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1955 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1956 memcpy(ptr
, dmA
, len
);
1957 HeapFree(GetProcessHeap(), 0, dmA
);
1967 FIXME("for level %u\n", level
);
1969 pPrintersW
+= pi_sizeof
[level
];
1970 out
+= pi_sizeof
[level
];
1975 /******************************************************************
1976 * convert_driverinfo_W_to_A [internal]
1979 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1980 DWORD level
, DWORD outlen
, DWORD numentries
)
1986 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1988 len
= di_sizeof
[level
] * numentries
;
1989 ptr
= (LPSTR
) out
+ len
;
1992 /* copy the numbers of all PRINTER_INFO_* first */
1993 memcpy(out
, pDriversW
, len
);
1995 #define COPY_STRING(fld) \
1998 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1999 ptr += len; outlen -= len;\
2001 #define COPY_MULTIZ_STRING(fld) \
2002 { LPWSTR p = diW->fld; if (p){ \
2005 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2006 ptr += len; outlen -= len; p += len;\
2008 while(len > 1 && outlen > 0); \
2011 while (id
< numentries
)
2017 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
2018 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
2020 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2027 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
2028 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
2030 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2033 COPY_STRING(pEnvironment
);
2034 COPY_STRING(pDriverPath
);
2035 COPY_STRING(pDataFile
);
2036 COPY_STRING(pConfigFile
);
2041 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
2042 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
2044 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2047 COPY_STRING(pEnvironment
);
2048 COPY_STRING(pDriverPath
);
2049 COPY_STRING(pDataFile
);
2050 COPY_STRING(pConfigFile
);
2051 COPY_STRING(pHelpFile
);
2052 COPY_MULTIZ_STRING(pDependentFiles
);
2053 COPY_STRING(pMonitorName
);
2054 COPY_STRING(pDefaultDataType
);
2059 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
2060 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
2062 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2065 COPY_STRING(pEnvironment
);
2066 COPY_STRING(pDriverPath
);
2067 COPY_STRING(pDataFile
);
2068 COPY_STRING(pConfigFile
);
2069 COPY_STRING(pHelpFile
);
2070 COPY_MULTIZ_STRING(pDependentFiles
);
2071 COPY_STRING(pMonitorName
);
2072 COPY_STRING(pDefaultDataType
);
2073 COPY_MULTIZ_STRING(pszzPreviousNames
);
2078 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
2079 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
2081 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2084 COPY_STRING(pEnvironment
);
2085 COPY_STRING(pDriverPath
);
2086 COPY_STRING(pDataFile
);
2087 COPY_STRING(pConfigFile
);
2092 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
2093 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
2095 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2098 COPY_STRING(pEnvironment
);
2099 COPY_STRING(pDriverPath
);
2100 COPY_STRING(pDataFile
);
2101 COPY_STRING(pConfigFile
);
2102 COPY_STRING(pHelpFile
);
2103 COPY_MULTIZ_STRING(pDependentFiles
);
2104 COPY_STRING(pMonitorName
);
2105 COPY_STRING(pDefaultDataType
);
2106 COPY_MULTIZ_STRING(pszzPreviousNames
);
2107 COPY_STRING(pszMfgName
);
2108 COPY_STRING(pszOEMUrl
);
2109 COPY_STRING(pszHardwareID
);
2110 COPY_STRING(pszProvider
);
2115 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
2116 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
2118 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2121 COPY_STRING(pEnvironment
);
2122 COPY_STRING(pDriverPath
);
2123 COPY_STRING(pDataFile
);
2124 COPY_STRING(pConfigFile
);
2125 COPY_STRING(pHelpFile
);
2126 COPY_MULTIZ_STRING(pDependentFiles
);
2127 COPY_STRING(pMonitorName
);
2128 COPY_STRING(pDefaultDataType
);
2129 COPY_MULTIZ_STRING(pszzPreviousNames
);
2130 COPY_STRING(pszMfgName
);
2131 COPY_STRING(pszOEMUrl
);
2132 COPY_STRING(pszHardwareID
);
2133 COPY_STRING(pszProvider
);
2134 COPY_STRING(pszPrintProcessor
);
2135 COPY_STRING(pszVendorSetup
);
2136 COPY_MULTIZ_STRING(pszzColorProfiles
);
2137 COPY_STRING(pszInfPath
);
2138 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
2144 FIXME("for level %u\n", level
);
2147 pDriversW
+= di_sizeof
[level
];
2148 out
+= di_sizeof
[level
];
2153 #undef COPY_MULTIZ_STRING
2157 /***********************************************************
2160 static void *printer_info_AtoW( const void *data
, DWORD level
)
2163 UNICODE_STRING usBuffer
;
2165 if (!data
) return NULL
;
2167 if (level
< 1 || level
> 9) return NULL
;
2169 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
2170 if (!ret
) return NULL
;
2172 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
2178 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
2179 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
2181 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
2182 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
2183 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
2184 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
2185 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
2186 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
2187 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
2188 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2189 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
2190 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
2191 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
2192 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
2199 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
2200 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
2202 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2207 FIXME( "Unhandled level %d\n", level
);
2208 HeapFree( GetProcessHeap(), 0, ret
);
2215 /***********************************************************
2218 static void free_printer_info( void *data
, DWORD level
)
2226 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
2228 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
2229 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
2230 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
2231 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
2232 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
2233 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
2234 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
2235 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2236 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
2237 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
2238 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
2239 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
2246 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
2248 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2253 FIXME( "Unhandled level %d\n", level
);
2256 HeapFree( GetProcessHeap(), 0, data
);
2260 /******************************************************************
2261 * DeviceCapabilities [WINSPOOL.@]
2262 * DeviceCapabilitiesA [WINSPOOL.@]
2265 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
2266 LPSTR pOutput
, LPDEVMODEA lpdm
)
2270 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice
), debugstr_a(pPort
), cap
, pOutput
, lpdm
);
2272 if (!GDI_CallDeviceCapabilities16
)
2274 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2276 if (!GDI_CallDeviceCapabilities16
) return -1;
2278 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
2280 /* If DC_PAPERSIZE map POINT16s to POINTs */
2281 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
2282 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
2283 POINT
*pt
= (POINT
*)pOutput
;
2285 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
2286 for(i
= 0; i
< ret
; i
++, pt
++)
2291 HeapFree( GetProcessHeap(), 0, tmp
);
2297 /*****************************************************************************
2298 * DeviceCapabilitiesW [WINSPOOL.@]
2300 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2303 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2304 WORD fwCapability
, LPWSTR pOutput
,
2305 const DEVMODEW
*pDevMode
)
2307 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
2308 LPSTR pDeviceA
= strdupWtoA(pDevice
);
2309 LPSTR pPortA
= strdupWtoA(pPort
);
2312 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice
), debugstr_w(pPort
), fwCapability
, pOutput
, pDevMode
);
2314 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
2315 fwCapability
== DC_FILEDEPENDENCIES
||
2316 fwCapability
== DC_PAPERNAMES
)) {
2317 /* These need A -> W translation */
2320 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2324 switch(fwCapability
) {
2329 case DC_FILEDEPENDENCIES
:
2333 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2334 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2336 for(i
= 0; i
< ret
; i
++)
2337 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2338 pOutput
+ (i
* size
), size
);
2339 HeapFree(GetProcessHeap(), 0, pOutputA
);
2341 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2342 (LPSTR
)pOutput
, dmA
);
2344 HeapFree(GetProcessHeap(),0,pPortA
);
2345 HeapFree(GetProcessHeap(),0,pDeviceA
);
2346 HeapFree(GetProcessHeap(),0,dmA
);
2350 /******************************************************************
2351 * DocumentPropertiesA [WINSPOOL.@]
2353 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2355 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2356 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2357 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2359 LPSTR lpName
= pDeviceName
, dupname
= NULL
;
2360 static CHAR port
[] = "LPT1:";
2363 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2364 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2367 if(!pDeviceName
|| !*pDeviceName
) {
2368 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2370 ERR("no name from hPrinter?\n");
2371 SetLastError(ERROR_INVALID_HANDLE
);
2374 lpName
= dupname
= strdupWtoA(lpNameW
);
2377 if (!GDI_CallExtDeviceMode16
)
2379 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2381 if (!GDI_CallExtDeviceMode16
) {
2382 ERR("No CallExtDeviceMode16?\n");
2387 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2388 pDevModeInput
, NULL
, fMode
);
2391 HeapFree(GetProcessHeap(), 0, dupname
);
2396 /*****************************************************************************
2397 * DocumentPropertiesW (WINSPOOL.@)
2399 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2401 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2403 LPDEVMODEW pDevModeOutput
,
2404 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2407 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2408 LPDEVMODEA pDevModeInputA
;
2409 LPDEVMODEA pDevModeOutputA
= NULL
;
2412 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2413 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2415 if(pDevModeOutput
) {
2416 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2417 if(ret
< 0) return ret
;
2418 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2420 pDevModeInputA
= (fMode
& DM_IN_BUFFER
) ? DEVMODEdupWtoA(pDevModeInput
) : NULL
;
2421 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2422 pDevModeInputA
, fMode
);
2423 if(pDevModeOutput
) {
2424 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2425 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2427 if(fMode
== 0 && ret
> 0)
2428 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2429 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2430 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2434 /*****************************************************************************
2435 * IsValidDevmodeA [WINSPOOL.@]
2437 * Validate a DEVMODE structure and fix errors if possible.
2440 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
2442 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2450 /*****************************************************************************
2451 * IsValidDevmodeW [WINSPOOL.@]
2453 * Validate a DEVMODE structure and fix errors if possible.
2456 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
2458 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2466 /******************************************************************
2467 * OpenPrinterA [WINSPOOL.@]
2472 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2473 LPPRINTER_DEFAULTSA pDefault
)
2475 UNICODE_STRING lpPrinterNameW
;
2476 UNICODE_STRING usBuffer
;
2477 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2478 PWSTR pwstrPrinterNameW
;
2481 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName
), phPrinter
, pDefault
);
2483 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2486 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2487 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2488 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2489 pDefaultW
= &DefaultW
;
2491 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2493 RtlFreeUnicodeString(&usBuffer
);
2494 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2496 RtlFreeUnicodeString(&lpPrinterNameW
);
2500 /******************************************************************
2501 * OpenPrinterW [WINSPOOL.@]
2503 * Open a Printer / Printserver or a Printer-Object
2506 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2507 * phPrinter [O] The resulting Handle is stored here
2508 * pDefault [I] PTR to Default Printer Settings or NULL
2515 * lpPrinterName is one of:
2516 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2517 *| Printer: "PrinterName"
2518 *| Printer-Object: "PrinterName,Job xxx"
2519 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2520 *| XcvPort: "Servername,XcvPort PortName"
2523 *| Printer-Object not supported
2524 *| pDefaults is ignored
2527 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2531 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2534 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2535 SetLastError(ERROR_INVALID_PARAMETER
);
2539 /* Get the unique handle of the printer or Printserver */
2540 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2542 if (*phPrinter
&& WINSPOOL_GetOpenedPrinterRegKey( *phPrinter
, &key
) == ERROR_SUCCESS
)
2544 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2546 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2547 WaitForSingleObject( init_mutex
, INFINITE
);
2548 status
= get_dword_from_reg( key
, StatusW
);
2549 set_reg_DWORD( key
, StatusW
, status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2550 ReleaseMutex( init_mutex
);
2551 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2552 update_driver( *phPrinter
);
2556 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2557 return (*phPrinter
!= 0);
2560 /******************************************************************
2561 * AddMonitorA [WINSPOOL.@]
2566 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2568 LPWSTR nameW
= NULL
;
2571 LPMONITOR_INFO_2A mi2a
;
2572 MONITOR_INFO_2W mi2w
;
2574 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2575 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2576 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2577 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2578 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2581 SetLastError(ERROR_INVALID_LEVEL
);
2585 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2591 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2592 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2593 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2596 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2598 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2599 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2600 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2602 if (mi2a
->pEnvironment
) {
2603 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2604 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2605 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2607 if (mi2a
->pDLLName
) {
2608 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2609 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2610 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2613 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2615 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2616 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2617 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2619 HeapFree(GetProcessHeap(), 0, nameW
);
2623 /******************************************************************************
2624 * AddMonitorW [WINSPOOL.@]
2626 * Install a Printmonitor
2629 * pName [I] Servername or NULL (local Computer)
2630 * Level [I] Structure-Level (Must be 2)
2631 * pMonitors [I] PTR to MONITOR_INFO_2
2638 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2641 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2643 LPMONITOR_INFO_2W mi2w
;
2645 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2646 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2647 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2648 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2649 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2651 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2654 SetLastError(ERROR_INVALID_LEVEL
);
2658 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2663 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2666 /******************************************************************
2667 * DeletePrinterDriverA [WINSPOOL.@]
2670 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2672 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2675 /******************************************************************
2676 * DeletePrinterDriverW [WINSPOOL.@]
2679 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2681 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2684 /******************************************************************
2685 * DeleteMonitorA [WINSPOOL.@]
2687 * See DeleteMonitorW.
2690 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2692 LPWSTR nameW
= NULL
;
2693 LPWSTR EnvironmentW
= NULL
;
2694 LPWSTR MonitorNameW
= NULL
;
2699 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2700 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2701 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2705 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2706 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2707 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2710 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2711 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2712 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2715 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2717 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2718 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2719 HeapFree(GetProcessHeap(), 0, nameW
);
2723 /******************************************************************
2724 * DeleteMonitorW [WINSPOOL.@]
2726 * Delete a specific Printmonitor from a Printing-Environment
2729 * pName [I] Servername or NULL (local Computer)
2730 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2731 * pMonitorName [I] Name of the Monitor, that should be deleted
2738 * pEnvironment is ignored in Windows for the local Computer.
2741 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2744 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2745 debugstr_w(pMonitorName
));
2747 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2749 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2753 /******************************************************************
2754 * DeletePortA [WINSPOOL.@]
2759 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2761 LPWSTR nameW
= NULL
;
2762 LPWSTR portW
= NULL
;
2766 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2768 /* convert servername to unicode */
2770 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2771 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2772 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2775 /* convert portname to unicode */
2777 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2778 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2779 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2782 res
= DeletePortW(nameW
, hWnd
, portW
);
2783 HeapFree(GetProcessHeap(), 0, nameW
);
2784 HeapFree(GetProcessHeap(), 0, portW
);
2788 /******************************************************************
2789 * DeletePortW [WINSPOOL.@]
2791 * Delete a specific Port
2794 * pName [I] Servername or NULL (local Computer)
2795 * hWnd [I] Handle to parent Window for the Dialog-Box
2796 * pPortName [I] Name of the Port, that should be deleted
2803 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2805 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2807 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2810 SetLastError(RPC_X_NULL_REF_POINTER
);
2814 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2817 /******************************************************************************
2818 * WritePrinter [WINSPOOL.@]
2820 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2822 opened_printer_t
*printer
;
2825 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2827 EnterCriticalSection(&printer_handles_cs
);
2828 printer
= get_opened_printer(hPrinter
);
2831 SetLastError(ERROR_INVALID_HANDLE
);
2837 SetLastError(ERROR_SPL_NO_STARTDOC
);
2841 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2843 LeaveCriticalSection(&printer_handles_cs
);
2847 /*****************************************************************************
2848 * AddFormA [WINSPOOL.@]
2850 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2852 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2856 /*****************************************************************************
2857 * AddFormW [WINSPOOL.@]
2859 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2861 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2865 /*****************************************************************************
2866 * AddJobA [WINSPOOL.@]
2868 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2871 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2875 SetLastError(ERROR_INVALID_LEVEL
);
2879 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2882 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2883 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2884 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2885 if(*pcbNeeded
> cbBuf
) {
2886 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2889 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2890 addjobA
->JobId
= addjobW
->JobId
;
2891 addjobA
->Path
= (char *)(addjobA
+ 1);
2892 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2898 /*****************************************************************************
2899 * AddJobW [WINSPOOL.@]
2901 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2903 opened_printer_t
*printer
;
2906 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2907 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2908 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2910 ADDJOB_INFO_1W
*addjob
;
2912 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2914 EnterCriticalSection(&printer_handles_cs
);
2916 printer
= get_opened_printer(hPrinter
);
2919 SetLastError(ERROR_INVALID_HANDLE
);
2924 SetLastError(ERROR_INVALID_LEVEL
);
2928 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2932 job
->job_id
= InterlockedIncrement(&next_job_id
);
2934 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2935 if(path
[len
- 1] != '\\')
2937 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2938 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2940 len
= strlenW(filename
);
2941 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2942 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2943 job
->portname
= NULL
;
2944 job
->document_title
= strdupW(default_doc_title
);
2945 job
->printer_name
= strdupW(printer
->name
);
2946 job
->devmode
= dup_devmode( printer
->devmode
);
2947 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2949 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2950 if(*pcbNeeded
<= cbBuf
) {
2951 addjob
= (ADDJOB_INFO_1W
*)pData
;
2952 addjob
->JobId
= job
->job_id
;
2953 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2954 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2957 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2960 LeaveCriticalSection(&printer_handles_cs
);
2964 /*****************************************************************************
2965 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2967 * Return the PATH for the Print-Processors
2969 * See GetPrintProcessorDirectoryW.
2973 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2974 DWORD level
, LPBYTE Info
,
2975 DWORD cbBuf
, LPDWORD pcbNeeded
)
2977 LPWSTR serverW
= NULL
;
2982 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2983 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2987 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2988 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2989 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2993 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2994 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2995 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2998 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2999 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3001 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
3004 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
3005 cbBuf
, NULL
, NULL
) > 0;
3008 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
3009 HeapFree(GetProcessHeap(), 0, envW
);
3010 HeapFree(GetProcessHeap(), 0, serverW
);
3014 /*****************************************************************************
3015 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3017 * Return the PATH for the Print-Processors
3020 * server [I] Servername (NT only) or NULL (local Computer)
3021 * env [I] Printing-Environment (see below) or NULL (Default)
3022 * level [I] Structure-Level (must be 1)
3023 * Info [O] PTR to Buffer that receives the Result
3024 * cbBuf [I] Size of Buffer at "Info"
3025 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3026 * required for the Buffer at "Info"
3029 * Success: TRUE and in pcbNeeded the Bytes used in Info
3030 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3031 * if cbBuf is too small
3033 * Native Values returned in Info on Success:
3034 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3035 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3036 *| win9x(Windows 4.0): "%winsysdir%"
3038 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3041 * Only NULL or "" is supported for server
3044 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
3045 DWORD level
, LPBYTE Info
,
3046 DWORD cbBuf
, LPDWORD pcbNeeded
)
3049 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
3050 Info
, cbBuf
, pcbNeeded
);
3052 if ((backend
== NULL
) && !load_backend()) return FALSE
;
3055 /* (Level != 1) is ignored in win9x */
3056 SetLastError(ERROR_INVALID_LEVEL
);
3060 if (pcbNeeded
== NULL
) {
3061 /* (pcbNeeded == NULL) is ignored in win9x */
3062 SetLastError(RPC_X_NULL_REF_POINTER
);
3066 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
3069 /*****************************************************************************
3070 * WINSPOOL_OpenDriverReg [internal]
3072 * opens the registry for the printer drivers depending on the given input
3073 * variable pEnvironment
3076 * the opened hkey on success
3079 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
3083 const printenv_t
* env
;
3085 TRACE("(%s)\n", debugstr_w(pEnvironment
));
3087 env
= validate_envW(pEnvironment
);
3088 if (!env
) return NULL
;
3090 buffer
= HeapAlloc( GetProcessHeap(), 0,
3091 (strlenW(DriversW
) + strlenW(env
->envname
) +
3092 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
3094 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
3095 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
3096 HeapFree(GetProcessHeap(), 0, buffer
);
3101 /*****************************************************************************
3102 * set_devices_and_printerports [internal]
3104 * set the [Devices] and [PrinterPorts] entries for a printer.
3107 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
3109 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
3113 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
3115 /* FIXME: the driver must change to "winspool" */
3116 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
3118 lstrcpyW(devline
, driver_nt
);
3119 lstrcatW(devline
, commaW
);
3120 lstrcatW(devline
, pi
->pPortName
);
3122 TRACE("using %s\n", debugstr_w(devline
));
3123 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
3124 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
3125 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3126 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3130 lstrcatW(devline
, timeout_15_45
);
3131 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
3132 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
3133 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3134 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3137 HeapFree(GetProcessHeap(), 0, devline
);
3141 /*****************************************************************************
3142 * AddPrinterW [WINSPOOL.@]
3144 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3146 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
3149 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
3152 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
3155 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
3156 SetLastError(ERROR_INVALID_PARAMETER
);
3160 ERR("Level = %d, unsupported!\n", Level
);
3161 SetLastError(ERROR_INVALID_LEVEL
);
3165 SetLastError(ERROR_INVALID_PARAMETER
);
3168 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3170 ERR("Can't create Printers key\n");
3173 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3174 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
3175 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3176 RegCloseKey(hkeyPrinter
);
3177 RegCloseKey(hkeyPrinters
);
3180 RegCloseKey(hkeyPrinter
);
3182 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
3184 ERR("Can't create Drivers key\n");
3185 RegCloseKey(hkeyPrinters
);
3188 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3190 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3191 RegCloseKey(hkeyPrinters
);
3192 RegCloseKey(hkeyDrivers
);
3193 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3196 RegCloseKey(hkeyDriver
);
3197 RegCloseKey(hkeyDrivers
);
3199 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3200 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3201 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3202 RegCloseKey(hkeyPrinters
);
3206 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3208 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3209 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3210 RegCloseKey(hkeyPrinters
);
3214 set_devices_and_printerports(pi
);
3216 set_reg_DWORD(hkeyPrinter
, AttributesW
, pi
->Attributes
);
3217 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3218 set_reg_DWORD(hkeyPrinter
, Default_PriorityW
, pi
->DefaultPriority
);
3219 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3220 set_reg_DWORD(hkeyPrinter
, dnsTimeoutW
, 0);
3221 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3222 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3223 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3224 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3225 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3226 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3227 set_reg_DWORD(hkeyPrinter
, PriorityW
, pi
->Priority
);
3228 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3229 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3230 set_reg_DWORD(hkeyPrinter
, StartTimeW
, pi
->StartTime
);
3231 set_reg_DWORD(hkeyPrinter
, StatusW
, pi
->Status
);
3232 set_reg_DWORD(hkeyPrinter
, txTimeoutW
, 0);
3233 set_reg_DWORD(hkeyPrinter
, UntilTimeW
, pi
->UntilTime
);
3235 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3239 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3240 size
= sizeof(DEVMODEW
);
3246 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3248 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
3250 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3251 HeapFree( GetProcessHeap(), 0, dm
);
3256 /* set devmode to printer name */
3257 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3261 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
3262 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
3264 RegCloseKey(hkeyPrinter
);
3265 RegCloseKey(hkeyPrinters
);
3266 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3267 ERR("OpenPrinter failing\n");
3273 /*****************************************************************************
3274 * AddPrinterA [WINSPOOL.@]
3276 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3278 UNICODE_STRING pNameW
;
3280 PRINTER_INFO_2W
*piW
;
3281 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3284 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
3286 ERR("Level = %d, unsupported!\n", Level
);
3287 SetLastError(ERROR_INVALID_LEVEL
);
3290 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3291 piW
= printer_info_AtoW( piA
, Level
);
3293 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3295 free_printer_info( piW
, Level
);
3296 RtlFreeUnicodeString(&pNameW
);
3301 /*****************************************************************************
3302 * ClosePrinter [WINSPOOL.@]
3304 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3306 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3307 opened_printer_t
*printer
= NULL
;
3310 TRACE("(%p)\n", hPrinter
);
3312 EnterCriticalSection(&printer_handles_cs
);
3314 if ((i
> 0) && (i
<= nb_printer_handles
))
3315 printer
= printer_handles
[i
- 1];
3320 struct list
*cursor
, *cursor2
;
3322 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
3324 if (printer
->backend_printer
) {
3325 backend
->fpClosePrinter(printer
->backend_printer
);
3329 EndDocPrinter(hPrinter
);
3331 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3333 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3335 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3336 ScheduleJob(hPrinter
, job
->job_id
);
3338 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3341 free_printer_entry( printer
);
3342 printer_handles
[i
- 1] = NULL
;
3345 LeaveCriticalSection(&printer_handles_cs
);
3349 /*****************************************************************************
3350 * DeleteFormA [WINSPOOL.@]
3352 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3354 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3358 /*****************************************************************************
3359 * DeleteFormW [WINSPOOL.@]
3361 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3363 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3367 /*****************************************************************************
3368 * DeletePrinter [WINSPOOL.@]
3370 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3372 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3373 HKEY hkeyPrinters
, hkey
;
3374 WCHAR def
[MAX_PATH
];
3375 DWORD size
= sizeof( def
) / sizeof( def
[0] );
3378 SetLastError(ERROR_INVALID_HANDLE
);
3381 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3382 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3383 RegCloseKey(hkeyPrinters
);
3385 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3386 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
3388 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3389 RegDeleteValueW(hkey
, lpNameW
);
3393 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3394 RegDeleteValueW(hkey
, lpNameW
);
3398 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
3400 WriteProfileStringW( windowsW
, deviceW
, NULL
);
3401 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
3403 RegDeleteValueW( hkey
, deviceW
);
3404 RegCloseKey( hkey
);
3406 SetDefaultPrinterW( NULL
);
3412 /*****************************************************************************
3413 * SetPrinterA [WINSPOOL.@]
3415 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3422 dataW
= printer_info_AtoW( data
, level
);
3423 if (!dataW
) return FALSE
;
3426 ret
= SetPrinterW( printer
, level
, dataW
, command
);
3428 if (dataW
!= data
) free_printer_info( dataW
, level
);
3433 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
3435 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
3436 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
3437 set_reg_szW( key
, PortW
, pi
->pPortName
);
3438 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
3439 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
3440 set_reg_szW( key
, LocationW
, pi
->pLocation
);
3443 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3445 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
3446 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
3447 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
3448 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
3450 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
3451 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
3452 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
3453 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
3454 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
3457 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
3459 if (!pi
->pDevMode
) return FALSE
;
3461 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3465 /******************************************************************************
3466 * SetPrinterW [WINSPOOL.@]
3468 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3473 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
3475 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
3477 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
3484 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
3485 set_printer_2( key
, pi2
);
3492 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
3493 ret
= set_printer_9( key
, pi
);
3498 FIXME( "Unimplemented level %d\n", level
);
3499 SetLastError( ERROR_INVALID_LEVEL
);
3506 /*****************************************************************************
3507 * SetJobA [WINSPOOL.@]
3509 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3510 LPBYTE pJob
, DWORD Command
)
3514 UNICODE_STRING usBuffer
;
3516 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3518 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3519 are all ignored by SetJob, so we don't bother copying them */
3527 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3528 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3530 JobW
= (LPBYTE
)info1W
;
3531 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3532 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3533 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3534 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3535 info1W
->Status
= info1A
->Status
;
3536 info1W
->Priority
= info1A
->Priority
;
3537 info1W
->Position
= info1A
->Position
;
3538 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3543 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3544 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3546 JobW
= (LPBYTE
)info2W
;
3547 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3548 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3549 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3550 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3551 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3552 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3553 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3554 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3555 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3556 info2W
->Status
= info2A
->Status
;
3557 info2W
->Priority
= info2A
->Priority
;
3558 info2W
->Position
= info2A
->Position
;
3559 info2W
->StartTime
= info2A
->StartTime
;
3560 info2W
->UntilTime
= info2A
->UntilTime
;
3561 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3565 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3566 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3569 SetLastError(ERROR_INVALID_LEVEL
);
3573 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3579 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3580 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3581 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3582 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3583 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3588 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3589 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3590 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3591 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3592 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3593 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3594 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3595 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3596 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3600 HeapFree(GetProcessHeap(), 0, JobW
);
3605 /*****************************************************************************
3606 * SetJobW [WINSPOOL.@]
3608 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3609 LPBYTE pJob
, DWORD Command
)
3614 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3615 FIXME("Ignoring everything other than document title\n");
3617 EnterCriticalSection(&printer_handles_cs
);
3618 job
= get_job(hPrinter
, JobId
);
3628 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3629 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3630 job
->document_title
= strdupW(info1
->pDocument
);
3635 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3636 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3637 job
->document_title
= strdupW(info2
->pDocument
);
3638 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3639 job
->devmode
= dup_devmode( info2
->pDevMode
);
3645 SetLastError(ERROR_INVALID_LEVEL
);
3650 LeaveCriticalSection(&printer_handles_cs
);
3654 /*****************************************************************************
3655 * EndDocPrinter [WINSPOOL.@]
3657 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3659 opened_printer_t
*printer
;
3661 TRACE("(%p)\n", hPrinter
);
3663 EnterCriticalSection(&printer_handles_cs
);
3665 printer
= get_opened_printer(hPrinter
);
3668 SetLastError(ERROR_INVALID_HANDLE
);
3674 SetLastError(ERROR_SPL_NO_STARTDOC
);
3678 CloseHandle(printer
->doc
->hf
);
3679 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3680 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3681 printer
->doc
= NULL
;
3684 LeaveCriticalSection(&printer_handles_cs
);
3688 /*****************************************************************************
3689 * EndPagePrinter [WINSPOOL.@]
3691 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3693 FIXME("(%p): stub\n", hPrinter
);
3697 /*****************************************************************************
3698 * StartDocPrinterA [WINSPOOL.@]
3700 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3702 UNICODE_STRING usBuffer
;
3704 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3707 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3708 or one (DOC_INFO_3) extra DWORDs */
3712 doc2W
.JobId
= doc2
->JobId
;
3715 doc2W
.dwMode
= doc2
->dwMode
;
3718 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3719 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3720 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3724 SetLastError(ERROR_INVALID_LEVEL
);
3728 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3730 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3731 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3732 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3737 /*****************************************************************************
3738 * StartDocPrinterW [WINSPOOL.@]
3740 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3742 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3743 opened_printer_t
*printer
;
3744 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3745 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3746 JOB_INFO_1W job_info
;
3747 DWORD needed
, ret
= 0;
3752 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3753 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3754 debugstr_w(doc
->pDatatype
));
3756 if(Level
< 1 || Level
> 3)
3758 SetLastError(ERROR_INVALID_LEVEL
);
3762 EnterCriticalSection(&printer_handles_cs
);
3763 printer
= get_opened_printer(hPrinter
);
3766 SetLastError(ERROR_INVALID_HANDLE
);
3772 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3776 /* Even if we're printing to a file we still add a print job, we'll
3777 just ignore the spool file name */
3779 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3781 ERR("AddJob failed gle %u\n", GetLastError());
3785 /* use pOutputFile only, when it is a real filename */
3786 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3787 filename
= doc
->pOutputFile
;
3789 filename
= addjob
->Path
;
3791 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3792 if(hf
== INVALID_HANDLE_VALUE
)
3795 memset(&job_info
, 0, sizeof(job_info
));
3796 job_info
.pDocument
= doc
->pDocName
;
3797 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3799 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3800 printer
->doc
->hf
= hf
;
3801 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3802 job
= get_job(hPrinter
, ret
);
3803 job
->portname
= strdupW(doc
->pOutputFile
);
3806 LeaveCriticalSection(&printer_handles_cs
);
3811 /*****************************************************************************
3812 * StartPagePrinter [WINSPOOL.@]
3814 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3816 FIXME("(%p): stub\n", hPrinter
);
3820 /*****************************************************************************
3821 * GetFormA [WINSPOOL.@]
3823 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3824 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3826 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3827 Level
,pForm
,cbBuf
,pcbNeeded
);
3831 /*****************************************************************************
3832 * GetFormW [WINSPOOL.@]
3834 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3835 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3837 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3838 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3842 /*****************************************************************************
3843 * SetFormA [WINSPOOL.@]
3845 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3848 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3852 /*****************************************************************************
3853 * SetFormW [WINSPOOL.@]
3855 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3858 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3862 /*****************************************************************************
3863 * ReadPrinter [WINSPOOL.@]
3865 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3866 LPDWORD pNoBytesRead
)
3868 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3872 /*****************************************************************************
3873 * ResetPrinterA [WINSPOOL.@]
3875 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3877 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3881 /*****************************************************************************
3882 * ResetPrinterW [WINSPOOL.@]
3884 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3886 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3890 /*****************************************************************************
3891 * get_filename_from_reg [internal]
3893 * Get ValueName from hkey storing result in out
3894 * when the Value in the registry has only a filename, use driverdir as prefix
3895 * outlen is space left in out
3896 * String is stored either as unicode or ascii
3900 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3901 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3903 WCHAR filename
[MAX_PATH
];
3907 LPWSTR buffer
= filename
;
3911 size
= sizeof(filename
);
3913 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3914 if (ret
== ERROR_MORE_DATA
) {
3915 TRACE("need dynamic buffer: %u\n", size
);
3916 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3918 /* No Memory is bad */
3922 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3925 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3926 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3932 /* do we have a full path ? */
3933 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3934 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3937 /* we must build the full Path */
3939 if ((out
) && (outlen
> dirlen
)) {
3940 lstrcpyW((LPWSTR
)out
, driverdir
);
3948 /* write the filename */
3949 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3950 if ((out
) && (outlen
>= size
)) {
3951 lstrcpyW((LPWSTR
)out
, ptr
);
3958 ptr
+= lstrlenW(ptr
)+1;
3959 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3962 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3964 /* write the multisz-termination */
3965 if (type
== REG_MULTI_SZ
) {
3966 size
= sizeof(WCHAR
);
3969 if (out
&& (outlen
>= size
)) {
3970 memset (out
, 0, size
);
3976 /*****************************************************************************
3977 * WINSPOOL_GetStringFromReg
3979 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3980 * String is stored as unicode.
3982 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3983 DWORD buflen
, DWORD
*needed
)
3985 DWORD sz
= buflen
, type
;
3988 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3989 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3990 WARN("Got ret = %d\n", ret
);
3994 /* add space for terminating '\0' */
3995 sz
+= sizeof(WCHAR
);
3999 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
4004 /*****************************************************************************
4005 * WINSPOOL_GetDefaultDevMode
4007 * Get a default DevMode values for wineps.
4009 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr
, DWORD buflen
, DWORD
*needed
)
4011 static const WCHAR winepsW
[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4013 if (buflen
>= sizeof(DEVMODEW
))
4015 DEVMODEW
*dm
= (DEVMODEW
*)ptr
;
4017 /* the driver will update registry with real values */
4018 memset(dm
, 0, sizeof(*dm
));
4019 dm
->dmSize
= sizeof(*dm
);
4020 lstrcpyW(dm
->dmDeviceName
, winepsW
);
4022 *needed
= sizeof(DEVMODEW
);
4025 /*****************************************************************************
4026 * WINSPOOL_GetDevModeFromReg
4028 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4029 * DevMode is stored either as unicode or ascii.
4031 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
4033 DWORD buflen
, DWORD
*needed
)
4035 DWORD sz
= buflen
, type
;
4038 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
4039 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4040 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
4041 if (sz
< sizeof(DEVMODEA
))
4043 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
4046 /* ensures that dmSize is not erratically bogus if registry is invalid */
4047 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
4048 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
4049 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
4050 if (ptr
&& (buflen
>= sz
)) {
4051 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
4052 memcpy(ptr
, dmW
, sz
);
4053 HeapFree(GetProcessHeap(),0,dmW
);
4059 /*********************************************************************
4060 * WINSPOOL_GetPrinter_1
4062 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4064 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
4065 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4067 DWORD size
, left
= cbBuf
;
4068 BOOL space
= (cbBuf
> 0);
4073 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4074 if(space
&& size
<= left
) {
4075 pi1
->pName
= (LPWSTR
)ptr
;
4083 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4084 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4085 if(space
&& size
<= left
) {
4086 pi1
->pDescription
= (LPWSTR
)ptr
;
4094 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4095 if(space
&& size
<= left
) {
4096 pi1
->pComment
= (LPWSTR
)ptr
;
4104 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
4106 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
4107 memset(pi1
, 0, sizeof(*pi1
));
4111 /*********************************************************************
4112 * WINSPOOL_GetPrinter_2
4114 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4116 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
4117 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4119 DWORD size
, left
= cbBuf
;
4120 BOOL space
= (cbBuf
> 0);
4125 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4126 if(space
&& size
<= left
) {
4127 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4134 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
4135 if(space
&& size
<= left
) {
4136 pi2
->pShareName
= (LPWSTR
)ptr
;
4143 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4144 if(space
&& size
<= left
) {
4145 pi2
->pPortName
= (LPWSTR
)ptr
;
4152 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
4153 if(space
&& size
<= left
) {
4154 pi2
->pDriverName
= (LPWSTR
)ptr
;
4161 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4162 if(space
&& size
<= left
) {
4163 pi2
->pComment
= (LPWSTR
)ptr
;
4170 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
4171 if(space
&& size
<= left
) {
4172 pi2
->pLocation
= (LPWSTR
)ptr
;
4179 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
4180 if(space
&& size
<= left
) {
4181 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4190 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
4191 if(space
&& size
<= left
) {
4192 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4199 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
4200 if(space
&& size
<= left
) {
4201 pi2
->pSepFile
= (LPWSTR
)ptr
;
4208 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
4209 if(space
&& size
<= left
) {
4210 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4217 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
4218 if(space
&& size
<= left
) {
4219 pi2
->pDatatype
= (LPWSTR
)ptr
;
4226 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
4227 if(space
&& size
<= left
) {
4228 pi2
->pParameters
= (LPWSTR
)ptr
;
4236 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4237 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
4238 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
4239 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
4240 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
4243 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4244 memset(pi2
, 0, sizeof(*pi2
));
4249 /*********************************************************************
4250 * WINSPOOL_GetPrinter_4
4252 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4254 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4255 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4257 DWORD size
, left
= cbBuf
;
4258 BOOL space
= (cbBuf
> 0);
4263 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4264 if(space
&& size
<= left
) {
4265 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4273 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4276 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4277 memset(pi4
, 0, sizeof(*pi4
));
4282 /*********************************************************************
4283 * WINSPOOL_GetPrinter_5
4285 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4287 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4288 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4290 DWORD size
, left
= cbBuf
;
4291 BOOL space
= (cbBuf
> 0);
4296 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4297 if(space
&& size
<= left
) {
4298 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4305 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4306 if(space
&& size
<= left
) {
4307 pi5
->pPortName
= (LPWSTR
)ptr
;
4315 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4316 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
4317 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
4320 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4321 memset(pi5
, 0, sizeof(*pi5
));
4326 /*********************************************************************
4327 * WINSPOOL_GetPrinter_7
4329 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4331 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4332 DWORD cbBuf
, LPDWORD pcbNeeded
)
4334 DWORD size
, left
= cbBuf
;
4335 BOOL space
= (cbBuf
> 0);
4340 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
4343 size
= sizeof(pi7
->pszObjectGUID
);
4345 if (space
&& size
<= left
) {
4346 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4353 /* We do not have a Directory Service */
4354 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4357 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4358 memset(pi7
, 0, sizeof(*pi7
));
4363 /*********************************************************************
4364 * WINSPOOL_GetPrinter_9
4366 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4368 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4369 DWORD cbBuf
, LPDWORD pcbNeeded
)
4372 BOOL space
= (cbBuf
> 0);
4376 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
4377 if(space
&& size
<= cbBuf
) {
4378 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4385 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
4386 if(space
&& size
<= cbBuf
) {
4387 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4393 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4394 memset(pi9
, 0, sizeof(*pi9
));
4399 /*****************************************************************************
4400 * GetPrinterW [WINSPOOL.@]
4402 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4403 DWORD cbBuf
, LPDWORD pcbNeeded
)
4405 DWORD size
, needed
= 0, err
;
4410 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4412 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
4415 SetLastError( err
);
4422 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4424 size
= sizeof(PRINTER_INFO_2W
);
4426 ptr
= pPrinter
+ size
;
4428 memset(pPrinter
, 0, size
);
4433 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
4440 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4442 size
= sizeof(PRINTER_INFO_4W
);
4444 ptr
= pPrinter
+ size
;
4446 memset(pPrinter
, 0, size
);
4451 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
4459 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4461 size
= sizeof(PRINTER_INFO_5W
);
4463 ptr
= pPrinter
+ size
;
4465 memset(pPrinter
, 0, size
);
4471 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4479 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4481 size
= sizeof(PRINTER_INFO_6
);
4482 if (size
<= cbBuf
) {
4483 /* FIXME: We do not update the status yet */
4484 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4496 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4498 size
= sizeof(PRINTER_INFO_7W
);
4499 if (size
<= cbBuf
) {
4500 ptr
= pPrinter
+ size
;
4502 memset(pPrinter
, 0, size
);
4508 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4515 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4516 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4520 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4522 size
= sizeof(PRINTER_INFO_9W
);
4524 ptr
= pPrinter
+ size
;
4526 memset(pPrinter
, 0, size
);
4532 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4539 FIXME("Unimplemented level %d\n", Level
);
4540 SetLastError(ERROR_INVALID_LEVEL
);
4541 RegCloseKey(hkeyPrinter
);
4545 RegCloseKey(hkeyPrinter
);
4547 TRACE("returning %d needed = %d\n", ret
, needed
);
4548 if(pcbNeeded
) *pcbNeeded
= needed
;
4550 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4554 /*****************************************************************************
4555 * GetPrinterA [WINSPOOL.@]
4557 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4558 DWORD cbBuf
, LPDWORD pcbNeeded
)
4564 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4566 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4568 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4569 HeapFree(GetProcessHeap(), 0, buf
);
4574 /*****************************************************************************
4575 * WINSPOOL_EnumPrintersW
4577 * Implementation of EnumPrintersW
4579 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4580 DWORD dwLevel
, LPBYTE lpbPrinters
,
4581 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4582 LPDWORD lpdwReturned
)
4585 HKEY hkeyPrinters
, hkeyPrinter
;
4586 WCHAR PrinterName
[255];
4587 DWORD needed
= 0, number
= 0;
4588 DWORD used
, i
, left
;
4592 memset(lpbPrinters
, 0, cbBuf
);
4598 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4599 if(dwType
== PRINTER_ENUM_DEFAULT
)
4602 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4603 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4604 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4606 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4612 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4613 FIXME("dwType = %08x\n", dwType
);
4614 SetLastError(ERROR_INVALID_FLAGS
);
4618 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4620 ERR("Can't create Printers key\n");
4624 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4625 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4626 RegCloseKey(hkeyPrinters
);
4627 ERR("Can't query Printers key\n");
4630 TRACE("Found %d printers\n", number
);
4634 used
= number
* sizeof(PRINTER_INFO_1W
);
4637 used
= number
* sizeof(PRINTER_INFO_2W
);
4640 used
= number
* sizeof(PRINTER_INFO_4W
);
4643 used
= number
* sizeof(PRINTER_INFO_5W
);
4647 SetLastError(ERROR_INVALID_LEVEL
);
4648 RegCloseKey(hkeyPrinters
);
4651 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4653 for(i
= 0; i
< number
; i
++) {
4654 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4656 ERR("Can't enum key number %d\n", i
);
4657 RegCloseKey(hkeyPrinters
);
4660 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4661 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4663 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4664 RegCloseKey(hkeyPrinters
);
4669 buf
= lpbPrinters
+ used
;
4670 left
= cbBuf
- used
;
4678 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4681 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4684 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4687 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4690 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4693 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4696 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4699 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4702 ERR("Shouldn't be here!\n");
4703 RegCloseKey(hkeyPrinter
);
4704 RegCloseKey(hkeyPrinters
);
4707 RegCloseKey(hkeyPrinter
);
4709 RegCloseKey(hkeyPrinters
);
4716 memset(lpbPrinters
, 0, cbBuf
);
4717 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4721 *lpdwReturned
= number
;
4722 SetLastError(ERROR_SUCCESS
);
4727 /******************************************************************
4728 * EnumPrintersW [WINSPOOL.@]
4730 * Enumerates the available printers, print servers and print
4731 * providers, depending on the specified flags, name and level.
4735 * If level is set to 1:
4736 * Returns an array of PRINTER_INFO_1 data structures in the
4737 * lpbPrinters buffer.
4739 * If level is set to 2:
4740 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4741 * Returns an array of PRINTER_INFO_2 data structures in the
4742 * lpbPrinters buffer. Note that according to MSDN also an
4743 * OpenPrinter should be performed on every remote printer.
4745 * If level is set to 4 (officially WinNT only):
4746 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4747 * Fast: Only the registry is queried to retrieve printer names,
4748 * no connection to the driver is made.
4749 * Returns an array of PRINTER_INFO_4 data structures in the
4750 * lpbPrinters buffer.
4752 * If level is set to 5 (officially WinNT4/Win9x only):
4753 * Fast: Only the registry is queried to retrieve printer names,
4754 * no connection to the driver is made.
4755 * Returns an array of PRINTER_INFO_5 data structures in the
4756 * lpbPrinters buffer.
4758 * If level set to 3 or 6+:
4759 * returns zero (failure!)
4761 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4765 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4766 * - Only levels 2, 4 and 5 are implemented at the moment.
4767 * - 16-bit printer drivers are not enumerated.
4768 * - Returned amount of bytes used/needed does not match the real Windoze
4769 * implementation (as in this implementation, all strings are part
4770 * of the buffer, whereas Win32 keeps them somewhere else)
4771 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4774 * - In a regular Wine installation, no registry settings for printers
4775 * exist, which makes this function return an empty list.
4777 BOOL WINAPI
EnumPrintersW(
4778 DWORD dwType
, /* [in] Types of print objects to enumerate */
4779 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4780 DWORD dwLevel
, /* [in] type of printer info structure */
4781 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4782 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4783 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4784 LPDWORD lpdwReturned
/* [out] number of entries returned */
4787 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4788 lpdwNeeded
, lpdwReturned
);
4791 /******************************************************************
4792 * EnumPrintersA [WINSPOOL.@]
4797 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4798 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4801 UNICODE_STRING pNameU
;
4805 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4806 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4808 pNameW
= asciitounicode(&pNameU
, pName
);
4810 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4811 MS Office need this */
4812 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4814 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4816 RtlFreeUnicodeString(&pNameU
);
4818 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4820 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4824 /*****************************************************************************
4825 * WINSPOOL_GetDriverInfoFromReg [internal]
4827 * Enters the information from the registry into the DRIVER_INFO struct
4830 * zero if the printer driver does not exist in the registry
4831 * (only if Level > 1) otherwise nonzero
4833 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4836 const printenv_t
* env
,
4838 LPBYTE ptr
, /* DRIVER_INFO */
4839 LPBYTE pDriverStrings
, /* strings buffer */
4840 DWORD cbBuf
, /* size of string buffer */
4841 LPDWORD pcbNeeded
) /* space needed for str. */
4845 WCHAR driverdir
[MAX_PATH
];
4847 LPBYTE strPtr
= pDriverStrings
;
4848 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4850 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4851 debugstr_w(DriverName
), env
,
4852 Level
, di
, pDriverStrings
, cbBuf
);
4854 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4856 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4857 if (*pcbNeeded
<= cbBuf
)
4858 strcpyW((LPWSTR
)strPtr
, DriverName
);
4860 /* pName for level 1 has a different offset! */
4862 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4866 /* .cVersion and .pName for level > 1 */
4868 di
->cVersion
= env
->driverversion
;
4869 di
->pName
= (LPWSTR
) strPtr
;
4870 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4873 /* Reserve Space for the largest subdir and a Backslash*/
4874 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4875 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4876 /* Should never Fail */
4879 lstrcatW(driverdir
, env
->versionsubdir
);
4880 lstrcatW(driverdir
, backslashW
);
4882 /* dirlen must not include the terminating zero */
4883 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4885 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4886 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4887 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4892 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4895 if (*pcbNeeded
<= cbBuf
) {
4896 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4897 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4898 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4901 /* .pDriverPath is the Graphics rendering engine.
4902 The full Path is required to avoid a crash in some apps */
4903 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4905 if (*pcbNeeded
<= cbBuf
)
4906 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4908 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4909 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4912 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4913 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4915 if (*pcbNeeded
<= cbBuf
)
4916 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4918 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4919 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4922 /* .pConfigFile is the Driver user Interface */
4923 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4925 if (*pcbNeeded
<= cbBuf
)
4926 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4928 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4929 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4933 RegCloseKey(hkeyDriver
);
4934 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4939 RegCloseKey(hkeyDriver
);
4940 FIXME("level 5: incomplete\n");
4945 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4947 if (*pcbNeeded
<= cbBuf
)
4948 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4950 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4951 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4954 /* .pDependentFiles */
4955 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4957 if (*pcbNeeded
<= cbBuf
)
4958 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4960 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4961 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4963 else if (GetVersion() & 0x80000000) {
4964 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4965 size
= 2 * sizeof(WCHAR
);
4967 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4969 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4970 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4973 /* .pMonitorName is the optional Language Monitor */
4974 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4976 if (*pcbNeeded
<= cbBuf
)
4977 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4979 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4980 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4983 /* .pDefaultDataType */
4984 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4986 if(*pcbNeeded
<= cbBuf
)
4987 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4989 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4990 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4994 RegCloseKey(hkeyDriver
);
4995 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4999 /* .pszzPreviousNames */
5000 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
5002 if(*pcbNeeded
<= cbBuf
)
5003 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
5005 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
5006 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5010 RegCloseKey(hkeyDriver
);
5011 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5015 /* support is missing, but not important enough for a FIXME */
5016 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
5019 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
5021 if(*pcbNeeded
<= cbBuf
)
5022 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
5024 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
5025 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5029 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
5031 if(*pcbNeeded
<= cbBuf
)
5032 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
5034 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
5035 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5038 /* .pszHardwareID */
5039 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
5041 if(*pcbNeeded
<= cbBuf
)
5042 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
5044 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
5045 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5049 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
5051 if(*pcbNeeded
<= cbBuf
)
5052 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
5054 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
5055 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5059 RegCloseKey(hkeyDriver
);
5063 /* support is missing, but not important enough for a FIXME */
5064 TRACE("level 8: incomplete\n");
5066 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5067 RegCloseKey(hkeyDriver
);
5071 /*****************************************************************************
5072 * GetPrinterDriverW [WINSPOOL.@]
5074 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5075 DWORD Level
, LPBYTE pDriverInfo
,
5076 DWORD cbBuf
, LPDWORD pcbNeeded
)
5079 WCHAR DriverName
[100];
5080 DWORD ret
, type
, size
, needed
= 0;
5082 HKEY hkeyPrinter
, hkeyDrivers
;
5083 const printenv_t
* env
;
5085 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
5086 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
5089 ZeroMemory(pDriverInfo
, cbBuf
);
5091 if (!(name
= get_opened_printer_name(hPrinter
))) {
5092 SetLastError(ERROR_INVALID_HANDLE
);
5096 if (Level
< 1 || Level
== 7 || Level
> 8) {
5097 SetLastError(ERROR_INVALID_LEVEL
);
5101 env
= validate_envW(pEnvironment
);
5102 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5104 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
5107 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
5108 SetLastError( ret
);
5112 size
= sizeof(DriverName
);
5114 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5115 (LPBYTE
)DriverName
, &size
);
5116 RegCloseKey(hkeyPrinter
);
5117 if(ret
!= ERROR_SUCCESS
) {
5118 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5122 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5124 ERR("Can't create Drivers key\n");
5128 size
= di_sizeof
[Level
];
5129 if ((size
<= cbBuf
) && pDriverInfo
)
5130 ptr
= pDriverInfo
+ size
;
5132 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5133 env
, Level
, pDriverInfo
, ptr
,
5134 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5136 RegCloseKey(hkeyDrivers
);
5140 RegCloseKey(hkeyDrivers
);
5142 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5143 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5144 if(cbBuf
>= size
+ needed
) return TRUE
;
5145 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5149 /*****************************************************************************
5150 * GetPrinterDriverA [WINSPOOL.@]
5152 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5153 DWORD Level
, LPBYTE pDriverInfo
,
5154 DWORD cbBuf
, LPDWORD pcbNeeded
)
5157 UNICODE_STRING pEnvW
;
5163 ZeroMemory(pDriverInfo
, cbBuf
);
5164 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5167 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5168 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5171 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5173 HeapFree(GetProcessHeap(), 0, buf
);
5175 RtlFreeUnicodeString(&pEnvW
);
5179 /*****************************************************************************
5180 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5182 * Return the PATH for the Printer-Drivers (UNICODE)
5185 * pName [I] Servername (NT only) or NULL (local Computer)
5186 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5187 * Level [I] Structure-Level (must be 1)
5188 * pDriverDirectory [O] PTR to Buffer that receives the Result
5189 * cbBuf [I] Size of Buffer at pDriverDirectory
5190 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5191 * required for pDriverDirectory
5194 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5195 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5196 * if cbBuf is too small
5198 * Native Values returned in pDriverDirectory on Success:
5199 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5200 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5201 *| win9x(Windows 4.0): "%winsysdir%"
5203 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5206 *- Only NULL or "" is supported for pName
5209 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5210 DWORD Level
, LPBYTE pDriverDirectory
,
5211 DWORD cbBuf
, LPDWORD pcbNeeded
)
5213 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5214 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5216 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5219 /* (Level != 1) is ignored in win9x */
5220 SetLastError(ERROR_INVALID_LEVEL
);
5223 if (pcbNeeded
== NULL
) {
5224 /* (pcbNeeded == NULL) is ignored in win9x */
5225 SetLastError(RPC_X_NULL_REF_POINTER
);
5229 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5230 pDriverDirectory
, cbBuf
, pcbNeeded
);
5235 /*****************************************************************************
5236 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5238 * Return the PATH for the Printer-Drivers (ANSI)
5240 * See GetPrinterDriverDirectoryW.
5243 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5246 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5247 DWORD Level
, LPBYTE pDriverDirectory
,
5248 DWORD cbBuf
, LPDWORD pcbNeeded
)
5250 UNICODE_STRING nameW
, environmentW
;
5253 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5254 WCHAR
*driverDirectoryW
= NULL
;
5256 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5257 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5259 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5261 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5262 else nameW
.Buffer
= NULL
;
5263 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5264 else environmentW
.Buffer
= NULL
;
5266 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5267 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5270 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5271 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5273 *pcbNeeded
= needed
;
5274 ret
= needed
<= cbBuf
;
5276 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5278 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5280 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5281 RtlFreeUnicodeString(&environmentW
);
5282 RtlFreeUnicodeString(&nameW
);
5287 /*****************************************************************************
5288 * AddPrinterDriverA [WINSPOOL.@]
5290 * See AddPrinterDriverW.
5293 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5295 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5296 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5299 /******************************************************************************
5300 * AddPrinterDriverW (WINSPOOL.@)
5302 * Install a Printer Driver
5305 * pName [I] Servername or NULL (local Computer)
5306 * level [I] Level for the supplied DRIVER_INFO_*W struct
5307 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5314 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5316 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5317 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5320 /*****************************************************************************
5321 * AddPrintProcessorA [WINSPOOL.@]
5323 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5324 LPSTR pPrintProcessorName
)
5326 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5327 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5331 /*****************************************************************************
5332 * AddPrintProcessorW [WINSPOOL.@]
5334 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5335 LPWSTR pPrintProcessorName
)
5337 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5338 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5342 /*****************************************************************************
5343 * AddPrintProvidorA [WINSPOOL.@]
5345 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5347 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5351 /*****************************************************************************
5352 * AddPrintProvidorW [WINSPOOL.@]
5354 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5356 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5360 /*****************************************************************************
5361 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5363 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5364 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5366 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5367 pDevModeOutput
, pDevModeInput
);
5371 /*****************************************************************************
5372 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5374 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5375 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5377 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5378 pDevModeOutput
, pDevModeInput
);
5382 /*****************************************************************************
5383 * PrinterProperties [WINSPOOL.@]
5385 * Displays a dialog to set the properties of the printer.
5388 * nonzero on success or zero on failure
5391 * implemented as stub only
5393 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5394 HANDLE hPrinter
/* [in] handle to printer object */
5396 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5397 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5401 /*****************************************************************************
5402 * EnumJobsA [WINSPOOL.@]
5405 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5406 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5409 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5410 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5412 if(pcbNeeded
) *pcbNeeded
= 0;
5413 if(pcReturned
) *pcReturned
= 0;
5418 /*****************************************************************************
5419 * EnumJobsW [WINSPOOL.@]
5422 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5423 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5426 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5427 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5429 if(pcbNeeded
) *pcbNeeded
= 0;
5430 if(pcReturned
) *pcReturned
= 0;
5434 /*****************************************************************************
5435 * WINSPOOL_EnumPrinterDrivers [internal]
5437 * Delivers information about all printer drivers installed on the
5438 * localhost or a given server
5441 * nonzero on success or zero on failure. If the buffer for the returned
5442 * information is too small the function will return an error
5445 * - only implemented for localhost, foreign hosts will return an error
5447 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5448 DWORD Level
, LPBYTE pDriverInfo
,
5450 DWORD cbBuf
, LPDWORD pcbNeeded
,
5451 LPDWORD pcFound
, DWORD data_offset
)
5455 const printenv_t
* env
;
5457 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5458 debugstr_w(pName
), debugstr_w(pEnvironment
),
5459 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5461 env
= validate_envW(pEnvironment
);
5462 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5466 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5468 ERR("Can't open Drivers key\n");
5472 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5473 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5474 RegCloseKey(hkeyDrivers
);
5475 ERR("Can't query Drivers key\n");
5478 TRACE("Found %d Drivers\n", *pcFound
);
5480 /* get size of single struct
5481 * unicode and ascii structure have the same size
5483 size
= di_sizeof
[Level
];
5485 if (data_offset
== 0)
5486 data_offset
= size
* (*pcFound
);
5487 *pcbNeeded
= data_offset
;
5489 for( i
= 0; i
< *pcFound
; i
++) {
5490 WCHAR DriverNameW
[255];
5491 PBYTE table_ptr
= NULL
;
5492 PBYTE data_ptr
= NULL
;
5495 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5497 ERR("Can't enum key number %d\n", i
);
5498 RegCloseKey(hkeyDrivers
);
5502 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5503 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5504 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5505 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5507 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5508 env
, Level
, table_ptr
, data_ptr
,
5509 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5511 RegCloseKey(hkeyDrivers
);
5515 *pcbNeeded
+= needed
;
5518 RegCloseKey(hkeyDrivers
);
5520 if(cbBuf
< *pcbNeeded
){
5521 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5528 /*****************************************************************************
5529 * EnumPrinterDriversW [WINSPOOL.@]
5531 * see function EnumPrinterDrivers for RETURNS, BUGS
5533 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5534 LPBYTE pDriverInfo
, DWORD cbBuf
,
5535 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5537 static const WCHAR allW
[] = {'a','l','l',0};
5541 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5543 SetLastError(RPC_X_NULL_REF_POINTER
);
5547 /* check for local drivers */
5548 if((pName
) && (pName
[0])) {
5549 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5550 SetLastError(ERROR_ACCESS_DENIED
);
5554 /* check input parameter */
5555 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5556 SetLastError(ERROR_INVALID_LEVEL
);
5560 if(pDriverInfo
&& cbBuf
> 0)
5561 memset( pDriverInfo
, 0, cbBuf
);
5563 /* Exception: pull all printers */
5564 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5566 DWORD i
, needed
, bufsize
= cbBuf
;
5567 DWORD total_found
= 0;
5570 /* Precompute the overall total; we need this to know
5571 where pointers end and data begins (i.e. data_offset) */
5572 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5575 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5576 NULL
, 0, 0, &needed
, &found
, 0);
5577 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5578 total_found
+= found
;
5581 data_offset
= di_sizeof
[Level
] * total_found
;
5586 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5589 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5590 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5591 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5593 *pcReturned
+= found
;
5594 *pcbNeeded
= needed
;
5595 data_offset
= needed
;
5596 total_found
+= found
;
5601 /* Normal behavior */
5602 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5603 0, cbBuf
, pcbNeeded
, &found
, 0);
5605 *pcReturned
= found
;
5610 /*****************************************************************************
5611 * EnumPrinterDriversA [WINSPOOL.@]
5613 * see function EnumPrinterDrivers for RETURNS, BUGS
5615 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5616 LPBYTE pDriverInfo
, DWORD cbBuf
,
5617 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5620 UNICODE_STRING pNameW
, pEnvironmentW
;
5621 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5625 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5627 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5628 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5630 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5631 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5633 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5635 HeapFree(GetProcessHeap(), 0, buf
);
5637 RtlFreeUnicodeString(&pNameW
);
5638 RtlFreeUnicodeString(&pEnvironmentW
);
5643 /******************************************************************************
5644 * EnumPortsA (WINSPOOL.@)
5649 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5650 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5653 LPBYTE bufferW
= NULL
;
5654 LPWSTR nameW
= NULL
;
5656 DWORD numentries
= 0;
5659 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5660 cbBuf
, pcbNeeded
, pcReturned
);
5662 /* convert servername to unicode */
5664 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5665 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5666 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5668 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5669 needed
= cbBuf
* sizeof(WCHAR
);
5670 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5671 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5673 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5674 if (pcbNeeded
) needed
= *pcbNeeded
;
5675 /* HeapReAlloc return NULL, when bufferW was NULL */
5676 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5677 HeapAlloc(GetProcessHeap(), 0, needed
);
5679 /* Try again with the large Buffer */
5680 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5682 needed
= pcbNeeded
? *pcbNeeded
: 0;
5683 numentries
= pcReturned
? *pcReturned
: 0;
5686 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5687 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5690 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5691 DWORD entrysize
= 0;
5694 LPPORT_INFO_2W pi2w
;
5695 LPPORT_INFO_2A pi2a
;
5698 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5700 /* First pass: calculate the size for all Entries */
5701 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5702 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5704 while (index
< numentries
) {
5706 needed
+= entrysize
; /* PORT_INFO_?A */
5707 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5709 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5710 NULL
, 0, NULL
, NULL
);
5712 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5713 NULL
, 0, NULL
, NULL
);
5714 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5715 NULL
, 0, NULL
, NULL
);
5717 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5718 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5719 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5722 /* check for errors and quit on failure */
5723 if (cbBuf
< needed
) {
5724 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5728 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5729 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5730 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5731 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5732 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5734 /* Second Pass: Fill the User Buffer (if we have one) */
5735 while ((index
< numentries
) && pPorts
) {
5737 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5738 pi2a
->pPortName
= ptr
;
5739 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5740 ptr
, cbBuf
, NULL
, NULL
);
5744 pi2a
->pMonitorName
= ptr
;
5745 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5746 ptr
, cbBuf
, NULL
, NULL
);
5750 pi2a
->pDescription
= ptr
;
5751 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5752 ptr
, cbBuf
, NULL
, NULL
);
5756 pi2a
->fPortType
= pi2w
->fPortType
;
5757 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5760 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5761 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5762 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5767 if (pcbNeeded
) *pcbNeeded
= needed
;
5768 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5770 HeapFree(GetProcessHeap(), 0, nameW
);
5771 HeapFree(GetProcessHeap(), 0, bufferW
);
5773 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5774 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5780 /******************************************************************************
5781 * EnumPortsW (WINSPOOL.@)
5783 * Enumerate available Ports
5786 * pName [I] Servername or NULL (local Computer)
5787 * Level [I] Structure-Level (1 or 2)
5788 * pPorts [O] PTR to Buffer that receives the Result
5789 * cbBuf [I] Size of Buffer at pPorts
5790 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5791 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5795 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5798 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5801 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5802 cbBuf
, pcbNeeded
, pcReturned
);
5804 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5806 /* Level is not checked in win9x */
5807 if (!Level
|| (Level
> 2)) {
5808 WARN("level (%d) is ignored in win9x\n", Level
);
5809 SetLastError(ERROR_INVALID_LEVEL
);
5812 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5813 SetLastError(RPC_X_NULL_REF_POINTER
);
5817 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5820 /******************************************************************************
5821 * GetDefaultPrinterW (WINSPOOL.@)
5824 * This function must read the value from data 'device' of key
5825 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5827 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5831 WCHAR
*buffer
, *ptr
;
5835 SetLastError(ERROR_INVALID_PARAMETER
);
5839 /* make the buffer big enough for the stuff from the profile/registry,
5840 * the content must fit into the local buffer to compute the correct
5841 * size even if the extern buffer is too small or not given.
5842 * (20 for ,driver,port) */
5844 len
= max(100, (insize
+ 20));
5845 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5847 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5849 SetLastError (ERROR_FILE_NOT_FOUND
);
5853 TRACE("%s\n", debugstr_w(buffer
));
5855 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5857 SetLastError(ERROR_INVALID_NAME
);
5863 *namesize
= strlenW(buffer
) + 1;
5864 if(!name
|| (*namesize
> insize
))
5866 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5870 strcpyW(name
, buffer
);
5873 HeapFree( GetProcessHeap(), 0, buffer
);
5878 /******************************************************************************
5879 * GetDefaultPrinterA (WINSPOOL.@)
5881 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5885 WCHAR
*bufferW
= NULL
;
5889 SetLastError(ERROR_INVALID_PARAMETER
);
5893 if(name
&& *namesize
) {
5895 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5898 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5903 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5907 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5910 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5913 HeapFree( GetProcessHeap(), 0, bufferW
);
5918 /******************************************************************************
5919 * SetDefaultPrinterW (WINSPOOL.204)
5921 * Set the Name of the Default Printer
5924 * pszPrinter [I] Name of the Printer or NULL
5931 * When the Parameter is NULL or points to an Empty String and
5932 * a Default Printer was already present, then this Function changes nothing.
5933 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5934 * the First enumerated local Printer is used.
5937 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5939 WCHAR default_printer
[MAX_PATH
];
5940 LPWSTR buffer
= NULL
;
5946 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5947 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5949 default_printer
[0] = '\0';
5950 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5952 /* if we have a default Printer, do nothing. */
5953 if (GetDefaultPrinterW(default_printer
, &size
))
5957 /* we have no default Printer: search local Printers and use the first */
5958 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5960 default_printer
[0] = '\0';
5961 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5962 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5964 pszPrinter
= default_printer
;
5965 TRACE("using %s\n", debugstr_w(pszPrinter
));
5970 if (pszPrinter
== NULL
) {
5971 TRACE("no local printer found\n");
5972 SetLastError(ERROR_FILE_NOT_FOUND
);
5977 /* "pszPrinter" is never empty or NULL here. */
5978 namelen
= lstrlenW(pszPrinter
);
5979 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5980 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5982 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5983 HeapFree(GetProcessHeap(), 0, buffer
);
5984 SetLastError(ERROR_FILE_NOT_FOUND
);
5988 /* read the devices entry for the printer (driver,port) to build the string for the
5989 default device entry (printer,driver,port) */
5990 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5991 buffer
[namelen
] = ',';
5992 namelen
++; /* move index to the start of the driver */
5994 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5995 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5997 TRACE("set device to %s\n", debugstr_w(buffer
));
5999 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
6000 TRACE("failed to set the device entry: %d\n", GetLastError());
6001 lres
= ERROR_INVALID_PRINTER_NAME
;
6004 /* remove the next section, when INIFileMapping is implemented */
6007 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
6008 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
6015 if (lres
!= ERROR_FILE_NOT_FOUND
)
6016 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
6018 SetLastError(ERROR_INVALID_PRINTER_NAME
);
6022 HeapFree(GetProcessHeap(), 0, buffer
);
6023 return (lres
== ERROR_SUCCESS
);
6026 /******************************************************************************
6027 * SetDefaultPrinterA (WINSPOOL.202)
6029 * See SetDefaultPrinterW.
6032 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
6034 LPWSTR bufferW
= NULL
;
6037 TRACE("(%s)\n", debugstr_a(pszPrinter
));
6039 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
6040 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6041 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
6043 res
= SetDefaultPrinterW(bufferW
);
6044 HeapFree(GetProcessHeap(), 0, bufferW
);
6048 /******************************************************************************
6049 * SetPrinterDataExA (WINSPOOL.@)
6051 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6052 LPCSTR pValueName
, DWORD Type
,
6053 LPBYTE pData
, DWORD cbData
)
6055 HKEY hkeyPrinter
, hkeySubkey
;
6058 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
6059 debugstr_a(pValueName
), Type
, pData
, cbData
);
6061 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6065 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6067 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
6068 RegCloseKey(hkeyPrinter
);
6071 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6072 RegCloseKey(hkeySubkey
);
6073 RegCloseKey(hkeyPrinter
);
6077 /******************************************************************************
6078 * SetPrinterDataExW (WINSPOOL.@)
6080 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6081 LPCWSTR pValueName
, DWORD Type
,
6082 LPBYTE pData
, DWORD cbData
)
6084 HKEY hkeyPrinter
, hkeySubkey
;
6087 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
6088 debugstr_w(pValueName
), Type
, pData
, cbData
);
6090 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6094 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6096 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
6097 RegCloseKey(hkeyPrinter
);
6100 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6101 RegCloseKey(hkeySubkey
);
6102 RegCloseKey(hkeyPrinter
);
6106 /******************************************************************************
6107 * SetPrinterDataA (WINSPOOL.@)
6109 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
6110 LPBYTE pData
, DWORD cbData
)
6112 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
6116 /******************************************************************************
6117 * SetPrinterDataW (WINSPOOL.@)
6119 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
6120 LPBYTE pData
, DWORD cbData
)
6122 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6126 /******************************************************************************
6127 * GetPrinterDataExA (WINSPOOL.@)
6129 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6130 LPCSTR pValueName
, LPDWORD pType
,
6131 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6133 opened_printer_t
*printer
;
6134 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6137 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6138 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6140 printer
= get_opened_printer(hPrinter
);
6141 if(!printer
) return ERROR_INVALID_HANDLE
;
6143 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6144 if (ret
) return ret
;
6146 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6148 if (printer
->name
) {
6150 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6152 RegCloseKey(hkeyPrinters
);
6155 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6156 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6157 RegCloseKey(hkeyPrinter
);
6158 RegCloseKey(hkeyPrinters
);
6163 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6164 0, pType
, pData
, pcbNeeded
);
6166 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6168 RegCloseKey(hkeySubkey
);
6169 RegCloseKey(hkeyPrinter
);
6170 RegCloseKey(hkeyPrinters
);
6172 TRACE("--> %d\n", ret
);
6176 /******************************************************************************
6177 * GetPrinterDataExW (WINSPOOL.@)
6179 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6180 LPCWSTR pValueName
, LPDWORD pType
,
6181 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6183 opened_printer_t
*printer
;
6184 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6187 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6188 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6190 printer
= get_opened_printer(hPrinter
);
6191 if(!printer
) return ERROR_INVALID_HANDLE
;
6193 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6194 if (ret
) return ret
;
6196 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6198 if (printer
->name
) {
6200 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6202 RegCloseKey(hkeyPrinters
);
6205 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6206 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6207 RegCloseKey(hkeyPrinter
);
6208 RegCloseKey(hkeyPrinters
);
6213 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6214 0, pType
, pData
, pcbNeeded
);
6216 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6218 RegCloseKey(hkeySubkey
);
6219 RegCloseKey(hkeyPrinter
);
6220 RegCloseKey(hkeyPrinters
);
6222 TRACE("--> %d\n", ret
);
6226 /******************************************************************************
6227 * GetPrinterDataA (WINSPOOL.@)
6229 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6230 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6232 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6233 pData
, nSize
, pcbNeeded
);
6236 /******************************************************************************
6237 * GetPrinterDataW (WINSPOOL.@)
6239 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6240 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6242 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6243 pData
, nSize
, pcbNeeded
);
6246 /*******************************************************************************
6247 * EnumPrinterDataExW [WINSPOOL.@]
6249 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6250 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6251 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6253 HKEY hkPrinter
, hkSubKey
;
6254 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6255 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6260 PPRINTER_ENUM_VALUESW ppev
;
6262 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6264 if (pKeyName
== NULL
|| *pKeyName
== 0)
6265 return ERROR_INVALID_PARAMETER
;
6267 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6268 if (ret
!= ERROR_SUCCESS
)
6270 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6275 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6276 if (ret
!= ERROR_SUCCESS
)
6278 r
= RegCloseKey (hkPrinter
);
6279 if (r
!= ERROR_SUCCESS
)
6280 WARN ("RegCloseKey returned %i\n", r
);
6281 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6282 debugstr_w (pKeyName
), ret
);
6286 ret
= RegCloseKey (hkPrinter
);
6287 if (ret
!= ERROR_SUCCESS
)
6289 ERR ("RegCloseKey returned %i\n", ret
);
6290 r
= RegCloseKey (hkSubKey
);
6291 if (r
!= ERROR_SUCCESS
)
6292 WARN ("RegCloseKey returned %i\n", r
);
6296 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6297 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6298 if (ret
!= ERROR_SUCCESS
)
6300 r
= RegCloseKey (hkSubKey
);
6301 if (r
!= ERROR_SUCCESS
)
6302 WARN ("RegCloseKey returned %i\n", r
);
6303 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6307 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6308 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6310 if (cValues
== 0) /* empty key */
6312 r
= RegCloseKey (hkSubKey
);
6313 if (r
!= ERROR_SUCCESS
)
6314 WARN ("RegCloseKey returned %i\n", r
);
6315 *pcbEnumValues
= *pnEnumValues
= 0;
6316 return ERROR_SUCCESS
;
6319 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6321 hHeap
= GetProcessHeap ();
6324 ERR ("GetProcessHeap failed\n");
6325 r
= RegCloseKey (hkSubKey
);
6326 if (r
!= ERROR_SUCCESS
)
6327 WARN ("RegCloseKey returned %i\n", r
);
6328 return ERROR_OUTOFMEMORY
;
6331 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6332 if (lpValueName
== NULL
)
6334 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6335 r
= RegCloseKey (hkSubKey
);
6336 if (r
!= ERROR_SUCCESS
)
6337 WARN ("RegCloseKey returned %i\n", r
);
6338 return ERROR_OUTOFMEMORY
;
6341 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6342 if (lpValue
== NULL
)
6344 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6345 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6346 WARN ("HeapFree failed with code %i\n", GetLastError ());
6347 r
= RegCloseKey (hkSubKey
);
6348 if (r
!= ERROR_SUCCESS
)
6349 WARN ("RegCloseKey returned %i\n", r
);
6350 return ERROR_OUTOFMEMORY
;
6353 TRACE ("pass 1: calculating buffer required for all names and values\n");
6355 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6357 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6359 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6361 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6362 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6363 NULL
, NULL
, lpValue
, &cbValueLen
);
6364 if (ret
!= ERROR_SUCCESS
)
6366 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6367 WARN ("HeapFree failed with code %i\n", GetLastError ());
6368 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6369 WARN ("HeapFree failed with code %i\n", GetLastError ());
6370 r
= RegCloseKey (hkSubKey
);
6371 if (r
!= ERROR_SUCCESS
)
6372 WARN ("RegCloseKey returned %i\n", r
);
6373 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6377 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6378 debugstr_w (lpValueName
), dwIndex
,
6379 cbValueNameLen
+ 1, cbValueLen
);
6381 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6382 cbBufSize
+= cbValueLen
;
6385 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6387 *pcbEnumValues
= cbBufSize
;
6388 *pnEnumValues
= cValues
;
6390 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6392 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6393 WARN ("HeapFree failed with code %i\n", GetLastError ());
6394 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6395 WARN ("HeapFree failed with code %i\n", GetLastError ());
6396 r
= RegCloseKey (hkSubKey
);
6397 if (r
!= ERROR_SUCCESS
)
6398 WARN ("RegCloseKey returned %i\n", r
);
6399 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6400 return ERROR_MORE_DATA
;
6403 TRACE ("pass 2: copying all names and values to buffer\n");
6405 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6406 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6408 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6410 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6411 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6412 NULL
, &dwType
, lpValue
, &cbValueLen
);
6413 if (ret
!= ERROR_SUCCESS
)
6415 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6416 WARN ("HeapFree failed with code %i\n", GetLastError ());
6417 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6418 WARN ("HeapFree failed with code %i\n", GetLastError ());
6419 r
= RegCloseKey (hkSubKey
);
6420 if (r
!= ERROR_SUCCESS
)
6421 WARN ("RegCloseKey returned %i\n", r
);
6422 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6426 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6427 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6428 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6429 pEnumValues
+= cbValueNameLen
;
6431 /* return # of *bytes* (including trailing \0), not # of chars */
6432 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6434 ppev
[dwIndex
].dwType
= dwType
;
6436 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6437 ppev
[dwIndex
].pData
= pEnumValues
;
6438 pEnumValues
+= cbValueLen
;
6440 ppev
[dwIndex
].cbData
= cbValueLen
;
6442 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6443 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6446 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6448 ret
= GetLastError ();
6449 ERR ("HeapFree failed with code %i\n", ret
);
6450 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6451 WARN ("HeapFree failed with code %i\n", GetLastError ());
6452 r
= RegCloseKey (hkSubKey
);
6453 if (r
!= ERROR_SUCCESS
)
6454 WARN ("RegCloseKey returned %i\n", r
);
6458 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6460 ret
= GetLastError ();
6461 ERR ("HeapFree failed with code %i\n", ret
);
6462 r
= RegCloseKey (hkSubKey
);
6463 if (r
!= ERROR_SUCCESS
)
6464 WARN ("RegCloseKey returned %i\n", r
);
6468 ret
= RegCloseKey (hkSubKey
);
6469 if (ret
!= ERROR_SUCCESS
)
6471 ERR ("RegCloseKey returned %i\n", ret
);
6475 return ERROR_SUCCESS
;
6478 /*******************************************************************************
6479 * EnumPrinterDataExA [WINSPOOL.@]
6481 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6482 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6483 * what Windows 2000 SP1 does.
6486 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6487 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6488 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6492 DWORD ret
, dwIndex
, dwBufSize
;
6496 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6498 if (pKeyName
== NULL
|| *pKeyName
== 0)
6499 return ERROR_INVALID_PARAMETER
;
6501 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6504 ret
= GetLastError ();
6505 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6509 hHeap
= GetProcessHeap ();
6512 ERR ("GetProcessHeap failed\n");
6513 return ERROR_OUTOFMEMORY
;
6516 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6517 if (pKeyNameW
== NULL
)
6519 ERR ("Failed to allocate %i bytes from process heap\n",
6520 (LONG
)(len
* sizeof (WCHAR
)));
6521 return ERROR_OUTOFMEMORY
;
6524 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6526 ret
= GetLastError ();
6527 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6528 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6529 WARN ("HeapFree failed with code %i\n", GetLastError ());
6533 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6534 pcbEnumValues
, pnEnumValues
);
6535 if (ret
!= ERROR_SUCCESS
)
6537 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6538 WARN ("HeapFree failed with code %i\n", GetLastError ());
6539 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6543 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6545 ret
= GetLastError ();
6546 ERR ("HeapFree failed with code %i\n", ret
);
6550 if (*pnEnumValues
== 0) /* empty key */
6551 return ERROR_SUCCESS
;
6554 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6556 PPRINTER_ENUM_VALUESW ppev
=
6557 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6559 if (dwBufSize
< ppev
->cbValueName
)
6560 dwBufSize
= ppev
->cbValueName
;
6562 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6563 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6564 dwBufSize
= ppev
->cbData
;
6567 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6569 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6570 if (pBuffer
== NULL
)
6572 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6573 return ERROR_OUTOFMEMORY
;
6576 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6578 PPRINTER_ENUM_VALUESW ppev
=
6579 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6581 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6582 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6586 ret
= GetLastError ();
6587 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6588 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6589 WARN ("HeapFree failed with code %i\n", GetLastError ());
6593 memcpy (ppev
->pValueName
, pBuffer
, len
);
6595 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6597 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6598 ppev
->dwType
!= REG_MULTI_SZ
)
6601 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6602 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6605 ret
= GetLastError ();
6606 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6607 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6608 WARN ("HeapFree failed with code %i\n", GetLastError ());
6612 memcpy (ppev
->pData
, pBuffer
, len
);
6614 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6615 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6618 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6620 ret
= GetLastError ();
6621 ERR ("HeapFree failed with code %i\n", ret
);
6625 return ERROR_SUCCESS
;
6628 /******************************************************************************
6629 * AbortPrinter (WINSPOOL.@)
6631 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6633 FIXME("(%p), stub!\n", hPrinter
);
6637 /******************************************************************************
6638 * AddPortA (WINSPOOL.@)
6643 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6645 LPWSTR nameW
= NULL
;
6646 LPWSTR monitorW
= NULL
;
6650 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6653 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6654 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6655 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6659 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6660 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6661 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6663 res
= AddPortW(nameW
, hWnd
, monitorW
);
6664 HeapFree(GetProcessHeap(), 0, nameW
);
6665 HeapFree(GetProcessHeap(), 0, monitorW
);
6669 /******************************************************************************
6670 * AddPortW (WINSPOOL.@)
6672 * Add a Port for a specific Monitor
6675 * pName [I] Servername or NULL (local Computer)
6676 * hWnd [I] Handle to parent Window for the Dialog-Box
6677 * pMonitorName [I] Name of the Monitor that manage the Port
6684 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6686 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6688 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6690 if (!pMonitorName
) {
6691 SetLastError(RPC_X_NULL_REF_POINTER
);
6695 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6698 /******************************************************************************
6699 * AddPortExA (WINSPOOL.@)
6704 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6707 PORT_INFO_2A
* pi2A
;
6708 LPWSTR nameW
= NULL
;
6709 LPWSTR monitorW
= NULL
;
6713 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6715 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6716 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6718 if ((level
< 1) || (level
> 2)) {
6719 SetLastError(ERROR_INVALID_LEVEL
);
6724 SetLastError(ERROR_INVALID_PARAMETER
);
6729 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6730 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6731 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6735 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6736 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6737 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6740 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6742 if (pi2A
->pPortName
) {
6743 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6744 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6745 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6749 if (pi2A
->pMonitorName
) {
6750 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6751 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6752 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6755 if (pi2A
->pDescription
) {
6756 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6757 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6758 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6760 pi2W
.fPortType
= pi2A
->fPortType
;
6761 pi2W
.Reserved
= pi2A
->Reserved
;
6764 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6766 HeapFree(GetProcessHeap(), 0, nameW
);
6767 HeapFree(GetProcessHeap(), 0, monitorW
);
6768 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6769 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6770 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6775 /******************************************************************************
6776 * AddPortExW (WINSPOOL.@)
6778 * Add a Port for a specific Monitor, without presenting a user interface
6781 * pName [I] Servername or NULL (local Computer)
6782 * level [I] Structure-Level (1 or 2) for pBuffer
6783 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6784 * pMonitorName [I] Name of the Monitor that manage the Port
6791 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6795 pi2
= (PORT_INFO_2W
*) pBuffer
;
6797 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6798 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6799 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6800 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6802 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6804 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6805 SetLastError(ERROR_INVALID_PARAMETER
);
6809 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6812 /******************************************************************************
6813 * AddPrinterConnectionA (WINSPOOL.@)
6815 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6817 FIXME("%s\n", debugstr_a(pName
));
6821 /******************************************************************************
6822 * AddPrinterConnectionW (WINSPOOL.@)
6824 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6826 FIXME("%s\n", debugstr_w(pName
));
6830 /******************************************************************************
6831 * AddPrinterDriverExW (WINSPOOL.@)
6833 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6836 * pName [I] Servername or NULL (local Computer)
6837 * level [I] Level for the supplied DRIVER_INFO_*W struct
6838 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6839 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6846 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6848 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6850 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6852 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6853 SetLastError(ERROR_INVALID_LEVEL
);
6858 SetLastError(ERROR_INVALID_PARAMETER
);
6862 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6865 /******************************************************************************
6866 * AddPrinterDriverExA (WINSPOOL.@)
6868 * See AddPrinterDriverExW.
6871 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6873 DRIVER_INFO_8A
*diA
;
6875 LPWSTR nameW
= NULL
;
6880 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6882 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6883 ZeroMemory(&diW
, sizeof(diW
));
6885 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6886 SetLastError(ERROR_INVALID_LEVEL
);
6891 SetLastError(ERROR_INVALID_PARAMETER
);
6895 /* convert servername to unicode */
6897 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6898 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6899 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6903 diW
.cVersion
= diA
->cVersion
;
6906 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6907 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6908 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6911 if (diA
->pEnvironment
) {
6912 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6913 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6914 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6917 if (diA
->pDriverPath
) {
6918 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6919 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6920 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6923 if (diA
->pDataFile
) {
6924 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6925 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6926 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6929 if (diA
->pConfigFile
) {
6930 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6931 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6932 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6935 if ((Level
> 2) && diA
->pDependentFiles
) {
6936 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6937 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6938 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6939 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6942 if ((Level
> 2) && diA
->pMonitorName
) {
6943 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6944 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6945 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6948 if ((Level
> 3) && diA
->pDefaultDataType
) {
6949 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6950 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6951 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6954 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6955 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6956 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6957 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6958 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6961 if ((Level
> 5) && diA
->pszMfgName
) {
6962 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6963 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6964 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6967 if ((Level
> 5) && diA
->pszOEMUrl
) {
6968 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6969 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6970 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6973 if ((Level
> 5) && diA
->pszHardwareID
) {
6974 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6975 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6976 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6979 if ((Level
> 5) && diA
->pszProvider
) {
6980 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6981 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6982 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6986 FIXME("level %u is incomplete\n", Level
);
6989 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6990 TRACE("got %u with %u\n", res
, GetLastError());
6991 HeapFree(GetProcessHeap(), 0, nameW
);
6992 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6993 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6994 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6995 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6996 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6997 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6998 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6999 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
7000 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
7001 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
7002 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
7003 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
7004 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
7006 TRACE("=> %u with %u\n", res
, GetLastError());
7010 /******************************************************************************
7011 * ConfigurePortA (WINSPOOL.@)
7013 * See ConfigurePortW.
7016 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
7018 LPWSTR nameW
= NULL
;
7019 LPWSTR portW
= NULL
;
7023 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
7025 /* convert servername to unicode */
7027 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7028 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7029 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7032 /* convert portname to unicode */
7034 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
7035 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7036 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
7039 res
= ConfigurePortW(nameW
, hWnd
, portW
);
7040 HeapFree(GetProcessHeap(), 0, nameW
);
7041 HeapFree(GetProcessHeap(), 0, portW
);
7045 /******************************************************************************
7046 * ConfigurePortW (WINSPOOL.@)
7048 * Display the Configuration-Dialog for a specific Port
7051 * pName [I] Servername or NULL (local Computer)
7052 * hWnd [I] Handle to parent Window for the Dialog-Box
7053 * pPortName [I] Name of the Port, that should be configured
7060 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
7063 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
7065 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7068 SetLastError(RPC_X_NULL_REF_POINTER
);
7072 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
7075 /******************************************************************************
7076 * ConnectToPrinterDlg (WINSPOOL.@)
7078 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
7080 FIXME("%p %x\n", hWnd
, Flags
);
7084 /******************************************************************************
7085 * DeletePrinterConnectionA (WINSPOOL.@)
7087 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
7089 FIXME("%s\n", debugstr_a(pName
));
7093 /******************************************************************************
7094 * DeletePrinterConnectionW (WINSPOOL.@)
7096 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
7098 FIXME("%s\n", debugstr_w(pName
));
7102 /******************************************************************************
7103 * DeletePrinterDriverExW (WINSPOOL.@)
7105 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
7106 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7111 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7112 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
7114 if(pName
&& pName
[0])
7116 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
7117 SetLastError(ERROR_INVALID_PARAMETER
);
7123 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7124 SetLastError(ERROR_INVALID_PARAMETER
);
7128 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7132 ERR("Can't open drivers key\n");
7136 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7139 RegCloseKey(hkey_drivers
);
7144 /******************************************************************************
7145 * DeletePrinterDriverExA (WINSPOOL.@)
7147 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7148 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7150 UNICODE_STRING NameW
, EnvW
, DriverW
;
7153 asciitounicode(&NameW
, pName
);
7154 asciitounicode(&EnvW
, pEnvironment
);
7155 asciitounicode(&DriverW
, pDriverName
);
7157 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7159 RtlFreeUnicodeString(&DriverW
);
7160 RtlFreeUnicodeString(&EnvW
);
7161 RtlFreeUnicodeString(&NameW
);
7166 /******************************************************************************
7167 * DeletePrinterDataExW (WINSPOOL.@)
7169 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7172 FIXME("%p %s %s\n", hPrinter
,
7173 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7174 return ERROR_INVALID_PARAMETER
;
7177 /******************************************************************************
7178 * DeletePrinterDataExA (WINSPOOL.@)
7180 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7183 FIXME("%p %s %s\n", hPrinter
,
7184 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7185 return ERROR_INVALID_PARAMETER
;
7188 /******************************************************************************
7189 * DeletePrintProcessorA (WINSPOOL.@)
7191 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7193 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7194 debugstr_a(pPrintProcessorName
));
7198 /******************************************************************************
7199 * DeletePrintProcessorW (WINSPOOL.@)
7201 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7203 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7204 debugstr_w(pPrintProcessorName
));
7208 /******************************************************************************
7209 * DeletePrintProvidorA (WINSPOOL.@)
7211 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7213 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7214 debugstr_a(pPrintProviderName
));
7218 /******************************************************************************
7219 * DeletePrintProvidorW (WINSPOOL.@)
7221 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7223 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7224 debugstr_w(pPrintProviderName
));
7228 /******************************************************************************
7229 * EnumFormsA (WINSPOOL.@)
7231 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7232 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7234 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7235 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7239 /******************************************************************************
7240 * EnumFormsW (WINSPOOL.@)
7242 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7243 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7245 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7246 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7250 /*****************************************************************************
7251 * EnumMonitorsA [WINSPOOL.@]
7253 * See EnumMonitorsW.
7256 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7257 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7260 LPBYTE bufferW
= NULL
;
7261 LPWSTR nameW
= NULL
;
7263 DWORD numentries
= 0;
7266 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7267 cbBuf
, pcbNeeded
, pcReturned
);
7269 /* convert servername to unicode */
7271 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7272 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7273 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7275 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7276 needed
= cbBuf
* sizeof(WCHAR
);
7277 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7278 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7280 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7281 if (pcbNeeded
) needed
= *pcbNeeded
;
7282 /* HeapReAlloc return NULL, when bufferW was NULL */
7283 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7284 HeapAlloc(GetProcessHeap(), 0, needed
);
7286 /* Try again with the large Buffer */
7287 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7289 numentries
= pcReturned
? *pcReturned
: 0;
7292 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7293 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7296 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7297 DWORD entrysize
= 0;
7300 LPMONITOR_INFO_2W mi2w
;
7301 LPMONITOR_INFO_2A mi2a
;
7303 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7304 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7306 /* First pass: calculate the size for all Entries */
7307 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7308 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7310 while (index
< numentries
) {
7312 needed
+= entrysize
; /* MONITOR_INFO_?A */
7313 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7315 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7316 NULL
, 0, NULL
, NULL
);
7318 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7319 NULL
, 0, NULL
, NULL
);
7320 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7321 NULL
, 0, NULL
, NULL
);
7323 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7324 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7325 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7328 /* check for errors and quit on failure */
7329 if (cbBuf
< needed
) {
7330 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7334 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7335 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7336 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7337 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7338 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7340 /* Second Pass: Fill the User Buffer (if we have one) */
7341 while ((index
< numentries
) && pMonitors
) {
7343 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7345 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7346 ptr
, cbBuf
, NULL
, NULL
);
7350 mi2a
->pEnvironment
= ptr
;
7351 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7352 ptr
, cbBuf
, NULL
, NULL
);
7356 mi2a
->pDLLName
= ptr
;
7357 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7358 ptr
, cbBuf
, NULL
, NULL
);
7362 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7363 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7364 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7368 if (pcbNeeded
) *pcbNeeded
= needed
;
7369 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7371 HeapFree(GetProcessHeap(), 0, nameW
);
7372 HeapFree(GetProcessHeap(), 0, bufferW
);
7374 TRACE("returning %d with %d (%d byte for %d entries)\n",
7375 (res
), GetLastError(), needed
, numentries
);
7381 /*****************************************************************************
7382 * EnumMonitorsW [WINSPOOL.@]
7384 * Enumerate available Port-Monitors
7387 * pName [I] Servername or NULL (local Computer)
7388 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7389 * pMonitors [O] PTR to Buffer that receives the Result
7390 * cbBuf [I] Size of Buffer at pMonitors
7391 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7392 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7396 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7399 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7400 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7403 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7404 cbBuf
, pcbNeeded
, pcReturned
);
7406 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7408 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7409 SetLastError(RPC_X_NULL_REF_POINTER
);
7413 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7416 /******************************************************************************
7417 * SpoolerInit (WINSPOOL.@)
7419 * Initialize the Spooler
7426 * The function fails on windows, when the spooler service is not running
7429 BOOL WINAPI
SpoolerInit(void)
7432 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7436 /******************************************************************************
7437 * XcvDataW (WINSPOOL.@)
7439 * Execute commands in the Printmonitor DLL
7442 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7443 * pszDataName [i] Name of the command to execute
7444 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7445 * cbInputData [i] Size in Bytes of Buffer at pInputData
7446 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7447 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7448 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7449 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7456 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7457 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7459 * Minimal List of commands, that a Printmonitor DLL should support:
7461 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7462 *| "AddPort" : Add a Port
7463 *| "DeletePort": Delete a Port
7465 * Many Printmonitors support additional commands. Examples for localspl.dll:
7466 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7467 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7470 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7471 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7472 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7474 opened_printer_t
*printer
;
7476 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7477 pInputData
, cbInputData
, pOutputData
,
7478 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7480 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7482 printer
= get_opened_printer(hXcv
);
7483 if (!printer
|| (!printer
->backend_printer
)) {
7484 SetLastError(ERROR_INVALID_HANDLE
);
7488 if (!pcbOutputNeeded
) {
7489 SetLastError(ERROR_INVALID_PARAMETER
);
7493 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7494 SetLastError(RPC_X_NULL_REF_POINTER
);
7498 *pcbOutputNeeded
= 0;
7500 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7501 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7505 /*****************************************************************************
7506 * EnumPrinterDataA [WINSPOOL.@]
7509 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7510 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7511 DWORD cbData
, LPDWORD pcbData
)
7513 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7514 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7515 return ERROR_NO_MORE_ITEMS
;
7518 /*****************************************************************************
7519 * EnumPrinterDataW [WINSPOOL.@]
7522 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7523 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7524 DWORD cbData
, LPDWORD pcbData
)
7526 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7527 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7528 return ERROR_NO_MORE_ITEMS
;
7531 /*****************************************************************************
7532 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7535 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7536 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7537 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7539 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7540 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7541 pcbNeeded
, pcReturned
);
7545 /*****************************************************************************
7546 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7549 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7550 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7551 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7553 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7554 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7555 pcbNeeded
, pcReturned
);
7559 /*****************************************************************************
7560 * EnumPrintProcessorsA [WINSPOOL.@]
7562 * See EnumPrintProcessorsW.
7565 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7566 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7569 LPBYTE bufferW
= NULL
;
7570 LPWSTR nameW
= NULL
;
7573 DWORD numentries
= 0;
7576 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7577 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7579 /* convert names to unicode */
7581 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7582 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7583 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7586 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7587 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7588 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7591 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7592 needed
= cbBuf
* sizeof(WCHAR
);
7593 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7594 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7596 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7597 if (pcbNeeded
) needed
= *pcbNeeded
;
7598 /* HeapReAlloc return NULL, when bufferW was NULL */
7599 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7600 HeapAlloc(GetProcessHeap(), 0, needed
);
7602 /* Try again with the large Buffer */
7603 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7605 numentries
= pcReturned
? *pcReturned
: 0;
7609 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7612 PPRINTPROCESSOR_INFO_1W ppiw
;
7613 PPRINTPROCESSOR_INFO_1A ppia
;
7615 /* First pass: calculate the size for all Entries */
7616 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7617 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7619 while (index
< numentries
) {
7621 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7622 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7624 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7625 NULL
, 0, NULL
, NULL
);
7627 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7628 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7631 /* check for errors and quit on failure */
7632 if (cbBuf
< needed
) {
7633 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7638 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7639 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7640 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7641 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7642 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7644 /* Second Pass: Fill the User Buffer (if we have one) */
7645 while ((index
< numentries
) && pPPInfo
) {
7647 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7649 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7650 ptr
, cbBuf
, NULL
, NULL
);
7654 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7655 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7660 if (pcbNeeded
) *pcbNeeded
= needed
;
7661 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7663 HeapFree(GetProcessHeap(), 0, nameW
);
7664 HeapFree(GetProcessHeap(), 0, envW
);
7665 HeapFree(GetProcessHeap(), 0, bufferW
);
7667 TRACE("returning %d with %d (%d byte for %d entries)\n",
7668 (res
), GetLastError(), needed
, numentries
);
7673 /*****************************************************************************
7674 * EnumPrintProcessorsW [WINSPOOL.@]
7676 * Enumerate available Print Processors
7679 * pName [I] Servername or NULL (local Computer)
7680 * pEnvironment [I] Printing-Environment or NULL (Default)
7681 * Level [I] Structure-Level (Only 1 is allowed)
7682 * pPPInfo [O] PTR to Buffer that receives the Result
7683 * cbBuf [I] Size of Buffer at pPPInfo
7684 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7685 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7689 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7692 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7693 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7696 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7697 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7699 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7701 if (!pcbNeeded
|| !pcReturned
) {
7702 SetLastError(RPC_X_NULL_REF_POINTER
);
7706 if (!pPPInfo
&& (cbBuf
> 0)) {
7707 SetLastError(ERROR_INVALID_USER_BUFFER
);
7711 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7712 cbBuf
, pcbNeeded
, pcReturned
);
7715 /*****************************************************************************
7716 * ExtDeviceMode [WINSPOOL.@]
7719 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7720 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7723 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7724 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7725 debugstr_a(pProfile
), fMode
);
7729 /*****************************************************************************
7730 * FindClosePrinterChangeNotification [WINSPOOL.@]
7733 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7735 FIXME("Stub: %p\n", hChange
);
7739 /*****************************************************************************
7740 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7743 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7744 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7746 FIXME("Stub: %p %x %x %p\n",
7747 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7748 return INVALID_HANDLE_VALUE
;
7751 /*****************************************************************************
7752 * FindNextPrinterChangeNotification [WINSPOOL.@]
7755 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7756 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7758 FIXME("Stub: %p %p %p %p\n",
7759 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7763 /*****************************************************************************
7764 * FreePrinterNotifyInfo [WINSPOOL.@]
7767 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7769 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7773 /*****************************************************************************
7776 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7777 * ansi depending on the unicode parameter.
7779 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7789 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7792 memcpy(ptr
, str
, *size
);
7799 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7802 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7809 /*****************************************************************************
7812 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7813 LPDWORD pcbNeeded
, BOOL unicode
)
7815 DWORD size
, left
= cbBuf
;
7816 BOOL space
= (cbBuf
> 0);
7823 ji1
->JobId
= job
->job_id
;
7826 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7827 if(space
&& size
<= left
)
7829 ji1
->pDocument
= (LPWSTR
)ptr
;
7837 if (job
->printer_name
)
7839 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7840 if(space
&& size
<= left
)
7842 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7854 /*****************************************************************************
7857 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7858 LPDWORD pcbNeeded
, BOOL unicode
)
7860 DWORD size
, left
= cbBuf
;
7862 BOOL space
= (cbBuf
> 0);
7864 LPDEVMODEA dmA
= NULL
;
7871 ji2
->JobId
= job
->job_id
;
7874 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7875 if(space
&& size
<= left
)
7877 ji2
->pDocument
= (LPWSTR
)ptr
;
7885 if (job
->printer_name
)
7887 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7888 if(space
&& size
<= left
)
7890 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7903 dmA
= DEVMODEdupWtoA(job
->devmode
);
7904 devmode
= (LPDEVMODEW
) dmA
;
7905 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7909 devmode
= job
->devmode
;
7910 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7914 FIXME("Can't convert DEVMODE W to A\n");
7917 /* align DEVMODE to a DWORD boundary */
7918 shift
= (4 - (*pcbNeeded
& 3)) & 3;
7924 memcpy(ptr
, devmode
, size
-shift
);
7925 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7926 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7939 /*****************************************************************************
7942 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7943 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7946 DWORD needed
= 0, size
;
7950 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7952 EnterCriticalSection(&printer_handles_cs
);
7953 job
= get_job(hPrinter
, JobId
);
7960 size
= sizeof(JOB_INFO_1W
);
7965 memset(pJob
, 0, size
);
7969 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7974 size
= sizeof(JOB_INFO_2W
);
7979 memset(pJob
, 0, size
);
7983 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7988 size
= sizeof(JOB_INFO_3
);
7992 memset(pJob
, 0, size
);
8001 SetLastError(ERROR_INVALID_LEVEL
);
8005 *pcbNeeded
= needed
;
8007 LeaveCriticalSection(&printer_handles_cs
);
8011 /*****************************************************************************
8012 * GetJobA [WINSPOOL.@]
8015 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8016 DWORD cbBuf
, LPDWORD pcbNeeded
)
8018 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
8021 /*****************************************************************************
8022 * GetJobW [WINSPOOL.@]
8025 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8026 DWORD cbBuf
, LPDWORD pcbNeeded
)
8028 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
8031 /*****************************************************************************
8034 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
8037 char *unixname
, *cmdA
;
8039 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
8045 if(!(unixname
= wine_get_unix_file_name(filename
)))
8048 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
8049 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
8050 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
8052 TRACE("printing with: %s\n", cmdA
);
8054 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
8059 ERR("pipe() failed!\n");
8063 if ((pid
= fork()) == 0)
8069 /* reset signals that we previously set to SIG_IGN */
8070 signal(SIGPIPE
, SIG_DFL
);
8072 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
8077 ERR("fork() failed!\n");
8083 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
8084 write(fds
[1], buf
, no_read
);
8091 wret
= waitpid(pid
, &status
, 0);
8092 } while (wret
< 0 && errno
== EINTR
);
8095 ERR("waitpid() failed!\n");
8098 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
8100 ERR("child process failed! %d\n", status
);
8107 if(file_fd
!= -1) close(file_fd
);
8108 if(fds
[0] != -1) close(fds
[0]);
8109 if(fds
[1] != -1) close(fds
[1]);
8111 HeapFree(GetProcessHeap(), 0, cmdA
);
8112 HeapFree(GetProcessHeap(), 0, unixname
);
8119 /*****************************************************************************
8122 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8125 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8128 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8129 sprintfW(cmd
, fmtW
, printer_name
);
8131 r
= schedule_pipe(cmd
, filename
);
8133 HeapFree(GetProcessHeap(), 0, cmd
);
8137 #ifdef SONAME_LIBCUPS
8138 /*****************************************************************************
8139 * get_cups_jobs_ticket_options
8141 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8142 * The CUPS scheduler only looks for these in Print-File requests, and since
8143 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8146 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8148 FILE *fp
= fopen( file
, "r" );
8149 char buf
[257]; /* DSC max of 256 + '\0' */
8150 const char *ps_adobe
= "%!PS-Adobe-";
8151 const char *cups_job
= "%cupsJobTicket:";
8153 if (!fp
) return num_options
;
8154 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8155 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8156 while (fgets( buf
, sizeof(buf
), fp
))
8158 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8159 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8167 static int get_cups_default_options( const char *printer
, int num_options
, cups_option_t
**options
)
8172 if (!pcupsGetNamedDest
) return num_options
;
8174 dest
= pcupsGetNamedDest( NULL
, printer
, NULL
);
8175 if (!dest
) return num_options
;
8177 for (i
= 0; i
< dest
->num_options
; i
++)
8179 if (!pcupsGetOption( dest
->options
[i
].name
, num_options
, *options
))
8180 num_options
= pcupsAddOption( dest
->options
[i
].name
, dest
->options
[i
].value
,
8181 num_options
, options
);
8184 pcupsFreeDests( 1, dest
);
8189 /*****************************************************************************
8192 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8194 #ifdef SONAME_LIBCUPS
8197 char *unixname
, *queue
, *unix_doc_title
;
8200 int num_options
= 0, i
;
8201 cups_option_t
*options
= NULL
;
8203 if(!(unixname
= wine_get_unix_file_name(filename
)))
8206 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8207 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8208 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8210 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8211 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8212 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8214 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8215 num_options
= get_cups_default_options( queue
, num_options
, &options
);
8217 TRACE( "printing via cups with options:\n" );
8218 for (i
= 0; i
< num_options
; i
++)
8219 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8221 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8223 pcupsFreeOptions( num_options
, options
);
8225 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8226 HeapFree(GetProcessHeap(), 0, queue
);
8227 HeapFree(GetProcessHeap(), 0, unixname
);
8233 return schedule_lpr(printer_name
, filename
);
8237 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8244 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8248 if(HIWORD(wparam
) == BN_CLICKED
)
8250 if(LOWORD(wparam
) == IDOK
)
8253 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8256 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8257 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8259 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8261 WCHAR caption
[200], message
[200];
8264 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8265 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
8266 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8267 if(mb_ret
== IDCANCEL
)
8269 HeapFree(GetProcessHeap(), 0, filename
);
8273 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8274 if(hf
== INVALID_HANDLE_VALUE
)
8276 WCHAR caption
[200], message
[200];
8278 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8279 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
8280 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8281 HeapFree(GetProcessHeap(), 0, filename
);
8285 DeleteFileW(filename
);
8286 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8288 EndDialog(hwnd
, IDOK
);
8291 if(LOWORD(wparam
) == IDCANCEL
)
8293 EndDialog(hwnd
, IDCANCEL
);
8302 /*****************************************************************************
8305 static BOOL
get_filename(LPWSTR
*filename
)
8307 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8308 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8311 /*****************************************************************************
8314 static BOOL
schedule_file(LPCWSTR filename
)
8316 LPWSTR output
= NULL
;
8318 if(get_filename(&output
))
8321 TRACE("copy to %s\n", debugstr_w(output
));
8322 r
= CopyFileW(filename
, output
, FALSE
);
8323 HeapFree(GetProcessHeap(), 0, output
);
8329 /*****************************************************************************
8332 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8334 int in_fd
, out_fd
, no_read
;
8337 char *unixname
, *outputA
;
8340 if(!(unixname
= wine_get_unix_file_name(filename
)))
8343 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8344 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8345 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8347 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8348 in_fd
= open(unixname
, O_RDONLY
);
8349 if(out_fd
== -1 || in_fd
== -1)
8352 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8353 write(out_fd
, buf
, no_read
);
8357 if(in_fd
!= -1) close(in_fd
);
8358 if(out_fd
!= -1) close(out_fd
);
8359 HeapFree(GetProcessHeap(), 0, outputA
);
8360 HeapFree(GetProcessHeap(), 0, unixname
);
8364 /*****************************************************************************
8365 * ScheduleJob [WINSPOOL.@]
8368 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8370 opened_printer_t
*printer
;
8372 struct list
*cursor
, *cursor2
;
8374 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8375 EnterCriticalSection(&printer_handles_cs
);
8376 printer
= get_opened_printer(hPrinter
);
8380 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8382 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8385 if(job
->job_id
!= dwJobID
) continue;
8387 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8388 if(hf
!= INVALID_HANDLE_VALUE
)
8390 PRINTER_INFO_5W
*pi5
= NULL
;
8391 LPWSTR portname
= job
->portname
;
8395 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8396 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8400 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8401 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8402 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8403 portname
= pi5
->pPortName
;
8405 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8406 debugstr_w(portname
));
8410 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8411 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8413 DWORD type
, count
= sizeof(output
);
8414 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8417 if(output
[0] == '|')
8419 ret
= schedule_pipe(output
+ 1, job
->filename
);
8423 ret
= schedule_unixfile(output
, job
->filename
);
8425 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8427 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8429 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8431 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8433 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8435 ret
= schedule_file(job
->filename
);
8439 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8441 HeapFree(GetProcessHeap(), 0, pi5
);
8443 DeleteFileW(job
->filename
);
8445 list_remove(cursor
);
8446 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8447 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8448 HeapFree(GetProcessHeap(), 0, job
->portname
);
8449 HeapFree(GetProcessHeap(), 0, job
->filename
);
8450 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8451 HeapFree(GetProcessHeap(), 0, job
);
8455 LeaveCriticalSection(&printer_handles_cs
);
8459 /*****************************************************************************
8460 * StartDocDlgA [WINSPOOL.@]
8462 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8464 UNICODE_STRING usBuffer
;
8467 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8470 docW
.cbSize
= sizeof(docW
);
8471 if (doc
->lpszDocName
)
8473 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8474 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
8476 if (doc
->lpszOutput
)
8478 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8479 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
8481 if (doc
->lpszDatatype
)
8483 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8484 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
8486 docW
.fwType
= doc
->fwType
;
8488 retW
= StartDocDlgW(hPrinter
, &docW
);
8492 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8493 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8494 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8495 HeapFree(GetProcessHeap(), 0, retW
);
8498 HeapFree(GetProcessHeap(), 0, datatypeW
);
8499 HeapFree(GetProcessHeap(), 0, outputW
);
8500 HeapFree(GetProcessHeap(), 0, docnameW
);
8505 /*****************************************************************************
8506 * StartDocDlgW [WINSPOOL.@]
8508 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8509 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8510 * port is "FILE:". Also returns the full path if passed a relative path.
8512 * The caller should free the returned string from the process heap.
8514 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8519 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8521 PRINTER_INFO_5W
*pi5
;
8522 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8523 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8525 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8526 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8527 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8529 HeapFree(GetProcessHeap(), 0, pi5
);
8532 HeapFree(GetProcessHeap(), 0, pi5
);
8535 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8539 if (get_filename(&name
))
8541 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8543 HeapFree(GetProcessHeap(), 0, name
);
8546 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8547 GetFullPathNameW(name
, len
, ret
, NULL
);
8548 HeapFree(GetProcessHeap(), 0, name
);
8553 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8556 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8557 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8559 attr
= GetFileAttributesW(ret
);
8560 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8562 HeapFree(GetProcessHeap(), 0, ret
);
8568 /*****************************************************************************
8569 * UploadPrinterDriverPackageA [WINSPOOL.@]
8571 HRESULT WINAPI
UploadPrinterDriverPackageA( LPCSTR server
, LPCSTR path
, LPCSTR env
,
8572 DWORD flags
, HWND hwnd
, LPSTR dst
, PULONG dstlen
)
8574 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server
), debugstr_a(path
), debugstr_a(env
),
8575 flags
, hwnd
, dst
, dstlen
);
8579 /*****************************************************************************
8580 * UploadPrinterDriverPackageW [WINSPOOL.@]
8582 HRESULT WINAPI
UploadPrinterDriverPackageW( LPCWSTR server
, LPCWSTR path
, LPCWSTR env
,
8583 DWORD flags
, HWND hwnd
, LPWSTR dst
, PULONG dstlen
)
8585 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server
), debugstr_w(path
), debugstr_w(env
),
8586 flags
, hwnd
, dst
, dstlen
);