4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
47 #ifdef HAVE_CUPS_PPD_H
48 # include <cups/ppd.h>
51 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
52 #define GetCurrentProcess GetCurrentProcess_Mac
53 #define GetCurrentThread GetCurrentThread_Mac
54 #define LoadResource LoadResource_Mac
55 #define AnimatePalette AnimatePalette_Mac
56 #define EqualRgn EqualRgn_Mac
57 #define FillRgn FillRgn_Mac
58 #define FrameRgn FrameRgn_Mac
59 #define GetPixel GetPixel_Mac
60 #define InvertRgn InvertRgn_Mac
61 #define LineTo LineTo_Mac
62 #define OffsetRgn OffsetRgn_Mac
63 #define PaintRgn PaintRgn_Mac
64 #define Polygon Polygon_Mac
65 #define ResizePalette ResizePalette_Mac
66 #define SetRectRgn SetRectRgn_Mac
67 #define EqualRect EqualRect_Mac
68 #define FillRect FillRect_Mac
69 #define FrameRect FrameRect_Mac
70 #define GetCursor GetCursor_Mac
71 #define InvertRect InvertRect_Mac
72 #define OffsetRect OffsetRect_Mac
73 #define PtInRect PtInRect_Mac
74 #define SetCursor SetCursor_Mac
75 #define SetRect SetRect_Mac
76 #define ShowCursor ShowCursor_Mac
77 #define UnionRect UnionRect_Mac
78 #include <ApplicationServices/ApplicationServices.h>
79 #undef GetCurrentProcess
80 #undef GetCurrentThread
107 #define NONAMELESSSTRUCT
108 #define NONAMELESSUNION
110 #include "wine/library.h"
114 #include "winerror.h"
117 #include "winspool.h"
118 #include "winternl.h"
119 #include "wine/windef16.h"
120 #include "wine/unicode.h"
121 #include "wine/debug.h"
122 #include "wine/list.h"
125 #include "ddk/winsplp.h"
128 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
130 /* ############################### */
132 static CRITICAL_SECTION printer_handles_cs
;
133 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
135 0, 0, &printer_handles_cs
,
136 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
137 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
139 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
141 /* ############################### */
156 HANDLE backend_printer
;
167 WCHAR
*document_title
;
177 LPCWSTR versionregpath
;
178 LPCWSTR versionsubdir
;
181 /* ############################### */
183 static opened_printer_t
**printer_handles
;
184 static UINT nb_printer_handles
;
185 static LONG next_job_id
= 1;
187 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
188 WORD fwCapability
, LPSTR lpszOutput
,
190 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
191 LPSTR lpszDevice
, LPSTR lpszPort
,
192 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
195 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
196 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
197 'c','o','n','t','r','o','l','\\',
198 'P','r','i','n','t','\\',
199 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
200 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
202 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
203 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
204 'C','o','n','t','r','o','l','\\',
205 'P','r','i','n','t','\\',
206 'P','r','i','n','t','e','r','s',0};
208 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
209 'M','i','c','r','o','s','o','f','t','\\',
210 'W','i','n','d','o','w','s',' ','N','T','\\',
211 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
212 'W','i','n','d','o','w','s',0};
214 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
215 'M','i','c','r','o','s','o','f','t','\\',
216 'W','i','n','d','o','w','s',' ','N','T','\\',
217 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
218 'D','e','v','i','c','e','s',0};
220 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
221 'M','i','c','r','o','s','o','f','t','\\',
222 'W','i','n','d','o','w','s',' ','N','T','\\',
223 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
224 'P','r','i','n','t','e','r','P','o','r','t','s',0};
226 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
227 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
228 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
229 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
230 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
231 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
232 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
233 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
234 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
235 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
237 static const WCHAR AttributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0};
238 static const WCHAR backslashW
[] = {'\\',0};
239 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
240 'i','o','n',' ','F','i','l','e',0};
241 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
242 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
243 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
244 static const WCHAR Default_PriorityW
[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
245 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
246 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
247 static const WCHAR dnsTimeoutW
[] = {'d','n','s','T','i','m','e','o','u','t',0};
248 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
249 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
250 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
251 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
252 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
253 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
254 static const WCHAR NameW
[] = {'N','a','m','e',0};
255 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
256 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
257 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
258 static const WCHAR PortW
[] = {'P','o','r','t',0};
259 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
260 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
261 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
262 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
263 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
264 static const WCHAR PriorityW
[] = {'P','r','i','o','r','i','t','y',0};
265 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
266 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
267 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
268 static const WCHAR StartTimeW
[] = {'S','t','a','r','t','T','i','m','e',0};
269 static const WCHAR StatusW
[] = {'S','t','a','t','u','s',0};
270 static const WCHAR txTimeoutW
[] = {'t','x','T','i','m','e','o','u','t',0};
271 static const WCHAR UntilTimeW
[] = {'U','n','t','i','l','T','i','m','e',0};
272 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
273 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
274 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
275 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
276 static WCHAR rawW
[] = {'R','A','W',0};
277 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
278 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
279 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
280 static const WCHAR commaW
[] = {',',0};
281 static WCHAR emptyStringW
[] = {0};
283 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
285 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
286 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
287 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
289 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
290 'D','o','c','u','m','e','n','t',0};
292 static const WCHAR PPD_Overrides
[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
293 static const WCHAR DefaultPageSize
[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
295 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
296 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
297 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
298 0, sizeof(DRIVER_INFO_8W
)};
301 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
302 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
303 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
304 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
305 sizeof(PRINTER_INFO_9W
)};
307 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
308 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
309 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
311 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
313 /******************************************************************
314 * validate the user-supplied printing-environment [internal]
317 * env [I] PTR to Environment-String or NULL
321 * Success: PTR to printenv_t
324 * An empty string is handled the same way as NULL.
325 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
329 static const printenv_t
* validate_envW(LPCWSTR env
)
331 const printenv_t
*result
= NULL
;
334 TRACE("testing %s\n", debugstr_w(env
));
337 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
339 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
341 result
= all_printenv
[i
];
346 if (result
== NULL
) {
347 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
348 SetLastError(ERROR_INVALID_ENVIRONMENT
);
350 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
354 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
356 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
362 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
363 if passed a NULL string. This returns NULLs to the result.
365 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
369 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
370 return usBufferPtr
->Buffer
;
372 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
376 static LPWSTR
strdupW(LPCWSTR p
)
382 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
383 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
388 static LPSTR
strdupWtoA( LPCWSTR str
)
393 if (!str
) return NULL
;
394 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
395 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
396 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
400 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
404 if (!dm
) return NULL
;
405 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
406 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
410 /***********************************************************
412 * Creates an ansi copy of supplied devmode
414 static DEVMODEA
*DEVMODEdupWtoA( const DEVMODEW
*dmW
)
419 if (!dmW
) return NULL
;
420 size
= dmW
->dmSize
- CCHDEVICENAME
-
421 ((dmW
->dmSize
> FIELD_OFFSET( DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
423 dmA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
424 if (!dmA
) return NULL
;
426 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmDeviceName
, -1,
427 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
429 if (FIELD_OFFSET( DEVMODEW
, dmFormName
) >= dmW
->dmSize
)
431 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
432 dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
436 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
437 FIELD_OFFSET( DEVMODEW
, dmFormName
) - FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
438 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmFormName
, -1,
439 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
441 memcpy( &dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmLogPixels
) );
445 memcpy( (char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
450 /******************************************************************
451 * verify, that the filename is a local file
454 static inline BOOL
is_local_file(LPWSTR name
)
456 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
459 /* ################################ */
461 static int multi_sz_lenA(const char *str
)
463 const char *ptr
= str
;
467 ptr
+= lstrlenA(ptr
) + 1;
470 return ptr
- str
+ 1;
473 /*****************************************************************************
476 * Return DWORD associated with name from hkey.
478 static DWORD
get_dword_from_reg( HKEY hkey
, const WCHAR
*name
)
480 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
483 ret
= RegQueryValueExW( hkey
, name
, 0, &type
, (LPBYTE
)&value
, &sz
);
485 if (ret
!= ERROR_SUCCESS
)
487 WARN( "Got ret = %d on name %s\n", ret
, debugstr_w(name
) );
490 if (type
!= REG_DWORD
)
492 ERR( "Got type %d\n", type
);
498 static inline DWORD
set_reg_DWORD( HKEY hkey
, const WCHAR
*keyname
, const DWORD value
)
500 return RegSetValueExW( hkey
, keyname
, 0, REG_DWORD
, (const BYTE
*)&value
, sizeof(value
) );
503 /******************************************************************
505 * Get the pointer to the opened printer referred by the handle
507 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
509 UINT_PTR idx
= (UINT_PTR
)hprn
;
510 opened_printer_t
*ret
= NULL
;
512 EnterCriticalSection(&printer_handles_cs
);
514 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
515 ret
= printer_handles
[idx
- 1];
517 LeaveCriticalSection(&printer_handles_cs
);
521 /******************************************************************
522 * get_opened_printer_name
523 * Get the pointer to the opened printer name referred by the handle
525 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
527 opened_printer_t
*printer
= get_opened_printer(hprn
);
528 if(!printer
) return NULL
;
529 return printer
->name
;
532 static DWORD
open_printer_reg_key( const WCHAR
*name
, HKEY
*key
)
538 err
= RegCreateKeyW( HKEY_LOCAL_MACHINE
, PrintersW
, &printers
);
541 err
= RegOpenKeyW( printers
, name
, key
);
542 if (err
) err
= ERROR_INVALID_PRINTER_NAME
;
543 RegCloseKey( printers
);
547 /******************************************************************
548 * WINSPOOL_GetOpenedPrinterRegKey
551 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
553 LPCWSTR name
= get_opened_printer_name(hPrinter
);
555 if(!name
) return ERROR_INVALID_HANDLE
;
556 return open_printer_reg_key( name
, phkey
);
560 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
563 /* If forcing, or no profile string entry for device yet, set the entry
565 * The always change entry if not WINEPS yet is discussable.
568 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
570 !strstr(qbuf
,"WINEPS.DRV")
572 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
575 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
576 WriteProfileStringA("windows","device",buf
);
577 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
578 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
581 HeapFree(GetProcessHeap(),0,buf
);
585 static BOOL
add_printer_driver(const WCHAR
*name
, WCHAR
*ppd
)
591 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
593 di3
.pName
= (WCHAR
*)name
;
594 di3
.pDriverPath
= driver_nt
;
596 di3
.pConfigFile
= driver_nt
;
597 di3
.pDefaultDataType
= rawW
;
599 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
601 di3
.pEnvironment
= (WCHAR
*) all_printenv
[i
]->envname
;
602 if (all_printenv
[i
]->envname
== envname_win40W
)
604 /* We use wineps16.drv as driver for 16 bit */
605 di3
.pDriverPath
= driver_9x
;
606 di3
.pConfigFile
= driver_9x
;
608 res
= AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
);
609 TRACE("got %d and %d for %s (%s)\n", res
, GetLastError(), debugstr_w(name
), debugstr_w(di3
.pEnvironment
));
611 if (!res
&& (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
613 ERR("failed with %u for %s (%s) %s\n", GetLastError(), debugstr_w(name
),
614 debugstr_w(di3
.pEnvironment
), debugstr_w(di3
.pDriverPath
));
622 static inline char *expand_env_string( char *str
, DWORD type
)
624 if (type
== REG_EXPAND_SZ
)
627 DWORD needed
= ExpandEnvironmentStringsA( str
, NULL
, 0 );
628 tmp
= HeapAlloc( GetProcessHeap(), 0, needed
);
631 ExpandEnvironmentStringsA( str
, tmp
, needed
);
632 HeapFree( GetProcessHeap(), 0, str
);
639 static char *get_fallback_ppd_name( const char *printer_name
)
641 static const WCHAR ppds_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
642 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
647 if (RegOpenKeyW( HKEY_CURRENT_USER
, ppds_key
, &hkey
) == ERROR_SUCCESS
)
649 const char *value_name
= NULL
;
651 if (RegQueryValueExA( hkey
, printer_name
, 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
652 value_name
= printer_name
;
653 else if (RegQueryValueExA( hkey
, "generic", 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
654 value_name
= "generic";
658 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
659 if (!ret
) return NULL
;
660 RegQueryValueExA( hkey
, value_name
, 0, &type
, (BYTE
*)ret
, &needed
);
663 if (ret
) return expand_env_string( ret
, type
);
668 static BOOL
copy_file( const char *src
, const char *dst
)
670 int fds
[2] = {-1, -1}, num
;
674 fds
[0] = open( src
, O_RDONLY
);
675 fds
[1] = open( dst
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666 );
676 if (fds
[0] == -1 || fds
[1] == -1) goto fail
;
678 while ((num
= read( fds
[0], buf
, sizeof(buf
) )) != 0)
680 if (num
== -1) goto fail
;
681 if (write( fds
[1], buf
, num
) != num
) goto fail
;
686 if (fds
[1] != -1) close( fds
[1] );
687 if (fds
[0] != -1) close( fds
[0] );
691 static BOOL
get_internal_fallback_ppd( const WCHAR
*ppd
)
693 static const WCHAR typeW
[] = {'P','P','D','F','I','L','E',0};
699 HRSRC res
= FindResourceW( WINSPOOL_hInstance
, MAKEINTRESOURCEW(1), typeW
);
701 if (!res
|| !(ptr
= LoadResource( WINSPOOL_hInstance
, res
))) return FALSE
;
702 size
= SizeofResource( WINSPOOL_hInstance
, res
);
703 end
= memchr( ptr
, 0, size
); /* resource file may contain additional nulls */
704 if (end
) size
= end
- ptr
;
705 file
= CreateFileW( ppd
, GENERIC_WRITE
, FILE_SHARE_READ
, NULL
, CREATE_ALWAYS
, 0, 0 );
706 if (file
== INVALID_HANDLE_VALUE
) return FALSE
;
707 ret
= WriteFile( file
, ptr
, size
, &written
, NULL
) && written
== size
;
709 if (ret
) TRACE( "using internal fallback for %s\n", debugstr_w( ppd
));
710 else DeleteFileW( ppd
);
714 static BOOL
get_fallback_ppd( const char *printer_name
, const WCHAR
*ppd
)
716 char *dst
, *src
= get_fallback_ppd_name( printer_name
);
719 if (!src
) return get_internal_fallback_ppd( ppd
);
721 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name
), debugstr_w(ppd
), debugstr_a(src
) );
723 if (!(dst
= wine_get_unix_file_name( ppd
))) goto fail
;
725 if (symlink( src
, dst
) == -1)
726 if (errno
!= ENOSYS
|| !copy_file( src
, dst
))
731 HeapFree( GetProcessHeap(), 0, dst
);
732 HeapFree( GetProcessHeap(), 0, src
);
736 static WCHAR
*get_ppd_filename( const WCHAR
*dir
, const WCHAR
*file_name
)
738 static const WCHAR dot_ppd
[] = {'.','p','p','d',0};
739 int len
= (strlenW( dir
) + strlenW( file_name
)) * sizeof(WCHAR
) + sizeof(dot_ppd
);
740 WCHAR
*ppd
= HeapAlloc( GetProcessHeap(), 0, len
);
742 if (!ppd
) return NULL
;
744 strcatW( ppd
, file_name
);
745 strcatW( ppd
, dot_ppd
);
750 static WCHAR
*get_ppd_dir( void )
752 static const WCHAR wine_ppds
[] = {'w','i','n','e','_','p','p','d','s','\\',0};
754 WCHAR
*dir
, tmp_path
[MAX_PATH
];
757 len
= GetTempPathW( ARRAY_SIZE( tmp_path
), tmp_path
);
758 if (!len
) return NULL
;
759 dir
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) + sizeof(wine_ppds
) ) ;
760 if (!dir
) return NULL
;
762 memcpy( dir
, tmp_path
, len
* sizeof(WCHAR
) );
763 memcpy( dir
+ len
, wine_ppds
, sizeof(wine_ppds
) );
764 res
= CreateDirectoryW( dir
, NULL
);
765 if (!res
&& GetLastError() != ERROR_ALREADY_EXISTS
)
767 HeapFree( GetProcessHeap(), 0, dir
);
770 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir
) );
774 static void unlink_ppd( const WCHAR
*ppd
)
776 char *unix_name
= wine_get_unix_file_name( ppd
);
778 HeapFree( GetProcessHeap(), 0, unix_name
);
781 #ifdef SONAME_LIBCUPS
783 static void *cupshandle
;
786 DO_FUNC(cupsAddOption); \
787 DO_FUNC(cupsFreeDests); \
788 DO_FUNC(cupsFreeOptions); \
789 DO_FUNC(cupsGetDests); \
790 DO_FUNC(cupsGetOption); \
791 DO_FUNC(cupsParseOptions); \
792 DO_FUNC(cupsPrintFile)
793 #define CUPS_OPT_FUNCS \
794 DO_FUNC(cupsGetNamedDest); \
795 DO_FUNC(cupsGetPPD); \
796 DO_FUNC(cupsGetPPD3); \
797 DO_FUNC(cupsLastErrorString)
799 #define DO_FUNC(f) static typeof(f) *p##f
802 static cups_dest_t
* (*pcupsGetNamedDest
)(http_t
*, const char *, const char *);
803 static const char * (*pcupsGetPPD
)(const char *);
804 static http_status_t (*pcupsGetPPD3
)(http_t
*, const char *, time_t *, char *, size_t);
805 static const char * (*pcupsLastErrorString
)(void);
807 static http_status_t
cupsGetPPD3_wrapper( http_t
*http
, const char *name
,
808 time_t *modtime
, char *buffer
,
813 if (pcupsGetPPD3
) return pcupsGetPPD3( http
, name
, modtime
, buffer
, bufsize
);
815 if (!pcupsGetPPD
) return HTTP_NOT_FOUND
;
817 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
820 ppd
= pcupsGetPPD( name
);
822 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd
) );
824 if (!ppd
) return HTTP_NOT_FOUND
;
826 if (rename( ppd
, buffer
) == -1)
828 BOOL res
= copy_file( ppd
, buffer
);
830 if (!res
) return HTTP_NOT_FOUND
;
835 static BOOL
get_cups_ppd( const char *printer_name
, const WCHAR
*ppd
)
838 http_status_t http_status
;
839 char *unix_name
= wine_get_unix_file_name( ppd
);
841 TRACE( "(%s, %s)\n", debugstr_a(printer_name
), debugstr_w(ppd
) );
843 if (!unix_name
) return FALSE
;
845 http_status
= cupsGetPPD3_wrapper( 0, printer_name
, &modtime
,
846 unix_name
, strlen( unix_name
) + 1 );
848 if (http_status
!= HTTP_OK
) unlink( unix_name
);
849 HeapFree( GetProcessHeap(), 0, unix_name
);
851 if (http_status
== HTTP_OK
) return TRUE
;
853 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
854 debugstr_a(printer_name
), http_status
);
855 return get_fallback_ppd( printer_name
, ppd
);
858 static WCHAR
*get_cups_option( const char *name
, int num_options
, cups_option_t
*options
)
864 value
= pcupsGetOption( name
, num_options
, options
);
865 if (!value
) return NULL
;
867 len
= MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, NULL
, 0 );
868 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
869 if (ret
) MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, ret
, len
);
874 static cups_ptype_t
get_cups_printer_type( const cups_dest_t
*dest
)
876 WCHAR
*type
= get_cups_option( "printer-type", dest
->num_options
, dest
->options
), *end
;
877 cups_ptype_t ret
= 0;
881 ret
= (cups_ptype_t
)strtoulW( type
, &end
, 10 );
884 HeapFree( GetProcessHeap(), 0, type
);
888 static void load_cups(void)
890 cupshandle
= wine_dlopen( SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0 );
891 if (!cupshandle
) return;
893 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
896 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
899 ERR("failed to load symbol %s\n", #x); \
905 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
910 static BOOL
CUPS_LoadPrinters(void)
913 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
916 WCHAR
*port
, *ppd_dir
= NULL
, *ppd
;
917 HKEY hkeyPrinter
, hkeyPrinters
;
918 WCHAR nameW
[MAX_PATH
];
919 HANDLE added_printer
;
920 cups_ptype_t printer_type
;
922 if (!cupshandle
) return FALSE
;
924 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
926 ERR("Can't create Printers key\n");
930 nrofdests
= pcupsGetDests(&dests
);
931 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
932 for (i
=0;i
<nrofdests
;i
++) {
933 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, ARRAY_SIZE(nameW
));
934 printer_type
= get_cups_printer_type( dests
+ i
);
936 TRACE( "Printer %d: %s. printer_type %x\n", i
, debugstr_w(nameW
), printer_type
);
938 if (printer_type
& 0x2000000 /* CUPS_PRINTER_SCANNER */)
940 TRACE( "skipping scanner-only device\n" );
944 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
945 lstrcpyW(port
, CUPS_Port
);
946 lstrcatW(port
, nameW
);
948 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
949 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
950 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
952 TRACE("Printer already exists\n");
953 /* overwrite old LPR:* port */
954 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
955 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
956 /* flag that the PPD file should be checked for an update */
957 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
958 RegCloseKey(hkeyPrinter
);
960 BOOL added_driver
= FALSE
;
962 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir()))
964 HeapFree( GetProcessHeap(), 0, port
);
967 ppd
= get_ppd_filename( ppd_dir
, nameW
);
968 if (get_cups_ppd( dests
[i
].name
, ppd
))
970 added_driver
= add_printer_driver( nameW
, ppd
);
973 HeapFree( GetProcessHeap(), 0, ppd
);
976 HeapFree( GetProcessHeap(), 0, port
);
980 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
981 pi2
.pPrinterName
= nameW
;
982 pi2
.pDatatype
= rawW
;
983 pi2
.pPrintProcessor
= WinPrintW
;
984 pi2
.pDriverName
= nameW
;
985 pi2
.pComment
= get_cups_option( "printer-info", dests
[i
].num_options
, dests
[i
].options
);
986 pi2
.pLocation
= get_cups_option( "printer-location", dests
[i
].num_options
, dests
[i
].options
);
987 pi2
.pPortName
= port
;
988 pi2
.pParameters
= emptyStringW
;
989 pi2
.pShareName
= emptyStringW
;
990 pi2
.pSepFile
= emptyStringW
;
992 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
993 if (added_printer
) ClosePrinter( added_printer
);
994 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
995 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
997 HeapFree( GetProcessHeap(), 0, pi2
.pComment
);
998 HeapFree( GetProcessHeap(), 0, pi2
.pLocation
);
1000 HeapFree( GetProcessHeap(), 0, port
);
1003 if (dests
[i
].is_default
) {
1004 SetDefaultPrinterW(nameW
);
1011 RemoveDirectoryW( ppd_dir
);
1012 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1015 if (hadprinter
&& !haddefault
) {
1016 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, ARRAY_SIZE(nameW
));
1017 SetDefaultPrinterW(nameW
);
1019 pcupsFreeDests(nrofdests
, dests
);
1020 RegCloseKey(hkeyPrinters
);
1026 static char *get_queue_name( HANDLE printer
, BOOL
*cups
)
1028 WCHAR
*port
, *name
= NULL
;
1029 DWORD err
, needed
, type
;
1035 err
= WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
);
1036 if (err
) return NULL
;
1037 err
= RegQueryValueExW( key
, PortW
, 0, &type
, NULL
, &needed
);
1039 port
= HeapAlloc( GetProcessHeap(), 0, needed
);
1040 if (!port
) goto end
;
1041 RegQueryValueExW( key
, PortW
, 0, &type
, (BYTE
*)port
, &needed
);
1043 if (!strncmpW( port
, CUPS_Port
, ARRAY_SIZE( CUPS_Port
) -1 ))
1045 name
= port
+ ARRAY_SIZE( CUPS_Port
) - 1;
1048 else if (!strncmpW( port
, LPR_Port
, ARRAY_SIZE( LPR_Port
) -1 ))
1049 name
= port
+ ARRAY_SIZE( LPR_Port
) - 1;
1052 needed
= WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
1053 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
1054 if(ret
) WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, ret
, needed
, NULL
, NULL
);
1056 HeapFree( GetProcessHeap(), 0, port
);
1063 static void set_ppd_overrides( HANDLE printer
)
1067 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1069 PMPrintSession session
= NULL
;
1070 PMPageFormat format
= NULL
;
1072 CFStringRef paper_name
;
1075 status
= PMCreateSession( &session
);
1076 if (status
) goto end
;
1078 status
= PMCreatePageFormat( &format
);
1079 if (status
) goto end
;
1081 status
= PMSessionDefaultPageFormat( session
, format
);
1082 if (status
) goto end
;
1084 status
= PMGetPageFormatPaper( format
, &paper
);
1085 if (status
) goto end
;
1087 status
= PMPaperGetPPDPaperName( paper
, &paper_name
);
1088 if (status
) goto end
;
1091 range
.length
= CFStringGetLength( paper_name
);
1092 size
= (range
.length
+ 1) * sizeof(WCHAR
);
1094 wstr
= HeapAlloc( GetProcessHeap(), 0, size
);
1095 CFStringGetCharacters( paper_name
, range
, (UniChar
*)wstr
);
1096 wstr
[range
.length
] = 0;
1099 if (format
) PMRelease( format
);
1100 if (session
) PMRelease( session
);
1103 SetPrinterDataExW( printer
, PPD_Overrides
, DefaultPageSize
, REG_SZ
, (BYTE
*)wstr
, size
);
1104 HeapFree( GetProcessHeap(), 0, wstr
);
1107 static BOOL
update_driver( HANDLE printer
)
1110 const WCHAR
*name
= get_opened_printer_name( printer
);
1111 WCHAR
*ppd_dir
, *ppd
;
1114 if (!name
) return FALSE
;
1115 queue_name
= get_queue_name( printer
, &is_cups
);
1116 if (!queue_name
) return FALSE
;
1118 if (!(ppd_dir
= get_ppd_dir()))
1120 HeapFree( GetProcessHeap(), 0, queue_name
);
1123 ppd
= get_ppd_filename( ppd_dir
, name
);
1125 #ifdef SONAME_LIBCUPS
1127 ret
= get_cups_ppd( queue_name
, ppd
);
1130 ret
= get_fallback_ppd( queue_name
, ppd
);
1134 TRACE( "updating driver %s\n", debugstr_w( name
) );
1135 ret
= add_printer_driver( name
, ppd
);
1138 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1139 HeapFree( GetProcessHeap(), 0, ppd
);
1140 HeapFree( GetProcessHeap(), 0, queue_name
);
1142 set_ppd_overrides( printer
);
1144 /* call into the driver to update the devmode */
1145 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
1150 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
1152 PRINTER_INFO_2A pinfo2a
;
1155 char *e
,*s
,*name
,*prettyname
,*devname
;
1156 BOOL ret
= FALSE
, set_default
= FALSE
;
1157 char *port
= NULL
, *env_default
;
1158 HKEY hkeyPrinter
, hkeyPrinters
= NULL
;
1159 WCHAR devnameW
[MAX_PATH
], *ppd_dir
= NULL
, *ppd
;
1160 HANDLE added_printer
;
1162 while (isspace(*pent
)) pent
++;
1163 r
= strchr(pent
,':');
1165 name_len
= r
- pent
;
1167 name_len
= strlen(pent
);
1168 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
1169 memcpy(name
, pent
, name_len
);
1170 name
[name_len
] = '\0';
1176 TRACE("name=%s entry=%s\n",name
, pent
);
1178 if(ispunct(*name
)) { /* a tc entry, not a real printer */
1179 TRACE("skipping tc entry\n");
1183 if(strstr(pent
,":server")) { /* server only version so skip */
1184 TRACE("skipping server entry\n");
1188 /* Determine whether this is a postscript printer. */
1191 env_default
= getenv("PRINTER");
1193 /* Get longest name, usually the one at the right for later display. */
1194 while((s
=strchr(prettyname
,'|'))) {
1197 while(isspace(*--e
)) *e
= '\0';
1198 TRACE("\t%s\n", debugstr_a(prettyname
));
1199 if(env_default
&& !_strnicmp(prettyname
, env_default
, -1)) set_default
= TRUE
;
1200 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
1203 e
= prettyname
+ strlen(prettyname
);
1204 while(isspace(*--e
)) *e
= '\0';
1205 TRACE("\t%s\n", debugstr_a(prettyname
));
1206 if(env_default
&& !_strnicmp(prettyname
, env_default
, -1)) set_default
= TRUE
;
1208 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1209 * if it is too long, we use it as comment below. */
1210 devname
= prettyname
;
1211 if (strlen(devname
)>=CCHDEVICENAME
-1)
1213 if (strlen(devname
)>=CCHDEVICENAME
-1) {
1218 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
1219 sprintf(port
,"LPR:%s",name
);
1221 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1223 ERR("Can't create Printers key\n");
1228 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, ARRAY_SIZE(devnameW
));
1230 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1231 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1232 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1234 TRACE("Printer already exists\n");
1235 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1236 /* flag that the PPD file should be checked for an update */
1237 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1238 RegCloseKey(hkeyPrinter
);
1240 static CHAR data_type
[] = "RAW",
1241 print_proc
[] = "WinPrint",
1242 comment
[] = "WINEPS Printer using LPR",
1243 params
[] = "<parameters?>",
1244 share_name
[] = "<share name?>",
1245 sep_file
[] = "<sep file?>";
1246 BOOL added_driver
= FALSE
;
1248 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir())) goto end
;
1249 ppd
= get_ppd_filename( ppd_dir
, devnameW
);
1250 if (get_fallback_ppd( devname
, ppd
))
1252 added_driver
= add_printer_driver( devnameW
, ppd
);
1255 HeapFree( GetProcessHeap(), 0, ppd
);
1256 if (!added_driver
) goto end
;
1258 memset(&pinfo2a
,0,sizeof(pinfo2a
));
1259 pinfo2a
.pPrinterName
= devname
;
1260 pinfo2a
.pDatatype
= data_type
;
1261 pinfo2a
.pPrintProcessor
= print_proc
;
1262 pinfo2a
.pDriverName
= devname
;
1263 pinfo2a
.pComment
= comment
;
1264 pinfo2a
.pLocation
= prettyname
;
1265 pinfo2a
.pPortName
= port
;
1266 pinfo2a
.pParameters
= params
;
1267 pinfo2a
.pShareName
= share_name
;
1268 pinfo2a
.pSepFile
= sep_file
;
1270 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
1271 if (added_printer
) ClosePrinter( added_printer
);
1272 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1273 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
1276 if (isfirst
|| set_default
)
1277 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
1280 if (hkeyPrinters
) RegCloseKey( hkeyPrinters
);
1283 RemoveDirectoryW( ppd_dir
);
1284 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1286 HeapFree(GetProcessHeap(), 0, port
);
1287 HeapFree(GetProcessHeap(), 0, name
);
1292 PRINTCAP_LoadPrinters(void) {
1293 BOOL hadprinter
= FALSE
;
1297 BOOL had_bash
= FALSE
;
1299 f
= fopen("/etc/printcap","r");
1303 while(fgets(buf
,sizeof(buf
),f
)) {
1306 end
=strchr(buf
,'\n');
1310 while(isspace(*start
)) start
++;
1311 if(*start
== '#' || *start
== '\0')
1314 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
1315 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1316 HeapFree(GetProcessHeap(),0,pent
);
1320 if (end
&& *--end
== '\\') {
1327 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
1330 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
1336 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1337 HeapFree(GetProcessHeap(),0,pent
);
1343 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
1346 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
1347 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
1349 return ERROR_FILE_NOT_FOUND
;
1352 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
1354 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
1355 DWORD ret
= ERROR_FILE_NOT_FOUND
;
1357 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1358 and we support these drivers. NT writes DEVMODEW so somehow
1359 we'll need to distinguish between these when we support NT
1364 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
1365 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1366 HeapFree( GetProcessHeap(), 0, dmA
);
1372 /******************************************************************
1373 * get_servername_from_name (internal)
1375 * for an external server, a copy of the serverpart from the full name is returned
1378 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1382 WCHAR buffer
[MAX_PATH
];
1385 if (name
== NULL
) return NULL
;
1386 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1388 server
= strdupW(&name
[2]); /* skip over both backslash */
1389 if (server
== NULL
) return NULL
;
1391 /* strip '\' and the printername */
1392 ptr
= strchrW(server
, '\\');
1393 if (ptr
) ptr
[0] = '\0';
1395 TRACE("found %s\n", debugstr_w(server
));
1397 len
= ARRAY_SIZE(buffer
);
1398 if (GetComputerNameW(buffer
, &len
)) {
1399 if (lstrcmpW(buffer
, server
) == 0) {
1400 /* The requested Servername is our computername */
1401 HeapFree(GetProcessHeap(), 0, server
);
1408 /******************************************************************
1409 * get_basename_from_name (internal)
1411 * skip over the serverpart from the full name
1414 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1416 if (name
== NULL
) return NULL
;
1417 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1418 /* skip over the servername and search for the following '\' */
1419 name
= strchrW(&name
[2], '\\');
1420 if ((name
) && (name
[1])) {
1421 /* found a separator ('\') followed by a name:
1422 skip over the separator and return the rest */
1427 /* no basename present (we found only a servername) */
1434 static void free_printer_entry( opened_printer_t
*printer
)
1436 /* the queue is shared, so don't free that here */
1437 HeapFree( GetProcessHeap(), 0, printer
->printername
);
1438 HeapFree( GetProcessHeap(), 0, printer
->name
);
1439 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
1440 HeapFree( GetProcessHeap(), 0, printer
);
1443 /******************************************************************
1444 * get_opened_printer_entry
1445 * Get the first place empty in the opened printer table
1448 * - pDefault is ignored
1450 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1452 UINT_PTR handle
= nb_printer_handles
, i
;
1453 jobqueue_t
*queue
= NULL
;
1454 opened_printer_t
*printer
= NULL
;
1456 LPCWSTR printername
;
1458 if ((backend
== NULL
) && !load_backend()) return NULL
;
1460 servername
= get_servername_from_name(name
);
1462 FIXME("server %s not supported\n", debugstr_w(servername
));
1463 HeapFree(GetProcessHeap(), 0, servername
);
1464 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1468 printername
= get_basename_from_name(name
);
1469 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1471 /* an empty printername is invalid */
1472 if (printername
&& (!printername
[0])) {
1473 SetLastError(ERROR_INVALID_PARAMETER
);
1477 EnterCriticalSection(&printer_handles_cs
);
1479 for (i
= 0; i
< nb_printer_handles
; i
++)
1481 if (!printer_handles
[i
])
1483 if(handle
== nb_printer_handles
)
1488 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1489 queue
= printer_handles
[i
]->queue
;
1493 if (handle
>= nb_printer_handles
)
1495 opened_printer_t
**new_array
;
1496 if (printer_handles
)
1497 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1498 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1500 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1501 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1508 printer_handles
= new_array
;
1509 nb_printer_handles
+= 16;
1512 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1518 /* get a printer handle from the backend */
1519 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1524 /* clone the base name. This is NULL for the printserver */
1525 printer
->printername
= strdupW(printername
);
1527 /* clone the full name */
1528 printer
->name
= strdupW(name
);
1529 if (name
&& (!printer
->name
)) {
1534 if (pDefault
&& pDefault
->pDevMode
)
1535 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
1538 printer
->queue
= queue
;
1541 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1542 if (!printer
->queue
) {
1546 list_init(&printer
->queue
->jobs
);
1547 printer
->queue
->ref
= 0;
1549 InterlockedIncrement(&printer
->queue
->ref
);
1551 printer_handles
[handle
] = printer
;
1554 LeaveCriticalSection(&printer_handles_cs
);
1555 if (!handle
&& printer
) {
1556 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1557 free_printer_entry( printer
);
1560 return (HANDLE
)handle
;
1563 static void old_printer_check( BOOL delete_phase
)
1565 PRINTER_INFO_5W
* pi
;
1566 DWORD needed
, type
, num
, delete, i
, size
;
1567 const DWORD one
= 1;
1571 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1572 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1574 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1575 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1576 for (i
= 0; i
< num
; i
++)
1578 if (!pi
[i
].pPortName
) continue;
1580 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1581 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1584 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1588 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1594 size
= sizeof( delete );
1595 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1599 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1600 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1602 DeletePrinter( hprn
);
1603 ClosePrinter( hprn
);
1605 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1609 HeapFree(GetProcessHeap(), 0, pi
);
1612 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1613 'M','U','T','E','X','_','_','\0'};
1614 static HANDLE init_mutex
;
1616 void WINSPOOL_LoadSystemPrinters(void)
1618 HKEY hkey
, hkeyPrinters
;
1619 DWORD needed
, num
, i
;
1620 WCHAR PrinterName
[256];
1623 #ifdef SONAME_LIBCUPS
1627 /* FIXME: The init code should be moved to spoolsv.exe */
1628 init_mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1631 ERR( "Failed to create mutex\n" );
1634 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1636 WaitForSingleObject( init_mutex
, INFINITE
);
1637 ReleaseMutex( init_mutex
);
1638 TRACE( "Init already done\n" );
1642 /* This ensures that all printer entries have a valid Name value. If causes
1643 problems later if they don't. If one is found to be missed we create one
1644 and set it equal to the name of the key */
1645 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1646 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1647 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1648 for(i
= 0; i
< num
; i
++) {
1649 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, ARRAY_SIZE(PrinterName
)) == ERROR_SUCCESS
) {
1650 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1651 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1652 set_reg_szW(hkey
, NameW
, PrinterName
);
1659 RegCloseKey(hkeyPrinters
);
1662 old_printer_check( FALSE
);
1664 #ifdef SONAME_LIBCUPS
1665 done
= CUPS_LoadPrinters();
1668 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1669 PRINTCAP_LoadPrinters();
1671 old_printer_check( TRUE
);
1673 ReleaseMutex( init_mutex
);
1677 /******************************************************************
1680 * Get the pointer to the specified job.
1681 * Should hold the printer_handles_cs before calling.
1683 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1685 opened_printer_t
*printer
= get_opened_printer(hprn
);
1688 if(!printer
) return NULL
;
1689 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1691 if(job
->job_id
== JobId
)
1697 /***********************************************************
1700 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1703 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1706 Formname
= (dmA
->dmSize
> off_formname
);
1707 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1708 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1709 dmW
->dmDeviceName
, CCHDEVICENAME
);
1711 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1712 dmA
->dmSize
- CCHDEVICENAME
);
1714 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1715 off_formname
- CCHDEVICENAME
);
1716 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1717 dmW
->dmFormName
, CCHFORMNAME
);
1718 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1719 (off_formname
+ CCHFORMNAME
));
1722 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1723 dmA
->dmDriverExtra
);
1727 /******************************************************************
1728 * convert_printerinfo_W_to_A [internal]
1731 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1732 DWORD level
, DWORD outlen
, DWORD numentries
)
1738 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1740 len
= pi_sizeof
[level
] * numentries
;
1741 ptr
= (LPSTR
) out
+ len
;
1744 /* copy the numbers of all PRINTER_INFO_* first */
1745 memcpy(out
, pPrintersW
, len
);
1747 while (id
< numentries
) {
1751 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1752 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1754 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1755 if (piW
->pDescription
) {
1756 piA
->pDescription
= ptr
;
1757 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1758 ptr
, outlen
, NULL
, NULL
);
1764 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1765 ptr
, outlen
, NULL
, NULL
);
1769 if (piW
->pComment
) {
1770 piA
->pComment
= ptr
;
1771 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1772 ptr
, outlen
, NULL
, NULL
);
1781 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1782 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1785 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1786 if (piW
->pServerName
) {
1787 piA
->pServerName
= ptr
;
1788 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1789 ptr
, outlen
, NULL
, NULL
);
1793 if (piW
->pPrinterName
) {
1794 piA
->pPrinterName
= ptr
;
1795 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1796 ptr
, outlen
, NULL
, NULL
);
1800 if (piW
->pShareName
) {
1801 piA
->pShareName
= ptr
;
1802 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1803 ptr
, outlen
, NULL
, NULL
);
1807 if (piW
->pPortName
) {
1808 piA
->pPortName
= ptr
;
1809 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1810 ptr
, outlen
, NULL
, NULL
);
1814 if (piW
->pDriverName
) {
1815 piA
->pDriverName
= ptr
;
1816 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1817 ptr
, outlen
, NULL
, NULL
);
1821 if (piW
->pComment
) {
1822 piA
->pComment
= ptr
;
1823 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1824 ptr
, outlen
, NULL
, NULL
);
1828 if (piW
->pLocation
) {
1829 piA
->pLocation
= ptr
;
1830 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1831 ptr
, outlen
, NULL
, NULL
);
1836 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1838 /* align DEVMODEA to a DWORD boundary */
1839 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1843 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1844 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1845 memcpy(ptr
, dmA
, len
);
1846 HeapFree(GetProcessHeap(), 0, dmA
);
1852 if (piW
->pSepFile
) {
1853 piA
->pSepFile
= ptr
;
1854 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1855 ptr
, outlen
, NULL
, NULL
);
1859 if (piW
->pPrintProcessor
) {
1860 piA
->pPrintProcessor
= ptr
;
1861 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1862 ptr
, outlen
, NULL
, NULL
);
1866 if (piW
->pDatatype
) {
1867 piA
->pDatatype
= ptr
;
1868 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1869 ptr
, outlen
, NULL
, NULL
);
1873 if (piW
->pParameters
) {
1874 piA
->pParameters
= ptr
;
1875 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1876 ptr
, outlen
, NULL
, NULL
);
1880 if (piW
->pSecurityDescriptor
) {
1881 piA
->pSecurityDescriptor
= NULL
;
1882 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1889 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1890 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1892 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1894 if (piW
->pPrinterName
) {
1895 piA
->pPrinterName
= ptr
;
1896 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1897 ptr
, outlen
, NULL
, NULL
);
1901 if (piW
->pServerName
) {
1902 piA
->pServerName
= ptr
;
1903 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1904 ptr
, outlen
, NULL
, NULL
);
1913 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1914 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1916 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1918 if (piW
->pPrinterName
) {
1919 piA
->pPrinterName
= ptr
;
1920 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1921 ptr
, outlen
, NULL
, NULL
);
1925 if (piW
->pPortName
) {
1926 piA
->pPortName
= ptr
;
1927 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1928 ptr
, outlen
, NULL
, NULL
);
1935 case 6: /* 6A and 6W are the same structure */
1940 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1941 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1943 TRACE("(%u) #%u\n", level
, id
);
1944 if (piW
->pszObjectGUID
) {
1945 piA
->pszObjectGUID
= ptr
;
1946 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1947 ptr
, outlen
, NULL
, NULL
);
1957 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1958 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1961 TRACE("(%u) #%u\n", level
, id
);
1962 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1964 /* align DEVMODEA to a DWORD boundary */
1965 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1969 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1970 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1971 memcpy(ptr
, dmA
, len
);
1972 HeapFree(GetProcessHeap(), 0, dmA
);
1982 FIXME("for level %u\n", level
);
1984 pPrintersW
+= pi_sizeof
[level
];
1985 out
+= pi_sizeof
[level
];
1990 /******************************************************************
1991 * convert_driverinfo_W_to_A [internal]
1994 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1995 DWORD level
, DWORD outlen
, DWORD numentries
)
2001 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
2003 len
= di_sizeof
[level
] * numentries
;
2004 ptr
= (LPSTR
) out
+ len
;
2007 /* copy the numbers of all PRINTER_INFO_* first */
2008 memcpy(out
, pDriversW
, len
);
2010 #define COPY_STRING(fld) \
2013 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2014 ptr += len; outlen -= len;\
2016 #define COPY_MULTIZ_STRING(fld) \
2017 { LPWSTR p = diW->fld; if (p){ \
2020 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2021 ptr += len; outlen -= len; p += len;\
2023 while(len > 1 && outlen > 0); \
2026 while (id
< numentries
)
2032 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
2033 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
2035 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2042 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
2043 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
2045 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2048 COPY_STRING(pEnvironment
);
2049 COPY_STRING(pDriverPath
);
2050 COPY_STRING(pDataFile
);
2051 COPY_STRING(pConfigFile
);
2056 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
2057 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
2059 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2062 COPY_STRING(pEnvironment
);
2063 COPY_STRING(pDriverPath
);
2064 COPY_STRING(pDataFile
);
2065 COPY_STRING(pConfigFile
);
2066 COPY_STRING(pHelpFile
);
2067 COPY_MULTIZ_STRING(pDependentFiles
);
2068 COPY_STRING(pMonitorName
);
2069 COPY_STRING(pDefaultDataType
);
2074 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
2075 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
2077 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2080 COPY_STRING(pEnvironment
);
2081 COPY_STRING(pDriverPath
);
2082 COPY_STRING(pDataFile
);
2083 COPY_STRING(pConfigFile
);
2084 COPY_STRING(pHelpFile
);
2085 COPY_MULTIZ_STRING(pDependentFiles
);
2086 COPY_STRING(pMonitorName
);
2087 COPY_STRING(pDefaultDataType
);
2088 COPY_MULTIZ_STRING(pszzPreviousNames
);
2093 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
2094 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
2096 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2099 COPY_STRING(pEnvironment
);
2100 COPY_STRING(pDriverPath
);
2101 COPY_STRING(pDataFile
);
2102 COPY_STRING(pConfigFile
);
2107 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
2108 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
2110 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2113 COPY_STRING(pEnvironment
);
2114 COPY_STRING(pDriverPath
);
2115 COPY_STRING(pDataFile
);
2116 COPY_STRING(pConfigFile
);
2117 COPY_STRING(pHelpFile
);
2118 COPY_MULTIZ_STRING(pDependentFiles
);
2119 COPY_STRING(pMonitorName
);
2120 COPY_STRING(pDefaultDataType
);
2121 COPY_MULTIZ_STRING(pszzPreviousNames
);
2122 COPY_STRING(pszMfgName
);
2123 COPY_STRING(pszOEMUrl
);
2124 COPY_STRING(pszHardwareID
);
2125 COPY_STRING(pszProvider
);
2130 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
2131 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
2133 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2136 COPY_STRING(pEnvironment
);
2137 COPY_STRING(pDriverPath
);
2138 COPY_STRING(pDataFile
);
2139 COPY_STRING(pConfigFile
);
2140 COPY_STRING(pHelpFile
);
2141 COPY_MULTIZ_STRING(pDependentFiles
);
2142 COPY_STRING(pMonitorName
);
2143 COPY_STRING(pDefaultDataType
);
2144 COPY_MULTIZ_STRING(pszzPreviousNames
);
2145 COPY_STRING(pszMfgName
);
2146 COPY_STRING(pszOEMUrl
);
2147 COPY_STRING(pszHardwareID
);
2148 COPY_STRING(pszProvider
);
2149 COPY_STRING(pszPrintProcessor
);
2150 COPY_STRING(pszVendorSetup
);
2151 COPY_MULTIZ_STRING(pszzColorProfiles
);
2152 COPY_STRING(pszInfPath
);
2153 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
2159 FIXME("for level %u\n", level
);
2162 pDriversW
+= di_sizeof
[level
];
2163 out
+= di_sizeof
[level
];
2168 #undef COPY_MULTIZ_STRING
2172 /***********************************************************
2175 static void *printer_info_AtoW( const void *data
, DWORD level
)
2178 UNICODE_STRING usBuffer
;
2180 if (!data
) return NULL
;
2182 if (level
< 1 || level
> 9) return NULL
;
2184 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
2185 if (!ret
) return NULL
;
2187 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
2193 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
2194 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
2196 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
2197 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
2198 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
2199 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
2200 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
2201 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
2202 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
2203 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2204 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
2205 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
2206 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
2207 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
2214 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
2215 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
2217 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2222 FIXME( "Unhandled level %d\n", level
);
2223 HeapFree( GetProcessHeap(), 0, ret
);
2230 /***********************************************************
2233 static void free_printer_info( void *data
, DWORD level
)
2241 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
2243 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
2244 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
2245 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
2246 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
2247 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
2248 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
2249 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
2250 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2251 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
2252 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
2253 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
2254 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
2261 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
2263 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2268 FIXME( "Unhandled level %d\n", level
);
2271 HeapFree( GetProcessHeap(), 0, data
);
2275 /******************************************************************
2276 * DeviceCapabilities [WINSPOOL.@]
2277 * DeviceCapabilitiesA [WINSPOOL.@]
2280 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
2281 LPSTR pOutput
, LPDEVMODEA lpdm
)
2285 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice
), debugstr_a(pPort
), cap
, pOutput
, lpdm
);
2287 if (!GDI_CallDeviceCapabilities16
)
2289 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2291 if (!GDI_CallDeviceCapabilities16
) return -1;
2293 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
2295 /* If DC_PAPERSIZE map POINT16s to POINTs */
2296 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
2297 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
2298 POINT
*pt
= (POINT
*)pOutput
;
2300 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
2301 for(i
= 0; i
< ret
; i
++, pt
++)
2306 HeapFree( GetProcessHeap(), 0, tmp
);
2312 /*****************************************************************************
2313 * DeviceCapabilitiesW [WINSPOOL.@]
2315 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2318 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2319 WORD fwCapability
, LPWSTR pOutput
,
2320 const DEVMODEW
*pDevMode
)
2322 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
2323 LPSTR pDeviceA
= strdupWtoA(pDevice
);
2324 LPSTR pPortA
= strdupWtoA(pPort
);
2327 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice
), debugstr_w(pPort
), fwCapability
, pOutput
, pDevMode
);
2329 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
2330 fwCapability
== DC_FILEDEPENDENCIES
||
2331 fwCapability
== DC_PAPERNAMES
)) {
2332 /* These need A -> W translation */
2335 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2339 switch(fwCapability
) {
2344 case DC_FILEDEPENDENCIES
:
2348 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2349 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2351 for(i
= 0; i
< ret
; i
++)
2352 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2353 pOutput
+ (i
* size
), size
);
2354 HeapFree(GetProcessHeap(), 0, pOutputA
);
2356 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2357 (LPSTR
)pOutput
, dmA
);
2359 HeapFree(GetProcessHeap(),0,pPortA
);
2360 HeapFree(GetProcessHeap(),0,pDeviceA
);
2361 HeapFree(GetProcessHeap(),0,dmA
);
2365 /******************************************************************
2366 * DocumentPropertiesA [WINSPOOL.@]
2368 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2370 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2371 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2372 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2374 LPSTR lpName
= pDeviceName
, dupname
= NULL
;
2375 static CHAR port
[] = "LPT1:";
2378 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2379 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2382 if(!pDeviceName
|| !*pDeviceName
) {
2383 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2385 ERR("no name from hPrinter?\n");
2386 SetLastError(ERROR_INVALID_HANDLE
);
2389 lpName
= dupname
= strdupWtoA(lpNameW
);
2392 if (!GDI_CallExtDeviceMode16
)
2394 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2396 if (!GDI_CallExtDeviceMode16
) {
2397 ERR("No CallExtDeviceMode16?\n");
2402 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2403 pDevModeInput
, NULL
, fMode
);
2406 HeapFree(GetProcessHeap(), 0, dupname
);
2411 /*****************************************************************************
2412 * DocumentPropertiesW (WINSPOOL.@)
2414 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2416 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2418 LPDEVMODEW pDevModeOutput
,
2419 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2422 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2423 LPDEVMODEA pDevModeInputA
;
2424 LPDEVMODEA pDevModeOutputA
= NULL
;
2427 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2428 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2430 if(pDevModeOutput
) {
2431 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2432 if(ret
< 0) return ret
;
2433 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2435 pDevModeInputA
= (fMode
& DM_IN_BUFFER
) ? DEVMODEdupWtoA(pDevModeInput
) : NULL
;
2436 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2437 pDevModeInputA
, fMode
);
2438 if(pDevModeOutput
) {
2439 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2440 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2442 if(fMode
== 0 && ret
> 0)
2443 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2444 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2445 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2449 /*****************************************************************************
2450 * IsValidDevmodeA [WINSPOOL.@]
2452 * Validate a DEVMODE structure and fix errors if possible.
2455 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA pDevMode
, SIZE_T size
)
2457 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2465 /*****************************************************************************
2466 * IsValidDevmodeW [WINSPOOL.@]
2468 * Validate a DEVMODE structure and fix errors if possible.
2471 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW dm
, SIZE_T size
)
2479 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
2480 { DM_ORIENTATION
, F_SIZE(u1
.s1
.dmOrientation
) },
2481 { DM_PAPERSIZE
, F_SIZE(u1
.s1
.dmPaperSize
) },
2482 { DM_PAPERLENGTH
, F_SIZE(u1
.s1
.dmPaperLength
) },
2483 { DM_PAPERWIDTH
, F_SIZE(u1
.s1
.dmPaperWidth
) },
2484 { DM_SCALE
, F_SIZE(u1
.s1
.dmScale
) },
2485 { DM_COPIES
, F_SIZE(u1
.s1
.dmCopies
) },
2486 { DM_DEFAULTSOURCE
, F_SIZE(u1
.s1
.dmDefaultSource
) },
2487 { DM_PRINTQUALITY
, F_SIZE(u1
.s1
.dmPrintQuality
) },
2488 { DM_POSITION
, F_SIZE(u1
.s2
.dmPosition
) },
2489 { DM_DISPLAYORIENTATION
, F_SIZE(u1
.s2
.dmDisplayOrientation
) },
2490 { DM_DISPLAYFIXEDOUTPUT
, F_SIZE(u1
.s2
.dmDisplayFixedOutput
) },
2491 { DM_COLOR
, F_SIZE(dmColor
) },
2492 { DM_DUPLEX
, F_SIZE(dmDuplex
) },
2493 { DM_YRESOLUTION
, F_SIZE(dmYResolution
) },
2494 { DM_TTOPTION
, F_SIZE(dmTTOption
) },
2495 { DM_COLLATE
, F_SIZE(dmCollate
) },
2496 { DM_FORMNAME
, F_SIZE(dmFormName
) },
2497 { DM_LOGPIXELS
, F_SIZE(dmLogPixels
) },
2498 { DM_BITSPERPEL
, F_SIZE(dmBitsPerPel
) },
2499 { DM_PELSWIDTH
, F_SIZE(dmPelsWidth
) },
2500 { DM_PELSHEIGHT
, F_SIZE(dmPelsHeight
) },
2501 { DM_DISPLAYFLAGS
, F_SIZE(u2
.dmDisplayFlags
) },
2502 { DM_NUP
, F_SIZE(u2
.dmNup
) },
2503 { DM_DISPLAYFREQUENCY
, F_SIZE(dmDisplayFrequency
) },
2504 { DM_ICMMETHOD
, F_SIZE(dmICMMethod
) },
2505 { DM_ICMINTENT
, F_SIZE(dmICMIntent
) },
2506 { DM_MEDIATYPE
, F_SIZE(dmMediaType
) },
2507 { DM_DITHERTYPE
, F_SIZE(dmDitherType
) },
2508 { DM_PANNINGWIDTH
, F_SIZE(dmPanningWidth
) },
2509 { DM_PANNINGHEIGHT
, F_SIZE(dmPanningHeight
) }
2514 if (!dm
) return FALSE
;
2515 if (size
< FIELD_OFFSET(DEVMODEW
, dmFields
) + sizeof(dm
->dmFields
)) return FALSE
;
2517 for (i
= 0; i
< ARRAY_SIZE(map
); i
++)
2518 if ((dm
->dmFields
& map
[i
].flag
) && size
< map
[i
].size
)
2524 /******************************************************************
2525 * OpenPrinterA [WINSPOOL.@]
2530 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2531 LPPRINTER_DEFAULTSA pDefault
)
2533 UNICODE_STRING lpPrinterNameW
;
2534 UNICODE_STRING usBuffer
;
2535 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2536 PWSTR pwstrPrinterNameW
;
2539 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName
), phPrinter
, pDefault
);
2541 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2544 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2545 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2546 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2547 pDefaultW
= &DefaultW
;
2549 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2551 RtlFreeUnicodeString(&usBuffer
);
2552 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2554 RtlFreeUnicodeString(&lpPrinterNameW
);
2558 /******************************************************************
2559 * OpenPrinterW [WINSPOOL.@]
2561 * Open a Printer / Printserver or a Printer-Object
2564 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2565 * phPrinter [O] The resulting Handle is stored here
2566 * pDefault [I] PTR to Default Printer Settings or NULL
2573 * lpPrinterName is one of:
2574 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2575 *| Printer: "PrinterName"
2576 *| Printer-Object: "PrinterName,Job xxx"
2577 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2578 *| XcvPort: "Servername,XcvPort PortName"
2581 *| Printer-Object not supported
2582 *| pDefaults is ignored
2585 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2589 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2592 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2593 SetLastError(ERROR_INVALID_PARAMETER
);
2597 /* Get the unique handle of the printer or Printserver */
2598 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2600 if (*phPrinter
&& WINSPOOL_GetOpenedPrinterRegKey( *phPrinter
, &key
) == ERROR_SUCCESS
)
2602 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2604 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2605 WaitForSingleObject( init_mutex
, INFINITE
);
2606 status
= get_dword_from_reg( key
, StatusW
);
2607 set_reg_DWORD( key
, StatusW
, status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2608 ReleaseMutex( init_mutex
);
2609 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2610 update_driver( *phPrinter
);
2614 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2615 return (*phPrinter
!= 0);
2618 /******************************************************************
2619 * AddMonitorA [WINSPOOL.@]
2624 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2626 LPWSTR nameW
= NULL
;
2629 LPMONITOR_INFO_2A mi2a
;
2630 MONITOR_INFO_2W mi2w
;
2632 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2633 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2634 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2635 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2636 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2639 SetLastError(ERROR_INVALID_LEVEL
);
2643 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2649 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2650 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2651 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2654 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2656 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2657 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2658 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2660 if (mi2a
->pEnvironment
) {
2661 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2662 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2663 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2665 if (mi2a
->pDLLName
) {
2666 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2667 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2668 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2671 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2673 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2674 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2675 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2677 HeapFree(GetProcessHeap(), 0, nameW
);
2681 /******************************************************************************
2682 * AddMonitorW [WINSPOOL.@]
2684 * Install a Printmonitor
2687 * pName [I] Servername or NULL (local Computer)
2688 * Level [I] Structure-Level (Must be 2)
2689 * pMonitors [I] PTR to MONITOR_INFO_2
2696 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2699 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2701 LPMONITOR_INFO_2W mi2w
;
2703 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2704 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2705 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2706 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2707 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2709 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2712 SetLastError(ERROR_INVALID_LEVEL
);
2716 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2721 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2724 /******************************************************************
2725 * DeletePrinterDriverA [WINSPOOL.@]
2728 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2730 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2733 /******************************************************************
2734 * DeletePrinterDriverW [WINSPOOL.@]
2737 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2739 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2742 /******************************************************************
2743 * DeleteMonitorA [WINSPOOL.@]
2745 * See DeleteMonitorW.
2748 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2750 LPWSTR nameW
= NULL
;
2751 LPWSTR EnvironmentW
= NULL
;
2752 LPWSTR MonitorNameW
= NULL
;
2757 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2758 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2759 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2763 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2764 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2765 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2768 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2769 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2770 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2773 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2775 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2776 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2777 HeapFree(GetProcessHeap(), 0, nameW
);
2781 /******************************************************************
2782 * DeleteMonitorW [WINSPOOL.@]
2784 * Delete a specific Printmonitor from a Printing-Environment
2787 * pName [I] Servername or NULL (local Computer)
2788 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2789 * pMonitorName [I] Name of the Monitor, that should be deleted
2796 * pEnvironment is ignored in Windows for the local Computer.
2799 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2802 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2803 debugstr_w(pMonitorName
));
2805 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2807 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2811 /******************************************************************
2812 * DeletePortA [WINSPOOL.@]
2817 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2819 LPWSTR nameW
= NULL
;
2820 LPWSTR portW
= NULL
;
2824 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2826 /* convert servername to unicode */
2828 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2829 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2830 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2833 /* convert portname to unicode */
2835 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2836 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2837 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2840 res
= DeletePortW(nameW
, hWnd
, portW
);
2841 HeapFree(GetProcessHeap(), 0, nameW
);
2842 HeapFree(GetProcessHeap(), 0, portW
);
2846 /******************************************************************
2847 * DeletePortW [WINSPOOL.@]
2849 * Delete a specific Port
2852 * pName [I] Servername or NULL (local Computer)
2853 * hWnd [I] Handle to parent Window for the Dialog-Box
2854 * pPortName [I] Name of the Port, that should be deleted
2861 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2863 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2865 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2868 SetLastError(RPC_X_NULL_REF_POINTER
);
2872 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2875 /******************************************************************************
2876 * WritePrinter [WINSPOOL.@]
2878 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2880 opened_printer_t
*printer
;
2883 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2885 EnterCriticalSection(&printer_handles_cs
);
2886 printer
= get_opened_printer(hPrinter
);
2889 SetLastError(ERROR_INVALID_HANDLE
);
2895 SetLastError(ERROR_SPL_NO_STARTDOC
);
2899 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2901 LeaveCriticalSection(&printer_handles_cs
);
2905 /*****************************************************************************
2906 * AddFormA [WINSPOOL.@]
2908 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2910 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2914 /*****************************************************************************
2915 * AddFormW [WINSPOOL.@]
2917 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2919 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2923 /*****************************************************************************
2924 * AddJobA [WINSPOOL.@]
2926 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2929 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2933 SetLastError(ERROR_INVALID_LEVEL
);
2937 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2940 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2941 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2942 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2943 if(*pcbNeeded
> cbBuf
) {
2944 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2947 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2948 addjobA
->JobId
= addjobW
->JobId
;
2949 addjobA
->Path
= (char *)(addjobA
+ 1);
2950 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2956 /*****************************************************************************
2957 * AddJobW [WINSPOOL.@]
2959 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2961 opened_printer_t
*printer
;
2964 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2965 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2966 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2968 ADDJOB_INFO_1W
*addjob
;
2970 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2972 EnterCriticalSection(&printer_handles_cs
);
2974 printer
= get_opened_printer(hPrinter
);
2977 SetLastError(ERROR_INVALID_HANDLE
);
2982 SetLastError(ERROR_INVALID_LEVEL
);
2986 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2990 job
->job_id
= InterlockedIncrement(&next_job_id
);
2992 len
= GetSystemDirectoryW(path
, ARRAY_SIZE(path
));
2993 if(path
[len
- 1] != '\\')
2995 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2996 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2998 len
= strlenW(filename
);
2999 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
3000 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
3001 job
->portname
= NULL
;
3002 job
->document_title
= strdupW(default_doc_title
);
3003 job
->printer_name
= strdupW(printer
->name
);
3004 job
->devmode
= dup_devmode( printer
->devmode
);
3005 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
3007 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
3008 if(*pcbNeeded
<= cbBuf
) {
3009 addjob
= (ADDJOB_INFO_1W
*)pData
;
3010 addjob
->JobId
= job
->job_id
;
3011 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
3012 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
3015 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3018 LeaveCriticalSection(&printer_handles_cs
);
3022 /*****************************************************************************
3023 * GetPrintProcessorDirectoryA [WINSPOOL.@]
3025 * Return the PATH for the Print-Processors
3027 * See GetPrintProcessorDirectoryW.
3031 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
3032 DWORD level
, LPBYTE Info
,
3033 DWORD cbBuf
, LPDWORD pcbNeeded
)
3035 LPWSTR serverW
= NULL
;
3040 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
3041 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
3045 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
3046 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3047 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
3051 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
3052 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3053 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
3056 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3057 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3059 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
3062 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
3063 cbBuf
, NULL
, NULL
) > 0;
3066 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
3067 HeapFree(GetProcessHeap(), 0, envW
);
3068 HeapFree(GetProcessHeap(), 0, serverW
);
3072 /*****************************************************************************
3073 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3075 * Return the PATH for the Print-Processors
3078 * server [I] Servername (NT only) or NULL (local Computer)
3079 * env [I] Printing-Environment (see below) or NULL (Default)
3080 * level [I] Structure-Level (must be 1)
3081 * Info [O] PTR to Buffer that receives the Result
3082 * cbBuf [I] Size of Buffer at "Info"
3083 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3084 * required for the Buffer at "Info"
3087 * Success: TRUE and in pcbNeeded the Bytes used in Info
3088 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3089 * if cbBuf is too small
3091 * Native Values returned in Info on Success:
3092 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3093 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3094 *| win9x(Windows 4.0): "%winsysdir%"
3096 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3099 * Only NULL or "" is supported for server
3102 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
3103 DWORD level
, LPBYTE Info
,
3104 DWORD cbBuf
, LPDWORD pcbNeeded
)
3107 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
3108 Info
, cbBuf
, pcbNeeded
);
3110 if ((backend
== NULL
) && !load_backend()) return FALSE
;
3113 /* (Level != 1) is ignored in win9x */
3114 SetLastError(ERROR_INVALID_LEVEL
);
3118 if (pcbNeeded
== NULL
) {
3119 /* (pcbNeeded == NULL) is ignored in win9x */
3120 SetLastError(RPC_X_NULL_REF_POINTER
);
3124 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
3127 /*****************************************************************************
3128 * WINSPOOL_OpenDriverReg [internal]
3130 * opens the registry for the printer drivers depending on the given input
3131 * variable pEnvironment
3134 * the opened hkey on success
3137 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
3141 const printenv_t
* env
;
3143 TRACE("(%s)\n", debugstr_w(pEnvironment
));
3145 env
= validate_envW(pEnvironment
);
3146 if (!env
) return NULL
;
3148 buffer
= HeapAlloc( GetProcessHeap(), 0,
3149 (strlenW(DriversW
) + strlenW(env
->envname
) +
3150 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
3152 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
3153 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
3154 HeapFree(GetProcessHeap(), 0, buffer
);
3159 /*****************************************************************************
3160 * set_devices_and_printerports [internal]
3162 * set the [Devices] and [PrinterPorts] entries for a printer.
3165 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
3167 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
3171 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
3173 /* FIXME: the driver must change to "winspool" */
3174 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
3176 lstrcpyW(devline
, driver_nt
);
3177 lstrcatW(devline
, commaW
);
3178 lstrcatW(devline
, pi
->pPortName
);
3180 TRACE("using %s\n", debugstr_w(devline
));
3181 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
3182 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
3183 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3184 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3188 lstrcatW(devline
, timeout_15_45
);
3189 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
3190 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
3191 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3192 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3195 HeapFree(GetProcessHeap(), 0, devline
);
3199 /*****************************************************************************
3200 * AddPrinterW [WINSPOOL.@]
3202 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3204 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
3207 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
3210 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
3212 if(pName
&& *pName
) {
3213 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
3214 SetLastError(ERROR_INVALID_PARAMETER
);
3218 ERR("Level = %d, unsupported!\n", Level
);
3219 SetLastError(ERROR_INVALID_LEVEL
);
3223 SetLastError(ERROR_INVALID_PARAMETER
);
3226 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3228 ERR("Can't create Printers key\n");
3231 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3232 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
3233 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3234 RegCloseKey(hkeyPrinter
);
3235 RegCloseKey(hkeyPrinters
);
3238 RegCloseKey(hkeyPrinter
);
3240 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
3242 ERR("Can't create Drivers key\n");
3243 RegCloseKey(hkeyPrinters
);
3246 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3248 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3249 RegCloseKey(hkeyPrinters
);
3250 RegCloseKey(hkeyDrivers
);
3251 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3254 RegCloseKey(hkeyDriver
);
3255 RegCloseKey(hkeyDrivers
);
3257 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3258 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3259 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3260 RegCloseKey(hkeyPrinters
);
3264 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3266 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3267 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3268 RegCloseKey(hkeyPrinters
);
3272 set_devices_and_printerports(pi
);
3274 set_reg_DWORD(hkeyPrinter
, AttributesW
, pi
->Attributes
);
3275 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3276 set_reg_DWORD(hkeyPrinter
, Default_PriorityW
, pi
->DefaultPriority
);
3277 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3278 set_reg_DWORD(hkeyPrinter
, dnsTimeoutW
, 0);
3279 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3280 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3281 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3282 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3283 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3284 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3285 set_reg_DWORD(hkeyPrinter
, PriorityW
, pi
->Priority
);
3286 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3287 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3288 set_reg_DWORD(hkeyPrinter
, StartTimeW
, pi
->StartTime
);
3289 set_reg_DWORD(hkeyPrinter
, StatusW
, pi
->Status
);
3290 set_reg_DWORD(hkeyPrinter
, txTimeoutW
, 0);
3291 set_reg_DWORD(hkeyPrinter
, UntilTimeW
, pi
->UntilTime
);
3293 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3297 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3298 size
= sizeof(DEVMODEW
);
3304 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3306 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
3308 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3309 HeapFree( GetProcessHeap(), 0, dm
);
3314 /* set devmode to printer name */
3315 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3319 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
3320 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
3322 RegCloseKey(hkeyPrinter
);
3323 RegCloseKey(hkeyPrinters
);
3324 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3325 ERR("OpenPrinter failing\n");
3331 /*****************************************************************************
3332 * AddPrinterA [WINSPOOL.@]
3334 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3336 UNICODE_STRING pNameW
;
3338 PRINTER_INFO_2W
*piW
;
3339 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3342 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
3344 ERR("Level = %d, unsupported!\n", Level
);
3345 SetLastError(ERROR_INVALID_LEVEL
);
3348 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3349 piW
= printer_info_AtoW( piA
, Level
);
3351 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3353 free_printer_info( piW
, Level
);
3354 RtlFreeUnicodeString(&pNameW
);
3359 /*****************************************************************************
3360 * ClosePrinter [WINSPOOL.@]
3362 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3364 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3365 opened_printer_t
*printer
= NULL
;
3367 TRACE("(%p)\n", hPrinter
);
3369 EnterCriticalSection(&printer_handles_cs
);
3371 if ((i
> 0) && (i
<= nb_printer_handles
))
3372 printer
= printer_handles
[i
- 1];
3377 struct list
*cursor
, *cursor2
;
3379 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
3382 EndDocPrinter(hPrinter
);
3384 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3386 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3388 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3389 ScheduleJob(hPrinter
, job
->job_id
);
3391 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3394 if (printer
->backend_printer
) {
3395 backend
->fpClosePrinter(printer
->backend_printer
);
3398 free_printer_entry( printer
);
3399 printer_handles
[i
- 1] = NULL
;
3400 LeaveCriticalSection(&printer_handles_cs
);
3404 LeaveCriticalSection(&printer_handles_cs
);
3405 SetLastError(ERROR_INVALID_HANDLE
);
3409 /*****************************************************************************
3410 * DeleteFormA [WINSPOOL.@]
3412 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3414 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3418 /*****************************************************************************
3419 * DeleteFormW [WINSPOOL.@]
3421 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3423 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3427 /*****************************************************************************
3428 * DeletePrinter [WINSPOOL.@]
3430 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3432 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3433 HKEY hkeyPrinters
, hkey
;
3434 WCHAR def
[MAX_PATH
];
3435 DWORD size
= ARRAY_SIZE(def
);
3438 SetLastError(ERROR_INVALID_HANDLE
);
3441 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3442 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3443 RegCloseKey(hkeyPrinters
);
3445 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3446 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
3448 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3449 RegDeleteValueW(hkey
, lpNameW
);
3453 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3454 RegDeleteValueW(hkey
, lpNameW
);
3458 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
3460 WriteProfileStringW( windowsW
, deviceW
, NULL
);
3461 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
3463 RegDeleteValueW( hkey
, deviceW
);
3464 RegCloseKey( hkey
);
3466 SetDefaultPrinterW( NULL
);
3472 /*****************************************************************************
3473 * SetPrinterA [WINSPOOL.@]
3475 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3482 dataW
= printer_info_AtoW( data
, level
);
3483 if (!dataW
) return FALSE
;
3486 ret
= SetPrinterW( printer
, level
, dataW
, command
);
3488 if (dataW
!= data
) free_printer_info( dataW
, level
);
3493 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
3495 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
3496 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
3497 set_reg_szW( key
, PortW
, pi
->pPortName
);
3498 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
3499 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
3500 set_reg_szW( key
, LocationW
, pi
->pLocation
);
3503 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3505 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
3506 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
3507 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
3508 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
3510 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
3511 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
3512 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
3513 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
3514 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
3517 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
3519 if (!pi
->pDevMode
) return FALSE
;
3521 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3525 /******************************************************************************
3526 * SetPrinterW [WINSPOOL.@]
3528 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3533 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
3535 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
3537 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
3544 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
3545 set_printer_2( key
, pi2
);
3551 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3552 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3556 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
3557 ret
= set_printer_9( key
, pi
);
3562 FIXME( "Unimplemented level %d\n", level
);
3563 SetLastError( ERROR_INVALID_LEVEL
);
3570 /*****************************************************************************
3571 * SetJobA [WINSPOOL.@]
3573 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3574 LPBYTE pJob
, DWORD Command
)
3578 UNICODE_STRING usBuffer
;
3580 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3582 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3583 are all ignored by SetJob, so we don't bother copying them */
3591 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3592 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3594 JobW
= (LPBYTE
)info1W
;
3595 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3596 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3597 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3598 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3599 info1W
->Status
= info1A
->Status
;
3600 info1W
->Priority
= info1A
->Priority
;
3601 info1W
->Position
= info1A
->Position
;
3602 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3607 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3608 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3610 JobW
= (LPBYTE
)info2W
;
3611 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3612 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3613 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3614 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3615 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3616 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3617 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3618 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3619 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3620 info2W
->Status
= info2A
->Status
;
3621 info2W
->Priority
= info2A
->Priority
;
3622 info2W
->Position
= info2A
->Position
;
3623 info2W
->StartTime
= info2A
->StartTime
;
3624 info2W
->UntilTime
= info2A
->UntilTime
;
3625 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3629 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3630 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3633 SetLastError(ERROR_INVALID_LEVEL
);
3637 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3643 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3644 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3645 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3646 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3647 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3652 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3653 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3654 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3655 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3656 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3657 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3658 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3659 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3660 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3664 HeapFree(GetProcessHeap(), 0, JobW
);
3669 /*****************************************************************************
3670 * SetJobW [WINSPOOL.@]
3672 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3673 LPBYTE pJob
, DWORD Command
)
3678 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3679 FIXME("Ignoring everything other than document title\n");
3681 EnterCriticalSection(&printer_handles_cs
);
3682 job
= get_job(hPrinter
, JobId
);
3692 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3693 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3694 job
->document_title
= strdupW(info1
->pDocument
);
3699 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3700 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3701 job
->document_title
= strdupW(info2
->pDocument
);
3702 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3703 job
->devmode
= dup_devmode( info2
->pDevMode
);
3709 SetLastError(ERROR_INVALID_LEVEL
);
3714 LeaveCriticalSection(&printer_handles_cs
);
3718 /*****************************************************************************
3719 * EndDocPrinter [WINSPOOL.@]
3721 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3723 opened_printer_t
*printer
;
3725 TRACE("(%p)\n", hPrinter
);
3727 EnterCriticalSection(&printer_handles_cs
);
3729 printer
= get_opened_printer(hPrinter
);
3732 SetLastError(ERROR_INVALID_HANDLE
);
3738 SetLastError(ERROR_SPL_NO_STARTDOC
);
3742 CloseHandle(printer
->doc
->hf
);
3743 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3744 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3745 printer
->doc
= NULL
;
3748 LeaveCriticalSection(&printer_handles_cs
);
3752 /*****************************************************************************
3753 * EndPagePrinter [WINSPOOL.@]
3755 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3757 FIXME("(%p): stub\n", hPrinter
);
3761 /*****************************************************************************
3762 * StartDocPrinterA [WINSPOOL.@]
3764 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3766 UNICODE_STRING usBuffer
;
3768 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3771 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3772 or one (DOC_INFO_3) extra DWORDs */
3776 doc2W
.JobId
= doc2
->JobId
;
3779 doc2W
.dwMode
= doc2
->dwMode
;
3782 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3783 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3784 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3788 SetLastError(ERROR_INVALID_LEVEL
);
3792 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3794 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3795 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3796 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3801 /*****************************************************************************
3802 * StartDocPrinterW [WINSPOOL.@]
3804 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3806 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3807 opened_printer_t
*printer
;
3808 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3809 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3810 JOB_INFO_1W job_info
;
3811 DWORD needed
, ret
= 0;
3816 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3817 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3818 debugstr_w(doc
->pDatatype
));
3820 if(Level
< 1 || Level
> 3)
3822 SetLastError(ERROR_INVALID_LEVEL
);
3826 EnterCriticalSection(&printer_handles_cs
);
3827 printer
= get_opened_printer(hPrinter
);
3830 SetLastError(ERROR_INVALID_HANDLE
);
3836 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3840 /* Even if we're printing to a file we still add a print job, we'll
3841 just ignore the spool file name */
3843 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3845 ERR("AddJob failed gle %u\n", GetLastError());
3849 /* use pOutputFile only, when it is a real filename */
3850 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3851 filename
= doc
->pOutputFile
;
3853 filename
= addjob
->Path
;
3855 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3856 if(hf
== INVALID_HANDLE_VALUE
)
3859 memset(&job_info
, 0, sizeof(job_info
));
3860 job_info
.pDocument
= doc
->pDocName
;
3861 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3863 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3864 printer
->doc
->hf
= hf
;
3865 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3866 job
= get_job(hPrinter
, ret
);
3867 job
->portname
= strdupW(doc
->pOutputFile
);
3870 LeaveCriticalSection(&printer_handles_cs
);
3875 /*****************************************************************************
3876 * StartPagePrinter [WINSPOOL.@]
3878 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3880 FIXME("(%p): stub\n", hPrinter
);
3884 /*****************************************************************************
3885 * GetFormA [WINSPOOL.@]
3887 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3888 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3890 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3891 Level
,pForm
,cbBuf
,pcbNeeded
);
3895 /*****************************************************************************
3896 * GetFormW [WINSPOOL.@]
3898 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3899 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3901 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3902 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3906 /*****************************************************************************
3907 * SetFormA [WINSPOOL.@]
3909 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3912 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3916 /*****************************************************************************
3917 * SetFormW [WINSPOOL.@]
3919 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3922 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3926 /*****************************************************************************
3927 * ReadPrinter [WINSPOOL.@]
3929 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3930 LPDWORD pNoBytesRead
)
3932 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3936 /*****************************************************************************
3937 * ResetPrinterA [WINSPOOL.@]
3939 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3941 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3945 /*****************************************************************************
3946 * ResetPrinterW [WINSPOOL.@]
3948 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3950 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3954 /*****************************************************************************
3955 * get_filename_from_reg [internal]
3957 * Get ValueName from hkey storing result in out
3958 * when the Value in the registry has only a filename, use driverdir as prefix
3959 * outlen is space left in out
3960 * String is stored either as unicode or ascii
3964 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3965 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3967 WCHAR filename
[MAX_PATH
];
3971 LPWSTR buffer
= filename
;
3975 size
= sizeof(filename
);
3977 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3978 if (ret
== ERROR_MORE_DATA
) {
3979 TRACE("need dynamic buffer: %u\n", size
);
3980 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3982 /* No Memory is bad */
3986 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3989 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3990 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3996 /* do we have a full path ? */
3997 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3998 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
4001 /* we must build the full Path */
4003 if ((out
) && (outlen
> dirlen
)) {
4004 lstrcpyW((LPWSTR
)out
, driverdir
);
4012 /* write the filename */
4013 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
4014 if ((out
) && (outlen
>= size
)) {
4015 lstrcpyW((LPWSTR
)out
, ptr
);
4022 ptr
+= lstrlenW(ptr
)+1;
4023 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
4026 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
4028 /* write the multisz-termination */
4029 if (type
== REG_MULTI_SZ
) {
4030 size
= sizeof(WCHAR
);
4033 if (out
&& (outlen
>= size
)) {
4034 memset (out
, 0, size
);
4040 /*****************************************************************************
4041 * WINSPOOL_GetStringFromReg
4043 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4044 * String is stored as unicode.
4046 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
4047 DWORD buflen
, DWORD
*needed
)
4049 DWORD sz
= buflen
, type
;
4052 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4053 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
4054 WARN("Got ret = %d\n", ret
);
4058 /* add space for terminating '\0' */
4059 sz
+= sizeof(WCHAR
);
4063 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
4068 /*****************************************************************************
4069 * WINSPOOL_GetDefaultDevMode
4071 * Get a default DevMode values for wineps.
4073 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr
, DWORD buflen
, DWORD
*needed
)
4075 static const WCHAR winepsW
[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4077 if (buflen
>= sizeof(DEVMODEW
))
4079 DEVMODEW
*dm
= (DEVMODEW
*)ptr
;
4081 /* the driver will update registry with real values */
4082 memset(dm
, 0, sizeof(*dm
));
4083 dm
->dmSize
= sizeof(*dm
);
4084 lstrcpyW(dm
->dmDeviceName
, winepsW
);
4086 *needed
= sizeof(DEVMODEW
);
4089 /*****************************************************************************
4090 * WINSPOOL_GetDevModeFromReg
4092 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4093 * DevMode is stored either as unicode or ascii.
4095 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
4097 DWORD buflen
, DWORD
*needed
)
4099 DWORD sz
= buflen
, type
;
4102 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
4103 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4104 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
4105 if (sz
< sizeof(DEVMODEA
))
4107 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
4110 /* ensures that dmSize is not erratically bogus if registry is invalid */
4111 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
4112 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
4113 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
4114 if (ptr
&& (buflen
>= sz
)) {
4115 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
4116 memcpy(ptr
, dmW
, sz
);
4117 HeapFree(GetProcessHeap(),0,dmW
);
4123 /*********************************************************************
4124 * WINSPOOL_GetPrinter_1
4126 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4128 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
4129 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4131 DWORD size
, left
= cbBuf
;
4132 BOOL space
= (cbBuf
> 0);
4137 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4138 if(space
&& size
<= left
) {
4139 pi1
->pName
= (LPWSTR
)ptr
;
4147 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4148 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4149 if(space
&& size
<= left
) {
4150 pi1
->pDescription
= (LPWSTR
)ptr
;
4158 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4159 if(space
&& size
<= left
) {
4160 pi1
->pComment
= (LPWSTR
)ptr
;
4168 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
4170 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
4171 memset(pi1
, 0, sizeof(*pi1
));
4175 /*********************************************************************
4176 * WINSPOOL_GetPrinter_2
4178 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4180 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
4181 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4183 DWORD size
, left
= cbBuf
;
4184 BOOL space
= (cbBuf
> 0);
4189 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4190 if(space
&& size
<= left
) {
4191 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4198 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
4199 if(space
&& size
<= left
) {
4200 pi2
->pShareName
= (LPWSTR
)ptr
;
4207 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4208 if(space
&& size
<= left
) {
4209 pi2
->pPortName
= (LPWSTR
)ptr
;
4216 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
4217 if(space
&& size
<= left
) {
4218 pi2
->pDriverName
= (LPWSTR
)ptr
;
4225 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4226 if(space
&& size
<= left
) {
4227 pi2
->pComment
= (LPWSTR
)ptr
;
4234 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
4235 if(space
&& size
<= left
) {
4236 pi2
->pLocation
= (LPWSTR
)ptr
;
4243 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
4244 if(space
&& size
<= left
) {
4245 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4254 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
4255 if(space
&& size
<= left
) {
4256 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4263 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
4264 if(space
&& size
<= left
) {
4265 pi2
->pSepFile
= (LPWSTR
)ptr
;
4272 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
4273 if(space
&& size
<= left
) {
4274 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4281 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
4282 if(space
&& size
<= left
) {
4283 pi2
->pDatatype
= (LPWSTR
)ptr
;
4290 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
4291 if(space
&& size
<= left
) {
4292 pi2
->pParameters
= (LPWSTR
)ptr
;
4300 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4301 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
4302 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
4303 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
4304 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
4307 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4308 memset(pi2
, 0, sizeof(*pi2
));
4313 /*********************************************************************
4314 * WINSPOOL_GetPrinter_4
4316 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4318 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4319 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4321 DWORD size
, left
= cbBuf
;
4322 BOOL space
= (cbBuf
> 0);
4327 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4328 if(space
&& size
<= left
) {
4329 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4337 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4340 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4341 memset(pi4
, 0, sizeof(*pi4
));
4346 /*********************************************************************
4347 * WINSPOOL_GetPrinter_5
4349 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4351 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4352 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4354 DWORD size
, left
= cbBuf
;
4355 BOOL space
= (cbBuf
> 0);
4360 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4361 if(space
&& size
<= left
) {
4362 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4369 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4370 if(space
&& size
<= left
) {
4371 pi5
->pPortName
= (LPWSTR
)ptr
;
4379 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4380 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
4381 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
4384 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4385 memset(pi5
, 0, sizeof(*pi5
));
4390 /*********************************************************************
4391 * WINSPOOL_GetPrinter_7
4393 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4395 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4396 DWORD cbBuf
, LPDWORD pcbNeeded
)
4398 DWORD size
, left
= cbBuf
;
4399 BOOL space
= (cbBuf
> 0);
4404 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
4407 size
= sizeof(pi7
->pszObjectGUID
);
4409 if (space
&& size
<= left
) {
4410 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4417 /* We do not have a Directory Service */
4418 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4421 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4422 memset(pi7
, 0, sizeof(*pi7
));
4427 /*********************************************************************
4428 * WINSPOOL_GetPrinter_9
4430 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4432 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4433 DWORD cbBuf
, LPDWORD pcbNeeded
)
4436 BOOL space
= (cbBuf
> 0);
4440 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
4441 if(space
&& size
<= cbBuf
) {
4442 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4449 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
4450 if(space
&& size
<= cbBuf
) {
4451 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4457 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4458 memset(pi9
, 0, sizeof(*pi9
));
4463 /*****************************************************************************
4464 * GetPrinterW [WINSPOOL.@]
4466 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4467 DWORD cbBuf
, LPDWORD pcbNeeded
)
4469 DWORD size
, needed
= 0, err
;
4474 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4476 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
4479 SetLastError( err
);
4486 PRINTER_INFO_1W
*pi1
= (PRINTER_INFO_1W
*)pPrinter
;
4488 size
= sizeof(PRINTER_INFO_1W
);
4489 if (size
<= cbBuf
) {
4490 ptr
= pPrinter
+ size
;
4492 memset(pPrinter
, 0, size
);
4497 ret
= WINSPOOL_GetPrinter_1(hkeyPrinter
, pi1
, ptr
, cbBuf
, &needed
);
4504 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4506 size
= sizeof(PRINTER_INFO_2W
);
4508 ptr
= pPrinter
+ size
;
4510 memset(pPrinter
, 0, size
);
4515 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
4522 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4524 size
= sizeof(PRINTER_INFO_4W
);
4526 ptr
= pPrinter
+ size
;
4528 memset(pPrinter
, 0, size
);
4533 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
4541 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4543 size
= sizeof(PRINTER_INFO_5W
);
4545 ptr
= pPrinter
+ size
;
4547 memset(pPrinter
, 0, size
);
4553 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4561 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4563 size
= sizeof(PRINTER_INFO_6
);
4564 if (size
<= cbBuf
) {
4565 /* FIXME: We do not update the status yet */
4566 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4578 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4580 size
= sizeof(PRINTER_INFO_7W
);
4581 if (size
<= cbBuf
) {
4582 ptr
= pPrinter
+ size
;
4584 memset(pPrinter
, 0, size
);
4590 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4597 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4598 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4602 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4604 size
= sizeof(PRINTER_INFO_9W
);
4606 ptr
= pPrinter
+ size
;
4608 memset(pPrinter
, 0, size
);
4614 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4621 FIXME("Unimplemented level %d\n", Level
);
4622 SetLastError(ERROR_INVALID_LEVEL
);
4623 RegCloseKey(hkeyPrinter
);
4627 RegCloseKey(hkeyPrinter
);
4629 TRACE("returning %d needed = %d\n", ret
, needed
);
4630 if(pcbNeeded
) *pcbNeeded
= needed
;
4632 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4636 /*****************************************************************************
4637 * GetPrinterA [WINSPOOL.@]
4639 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4640 DWORD cbBuf
, LPDWORD pcbNeeded
)
4646 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4648 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4650 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4651 HeapFree(GetProcessHeap(), 0, buf
);
4656 /*****************************************************************************
4657 * WINSPOOL_EnumPrintersW
4659 * Implementation of EnumPrintersW
4661 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4662 DWORD dwLevel
, LPBYTE lpbPrinters
,
4663 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4664 LPDWORD lpdwReturned
)
4667 HKEY hkeyPrinters
, hkeyPrinter
;
4668 WCHAR PrinterName
[255];
4669 DWORD needed
= 0, number
= 0;
4670 DWORD used
, i
, left
;
4674 memset(lpbPrinters
, 0, cbBuf
);
4680 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4681 if(dwType
== PRINTER_ENUM_DEFAULT
)
4684 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4685 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4686 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4688 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4694 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4695 FIXME("dwType = %08x\n", dwType
);
4696 SetLastError(ERROR_INVALID_FLAGS
);
4700 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4702 ERR("Can't create Printers key\n");
4706 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4707 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4708 RegCloseKey(hkeyPrinters
);
4709 ERR("Can't query Printers key\n");
4712 TRACE("Found %d printers\n", number
);
4716 used
= number
* sizeof(PRINTER_INFO_1W
);
4719 used
= number
* sizeof(PRINTER_INFO_2W
);
4722 used
= number
* sizeof(PRINTER_INFO_4W
);
4725 used
= number
* sizeof(PRINTER_INFO_5W
);
4729 SetLastError(ERROR_INVALID_LEVEL
);
4730 RegCloseKey(hkeyPrinters
);
4733 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4735 for(i
= 0; i
< number
; i
++) {
4736 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, ARRAY_SIZE(PrinterName
)) != ERROR_SUCCESS
) {
4737 ERR("Can't enum key number %d\n", i
);
4738 RegCloseKey(hkeyPrinters
);
4741 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4742 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4744 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4745 RegCloseKey(hkeyPrinters
);
4750 buf
= lpbPrinters
+ used
;
4751 left
= cbBuf
- used
;
4759 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4762 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4765 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4768 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4771 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4774 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4777 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4780 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4783 ERR("Shouldn't be here!\n");
4784 RegCloseKey(hkeyPrinter
);
4785 RegCloseKey(hkeyPrinters
);
4788 RegCloseKey(hkeyPrinter
);
4790 RegCloseKey(hkeyPrinters
);
4797 memset(lpbPrinters
, 0, cbBuf
);
4798 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4802 *lpdwReturned
= number
;
4803 SetLastError(ERROR_SUCCESS
);
4808 /******************************************************************
4809 * EnumPrintersW [WINSPOOL.@]
4811 * Enumerates the available printers, print servers and print
4812 * providers, depending on the specified flags, name and level.
4816 * If level is set to 1:
4817 * Returns an array of PRINTER_INFO_1 data structures in the
4818 * lpbPrinters buffer.
4820 * If level is set to 2:
4821 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4822 * Returns an array of PRINTER_INFO_2 data structures in the
4823 * lpbPrinters buffer. Note that according to MSDN also an
4824 * OpenPrinter should be performed on every remote printer.
4826 * If level is set to 4 (officially WinNT only):
4827 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4828 * Fast: Only the registry is queried to retrieve printer names,
4829 * no connection to the driver is made.
4830 * Returns an array of PRINTER_INFO_4 data structures in the
4831 * lpbPrinters buffer.
4833 * If level is set to 5 (officially WinNT4/Win9x only):
4834 * Fast: Only the registry is queried to retrieve printer names,
4835 * no connection to the driver is made.
4836 * Returns an array of PRINTER_INFO_5 data structures in the
4837 * lpbPrinters buffer.
4839 * If level set to 3 or 6+:
4840 * returns zero (failure!)
4842 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4846 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4847 * - Only levels 2, 4 and 5 are implemented at the moment.
4848 * - 16-bit printer drivers are not enumerated.
4849 * - Returned amount of bytes used/needed does not match the real Windoze
4850 * implementation (as in this implementation, all strings are part
4851 * of the buffer, whereas Win32 keeps them somewhere else)
4852 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4855 * - In a regular Wine installation, no registry settings for printers
4856 * exist, which makes this function return an empty list.
4858 BOOL WINAPI
EnumPrintersW(
4859 DWORD dwType
, /* [in] Types of print objects to enumerate */
4860 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4861 DWORD dwLevel
, /* [in] type of printer info structure */
4862 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4863 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4864 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4865 LPDWORD lpdwReturned
/* [out] number of entries returned */
4868 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4869 lpdwNeeded
, lpdwReturned
);
4872 /******************************************************************
4873 * EnumPrintersA [WINSPOOL.@]
4878 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4879 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4882 UNICODE_STRING pNameU
;
4886 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4887 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4889 pNameW
= asciitounicode(&pNameU
, pName
);
4891 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4892 MS Office need this */
4893 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4895 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4897 RtlFreeUnicodeString(&pNameU
);
4899 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4901 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4905 /*****************************************************************************
4906 * WINSPOOL_GetDriverInfoFromReg [internal]
4908 * Enters the information from the registry into the DRIVER_INFO struct
4911 * zero if the printer driver does not exist in the registry
4912 * (only if Level > 1) otherwise nonzero
4914 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4917 const printenv_t
* env
,
4919 LPBYTE ptr
, /* DRIVER_INFO */
4920 LPBYTE pDriverStrings
, /* strings buffer */
4921 DWORD cbBuf
, /* size of string buffer */
4922 LPDWORD pcbNeeded
) /* space needed for str. */
4926 WCHAR driverdir
[MAX_PATH
];
4928 LPBYTE strPtr
= pDriverStrings
;
4929 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4931 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4932 debugstr_w(DriverName
), env
,
4933 Level
, di
, pDriverStrings
, cbBuf
);
4935 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4937 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4938 if (*pcbNeeded
<= cbBuf
)
4939 strcpyW((LPWSTR
)strPtr
, DriverName
);
4941 /* pName for level 1 has a different offset! */
4943 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4947 /* .cVersion and .pName for level > 1 */
4949 di
->cVersion
= env
->driverversion
;
4950 di
->pName
= (LPWSTR
) strPtr
;
4951 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4954 /* Reserve Space for the largest subdir and a Backslash*/
4955 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4956 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4957 /* Should never Fail */
4960 lstrcatW(driverdir
, env
->versionsubdir
);
4961 lstrcatW(driverdir
, backslashW
);
4963 /* dirlen must not include the terminating zero */
4964 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4966 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4967 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4968 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4973 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4976 if (*pcbNeeded
<= cbBuf
) {
4977 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4978 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4979 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4982 /* .pDriverPath is the Graphics rendering engine.
4983 The full Path is required to avoid a crash in some apps */
4984 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4986 if (*pcbNeeded
<= cbBuf
)
4987 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4989 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4990 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4993 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4994 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4996 if (*pcbNeeded
<= cbBuf
)
4997 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4999 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
5000 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5003 /* .pConfigFile is the Driver user Interface */
5004 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
5006 if (*pcbNeeded
<= cbBuf
)
5007 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
5009 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
5010 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5014 RegCloseKey(hkeyDriver
);
5015 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5020 RegCloseKey(hkeyDriver
);
5021 FIXME("level 5: incomplete\n");
5026 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
5028 if (*pcbNeeded
<= cbBuf
)
5029 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
5031 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
5032 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5035 /* .pDependentFiles */
5036 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
5038 if (*pcbNeeded
<= cbBuf
)
5039 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
5041 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
5042 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5044 else if (GetVersion() & 0x80000000) {
5045 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
5046 size
= 2 * sizeof(WCHAR
);
5048 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
5050 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
5051 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5054 /* .pMonitorName is the optional Language Monitor */
5055 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
5057 if (*pcbNeeded
<= cbBuf
)
5058 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
5060 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
5061 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5064 /* .pDefaultDataType */
5065 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
5067 if(*pcbNeeded
<= cbBuf
)
5068 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
5070 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
5071 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5075 RegCloseKey(hkeyDriver
);
5076 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5080 /* .pszzPreviousNames */
5081 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
5083 if(*pcbNeeded
<= cbBuf
)
5084 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
5086 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
5087 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5091 RegCloseKey(hkeyDriver
);
5092 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5096 /* support is missing, but not important enough for a FIXME */
5097 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
5100 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
5102 if(*pcbNeeded
<= cbBuf
)
5103 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
5105 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
5106 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5110 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
5112 if(*pcbNeeded
<= cbBuf
)
5113 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
5115 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
5116 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5119 /* .pszHardwareID */
5120 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
5122 if(*pcbNeeded
<= cbBuf
)
5123 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
5125 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
5126 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5130 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
5132 if(*pcbNeeded
<= cbBuf
)
5133 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
5135 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
5136 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5140 RegCloseKey(hkeyDriver
);
5144 /* support is missing, but not important enough for a FIXME */
5145 TRACE("level 8: incomplete\n");
5147 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5148 RegCloseKey(hkeyDriver
);
5152 /*****************************************************************************
5153 * GetPrinterDriverW [WINSPOOL.@]
5155 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5156 DWORD Level
, LPBYTE pDriverInfo
,
5157 DWORD cbBuf
, LPDWORD pcbNeeded
)
5160 WCHAR DriverName
[100];
5161 DWORD ret
, type
, size
, needed
= 0;
5163 HKEY hkeyPrinter
, hkeyDrivers
;
5164 const printenv_t
* env
;
5166 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
5167 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
5170 ZeroMemory(pDriverInfo
, cbBuf
);
5172 if (!(name
= get_opened_printer_name(hPrinter
))) {
5173 SetLastError(ERROR_INVALID_HANDLE
);
5177 if (Level
< 1 || Level
== 7 || Level
> 8) {
5178 SetLastError(ERROR_INVALID_LEVEL
);
5182 env
= validate_envW(pEnvironment
);
5183 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5185 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
5188 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
5189 SetLastError( ret
);
5193 size
= sizeof(DriverName
);
5195 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5196 (LPBYTE
)DriverName
, &size
);
5197 RegCloseKey(hkeyPrinter
);
5198 if(ret
!= ERROR_SUCCESS
) {
5199 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5203 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5205 ERR("Can't create Drivers key\n");
5209 size
= di_sizeof
[Level
];
5210 if ((size
<= cbBuf
) && pDriverInfo
)
5211 ptr
= pDriverInfo
+ size
;
5213 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5214 env
, Level
, pDriverInfo
, ptr
,
5215 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5217 RegCloseKey(hkeyDrivers
);
5221 RegCloseKey(hkeyDrivers
);
5223 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5224 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5225 if(cbBuf
>= size
+ needed
) return TRUE
;
5226 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5230 /*****************************************************************************
5231 * GetPrinterDriverA [WINSPOOL.@]
5233 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5234 DWORD Level
, LPBYTE pDriverInfo
,
5235 DWORD cbBuf
, LPDWORD pcbNeeded
)
5238 UNICODE_STRING pEnvW
;
5244 ZeroMemory(pDriverInfo
, cbBuf
);
5245 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5248 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5249 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5252 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5254 HeapFree(GetProcessHeap(), 0, buf
);
5256 RtlFreeUnicodeString(&pEnvW
);
5260 /*****************************************************************************
5261 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5263 * Return the PATH for the Printer-Drivers (UNICODE)
5266 * pName [I] Servername (NT only) or NULL (local Computer)
5267 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5268 * Level [I] Structure-Level (must be 1)
5269 * pDriverDirectory [O] PTR to Buffer that receives the Result
5270 * cbBuf [I] Size of Buffer at pDriverDirectory
5271 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5272 * required for pDriverDirectory
5275 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5276 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5277 * if cbBuf is too small
5279 * Native Values returned in pDriverDirectory on Success:
5280 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5281 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5282 *| win9x(Windows 4.0): "%winsysdir%"
5284 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5287 *- Only NULL or "" is supported for pName
5290 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5291 DWORD Level
, LPBYTE pDriverDirectory
,
5292 DWORD cbBuf
, LPDWORD pcbNeeded
)
5294 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5295 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5297 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5300 /* (Level != 1) is ignored in win9x */
5301 SetLastError(ERROR_INVALID_LEVEL
);
5304 if (pcbNeeded
== NULL
) {
5305 /* (pcbNeeded == NULL) is ignored in win9x */
5306 SetLastError(RPC_X_NULL_REF_POINTER
);
5310 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5311 pDriverDirectory
, cbBuf
, pcbNeeded
);
5316 /*****************************************************************************
5317 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5319 * Return the PATH for the Printer-Drivers (ANSI)
5321 * See GetPrinterDriverDirectoryW.
5324 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5327 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5328 DWORD Level
, LPBYTE pDriverDirectory
,
5329 DWORD cbBuf
, LPDWORD pcbNeeded
)
5331 UNICODE_STRING nameW
, environmentW
;
5334 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5335 WCHAR
*driverDirectoryW
= NULL
;
5337 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5338 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5340 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5342 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5343 else nameW
.Buffer
= NULL
;
5344 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5345 else environmentW
.Buffer
= NULL
;
5347 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5348 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5351 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5352 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5354 *pcbNeeded
= needed
;
5355 ret
= needed
<= cbBuf
;
5357 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5359 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5361 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5362 RtlFreeUnicodeString(&environmentW
);
5363 RtlFreeUnicodeString(&nameW
);
5368 /*****************************************************************************
5369 * AddPrinterDriverA [WINSPOOL.@]
5371 * See AddPrinterDriverW.
5374 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5376 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5377 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5380 /******************************************************************************
5381 * AddPrinterDriverW (WINSPOOL.@)
5383 * Install a Printer Driver
5386 * pName [I] Servername or NULL (local Computer)
5387 * level [I] Level for the supplied DRIVER_INFO_*W struct
5388 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5395 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5397 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5398 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5401 /*****************************************************************************
5402 * AddPrintProcessorA [WINSPOOL.@]
5404 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5405 LPSTR pPrintProcessorName
)
5407 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5408 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5412 /*****************************************************************************
5413 * AddPrintProcessorW [WINSPOOL.@]
5415 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5416 LPWSTR pPrintProcessorName
)
5418 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5419 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5423 /*****************************************************************************
5424 * AddPrintProvidorA [WINSPOOL.@]
5426 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5428 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5432 /*****************************************************************************
5433 * AddPrintProvidorW [WINSPOOL.@]
5435 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5437 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5441 /*****************************************************************************
5442 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5444 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5445 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5447 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5448 pDevModeOutput
, pDevModeInput
);
5452 /*****************************************************************************
5453 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5455 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5456 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5458 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5459 pDevModeOutput
, pDevModeInput
);
5463 /*****************************************************************************
5464 * PrinterProperties [WINSPOOL.@]
5466 * Displays a dialog to set the properties of the printer.
5469 * nonzero on success or zero on failure
5472 * implemented as stub only
5474 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5475 HANDLE hPrinter
/* [in] handle to printer object */
5477 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5478 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5482 /*****************************************************************************
5483 * EnumJobsA [WINSPOOL.@]
5486 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5487 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5490 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5491 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5493 if(pcbNeeded
) *pcbNeeded
= 0;
5494 if(pcReturned
) *pcReturned
= 0;
5499 /*****************************************************************************
5500 * EnumJobsW [WINSPOOL.@]
5503 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5504 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5507 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5508 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5510 if(pcbNeeded
) *pcbNeeded
= 0;
5511 if(pcReturned
) *pcReturned
= 0;
5515 /*****************************************************************************
5516 * WINSPOOL_EnumPrinterDrivers [internal]
5518 * Delivers information about all printer drivers installed on the
5519 * localhost or a given server
5522 * nonzero on success or zero on failure. If the buffer for the returned
5523 * information is too small the function will return an error
5526 * - only implemented for localhost, foreign hosts will return an error
5528 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5529 DWORD Level
, LPBYTE pDriverInfo
,
5531 DWORD cbBuf
, LPDWORD pcbNeeded
,
5532 LPDWORD pcFound
, DWORD data_offset
)
5536 const printenv_t
* env
;
5538 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5539 debugstr_w(pName
), debugstr_w(pEnvironment
),
5540 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5542 env
= validate_envW(pEnvironment
);
5543 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5547 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5549 ERR("Can't open Drivers key\n");
5553 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5554 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5555 RegCloseKey(hkeyDrivers
);
5556 ERR("Can't query Drivers key\n");
5559 TRACE("Found %d Drivers\n", *pcFound
);
5561 /* get size of single struct
5562 * unicode and ascii structure have the same size
5564 size
= di_sizeof
[Level
];
5566 if (data_offset
== 0)
5567 data_offset
= size
* (*pcFound
);
5568 *pcbNeeded
= data_offset
;
5570 for( i
= 0; i
< *pcFound
; i
++) {
5571 WCHAR DriverNameW
[255];
5572 PBYTE table_ptr
= NULL
;
5573 PBYTE data_ptr
= NULL
;
5576 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, ARRAY_SIZE(DriverNameW
)) != ERROR_SUCCESS
) {
5577 ERR("Can't enum key number %d\n", i
);
5578 RegCloseKey(hkeyDrivers
);
5582 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5583 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5584 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5585 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5587 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5588 env
, Level
, table_ptr
, data_ptr
,
5589 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5591 RegCloseKey(hkeyDrivers
);
5595 *pcbNeeded
+= needed
;
5598 RegCloseKey(hkeyDrivers
);
5600 if(cbBuf
< *pcbNeeded
){
5601 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5608 /*****************************************************************************
5609 * EnumPrinterDriversW [WINSPOOL.@]
5611 * see function EnumPrinterDrivers for RETURNS, BUGS
5613 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5614 LPBYTE pDriverInfo
, DWORD cbBuf
,
5615 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5617 static const WCHAR allW
[] = {'a','l','l',0};
5621 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5623 SetLastError(RPC_X_NULL_REF_POINTER
);
5627 /* check for local drivers */
5628 if((pName
) && (pName
[0])) {
5629 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5630 SetLastError(ERROR_ACCESS_DENIED
);
5634 /* check input parameter */
5635 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5636 SetLastError(ERROR_INVALID_LEVEL
);
5640 if(pDriverInfo
&& cbBuf
> 0)
5641 memset( pDriverInfo
, 0, cbBuf
);
5643 /* Exception: pull all printers */
5644 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5646 DWORD i
, needed
, bufsize
= cbBuf
;
5647 DWORD total_found
= 0;
5650 /* Precompute the overall total; we need this to know
5651 where pointers end and data begins (i.e. data_offset) */
5652 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5655 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5656 NULL
, 0, 0, &needed
, &found
, 0);
5657 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5658 total_found
+= found
;
5661 data_offset
= di_sizeof
[Level
] * total_found
;
5666 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
5669 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5670 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5671 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5673 *pcReturned
+= found
;
5674 *pcbNeeded
= needed
;
5675 data_offset
= needed
;
5676 total_found
+= found
;
5681 /* Normal behavior */
5682 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5683 0, cbBuf
, pcbNeeded
, &found
, 0);
5685 *pcReturned
= found
;
5690 /*****************************************************************************
5691 * EnumPrinterDriversA [WINSPOOL.@]
5693 * see function EnumPrinterDrivers for RETURNS, BUGS
5695 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5696 LPBYTE pDriverInfo
, DWORD cbBuf
,
5697 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5700 UNICODE_STRING pNameW
, pEnvironmentW
;
5701 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5705 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5707 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5708 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5710 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5711 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5713 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5715 HeapFree(GetProcessHeap(), 0, buf
);
5717 RtlFreeUnicodeString(&pNameW
);
5718 RtlFreeUnicodeString(&pEnvironmentW
);
5723 /******************************************************************************
5724 * EnumPortsA (WINSPOOL.@)
5729 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5730 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5733 LPBYTE bufferW
= NULL
;
5734 LPWSTR nameW
= NULL
;
5736 DWORD numentries
= 0;
5739 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5740 cbBuf
, pcbNeeded
, pcReturned
);
5742 /* convert servername to unicode */
5744 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5745 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5746 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5748 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5749 needed
= cbBuf
* sizeof(WCHAR
);
5750 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5751 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5753 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5754 if (pcbNeeded
) needed
= *pcbNeeded
;
5755 /* HeapReAlloc return NULL, when bufferW was NULL */
5756 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5757 HeapAlloc(GetProcessHeap(), 0, needed
);
5759 /* Try again with the large Buffer */
5760 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5762 needed
= pcbNeeded
? *pcbNeeded
: 0;
5763 numentries
= pcReturned
? *pcReturned
: 0;
5766 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5767 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5770 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5771 DWORD entrysize
= 0;
5774 LPPORT_INFO_2W pi2w
;
5775 LPPORT_INFO_2A pi2a
;
5778 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5780 /* First pass: calculate the size for all Entries */
5781 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5782 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5784 while (index
< numentries
) {
5786 needed
+= entrysize
; /* PORT_INFO_?A */
5787 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5789 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5790 NULL
, 0, NULL
, NULL
);
5792 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5793 NULL
, 0, NULL
, NULL
);
5794 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5795 NULL
, 0, NULL
, NULL
);
5797 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5798 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5799 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5802 /* check for errors and quit on failure */
5803 if (cbBuf
< needed
) {
5804 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5808 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5809 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5810 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5811 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5812 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5814 /* Second Pass: Fill the User Buffer (if we have one) */
5815 while ((index
< numentries
) && pPorts
) {
5817 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5818 pi2a
->pPortName
= ptr
;
5819 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5820 ptr
, cbBuf
, NULL
, NULL
);
5824 pi2a
->pMonitorName
= ptr
;
5825 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5826 ptr
, cbBuf
, NULL
, NULL
);
5830 pi2a
->pDescription
= ptr
;
5831 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5832 ptr
, cbBuf
, NULL
, NULL
);
5836 pi2a
->fPortType
= pi2w
->fPortType
;
5837 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5840 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5841 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5842 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5847 if (pcbNeeded
) *pcbNeeded
= needed
;
5848 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5850 HeapFree(GetProcessHeap(), 0, nameW
);
5851 HeapFree(GetProcessHeap(), 0, bufferW
);
5853 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5854 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5860 /******************************************************************************
5861 * EnumPortsW (WINSPOOL.@)
5863 * Enumerate available Ports
5866 * pName [I] Servername or NULL (local Computer)
5867 * Level [I] Structure-Level (1 or 2)
5868 * pPorts [O] PTR to Buffer that receives the Result
5869 * cbBuf [I] Size of Buffer at pPorts
5870 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5871 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5875 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5878 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5881 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5882 cbBuf
, pcbNeeded
, pcReturned
);
5884 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5886 /* Level is not checked in win9x */
5887 if (!Level
|| (Level
> 2)) {
5888 WARN("level (%d) is ignored in win9x\n", Level
);
5889 SetLastError(ERROR_INVALID_LEVEL
);
5892 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5893 SetLastError(RPC_X_NULL_REF_POINTER
);
5897 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5900 /******************************************************************************
5901 * GetDefaultPrinterW (WINSPOOL.@)
5904 * This function must read the value from data 'device' of key
5905 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5907 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5911 WCHAR
*buffer
, *ptr
;
5915 SetLastError(ERROR_INVALID_PARAMETER
);
5919 /* make the buffer big enough for the stuff from the profile/registry,
5920 * the content must fit into the local buffer to compute the correct
5921 * size even if the extern buffer is too small or not given.
5922 * (20 for ,driver,port) */
5924 len
= max(100, (insize
+ 20));
5925 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5927 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5929 SetLastError (ERROR_FILE_NOT_FOUND
);
5933 TRACE("%s\n", debugstr_w(buffer
));
5935 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5937 SetLastError(ERROR_INVALID_NAME
);
5943 *namesize
= strlenW(buffer
) + 1;
5944 if(!name
|| (*namesize
> insize
))
5946 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5950 strcpyW(name
, buffer
);
5953 HeapFree( GetProcessHeap(), 0, buffer
);
5958 /******************************************************************************
5959 * GetDefaultPrinterA (WINSPOOL.@)
5961 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5965 WCHAR
*bufferW
= NULL
;
5969 SetLastError(ERROR_INVALID_PARAMETER
);
5973 if(name
&& *namesize
) {
5975 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5978 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5983 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5987 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5990 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5993 HeapFree( GetProcessHeap(), 0, bufferW
);
5998 /******************************************************************************
5999 * SetDefaultPrinterW (WINSPOOL.204)
6001 * Set the Name of the Default Printer
6004 * pszPrinter [I] Name of the Printer or NULL
6011 * When the Parameter is NULL or points to an Empty String and
6012 * a Default Printer was already present, then this Function changes nothing.
6013 * Without a Default Printer and NULL (or an Empty String) as Parameter,
6014 * the First enumerated local Printer is used.
6017 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
6019 WCHAR default_printer
[MAX_PATH
];
6020 LPWSTR buffer
= NULL
;
6026 TRACE("(%s)\n", debugstr_w(pszPrinter
));
6027 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
6029 default_printer
[0] = '\0';
6030 size
= ARRAY_SIZE(default_printer
);
6032 /* if we have a default Printer, do nothing. */
6033 if (GetDefaultPrinterW(default_printer
, &size
))
6037 /* we have no default Printer: search local Printers and use the first */
6038 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
6040 default_printer
[0] = '\0';
6041 size
= ARRAY_SIZE(default_printer
);
6042 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
6044 pszPrinter
= default_printer
;
6045 TRACE("using %s\n", debugstr_w(pszPrinter
));
6050 if (pszPrinter
== NULL
) {
6051 TRACE("no local printer found\n");
6052 SetLastError(ERROR_FILE_NOT_FOUND
);
6057 /* "pszPrinter" is never empty or NULL here. */
6058 namelen
= lstrlenW(pszPrinter
);
6059 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
6060 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
6062 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
6063 HeapFree(GetProcessHeap(), 0, buffer
);
6064 SetLastError(ERROR_FILE_NOT_FOUND
);
6068 /* read the devices entry for the printer (driver,port) to build the string for the
6069 default device entry (printer,driver,port) */
6070 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
6071 buffer
[namelen
] = ',';
6072 namelen
++; /* move index to the start of the driver */
6074 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
6075 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
6077 TRACE("set device to %s\n", debugstr_w(buffer
));
6079 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
6080 TRACE("failed to set the device entry: %d\n", GetLastError());
6081 lres
= ERROR_INVALID_PRINTER_NAME
;
6084 /* remove the next section, when INIFileMapping is implemented */
6087 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
6088 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
6095 if (lres
!= ERROR_FILE_NOT_FOUND
)
6096 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
6098 SetLastError(ERROR_INVALID_PRINTER_NAME
);
6102 HeapFree(GetProcessHeap(), 0, buffer
);
6103 return (lres
== ERROR_SUCCESS
);
6106 /******************************************************************************
6107 * SetDefaultPrinterA (WINSPOOL.202)
6109 * See SetDefaultPrinterW.
6112 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
6114 LPWSTR bufferW
= NULL
;
6117 TRACE("(%s)\n", debugstr_a(pszPrinter
));
6119 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
6120 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6121 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
6123 res
= SetDefaultPrinterW(bufferW
);
6124 HeapFree(GetProcessHeap(), 0, bufferW
);
6128 /******************************************************************************
6129 * SetPrinterDataExA (WINSPOOL.@)
6131 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6132 LPCSTR pValueName
, DWORD Type
,
6133 LPBYTE pData
, DWORD cbData
)
6135 HKEY hkeyPrinter
, hkeySubkey
;
6138 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
6139 debugstr_a(pValueName
), Type
, pData
, cbData
);
6141 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6145 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6147 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
6148 RegCloseKey(hkeyPrinter
);
6151 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6152 RegCloseKey(hkeySubkey
);
6153 RegCloseKey(hkeyPrinter
);
6157 /******************************************************************************
6158 * SetPrinterDataExW (WINSPOOL.@)
6160 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6161 LPCWSTR pValueName
, DWORD Type
,
6162 LPBYTE pData
, DWORD cbData
)
6164 HKEY hkeyPrinter
, hkeySubkey
;
6167 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
6168 debugstr_w(pValueName
), Type
, pData
, cbData
);
6170 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6174 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6176 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
6177 RegCloseKey(hkeyPrinter
);
6180 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6181 RegCloseKey(hkeySubkey
);
6182 RegCloseKey(hkeyPrinter
);
6186 /******************************************************************************
6187 * SetPrinterDataA (WINSPOOL.@)
6189 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
6190 LPBYTE pData
, DWORD cbData
)
6192 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
6196 /******************************************************************************
6197 * SetPrinterDataW (WINSPOOL.@)
6199 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
6200 LPBYTE pData
, DWORD cbData
)
6202 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6206 /******************************************************************************
6207 * GetPrinterDataExA (WINSPOOL.@)
6209 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6210 LPCSTR pValueName
, LPDWORD pType
,
6211 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6213 opened_printer_t
*printer
;
6214 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6217 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6218 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6220 printer
= get_opened_printer(hPrinter
);
6221 if(!printer
) return ERROR_INVALID_HANDLE
;
6223 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6224 if (ret
) return ret
;
6226 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6228 if (printer
->name
) {
6230 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6232 RegCloseKey(hkeyPrinters
);
6235 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6236 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6237 RegCloseKey(hkeyPrinter
);
6238 RegCloseKey(hkeyPrinters
);
6243 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6244 0, pType
, pData
, pcbNeeded
);
6246 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6248 RegCloseKey(hkeySubkey
);
6249 RegCloseKey(hkeyPrinter
);
6250 RegCloseKey(hkeyPrinters
);
6252 TRACE("--> %d\n", ret
);
6256 /******************************************************************************
6257 * GetPrinterDataExW (WINSPOOL.@)
6259 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6260 LPCWSTR pValueName
, LPDWORD pType
,
6261 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6263 opened_printer_t
*printer
;
6264 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6267 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6268 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6270 printer
= get_opened_printer(hPrinter
);
6271 if(!printer
) return ERROR_INVALID_HANDLE
;
6273 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6274 if (ret
) return ret
;
6276 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6278 if (printer
->name
) {
6280 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6282 RegCloseKey(hkeyPrinters
);
6285 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6286 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6287 RegCloseKey(hkeyPrinter
);
6288 RegCloseKey(hkeyPrinters
);
6293 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6294 0, pType
, pData
, pcbNeeded
);
6296 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6298 RegCloseKey(hkeySubkey
);
6299 RegCloseKey(hkeyPrinter
);
6300 RegCloseKey(hkeyPrinters
);
6302 TRACE("--> %d\n", ret
);
6306 /******************************************************************************
6307 * GetPrinterDataA (WINSPOOL.@)
6309 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6310 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6312 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6313 pData
, nSize
, pcbNeeded
);
6316 /******************************************************************************
6317 * GetPrinterDataW (WINSPOOL.@)
6319 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6320 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6322 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6323 pData
, nSize
, pcbNeeded
);
6326 /*******************************************************************************
6327 * EnumPrinterDataExW [WINSPOOL.@]
6329 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6330 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6331 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6333 HKEY hkPrinter
, hkSubKey
;
6334 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6335 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6340 PPRINTER_ENUM_VALUESW ppev
;
6342 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6344 if (pKeyName
== NULL
|| *pKeyName
== 0)
6345 return ERROR_INVALID_PARAMETER
;
6347 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6348 if (ret
!= ERROR_SUCCESS
)
6350 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6355 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6356 if (ret
!= ERROR_SUCCESS
)
6358 r
= RegCloseKey (hkPrinter
);
6359 if (r
!= ERROR_SUCCESS
)
6360 WARN ("RegCloseKey returned %i\n", r
);
6361 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6362 debugstr_w (pKeyName
), ret
);
6366 ret
= RegCloseKey (hkPrinter
);
6367 if (ret
!= ERROR_SUCCESS
)
6369 ERR ("RegCloseKey returned %i\n", ret
);
6370 r
= RegCloseKey (hkSubKey
);
6371 if (r
!= ERROR_SUCCESS
)
6372 WARN ("RegCloseKey returned %i\n", r
);
6376 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6377 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6378 if (ret
!= ERROR_SUCCESS
)
6380 r
= RegCloseKey (hkSubKey
);
6381 if (r
!= ERROR_SUCCESS
)
6382 WARN ("RegCloseKey returned %i\n", r
);
6383 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6387 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6388 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6390 if (cValues
== 0) /* empty key */
6392 r
= RegCloseKey (hkSubKey
);
6393 if (r
!= ERROR_SUCCESS
)
6394 WARN ("RegCloseKey returned %i\n", r
);
6395 *pcbEnumValues
= *pnEnumValues
= 0;
6396 return ERROR_SUCCESS
;
6399 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6401 hHeap
= GetProcessHeap ();
6404 ERR ("GetProcessHeap failed\n");
6405 r
= RegCloseKey (hkSubKey
);
6406 if (r
!= ERROR_SUCCESS
)
6407 WARN ("RegCloseKey returned %i\n", r
);
6408 return ERROR_OUTOFMEMORY
;
6411 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6412 if (lpValueName
== NULL
)
6414 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6415 r
= RegCloseKey (hkSubKey
);
6416 if (r
!= ERROR_SUCCESS
)
6417 WARN ("RegCloseKey returned %i\n", r
);
6418 return ERROR_OUTOFMEMORY
;
6421 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6422 if (lpValue
== NULL
)
6424 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6425 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6426 WARN ("HeapFree failed with code %i\n", GetLastError ());
6427 r
= RegCloseKey (hkSubKey
);
6428 if (r
!= ERROR_SUCCESS
)
6429 WARN ("RegCloseKey returned %i\n", r
);
6430 return ERROR_OUTOFMEMORY
;
6433 TRACE ("pass 1: calculating buffer required for all names and values\n");
6435 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6437 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6439 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6441 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6442 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6443 NULL
, NULL
, lpValue
, &cbValueLen
);
6444 if (ret
!= ERROR_SUCCESS
)
6446 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6447 WARN ("HeapFree failed with code %i\n", GetLastError ());
6448 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6449 WARN ("HeapFree failed with code %i\n", GetLastError ());
6450 r
= RegCloseKey (hkSubKey
);
6451 if (r
!= ERROR_SUCCESS
)
6452 WARN ("RegCloseKey returned %i\n", r
);
6453 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6457 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6458 debugstr_w (lpValueName
), dwIndex
,
6459 cbValueNameLen
+ 1, cbValueLen
);
6461 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6462 cbBufSize
+= cbValueLen
;
6465 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6467 *pcbEnumValues
= cbBufSize
;
6468 *pnEnumValues
= cValues
;
6470 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6472 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6473 WARN ("HeapFree failed with code %i\n", GetLastError ());
6474 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6475 WARN ("HeapFree failed with code %i\n", GetLastError ());
6476 r
= RegCloseKey (hkSubKey
);
6477 if (r
!= ERROR_SUCCESS
)
6478 WARN ("RegCloseKey returned %i\n", r
);
6479 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6480 return ERROR_MORE_DATA
;
6483 TRACE ("pass 2: copying all names and values to buffer\n");
6485 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6486 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6488 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6490 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6491 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6492 NULL
, &dwType
, lpValue
, &cbValueLen
);
6493 if (ret
!= ERROR_SUCCESS
)
6495 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6496 WARN ("HeapFree failed with code %i\n", GetLastError ());
6497 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6498 WARN ("HeapFree failed with code %i\n", GetLastError ());
6499 r
= RegCloseKey (hkSubKey
);
6500 if (r
!= ERROR_SUCCESS
)
6501 WARN ("RegCloseKey returned %i\n", r
);
6502 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6506 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6507 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6508 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6509 pEnumValues
+= cbValueNameLen
;
6511 /* return # of *bytes* (including trailing \0), not # of chars */
6512 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6514 ppev
[dwIndex
].dwType
= dwType
;
6516 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6517 ppev
[dwIndex
].pData
= pEnumValues
;
6518 pEnumValues
+= cbValueLen
;
6520 ppev
[dwIndex
].cbData
= cbValueLen
;
6522 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6523 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6526 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6528 ret
= GetLastError ();
6529 ERR ("HeapFree failed with code %i\n", ret
);
6530 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6531 WARN ("HeapFree failed with code %i\n", GetLastError ());
6532 r
= RegCloseKey (hkSubKey
);
6533 if (r
!= ERROR_SUCCESS
)
6534 WARN ("RegCloseKey returned %i\n", r
);
6538 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6540 ret
= GetLastError ();
6541 ERR ("HeapFree failed with code %i\n", ret
);
6542 r
= RegCloseKey (hkSubKey
);
6543 if (r
!= ERROR_SUCCESS
)
6544 WARN ("RegCloseKey returned %i\n", r
);
6548 ret
= RegCloseKey (hkSubKey
);
6549 if (ret
!= ERROR_SUCCESS
)
6551 ERR ("RegCloseKey returned %i\n", ret
);
6555 return ERROR_SUCCESS
;
6558 /*******************************************************************************
6559 * EnumPrinterDataExA [WINSPOOL.@]
6561 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6562 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6563 * what Windows 2000 SP1 does.
6566 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6567 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6568 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6572 DWORD ret
, dwIndex
, dwBufSize
;
6576 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6578 if (pKeyName
== NULL
|| *pKeyName
== 0)
6579 return ERROR_INVALID_PARAMETER
;
6581 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6584 ret
= GetLastError ();
6585 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6589 hHeap
= GetProcessHeap ();
6592 ERR ("GetProcessHeap failed\n");
6593 return ERROR_OUTOFMEMORY
;
6596 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6597 if (pKeyNameW
== NULL
)
6599 ERR ("Failed to allocate %i bytes from process heap\n",
6600 (LONG
)(len
* sizeof (WCHAR
)));
6601 return ERROR_OUTOFMEMORY
;
6604 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6606 ret
= GetLastError ();
6607 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6608 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6609 WARN ("HeapFree failed with code %i\n", GetLastError ());
6613 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6614 pcbEnumValues
, pnEnumValues
);
6615 if (ret
!= ERROR_SUCCESS
)
6617 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6618 WARN ("HeapFree failed with code %i\n", GetLastError ());
6619 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6623 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6625 ret
= GetLastError ();
6626 ERR ("HeapFree failed with code %i\n", ret
);
6630 if (*pnEnumValues
== 0) /* empty key */
6631 return ERROR_SUCCESS
;
6634 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6636 PPRINTER_ENUM_VALUESW ppev
=
6637 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6639 if (dwBufSize
< ppev
->cbValueName
)
6640 dwBufSize
= ppev
->cbValueName
;
6642 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6643 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6644 dwBufSize
= ppev
->cbData
;
6647 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6649 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6650 if (pBuffer
== NULL
)
6652 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6653 return ERROR_OUTOFMEMORY
;
6656 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6658 PPRINTER_ENUM_VALUESW ppev
=
6659 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6661 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6662 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6666 ret
= GetLastError ();
6667 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6668 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6669 WARN ("HeapFree failed with code %i\n", GetLastError ());
6673 memcpy (ppev
->pValueName
, pBuffer
, len
);
6675 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6677 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6678 ppev
->dwType
!= REG_MULTI_SZ
)
6681 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6682 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6685 ret
= GetLastError ();
6686 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6687 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6688 WARN ("HeapFree failed with code %i\n", GetLastError ());
6692 memcpy (ppev
->pData
, pBuffer
, len
);
6694 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6695 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6698 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6700 ret
= GetLastError ();
6701 ERR ("HeapFree failed with code %i\n", ret
);
6705 return ERROR_SUCCESS
;
6708 /******************************************************************************
6709 * AbortPrinter (WINSPOOL.@)
6711 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6713 FIXME("(%p), stub!\n", hPrinter
);
6717 /******************************************************************************
6718 * AddPortA (WINSPOOL.@)
6723 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6725 LPWSTR nameW
= NULL
;
6726 LPWSTR monitorW
= NULL
;
6730 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6733 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6734 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6735 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6739 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6740 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6741 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6743 res
= AddPortW(nameW
, hWnd
, monitorW
);
6744 HeapFree(GetProcessHeap(), 0, nameW
);
6745 HeapFree(GetProcessHeap(), 0, monitorW
);
6749 /******************************************************************************
6750 * AddPortW (WINSPOOL.@)
6752 * Add a Port for a specific Monitor
6755 * pName [I] Servername or NULL (local Computer)
6756 * hWnd [I] Handle to parent Window for the Dialog-Box
6757 * pMonitorName [I] Name of the Monitor that manage the Port
6764 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6766 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6768 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6770 if (!pMonitorName
) {
6771 SetLastError(RPC_X_NULL_REF_POINTER
);
6775 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6778 /******************************************************************************
6779 * AddPortExA (WINSPOOL.@)
6784 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6787 PORT_INFO_2A
* pi2A
;
6788 LPWSTR nameW
= NULL
;
6789 LPWSTR monitorW
= NULL
;
6793 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6795 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6796 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6798 if ((level
< 1) || (level
> 2)) {
6799 SetLastError(ERROR_INVALID_LEVEL
);
6804 SetLastError(ERROR_INVALID_PARAMETER
);
6809 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6810 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6811 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6815 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6816 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6817 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6820 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6822 if (pi2A
->pPortName
) {
6823 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6824 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6825 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6829 if (pi2A
->pMonitorName
) {
6830 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6831 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6832 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6835 if (pi2A
->pDescription
) {
6836 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6837 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6838 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6840 pi2W
.fPortType
= pi2A
->fPortType
;
6841 pi2W
.Reserved
= pi2A
->Reserved
;
6844 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6846 HeapFree(GetProcessHeap(), 0, nameW
);
6847 HeapFree(GetProcessHeap(), 0, monitorW
);
6848 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6849 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6850 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6855 /******************************************************************************
6856 * AddPortExW (WINSPOOL.@)
6858 * Add a Port for a specific Monitor, without presenting a user interface
6861 * pName [I] Servername or NULL (local Computer)
6862 * level [I] Structure-Level (1 or 2) for pBuffer
6863 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6864 * pMonitorName [I] Name of the Monitor that manage the Port
6871 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6875 pi2
= (PORT_INFO_2W
*) pBuffer
;
6877 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6878 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6879 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6880 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6882 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6884 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6885 SetLastError(ERROR_INVALID_PARAMETER
);
6889 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6892 /******************************************************************************
6893 * AddPrinterConnectionA (WINSPOOL.@)
6895 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6897 FIXME("%s\n", debugstr_a(pName
));
6901 /******************************************************************************
6902 * AddPrinterConnectionW (WINSPOOL.@)
6904 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6906 FIXME("%s\n", debugstr_w(pName
));
6910 /******************************************************************************
6911 * AddPrinterDriverExW (WINSPOOL.@)
6913 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6916 * pName [I] Servername or NULL (local Computer)
6917 * level [I] Level for the supplied DRIVER_INFO_*W struct
6918 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6919 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6926 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6928 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6930 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6932 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6933 SetLastError(ERROR_INVALID_LEVEL
);
6938 SetLastError(ERROR_INVALID_PARAMETER
);
6942 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6945 /******************************************************************************
6946 * AddPrinterDriverExA (WINSPOOL.@)
6948 * See AddPrinterDriverExW.
6951 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6953 DRIVER_INFO_8A
*diA
;
6955 LPWSTR nameW
= NULL
;
6960 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6962 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6963 ZeroMemory(&diW
, sizeof(diW
));
6965 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6966 SetLastError(ERROR_INVALID_LEVEL
);
6971 SetLastError(ERROR_INVALID_PARAMETER
);
6975 /* convert servername to unicode */
6977 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6978 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6979 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6983 diW
.cVersion
= diA
->cVersion
;
6986 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6987 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6988 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6991 if (diA
->pEnvironment
) {
6992 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6993 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6994 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6997 if (diA
->pDriverPath
) {
6998 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6999 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7000 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
7003 if (diA
->pDataFile
) {
7004 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
7005 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7006 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
7009 if (diA
->pConfigFile
) {
7010 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
7011 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7012 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
7015 if ((Level
> 2) && diA
->pHelpFile
) {
7016 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, NULL
, 0);
7017 diW
.pHelpFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7018 MultiByteToWideChar(CP_ACP
, 0, diA
->pHelpFile
, -1, diW
.pHelpFile
, len
);
7021 if ((Level
> 2) && diA
->pDependentFiles
) {
7022 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
7023 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
7024 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7025 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
7028 if ((Level
> 2) && diA
->pMonitorName
) {
7029 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
7030 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7031 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
7034 if ((Level
> 2) && diA
->pDefaultDataType
) {
7035 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
7036 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7037 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
7040 if ((Level
> 3) && diA
->pszzPreviousNames
) {
7041 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
7042 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
7043 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7044 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
7048 diW
.ftDriverDate
= diA
->ftDriverDate
;
7049 diW
.dwlDriverVersion
= diA
->dwlDriverVersion
;
7052 if ((Level
> 5) && diA
->pszMfgName
) {
7053 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
7054 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7055 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
7058 if ((Level
> 5) && diA
->pszOEMUrl
) {
7059 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
7060 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7061 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
7064 if ((Level
> 5) && diA
->pszHardwareID
) {
7065 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
7066 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7067 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
7070 if ((Level
> 5) && diA
->pszProvider
) {
7071 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
7072 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7073 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
7076 if ((Level
> 7) && diA
->pszPrintProcessor
) {
7077 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, NULL
, 0);
7078 diW
.pszPrintProcessor
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7079 MultiByteToWideChar(CP_ACP
, 0, diA
->pszPrintProcessor
, -1, diW
.pszPrintProcessor
, len
);
7082 if ((Level
> 7) && diA
->pszVendorSetup
) {
7083 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, NULL
, 0);
7084 diW
.pszVendorSetup
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7085 MultiByteToWideChar(CP_ACP
, 0, diA
->pszVendorSetup
, -1, diW
.pszVendorSetup
, len
);
7088 if ((Level
> 7) && diA
->pszzColorProfiles
) {
7089 lenA
= multi_sz_lenA(diA
->pszzColorProfiles
);
7090 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, NULL
, 0);
7091 diW
.pszzColorProfiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7092 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzColorProfiles
, lenA
, diW
.pszzColorProfiles
, len
);
7095 if ((Level
> 7) && diA
->pszInfPath
) {
7096 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, NULL
, 0);
7097 diW
.pszInfPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7098 MultiByteToWideChar(CP_ACP
, 0, diA
->pszInfPath
, -1, diW
.pszInfPath
, len
);
7101 if ((Level
> 7) && diA
->pszzCoreDriverDependencies
) {
7102 lenA
= multi_sz_lenA(diA
->pszzCoreDriverDependencies
);
7103 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, NULL
, 0);
7104 diW
.pszzCoreDriverDependencies
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7105 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzCoreDriverDependencies
, lenA
, diW
.pszzCoreDriverDependencies
, len
);
7109 diW
.dwPrinterDriverAttributes
= diA
->dwPrinterDriverAttributes
;
7110 diW
.ftMinInboxDriverVerDate
= diA
->ftMinInboxDriverVerDate
;
7111 diW
.dwlMinInboxDriverVerVersion
= diA
->dwlMinInboxDriverVerVersion
;
7114 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
7115 TRACE("got %u with %u\n", res
, GetLastError());
7116 HeapFree(GetProcessHeap(), 0, nameW
);
7117 HeapFree(GetProcessHeap(), 0, diW
.pName
);
7118 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
7119 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
7120 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
7121 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
7122 HeapFree(GetProcessHeap(), 0, diW
.pHelpFile
);
7123 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
7124 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
7125 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
7126 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
7127 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
7128 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
7129 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
7130 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
7131 HeapFree(GetProcessHeap(), 0, diW
.pszPrintProcessor
);
7132 HeapFree(GetProcessHeap(), 0, diW
.pszVendorSetup
);
7133 HeapFree(GetProcessHeap(), 0, diW
.pszzColorProfiles
);
7134 HeapFree(GetProcessHeap(), 0, diW
.pszInfPath
);
7135 HeapFree(GetProcessHeap(), 0, diW
.pszzCoreDriverDependencies
);
7137 TRACE("=> %u with %u\n", res
, GetLastError());
7141 /******************************************************************************
7142 * ConfigurePortA (WINSPOOL.@)
7144 * See ConfigurePortW.
7147 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
7149 LPWSTR nameW
= NULL
;
7150 LPWSTR portW
= NULL
;
7154 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
7156 /* convert servername to unicode */
7158 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7159 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7160 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7163 /* convert portname to unicode */
7165 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
7166 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7167 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
7170 res
= ConfigurePortW(nameW
, hWnd
, portW
);
7171 HeapFree(GetProcessHeap(), 0, nameW
);
7172 HeapFree(GetProcessHeap(), 0, portW
);
7176 /******************************************************************************
7177 * ConfigurePortW (WINSPOOL.@)
7179 * Display the Configuration-Dialog for a specific Port
7182 * pName [I] Servername or NULL (local Computer)
7183 * hWnd [I] Handle to parent Window for the Dialog-Box
7184 * pPortName [I] Name of the Port, that should be configured
7191 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
7194 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
7196 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7199 SetLastError(RPC_X_NULL_REF_POINTER
);
7203 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
7206 /******************************************************************************
7207 * ConnectToPrinterDlg (WINSPOOL.@)
7209 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
7211 FIXME("%p %x\n", hWnd
, Flags
);
7215 /******************************************************************************
7216 * DeletePrinterConnectionA (WINSPOOL.@)
7218 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
7220 FIXME("%s\n", debugstr_a(pName
));
7224 /******************************************************************************
7225 * DeletePrinterConnectionW (WINSPOOL.@)
7227 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
7229 FIXME("%s\n", debugstr_w(pName
));
7233 /******************************************************************************
7234 * DeletePrinterDriverExW (WINSPOOL.@)
7236 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
7237 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7242 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7243 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
7245 if(pName
&& pName
[0])
7247 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
7248 SetLastError(ERROR_INVALID_PARAMETER
);
7254 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7255 SetLastError(ERROR_INVALID_PARAMETER
);
7259 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7263 ERR("Can't open drivers key\n");
7267 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7270 RegCloseKey(hkey_drivers
);
7275 /******************************************************************************
7276 * DeletePrinterDriverExA (WINSPOOL.@)
7278 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7279 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7281 UNICODE_STRING NameW
, EnvW
, DriverW
;
7284 asciitounicode(&NameW
, pName
);
7285 asciitounicode(&EnvW
, pEnvironment
);
7286 asciitounicode(&DriverW
, pDriverName
);
7288 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7290 RtlFreeUnicodeString(&DriverW
);
7291 RtlFreeUnicodeString(&EnvW
);
7292 RtlFreeUnicodeString(&NameW
);
7297 /******************************************************************************
7298 * DeletePrinterDataExW (WINSPOOL.@)
7300 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7303 FIXME("%p %s %s\n", hPrinter
,
7304 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7305 return ERROR_INVALID_PARAMETER
;
7308 /******************************************************************************
7309 * DeletePrinterDataExA (WINSPOOL.@)
7311 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7314 FIXME("%p %s %s\n", hPrinter
,
7315 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7316 return ERROR_INVALID_PARAMETER
;
7319 /******************************************************************************
7320 * DeletePrintProcessorA (WINSPOOL.@)
7322 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7324 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7325 debugstr_a(pPrintProcessorName
));
7329 /******************************************************************************
7330 * DeletePrintProcessorW (WINSPOOL.@)
7332 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7334 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7335 debugstr_w(pPrintProcessorName
));
7339 /******************************************************************************
7340 * DeletePrintProvidorA (WINSPOOL.@)
7342 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7344 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7345 debugstr_a(pPrintProviderName
));
7349 /******************************************************************************
7350 * DeletePrintProvidorW (WINSPOOL.@)
7352 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7354 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7355 debugstr_w(pPrintProviderName
));
7359 /******************************************************************************
7360 * EnumFormsA (WINSPOOL.@)
7362 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7363 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7365 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7366 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7370 /******************************************************************************
7371 * EnumFormsW (WINSPOOL.@)
7373 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7374 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7376 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7377 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7381 /*****************************************************************************
7382 * EnumMonitorsA [WINSPOOL.@]
7384 * See EnumMonitorsW.
7387 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7388 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7391 LPBYTE bufferW
= NULL
;
7392 LPWSTR nameW
= NULL
;
7394 DWORD numentries
= 0;
7397 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7398 cbBuf
, pcbNeeded
, pcReturned
);
7400 /* convert servername to unicode */
7402 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7403 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7404 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7406 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7407 needed
= cbBuf
* sizeof(WCHAR
);
7408 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7409 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7411 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7412 if (pcbNeeded
) needed
= *pcbNeeded
;
7413 /* HeapReAlloc return NULL, when bufferW was NULL */
7414 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7415 HeapAlloc(GetProcessHeap(), 0, needed
);
7417 /* Try again with the large Buffer */
7418 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7420 numentries
= pcReturned
? *pcReturned
: 0;
7423 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7424 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7427 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7428 DWORD entrysize
= 0;
7431 LPMONITOR_INFO_2W mi2w
;
7432 LPMONITOR_INFO_2A mi2a
;
7434 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7435 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7437 /* First pass: calculate the size for all Entries */
7438 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7439 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7441 while (index
< numentries
) {
7443 needed
+= entrysize
; /* MONITOR_INFO_?A */
7444 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7446 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7447 NULL
, 0, NULL
, NULL
);
7449 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7450 NULL
, 0, NULL
, NULL
);
7451 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7452 NULL
, 0, NULL
, NULL
);
7454 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7455 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7456 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7459 /* check for errors and quit on failure */
7460 if (cbBuf
< needed
) {
7461 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7465 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7466 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7467 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7468 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7469 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7471 /* Second Pass: Fill the User Buffer (if we have one) */
7472 while ((index
< numentries
) && pMonitors
) {
7474 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7476 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7477 ptr
, cbBuf
, NULL
, NULL
);
7481 mi2a
->pEnvironment
= ptr
;
7482 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7483 ptr
, cbBuf
, NULL
, NULL
);
7487 mi2a
->pDLLName
= ptr
;
7488 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7489 ptr
, cbBuf
, NULL
, NULL
);
7493 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7494 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7495 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7499 if (pcbNeeded
) *pcbNeeded
= needed
;
7500 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7502 HeapFree(GetProcessHeap(), 0, nameW
);
7503 HeapFree(GetProcessHeap(), 0, bufferW
);
7505 TRACE("returning %d with %d (%d byte for %d entries)\n",
7506 (res
), GetLastError(), needed
, numentries
);
7512 /*****************************************************************************
7513 * EnumMonitorsW [WINSPOOL.@]
7515 * Enumerate available Port-Monitors
7518 * pName [I] Servername or NULL (local Computer)
7519 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7520 * pMonitors [O] PTR to Buffer that receives the Result
7521 * cbBuf [I] Size of Buffer at pMonitors
7522 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7523 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7527 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7530 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7531 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7534 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7535 cbBuf
, pcbNeeded
, pcReturned
);
7537 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7539 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7540 SetLastError(RPC_X_NULL_REF_POINTER
);
7544 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7547 /******************************************************************************
7548 * SpoolerInit (WINSPOOL.@)
7550 * Initialize the Spooler
7557 * The function fails on windows, when the spooler service is not running
7560 BOOL WINAPI
SpoolerInit(void)
7563 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7567 /******************************************************************************
7568 * XcvDataW (WINSPOOL.@)
7570 * Execute commands in the Printmonitor DLL
7573 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7574 * pszDataName [i] Name of the command to execute
7575 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7576 * cbInputData [i] Size in Bytes of Buffer at pInputData
7577 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7578 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7579 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7580 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7587 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7588 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7590 * Minimal List of commands, that a Printmonitor DLL should support:
7592 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7593 *| "AddPort" : Add a Port
7594 *| "DeletePort": Delete a Port
7596 * Many Printmonitors support additional commands. Examples for localspl.dll:
7597 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7598 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7601 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7602 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7603 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7605 opened_printer_t
*printer
;
7607 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7608 pInputData
, cbInputData
, pOutputData
,
7609 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7611 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7613 printer
= get_opened_printer(hXcv
);
7614 if (!printer
|| (!printer
->backend_printer
)) {
7615 SetLastError(ERROR_INVALID_HANDLE
);
7619 if (!pcbOutputNeeded
) {
7620 SetLastError(ERROR_INVALID_PARAMETER
);
7624 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7625 SetLastError(RPC_X_NULL_REF_POINTER
);
7629 *pcbOutputNeeded
= 0;
7631 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7632 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7636 /*****************************************************************************
7637 * EnumPrinterDataA [WINSPOOL.@]
7640 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7641 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7642 DWORD cbData
, LPDWORD pcbData
)
7644 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7645 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7646 return ERROR_NO_MORE_ITEMS
;
7649 /*****************************************************************************
7650 * EnumPrinterDataW [WINSPOOL.@]
7653 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7654 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7655 DWORD cbData
, LPDWORD pcbData
)
7657 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7658 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7659 return ERROR_NO_MORE_ITEMS
;
7662 /*****************************************************************************
7663 * EnumPrinterKeyA [WINSPOOL.@]
7666 DWORD WINAPI
EnumPrinterKeyA(HANDLE printer
, const CHAR
*key
, CHAR
*subkey
, DWORD size
, DWORD
*needed
)
7668 FIXME("%p %s %p %x %p\n", printer
, debugstr_a(key
), subkey
, size
, needed
);
7669 return ERROR_CALL_NOT_IMPLEMENTED
;
7672 /*****************************************************************************
7673 * EnumPrinterKeyW [WINSPOOL.@]
7676 DWORD WINAPI
EnumPrinterKeyW(HANDLE printer
, const WCHAR
*key
, WCHAR
*subkey
, DWORD size
, DWORD
*needed
)
7678 FIXME("%p %s %p %x %p\n", printer
, debugstr_w(key
), subkey
, size
, needed
);
7679 return ERROR_CALL_NOT_IMPLEMENTED
;
7682 /*****************************************************************************
7683 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7686 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7687 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7688 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7690 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7691 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7692 pcbNeeded
, pcReturned
);
7696 /*****************************************************************************
7697 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7700 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7701 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7702 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7704 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7705 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7706 pcbNeeded
, pcReturned
);
7710 /*****************************************************************************
7711 * EnumPrintProcessorsA [WINSPOOL.@]
7713 * See EnumPrintProcessorsW.
7716 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7717 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7720 LPBYTE bufferW
= NULL
;
7721 LPWSTR nameW
= NULL
;
7724 DWORD numentries
= 0;
7727 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7728 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7730 /* convert names to unicode */
7732 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7733 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7734 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7737 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7738 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7739 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7742 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7743 needed
= cbBuf
* sizeof(WCHAR
);
7744 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7745 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7747 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7748 if (pcbNeeded
) needed
= *pcbNeeded
;
7749 /* HeapReAlloc return NULL, when bufferW was NULL */
7750 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7751 HeapAlloc(GetProcessHeap(), 0, needed
);
7753 /* Try again with the large Buffer */
7754 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7756 numentries
= pcReturned
? *pcReturned
: 0;
7760 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7763 PPRINTPROCESSOR_INFO_1W ppiw
;
7764 PPRINTPROCESSOR_INFO_1A ppia
;
7766 /* First pass: calculate the size for all Entries */
7767 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7768 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7770 while (index
< numentries
) {
7772 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7773 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7775 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7776 NULL
, 0, NULL
, NULL
);
7778 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7779 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7782 /* check for errors and quit on failure */
7783 if (cbBuf
< needed
) {
7784 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7789 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7790 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7791 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7792 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7793 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7795 /* Second Pass: Fill the User Buffer (if we have one) */
7796 while ((index
< numentries
) && pPPInfo
) {
7798 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7800 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7801 ptr
, cbBuf
, NULL
, NULL
);
7805 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7806 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7811 if (pcbNeeded
) *pcbNeeded
= needed
;
7812 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7814 HeapFree(GetProcessHeap(), 0, nameW
);
7815 HeapFree(GetProcessHeap(), 0, envW
);
7816 HeapFree(GetProcessHeap(), 0, bufferW
);
7818 TRACE("returning %d with %d (%d byte for %d entries)\n",
7819 (res
), GetLastError(), needed
, numentries
);
7824 /*****************************************************************************
7825 * EnumPrintProcessorsW [WINSPOOL.@]
7827 * Enumerate available Print Processors
7830 * pName [I] Servername or NULL (local Computer)
7831 * pEnvironment [I] Printing-Environment or NULL (Default)
7832 * Level [I] Structure-Level (Only 1 is allowed)
7833 * pPPInfo [O] PTR to Buffer that receives the Result
7834 * cbBuf [I] Size of Buffer at pPPInfo
7835 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7836 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7840 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7843 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7844 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7847 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7848 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7850 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7852 if (!pcbNeeded
|| !pcReturned
) {
7853 SetLastError(RPC_X_NULL_REF_POINTER
);
7857 if (!pPPInfo
&& (cbBuf
> 0)) {
7858 SetLastError(ERROR_INVALID_USER_BUFFER
);
7862 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7863 cbBuf
, pcbNeeded
, pcReturned
);
7866 /*****************************************************************************
7867 * ExtDeviceMode [WINSPOOL.@]
7870 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7871 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7874 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7875 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7876 debugstr_a(pProfile
), fMode
);
7880 /*****************************************************************************
7881 * FindClosePrinterChangeNotification [WINSPOOL.@]
7884 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7886 FIXME("Stub: %p\n", hChange
);
7890 /*****************************************************************************
7891 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7894 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7895 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7897 FIXME("Stub: %p %x %x %p\n",
7898 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7899 return INVALID_HANDLE_VALUE
;
7902 /*****************************************************************************
7903 * FindNextPrinterChangeNotification [WINSPOOL.@]
7906 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7907 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7909 FIXME("Stub: %p %p %p %p\n",
7910 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7914 /*****************************************************************************
7915 * FreePrinterNotifyInfo [WINSPOOL.@]
7918 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7920 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7924 /*****************************************************************************
7927 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7928 * ansi depending on the unicode parameter.
7930 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7940 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7943 memcpy(ptr
, str
, *size
);
7950 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7953 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7960 /*****************************************************************************
7963 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7964 LPDWORD pcbNeeded
, BOOL unicode
)
7966 DWORD size
, left
= cbBuf
;
7967 BOOL space
= (cbBuf
> 0);
7974 ji1
->JobId
= job
->job_id
;
7977 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7978 if(space
&& size
<= left
)
7980 ji1
->pDocument
= (LPWSTR
)ptr
;
7988 if (job
->printer_name
)
7990 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7991 if(space
&& size
<= left
)
7993 ji1
->pPrinterName
= (LPWSTR
)ptr
;
8005 /*****************************************************************************
8008 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
8009 LPDWORD pcbNeeded
, BOOL unicode
)
8011 DWORD size
, left
= cbBuf
;
8013 BOOL space
= (cbBuf
> 0);
8015 LPDEVMODEA dmA
= NULL
;
8022 ji2
->JobId
= job
->job_id
;
8025 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
8026 if(space
&& size
<= left
)
8028 ji2
->pDocument
= (LPWSTR
)ptr
;
8036 if (job
->printer_name
)
8038 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
8039 if(space
&& size
<= left
)
8041 ji2
->pPrinterName
= (LPWSTR
)ptr
;
8054 dmA
= DEVMODEdupWtoA(job
->devmode
);
8055 devmode
= (LPDEVMODEW
) dmA
;
8056 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
8060 devmode
= job
->devmode
;
8061 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
8065 FIXME("Can't convert DEVMODE W to A\n");
8068 /* align DEVMODE to a DWORD boundary */
8069 shift
= (4 - (*pcbNeeded
& 3)) & 3;
8075 memcpy(ptr
, devmode
, size
-shift
);
8076 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
8077 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
8090 /*****************************************************************************
8093 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8094 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
8097 DWORD needed
= 0, size
;
8101 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
8103 EnterCriticalSection(&printer_handles_cs
);
8104 job
= get_job(hPrinter
, JobId
);
8111 size
= sizeof(JOB_INFO_1W
);
8116 memset(pJob
, 0, size
);
8120 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8125 size
= sizeof(JOB_INFO_2W
);
8130 memset(pJob
, 0, size
);
8134 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8139 size
= sizeof(JOB_INFO_3
);
8143 memset(pJob
, 0, size
);
8152 SetLastError(ERROR_INVALID_LEVEL
);
8156 *pcbNeeded
= needed
;
8158 LeaveCriticalSection(&printer_handles_cs
);
8162 /*****************************************************************************
8163 * GetJobA [WINSPOOL.@]
8166 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8167 DWORD cbBuf
, LPDWORD pcbNeeded
)
8169 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
8172 /*****************************************************************************
8173 * GetJobW [WINSPOOL.@]
8176 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8177 DWORD cbBuf
, LPDWORD pcbNeeded
)
8179 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
8182 /*****************************************************************************
8185 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
8188 char *unixname
, *cmdA
;
8190 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
8196 if(!(unixname
= wine_get_unix_file_name(filename
)))
8199 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
8200 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
8201 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
8203 TRACE("printing with: %s\n", cmdA
);
8205 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
8210 ERR("pipe() failed!\n");
8214 if ((pid
= fork()) == 0)
8220 /* reset signals that we previously set to SIG_IGN */
8221 signal(SIGPIPE
, SIG_DFL
);
8223 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
8228 ERR("fork() failed!\n");
8234 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
8235 write(fds
[1], buf
, no_read
);
8242 wret
= waitpid(pid
, &status
, 0);
8243 } while (wret
< 0 && errno
== EINTR
);
8246 ERR("waitpid() failed!\n");
8249 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
8251 ERR("child process failed! %d\n", status
);
8258 if(file_fd
!= -1) close(file_fd
);
8259 if(fds
[0] != -1) close(fds
[0]);
8260 if(fds
[1] != -1) close(fds
[1]);
8262 HeapFree(GetProcessHeap(), 0, cmdA
);
8263 HeapFree(GetProcessHeap(), 0, unixname
);
8270 /*****************************************************************************
8273 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8275 static const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8279 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8280 sprintfW(cmd
, fmtW
, printer_name
);
8282 r
= schedule_pipe(cmd
, filename
);
8284 HeapFree(GetProcessHeap(), 0, cmd
);
8288 #ifdef SONAME_LIBCUPS
8289 /*****************************************************************************
8290 * get_cups_jobs_ticket_options
8292 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8293 * The CUPS scheduler only looks for these in Print-File requests, and since
8294 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8297 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8299 FILE *fp
= fopen( file
, "r" );
8300 char buf
[257]; /* DSC max of 256 + '\0' */
8301 const char *ps_adobe
= "%!PS-Adobe-";
8302 const char *cups_job
= "%cupsJobTicket:";
8304 if (!fp
) return num_options
;
8305 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8306 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8307 while (fgets( buf
, sizeof(buf
), fp
))
8309 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8310 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8318 static int get_cups_default_options( const char *printer
, int num_options
, cups_option_t
**options
)
8323 if (!pcupsGetNamedDest
) return num_options
;
8325 dest
= pcupsGetNamedDest( NULL
, printer
, NULL
);
8326 if (!dest
) return num_options
;
8328 for (i
= 0; i
< dest
->num_options
; i
++)
8330 if (!pcupsGetOption( dest
->options
[i
].name
, num_options
, *options
))
8331 num_options
= pcupsAddOption( dest
->options
[i
].name
, dest
->options
[i
].value
,
8332 num_options
, options
);
8335 pcupsFreeDests( 1, dest
);
8340 /*****************************************************************************
8343 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8345 #ifdef SONAME_LIBCUPS
8348 char *unixname
, *queue
, *unix_doc_title
;
8351 int num_options
= 0, i
;
8352 cups_option_t
*options
= NULL
;
8354 if(!(unixname
= wine_get_unix_file_name(filename
)))
8357 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8358 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8359 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8361 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8362 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8363 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8365 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8366 num_options
= get_cups_default_options( queue
, num_options
, &options
);
8368 TRACE( "printing via cups with options:\n" );
8369 for (i
= 0; i
< num_options
; i
++)
8370 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8372 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8373 if (ret
== 0 && pcupsLastErrorString
)
8374 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8376 pcupsFreeOptions( num_options
, options
);
8378 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8379 HeapFree(GetProcessHeap(), 0, queue
);
8380 HeapFree(GetProcessHeap(), 0, unixname
);
8386 return schedule_lpr(printer_name
, filename
);
8390 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8397 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8401 if(HIWORD(wparam
) == BN_CLICKED
)
8403 if(LOWORD(wparam
) == IDOK
)
8406 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8409 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8410 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8412 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8414 WCHAR caption
[200], message
[200];
8417 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
8418 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, ARRAY_SIZE(message
));
8419 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8420 if(mb_ret
== IDCANCEL
)
8422 HeapFree(GetProcessHeap(), 0, filename
);
8426 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8427 if(hf
== INVALID_HANDLE_VALUE
)
8429 WCHAR caption
[200], message
[200];
8431 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, ARRAY_SIZE(caption
));
8432 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, ARRAY_SIZE(message
));
8433 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8434 HeapFree(GetProcessHeap(), 0, filename
);
8438 DeleteFileW(filename
);
8439 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8441 EndDialog(hwnd
, IDOK
);
8444 if(LOWORD(wparam
) == IDCANCEL
)
8446 EndDialog(hwnd
, IDCANCEL
);
8455 /*****************************************************************************
8458 static BOOL
get_filename(LPWSTR
*filename
)
8460 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8461 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8464 /*****************************************************************************
8467 static BOOL
schedule_file(LPCWSTR filename
)
8469 LPWSTR output
= NULL
;
8471 if(get_filename(&output
))
8474 TRACE("copy to %s\n", debugstr_w(output
));
8475 r
= CopyFileW(filename
, output
, FALSE
);
8476 HeapFree(GetProcessHeap(), 0, output
);
8482 /*****************************************************************************
8485 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8487 int in_fd
, out_fd
, no_read
;
8490 char *unixname
, *outputA
;
8493 if(!(unixname
= wine_get_unix_file_name(filename
)))
8496 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8497 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8498 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8500 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8501 in_fd
= open(unixname
, O_RDONLY
);
8502 if(out_fd
== -1 || in_fd
== -1)
8505 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8506 write(out_fd
, buf
, no_read
);
8510 if(in_fd
!= -1) close(in_fd
);
8511 if(out_fd
!= -1) close(out_fd
);
8512 HeapFree(GetProcessHeap(), 0, outputA
);
8513 HeapFree(GetProcessHeap(), 0, unixname
);
8517 /*****************************************************************************
8518 * ScheduleJob [WINSPOOL.@]
8521 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8523 opened_printer_t
*printer
;
8525 struct list
*cursor
, *cursor2
;
8527 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8528 EnterCriticalSection(&printer_handles_cs
);
8529 printer
= get_opened_printer(hPrinter
);
8533 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8535 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8538 if(job
->job_id
!= dwJobID
) continue;
8540 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8541 if(hf
!= INVALID_HANDLE_VALUE
)
8543 PRINTER_INFO_5W
*pi5
= NULL
;
8544 LPWSTR portname
= job
->portname
;
8548 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8549 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8553 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8554 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8555 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8556 portname
= pi5
->pPortName
;
8558 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8559 debugstr_w(portname
));
8563 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8564 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8566 DWORD type
, count
= sizeof(output
);
8567 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8570 if(output
[0] == '|')
8572 ret
= schedule_pipe(output
+ 1, job
->filename
);
8576 ret
= schedule_unixfile(output
, job
->filename
);
8578 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8580 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8582 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8584 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8586 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8588 ret
= schedule_file(job
->filename
);
8590 else if(isalpha(portname
[0]) && portname
[1] == ':')
8592 TRACE("copying to %s\n", debugstr_w(portname
));
8593 ret
= CopyFileW(job
->filename
, portname
, FALSE
);
8597 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8599 HeapFree(GetProcessHeap(), 0, pi5
);
8601 DeleteFileW(job
->filename
);
8603 list_remove(cursor
);
8604 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8605 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8606 HeapFree(GetProcessHeap(), 0, job
->portname
);
8607 HeapFree(GetProcessHeap(), 0, job
->filename
);
8608 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8609 HeapFree(GetProcessHeap(), 0, job
);
8613 LeaveCriticalSection(&printer_handles_cs
);
8617 /*****************************************************************************
8618 * StartDocDlgA [WINSPOOL.@]
8620 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8622 UNICODE_STRING usBuffer
;
8623 DOCINFOW docW
= { 0 };
8625 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8628 docW
.cbSize
= sizeof(docW
);
8629 if (doc
->lpszDocName
)
8631 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8632 if (!(docW
.lpszDocName
= docnameW
)) goto failed
;
8634 if (doc
->lpszOutput
)
8636 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8637 if (!(docW
.lpszOutput
= outputW
)) goto failed
;
8639 if (doc
->lpszDatatype
)
8641 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8642 if (!(docW
.lpszDatatype
= datatypeW
)) goto failed
;
8644 docW
.fwType
= doc
->fwType
;
8646 retW
= StartDocDlgW(hPrinter
, &docW
);
8650 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8651 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8652 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8653 HeapFree(GetProcessHeap(), 0, retW
);
8657 HeapFree(GetProcessHeap(), 0, datatypeW
);
8658 HeapFree(GetProcessHeap(), 0, outputW
);
8659 HeapFree(GetProcessHeap(), 0, docnameW
);
8664 /*****************************************************************************
8665 * StartDocDlgW [WINSPOOL.@]
8667 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8668 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8669 * port is "FILE:". Also returns the full path if passed a relative path.
8671 * The caller should free the returned string from the process heap.
8673 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8678 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8680 PRINTER_INFO_5W
*pi5
;
8681 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8682 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8684 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8685 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8686 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8688 HeapFree(GetProcessHeap(), 0, pi5
);
8691 HeapFree(GetProcessHeap(), 0, pi5
);
8694 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8698 if (get_filename(&name
))
8700 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8702 HeapFree(GetProcessHeap(), 0, name
);
8705 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8706 GetFullPathNameW(name
, len
, ret
, NULL
);
8707 HeapFree(GetProcessHeap(), 0, name
);
8712 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8715 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8716 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8718 attr
= GetFileAttributesW(ret
);
8719 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8721 HeapFree(GetProcessHeap(), 0, ret
);
8727 /*****************************************************************************
8728 * UploadPrinterDriverPackageA [WINSPOOL.@]
8730 HRESULT WINAPI
UploadPrinterDriverPackageA( LPCSTR server
, LPCSTR path
, LPCSTR env
,
8731 DWORD flags
, HWND hwnd
, LPSTR dst
, PULONG dstlen
)
8733 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server
), debugstr_a(path
), debugstr_a(env
),
8734 flags
, hwnd
, dst
, dstlen
);
8738 /*****************************************************************************
8739 * UploadPrinterDriverPackageW [WINSPOOL.@]
8741 HRESULT WINAPI
UploadPrinterDriverPackageW( LPCWSTR server
, LPCWSTR path
, LPCWSTR env
,
8742 DWORD flags
, HWND hwnd
, LPWSTR dst
, PULONG dstlen
)
8744 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server
), debugstr_w(path
), debugstr_w(env
),
8745 flags
, hwnd
, dst
, dstlen
);
8749 /*****************************************************************************
8750 * PerfOpen [WINSPOOL.@]
8752 DWORD WINAPI
PerfOpen(LPWSTR context
)
8754 FIXME("%s: stub\n", debugstr_w(context
));
8755 return ERROR_SUCCESS
;
8758 /*****************************************************************************
8759 * PerfClose [WINSPOOL.@]
8761 DWORD WINAPI
PerfClose(void)
8764 return ERROR_SUCCESS
;
8767 /*****************************************************************************
8768 * PerfCollect [WINSPOOL.@]
8770 DWORD WINAPI
PerfCollect(LPWSTR query
, LPVOID
*data
, LPDWORD size
, LPDWORD obj_count
)
8772 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query
), data
, size
, obj_count
);
8775 return ERROR_SUCCESS
;