4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
48 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
65 #include "ddk/winsplp.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
70 /* ############################### */
72 static CRITICAL_SECTION printer_handles_cs
;
73 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
75 0, 0, &printer_handles_cs
,
76 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
77 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
79 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
81 /* ############################### */
96 HANDLE backend_printer
;
107 WCHAR
*document_title
;
117 LPCWSTR versionregpath
;
118 LPCWSTR versionsubdir
;
121 /* ############################### */
123 static opened_printer_t
**printer_handles
;
124 static UINT nb_printer_handles
;
125 static LONG next_job_id
= 1;
127 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
128 WORD fwCapability
, LPSTR lpszOutput
,
130 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
131 LPSTR lpszDevice
, LPSTR lpszPort
,
132 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
135 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'c','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
140 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
142 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
143 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
144 'C','o','n','t','r','o','l','\\',
145 'P','r','i','n','t','\\',
146 'P','r','i','n','t','e','r','s',0};
148 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
150 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'W','i','n','d','o','w','s',0};
156 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'W','i','n','d','o','w','s',' ','N','T','\\',
159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
160 'D','e','v','i','c','e','s',0};
162 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
163 'M','i','c','r','o','s','o','f','t','\\',
164 'W','i','n','d','o','w','s',' ','N','T','\\',
165 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
166 'P','o','r','t','s',0};
168 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
169 'M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s',' ','N','T','\\',
171 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'P','r','i','n','t','e','r','P','o','r','t','s',0};
174 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
175 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
176 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
177 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
178 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
179 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
180 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
181 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
182 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
183 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
184 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
186 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
188 static const WCHAR AttributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0};
189 static const WCHAR backslashW
[] = {'\\',0};
190 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
191 'i','o','n',' ','F','i','l','e',0};
192 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
193 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
194 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
195 static const WCHAR Default_PriorityW
[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
196 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
197 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
198 static const WCHAR dnsTimeoutW
[] = {'d','n','s','T','i','m','e','o','u','t',0};
199 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
200 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
201 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
202 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
203 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
204 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
205 static const WCHAR NameW
[] = {'N','a','m','e',0};
206 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
207 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
208 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
209 static const WCHAR PortW
[] = {'P','o','r','t',0};
210 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
211 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
212 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
213 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
214 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
215 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
216 static const WCHAR PriorityW
[] = {'P','r','i','o','r','i','t','y',0};
217 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
218 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
219 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
220 static const WCHAR StartTimeW
[] = {'S','t','a','r','t','T','i','m','e',0};
221 static const WCHAR StatusW
[] = {'S','t','a','t','u','s',0};
222 static const WCHAR txTimeoutW
[] = {'t','x','T','i','m','e','o','u','t',0};
223 static const WCHAR UntilTimeW
[] = {'U','n','t','i','l','T','i','m','e',0};
224 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
225 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
226 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
227 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
228 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
229 static WCHAR rawW
[] = {'R','A','W',0};
230 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
231 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
232 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
233 static const WCHAR commaW
[] = {',',0};
234 static WCHAR emptyStringW
[] = {0};
236 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
238 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
239 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
240 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
242 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
243 'D','o','c','u','m','e','n','t',0};
245 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
246 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
247 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
248 0, sizeof(DRIVER_INFO_8W
)};
251 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
252 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
253 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
254 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
255 sizeof(PRINTER_INFO_9W
)};
257 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
258 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
259 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
261 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
263 /******************************************************************
264 * validate the user-supplied printing-environment [internal]
267 * env [I] PTR to Environment-String or NULL
271 * Success: PTR to printenv_t
274 * An empty string is handled the same way as NULL.
275 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
279 static const printenv_t
* validate_envW(LPCWSTR env
)
281 const printenv_t
*result
= NULL
;
284 TRACE("testing %s\n", debugstr_w(env
));
287 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
289 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
291 result
= all_printenv
[i
];
296 if (result
== NULL
) {
297 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
298 SetLastError(ERROR_INVALID_ENVIRONMENT
);
300 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
304 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
306 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
312 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
313 if passed a NULL string. This returns NULLs to the result.
315 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
319 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
320 return usBufferPtr
->Buffer
;
322 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
326 static LPWSTR
strdupW(LPCWSTR p
)
332 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
333 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
338 static LPSTR
strdupWtoA( LPCWSTR str
)
343 if (!str
) return NULL
;
344 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
345 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
346 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
350 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
354 if (!dm
) return NULL
;
355 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
356 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
360 /***********************************************************
362 * Creates an ansi copy of supplied devmode
364 static DEVMODEA
*DEVMODEdupWtoA( const DEVMODEW
*dmW
)
369 if (!dmW
) return NULL
;
370 size
= dmW
->dmSize
- CCHDEVICENAME
-
371 ((dmW
->dmSize
> FIELD_OFFSET( DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
373 dmA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
374 if (!dmA
) return NULL
;
376 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmDeviceName
, -1,
377 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
379 if (FIELD_OFFSET( DEVMODEW
, dmFormName
) >= dmW
->dmSize
)
381 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
382 dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
386 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
387 FIELD_OFFSET( DEVMODEW
, dmFormName
) - FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
388 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmFormName
, -1,
389 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
391 memcpy( &dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmLogPixels
) );
395 memcpy( (char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
400 /******************************************************************
401 * verify, that the filename is a local file
404 static inline BOOL
is_local_file(LPWSTR name
)
406 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
409 /* ################################ */
411 static int multi_sz_lenA(const char *str
)
413 const char *ptr
= str
;
417 ptr
+= lstrlenA(ptr
) + 1;
420 return ptr
- str
+ 1;
423 /*****************************************************************************
426 * Return DWORD associated with name from hkey.
428 static DWORD
get_dword_from_reg( HKEY hkey
, const WCHAR
*name
)
430 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
433 ret
= RegQueryValueExW( hkey
, name
, 0, &type
, (LPBYTE
)&value
, &sz
);
435 if (ret
!= ERROR_SUCCESS
)
437 WARN( "Got ret = %d on name %s\n", ret
, debugstr_w(name
) );
440 if (type
!= REG_DWORD
)
442 ERR( "Got type %d\n", type
);
448 static inline DWORD
set_reg_DWORD( HKEY hkey
, const WCHAR
*keyname
, const DWORD value
)
450 return RegSetValueExW( hkey
, keyname
, 0, REG_DWORD
, (const BYTE
*)&value
, sizeof(value
) );
453 /******************************************************************
455 * Get the pointer to the opened printer referred by the handle
457 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
459 UINT_PTR idx
= (UINT_PTR
)hprn
;
460 opened_printer_t
*ret
= NULL
;
462 EnterCriticalSection(&printer_handles_cs
);
464 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
465 ret
= printer_handles
[idx
- 1];
467 LeaveCriticalSection(&printer_handles_cs
);
471 /******************************************************************
472 * get_opened_printer_name
473 * Get the pointer to the opened printer name referred by the handle
475 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
477 opened_printer_t
*printer
= get_opened_printer(hprn
);
478 if(!printer
) return NULL
;
479 return printer
->name
;
482 static DWORD
open_printer_reg_key( const WCHAR
*name
, HKEY
*key
)
488 err
= RegCreateKeyW( HKEY_LOCAL_MACHINE
, PrintersW
, &printers
);
491 err
= RegOpenKeyW( printers
, name
, key
);
492 if (err
) err
= ERROR_INVALID_PRINTER_NAME
;
493 RegCloseKey( printers
);
497 /******************************************************************
498 * WINSPOOL_GetOpenedPrinterRegKey
501 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
503 LPCWSTR name
= get_opened_printer_name(hPrinter
);
505 if(!name
) return ERROR_INVALID_HANDLE
;
506 return open_printer_reg_key( name
, phkey
);
510 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
513 /* If forcing, or no profile string entry for device yet, set the entry
515 * The always change entry if not WINEPS yet is discussable.
518 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
520 !strstr(qbuf
,"WINEPS.DRV")
522 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
525 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
526 WriteProfileStringA("windows","device",buf
);
527 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
528 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
531 HeapFree(GetProcessHeap(),0,buf
);
535 static BOOL
add_printer_driver(const WCHAR
*name
, WCHAR
*ppd
)
539 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
541 di3
.pName
= (WCHAR
*)name
;
542 di3
.pEnvironment
= envname_x86W
;
543 di3
.pDriverPath
= driver_nt
;
545 di3
.pConfigFile
= driver_nt
;
546 di3
.pDefaultDataType
= rawW
;
548 if (AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
) ||
549 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
552 di3
.pEnvironment
= envname_win40W
;
553 di3
.pDriverPath
= driver_9x
;
554 di3
.pConfigFile
= driver_9x
;
555 if (AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
) ||
556 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
561 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3
.pDriverPath
), debugstr_w(di3
.pEnvironment
));
565 static inline char *expand_env_string( char *str
, DWORD type
)
567 if (type
== REG_EXPAND_SZ
)
570 DWORD needed
= ExpandEnvironmentStringsA( str
, NULL
, 0 );
571 tmp
= HeapAlloc( GetProcessHeap(), 0, needed
);
574 ExpandEnvironmentStringsA( str
, tmp
, needed
);
575 HeapFree( GetProcessHeap(), 0, str
);
582 static char *get_fallback_ppd_name( const char *printer_name
)
584 static const WCHAR ppds_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
585 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
589 const char *data_dir
, *filename
;
591 if (RegOpenKeyW( HKEY_CURRENT_USER
, ppds_key
, &hkey
) == ERROR_SUCCESS
)
593 const char *value_name
= NULL
;
595 if (RegQueryValueExA( hkey
, printer_name
, 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
596 value_name
= printer_name
;
597 else if (RegQueryValueExA( hkey
, "generic", 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
598 value_name
= "generic";
602 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
603 if (!ret
) return NULL
;
604 RegQueryValueExA( hkey
, value_name
, 0, &type
, (BYTE
*)ret
, &needed
);
607 if (ret
) return expand_env_string( ret
, type
);
610 if ((data_dir
= wine_get_data_dir())) filename
= "/generic.ppd";
611 else if ((data_dir
= wine_get_build_dir())) filename
= "/dlls/wineps.drv/generic.ppd";
614 ERR( "Error getting PPD file name for printer '%s'\n", debugstr_a(printer_name
) );
617 ret
= HeapAlloc( GetProcessHeap(), 0, strlen(data_dir
) + strlen(filename
) + 1 );
620 strcpy( ret
, data_dir
);
621 strcat( ret
, filename
);
627 static BOOL
copy_file( const char *src
, const char *dst
)
629 int fds
[2] = {-1, -1}, num
;
633 fds
[0] = open( src
, O_RDONLY
);
634 fds
[1] = open( dst
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666 );
635 if (fds
[0] == -1 || fds
[1] == -1) goto fail
;
637 while ((num
= read( fds
[0], buf
, sizeof(buf
) )) != 0)
639 if (num
== -1) goto fail
;
640 if (write( fds
[1], buf
, num
) != num
) goto fail
;
645 if (fds
[1] != -1) close( fds
[1] );
646 if (fds
[0] != -1) close( fds
[0] );
650 static BOOL
get_fallback_ppd( const char *printer_name
, const WCHAR
*ppd
)
652 char *src
= get_fallback_ppd_name( printer_name
);
653 char *dst
= wine_get_unix_file_name( ppd
);
656 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name
), debugstr_w(ppd
), debugstr_a(src
) );
658 if (!src
|| !dst
) goto fail
;
660 if (symlink( src
, dst
) == -1)
661 if (errno
!= ENOSYS
|| !copy_file( src
, dst
))
666 HeapFree( GetProcessHeap(), 0, dst
);
667 HeapFree( GetProcessHeap(), 0, src
);
671 static WCHAR
*get_ppd_filename( const WCHAR
*dir
, const WCHAR
*file_name
)
673 static const WCHAR dot_ppd
[] = {'.','p','p','d',0};
674 int len
= (strlenW( dir
) + strlenW( file_name
)) * sizeof(WCHAR
) + sizeof(dot_ppd
);
675 WCHAR
*ppd
= HeapAlloc( GetProcessHeap(), 0, len
);
677 if (!ppd
) return NULL
;
679 strcatW( ppd
, file_name
);
680 strcatW( ppd
, dot_ppd
);
685 static WCHAR
*get_ppd_dir( void )
687 static const WCHAR wine_ppds
[] = {'w','i','n','e','_','p','p','d','s','\\',0};
689 WCHAR
*dir
, tmp_path
[MAX_PATH
];
692 len
= GetTempPathW( sizeof(tmp_path
) / sizeof(tmp_path
[0]), tmp_path
);
693 if (!len
) return NULL
;
694 dir
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) + sizeof(wine_ppds
) ) ;
695 if (!dir
) return NULL
;
697 memcpy( dir
, tmp_path
, len
* sizeof(WCHAR
) );
698 memcpy( dir
+ len
, wine_ppds
, sizeof(wine_ppds
) );
699 res
= CreateDirectoryW( dir
, NULL
);
700 if (!res
&& GetLastError() != ERROR_ALREADY_EXISTS
)
702 HeapFree( GetProcessHeap(), 0, dir
);
705 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir
) );
709 static void unlink_ppd( const WCHAR
*ppd
)
711 char *unix_name
= wine_get_unix_file_name( ppd
);
713 HeapFree( GetProcessHeap(), 0, unix_name
);
716 #ifdef SONAME_LIBCUPS
718 static void *cupshandle
;
721 DO_FUNC(cupsFreeDests); \
722 DO_FUNC(cupsFreeOptions); \
723 DO_FUNC(cupsGetDests); \
724 DO_FUNC(cupsGetOption); \
725 DO_FUNC(cupsGetPPD); \
726 DO_FUNC(cupsParseOptions); \
727 DO_FUNC(cupsPrintFile);
728 #define CUPS_OPT_FUNCS \
729 DO_FUNC(cupsGetPPD3);
731 #define DO_FUNC(f) static typeof(f) *p##f
734 static http_status_t (*pcupsGetPPD3
)(http_t
*,const char *, time_t *, char *, size_t);
736 static http_status_t
cupsGetPPD3_wrapper( http_t
*http
, const char *name
,
737 time_t *modtime
, char *buffer
,
742 if (pcupsGetPPD3
) return pcupsGetPPD3( http
, name
, modtime
, buffer
, bufsize
);
744 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
747 ppd
= pcupsGetPPD( name
);
749 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd
) );
751 if (!ppd
) return HTTP_NOT_FOUND
;
753 if (rename( ppd
, buffer
) == -1)
755 BOOL res
= copy_file( ppd
, buffer
);
757 if (!res
) return HTTP_NOT_FOUND
;
762 static BOOL
get_cups_ppd( const char *printer_name
, const WCHAR
*ppd
)
765 http_status_t http_status
;
766 char *unix_name
= wine_get_unix_file_name( ppd
);
768 TRACE( "(%s, %s)\n", debugstr_a(printer_name
), debugstr_w(ppd
) );
770 if (!unix_name
) return FALSE
;
772 http_status
= cupsGetPPD3_wrapper( 0, printer_name
, &modtime
,
773 unix_name
, strlen( unix_name
) + 1 );
774 HeapFree( GetProcessHeap(), 0, unix_name
);
776 if (http_status
== HTTP_OK
) return TRUE
;
778 TRACE( "failed to get ppd for printer %s from cups, calling fallback\n", debugstr_a(printer_name
) );
779 return get_fallback_ppd( printer_name
, ppd
);
782 static WCHAR
*get_cups_option( const char *name
, int num_options
, cups_option_t
*options
)
788 value
= pcupsGetOption( name
, num_options
, options
);
789 if (!value
) return NULL
;
791 len
= MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, NULL
, 0 );
792 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
793 if (ret
) MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, ret
, len
);
798 static BOOL
CUPS_LoadPrinters(void)
801 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
804 WCHAR
*port
, *ppd_dir
= NULL
, *ppd
;
805 HKEY hkeyPrinter
, hkeyPrinters
;
807 WCHAR nameW
[MAX_PATH
];
808 HANDLE added_printer
;
810 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
812 TRACE("%s\n", loaderror
);
815 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
817 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
820 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 );
824 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
826 ERR("Can't create Printers key\n");
830 nrofdests
= pcupsGetDests(&dests
);
831 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
832 for (i
=0;i
<nrofdests
;i
++) {
833 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
835 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
836 lstrcpyW(port
, CUPS_Port
);
837 lstrcatW(port
, nameW
);
839 TRACE("Printer %d: %s\n", i
, debugstr_w(nameW
));
840 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
841 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
842 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
844 TRACE("Printer already exists\n");
845 /* overwrite old LPR:* port */
846 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
847 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
848 /* flag that the PPD file should be checked for an update */
849 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
850 RegCloseKey(hkeyPrinter
);
852 BOOL added_driver
= FALSE
;
854 if (!ppd_dir
) ppd_dir
= get_ppd_dir();
855 ppd
= get_ppd_filename( ppd_dir
, nameW
);
856 if (get_cups_ppd( dests
[i
].name
, ppd
))
858 added_driver
= add_printer_driver( nameW
, ppd
);
861 HeapFree( GetProcessHeap(), 0, ppd
);
862 if (!added_driver
) continue;
864 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
865 pi2
.pPrinterName
= nameW
;
866 pi2
.pDatatype
= rawW
;
867 pi2
.pPrintProcessor
= WinPrintW
;
868 pi2
.pDriverName
= nameW
;
869 pi2
.pComment
= get_cups_option( "printer-info", dests
[i
].num_options
, dests
[i
].options
);
870 pi2
.pLocation
= get_cups_option( "printer-location", dests
[i
].num_options
, dests
[i
].options
);
871 pi2
.pPortName
= port
;
872 pi2
.pParameters
= emptyStringW
;
873 pi2
.pShareName
= emptyStringW
;
874 pi2
.pSepFile
= emptyStringW
;
876 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
877 if (added_printer
) ClosePrinter( added_printer
);
878 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
879 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
881 HeapFree( GetProcessHeap(), 0, pi2
.pComment
);
882 HeapFree( GetProcessHeap(), 0, pi2
.pLocation
);
884 HeapFree( GetProcessHeap(), 0, port
);
887 if (dests
[i
].is_default
) {
888 SetDefaultPrinterW(nameW
);
895 RemoveDirectoryW( ppd_dir
);
896 HeapFree( GetProcessHeap(), 0, ppd_dir
);
899 if (hadprinter
&& !haddefault
) {
900 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
901 SetDefaultPrinterW(nameW
);
903 pcupsFreeDests(nrofdests
, dests
);
904 RegCloseKey(hkeyPrinters
);
910 static char *get_queue_name( HANDLE printer
, BOOL
*cups
)
912 WCHAR
*port
, *name
= NULL
;
913 DWORD err
, needed
, type
;
919 err
= WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
);
920 if (err
) return NULL
;
921 err
= RegQueryValueExW( key
, PortW
, 0, &type
, NULL
, &needed
);
923 port
= HeapAlloc( GetProcessHeap(), 0, needed
);
925 RegQueryValueExW( key
, PortW
, 0, &type
, (BYTE
*)port
, &needed
);
927 if (!strncmpW( port
, CUPS_Port
, sizeof(CUPS_Port
) / sizeof(WCHAR
) -1 ))
929 name
= port
+ sizeof(CUPS_Port
) / sizeof(WCHAR
) - 1;
932 else if (!strncmpW( port
, LPR_Port
, sizeof(LPR_Port
) / sizeof(WCHAR
) -1 ))
933 name
= port
+ sizeof(LPR_Port
) / sizeof(WCHAR
) - 1;
936 needed
= WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
937 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
938 if(ret
) WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, ret
, needed
, NULL
, NULL
);
940 HeapFree( GetProcessHeap(), 0, port
);
947 static BOOL
update_driver( HANDLE printer
)
950 const WCHAR
*name
= get_opened_printer_name( printer
);
951 WCHAR
*ppd_dir
, *ppd
;
954 if (!name
) return FALSE
;
955 queue_name
= get_queue_name( printer
, &is_cups
);
956 if (!queue_name
) return FALSE
;
958 ppd_dir
= get_ppd_dir();
959 ppd
= get_ppd_filename( ppd_dir
, name
);
961 #ifdef SONAME_LIBCUPS
963 ret
= get_cups_ppd( queue_name
, ppd
);
966 ret
= get_fallback_ppd( queue_name
, ppd
);
970 TRACE( "updating driver %s\n", debugstr_w( name
) );
971 ret
= add_printer_driver( name
, ppd
);
974 HeapFree( GetProcessHeap(), 0, ppd_dir
);
975 HeapFree( GetProcessHeap(), 0, ppd
);
976 HeapFree( GetProcessHeap(), 0, queue_name
);
978 /* call into the driver to update the devmode */
979 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
984 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
986 PRINTER_INFO_2A pinfo2a
;
989 char *e
,*s
,*name
,*prettyname
,*devname
;
990 BOOL ret
= FALSE
, set_default
= FALSE
;
991 char *port
= NULL
, *env_default
;
992 HKEY hkeyPrinter
, hkeyPrinters
= NULL
;
993 WCHAR devnameW
[MAX_PATH
], *ppd_dir
= NULL
, *ppd
;
994 HANDLE added_printer
;
996 while (isspace(*pent
)) pent
++;
997 r
= strchr(pent
,':');
1001 name_len
= strlen(pent
);
1002 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
1003 memcpy(name
, pent
, name_len
);
1004 name
[name_len
] = '\0';
1010 TRACE("name=%s entry=%s\n",name
, pent
);
1012 if(ispunct(*name
)) { /* a tc entry, not a real printer */
1013 TRACE("skipping tc entry\n");
1017 if(strstr(pent
,":server")) { /* server only version so skip */
1018 TRACE("skipping server entry\n");
1022 /* Determine whether this is a postscript printer. */
1025 env_default
= getenv("PRINTER");
1027 /* Get longest name, usually the one at the right for later display. */
1028 while((s
=strchr(prettyname
,'|'))) {
1031 while(isspace(*--e
)) *e
= '\0';
1032 TRACE("\t%s\n", debugstr_a(prettyname
));
1033 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1034 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
1037 e
= prettyname
+ strlen(prettyname
);
1038 while(isspace(*--e
)) *e
= '\0';
1039 TRACE("\t%s\n", debugstr_a(prettyname
));
1040 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1042 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1043 * if it is too long, we use it as comment below. */
1044 devname
= prettyname
;
1045 if (strlen(devname
)>=CCHDEVICENAME
-1)
1047 if (strlen(devname
)>=CCHDEVICENAME
-1) {
1052 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
1053 sprintf(port
,"LPR:%s",name
);
1055 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1057 ERR("Can't create Printers key\n");
1062 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
1064 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1065 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1066 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1068 TRACE("Printer already exists\n");
1069 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1070 /* flag that the PPD file should be checked for an update */
1071 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1072 RegCloseKey(hkeyPrinter
);
1074 static CHAR data_type
[] = "RAW",
1075 print_proc
[] = "WinPrint",
1076 comment
[] = "WINEPS Printer using LPR",
1077 params
[] = "<parameters?>",
1078 share_name
[] = "<share name?>",
1079 sep_file
[] = "<sep file?>";
1080 BOOL added_driver
= FALSE
;
1082 if (!ppd_dir
) ppd_dir
= get_ppd_dir();
1083 ppd
= get_ppd_filename( ppd_dir
, devnameW
);
1084 if (get_fallback_ppd( devname
, ppd
))
1086 added_driver
= add_printer_driver( devnameW
, ppd
);
1089 HeapFree( GetProcessHeap(), 0, ppd
);
1090 if (!added_driver
) goto end
;
1092 memset(&pinfo2a
,0,sizeof(pinfo2a
));
1093 pinfo2a
.pPrinterName
= devname
;
1094 pinfo2a
.pDatatype
= data_type
;
1095 pinfo2a
.pPrintProcessor
= print_proc
;
1096 pinfo2a
.pDriverName
= devname
;
1097 pinfo2a
.pComment
= comment
;
1098 pinfo2a
.pLocation
= prettyname
;
1099 pinfo2a
.pPortName
= port
;
1100 pinfo2a
.pParameters
= params
;
1101 pinfo2a
.pShareName
= share_name
;
1102 pinfo2a
.pSepFile
= sep_file
;
1104 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
1105 if (added_printer
) ClosePrinter( added_printer
);
1106 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1107 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
1110 if (isfirst
|| set_default
)
1111 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
1114 if (hkeyPrinters
) RegCloseKey( hkeyPrinters
);
1117 RemoveDirectoryW( ppd_dir
);
1118 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1120 HeapFree(GetProcessHeap(), 0, port
);
1121 HeapFree(GetProcessHeap(), 0, name
);
1126 PRINTCAP_LoadPrinters(void) {
1127 BOOL hadprinter
= FALSE
;
1131 BOOL had_bash
= FALSE
;
1133 f
= fopen("/etc/printcap","r");
1137 while(fgets(buf
,sizeof(buf
),f
)) {
1140 end
=strchr(buf
,'\n');
1144 while(isspace(*start
)) start
++;
1145 if(*start
== '#' || *start
== '\0')
1148 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
1149 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1150 HeapFree(GetProcessHeap(),0,pent
);
1154 if (end
&& *--end
== '\\') {
1161 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
1164 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
1170 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1171 HeapFree(GetProcessHeap(),0,pent
);
1177 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
1180 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
1181 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
1183 return ERROR_FILE_NOT_FOUND
;
1186 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
1188 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
1189 DWORD ret
= ERROR_FILE_NOT_FOUND
;
1191 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1192 and we support these drivers. NT writes DEVMODEW so somehow
1193 we'll need to distinguish between these when we support NT
1198 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
1199 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1200 HeapFree( GetProcessHeap(), 0, dmA
);
1206 /******************************************************************
1207 * get_servername_from_name (internal)
1209 * for an external server, a copy of the serverpart from the full name is returned
1212 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1216 WCHAR buffer
[MAX_PATH
];
1219 if (name
== NULL
) return NULL
;
1220 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1222 server
= strdupW(&name
[2]); /* skip over both backslash */
1223 if (server
== NULL
) return NULL
;
1225 /* strip '\' and the printername */
1226 ptr
= strchrW(server
, '\\');
1227 if (ptr
) ptr
[0] = '\0';
1229 TRACE("found %s\n", debugstr_w(server
));
1231 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1232 if (GetComputerNameW(buffer
, &len
)) {
1233 if (lstrcmpW(buffer
, server
) == 0) {
1234 /* The requested Servername is our computername */
1235 HeapFree(GetProcessHeap(), 0, server
);
1242 /******************************************************************
1243 * get_basename_from_name (internal)
1245 * skip over the serverpart from the full name
1248 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1250 if (name
== NULL
) return NULL
;
1251 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1252 /* skip over the servername and search for the following '\' */
1253 name
= strchrW(&name
[2], '\\');
1254 if ((name
) && (name
[1])) {
1255 /* found a separator ('\') followed by a name:
1256 skip over the separator and return the rest */
1261 /* no basename present (we found only a servername) */
1268 static void free_printer_entry( opened_printer_t
*printer
)
1270 /* the queue is shared, so don't free that here */
1271 HeapFree( GetProcessHeap(), 0, printer
->printername
);
1272 HeapFree( GetProcessHeap(), 0, printer
->name
);
1273 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
1274 HeapFree( GetProcessHeap(), 0, printer
);
1277 /******************************************************************
1278 * get_opened_printer_entry
1279 * Get the first place empty in the opened printer table
1282 * - pDefault is ignored
1284 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1286 UINT_PTR handle
= nb_printer_handles
, i
;
1287 jobqueue_t
*queue
= NULL
;
1288 opened_printer_t
*printer
= NULL
;
1290 LPCWSTR printername
;
1292 if ((backend
== NULL
) && !load_backend()) return NULL
;
1294 servername
= get_servername_from_name(name
);
1296 FIXME("server %s not supported\n", debugstr_w(servername
));
1297 HeapFree(GetProcessHeap(), 0, servername
);
1298 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1302 printername
= get_basename_from_name(name
);
1303 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1305 /* an empty printername is invalid */
1306 if (printername
&& (!printername
[0])) {
1307 SetLastError(ERROR_INVALID_PARAMETER
);
1311 EnterCriticalSection(&printer_handles_cs
);
1313 for (i
= 0; i
< nb_printer_handles
; i
++)
1315 if (!printer_handles
[i
])
1317 if(handle
== nb_printer_handles
)
1322 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1323 queue
= printer_handles
[i
]->queue
;
1327 if (handle
>= nb_printer_handles
)
1329 opened_printer_t
**new_array
;
1330 if (printer_handles
)
1331 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1332 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1334 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1335 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1342 printer_handles
= new_array
;
1343 nb_printer_handles
+= 16;
1346 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1352 /* get a printer handle from the backend */
1353 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1358 /* clone the base name. This is NULL for the printserver */
1359 printer
->printername
= strdupW(printername
);
1361 /* clone the full name */
1362 printer
->name
= strdupW(name
);
1363 if (name
&& (!printer
->name
)) {
1368 if (pDefault
&& pDefault
->pDevMode
)
1369 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
1372 printer
->queue
= queue
;
1375 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1376 if (!printer
->queue
) {
1380 list_init(&printer
->queue
->jobs
);
1381 printer
->queue
->ref
= 0;
1383 InterlockedIncrement(&printer
->queue
->ref
);
1385 printer_handles
[handle
] = printer
;
1388 LeaveCriticalSection(&printer_handles_cs
);
1389 if (!handle
&& printer
) {
1390 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1391 free_printer_entry( printer
);
1394 return (HANDLE
)handle
;
1397 static void old_printer_check( BOOL delete_phase
)
1399 PRINTER_INFO_5W
* pi
;
1400 DWORD needed
, type
, num
, delete, i
, size
;
1401 const DWORD one
= 1;
1405 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1406 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1408 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1409 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1410 for (i
= 0; i
< num
; i
++)
1412 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1413 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1416 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1420 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1426 size
= sizeof( delete );
1427 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1431 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1432 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1434 DeletePrinter( hprn
);
1435 ClosePrinter( hprn
);
1437 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1441 HeapFree(GetProcessHeap(), 0, pi
);
1444 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1445 'M','U','T','E','X','_','_','\0'};
1446 static HANDLE init_mutex
;
1448 void WINSPOOL_LoadSystemPrinters(void)
1450 HKEY hkey
, hkeyPrinters
;
1451 DWORD needed
, num
, i
;
1452 WCHAR PrinterName
[256];
1455 /* FIXME: The init code should be moved to spoolsv.exe */
1456 init_mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1459 ERR( "Failed to create mutex\n" );
1462 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1464 WaitForSingleObject( init_mutex
, INFINITE
);
1465 ReleaseMutex( init_mutex
);
1466 TRACE( "Init already done\n" );
1470 /* This ensures that all printer entries have a valid Name value. If causes
1471 problems later if they don't. If one is found to be missed we create one
1472 and set it equal to the name of the key */
1473 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1474 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1475 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1476 for(i
= 0; i
< num
; i
++) {
1477 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1478 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1479 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1480 set_reg_szW(hkey
, NameW
, PrinterName
);
1487 RegCloseKey(hkeyPrinters
);
1490 old_printer_check( FALSE
);
1492 #ifdef SONAME_LIBCUPS
1493 done
= CUPS_LoadPrinters();
1496 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1497 PRINTCAP_LoadPrinters();
1499 old_printer_check( TRUE
);
1501 ReleaseMutex( init_mutex
);
1505 /******************************************************************
1508 * Get the pointer to the specified job.
1509 * Should hold the printer_handles_cs before calling.
1511 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1513 opened_printer_t
*printer
= get_opened_printer(hprn
);
1516 if(!printer
) return NULL
;
1517 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1519 if(job
->job_id
== JobId
)
1525 /***********************************************************
1528 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1531 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1534 Formname
= (dmA
->dmSize
> off_formname
);
1535 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1536 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1537 dmW
->dmDeviceName
, CCHDEVICENAME
);
1539 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1540 dmA
->dmSize
- CCHDEVICENAME
);
1542 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1543 off_formname
- CCHDEVICENAME
);
1544 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1545 dmW
->dmFormName
, CCHFORMNAME
);
1546 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1547 (off_formname
+ CCHFORMNAME
));
1550 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1551 dmA
->dmDriverExtra
);
1555 /******************************************************************
1556 * convert_printerinfo_W_to_A [internal]
1559 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1560 DWORD level
, DWORD outlen
, DWORD numentries
)
1566 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1568 len
= pi_sizeof
[level
] * numentries
;
1569 ptr
= (LPSTR
) out
+ len
;
1572 /* copy the numbers of all PRINTER_INFO_* first */
1573 memcpy(out
, pPrintersW
, len
);
1575 while (id
< numentries
) {
1579 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1580 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1582 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1583 if (piW
->pDescription
) {
1584 piA
->pDescription
= ptr
;
1585 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1586 ptr
, outlen
, NULL
, NULL
);
1592 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1593 ptr
, outlen
, NULL
, NULL
);
1597 if (piW
->pComment
) {
1598 piA
->pComment
= ptr
;
1599 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1600 ptr
, outlen
, NULL
, NULL
);
1609 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1610 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1613 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1614 if (piW
->pServerName
) {
1615 piA
->pServerName
= ptr
;
1616 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1617 ptr
, outlen
, NULL
, NULL
);
1621 if (piW
->pPrinterName
) {
1622 piA
->pPrinterName
= ptr
;
1623 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1624 ptr
, outlen
, NULL
, NULL
);
1628 if (piW
->pShareName
) {
1629 piA
->pShareName
= ptr
;
1630 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1631 ptr
, outlen
, NULL
, NULL
);
1635 if (piW
->pPortName
) {
1636 piA
->pPortName
= ptr
;
1637 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1638 ptr
, outlen
, NULL
, NULL
);
1642 if (piW
->pDriverName
) {
1643 piA
->pDriverName
= ptr
;
1644 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1645 ptr
, outlen
, NULL
, NULL
);
1649 if (piW
->pComment
) {
1650 piA
->pComment
= ptr
;
1651 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1652 ptr
, outlen
, NULL
, NULL
);
1656 if (piW
->pLocation
) {
1657 piA
->pLocation
= ptr
;
1658 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1659 ptr
, outlen
, NULL
, NULL
);
1664 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1666 /* align DEVMODEA to a DWORD boundary */
1667 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1671 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1672 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1673 memcpy(ptr
, dmA
, len
);
1674 HeapFree(GetProcessHeap(), 0, dmA
);
1680 if (piW
->pSepFile
) {
1681 piA
->pSepFile
= ptr
;
1682 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1683 ptr
, outlen
, NULL
, NULL
);
1687 if (piW
->pPrintProcessor
) {
1688 piA
->pPrintProcessor
= ptr
;
1689 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1690 ptr
, outlen
, NULL
, NULL
);
1694 if (piW
->pDatatype
) {
1695 piA
->pDatatype
= ptr
;
1696 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1697 ptr
, outlen
, NULL
, NULL
);
1701 if (piW
->pParameters
) {
1702 piA
->pParameters
= ptr
;
1703 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1704 ptr
, outlen
, NULL
, NULL
);
1708 if (piW
->pSecurityDescriptor
) {
1709 piA
->pSecurityDescriptor
= NULL
;
1710 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1717 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1718 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1720 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1722 if (piW
->pPrinterName
) {
1723 piA
->pPrinterName
= ptr
;
1724 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1725 ptr
, outlen
, NULL
, NULL
);
1729 if (piW
->pServerName
) {
1730 piA
->pServerName
= ptr
;
1731 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1732 ptr
, outlen
, NULL
, NULL
);
1741 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1742 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1744 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1746 if (piW
->pPrinterName
) {
1747 piA
->pPrinterName
= ptr
;
1748 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1749 ptr
, outlen
, NULL
, NULL
);
1753 if (piW
->pPortName
) {
1754 piA
->pPortName
= ptr
;
1755 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1756 ptr
, outlen
, NULL
, NULL
);
1763 case 6: /* 6A and 6W are the same structure */
1768 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1769 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1771 TRACE("(%u) #%u\n", level
, id
);
1772 if (piW
->pszObjectGUID
) {
1773 piA
->pszObjectGUID
= ptr
;
1774 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1775 ptr
, outlen
, NULL
, NULL
);
1785 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1786 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1789 TRACE("(%u) #%u\n", level
, id
);
1790 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1792 /* align DEVMODEA to a DWORD boundary */
1793 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1797 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1798 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1799 memcpy(ptr
, dmA
, len
);
1800 HeapFree(GetProcessHeap(), 0, dmA
);
1810 FIXME("for level %u\n", level
);
1812 pPrintersW
+= pi_sizeof
[level
];
1813 out
+= pi_sizeof
[level
];
1818 /******************************************************************
1819 * convert_driverinfo_W_to_A [internal]
1822 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1823 DWORD level
, DWORD outlen
, DWORD numentries
)
1829 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1831 len
= di_sizeof
[level
] * numentries
;
1832 ptr
= (LPSTR
) out
+ len
;
1835 /* copy the numbers of all PRINTER_INFO_* first */
1836 memcpy(out
, pDriversW
, len
);
1838 #define COPY_STRING(fld) \
1841 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1842 ptr += len; outlen -= len;\
1844 #define COPY_MULTIZ_STRING(fld) \
1845 { LPWSTR p = diW->fld; if (p){ \
1848 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1849 ptr += len; outlen -= len; p += len;\
1851 while(len > 1 && outlen > 0); \
1854 while (id
< numentries
)
1860 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1861 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1863 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1870 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1871 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1873 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1876 COPY_STRING(pEnvironment
);
1877 COPY_STRING(pDriverPath
);
1878 COPY_STRING(pDataFile
);
1879 COPY_STRING(pConfigFile
);
1884 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1885 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1887 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1890 COPY_STRING(pEnvironment
);
1891 COPY_STRING(pDriverPath
);
1892 COPY_STRING(pDataFile
);
1893 COPY_STRING(pConfigFile
);
1894 COPY_STRING(pHelpFile
);
1895 COPY_MULTIZ_STRING(pDependentFiles
);
1896 COPY_STRING(pMonitorName
);
1897 COPY_STRING(pDefaultDataType
);
1902 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
1903 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
1905 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1908 COPY_STRING(pEnvironment
);
1909 COPY_STRING(pDriverPath
);
1910 COPY_STRING(pDataFile
);
1911 COPY_STRING(pConfigFile
);
1912 COPY_STRING(pHelpFile
);
1913 COPY_MULTIZ_STRING(pDependentFiles
);
1914 COPY_STRING(pMonitorName
);
1915 COPY_STRING(pDefaultDataType
);
1916 COPY_MULTIZ_STRING(pszzPreviousNames
);
1921 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
1922 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
1924 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1927 COPY_STRING(pEnvironment
);
1928 COPY_STRING(pDriverPath
);
1929 COPY_STRING(pDataFile
);
1930 COPY_STRING(pConfigFile
);
1935 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
1936 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
1938 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1941 COPY_STRING(pEnvironment
);
1942 COPY_STRING(pDriverPath
);
1943 COPY_STRING(pDataFile
);
1944 COPY_STRING(pConfigFile
);
1945 COPY_STRING(pHelpFile
);
1946 COPY_MULTIZ_STRING(pDependentFiles
);
1947 COPY_STRING(pMonitorName
);
1948 COPY_STRING(pDefaultDataType
);
1949 COPY_MULTIZ_STRING(pszzPreviousNames
);
1950 COPY_STRING(pszMfgName
);
1951 COPY_STRING(pszOEMUrl
);
1952 COPY_STRING(pszHardwareID
);
1953 COPY_STRING(pszProvider
);
1958 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
1959 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
1961 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1964 COPY_STRING(pEnvironment
);
1965 COPY_STRING(pDriverPath
);
1966 COPY_STRING(pDataFile
);
1967 COPY_STRING(pConfigFile
);
1968 COPY_STRING(pHelpFile
);
1969 COPY_MULTIZ_STRING(pDependentFiles
);
1970 COPY_STRING(pMonitorName
);
1971 COPY_STRING(pDefaultDataType
);
1972 COPY_MULTIZ_STRING(pszzPreviousNames
);
1973 COPY_STRING(pszMfgName
);
1974 COPY_STRING(pszOEMUrl
);
1975 COPY_STRING(pszHardwareID
);
1976 COPY_STRING(pszProvider
);
1977 COPY_STRING(pszPrintProcessor
);
1978 COPY_STRING(pszVendorSetup
);
1979 COPY_MULTIZ_STRING(pszzColorProfiles
);
1980 COPY_STRING(pszInfPath
);
1981 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
1987 FIXME("for level %u\n", level
);
1990 pDriversW
+= di_sizeof
[level
];
1991 out
+= di_sizeof
[level
];
1996 #undef COPY_MULTIZ_STRING
2000 /***********************************************************
2003 static void *printer_info_AtoW( const void *data
, DWORD level
)
2006 UNICODE_STRING usBuffer
;
2008 if (!data
) return NULL
;
2010 if (level
< 1 || level
> 9) return NULL
;
2012 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
2013 if (!ret
) return NULL
;
2015 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
2021 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
2022 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
2024 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
2025 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
2026 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
2027 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
2028 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
2029 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
2030 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
2031 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2032 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
2033 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
2034 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
2035 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
2042 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
2043 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
2045 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2050 FIXME( "Unhandled level %d\n", level
);
2051 HeapFree( GetProcessHeap(), 0, ret
);
2058 /***********************************************************
2061 static void free_printer_info( void *data
, DWORD level
)
2069 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
2071 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
2072 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
2073 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
2074 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
2075 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
2076 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
2077 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
2078 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2079 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
2080 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
2081 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
2082 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
2089 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
2091 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2096 FIXME( "Unhandled level %d\n", level
);
2099 HeapFree( GetProcessHeap(), 0, data
);
2103 /******************************************************************
2104 * DeviceCapabilities [WINSPOOL.@]
2105 * DeviceCapabilitiesA [WINSPOOL.@]
2108 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
2109 LPSTR pOutput
, LPDEVMODEA lpdm
)
2113 if (!GDI_CallDeviceCapabilities16
)
2115 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2117 if (!GDI_CallDeviceCapabilities16
) return -1;
2119 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
2121 /* If DC_PAPERSIZE map POINT16s to POINTs */
2122 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
2123 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
2124 POINT
*pt
= (POINT
*)pOutput
;
2126 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
2127 for(i
= 0; i
< ret
; i
++, pt
++)
2132 HeapFree( GetProcessHeap(), 0, tmp
);
2138 /*****************************************************************************
2139 * DeviceCapabilitiesW [WINSPOOL.@]
2141 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2144 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2145 WORD fwCapability
, LPWSTR pOutput
,
2146 const DEVMODEW
*pDevMode
)
2148 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
2149 LPSTR pDeviceA
= strdupWtoA(pDevice
);
2150 LPSTR pPortA
= strdupWtoA(pPort
);
2153 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
2154 fwCapability
== DC_FILEDEPENDENCIES
||
2155 fwCapability
== DC_PAPERNAMES
)) {
2156 /* These need A -> W translation */
2159 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2163 switch(fwCapability
) {
2168 case DC_FILEDEPENDENCIES
:
2172 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2173 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2175 for(i
= 0; i
< ret
; i
++)
2176 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2177 pOutput
+ (i
* size
), size
);
2178 HeapFree(GetProcessHeap(), 0, pOutputA
);
2180 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2181 (LPSTR
)pOutput
, dmA
);
2183 HeapFree(GetProcessHeap(),0,pPortA
);
2184 HeapFree(GetProcessHeap(),0,pDeviceA
);
2185 HeapFree(GetProcessHeap(),0,dmA
);
2189 /******************************************************************
2190 * DocumentPropertiesA [WINSPOOL.@]
2192 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2194 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2195 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2196 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2198 LPSTR lpName
= pDeviceName
;
2199 static CHAR port
[] = "LPT1:";
2202 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2203 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2207 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2209 ERR("no name from hPrinter?\n");
2210 SetLastError(ERROR_INVALID_HANDLE
);
2213 lpName
= strdupWtoA(lpNameW
);
2216 if (!GDI_CallExtDeviceMode16
)
2218 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2220 if (!GDI_CallExtDeviceMode16
) {
2221 ERR("No CallExtDeviceMode16?\n");
2225 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2226 pDevModeInput
, NULL
, fMode
);
2229 HeapFree(GetProcessHeap(),0,lpName
);
2234 /*****************************************************************************
2235 * DocumentPropertiesW (WINSPOOL.@)
2237 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2239 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2241 LPDEVMODEW pDevModeOutput
,
2242 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2245 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2246 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
2247 LPDEVMODEA pDevModeOutputA
= NULL
;
2250 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2251 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2253 if(pDevModeOutput
) {
2254 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2255 if(ret
< 0) return ret
;
2256 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2258 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2259 pDevModeInputA
, fMode
);
2260 if(pDevModeOutput
) {
2261 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2262 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2264 if(fMode
== 0 && ret
> 0)
2265 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2266 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2267 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2271 /*****************************************************************************
2272 * IsValidDevmodeA [WINSPOOL.@]
2274 * Validate a DEVMODE structure and fix errors if possible.
2277 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
2279 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2287 /*****************************************************************************
2288 * IsValidDevmodeW [WINSPOOL.@]
2290 * Validate a DEVMODE structure and fix errors if possible.
2293 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
2295 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2303 /******************************************************************
2304 * OpenPrinterA [WINSPOOL.@]
2309 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2310 LPPRINTER_DEFAULTSA pDefault
)
2312 UNICODE_STRING lpPrinterNameW
;
2313 UNICODE_STRING usBuffer
;
2314 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2315 PWSTR pwstrPrinterNameW
;
2318 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2321 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2322 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2323 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2324 pDefaultW
= &DefaultW
;
2326 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2328 RtlFreeUnicodeString(&usBuffer
);
2329 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2331 RtlFreeUnicodeString(&lpPrinterNameW
);
2335 /******************************************************************
2336 * OpenPrinterW [WINSPOOL.@]
2338 * Open a Printer / Printserver or a Printer-Object
2341 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2342 * phPrinter [O] The resulting Handle is stored here
2343 * pDefault [I] PTR to Default Printer Settings or NULL
2350 * lpPrinterName is one of:
2351 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2352 *| Printer: "PrinterName"
2353 *| Printer-Object: "PrinterName,Job xxx"
2354 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2355 *| XcvPort: "Servername,XcvPort PortName"
2358 *| Printer-Object not supported
2359 *| pDefaults is ignored
2362 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2365 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2368 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2369 SetLastError(ERROR_INVALID_PARAMETER
);
2373 /* Get the unique handle of the printer or Printserver */
2374 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2379 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2381 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter
, &key
);
2382 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2383 WaitForSingleObject( init_mutex
, INFINITE
);
2384 status
= get_dword_from_reg( key
, StatusW
);
2385 set_reg_DWORD( key
, StatusW
, status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2386 ReleaseMutex( init_mutex
);
2387 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2388 update_driver( *phPrinter
);
2392 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2393 return (*phPrinter
!= 0);
2396 /******************************************************************
2397 * AddMonitorA [WINSPOOL.@]
2402 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2404 LPWSTR nameW
= NULL
;
2407 LPMONITOR_INFO_2A mi2a
;
2408 MONITOR_INFO_2W mi2w
;
2410 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2411 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2412 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2413 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2414 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2417 SetLastError(ERROR_INVALID_LEVEL
);
2421 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2427 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2428 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2429 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2432 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2434 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2435 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2436 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2438 if (mi2a
->pEnvironment
) {
2439 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2440 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2441 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2443 if (mi2a
->pDLLName
) {
2444 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2445 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2446 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2449 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2451 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2452 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2453 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2455 HeapFree(GetProcessHeap(), 0, nameW
);
2459 /******************************************************************************
2460 * AddMonitorW [WINSPOOL.@]
2462 * Install a Printmonitor
2465 * pName [I] Servername or NULL (local Computer)
2466 * Level [I] Structure-Level (Must be 2)
2467 * pMonitors [I] PTR to MONITOR_INFO_2
2474 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2477 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2479 LPMONITOR_INFO_2W mi2w
;
2481 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2482 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2483 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2484 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2485 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2487 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2490 SetLastError(ERROR_INVALID_LEVEL
);
2494 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2499 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2502 /******************************************************************
2503 * DeletePrinterDriverA [WINSPOOL.@]
2506 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2508 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2511 /******************************************************************
2512 * DeletePrinterDriverW [WINSPOOL.@]
2515 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2517 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2520 /******************************************************************
2521 * DeleteMonitorA [WINSPOOL.@]
2523 * See DeleteMonitorW.
2526 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2528 LPWSTR nameW
= NULL
;
2529 LPWSTR EnvironmentW
= NULL
;
2530 LPWSTR MonitorNameW
= NULL
;
2535 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2536 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2537 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2541 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2542 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2543 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2546 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2547 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2548 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2551 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2553 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2554 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2555 HeapFree(GetProcessHeap(), 0, nameW
);
2559 /******************************************************************
2560 * DeleteMonitorW [WINSPOOL.@]
2562 * Delete a specific Printmonitor from a Printing-Environment
2565 * pName [I] Servername or NULL (local Computer)
2566 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2567 * pMonitorName [I] Name of the Monitor, that should be deleted
2574 * pEnvironment is ignored in Windows for the local Computer.
2577 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2580 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2581 debugstr_w(pMonitorName
));
2583 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2585 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2589 /******************************************************************
2590 * DeletePortA [WINSPOOL.@]
2595 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2597 LPWSTR nameW
= NULL
;
2598 LPWSTR portW
= NULL
;
2602 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2604 /* convert servername to unicode */
2606 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2607 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2608 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2611 /* convert portname to unicode */
2613 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2614 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2615 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2618 res
= DeletePortW(nameW
, hWnd
, portW
);
2619 HeapFree(GetProcessHeap(), 0, nameW
);
2620 HeapFree(GetProcessHeap(), 0, portW
);
2624 /******************************************************************
2625 * DeletePortW [WINSPOOL.@]
2627 * Delete a specific Port
2630 * pName [I] Servername or NULL (local Computer)
2631 * hWnd [I] Handle to parent Window for the Dialog-Box
2632 * pPortName [I] Name of the Port, that should be deleted
2639 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2641 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2643 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2646 SetLastError(RPC_X_NULL_REF_POINTER
);
2650 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2653 /******************************************************************************
2654 * WritePrinter [WINSPOOL.@]
2656 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2658 opened_printer_t
*printer
;
2661 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2663 EnterCriticalSection(&printer_handles_cs
);
2664 printer
= get_opened_printer(hPrinter
);
2667 SetLastError(ERROR_INVALID_HANDLE
);
2673 SetLastError(ERROR_SPL_NO_STARTDOC
);
2677 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2679 LeaveCriticalSection(&printer_handles_cs
);
2683 /*****************************************************************************
2684 * AddFormA [WINSPOOL.@]
2686 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2688 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2692 /*****************************************************************************
2693 * AddFormW [WINSPOOL.@]
2695 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2697 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2701 /*****************************************************************************
2702 * AddJobA [WINSPOOL.@]
2704 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2707 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2711 SetLastError(ERROR_INVALID_LEVEL
);
2715 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2718 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2719 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2720 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2721 if(*pcbNeeded
> cbBuf
) {
2722 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2725 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2726 addjobA
->JobId
= addjobW
->JobId
;
2727 addjobA
->Path
= (char *)(addjobA
+ 1);
2728 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2734 /*****************************************************************************
2735 * AddJobW [WINSPOOL.@]
2737 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2739 opened_printer_t
*printer
;
2742 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2743 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2744 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2746 ADDJOB_INFO_1W
*addjob
;
2748 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2750 EnterCriticalSection(&printer_handles_cs
);
2752 printer
= get_opened_printer(hPrinter
);
2755 SetLastError(ERROR_INVALID_HANDLE
);
2760 SetLastError(ERROR_INVALID_LEVEL
);
2764 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2768 job
->job_id
= InterlockedIncrement(&next_job_id
);
2770 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2771 if(path
[len
- 1] != '\\')
2773 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2774 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2776 len
= strlenW(filename
);
2777 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2778 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2779 job
->portname
= NULL
;
2780 job
->document_title
= strdupW(default_doc_title
);
2781 job
->printer_name
= strdupW(printer
->name
);
2782 job
->devmode
= dup_devmode( printer
->devmode
);
2783 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2785 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2786 if(*pcbNeeded
<= cbBuf
) {
2787 addjob
= (ADDJOB_INFO_1W
*)pData
;
2788 addjob
->JobId
= job
->job_id
;
2789 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2790 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2793 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2796 LeaveCriticalSection(&printer_handles_cs
);
2800 /*****************************************************************************
2801 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2803 * Return the PATH for the Print-Processors
2805 * See GetPrintProcessorDirectoryW.
2809 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2810 DWORD level
, LPBYTE Info
,
2811 DWORD cbBuf
, LPDWORD pcbNeeded
)
2813 LPWSTR serverW
= NULL
;
2818 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2819 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2823 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2824 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2825 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2829 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2830 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2831 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2834 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2835 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2837 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2840 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2841 cbBuf
, NULL
, NULL
) > 0;
2844 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2845 HeapFree(GetProcessHeap(), 0, envW
);
2846 HeapFree(GetProcessHeap(), 0, serverW
);
2850 /*****************************************************************************
2851 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2853 * Return the PATH for the Print-Processors
2856 * server [I] Servername (NT only) or NULL (local Computer)
2857 * env [I] Printing-Environment (see below) or NULL (Default)
2858 * level [I] Structure-Level (must be 1)
2859 * Info [O] PTR to Buffer that receives the Result
2860 * cbBuf [I] Size of Buffer at "Info"
2861 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2862 * required for the Buffer at "Info"
2865 * Success: TRUE and in pcbNeeded the Bytes used in Info
2866 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2867 * if cbBuf is too small
2869 * Native Values returned in Info on Success:
2870 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2871 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2872 *| win9x(Windows 4.0): "%winsysdir%"
2874 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2877 * Only NULL or "" is supported for server
2880 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2881 DWORD level
, LPBYTE Info
,
2882 DWORD cbBuf
, LPDWORD pcbNeeded
)
2885 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2886 Info
, cbBuf
, pcbNeeded
);
2888 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2891 /* (Level != 1) is ignored in win9x */
2892 SetLastError(ERROR_INVALID_LEVEL
);
2896 if (pcbNeeded
== NULL
) {
2897 /* (pcbNeeded == NULL) is ignored in win9x */
2898 SetLastError(RPC_X_NULL_REF_POINTER
);
2902 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2905 /*****************************************************************************
2906 * WINSPOOL_OpenDriverReg [internal]
2908 * opens the registry for the printer drivers depending on the given input
2909 * variable pEnvironment
2912 * the opened hkey on success
2915 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
2919 const printenv_t
* env
;
2921 TRACE("(%s)\n", debugstr_w(pEnvironment
));
2923 env
= validate_envW(pEnvironment
);
2924 if (!env
) return NULL
;
2926 buffer
= HeapAlloc( GetProcessHeap(), 0,
2927 (strlenW(DriversW
) + strlenW(env
->envname
) +
2928 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2930 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2931 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2932 HeapFree(GetProcessHeap(), 0, buffer
);
2937 /*****************************************************************************
2938 * set_devices_and_printerports [internal]
2940 * set the [Devices] and [PrinterPorts] entries for a printer.
2943 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
2945 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
2949 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
2951 /* FIXME: the driver must change to "winspool" */
2952 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
2954 lstrcpyW(devline
, driver_nt
);
2955 lstrcatW(devline
, commaW
);
2956 lstrcatW(devline
, pi
->pPortName
);
2958 TRACE("using %s\n", debugstr_w(devline
));
2959 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
2960 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
2961 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2962 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2966 lstrcatW(devline
, timeout_15_45
);
2967 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
2968 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
2969 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2970 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2973 HeapFree(GetProcessHeap(), 0, devline
);
2977 /*****************************************************************************
2978 * AddPrinterW [WINSPOOL.@]
2980 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2982 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2985 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2988 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2991 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2992 SetLastError(ERROR_INVALID_PARAMETER
);
2996 ERR("Level = %d, unsupported!\n", Level
);
2997 SetLastError(ERROR_INVALID_LEVEL
);
3001 SetLastError(ERROR_INVALID_PARAMETER
);
3004 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3006 ERR("Can't create Printers key\n");
3009 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3010 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
3011 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3012 RegCloseKey(hkeyPrinter
);
3013 RegCloseKey(hkeyPrinters
);
3016 RegCloseKey(hkeyPrinter
);
3018 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
3020 ERR("Can't create Drivers key\n");
3021 RegCloseKey(hkeyPrinters
);
3024 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3026 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3027 RegCloseKey(hkeyPrinters
);
3028 RegCloseKey(hkeyDrivers
);
3029 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3032 RegCloseKey(hkeyDriver
);
3033 RegCloseKey(hkeyDrivers
);
3035 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3036 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3037 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3038 RegCloseKey(hkeyPrinters
);
3042 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3044 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3045 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3046 RegCloseKey(hkeyPrinters
);
3050 set_devices_and_printerports(pi
);
3052 set_reg_DWORD(hkeyPrinter
, AttributesW
, pi
->Attributes
);
3053 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3054 set_reg_DWORD(hkeyPrinter
, Default_PriorityW
, pi
->DefaultPriority
);
3055 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3056 set_reg_DWORD(hkeyPrinter
, dnsTimeoutW
, 0);
3057 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3058 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3059 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3060 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3061 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3062 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3063 set_reg_DWORD(hkeyPrinter
, PriorityW
, pi
->Priority
);
3064 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3065 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3066 set_reg_DWORD(hkeyPrinter
, StartTimeW
, pi
->StartTime
);
3067 set_reg_DWORD(hkeyPrinter
, StatusW
, pi
->Status
);
3068 set_reg_DWORD(hkeyPrinter
, txTimeoutW
, 0);
3069 set_reg_DWORD(hkeyPrinter
, UntilTimeW
, pi
->UntilTime
);
3071 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3075 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3076 size
= sizeof(DEVMODEW
);
3082 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3084 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
3086 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3087 HeapFree( GetProcessHeap(), 0, dm
);
3092 /* set devmode to printer name */
3093 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3097 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
3098 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
3100 RegCloseKey(hkeyPrinter
);
3101 RegCloseKey(hkeyPrinters
);
3102 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3103 ERR("OpenPrinter failing\n");
3109 /*****************************************************************************
3110 * AddPrinterA [WINSPOOL.@]
3112 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3114 UNICODE_STRING pNameW
;
3116 PRINTER_INFO_2W
*piW
;
3117 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3120 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
3122 ERR("Level = %d, unsupported!\n", Level
);
3123 SetLastError(ERROR_INVALID_LEVEL
);
3126 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3127 piW
= printer_info_AtoW( piA
, Level
);
3129 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3131 free_printer_info( piW
, Level
);
3132 RtlFreeUnicodeString(&pNameW
);
3137 /*****************************************************************************
3138 * ClosePrinter [WINSPOOL.@]
3140 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3142 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3143 opened_printer_t
*printer
= NULL
;
3146 TRACE("(%p)\n", hPrinter
);
3148 EnterCriticalSection(&printer_handles_cs
);
3150 if ((i
> 0) && (i
<= nb_printer_handles
))
3151 printer
= printer_handles
[i
- 1];
3156 struct list
*cursor
, *cursor2
;
3158 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
3160 if (printer
->backend_printer
) {
3161 backend
->fpClosePrinter(printer
->backend_printer
);
3165 EndDocPrinter(hPrinter
);
3167 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3169 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3171 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3172 ScheduleJob(hPrinter
, job
->job_id
);
3174 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3177 free_printer_entry( printer
);
3178 printer_handles
[i
- 1] = NULL
;
3181 LeaveCriticalSection(&printer_handles_cs
);
3185 /*****************************************************************************
3186 * DeleteFormA [WINSPOOL.@]
3188 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3190 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3194 /*****************************************************************************
3195 * DeleteFormW [WINSPOOL.@]
3197 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3199 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3203 /*****************************************************************************
3204 * DeletePrinter [WINSPOOL.@]
3206 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3208 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3209 HKEY hkeyPrinters
, hkey
;
3210 WCHAR def
[MAX_PATH
];
3211 DWORD size
= sizeof( def
) / sizeof( def
[0] );
3214 SetLastError(ERROR_INVALID_HANDLE
);
3217 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3218 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3219 RegCloseKey(hkeyPrinters
);
3221 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3222 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
3224 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3225 RegDeleteValueW(hkey
, lpNameW
);
3229 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3230 RegDeleteValueW(hkey
, lpNameW
);
3234 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
3236 WriteProfileStringW( windowsW
, deviceW
, NULL
);
3237 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
3239 RegDeleteValueW( hkey
, deviceW
);
3240 RegCloseKey( hkey
);
3242 SetDefaultPrinterW( NULL
);
3248 /*****************************************************************************
3249 * SetPrinterA [WINSPOOL.@]
3251 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3258 dataW
= printer_info_AtoW( data
, level
);
3259 if (!dataW
) return FALSE
;
3262 ret
= SetPrinterW( printer
, level
, dataW
, command
);
3264 if (dataW
!= data
) free_printer_info( dataW
, level
);
3269 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
3271 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
3272 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
3273 set_reg_szW( key
, PortW
, pi
->pPortName
);
3274 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
3275 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
3276 set_reg_szW( key
, LocationW
, pi
->pLocation
);
3279 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3281 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
3282 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
3283 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
3284 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
3286 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
3287 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
3288 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
3289 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
3290 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
3293 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
3295 if (!pi
->pDevMode
) return FALSE
;
3297 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3301 /******************************************************************************
3302 * SetPrinterW [WINSPOOL.@]
3304 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3309 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
3311 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
3313 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
3320 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
3321 set_printer_2( key
, pi2
);
3328 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
3329 ret
= set_printer_9( key
, pi
);
3334 FIXME( "Unimplemented level %d\n", level
);
3335 SetLastError( ERROR_INVALID_LEVEL
);
3342 /*****************************************************************************
3343 * SetJobA [WINSPOOL.@]
3345 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3346 LPBYTE pJob
, DWORD Command
)
3350 UNICODE_STRING usBuffer
;
3352 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3354 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3355 are all ignored by SetJob, so we don't bother copying them */
3363 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3364 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3366 JobW
= (LPBYTE
)info1W
;
3367 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3368 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3369 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3370 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3371 info1W
->Status
= info1A
->Status
;
3372 info1W
->Priority
= info1A
->Priority
;
3373 info1W
->Position
= info1A
->Position
;
3374 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3379 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3380 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3382 JobW
= (LPBYTE
)info2W
;
3383 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3384 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3385 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3386 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3387 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3388 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3389 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3390 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3391 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3392 info2W
->Status
= info2A
->Status
;
3393 info2W
->Priority
= info2A
->Priority
;
3394 info2W
->Position
= info2A
->Position
;
3395 info2W
->StartTime
= info2A
->StartTime
;
3396 info2W
->UntilTime
= info2A
->UntilTime
;
3397 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3401 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3402 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3405 SetLastError(ERROR_INVALID_LEVEL
);
3409 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3415 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3416 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3417 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3418 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3419 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3424 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3425 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3426 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3427 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3428 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3429 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3430 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3431 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3432 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3436 HeapFree(GetProcessHeap(), 0, JobW
);
3441 /*****************************************************************************
3442 * SetJobW [WINSPOOL.@]
3444 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3445 LPBYTE pJob
, DWORD Command
)
3450 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3451 FIXME("Ignoring everything other than document title\n");
3453 EnterCriticalSection(&printer_handles_cs
);
3454 job
= get_job(hPrinter
, JobId
);
3464 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3465 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3466 job
->document_title
= strdupW(info1
->pDocument
);
3471 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3472 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3473 job
->document_title
= strdupW(info2
->pDocument
);
3474 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3475 job
->devmode
= dup_devmode( info2
->pDevMode
);
3481 SetLastError(ERROR_INVALID_LEVEL
);
3486 LeaveCriticalSection(&printer_handles_cs
);
3490 /*****************************************************************************
3491 * EndDocPrinter [WINSPOOL.@]
3493 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3495 opened_printer_t
*printer
;
3497 TRACE("(%p)\n", hPrinter
);
3499 EnterCriticalSection(&printer_handles_cs
);
3501 printer
= get_opened_printer(hPrinter
);
3504 SetLastError(ERROR_INVALID_HANDLE
);
3510 SetLastError(ERROR_SPL_NO_STARTDOC
);
3514 CloseHandle(printer
->doc
->hf
);
3515 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3516 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3517 printer
->doc
= NULL
;
3520 LeaveCriticalSection(&printer_handles_cs
);
3524 /*****************************************************************************
3525 * EndPagePrinter [WINSPOOL.@]
3527 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3529 FIXME("(%p): stub\n", hPrinter
);
3533 /*****************************************************************************
3534 * StartDocPrinterA [WINSPOOL.@]
3536 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3538 UNICODE_STRING usBuffer
;
3540 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3543 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3544 or one (DOC_INFO_3) extra DWORDs */
3548 doc2W
.JobId
= doc2
->JobId
;
3551 doc2W
.dwMode
= doc2
->dwMode
;
3554 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3555 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3556 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3560 SetLastError(ERROR_INVALID_LEVEL
);
3564 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3566 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3567 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3568 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3573 /*****************************************************************************
3574 * StartDocPrinterW [WINSPOOL.@]
3576 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3578 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3579 opened_printer_t
*printer
;
3580 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3581 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3582 JOB_INFO_1W job_info
;
3583 DWORD needed
, ret
= 0;
3588 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3589 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3590 debugstr_w(doc
->pDatatype
));
3592 if(Level
< 1 || Level
> 3)
3594 SetLastError(ERROR_INVALID_LEVEL
);
3598 EnterCriticalSection(&printer_handles_cs
);
3599 printer
= get_opened_printer(hPrinter
);
3602 SetLastError(ERROR_INVALID_HANDLE
);
3608 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3612 /* Even if we're printing to a file we still add a print job, we'll
3613 just ignore the spool file name */
3615 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3617 ERR("AddJob failed gle %u\n", GetLastError());
3621 /* use pOutputFile only, when it is a real filename */
3622 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3623 filename
= doc
->pOutputFile
;
3625 filename
= addjob
->Path
;
3627 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3628 if(hf
== INVALID_HANDLE_VALUE
)
3631 memset(&job_info
, 0, sizeof(job_info
));
3632 job_info
.pDocument
= doc
->pDocName
;
3633 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3635 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3636 printer
->doc
->hf
= hf
;
3637 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3638 job
= get_job(hPrinter
, ret
);
3639 job
->portname
= strdupW(doc
->pOutputFile
);
3642 LeaveCriticalSection(&printer_handles_cs
);
3647 /*****************************************************************************
3648 * StartPagePrinter [WINSPOOL.@]
3650 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3652 FIXME("(%p): stub\n", hPrinter
);
3656 /*****************************************************************************
3657 * GetFormA [WINSPOOL.@]
3659 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3660 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3662 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3663 Level
,pForm
,cbBuf
,pcbNeeded
);
3667 /*****************************************************************************
3668 * GetFormW [WINSPOOL.@]
3670 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3671 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3673 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3674 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3678 /*****************************************************************************
3679 * SetFormA [WINSPOOL.@]
3681 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3684 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3688 /*****************************************************************************
3689 * SetFormW [WINSPOOL.@]
3691 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3694 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3698 /*****************************************************************************
3699 * ReadPrinter [WINSPOOL.@]
3701 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3702 LPDWORD pNoBytesRead
)
3704 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3708 /*****************************************************************************
3709 * ResetPrinterA [WINSPOOL.@]
3711 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3713 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3717 /*****************************************************************************
3718 * ResetPrinterW [WINSPOOL.@]
3720 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3722 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3726 /*****************************************************************************
3727 * get_filename_from_reg [internal]
3729 * Get ValueName from hkey storing result in out
3730 * when the Value in the registry has only a filename, use driverdir as prefix
3731 * outlen is space left in out
3732 * String is stored either as unicode or ascii
3736 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3737 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3739 WCHAR filename
[MAX_PATH
];
3743 LPWSTR buffer
= filename
;
3747 size
= sizeof(filename
);
3749 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3750 if (ret
== ERROR_MORE_DATA
) {
3751 TRACE("need dynamic buffer: %u\n", size
);
3752 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3754 /* No Memory is bad */
3758 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3761 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3762 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3768 /* do we have a full path ? */
3769 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3770 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3773 /* we must build the full Path */
3775 if ((out
) && (outlen
> dirlen
)) {
3776 lstrcpyW((LPWSTR
)out
, driverdir
);
3784 /* write the filename */
3785 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3786 if ((out
) && (outlen
>= size
)) {
3787 lstrcpyW((LPWSTR
)out
, ptr
);
3794 ptr
+= lstrlenW(ptr
)+1;
3795 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3798 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3800 /* write the multisz-termination */
3801 if (type
== REG_MULTI_SZ
) {
3802 size
= sizeof(WCHAR
);
3805 if (out
&& (outlen
>= size
)) {
3806 memset (out
, 0, size
);
3812 /*****************************************************************************
3813 * WINSPOOL_GetStringFromReg
3815 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3816 * String is stored as unicode.
3818 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3819 DWORD buflen
, DWORD
*needed
)
3821 DWORD sz
= buflen
, type
;
3824 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3825 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3826 WARN("Got ret = %d\n", ret
);
3830 /* add space for terminating '\0' */
3831 sz
+= sizeof(WCHAR
);
3835 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3840 /*****************************************************************************
3841 * WINSPOOL_GetDefaultDevMode
3843 * Get a default DevMode values for wineps.
3847 static void WINSPOOL_GetDefaultDevMode(
3849 DWORD buflen
, DWORD
*needed
)
3852 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3854 /* fill default DEVMODE - should be read from ppd... */
3855 ZeroMemory( &dm
, sizeof(dm
) );
3856 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3857 dm
.dmSpecVersion
= DM_SPECVERSION
;
3858 dm
.dmDriverVersion
= 1;
3859 dm
.dmSize
= sizeof(DEVMODEW
);
3860 dm
.dmDriverExtra
= 0;
3862 DM_ORIENTATION
| DM_PAPERSIZE
|
3863 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3866 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3867 DM_YRESOLUTION
| DM_TTOPTION
;
3869 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3870 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3871 dm
.u1
.s1
.dmPaperLength
= 2970;
3872 dm
.u1
.s1
.dmPaperWidth
= 2100;
3874 dm
.u1
.s1
.dmScale
= 100;
3875 dm
.u1
.s1
.dmCopies
= 1;
3876 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3877 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3880 dm
.dmYResolution
= 300; /* 300dpi */
3881 dm
.dmTTOption
= DMTT_BITMAP
;
3884 /* dm.dmLogPixels */
3885 /* dm.dmBitsPerPel */
3886 /* dm.dmPelsWidth */
3887 /* dm.dmPelsHeight */
3888 /* dm.u2.dmDisplayFlags */
3889 /* dm.dmDisplayFrequency */
3890 /* dm.dmICMMethod */
3891 /* dm.dmICMIntent */
3892 /* dm.dmMediaType */
3893 /* dm.dmDitherType */
3894 /* dm.dmReserved1 */
3895 /* dm.dmReserved2 */
3896 /* dm.dmPanningWidth */
3897 /* dm.dmPanningHeight */
3899 if(buflen
>= sizeof(DEVMODEW
))
3900 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
3901 *needed
= sizeof(DEVMODEW
);
3904 /*****************************************************************************
3905 * WINSPOOL_GetDevModeFromReg
3907 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3908 * DevMode is stored either as unicode or ascii.
3910 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3912 DWORD buflen
, DWORD
*needed
)
3914 DWORD sz
= buflen
, type
;
3917 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3918 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3919 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3920 if (sz
< sizeof(DEVMODEA
))
3922 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3925 /* ensures that dmSize is not erratically bogus if registry is invalid */
3926 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3927 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3928 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3929 if (ptr
&& (buflen
>= sz
)) {
3930 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3931 memcpy(ptr
, dmW
, sz
);
3932 HeapFree(GetProcessHeap(),0,dmW
);
3938 /*********************************************************************
3939 * WINSPOOL_GetPrinter_1
3941 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3943 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3944 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3946 DWORD size
, left
= cbBuf
;
3947 BOOL space
= (cbBuf
> 0);
3952 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3953 if(space
&& size
<= left
) {
3954 pi1
->pName
= (LPWSTR
)ptr
;
3962 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3963 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3964 if(space
&& size
<= left
) {
3965 pi1
->pDescription
= (LPWSTR
)ptr
;
3973 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3974 if(space
&& size
<= left
) {
3975 pi1
->pComment
= (LPWSTR
)ptr
;
3983 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3985 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3986 memset(pi1
, 0, sizeof(*pi1
));
3990 /*********************************************************************
3991 * WINSPOOL_GetPrinter_2
3993 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3995 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3996 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3998 DWORD size
, left
= cbBuf
;
3999 BOOL space
= (cbBuf
> 0);
4004 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4005 if(space
&& size
<= left
) {
4006 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4013 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
4014 if(space
&& size
<= left
) {
4015 pi2
->pShareName
= (LPWSTR
)ptr
;
4022 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4023 if(space
&& size
<= left
) {
4024 pi2
->pPortName
= (LPWSTR
)ptr
;
4031 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
4032 if(space
&& size
<= left
) {
4033 pi2
->pDriverName
= (LPWSTR
)ptr
;
4040 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4041 if(space
&& size
<= left
) {
4042 pi2
->pComment
= (LPWSTR
)ptr
;
4049 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
4050 if(space
&& size
<= left
) {
4051 pi2
->pLocation
= (LPWSTR
)ptr
;
4058 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
4059 if(space
&& size
<= left
) {
4060 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4069 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
4070 if(space
&& size
<= left
) {
4071 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4078 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
4079 if(space
&& size
<= left
) {
4080 pi2
->pSepFile
= (LPWSTR
)ptr
;
4087 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
4088 if(space
&& size
<= left
) {
4089 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4096 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
4097 if(space
&& size
<= left
) {
4098 pi2
->pDatatype
= (LPWSTR
)ptr
;
4105 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
4106 if(space
&& size
<= left
) {
4107 pi2
->pParameters
= (LPWSTR
)ptr
;
4115 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4116 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
4117 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
4118 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
4119 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
4122 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4123 memset(pi2
, 0, sizeof(*pi2
));
4128 /*********************************************************************
4129 * WINSPOOL_GetPrinter_4
4131 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4133 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4134 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4136 DWORD size
, left
= cbBuf
;
4137 BOOL space
= (cbBuf
> 0);
4142 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4143 if(space
&& size
<= left
) {
4144 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4152 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4155 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4156 memset(pi4
, 0, sizeof(*pi4
));
4161 /*********************************************************************
4162 * WINSPOOL_GetPrinter_5
4164 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4166 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4167 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4169 DWORD size
, left
= cbBuf
;
4170 BOOL space
= (cbBuf
> 0);
4175 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4176 if(space
&& size
<= left
) {
4177 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4184 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4185 if(space
&& size
<= left
) {
4186 pi5
->pPortName
= (LPWSTR
)ptr
;
4194 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4195 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
4196 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
4199 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4200 memset(pi5
, 0, sizeof(*pi5
));
4205 /*********************************************************************
4206 * WINSPOOL_GetPrinter_7
4208 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4210 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4211 DWORD cbBuf
, LPDWORD pcbNeeded
)
4213 DWORD size
, left
= cbBuf
;
4214 BOOL space
= (cbBuf
> 0);
4219 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
4222 size
= sizeof(pi7
->pszObjectGUID
);
4224 if (space
&& size
<= left
) {
4225 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4232 /* We do not have a Directory Service */
4233 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4236 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4237 memset(pi7
, 0, sizeof(*pi7
));
4242 /*********************************************************************
4243 * WINSPOOL_GetPrinter_9
4245 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4247 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4248 DWORD cbBuf
, LPDWORD pcbNeeded
)
4251 BOOL space
= (cbBuf
> 0);
4255 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
4256 if(space
&& size
<= cbBuf
) {
4257 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4264 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
4265 if(space
&& size
<= cbBuf
) {
4266 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4272 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4273 memset(pi9
, 0, sizeof(*pi9
));
4278 /*****************************************************************************
4279 * GetPrinterW [WINSPOOL.@]
4281 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4282 DWORD cbBuf
, LPDWORD pcbNeeded
)
4284 DWORD size
, needed
= 0, err
;
4289 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4291 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
4294 SetLastError( err
);
4301 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4303 size
= sizeof(PRINTER_INFO_2W
);
4305 ptr
= pPrinter
+ size
;
4307 memset(pPrinter
, 0, size
);
4312 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
4319 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4321 size
= sizeof(PRINTER_INFO_4W
);
4323 ptr
= pPrinter
+ size
;
4325 memset(pPrinter
, 0, size
);
4330 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
4338 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4340 size
= sizeof(PRINTER_INFO_5W
);
4342 ptr
= pPrinter
+ size
;
4344 memset(pPrinter
, 0, size
);
4350 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4358 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4360 size
= sizeof(PRINTER_INFO_6
);
4361 if (size
<= cbBuf
) {
4362 /* FIXME: We do not update the status yet */
4363 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4375 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4377 size
= sizeof(PRINTER_INFO_7W
);
4378 if (size
<= cbBuf
) {
4379 ptr
= pPrinter
+ size
;
4381 memset(pPrinter
, 0, size
);
4387 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4394 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4395 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4399 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4401 size
= sizeof(PRINTER_INFO_9W
);
4403 ptr
= pPrinter
+ size
;
4405 memset(pPrinter
, 0, size
);
4411 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4418 FIXME("Unimplemented level %d\n", Level
);
4419 SetLastError(ERROR_INVALID_LEVEL
);
4420 RegCloseKey(hkeyPrinter
);
4424 RegCloseKey(hkeyPrinter
);
4426 TRACE("returning %d needed = %d\n", ret
, needed
);
4427 if(pcbNeeded
) *pcbNeeded
= needed
;
4429 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4433 /*****************************************************************************
4434 * GetPrinterA [WINSPOOL.@]
4436 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4437 DWORD cbBuf
, LPDWORD pcbNeeded
)
4443 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4445 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4447 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4448 HeapFree(GetProcessHeap(), 0, buf
);
4453 /*****************************************************************************
4454 * WINSPOOL_EnumPrintersW
4456 * Implementation of EnumPrintersW
4458 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4459 DWORD dwLevel
, LPBYTE lpbPrinters
,
4460 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4461 LPDWORD lpdwReturned
)
4464 HKEY hkeyPrinters
, hkeyPrinter
;
4465 WCHAR PrinterName
[255];
4466 DWORD needed
= 0, number
= 0;
4467 DWORD used
, i
, left
;
4471 memset(lpbPrinters
, 0, cbBuf
);
4477 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4478 if(dwType
== PRINTER_ENUM_DEFAULT
)
4481 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4482 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4483 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4485 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4491 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4492 FIXME("dwType = %08x\n", dwType
);
4493 SetLastError(ERROR_INVALID_FLAGS
);
4497 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4499 ERR("Can't create Printers key\n");
4503 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4504 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4505 RegCloseKey(hkeyPrinters
);
4506 ERR("Can't query Printers key\n");
4509 TRACE("Found %d printers\n", number
);
4513 used
= number
* sizeof(PRINTER_INFO_1W
);
4516 used
= number
* sizeof(PRINTER_INFO_2W
);
4519 used
= number
* sizeof(PRINTER_INFO_4W
);
4522 used
= number
* sizeof(PRINTER_INFO_5W
);
4526 SetLastError(ERROR_INVALID_LEVEL
);
4527 RegCloseKey(hkeyPrinters
);
4530 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4532 for(i
= 0; i
< number
; i
++) {
4533 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4535 ERR("Can't enum key number %d\n", i
);
4536 RegCloseKey(hkeyPrinters
);
4539 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4540 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4542 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4543 RegCloseKey(hkeyPrinters
);
4548 buf
= lpbPrinters
+ used
;
4549 left
= cbBuf
- used
;
4557 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4560 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4563 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4566 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4569 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4572 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4575 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4578 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4581 ERR("Shouldn't be here!\n");
4582 RegCloseKey(hkeyPrinter
);
4583 RegCloseKey(hkeyPrinters
);
4586 RegCloseKey(hkeyPrinter
);
4588 RegCloseKey(hkeyPrinters
);
4595 memset(lpbPrinters
, 0, cbBuf
);
4596 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4600 *lpdwReturned
= number
;
4601 SetLastError(ERROR_SUCCESS
);
4606 /******************************************************************
4607 * EnumPrintersW [WINSPOOL.@]
4609 * Enumerates the available printers, print servers and print
4610 * providers, depending on the specified flags, name and level.
4614 * If level is set to 1:
4615 * Returns an array of PRINTER_INFO_1 data structures in the
4616 * lpbPrinters buffer.
4618 * If level is set to 2:
4619 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4620 * Returns an array of PRINTER_INFO_2 data structures in the
4621 * lpbPrinters buffer. Note that according to MSDN also an
4622 * OpenPrinter should be performed on every remote printer.
4624 * If level is set to 4 (officially WinNT only):
4625 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4626 * Fast: Only the registry is queried to retrieve printer names,
4627 * no connection to the driver is made.
4628 * Returns an array of PRINTER_INFO_4 data structures in the
4629 * lpbPrinters buffer.
4631 * If level is set to 5 (officially WinNT4/Win9x only):
4632 * Fast: Only the registry is queried to retrieve printer names,
4633 * no connection to the driver is made.
4634 * Returns an array of PRINTER_INFO_5 data structures in the
4635 * lpbPrinters buffer.
4637 * If level set to 3 or 6+:
4638 * returns zero (failure!)
4640 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4644 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4645 * - Only levels 2, 4 and 5 are implemented at the moment.
4646 * - 16-bit printer drivers are not enumerated.
4647 * - Returned amount of bytes used/needed does not match the real Windoze
4648 * implementation (as in this implementation, all strings are part
4649 * of the buffer, whereas Win32 keeps them somewhere else)
4650 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4653 * - In a regular Wine installation, no registry settings for printers
4654 * exist, which makes this function return an empty list.
4656 BOOL WINAPI
EnumPrintersW(
4657 DWORD dwType
, /* [in] Types of print objects to enumerate */
4658 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4659 DWORD dwLevel
, /* [in] type of printer info structure */
4660 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4661 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4662 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4663 LPDWORD lpdwReturned
/* [out] number of entries returned */
4666 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4667 lpdwNeeded
, lpdwReturned
);
4670 /******************************************************************
4671 * EnumPrintersA [WINSPOOL.@]
4676 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4677 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4680 UNICODE_STRING pNameU
;
4684 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4685 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4687 pNameW
= asciitounicode(&pNameU
, pName
);
4689 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4690 MS Office need this */
4691 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4693 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4695 RtlFreeUnicodeString(&pNameU
);
4697 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4699 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4703 /*****************************************************************************
4704 * WINSPOOL_GetDriverInfoFromReg [internal]
4706 * Enters the information from the registry into the DRIVER_INFO struct
4709 * zero if the printer driver does not exist in the registry
4710 * (only if Level > 1) otherwise nonzero
4712 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4715 const printenv_t
* env
,
4717 LPBYTE ptr
, /* DRIVER_INFO */
4718 LPBYTE pDriverStrings
, /* strings buffer */
4719 DWORD cbBuf
, /* size of string buffer */
4720 LPDWORD pcbNeeded
) /* space needed for str. */
4724 WCHAR driverdir
[MAX_PATH
];
4726 LPBYTE strPtr
= pDriverStrings
;
4727 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4729 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4730 debugstr_w(DriverName
), env
,
4731 Level
, di
, pDriverStrings
, cbBuf
);
4733 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4735 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4736 if (*pcbNeeded
<= cbBuf
)
4737 strcpyW((LPWSTR
)strPtr
, DriverName
);
4739 /* pName for level 1 has a different offset! */
4741 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4745 /* .cVersion and .pName for level > 1 */
4747 di
->cVersion
= env
->driverversion
;
4748 di
->pName
= (LPWSTR
) strPtr
;
4749 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4752 /* Reserve Space for the largest subdir and a Backslash*/
4753 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4754 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4755 /* Should never Fail */
4758 lstrcatW(driverdir
, env
->versionsubdir
);
4759 lstrcatW(driverdir
, backslashW
);
4761 /* dirlen must not include the terminating zero */
4762 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4764 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4765 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4766 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4771 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4774 if (*pcbNeeded
<= cbBuf
) {
4775 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4776 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4777 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4780 /* .pDriverPath is the Graphics rendering engine.
4781 The full Path is required to avoid a crash in some apps */
4782 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4784 if (*pcbNeeded
<= cbBuf
)
4785 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4787 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4788 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4791 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4792 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4794 if (*pcbNeeded
<= cbBuf
)
4795 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4797 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4798 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4801 /* .pConfigFile is the Driver user Interface */
4802 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4804 if (*pcbNeeded
<= cbBuf
)
4805 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4807 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4808 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4812 RegCloseKey(hkeyDriver
);
4813 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4818 RegCloseKey(hkeyDriver
);
4819 FIXME("level 5: incomplete\n");
4824 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4826 if (*pcbNeeded
<= cbBuf
)
4827 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4829 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4830 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4833 /* .pDependentFiles */
4834 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4836 if (*pcbNeeded
<= cbBuf
)
4837 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4839 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4840 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4842 else if (GetVersion() & 0x80000000) {
4843 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4844 size
= 2 * sizeof(WCHAR
);
4846 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4848 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4849 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4852 /* .pMonitorName is the optional Language Monitor */
4853 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4855 if (*pcbNeeded
<= cbBuf
)
4856 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4858 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4859 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4862 /* .pDefaultDataType */
4863 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4865 if(*pcbNeeded
<= cbBuf
)
4866 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4868 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4869 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4873 RegCloseKey(hkeyDriver
);
4874 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4878 /* .pszzPreviousNames */
4879 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4881 if(*pcbNeeded
<= cbBuf
)
4882 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4884 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4885 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4889 RegCloseKey(hkeyDriver
);
4890 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4894 /* support is missing, but not important enough for a FIXME */
4895 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4898 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
4900 if(*pcbNeeded
<= cbBuf
)
4901 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
4903 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4904 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4908 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
4910 if(*pcbNeeded
<= cbBuf
)
4911 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
4913 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4914 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4917 /* .pszHardwareID */
4918 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
4920 if(*pcbNeeded
<= cbBuf
)
4921 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
4923 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4924 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4928 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
4930 if(*pcbNeeded
<= cbBuf
)
4931 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
4933 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4934 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4938 RegCloseKey(hkeyDriver
);
4942 /* support is missing, but not important enough for a FIXME */
4943 TRACE("level 8: incomplete\n");
4945 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4946 RegCloseKey(hkeyDriver
);
4950 /*****************************************************************************
4951 * GetPrinterDriverW [WINSPOOL.@]
4953 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4954 DWORD Level
, LPBYTE pDriverInfo
,
4955 DWORD cbBuf
, LPDWORD pcbNeeded
)
4958 WCHAR DriverName
[100];
4959 DWORD ret
, type
, size
, needed
= 0;
4961 HKEY hkeyPrinter
, hkeyDrivers
;
4962 const printenv_t
* env
;
4964 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4965 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4968 ZeroMemory(pDriverInfo
, cbBuf
);
4970 if (!(name
= get_opened_printer_name(hPrinter
))) {
4971 SetLastError(ERROR_INVALID_HANDLE
);
4975 if (Level
< 1 || Level
== 7 || Level
> 8) {
4976 SetLastError(ERROR_INVALID_LEVEL
);
4980 env
= validate_envW(pEnvironment
);
4981 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4983 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
4986 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
4987 SetLastError( ret
);
4991 size
= sizeof(DriverName
);
4993 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4994 (LPBYTE
)DriverName
, &size
);
4995 RegCloseKey(hkeyPrinter
);
4996 if(ret
!= ERROR_SUCCESS
) {
4997 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5001 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5003 ERR("Can't create Drivers key\n");
5007 size
= di_sizeof
[Level
];
5008 if ((size
<= cbBuf
) && pDriverInfo
)
5009 ptr
= pDriverInfo
+ size
;
5011 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5012 env
, Level
, pDriverInfo
, ptr
,
5013 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5015 RegCloseKey(hkeyDrivers
);
5019 RegCloseKey(hkeyDrivers
);
5021 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5022 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5023 if(cbBuf
>= size
+ needed
) return TRUE
;
5024 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5028 /*****************************************************************************
5029 * GetPrinterDriverA [WINSPOOL.@]
5031 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5032 DWORD Level
, LPBYTE pDriverInfo
,
5033 DWORD cbBuf
, LPDWORD pcbNeeded
)
5036 UNICODE_STRING pEnvW
;
5042 ZeroMemory(pDriverInfo
, cbBuf
);
5043 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5046 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5047 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5050 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5052 HeapFree(GetProcessHeap(), 0, buf
);
5054 RtlFreeUnicodeString(&pEnvW
);
5058 /*****************************************************************************
5059 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5061 * Return the PATH for the Printer-Drivers (UNICODE)
5064 * pName [I] Servername (NT only) or NULL (local Computer)
5065 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5066 * Level [I] Structure-Level (must be 1)
5067 * pDriverDirectory [O] PTR to Buffer that receives the Result
5068 * cbBuf [I] Size of Buffer at pDriverDirectory
5069 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5070 * required for pDriverDirectory
5073 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5074 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5075 * if cbBuf is too small
5077 * Native Values returned in pDriverDirectory on Success:
5078 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5079 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5080 *| win9x(Windows 4.0): "%winsysdir%"
5082 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5085 *- Only NULL or "" is supported for pName
5088 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5089 DWORD Level
, LPBYTE pDriverDirectory
,
5090 DWORD cbBuf
, LPDWORD pcbNeeded
)
5092 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5093 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5095 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5098 /* (Level != 1) is ignored in win9x */
5099 SetLastError(ERROR_INVALID_LEVEL
);
5102 if (pcbNeeded
== NULL
) {
5103 /* (pcbNeeded == NULL) is ignored in win9x */
5104 SetLastError(RPC_X_NULL_REF_POINTER
);
5108 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5109 pDriverDirectory
, cbBuf
, pcbNeeded
);
5114 /*****************************************************************************
5115 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5117 * Return the PATH for the Printer-Drivers (ANSI)
5119 * See GetPrinterDriverDirectoryW.
5122 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5125 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5126 DWORD Level
, LPBYTE pDriverDirectory
,
5127 DWORD cbBuf
, LPDWORD pcbNeeded
)
5129 UNICODE_STRING nameW
, environmentW
;
5132 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5133 WCHAR
*driverDirectoryW
= NULL
;
5135 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5136 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5138 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5140 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5141 else nameW
.Buffer
= NULL
;
5142 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5143 else environmentW
.Buffer
= NULL
;
5145 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5146 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5149 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5150 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5152 *pcbNeeded
= needed
;
5153 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
5155 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5157 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5159 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5160 RtlFreeUnicodeString(&environmentW
);
5161 RtlFreeUnicodeString(&nameW
);
5166 /*****************************************************************************
5167 * AddPrinterDriverA [WINSPOOL.@]
5169 * See AddPrinterDriverW.
5172 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5174 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5175 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5178 /******************************************************************************
5179 * AddPrinterDriverW (WINSPOOL.@)
5181 * Install a Printer Driver
5184 * pName [I] Servername or NULL (local Computer)
5185 * level [I] Level for the supplied DRIVER_INFO_*W struct
5186 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5193 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5195 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5196 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5199 /*****************************************************************************
5200 * AddPrintProcessorA [WINSPOOL.@]
5202 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5203 LPSTR pPrintProcessorName
)
5205 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5206 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5210 /*****************************************************************************
5211 * AddPrintProcessorW [WINSPOOL.@]
5213 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5214 LPWSTR pPrintProcessorName
)
5216 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5217 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5221 /*****************************************************************************
5222 * AddPrintProvidorA [WINSPOOL.@]
5224 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5226 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5230 /*****************************************************************************
5231 * AddPrintProvidorW [WINSPOOL.@]
5233 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5235 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5239 /*****************************************************************************
5240 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5242 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5243 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5245 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5246 pDevModeOutput
, pDevModeInput
);
5250 /*****************************************************************************
5251 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5253 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5254 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5256 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5257 pDevModeOutput
, pDevModeInput
);
5261 /*****************************************************************************
5262 * PrinterProperties [WINSPOOL.@]
5264 * Displays a dialog to set the properties of the printer.
5267 * nonzero on success or zero on failure
5270 * implemented as stub only
5272 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5273 HANDLE hPrinter
/* [in] handle to printer object */
5275 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5276 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5280 /*****************************************************************************
5281 * EnumJobsA [WINSPOOL.@]
5284 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5285 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5288 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5289 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5291 if(pcbNeeded
) *pcbNeeded
= 0;
5292 if(pcReturned
) *pcReturned
= 0;
5297 /*****************************************************************************
5298 * EnumJobsW [WINSPOOL.@]
5301 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5302 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5305 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5306 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5308 if(pcbNeeded
) *pcbNeeded
= 0;
5309 if(pcReturned
) *pcReturned
= 0;
5313 /*****************************************************************************
5314 * WINSPOOL_EnumPrinterDrivers [internal]
5316 * Delivers information about all printer drivers installed on the
5317 * localhost or a given server
5320 * nonzero on success or zero on failure. If the buffer for the returned
5321 * information is too small the function will return an error
5324 * - only implemented for localhost, foreign hosts will return an error
5326 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5327 DWORD Level
, LPBYTE pDriverInfo
,
5329 DWORD cbBuf
, LPDWORD pcbNeeded
,
5330 LPDWORD pcFound
, DWORD data_offset
)
5334 const printenv_t
* env
;
5336 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5337 debugstr_w(pName
), debugstr_w(pEnvironment
),
5338 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5340 env
= validate_envW(pEnvironment
);
5341 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5345 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5347 ERR("Can't open Drivers key\n");
5351 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5352 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5353 RegCloseKey(hkeyDrivers
);
5354 ERR("Can't query Drivers key\n");
5357 TRACE("Found %d Drivers\n", *pcFound
);
5359 /* get size of single struct
5360 * unicode and ascii structure have the same size
5362 size
= di_sizeof
[Level
];
5364 if (data_offset
== 0)
5365 data_offset
= size
* (*pcFound
);
5366 *pcbNeeded
= data_offset
;
5368 for( i
= 0; i
< *pcFound
; i
++) {
5369 WCHAR DriverNameW
[255];
5370 PBYTE table_ptr
= NULL
;
5371 PBYTE data_ptr
= NULL
;
5374 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5376 ERR("Can't enum key number %d\n", i
);
5377 RegCloseKey(hkeyDrivers
);
5381 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5382 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5383 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5384 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5386 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5387 env
, Level
, table_ptr
, data_ptr
,
5388 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5390 RegCloseKey(hkeyDrivers
);
5394 *pcbNeeded
+= needed
;
5397 RegCloseKey(hkeyDrivers
);
5399 if(cbBuf
< *pcbNeeded
){
5400 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5407 /*****************************************************************************
5408 * EnumPrinterDriversW [WINSPOOL.@]
5410 * see function EnumPrinterDrivers for RETURNS, BUGS
5412 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5413 LPBYTE pDriverInfo
, DWORD cbBuf
,
5414 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5416 static const WCHAR allW
[] = {'a','l','l',0};
5420 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5422 SetLastError(RPC_X_NULL_REF_POINTER
);
5426 /* check for local drivers */
5427 if((pName
) && (pName
[0])) {
5428 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5429 SetLastError(ERROR_ACCESS_DENIED
);
5433 /* check input parameter */
5434 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5435 SetLastError(ERROR_INVALID_LEVEL
);
5439 if(pDriverInfo
&& cbBuf
> 0)
5440 memset( pDriverInfo
, 0, cbBuf
);
5442 /* Exception: pull all printers */
5443 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5445 DWORD i
, needed
, bufsize
= cbBuf
;
5446 DWORD total_needed
= 0;
5447 DWORD total_found
= 0;
5450 /* Precompute the overall total; we need this to know
5451 where pointers end and data begins (i.e. data_offset) */
5452 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5455 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5456 NULL
, 0, 0, &needed
, &found
, 0);
5457 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5458 total_needed
+= needed
;
5459 total_found
+= found
;
5462 data_offset
= di_sizeof
[Level
] * total_found
;
5467 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5470 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5471 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5472 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5474 *pcReturned
+= found
;
5475 *pcbNeeded
= needed
;
5476 data_offset
= needed
;
5477 total_found
+= found
;
5482 /* Normal behavior */
5483 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5484 0, cbBuf
, pcbNeeded
, &found
, 0);
5486 *pcReturned
= found
;
5491 /*****************************************************************************
5492 * EnumPrinterDriversA [WINSPOOL.@]
5494 * see function EnumPrinterDrivers for RETURNS, BUGS
5496 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5497 LPBYTE pDriverInfo
, DWORD cbBuf
,
5498 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5501 UNICODE_STRING pNameW
, pEnvironmentW
;
5502 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5506 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5508 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5509 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5511 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5512 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5514 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5516 HeapFree(GetProcessHeap(), 0, buf
);
5518 RtlFreeUnicodeString(&pNameW
);
5519 RtlFreeUnicodeString(&pEnvironmentW
);
5524 /******************************************************************************
5525 * EnumPortsA (WINSPOOL.@)
5530 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5531 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5534 LPBYTE bufferW
= NULL
;
5535 LPWSTR nameW
= NULL
;
5537 DWORD numentries
= 0;
5540 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5541 cbBuf
, pcbNeeded
, pcReturned
);
5543 /* convert servername to unicode */
5545 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5546 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5547 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5549 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5550 needed
= cbBuf
* sizeof(WCHAR
);
5551 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5552 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5554 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5555 if (pcbNeeded
) needed
= *pcbNeeded
;
5556 /* HeapReAlloc return NULL, when bufferW was NULL */
5557 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5558 HeapAlloc(GetProcessHeap(), 0, needed
);
5560 /* Try again with the large Buffer */
5561 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5563 needed
= pcbNeeded
? *pcbNeeded
: 0;
5564 numentries
= pcReturned
? *pcReturned
: 0;
5567 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5568 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5571 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5572 DWORD entrysize
= 0;
5575 LPPORT_INFO_2W pi2w
;
5576 LPPORT_INFO_2A pi2a
;
5579 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5581 /* First pass: calculate the size for all Entries */
5582 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5583 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5585 while (index
< numentries
) {
5587 needed
+= entrysize
; /* PORT_INFO_?A */
5588 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5590 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5591 NULL
, 0, NULL
, NULL
);
5593 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5594 NULL
, 0, NULL
, NULL
);
5595 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5596 NULL
, 0, NULL
, NULL
);
5598 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5599 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5600 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5603 /* check for errors and quit on failure */
5604 if (cbBuf
< needed
) {
5605 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5609 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5610 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5611 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5612 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5613 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5615 /* Second Pass: Fill the User Buffer (if we have one) */
5616 while ((index
< numentries
) && pPorts
) {
5618 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5619 pi2a
->pPortName
= ptr
;
5620 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5621 ptr
, cbBuf
, NULL
, NULL
);
5625 pi2a
->pMonitorName
= ptr
;
5626 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5627 ptr
, cbBuf
, NULL
, NULL
);
5631 pi2a
->pDescription
= ptr
;
5632 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5633 ptr
, cbBuf
, NULL
, NULL
);
5637 pi2a
->fPortType
= pi2w
->fPortType
;
5638 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5641 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5642 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5643 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5648 if (pcbNeeded
) *pcbNeeded
= needed
;
5649 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5651 HeapFree(GetProcessHeap(), 0, nameW
);
5652 HeapFree(GetProcessHeap(), 0, bufferW
);
5654 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5655 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5661 /******************************************************************************
5662 * EnumPortsW (WINSPOOL.@)
5664 * Enumerate available Ports
5667 * pName [I] Servername or NULL (local Computer)
5668 * Level [I] Structure-Level (1 or 2)
5669 * pPorts [O] PTR to Buffer that receives the Result
5670 * cbBuf [I] Size of Buffer at pPorts
5671 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5672 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5676 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5679 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5682 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5683 cbBuf
, pcbNeeded
, pcReturned
);
5685 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5687 /* Level is not checked in win9x */
5688 if (!Level
|| (Level
> 2)) {
5689 WARN("level (%d) is ignored in win9x\n", Level
);
5690 SetLastError(ERROR_INVALID_LEVEL
);
5693 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5694 SetLastError(RPC_X_NULL_REF_POINTER
);
5698 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5701 /******************************************************************************
5702 * GetDefaultPrinterW (WINSPOOL.@)
5705 * This function must read the value from data 'device' of key
5706 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5708 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5712 WCHAR
*buffer
, *ptr
;
5716 SetLastError(ERROR_INVALID_PARAMETER
);
5720 /* make the buffer big enough for the stuff from the profile/registry,
5721 * the content must fit into the local buffer to compute the correct
5722 * size even if the extern buffer is too small or not given.
5723 * (20 for ,driver,port) */
5725 len
= max(100, (insize
+ 20));
5726 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5728 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5730 SetLastError (ERROR_FILE_NOT_FOUND
);
5734 TRACE("%s\n", debugstr_w(buffer
));
5736 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5738 SetLastError(ERROR_INVALID_NAME
);
5744 *namesize
= strlenW(buffer
) + 1;
5745 if(!name
|| (*namesize
> insize
))
5747 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5751 strcpyW(name
, buffer
);
5754 HeapFree( GetProcessHeap(), 0, buffer
);
5759 /******************************************************************************
5760 * GetDefaultPrinterA (WINSPOOL.@)
5762 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5766 WCHAR
*bufferW
= NULL
;
5770 SetLastError(ERROR_INVALID_PARAMETER
);
5774 if(name
&& *namesize
) {
5776 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5779 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5784 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5788 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5791 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5794 HeapFree( GetProcessHeap(), 0, bufferW
);
5799 /******************************************************************************
5800 * SetDefaultPrinterW (WINSPOOL.204)
5802 * Set the Name of the Default Printer
5805 * pszPrinter [I] Name of the Printer or NULL
5812 * When the Parameter is NULL or points to an Empty String and
5813 * a Default Printer was already present, then this Function changes nothing.
5814 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5815 * the First enumerated local Printer is used.
5818 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5820 WCHAR default_printer
[MAX_PATH
];
5821 LPWSTR buffer
= NULL
;
5827 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5828 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5830 default_printer
[0] = '\0';
5831 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5833 /* if we have a default Printer, do nothing. */
5834 if (GetDefaultPrinterW(default_printer
, &size
))
5838 /* we have no default Printer: search local Printers and use the first */
5839 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5841 default_printer
[0] = '\0';
5842 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5843 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5845 pszPrinter
= default_printer
;
5846 TRACE("using %s\n", debugstr_w(pszPrinter
));
5851 if (pszPrinter
== NULL
) {
5852 TRACE("no local printer found\n");
5853 SetLastError(ERROR_FILE_NOT_FOUND
);
5858 /* "pszPrinter" is never empty or NULL here. */
5859 namelen
= lstrlenW(pszPrinter
);
5860 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5861 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5863 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5864 HeapFree(GetProcessHeap(), 0, buffer
);
5865 SetLastError(ERROR_FILE_NOT_FOUND
);
5869 /* read the devices entry for the printer (driver,port) to build the string for the
5870 default device entry (printer,driver,port) */
5871 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5872 buffer
[namelen
] = ',';
5873 namelen
++; /* move index to the start of the driver */
5875 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5876 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5878 TRACE("set device to %s\n", debugstr_w(buffer
));
5880 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
5881 TRACE("failed to set the device entry: %d\n", GetLastError());
5882 lres
= ERROR_INVALID_PRINTER_NAME
;
5885 /* remove the next section, when INIFileMapping is implemented */
5888 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
5889 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
5896 if (lres
!= ERROR_FILE_NOT_FOUND
)
5897 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
5899 SetLastError(ERROR_INVALID_PRINTER_NAME
);
5903 HeapFree(GetProcessHeap(), 0, buffer
);
5904 return (lres
== ERROR_SUCCESS
);
5907 /******************************************************************************
5908 * SetDefaultPrinterA (WINSPOOL.202)
5910 * See SetDefaultPrinterW.
5913 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5915 LPWSTR bufferW
= NULL
;
5918 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5920 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
5921 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5922 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
5924 res
= SetDefaultPrinterW(bufferW
);
5925 HeapFree(GetProcessHeap(), 0, bufferW
);
5929 /******************************************************************************
5930 * SetPrinterDataExA (WINSPOOL.@)
5932 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5933 LPCSTR pValueName
, DWORD Type
,
5934 LPBYTE pData
, DWORD cbData
)
5936 HKEY hkeyPrinter
, hkeySubkey
;
5939 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5940 debugstr_a(pValueName
), Type
, pData
, cbData
);
5942 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5946 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5948 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5949 RegCloseKey(hkeyPrinter
);
5952 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5953 RegCloseKey(hkeySubkey
);
5954 RegCloseKey(hkeyPrinter
);
5958 /******************************************************************************
5959 * SetPrinterDataExW (WINSPOOL.@)
5961 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5962 LPCWSTR pValueName
, DWORD Type
,
5963 LPBYTE pData
, DWORD cbData
)
5965 HKEY hkeyPrinter
, hkeySubkey
;
5968 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5969 debugstr_w(pValueName
), Type
, pData
, cbData
);
5971 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5975 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5977 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5978 RegCloseKey(hkeyPrinter
);
5981 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5982 RegCloseKey(hkeySubkey
);
5983 RegCloseKey(hkeyPrinter
);
5987 /******************************************************************************
5988 * SetPrinterDataA (WINSPOOL.@)
5990 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5991 LPBYTE pData
, DWORD cbData
)
5993 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5997 /******************************************************************************
5998 * SetPrinterDataW (WINSPOOL.@)
6000 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
6001 LPBYTE pData
, DWORD cbData
)
6003 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6007 /******************************************************************************
6008 * GetPrinterDataExA (WINSPOOL.@)
6010 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6011 LPCSTR pValueName
, LPDWORD pType
,
6012 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6014 opened_printer_t
*printer
;
6015 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6018 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6019 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6021 printer
= get_opened_printer(hPrinter
);
6022 if(!printer
) return ERROR_INVALID_HANDLE
;
6024 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6025 if (ret
) return ret
;
6027 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6029 if (printer
->name
) {
6031 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6033 RegCloseKey(hkeyPrinters
);
6036 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6037 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6038 RegCloseKey(hkeyPrinter
);
6039 RegCloseKey(hkeyPrinters
);
6044 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6045 0, pType
, pData
, pcbNeeded
);
6047 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6049 RegCloseKey(hkeySubkey
);
6050 RegCloseKey(hkeyPrinter
);
6051 RegCloseKey(hkeyPrinters
);
6053 TRACE("--> %d\n", ret
);
6057 /******************************************************************************
6058 * GetPrinterDataExW (WINSPOOL.@)
6060 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6061 LPCWSTR pValueName
, LPDWORD pType
,
6062 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6064 opened_printer_t
*printer
;
6065 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6068 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6069 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6071 printer
= get_opened_printer(hPrinter
);
6072 if(!printer
) return ERROR_INVALID_HANDLE
;
6074 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6075 if (ret
) return ret
;
6077 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6079 if (printer
->name
) {
6081 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6083 RegCloseKey(hkeyPrinters
);
6086 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6087 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6088 RegCloseKey(hkeyPrinter
);
6089 RegCloseKey(hkeyPrinters
);
6094 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6095 0, pType
, pData
, pcbNeeded
);
6097 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6099 RegCloseKey(hkeySubkey
);
6100 RegCloseKey(hkeyPrinter
);
6101 RegCloseKey(hkeyPrinters
);
6103 TRACE("--> %d\n", ret
);
6107 /******************************************************************************
6108 * GetPrinterDataA (WINSPOOL.@)
6110 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6111 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6113 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6114 pData
, nSize
, pcbNeeded
);
6117 /******************************************************************************
6118 * GetPrinterDataW (WINSPOOL.@)
6120 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6121 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6123 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6124 pData
, nSize
, pcbNeeded
);
6127 /*******************************************************************************
6128 * EnumPrinterDataExW [WINSPOOL.@]
6130 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6131 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6132 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6134 HKEY hkPrinter
, hkSubKey
;
6135 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6136 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6141 PPRINTER_ENUM_VALUESW ppev
;
6143 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6145 if (pKeyName
== NULL
|| *pKeyName
== 0)
6146 return ERROR_INVALID_PARAMETER
;
6148 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6149 if (ret
!= ERROR_SUCCESS
)
6151 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6156 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6157 if (ret
!= ERROR_SUCCESS
)
6159 r
= RegCloseKey (hkPrinter
);
6160 if (r
!= ERROR_SUCCESS
)
6161 WARN ("RegCloseKey returned %i\n", r
);
6162 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6163 debugstr_w (pKeyName
), ret
);
6167 ret
= RegCloseKey (hkPrinter
);
6168 if (ret
!= ERROR_SUCCESS
)
6170 ERR ("RegCloseKey returned %i\n", ret
);
6171 r
= RegCloseKey (hkSubKey
);
6172 if (r
!= ERROR_SUCCESS
)
6173 WARN ("RegCloseKey returned %i\n", r
);
6177 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6178 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6179 if (ret
!= ERROR_SUCCESS
)
6181 r
= RegCloseKey (hkSubKey
);
6182 if (r
!= ERROR_SUCCESS
)
6183 WARN ("RegCloseKey returned %i\n", r
);
6184 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6188 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6189 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6191 if (cValues
== 0) /* empty key */
6193 r
= RegCloseKey (hkSubKey
);
6194 if (r
!= ERROR_SUCCESS
)
6195 WARN ("RegCloseKey returned %i\n", r
);
6196 *pcbEnumValues
= *pnEnumValues
= 0;
6197 return ERROR_SUCCESS
;
6200 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6202 hHeap
= GetProcessHeap ();
6205 ERR ("GetProcessHeap failed\n");
6206 r
= RegCloseKey (hkSubKey
);
6207 if (r
!= ERROR_SUCCESS
)
6208 WARN ("RegCloseKey returned %i\n", r
);
6209 return ERROR_OUTOFMEMORY
;
6212 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6213 if (lpValueName
== NULL
)
6215 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6216 r
= RegCloseKey (hkSubKey
);
6217 if (r
!= ERROR_SUCCESS
)
6218 WARN ("RegCloseKey returned %i\n", r
);
6219 return ERROR_OUTOFMEMORY
;
6222 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6223 if (lpValue
== NULL
)
6225 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6226 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6227 WARN ("HeapFree failed with code %i\n", GetLastError ());
6228 r
= RegCloseKey (hkSubKey
);
6229 if (r
!= ERROR_SUCCESS
)
6230 WARN ("RegCloseKey returned %i\n", r
);
6231 return ERROR_OUTOFMEMORY
;
6234 TRACE ("pass 1: calculating buffer required for all names and values\n");
6236 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6238 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6240 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6242 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6243 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6244 NULL
, NULL
, lpValue
, &cbValueLen
);
6245 if (ret
!= ERROR_SUCCESS
)
6247 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6248 WARN ("HeapFree failed with code %i\n", GetLastError ());
6249 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6250 WARN ("HeapFree failed with code %i\n", GetLastError ());
6251 r
= RegCloseKey (hkSubKey
);
6252 if (r
!= ERROR_SUCCESS
)
6253 WARN ("RegCloseKey returned %i\n", r
);
6254 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6258 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6259 debugstr_w (lpValueName
), dwIndex
,
6260 cbValueNameLen
+ 1, cbValueLen
);
6262 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6263 cbBufSize
+= cbValueLen
;
6266 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6268 *pcbEnumValues
= cbBufSize
;
6269 *pnEnumValues
= cValues
;
6271 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6273 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6274 WARN ("HeapFree failed with code %i\n", GetLastError ());
6275 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6276 WARN ("HeapFree failed with code %i\n", GetLastError ());
6277 r
= RegCloseKey (hkSubKey
);
6278 if (r
!= ERROR_SUCCESS
)
6279 WARN ("RegCloseKey returned %i\n", r
);
6280 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6281 return ERROR_MORE_DATA
;
6284 TRACE ("pass 2: copying all names and values to buffer\n");
6286 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6287 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6289 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6291 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6292 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6293 NULL
, &dwType
, lpValue
, &cbValueLen
);
6294 if (ret
!= ERROR_SUCCESS
)
6296 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6297 WARN ("HeapFree failed with code %i\n", GetLastError ());
6298 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6299 WARN ("HeapFree failed with code %i\n", GetLastError ());
6300 r
= RegCloseKey (hkSubKey
);
6301 if (r
!= ERROR_SUCCESS
)
6302 WARN ("RegCloseKey returned %i\n", r
);
6303 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6307 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6308 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6309 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6310 pEnumValues
+= cbValueNameLen
;
6312 /* return # of *bytes* (including trailing \0), not # of chars */
6313 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6315 ppev
[dwIndex
].dwType
= dwType
;
6317 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6318 ppev
[dwIndex
].pData
= pEnumValues
;
6319 pEnumValues
+= cbValueLen
;
6321 ppev
[dwIndex
].cbData
= cbValueLen
;
6323 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6324 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6327 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6329 ret
= GetLastError ();
6330 ERR ("HeapFree failed with code %i\n", ret
);
6331 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6332 WARN ("HeapFree failed with code %i\n", GetLastError ());
6333 r
= RegCloseKey (hkSubKey
);
6334 if (r
!= ERROR_SUCCESS
)
6335 WARN ("RegCloseKey returned %i\n", r
);
6339 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6341 ret
= GetLastError ();
6342 ERR ("HeapFree failed with code %i\n", ret
);
6343 r
= RegCloseKey (hkSubKey
);
6344 if (r
!= ERROR_SUCCESS
)
6345 WARN ("RegCloseKey returned %i\n", r
);
6349 ret
= RegCloseKey (hkSubKey
);
6350 if (ret
!= ERROR_SUCCESS
)
6352 ERR ("RegCloseKey returned %i\n", ret
);
6356 return ERROR_SUCCESS
;
6359 /*******************************************************************************
6360 * EnumPrinterDataExA [WINSPOOL.@]
6362 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6363 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6364 * what Windows 2000 SP1 does.
6367 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6368 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6369 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6373 DWORD ret
, dwIndex
, dwBufSize
;
6377 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6379 if (pKeyName
== NULL
|| *pKeyName
== 0)
6380 return ERROR_INVALID_PARAMETER
;
6382 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6385 ret
= GetLastError ();
6386 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6390 hHeap
= GetProcessHeap ();
6393 ERR ("GetProcessHeap failed\n");
6394 return ERROR_OUTOFMEMORY
;
6397 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6398 if (pKeyNameW
== NULL
)
6400 ERR ("Failed to allocate %i bytes from process heap\n",
6401 (LONG
)(len
* sizeof (WCHAR
)));
6402 return ERROR_OUTOFMEMORY
;
6405 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6407 ret
= GetLastError ();
6408 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6409 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6410 WARN ("HeapFree failed with code %i\n", GetLastError ());
6414 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6415 pcbEnumValues
, pnEnumValues
);
6416 if (ret
!= ERROR_SUCCESS
)
6418 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6419 WARN ("HeapFree failed with code %i\n", GetLastError ());
6420 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6424 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6426 ret
= GetLastError ();
6427 ERR ("HeapFree failed with code %i\n", ret
);
6431 if (*pnEnumValues
== 0) /* empty key */
6432 return ERROR_SUCCESS
;
6435 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6437 PPRINTER_ENUM_VALUESW ppev
=
6438 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6440 if (dwBufSize
< ppev
->cbValueName
)
6441 dwBufSize
= ppev
->cbValueName
;
6443 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6444 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6445 dwBufSize
= ppev
->cbData
;
6448 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6450 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6451 if (pBuffer
== NULL
)
6453 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6454 return ERROR_OUTOFMEMORY
;
6457 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6459 PPRINTER_ENUM_VALUESW ppev
=
6460 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6462 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6463 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6467 ret
= GetLastError ();
6468 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6469 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6470 WARN ("HeapFree failed with code %i\n", GetLastError ());
6474 memcpy (ppev
->pValueName
, pBuffer
, len
);
6476 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6478 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6479 ppev
->dwType
!= REG_MULTI_SZ
)
6482 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6483 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6486 ret
= GetLastError ();
6487 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6488 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6489 WARN ("HeapFree failed with code %i\n", GetLastError ());
6493 memcpy (ppev
->pData
, pBuffer
, len
);
6495 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6496 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6499 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6501 ret
= GetLastError ();
6502 ERR ("HeapFree failed with code %i\n", ret
);
6506 return ERROR_SUCCESS
;
6509 /******************************************************************************
6510 * AbortPrinter (WINSPOOL.@)
6512 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6514 FIXME("(%p), stub!\n", hPrinter
);
6518 /******************************************************************************
6519 * AddPortA (WINSPOOL.@)
6524 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6526 LPWSTR nameW
= NULL
;
6527 LPWSTR monitorW
= NULL
;
6531 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6534 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6535 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6536 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6540 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6541 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6542 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6544 res
= AddPortW(nameW
, hWnd
, monitorW
);
6545 HeapFree(GetProcessHeap(), 0, nameW
);
6546 HeapFree(GetProcessHeap(), 0, monitorW
);
6550 /******************************************************************************
6551 * AddPortW (WINSPOOL.@)
6553 * Add a Port for a specific Monitor
6556 * pName [I] Servername or NULL (local Computer)
6557 * hWnd [I] Handle to parent Window for the Dialog-Box
6558 * pMonitorName [I] Name of the Monitor that manage the Port
6565 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6567 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6569 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6571 if (!pMonitorName
) {
6572 SetLastError(RPC_X_NULL_REF_POINTER
);
6576 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6579 /******************************************************************************
6580 * AddPortExA (WINSPOOL.@)
6585 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6588 PORT_INFO_2A
* pi2A
;
6589 LPWSTR nameW
= NULL
;
6590 LPWSTR monitorW
= NULL
;
6594 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6596 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6597 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6599 if ((level
< 1) || (level
> 2)) {
6600 SetLastError(ERROR_INVALID_LEVEL
);
6605 SetLastError(ERROR_INVALID_PARAMETER
);
6610 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6611 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6612 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6616 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6617 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6618 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6621 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6623 if (pi2A
->pPortName
) {
6624 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6625 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6626 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6630 if (pi2A
->pMonitorName
) {
6631 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6632 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6633 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6636 if (pi2A
->pDescription
) {
6637 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6638 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6639 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6641 pi2W
.fPortType
= pi2A
->fPortType
;
6642 pi2W
.Reserved
= pi2A
->Reserved
;
6645 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6647 HeapFree(GetProcessHeap(), 0, nameW
);
6648 HeapFree(GetProcessHeap(), 0, monitorW
);
6649 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6650 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6651 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6656 /******************************************************************************
6657 * AddPortExW (WINSPOOL.@)
6659 * Add a Port for a specific Monitor, without presenting a user interface
6662 * pName [I] Servername or NULL (local Computer)
6663 * level [I] Structure-Level (1 or 2) for pBuffer
6664 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6665 * pMonitorName [I] Name of the Monitor that manage the Port
6672 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6676 pi2
= (PORT_INFO_2W
*) pBuffer
;
6678 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6679 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6680 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6681 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6683 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6685 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6686 SetLastError(ERROR_INVALID_PARAMETER
);
6690 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6693 /******************************************************************************
6694 * AddPrinterConnectionA (WINSPOOL.@)
6696 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6698 FIXME("%s\n", debugstr_a(pName
));
6702 /******************************************************************************
6703 * AddPrinterConnectionW (WINSPOOL.@)
6705 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6707 FIXME("%s\n", debugstr_w(pName
));
6711 /******************************************************************************
6712 * AddPrinterDriverExW (WINSPOOL.@)
6714 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6717 * pName [I] Servername or NULL (local Computer)
6718 * level [I] Level for the supplied DRIVER_INFO_*W struct
6719 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6720 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6727 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6729 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6731 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6733 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6734 SetLastError(ERROR_INVALID_LEVEL
);
6739 SetLastError(ERROR_INVALID_PARAMETER
);
6743 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6746 /******************************************************************************
6747 * AddPrinterDriverExA (WINSPOOL.@)
6749 * See AddPrinterDriverExW.
6752 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6754 DRIVER_INFO_8A
*diA
;
6756 LPWSTR nameW
= NULL
;
6761 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6763 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6764 ZeroMemory(&diW
, sizeof(diW
));
6766 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6767 SetLastError(ERROR_INVALID_LEVEL
);
6772 SetLastError(ERROR_INVALID_PARAMETER
);
6776 /* convert servername to unicode */
6778 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6779 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6780 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6784 diW
.cVersion
= diA
->cVersion
;
6787 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6788 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6789 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6792 if (diA
->pEnvironment
) {
6793 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6794 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6795 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6798 if (diA
->pDriverPath
) {
6799 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6800 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6801 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6804 if (diA
->pDataFile
) {
6805 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6806 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6807 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6810 if (diA
->pConfigFile
) {
6811 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6812 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6813 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6816 if ((Level
> 2) && diA
->pDependentFiles
) {
6817 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6818 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6819 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6820 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6823 if ((Level
> 2) && diA
->pMonitorName
) {
6824 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6825 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6826 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6829 if ((Level
> 3) && diA
->pDefaultDataType
) {
6830 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6831 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6832 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6835 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6836 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6837 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6838 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6839 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6842 if ((Level
> 5) && diA
->pszMfgName
) {
6843 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6844 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6845 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6848 if ((Level
> 5) && diA
->pszOEMUrl
) {
6849 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6850 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6851 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6854 if ((Level
> 5) && diA
->pszHardwareID
) {
6855 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6856 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6857 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6860 if ((Level
> 5) && diA
->pszProvider
) {
6861 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6862 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6863 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6867 FIXME("level %u is incomplete\n", Level
);
6870 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6871 TRACE("got %u with %u\n", res
, GetLastError());
6872 HeapFree(GetProcessHeap(), 0, nameW
);
6873 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6874 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6875 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6876 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6877 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6878 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6879 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6880 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6881 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6882 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6883 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6884 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6885 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6887 TRACE("=> %u with %u\n", res
, GetLastError());
6891 /******************************************************************************
6892 * ConfigurePortA (WINSPOOL.@)
6894 * See ConfigurePortW.
6897 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6899 LPWSTR nameW
= NULL
;
6900 LPWSTR portW
= NULL
;
6904 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6906 /* convert servername to unicode */
6908 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6909 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6910 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6913 /* convert portname to unicode */
6915 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6916 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6917 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6920 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6921 HeapFree(GetProcessHeap(), 0, nameW
);
6922 HeapFree(GetProcessHeap(), 0, portW
);
6926 /******************************************************************************
6927 * ConfigurePortW (WINSPOOL.@)
6929 * Display the Configuration-Dialog for a specific Port
6932 * pName [I] Servername or NULL (local Computer)
6933 * hWnd [I] Handle to parent Window for the Dialog-Box
6934 * pPortName [I] Name of the Port, that should be configured
6941 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6944 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6946 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6949 SetLastError(RPC_X_NULL_REF_POINTER
);
6953 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6956 /******************************************************************************
6957 * ConnectToPrinterDlg (WINSPOOL.@)
6959 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6961 FIXME("%p %x\n", hWnd
, Flags
);
6965 /******************************************************************************
6966 * DeletePrinterConnectionA (WINSPOOL.@)
6968 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6970 FIXME("%s\n", debugstr_a(pName
));
6974 /******************************************************************************
6975 * DeletePrinterConnectionW (WINSPOOL.@)
6977 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6979 FIXME("%s\n", debugstr_w(pName
));
6983 /******************************************************************************
6984 * DeletePrinterDriverExW (WINSPOOL.@)
6986 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6987 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6992 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6993 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6995 if(pName
&& pName
[0])
6997 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6998 SetLastError(ERROR_INVALID_PARAMETER
);
7004 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7005 SetLastError(ERROR_INVALID_PARAMETER
);
7009 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7013 ERR("Can't open drivers key\n");
7017 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7020 RegCloseKey(hkey_drivers
);
7025 /******************************************************************************
7026 * DeletePrinterDriverExA (WINSPOOL.@)
7028 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7029 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7031 UNICODE_STRING NameW
, EnvW
, DriverW
;
7034 asciitounicode(&NameW
, pName
);
7035 asciitounicode(&EnvW
, pEnvironment
);
7036 asciitounicode(&DriverW
, pDriverName
);
7038 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7040 RtlFreeUnicodeString(&DriverW
);
7041 RtlFreeUnicodeString(&EnvW
);
7042 RtlFreeUnicodeString(&NameW
);
7047 /******************************************************************************
7048 * DeletePrinterDataExW (WINSPOOL.@)
7050 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7053 FIXME("%p %s %s\n", hPrinter
,
7054 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7055 return ERROR_INVALID_PARAMETER
;
7058 /******************************************************************************
7059 * DeletePrinterDataExA (WINSPOOL.@)
7061 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7064 FIXME("%p %s %s\n", hPrinter
,
7065 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7066 return ERROR_INVALID_PARAMETER
;
7069 /******************************************************************************
7070 * DeletePrintProcessorA (WINSPOOL.@)
7072 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7074 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7075 debugstr_a(pPrintProcessorName
));
7079 /******************************************************************************
7080 * DeletePrintProcessorW (WINSPOOL.@)
7082 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7084 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7085 debugstr_w(pPrintProcessorName
));
7089 /******************************************************************************
7090 * DeletePrintProvidorA (WINSPOOL.@)
7092 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7094 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7095 debugstr_a(pPrintProviderName
));
7099 /******************************************************************************
7100 * DeletePrintProvidorW (WINSPOOL.@)
7102 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7104 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7105 debugstr_w(pPrintProviderName
));
7109 /******************************************************************************
7110 * EnumFormsA (WINSPOOL.@)
7112 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7113 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7115 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7116 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7120 /******************************************************************************
7121 * EnumFormsW (WINSPOOL.@)
7123 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7124 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7126 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7127 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7131 /*****************************************************************************
7132 * EnumMonitorsA [WINSPOOL.@]
7134 * See EnumMonitorsW.
7137 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7138 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7141 LPBYTE bufferW
= NULL
;
7142 LPWSTR nameW
= NULL
;
7144 DWORD numentries
= 0;
7147 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7148 cbBuf
, pcbNeeded
, pcReturned
);
7150 /* convert servername to unicode */
7152 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7153 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7154 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7156 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7157 needed
= cbBuf
* sizeof(WCHAR
);
7158 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7159 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7161 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7162 if (pcbNeeded
) needed
= *pcbNeeded
;
7163 /* HeapReAlloc return NULL, when bufferW was NULL */
7164 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7165 HeapAlloc(GetProcessHeap(), 0, needed
);
7167 /* Try again with the large Buffer */
7168 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7170 numentries
= pcReturned
? *pcReturned
: 0;
7173 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7174 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7177 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7178 DWORD entrysize
= 0;
7181 LPMONITOR_INFO_2W mi2w
;
7182 LPMONITOR_INFO_2A mi2a
;
7184 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7185 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7187 /* First pass: calculate the size for all Entries */
7188 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7189 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7191 while (index
< numentries
) {
7193 needed
+= entrysize
; /* MONITOR_INFO_?A */
7194 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7196 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7197 NULL
, 0, NULL
, NULL
);
7199 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7200 NULL
, 0, NULL
, NULL
);
7201 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7202 NULL
, 0, NULL
, NULL
);
7204 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7205 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7206 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7209 /* check for errors and quit on failure */
7210 if (cbBuf
< needed
) {
7211 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7215 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7216 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7217 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7218 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7219 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7221 /* Second Pass: Fill the User Buffer (if we have one) */
7222 while ((index
< numentries
) && pMonitors
) {
7224 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7226 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7227 ptr
, cbBuf
, NULL
, NULL
);
7231 mi2a
->pEnvironment
= ptr
;
7232 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7233 ptr
, cbBuf
, NULL
, NULL
);
7237 mi2a
->pDLLName
= ptr
;
7238 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7239 ptr
, cbBuf
, NULL
, NULL
);
7243 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7244 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7245 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7249 if (pcbNeeded
) *pcbNeeded
= needed
;
7250 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7252 HeapFree(GetProcessHeap(), 0, nameW
);
7253 HeapFree(GetProcessHeap(), 0, bufferW
);
7255 TRACE("returning %d with %d (%d byte for %d entries)\n",
7256 (res
), GetLastError(), needed
, numentries
);
7262 /*****************************************************************************
7263 * EnumMonitorsW [WINSPOOL.@]
7265 * Enumerate available Port-Monitors
7268 * pName [I] Servername or NULL (local Computer)
7269 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7270 * pMonitors [O] PTR to Buffer that receives the Result
7271 * cbBuf [I] Size of Buffer at pMonitors
7272 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7273 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7277 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7280 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7281 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7284 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7285 cbBuf
, pcbNeeded
, pcReturned
);
7287 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7289 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7290 SetLastError(RPC_X_NULL_REF_POINTER
);
7294 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7297 /******************************************************************************
7298 * SpoolerInit (WINSPOOL.@)
7300 * Initialize the Spooler
7307 * The function fails on windows, when the spooler service is not running
7310 BOOL WINAPI
SpoolerInit(void)
7313 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7317 /******************************************************************************
7318 * XcvDataW (WINSPOOL.@)
7320 * Execute commands in the Printmonitor DLL
7323 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7324 * pszDataName [i] Name of the command to execute
7325 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7326 * cbInputData [i] Size in Bytes of Buffer at pInputData
7327 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7328 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7329 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7330 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7337 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7338 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7340 * Minimal List of commands, that a Printmonitor DLL should support:
7342 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7343 *| "AddPort" : Add a Port
7344 *| "DeletePort": Delete a Port
7346 * Many Printmonitors support additional commands. Examples for localspl.dll:
7347 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7348 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7351 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7352 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7353 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7355 opened_printer_t
*printer
;
7357 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7358 pInputData
, cbInputData
, pOutputData
,
7359 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7361 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7363 printer
= get_opened_printer(hXcv
);
7364 if (!printer
|| (!printer
->backend_printer
)) {
7365 SetLastError(ERROR_INVALID_HANDLE
);
7369 if (!pcbOutputNeeded
) {
7370 SetLastError(ERROR_INVALID_PARAMETER
);
7374 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7375 SetLastError(RPC_X_NULL_REF_POINTER
);
7379 *pcbOutputNeeded
= 0;
7381 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7382 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7386 /*****************************************************************************
7387 * EnumPrinterDataA [WINSPOOL.@]
7390 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7391 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7392 DWORD cbData
, LPDWORD pcbData
)
7394 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7395 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7396 return ERROR_NO_MORE_ITEMS
;
7399 /*****************************************************************************
7400 * EnumPrinterDataW [WINSPOOL.@]
7403 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7404 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7405 DWORD cbData
, LPDWORD pcbData
)
7407 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7408 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7409 return ERROR_NO_MORE_ITEMS
;
7412 /*****************************************************************************
7413 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7416 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7417 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7418 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7420 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7421 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7422 pcbNeeded
, pcReturned
);
7426 /*****************************************************************************
7427 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7430 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7431 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7432 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7434 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7435 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7436 pcbNeeded
, pcReturned
);
7440 /*****************************************************************************
7441 * EnumPrintProcessorsA [WINSPOOL.@]
7443 * See EnumPrintProcessorsW.
7446 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7447 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7450 LPBYTE bufferW
= NULL
;
7451 LPWSTR nameW
= NULL
;
7454 DWORD numentries
= 0;
7457 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7458 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7460 /* convert names to unicode */
7462 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7463 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7464 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7467 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7468 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7469 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7472 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7473 needed
= cbBuf
* sizeof(WCHAR
);
7474 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7475 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7477 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7478 if (pcbNeeded
) needed
= *pcbNeeded
;
7479 /* HeapReAlloc return NULL, when bufferW was NULL */
7480 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7481 HeapAlloc(GetProcessHeap(), 0, needed
);
7483 /* Try again with the large Buffer */
7484 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7486 numentries
= pcReturned
? *pcReturned
: 0;
7490 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7493 PPRINTPROCESSOR_INFO_1W ppiw
;
7494 PPRINTPROCESSOR_INFO_1A ppia
;
7496 /* First pass: calculate the size for all Entries */
7497 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7498 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7500 while (index
< numentries
) {
7502 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7503 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7505 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7506 NULL
, 0, NULL
, NULL
);
7508 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7509 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7512 /* check for errors and quit on failure */
7513 if (cbBuf
< needed
) {
7514 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7519 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7520 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7521 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7522 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7523 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7525 /* Second Pass: Fill the User Buffer (if we have one) */
7526 while ((index
< numentries
) && pPPInfo
) {
7528 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7530 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7531 ptr
, cbBuf
, NULL
, NULL
);
7535 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7536 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7541 if (pcbNeeded
) *pcbNeeded
= needed
;
7542 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7544 HeapFree(GetProcessHeap(), 0, nameW
);
7545 HeapFree(GetProcessHeap(), 0, envW
);
7546 HeapFree(GetProcessHeap(), 0, bufferW
);
7548 TRACE("returning %d with %d (%d byte for %d entries)\n",
7549 (res
), GetLastError(), needed
, numentries
);
7554 /*****************************************************************************
7555 * EnumPrintProcessorsW [WINSPOOL.@]
7557 * Enumerate available Print Processors
7560 * pName [I] Servername or NULL (local Computer)
7561 * pEnvironment [I] Printing-Environment or NULL (Default)
7562 * Level [I] Structure-Level (Only 1 is allowed)
7563 * pPPInfo [O] PTR to Buffer that receives the Result
7564 * cbBuf [I] Size of Buffer at pPPInfo
7565 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7566 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7570 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7573 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7574 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7577 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7578 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7580 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7582 if (!pcbNeeded
|| !pcReturned
) {
7583 SetLastError(RPC_X_NULL_REF_POINTER
);
7587 if (!pPPInfo
&& (cbBuf
> 0)) {
7588 SetLastError(ERROR_INVALID_USER_BUFFER
);
7592 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7593 cbBuf
, pcbNeeded
, pcReturned
);
7596 /*****************************************************************************
7597 * ExtDeviceMode [WINSPOOL.@]
7600 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7601 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7604 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7605 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7606 debugstr_a(pProfile
), fMode
);
7610 /*****************************************************************************
7611 * FindClosePrinterChangeNotification [WINSPOOL.@]
7614 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7616 FIXME("Stub: %p\n", hChange
);
7620 /*****************************************************************************
7621 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7624 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7625 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7627 FIXME("Stub: %p %x %x %p\n",
7628 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7629 return INVALID_HANDLE_VALUE
;
7632 /*****************************************************************************
7633 * FindNextPrinterChangeNotification [WINSPOOL.@]
7636 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7637 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7639 FIXME("Stub: %p %p %p %p\n",
7640 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7644 /*****************************************************************************
7645 * FreePrinterNotifyInfo [WINSPOOL.@]
7648 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7650 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7654 /*****************************************************************************
7657 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7658 * ansi depending on the unicode parameter.
7660 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7670 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7673 memcpy(ptr
, str
, *size
);
7680 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7683 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7690 /*****************************************************************************
7693 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7694 LPDWORD pcbNeeded
, BOOL unicode
)
7696 DWORD size
, left
= cbBuf
;
7697 BOOL space
= (cbBuf
> 0);
7704 ji1
->JobId
= job
->job_id
;
7707 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7708 if(space
&& size
<= left
)
7710 ji1
->pDocument
= (LPWSTR
)ptr
;
7718 if (job
->printer_name
)
7720 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7721 if(space
&& size
<= left
)
7723 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7735 /*****************************************************************************
7738 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7739 LPDWORD pcbNeeded
, BOOL unicode
)
7741 DWORD size
, left
= cbBuf
;
7743 BOOL space
= (cbBuf
> 0);
7745 LPDEVMODEA dmA
= NULL
;
7752 ji2
->JobId
= job
->job_id
;
7755 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7756 if(space
&& size
<= left
)
7758 ji2
->pDocument
= (LPWSTR
)ptr
;
7766 if (job
->printer_name
)
7768 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7769 if(space
&& size
<= left
)
7771 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7784 dmA
= DEVMODEdupWtoA(job
->devmode
);
7785 devmode
= (LPDEVMODEW
) dmA
;
7786 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7790 devmode
= job
->devmode
;
7791 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7795 FIXME("Can't convert DEVMODE W to A\n");
7798 /* align DEVMODE to a DWORD boundary */
7799 shift
= (4 - (*pcbNeeded
& 3)) & 3;
7805 memcpy(ptr
, devmode
, size
-shift
);
7806 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7807 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7820 /*****************************************************************************
7823 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7824 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7827 DWORD needed
= 0, size
;
7831 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7833 EnterCriticalSection(&printer_handles_cs
);
7834 job
= get_job(hPrinter
, JobId
);
7841 size
= sizeof(JOB_INFO_1W
);
7846 memset(pJob
, 0, size
);
7850 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7855 size
= sizeof(JOB_INFO_2W
);
7860 memset(pJob
, 0, size
);
7864 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7869 size
= sizeof(JOB_INFO_3
);
7873 memset(pJob
, 0, size
);
7882 SetLastError(ERROR_INVALID_LEVEL
);
7886 *pcbNeeded
= needed
;
7888 LeaveCriticalSection(&printer_handles_cs
);
7892 /*****************************************************************************
7893 * GetJobA [WINSPOOL.@]
7896 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7897 DWORD cbBuf
, LPDWORD pcbNeeded
)
7899 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7902 /*****************************************************************************
7903 * GetJobW [WINSPOOL.@]
7906 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7907 DWORD cbBuf
, LPDWORD pcbNeeded
)
7909 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7912 /*****************************************************************************
7915 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7918 char *unixname
, *cmdA
;
7920 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7926 if(!(unixname
= wine_get_unix_file_name(filename
)))
7929 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7930 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7931 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7933 TRACE("printing with: %s\n", cmdA
);
7935 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7940 ERR("pipe() failed!\n");
7944 if ((pid
= fork()) == 0)
7950 /* reset signals that we previously set to SIG_IGN */
7951 signal(SIGPIPE
, SIG_DFL
);
7953 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7958 ERR("fork() failed!\n");
7962 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7963 write(fds
[1], buf
, no_read
);
7970 wret
= waitpid(pid
, &status
, 0);
7971 } while (wret
< 0 && errno
== EINTR
);
7974 ERR("waitpid() failed!\n");
7977 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
7979 ERR("child process failed! %d\n", status
);
7986 if(file_fd
!= -1) close(file_fd
);
7987 if(fds
[0] != -1) close(fds
[0]);
7988 if(fds
[1] != -1) close(fds
[1]);
7990 HeapFree(GetProcessHeap(), 0, cmdA
);
7991 HeapFree(GetProcessHeap(), 0, unixname
);
7998 /*****************************************************************************
8001 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8004 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8007 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8008 sprintfW(cmd
, fmtW
, printer_name
);
8010 r
= schedule_pipe(cmd
, filename
);
8012 HeapFree(GetProcessHeap(), 0, cmd
);
8016 #ifdef SONAME_LIBCUPS
8017 /*****************************************************************************
8018 * get_cups_jobs_ticket_options
8020 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8021 * The CUPS scheduler only looks for these in Print-File requests, and since
8022 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8025 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8027 FILE *fp
= fopen( file
, "r" );
8028 char buf
[257]; /* DSC max of 256 + '\0' */
8029 const char *ps_adobe
= "%!PS-Adobe-";
8030 const char *cups_job
= "%cupsJobTicket:";
8032 if (!fp
) return num_options
;
8033 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8034 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8035 while (fgets( buf
, sizeof(buf
), fp
))
8037 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8038 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8047 /*****************************************************************************
8050 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8052 #ifdef SONAME_LIBCUPS
8055 char *unixname
, *queue
, *unix_doc_title
;
8058 int num_options
= 0, i
;
8059 cups_option_t
*options
= NULL
;
8061 if(!(unixname
= wine_get_unix_file_name(filename
)))
8064 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8065 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8066 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8068 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8069 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8070 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8072 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8074 TRACE( "printing via cups with options:\n" );
8075 for (i
= 0; i
< num_options
; i
++)
8076 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8078 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8080 pcupsFreeOptions( num_options
, options
);
8082 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8083 HeapFree(GetProcessHeap(), 0, queue
);
8084 HeapFree(GetProcessHeap(), 0, unixname
);
8090 return schedule_lpr(printer_name
, filename
);
8094 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8101 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8105 if(HIWORD(wparam
) == BN_CLICKED
)
8107 if(LOWORD(wparam
) == IDOK
)
8110 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8113 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8114 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8116 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8118 WCHAR caption
[200], message
[200];
8121 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8122 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
8123 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8124 if(mb_ret
== IDCANCEL
)
8126 HeapFree(GetProcessHeap(), 0, filename
);
8130 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8131 if(hf
== INVALID_HANDLE_VALUE
)
8133 WCHAR caption
[200], message
[200];
8135 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8136 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
8137 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8138 HeapFree(GetProcessHeap(), 0, filename
);
8142 DeleteFileW(filename
);
8143 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8145 EndDialog(hwnd
, IDOK
);
8148 if(LOWORD(wparam
) == IDCANCEL
)
8150 EndDialog(hwnd
, IDCANCEL
);
8159 /*****************************************************************************
8162 static BOOL
get_filename(LPWSTR
*filename
)
8164 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8165 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8168 /*****************************************************************************
8171 static BOOL
schedule_file(LPCWSTR filename
)
8173 LPWSTR output
= NULL
;
8175 if(get_filename(&output
))
8178 TRACE("copy to %s\n", debugstr_w(output
));
8179 r
= CopyFileW(filename
, output
, FALSE
);
8180 HeapFree(GetProcessHeap(), 0, output
);
8186 /*****************************************************************************
8189 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8191 int in_fd
, out_fd
, no_read
;
8194 char *unixname
, *outputA
;
8197 if(!(unixname
= wine_get_unix_file_name(filename
)))
8200 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8201 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8202 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8204 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8205 in_fd
= open(unixname
, O_RDONLY
);
8206 if(out_fd
== -1 || in_fd
== -1)
8209 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8210 write(out_fd
, buf
, no_read
);
8214 if(in_fd
!= -1) close(in_fd
);
8215 if(out_fd
!= -1) close(out_fd
);
8216 HeapFree(GetProcessHeap(), 0, outputA
);
8217 HeapFree(GetProcessHeap(), 0, unixname
);
8221 /*****************************************************************************
8222 * ScheduleJob [WINSPOOL.@]
8225 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8227 opened_printer_t
*printer
;
8229 struct list
*cursor
, *cursor2
;
8231 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8232 EnterCriticalSection(&printer_handles_cs
);
8233 printer
= get_opened_printer(hPrinter
);
8237 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8239 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8242 if(job
->job_id
!= dwJobID
) continue;
8244 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8245 if(hf
!= INVALID_HANDLE_VALUE
)
8247 PRINTER_INFO_5W
*pi5
= NULL
;
8248 LPWSTR portname
= job
->portname
;
8252 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8253 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8257 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8258 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8259 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8260 portname
= pi5
->pPortName
;
8262 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8263 debugstr_w(portname
));
8267 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8268 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8270 DWORD type
, count
= sizeof(output
);
8271 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8274 if(output
[0] == '|')
8276 ret
= schedule_pipe(output
+ 1, job
->filename
);
8280 ret
= schedule_unixfile(output
, job
->filename
);
8282 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8284 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8286 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8288 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8290 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8292 ret
= schedule_file(job
->filename
);
8296 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8298 HeapFree(GetProcessHeap(), 0, pi5
);
8300 DeleteFileW(job
->filename
);
8302 list_remove(cursor
);
8303 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8304 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8305 HeapFree(GetProcessHeap(), 0, job
->portname
);
8306 HeapFree(GetProcessHeap(), 0, job
->filename
);
8307 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8308 HeapFree(GetProcessHeap(), 0, job
);
8312 LeaveCriticalSection(&printer_handles_cs
);
8316 /*****************************************************************************
8317 * StartDocDlgA [WINSPOOL.@]
8319 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8321 UNICODE_STRING usBuffer
;
8324 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8327 docW
.cbSize
= sizeof(docW
);
8328 if (doc
->lpszDocName
)
8330 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8331 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
8333 if (doc
->lpszOutput
)
8335 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8336 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
8338 if (doc
->lpszDatatype
)
8340 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8341 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
8343 docW
.fwType
= doc
->fwType
;
8345 retW
= StartDocDlgW(hPrinter
, &docW
);
8349 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8350 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8351 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8352 HeapFree(GetProcessHeap(), 0, retW
);
8355 HeapFree(GetProcessHeap(), 0, datatypeW
);
8356 HeapFree(GetProcessHeap(), 0, outputW
);
8357 HeapFree(GetProcessHeap(), 0, docnameW
);
8362 /*****************************************************************************
8363 * StartDocDlgW [WINSPOOL.@]
8365 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8366 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8367 * port is "FILE:". Also returns the full path if passed a relative path.
8369 * The caller should free the returned string from the process heap.
8371 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8376 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8378 PRINTER_INFO_5W
*pi5
;
8379 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8380 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8382 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8383 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8384 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8386 HeapFree(GetProcessHeap(), 0, pi5
);
8389 HeapFree(GetProcessHeap(), 0, pi5
);
8392 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8396 if (get_filename(&name
))
8398 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8400 HeapFree(GetProcessHeap(), 0, name
);
8403 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8404 GetFullPathNameW(name
, len
, ret
, NULL
);
8405 HeapFree(GetProcessHeap(), 0, name
);
8410 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8413 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8414 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8416 attr
= GetFileAttributesW(ret
);
8417 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8419 HeapFree(GetProcessHeap(), 0, ret
);