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
);
980 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
982 PRINTER_INFO_2A pinfo2a
;
985 char *e
,*s
,*name
,*prettyname
,*devname
;
986 BOOL ret
= FALSE
, set_default
= FALSE
;
987 char *port
= NULL
, *env_default
;
988 HKEY hkeyPrinter
, hkeyPrinters
= NULL
;
989 WCHAR devnameW
[MAX_PATH
], *ppd_dir
= NULL
, *ppd
;
990 HANDLE added_printer
;
992 while (isspace(*pent
)) pent
++;
993 r
= strchr(pent
,':');
997 name_len
= strlen(pent
);
998 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
999 memcpy(name
, pent
, name_len
);
1000 name
[name_len
] = '\0';
1006 TRACE("name=%s entry=%s\n",name
, pent
);
1008 if(ispunct(*name
)) { /* a tc entry, not a real printer */
1009 TRACE("skipping tc entry\n");
1013 if(strstr(pent
,":server")) { /* server only version so skip */
1014 TRACE("skipping server entry\n");
1018 /* Determine whether this is a postscript printer. */
1021 env_default
= getenv("PRINTER");
1023 /* Get longest name, usually the one at the right for later display. */
1024 while((s
=strchr(prettyname
,'|'))) {
1027 while(isspace(*--e
)) *e
= '\0';
1028 TRACE("\t%s\n", debugstr_a(prettyname
));
1029 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1030 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
1033 e
= prettyname
+ strlen(prettyname
);
1034 while(isspace(*--e
)) *e
= '\0';
1035 TRACE("\t%s\n", debugstr_a(prettyname
));
1036 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1038 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1039 * if it is too long, we use it as comment below. */
1040 devname
= prettyname
;
1041 if (strlen(devname
)>=CCHDEVICENAME
-1)
1043 if (strlen(devname
)>=CCHDEVICENAME
-1) {
1048 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
1049 sprintf(port
,"LPR:%s",name
);
1051 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1053 ERR("Can't create Printers key\n");
1058 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
1060 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1061 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1062 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1064 TRACE("Printer already exists\n");
1065 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1066 /* flag that the PPD file should be checked for an update */
1067 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1068 RegCloseKey(hkeyPrinter
);
1070 static CHAR data_type
[] = "RAW",
1071 print_proc
[] = "WinPrint",
1072 comment
[] = "WINEPS Printer using LPR",
1073 params
[] = "<parameters?>",
1074 share_name
[] = "<share name?>",
1075 sep_file
[] = "<sep file?>";
1076 BOOL added_driver
= FALSE
;
1078 if (!ppd_dir
) ppd_dir
= get_ppd_dir();
1079 ppd
= get_ppd_filename( ppd_dir
, devnameW
);
1080 if (get_fallback_ppd( devname
, ppd
))
1082 added_driver
= add_printer_driver( devnameW
, ppd
);
1085 HeapFree( GetProcessHeap(), 0, ppd
);
1086 if (!added_driver
) goto end
;
1088 memset(&pinfo2a
,0,sizeof(pinfo2a
));
1089 pinfo2a
.pPrinterName
= devname
;
1090 pinfo2a
.pDatatype
= data_type
;
1091 pinfo2a
.pPrintProcessor
= print_proc
;
1092 pinfo2a
.pDriverName
= devname
;
1093 pinfo2a
.pComment
= comment
;
1094 pinfo2a
.pLocation
= prettyname
;
1095 pinfo2a
.pPortName
= port
;
1096 pinfo2a
.pParameters
= params
;
1097 pinfo2a
.pShareName
= share_name
;
1098 pinfo2a
.pSepFile
= sep_file
;
1100 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
1101 if (added_printer
) ClosePrinter( added_printer
);
1102 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1103 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
1106 if (isfirst
|| set_default
)
1107 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
1110 if (hkeyPrinters
) RegCloseKey( hkeyPrinters
);
1113 RemoveDirectoryW( ppd_dir
);
1114 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1116 HeapFree(GetProcessHeap(), 0, port
);
1117 HeapFree(GetProcessHeap(), 0, name
);
1122 PRINTCAP_LoadPrinters(void) {
1123 BOOL hadprinter
= FALSE
;
1127 BOOL had_bash
= FALSE
;
1129 f
= fopen("/etc/printcap","r");
1133 while(fgets(buf
,sizeof(buf
),f
)) {
1136 end
=strchr(buf
,'\n');
1140 while(isspace(*start
)) start
++;
1141 if(*start
== '#' || *start
== '\0')
1144 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
1145 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1146 HeapFree(GetProcessHeap(),0,pent
);
1150 if (end
&& *--end
== '\\') {
1157 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
1160 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
1166 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1167 HeapFree(GetProcessHeap(),0,pent
);
1173 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
1176 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
1177 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
1179 return ERROR_FILE_NOT_FOUND
;
1182 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
1184 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
1185 DWORD ret
= ERROR_FILE_NOT_FOUND
;
1187 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1188 and we support these drivers. NT writes DEVMODEW so somehow
1189 we'll need to distinguish between these when we support NT
1194 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
1195 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1196 HeapFree( GetProcessHeap(), 0, dmA
);
1202 /******************************************************************
1203 * get_servername_from_name (internal)
1205 * for an external server, a copy of the serverpart from the full name is returned
1208 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1212 WCHAR buffer
[MAX_PATH
];
1215 if (name
== NULL
) return NULL
;
1216 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1218 server
= strdupW(&name
[2]); /* skip over both backslash */
1219 if (server
== NULL
) return NULL
;
1221 /* strip '\' and the printername */
1222 ptr
= strchrW(server
, '\\');
1223 if (ptr
) ptr
[0] = '\0';
1225 TRACE("found %s\n", debugstr_w(server
));
1227 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1228 if (GetComputerNameW(buffer
, &len
)) {
1229 if (lstrcmpW(buffer
, server
) == 0) {
1230 /* The requested Servername is our computername */
1231 HeapFree(GetProcessHeap(), 0, server
);
1238 /******************************************************************
1239 * get_basename_from_name (internal)
1241 * skip over the serverpart from the full name
1244 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1246 if (name
== NULL
) return NULL
;
1247 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1248 /* skip over the servername and search for the following '\' */
1249 name
= strchrW(&name
[2], '\\');
1250 if ((name
) && (name
[1])) {
1251 /* found a separator ('\') followed by a name:
1252 skip over the separator and return the rest */
1257 /* no basename present (we found only a servername) */
1264 static void free_printer_entry( opened_printer_t
*printer
)
1266 /* the queue is shared, so don't free that here */
1267 HeapFree( GetProcessHeap(), 0, printer
->printername
);
1268 HeapFree( GetProcessHeap(), 0, printer
->name
);
1269 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
1270 HeapFree( GetProcessHeap(), 0, printer
);
1273 /******************************************************************
1274 * get_opened_printer_entry
1275 * Get the first place empty in the opened printer table
1278 * - pDefault is ignored
1280 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1282 UINT_PTR handle
= nb_printer_handles
, i
;
1283 jobqueue_t
*queue
= NULL
;
1284 opened_printer_t
*printer
= NULL
;
1286 LPCWSTR printername
;
1288 if ((backend
== NULL
) && !load_backend()) return NULL
;
1290 servername
= get_servername_from_name(name
);
1292 FIXME("server %s not supported\n", debugstr_w(servername
));
1293 HeapFree(GetProcessHeap(), 0, servername
);
1294 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1298 printername
= get_basename_from_name(name
);
1299 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1301 /* an empty printername is invalid */
1302 if (printername
&& (!printername
[0])) {
1303 SetLastError(ERROR_INVALID_PARAMETER
);
1307 EnterCriticalSection(&printer_handles_cs
);
1309 for (i
= 0; i
< nb_printer_handles
; i
++)
1311 if (!printer_handles
[i
])
1313 if(handle
== nb_printer_handles
)
1318 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1319 queue
= printer_handles
[i
]->queue
;
1323 if (handle
>= nb_printer_handles
)
1325 opened_printer_t
**new_array
;
1326 if (printer_handles
)
1327 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1328 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1330 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1331 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1338 printer_handles
= new_array
;
1339 nb_printer_handles
+= 16;
1342 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1348 /* get a printer handle from the backend */
1349 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1354 /* clone the base name. This is NULL for the printserver */
1355 printer
->printername
= strdupW(printername
);
1357 /* clone the full name */
1358 printer
->name
= strdupW(name
);
1359 if (name
&& (!printer
->name
)) {
1364 if (pDefault
&& pDefault
->pDevMode
)
1365 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
1368 printer
->queue
= queue
;
1371 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1372 if (!printer
->queue
) {
1376 list_init(&printer
->queue
->jobs
);
1377 printer
->queue
->ref
= 0;
1379 InterlockedIncrement(&printer
->queue
->ref
);
1381 printer_handles
[handle
] = printer
;
1384 LeaveCriticalSection(&printer_handles_cs
);
1385 if (!handle
&& printer
) {
1386 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1387 free_printer_entry( printer
);
1390 return (HANDLE
)handle
;
1393 static void old_printer_check( BOOL delete_phase
)
1395 PRINTER_INFO_5W
* pi
;
1396 DWORD needed
, type
, num
, delete, i
, size
;
1397 const DWORD one
= 1;
1401 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1402 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1404 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1405 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1406 for (i
= 0; i
< num
; i
++)
1408 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1409 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1412 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1416 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1422 size
= sizeof( delete );
1423 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1427 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1428 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1430 DeletePrinter( hprn
);
1431 ClosePrinter( hprn
);
1433 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1437 HeapFree(GetProcessHeap(), 0, pi
);
1440 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1441 'M','U','T','E','X','_','_','\0'};
1442 static HANDLE init_mutex
;
1444 void WINSPOOL_LoadSystemPrinters(void)
1446 HKEY hkey
, hkeyPrinters
;
1447 DWORD needed
, num
, i
;
1448 WCHAR PrinterName
[256];
1451 /* FIXME: The init code should be moved to spoolsv.exe */
1452 init_mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1455 ERR( "Failed to create mutex\n" );
1458 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1460 WaitForSingleObject( init_mutex
, INFINITE
);
1461 ReleaseMutex( init_mutex
);
1462 TRACE( "Init already done\n" );
1466 /* This ensures that all printer entries have a valid Name value. If causes
1467 problems later if they don't. If one is found to be missed we create one
1468 and set it equal to the name of the key */
1469 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1470 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1471 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1472 for(i
= 0; i
< num
; i
++) {
1473 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1474 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1475 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1476 set_reg_szW(hkey
, NameW
, PrinterName
);
1483 RegCloseKey(hkeyPrinters
);
1486 old_printer_check( FALSE
);
1488 #ifdef SONAME_LIBCUPS
1489 done
= CUPS_LoadPrinters();
1492 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1493 PRINTCAP_LoadPrinters();
1495 old_printer_check( TRUE
);
1497 ReleaseMutex( init_mutex
);
1501 /******************************************************************
1504 * Get the pointer to the specified job.
1505 * Should hold the printer_handles_cs before calling.
1507 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1509 opened_printer_t
*printer
= get_opened_printer(hprn
);
1512 if(!printer
) return NULL
;
1513 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1515 if(job
->job_id
== JobId
)
1521 /***********************************************************
1524 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1527 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1530 Formname
= (dmA
->dmSize
> off_formname
);
1531 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1532 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1533 dmW
->dmDeviceName
, CCHDEVICENAME
);
1535 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1536 dmA
->dmSize
- CCHDEVICENAME
);
1538 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1539 off_formname
- CCHDEVICENAME
);
1540 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1541 dmW
->dmFormName
, CCHFORMNAME
);
1542 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1543 (off_formname
+ CCHFORMNAME
));
1546 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1547 dmA
->dmDriverExtra
);
1551 /******************************************************************
1552 * convert_printerinfo_W_to_A [internal]
1555 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1556 DWORD level
, DWORD outlen
, DWORD numentries
)
1562 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1564 len
= pi_sizeof
[level
] * numentries
;
1565 ptr
= (LPSTR
) out
+ len
;
1568 /* copy the numbers of all PRINTER_INFO_* first */
1569 memcpy(out
, pPrintersW
, len
);
1571 while (id
< numentries
) {
1575 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1576 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1578 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1579 if (piW
->pDescription
) {
1580 piA
->pDescription
= ptr
;
1581 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1582 ptr
, outlen
, NULL
, NULL
);
1588 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1589 ptr
, outlen
, NULL
, NULL
);
1593 if (piW
->pComment
) {
1594 piA
->pComment
= ptr
;
1595 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1596 ptr
, outlen
, NULL
, NULL
);
1605 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1606 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1609 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1610 if (piW
->pServerName
) {
1611 piA
->pServerName
= ptr
;
1612 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1613 ptr
, outlen
, NULL
, NULL
);
1617 if (piW
->pPrinterName
) {
1618 piA
->pPrinterName
= ptr
;
1619 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1620 ptr
, outlen
, NULL
, NULL
);
1624 if (piW
->pShareName
) {
1625 piA
->pShareName
= ptr
;
1626 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1627 ptr
, outlen
, NULL
, NULL
);
1631 if (piW
->pPortName
) {
1632 piA
->pPortName
= ptr
;
1633 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1634 ptr
, outlen
, NULL
, NULL
);
1638 if (piW
->pDriverName
) {
1639 piA
->pDriverName
= ptr
;
1640 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1641 ptr
, outlen
, NULL
, NULL
);
1645 if (piW
->pComment
) {
1646 piA
->pComment
= ptr
;
1647 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1648 ptr
, outlen
, NULL
, NULL
);
1652 if (piW
->pLocation
) {
1653 piA
->pLocation
= ptr
;
1654 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1655 ptr
, outlen
, NULL
, NULL
);
1660 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1662 /* align DEVMODEA to a DWORD boundary */
1663 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1667 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1668 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1669 memcpy(ptr
, dmA
, len
);
1670 HeapFree(GetProcessHeap(), 0, dmA
);
1676 if (piW
->pSepFile
) {
1677 piA
->pSepFile
= ptr
;
1678 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1679 ptr
, outlen
, NULL
, NULL
);
1683 if (piW
->pPrintProcessor
) {
1684 piA
->pPrintProcessor
= ptr
;
1685 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1686 ptr
, outlen
, NULL
, NULL
);
1690 if (piW
->pDatatype
) {
1691 piA
->pDatatype
= ptr
;
1692 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1693 ptr
, outlen
, NULL
, NULL
);
1697 if (piW
->pParameters
) {
1698 piA
->pParameters
= ptr
;
1699 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1700 ptr
, outlen
, NULL
, NULL
);
1704 if (piW
->pSecurityDescriptor
) {
1705 piA
->pSecurityDescriptor
= NULL
;
1706 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1713 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1714 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1716 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1718 if (piW
->pPrinterName
) {
1719 piA
->pPrinterName
= ptr
;
1720 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1721 ptr
, outlen
, NULL
, NULL
);
1725 if (piW
->pServerName
) {
1726 piA
->pServerName
= ptr
;
1727 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1728 ptr
, outlen
, NULL
, NULL
);
1737 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1738 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1740 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1742 if (piW
->pPrinterName
) {
1743 piA
->pPrinterName
= ptr
;
1744 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1745 ptr
, outlen
, NULL
, NULL
);
1749 if (piW
->pPortName
) {
1750 piA
->pPortName
= ptr
;
1751 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1752 ptr
, outlen
, NULL
, NULL
);
1759 case 6: /* 6A and 6W are the same structure */
1764 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1765 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1767 TRACE("(%u) #%u\n", level
, id
);
1768 if (piW
->pszObjectGUID
) {
1769 piA
->pszObjectGUID
= ptr
;
1770 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1771 ptr
, outlen
, NULL
, NULL
);
1781 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1782 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1785 TRACE("(%u) #%u\n", level
, id
);
1786 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1788 /* align DEVMODEA to a DWORD boundary */
1789 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1793 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1794 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1795 memcpy(ptr
, dmA
, len
);
1796 HeapFree(GetProcessHeap(), 0, dmA
);
1806 FIXME("for level %u\n", level
);
1808 pPrintersW
+= pi_sizeof
[level
];
1809 out
+= pi_sizeof
[level
];
1814 /******************************************************************
1815 * convert_driverinfo_W_to_A [internal]
1818 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1819 DWORD level
, DWORD outlen
, DWORD numentries
)
1825 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1827 len
= di_sizeof
[level
] * numentries
;
1828 ptr
= (LPSTR
) out
+ len
;
1831 /* copy the numbers of all PRINTER_INFO_* first */
1832 memcpy(out
, pDriversW
, len
);
1834 #define COPY_STRING(fld) \
1837 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1838 ptr += len; outlen -= len;\
1840 #define COPY_MULTIZ_STRING(fld) \
1841 { LPWSTR p = diW->fld; if (p){ \
1844 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1845 ptr += len; outlen -= len; p += len;\
1847 while(len > 1 && outlen > 0); \
1850 while (id
< numentries
)
1856 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1857 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1859 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1866 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1867 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1869 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1872 COPY_STRING(pEnvironment
);
1873 COPY_STRING(pDriverPath
);
1874 COPY_STRING(pDataFile
);
1875 COPY_STRING(pConfigFile
);
1880 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1881 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1883 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1886 COPY_STRING(pEnvironment
);
1887 COPY_STRING(pDriverPath
);
1888 COPY_STRING(pDataFile
);
1889 COPY_STRING(pConfigFile
);
1890 COPY_STRING(pHelpFile
);
1891 COPY_MULTIZ_STRING(pDependentFiles
);
1892 COPY_STRING(pMonitorName
);
1893 COPY_STRING(pDefaultDataType
);
1898 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
1899 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
1901 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1904 COPY_STRING(pEnvironment
);
1905 COPY_STRING(pDriverPath
);
1906 COPY_STRING(pDataFile
);
1907 COPY_STRING(pConfigFile
);
1908 COPY_STRING(pHelpFile
);
1909 COPY_MULTIZ_STRING(pDependentFiles
);
1910 COPY_STRING(pMonitorName
);
1911 COPY_STRING(pDefaultDataType
);
1912 COPY_MULTIZ_STRING(pszzPreviousNames
);
1917 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
1918 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
1920 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1923 COPY_STRING(pEnvironment
);
1924 COPY_STRING(pDriverPath
);
1925 COPY_STRING(pDataFile
);
1926 COPY_STRING(pConfigFile
);
1931 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
1932 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
1934 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1937 COPY_STRING(pEnvironment
);
1938 COPY_STRING(pDriverPath
);
1939 COPY_STRING(pDataFile
);
1940 COPY_STRING(pConfigFile
);
1941 COPY_STRING(pHelpFile
);
1942 COPY_MULTIZ_STRING(pDependentFiles
);
1943 COPY_STRING(pMonitorName
);
1944 COPY_STRING(pDefaultDataType
);
1945 COPY_MULTIZ_STRING(pszzPreviousNames
);
1946 COPY_STRING(pszMfgName
);
1947 COPY_STRING(pszOEMUrl
);
1948 COPY_STRING(pszHardwareID
);
1949 COPY_STRING(pszProvider
);
1954 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
1955 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
1957 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1960 COPY_STRING(pEnvironment
);
1961 COPY_STRING(pDriverPath
);
1962 COPY_STRING(pDataFile
);
1963 COPY_STRING(pConfigFile
);
1964 COPY_STRING(pHelpFile
);
1965 COPY_MULTIZ_STRING(pDependentFiles
);
1966 COPY_STRING(pMonitorName
);
1967 COPY_STRING(pDefaultDataType
);
1968 COPY_MULTIZ_STRING(pszzPreviousNames
);
1969 COPY_STRING(pszMfgName
);
1970 COPY_STRING(pszOEMUrl
);
1971 COPY_STRING(pszHardwareID
);
1972 COPY_STRING(pszProvider
);
1973 COPY_STRING(pszPrintProcessor
);
1974 COPY_STRING(pszVendorSetup
);
1975 COPY_MULTIZ_STRING(pszzColorProfiles
);
1976 COPY_STRING(pszInfPath
);
1977 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
1983 FIXME("for level %u\n", level
);
1986 pDriversW
+= di_sizeof
[level
];
1987 out
+= di_sizeof
[level
];
1992 #undef COPY_MULTIZ_STRING
1996 /***********************************************************
1999 static void *printer_info_AtoW( const void *data
, DWORD level
)
2002 UNICODE_STRING usBuffer
;
2004 if (!data
) return NULL
;
2006 if (level
< 1 || level
> 9) return NULL
;
2008 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
2009 if (!ret
) return NULL
;
2011 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
2017 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
2018 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
2020 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
2021 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
2022 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
2023 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
2024 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
2025 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
2026 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
2027 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2028 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
2029 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
2030 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
2031 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
2038 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
2039 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
2041 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2046 FIXME( "Unhandled level %d\n", level
);
2047 HeapFree( GetProcessHeap(), 0, ret
);
2054 /***********************************************************
2057 static void free_printer_info( void *data
, DWORD level
)
2065 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
2067 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
2068 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
2069 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
2070 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
2071 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
2072 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
2073 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
2074 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2075 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
2076 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
2077 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
2078 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
2085 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
2087 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2092 FIXME( "Unhandled level %d\n", level
);
2095 HeapFree( GetProcessHeap(), 0, data
);
2099 /******************************************************************
2100 * DeviceCapabilities [WINSPOOL.@]
2101 * DeviceCapabilitiesA [WINSPOOL.@]
2104 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
2105 LPSTR pOutput
, LPDEVMODEA lpdm
)
2109 if (!GDI_CallDeviceCapabilities16
)
2111 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2113 if (!GDI_CallDeviceCapabilities16
) return -1;
2115 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
2117 /* If DC_PAPERSIZE map POINT16s to POINTs */
2118 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
2119 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
2120 POINT
*pt
= (POINT
*)pOutput
;
2122 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
2123 for(i
= 0; i
< ret
; i
++, pt
++)
2128 HeapFree( GetProcessHeap(), 0, tmp
);
2134 /*****************************************************************************
2135 * DeviceCapabilitiesW [WINSPOOL.@]
2137 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2140 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2141 WORD fwCapability
, LPWSTR pOutput
,
2142 const DEVMODEW
*pDevMode
)
2144 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
2145 LPSTR pDeviceA
= strdupWtoA(pDevice
);
2146 LPSTR pPortA
= strdupWtoA(pPort
);
2149 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
2150 fwCapability
== DC_FILEDEPENDENCIES
||
2151 fwCapability
== DC_PAPERNAMES
)) {
2152 /* These need A -> W translation */
2155 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2159 switch(fwCapability
) {
2164 case DC_FILEDEPENDENCIES
:
2168 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2169 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2171 for(i
= 0; i
< ret
; i
++)
2172 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2173 pOutput
+ (i
* size
), size
);
2174 HeapFree(GetProcessHeap(), 0, pOutputA
);
2176 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2177 (LPSTR
)pOutput
, dmA
);
2179 HeapFree(GetProcessHeap(),0,pPortA
);
2180 HeapFree(GetProcessHeap(),0,pDeviceA
);
2181 HeapFree(GetProcessHeap(),0,dmA
);
2185 /******************************************************************
2186 * DocumentPropertiesA [WINSPOOL.@]
2188 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2190 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2191 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2192 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2194 LPSTR lpName
= pDeviceName
;
2195 static CHAR port
[] = "LPT1:";
2198 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2199 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2203 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2205 ERR("no name from hPrinter?\n");
2206 SetLastError(ERROR_INVALID_HANDLE
);
2209 lpName
= strdupWtoA(lpNameW
);
2212 if (!GDI_CallExtDeviceMode16
)
2214 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2216 if (!GDI_CallExtDeviceMode16
) {
2217 ERR("No CallExtDeviceMode16?\n");
2221 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2222 pDevModeInput
, NULL
, fMode
);
2225 HeapFree(GetProcessHeap(),0,lpName
);
2230 /*****************************************************************************
2231 * DocumentPropertiesW (WINSPOOL.@)
2233 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2235 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2237 LPDEVMODEW pDevModeOutput
,
2238 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2241 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2242 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
2243 LPDEVMODEA pDevModeOutputA
= NULL
;
2246 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2247 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2249 if(pDevModeOutput
) {
2250 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2251 if(ret
< 0) return ret
;
2252 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2254 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2255 pDevModeInputA
, fMode
);
2256 if(pDevModeOutput
) {
2257 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2258 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2260 if(fMode
== 0 && ret
> 0)
2261 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2262 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2263 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2267 /*****************************************************************************
2268 * IsValidDevmodeA [WINSPOOL.@]
2270 * Validate a DEVMODE structure and fix errors if possible.
2273 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
2275 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2283 /*****************************************************************************
2284 * IsValidDevmodeW [WINSPOOL.@]
2286 * Validate a DEVMODE structure and fix errors if possible.
2289 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
2291 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2299 /******************************************************************
2300 * OpenPrinterA [WINSPOOL.@]
2305 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2306 LPPRINTER_DEFAULTSA pDefault
)
2308 UNICODE_STRING lpPrinterNameW
;
2309 UNICODE_STRING usBuffer
;
2310 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2311 PWSTR pwstrPrinterNameW
;
2314 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2317 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2318 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2319 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2320 pDefaultW
= &DefaultW
;
2322 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2324 RtlFreeUnicodeString(&usBuffer
);
2325 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2327 RtlFreeUnicodeString(&lpPrinterNameW
);
2331 /******************************************************************
2332 * OpenPrinterW [WINSPOOL.@]
2334 * Open a Printer / Printserver or a Printer-Object
2337 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2338 * phPrinter [O] The resulting Handle is stored here
2339 * pDefault [I] PTR to Default Printer Settings or NULL
2346 * lpPrinterName is one of:
2347 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2348 *| Printer: "PrinterName"
2349 *| Printer-Object: "PrinterName,Job xxx"
2350 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2351 *| XcvPort: "Servername,XcvPort PortName"
2354 *| Printer-Object not supported
2355 *| pDefaults is ignored
2358 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2361 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2364 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2365 SetLastError(ERROR_INVALID_PARAMETER
);
2369 /* Get the unique handle of the printer or Printserver */
2370 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2372 WaitForSingleObject( init_mutex
, INFINITE
);
2376 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2378 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter
, &key
);
2379 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2380 status
= get_dword_from_reg( key
, StatusW
);
2381 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2383 update_driver( *phPrinter
);
2384 set_reg_DWORD( key
, StatusW
, status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2388 ReleaseMutex( init_mutex
);
2390 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2391 return (*phPrinter
!= 0);
2394 /******************************************************************
2395 * AddMonitorA [WINSPOOL.@]
2400 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2402 LPWSTR nameW
= NULL
;
2405 LPMONITOR_INFO_2A mi2a
;
2406 MONITOR_INFO_2W mi2w
;
2408 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2409 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2410 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2411 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2412 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2415 SetLastError(ERROR_INVALID_LEVEL
);
2419 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2425 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2426 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2427 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2430 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2432 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2433 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2434 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2436 if (mi2a
->pEnvironment
) {
2437 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2438 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2439 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2441 if (mi2a
->pDLLName
) {
2442 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2443 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2444 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2447 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2449 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2450 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2451 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2453 HeapFree(GetProcessHeap(), 0, nameW
);
2457 /******************************************************************************
2458 * AddMonitorW [WINSPOOL.@]
2460 * Install a Printmonitor
2463 * pName [I] Servername or NULL (local Computer)
2464 * Level [I] Structure-Level (Must be 2)
2465 * pMonitors [I] PTR to MONITOR_INFO_2
2472 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2475 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2477 LPMONITOR_INFO_2W mi2w
;
2479 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2480 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2481 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2482 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2483 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2485 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2488 SetLastError(ERROR_INVALID_LEVEL
);
2492 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2497 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2500 /******************************************************************
2501 * DeletePrinterDriverA [WINSPOOL.@]
2504 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2506 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2509 /******************************************************************
2510 * DeletePrinterDriverW [WINSPOOL.@]
2513 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2515 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2518 /******************************************************************
2519 * DeleteMonitorA [WINSPOOL.@]
2521 * See DeleteMonitorW.
2524 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2526 LPWSTR nameW
= NULL
;
2527 LPWSTR EnvironmentW
= NULL
;
2528 LPWSTR MonitorNameW
= NULL
;
2533 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2534 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2535 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2539 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2540 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2541 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2544 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2545 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2546 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2549 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2551 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2552 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2553 HeapFree(GetProcessHeap(), 0, nameW
);
2557 /******************************************************************
2558 * DeleteMonitorW [WINSPOOL.@]
2560 * Delete a specific Printmonitor from a Printing-Environment
2563 * pName [I] Servername or NULL (local Computer)
2564 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2565 * pMonitorName [I] Name of the Monitor, that should be deleted
2572 * pEnvironment is ignored in Windows for the local Computer.
2575 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2578 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2579 debugstr_w(pMonitorName
));
2581 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2583 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2587 /******************************************************************
2588 * DeletePortA [WINSPOOL.@]
2593 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2595 LPWSTR nameW
= NULL
;
2596 LPWSTR portW
= NULL
;
2600 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2602 /* convert servername to unicode */
2604 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2605 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2606 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2609 /* convert portname to unicode */
2611 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2612 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2613 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2616 res
= DeletePortW(nameW
, hWnd
, portW
);
2617 HeapFree(GetProcessHeap(), 0, nameW
);
2618 HeapFree(GetProcessHeap(), 0, portW
);
2622 /******************************************************************
2623 * DeletePortW [WINSPOOL.@]
2625 * Delete a specific Port
2628 * pName [I] Servername or NULL (local Computer)
2629 * hWnd [I] Handle to parent Window for the Dialog-Box
2630 * pPortName [I] Name of the Port, that should be deleted
2637 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2639 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2641 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2644 SetLastError(RPC_X_NULL_REF_POINTER
);
2648 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2651 /******************************************************************************
2652 * WritePrinter [WINSPOOL.@]
2654 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2656 opened_printer_t
*printer
;
2659 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2661 EnterCriticalSection(&printer_handles_cs
);
2662 printer
= get_opened_printer(hPrinter
);
2665 SetLastError(ERROR_INVALID_HANDLE
);
2671 SetLastError(ERROR_SPL_NO_STARTDOC
);
2675 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2677 LeaveCriticalSection(&printer_handles_cs
);
2681 /*****************************************************************************
2682 * AddFormA [WINSPOOL.@]
2684 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2686 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2690 /*****************************************************************************
2691 * AddFormW [WINSPOOL.@]
2693 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2695 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2699 /*****************************************************************************
2700 * AddJobA [WINSPOOL.@]
2702 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2705 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2709 SetLastError(ERROR_INVALID_LEVEL
);
2713 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2716 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2717 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2718 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2719 if(*pcbNeeded
> cbBuf
) {
2720 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2723 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2724 addjobA
->JobId
= addjobW
->JobId
;
2725 addjobA
->Path
= (char *)(addjobA
+ 1);
2726 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2732 /*****************************************************************************
2733 * AddJobW [WINSPOOL.@]
2735 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2737 opened_printer_t
*printer
;
2740 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2741 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2742 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2744 ADDJOB_INFO_1W
*addjob
;
2746 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2748 EnterCriticalSection(&printer_handles_cs
);
2750 printer
= get_opened_printer(hPrinter
);
2753 SetLastError(ERROR_INVALID_HANDLE
);
2758 SetLastError(ERROR_INVALID_LEVEL
);
2762 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2766 job
->job_id
= InterlockedIncrement(&next_job_id
);
2768 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2769 if(path
[len
- 1] != '\\')
2771 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2772 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2774 len
= strlenW(filename
);
2775 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2776 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2777 job
->portname
= NULL
;
2778 job
->document_title
= strdupW(default_doc_title
);
2779 job
->printer_name
= strdupW(printer
->name
);
2780 job
->devmode
= dup_devmode( printer
->devmode
);
2781 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2783 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2784 if(*pcbNeeded
<= cbBuf
) {
2785 addjob
= (ADDJOB_INFO_1W
*)pData
;
2786 addjob
->JobId
= job
->job_id
;
2787 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2788 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2791 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2794 LeaveCriticalSection(&printer_handles_cs
);
2798 /*****************************************************************************
2799 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2801 * Return the PATH for the Print-Processors
2803 * See GetPrintProcessorDirectoryW.
2807 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2808 DWORD level
, LPBYTE Info
,
2809 DWORD cbBuf
, LPDWORD pcbNeeded
)
2811 LPWSTR serverW
= NULL
;
2816 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2817 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2821 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2822 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2823 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2827 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2828 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2829 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2832 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2833 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2835 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2838 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2839 cbBuf
, NULL
, NULL
) > 0;
2842 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2843 HeapFree(GetProcessHeap(), 0, envW
);
2844 HeapFree(GetProcessHeap(), 0, serverW
);
2848 /*****************************************************************************
2849 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2851 * Return the PATH for the Print-Processors
2854 * server [I] Servername (NT only) or NULL (local Computer)
2855 * env [I] Printing-Environment (see below) or NULL (Default)
2856 * level [I] Structure-Level (must be 1)
2857 * Info [O] PTR to Buffer that receives the Result
2858 * cbBuf [I] Size of Buffer at "Info"
2859 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2860 * required for the Buffer at "Info"
2863 * Success: TRUE and in pcbNeeded the Bytes used in Info
2864 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2865 * if cbBuf is too small
2867 * Native Values returned in Info on Success:
2868 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2869 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2870 *| win9x(Windows 4.0): "%winsysdir%"
2872 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2875 * Only NULL or "" is supported for server
2878 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2879 DWORD level
, LPBYTE Info
,
2880 DWORD cbBuf
, LPDWORD pcbNeeded
)
2883 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2884 Info
, cbBuf
, pcbNeeded
);
2886 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2889 /* (Level != 1) is ignored in win9x */
2890 SetLastError(ERROR_INVALID_LEVEL
);
2894 if (pcbNeeded
== NULL
) {
2895 /* (pcbNeeded == NULL) is ignored in win9x */
2896 SetLastError(RPC_X_NULL_REF_POINTER
);
2900 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2903 /*****************************************************************************
2904 * WINSPOOL_OpenDriverReg [internal]
2906 * opens the registry for the printer drivers depending on the given input
2907 * variable pEnvironment
2910 * the opened hkey on success
2913 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
2917 const printenv_t
* env
;
2919 TRACE("(%s)\n", debugstr_w(pEnvironment
));
2921 env
= validate_envW(pEnvironment
);
2922 if (!env
) return NULL
;
2924 buffer
= HeapAlloc( GetProcessHeap(), 0,
2925 (strlenW(DriversW
) + strlenW(env
->envname
) +
2926 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2928 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2929 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2930 HeapFree(GetProcessHeap(), 0, buffer
);
2935 /*****************************************************************************
2936 * set_devices_and_printerports [internal]
2938 * set the [Devices] and [PrinterPorts] entries for a printer.
2941 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
2943 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
2947 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
2949 /* FIXME: the driver must change to "winspool" */
2950 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
2952 lstrcpyW(devline
, driver_nt
);
2953 lstrcatW(devline
, commaW
);
2954 lstrcatW(devline
, pi
->pPortName
);
2956 TRACE("using %s\n", debugstr_w(devline
));
2957 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
2958 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
2959 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2960 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2964 lstrcatW(devline
, timeout_15_45
);
2965 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
2966 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
2967 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2968 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2971 HeapFree(GetProcessHeap(), 0, devline
);
2975 /*****************************************************************************
2976 * AddPrinterW [WINSPOOL.@]
2978 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2980 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2983 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2986 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2989 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2990 SetLastError(ERROR_INVALID_PARAMETER
);
2994 ERR("Level = %d, unsupported!\n", Level
);
2995 SetLastError(ERROR_INVALID_LEVEL
);
2999 SetLastError(ERROR_INVALID_PARAMETER
);
3002 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3004 ERR("Can't create Printers key\n");
3007 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3008 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
3009 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3010 RegCloseKey(hkeyPrinter
);
3011 RegCloseKey(hkeyPrinters
);
3014 RegCloseKey(hkeyPrinter
);
3016 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
3018 ERR("Can't create Drivers key\n");
3019 RegCloseKey(hkeyPrinters
);
3022 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3024 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3025 RegCloseKey(hkeyPrinters
);
3026 RegCloseKey(hkeyDrivers
);
3027 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3030 RegCloseKey(hkeyDriver
);
3031 RegCloseKey(hkeyDrivers
);
3033 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3034 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3035 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3036 RegCloseKey(hkeyPrinters
);
3040 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3042 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3043 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3044 RegCloseKey(hkeyPrinters
);
3048 set_devices_and_printerports(pi
);
3050 set_reg_DWORD(hkeyPrinter
, AttributesW
, pi
->Attributes
);
3051 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3052 set_reg_DWORD(hkeyPrinter
, Default_PriorityW
, pi
->DefaultPriority
);
3053 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3054 set_reg_DWORD(hkeyPrinter
, dnsTimeoutW
, 0);
3055 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3056 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3057 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3058 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3059 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3060 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3061 set_reg_DWORD(hkeyPrinter
, PriorityW
, pi
->Priority
);
3062 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3063 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3064 set_reg_DWORD(hkeyPrinter
, StartTimeW
, pi
->StartTime
);
3065 set_reg_DWORD(hkeyPrinter
, StatusW
, pi
->Status
);
3066 set_reg_DWORD(hkeyPrinter
, txTimeoutW
, 0);
3067 set_reg_DWORD(hkeyPrinter
, UntilTimeW
, pi
->UntilTime
);
3069 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3073 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3074 size
= sizeof(DEVMODEW
);
3080 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3082 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
3084 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3085 HeapFree( GetProcessHeap(), 0, dm
);
3090 /* set devmode to printer name */
3091 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3095 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
3096 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
3098 RegCloseKey(hkeyPrinter
);
3099 RegCloseKey(hkeyPrinters
);
3100 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3101 ERR("OpenPrinter failing\n");
3107 /*****************************************************************************
3108 * AddPrinterA [WINSPOOL.@]
3110 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3112 UNICODE_STRING pNameW
;
3114 PRINTER_INFO_2W
*piW
;
3115 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3118 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
3120 ERR("Level = %d, unsupported!\n", Level
);
3121 SetLastError(ERROR_INVALID_LEVEL
);
3124 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3125 piW
= printer_info_AtoW( piA
, Level
);
3127 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3129 free_printer_info( piW
, Level
);
3130 RtlFreeUnicodeString(&pNameW
);
3135 /*****************************************************************************
3136 * ClosePrinter [WINSPOOL.@]
3138 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3140 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3141 opened_printer_t
*printer
= NULL
;
3144 TRACE("(%p)\n", hPrinter
);
3146 EnterCriticalSection(&printer_handles_cs
);
3148 if ((i
> 0) && (i
<= nb_printer_handles
))
3149 printer
= printer_handles
[i
- 1];
3154 struct list
*cursor
, *cursor2
;
3156 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
3158 if (printer
->backend_printer
) {
3159 backend
->fpClosePrinter(printer
->backend_printer
);
3163 EndDocPrinter(hPrinter
);
3165 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3167 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3169 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3170 ScheduleJob(hPrinter
, job
->job_id
);
3172 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3175 free_printer_entry( printer
);
3176 printer_handles
[i
- 1] = NULL
;
3179 LeaveCriticalSection(&printer_handles_cs
);
3183 /*****************************************************************************
3184 * DeleteFormA [WINSPOOL.@]
3186 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3188 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3192 /*****************************************************************************
3193 * DeleteFormW [WINSPOOL.@]
3195 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3197 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3201 /*****************************************************************************
3202 * DeletePrinter [WINSPOOL.@]
3204 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3206 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3207 HKEY hkeyPrinters
, hkey
;
3208 WCHAR def
[MAX_PATH
];
3209 DWORD size
= sizeof( def
) / sizeof( def
[0] );
3212 SetLastError(ERROR_INVALID_HANDLE
);
3215 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3216 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3217 RegCloseKey(hkeyPrinters
);
3219 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3220 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
3222 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3223 RegDeleteValueW(hkey
, lpNameW
);
3227 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3228 RegDeleteValueW(hkey
, lpNameW
);
3232 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
3234 WriteProfileStringW( windowsW
, deviceW
, NULL
);
3235 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
3237 RegDeleteValueW( hkey
, deviceW
);
3238 RegCloseKey( hkey
);
3240 SetDefaultPrinterW( NULL
);
3246 /*****************************************************************************
3247 * SetPrinterA [WINSPOOL.@]
3249 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3256 dataW
= printer_info_AtoW( data
, level
);
3257 if (!dataW
) return FALSE
;
3260 ret
= SetPrinterW( printer
, level
, dataW
, command
);
3262 if (dataW
!= data
) free_printer_info( dataW
, level
);
3267 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
3269 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
3270 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
3271 set_reg_szW( key
, PortW
, pi
->pPortName
);
3272 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
3273 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
3274 set_reg_szW( key
, LocationW
, pi
->pLocation
);
3277 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3279 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
3280 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
3281 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
3282 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
3284 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
3285 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
3286 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
3287 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
3288 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
3291 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
3293 if (!pi
->pDevMode
) return FALSE
;
3295 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3299 /******************************************************************************
3300 * SetPrinterW [WINSPOOL.@]
3302 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3307 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
3309 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
3311 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
3318 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
3319 set_printer_2( key
, pi2
);
3326 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
3327 ret
= set_printer_9( key
, pi
);
3332 FIXME( "Unimplemented level %d\n", level
);
3333 SetLastError( ERROR_INVALID_LEVEL
);
3340 /*****************************************************************************
3341 * SetJobA [WINSPOOL.@]
3343 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3344 LPBYTE pJob
, DWORD Command
)
3348 UNICODE_STRING usBuffer
;
3350 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3352 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3353 are all ignored by SetJob, so we don't bother copying them */
3361 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3362 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3364 JobW
= (LPBYTE
)info1W
;
3365 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3366 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3367 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3368 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3369 info1W
->Status
= info1A
->Status
;
3370 info1W
->Priority
= info1A
->Priority
;
3371 info1W
->Position
= info1A
->Position
;
3372 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3377 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3378 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3380 JobW
= (LPBYTE
)info2W
;
3381 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3382 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3383 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3384 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3385 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3386 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3387 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3388 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3389 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3390 info2W
->Status
= info2A
->Status
;
3391 info2W
->Priority
= info2A
->Priority
;
3392 info2W
->Position
= info2A
->Position
;
3393 info2W
->StartTime
= info2A
->StartTime
;
3394 info2W
->UntilTime
= info2A
->UntilTime
;
3395 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3399 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3400 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3403 SetLastError(ERROR_INVALID_LEVEL
);
3407 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3413 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3414 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3415 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3416 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3417 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3422 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3423 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3424 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3425 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3426 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3427 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3428 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3429 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3430 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3434 HeapFree(GetProcessHeap(), 0, JobW
);
3439 /*****************************************************************************
3440 * SetJobW [WINSPOOL.@]
3442 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3443 LPBYTE pJob
, DWORD Command
)
3448 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3449 FIXME("Ignoring everything other than document title\n");
3451 EnterCriticalSection(&printer_handles_cs
);
3452 job
= get_job(hPrinter
, JobId
);
3462 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3463 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3464 job
->document_title
= strdupW(info1
->pDocument
);
3469 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3470 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3471 job
->document_title
= strdupW(info2
->pDocument
);
3472 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3473 job
->devmode
= dup_devmode( info2
->pDevMode
);
3479 SetLastError(ERROR_INVALID_LEVEL
);
3484 LeaveCriticalSection(&printer_handles_cs
);
3488 /*****************************************************************************
3489 * EndDocPrinter [WINSPOOL.@]
3491 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3493 opened_printer_t
*printer
;
3495 TRACE("(%p)\n", hPrinter
);
3497 EnterCriticalSection(&printer_handles_cs
);
3499 printer
= get_opened_printer(hPrinter
);
3502 SetLastError(ERROR_INVALID_HANDLE
);
3508 SetLastError(ERROR_SPL_NO_STARTDOC
);
3512 CloseHandle(printer
->doc
->hf
);
3513 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3514 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3515 printer
->doc
= NULL
;
3518 LeaveCriticalSection(&printer_handles_cs
);
3522 /*****************************************************************************
3523 * EndPagePrinter [WINSPOOL.@]
3525 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3527 FIXME("(%p): stub\n", hPrinter
);
3531 /*****************************************************************************
3532 * StartDocPrinterA [WINSPOOL.@]
3534 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3536 UNICODE_STRING usBuffer
;
3538 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3541 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3542 or one (DOC_INFO_3) extra DWORDs */
3546 doc2W
.JobId
= doc2
->JobId
;
3549 doc2W
.dwMode
= doc2
->dwMode
;
3552 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3553 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3554 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3558 SetLastError(ERROR_INVALID_LEVEL
);
3562 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3564 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3565 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3566 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3571 /*****************************************************************************
3572 * StartDocPrinterW [WINSPOOL.@]
3574 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3576 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3577 opened_printer_t
*printer
;
3578 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3579 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3580 JOB_INFO_1W job_info
;
3581 DWORD needed
, ret
= 0;
3586 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3587 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3588 debugstr_w(doc
->pDatatype
));
3590 if(Level
< 1 || Level
> 3)
3592 SetLastError(ERROR_INVALID_LEVEL
);
3596 EnterCriticalSection(&printer_handles_cs
);
3597 printer
= get_opened_printer(hPrinter
);
3600 SetLastError(ERROR_INVALID_HANDLE
);
3606 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3610 /* Even if we're printing to a file we still add a print job, we'll
3611 just ignore the spool file name */
3613 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3615 ERR("AddJob failed gle %u\n", GetLastError());
3619 /* use pOutputFile only, when it is a real filename */
3620 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3621 filename
= doc
->pOutputFile
;
3623 filename
= addjob
->Path
;
3625 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3626 if(hf
== INVALID_HANDLE_VALUE
)
3629 memset(&job_info
, 0, sizeof(job_info
));
3630 job_info
.pDocument
= doc
->pDocName
;
3631 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3633 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3634 printer
->doc
->hf
= hf
;
3635 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3636 job
= get_job(hPrinter
, ret
);
3637 job
->portname
= strdupW(doc
->pOutputFile
);
3640 LeaveCriticalSection(&printer_handles_cs
);
3645 /*****************************************************************************
3646 * StartPagePrinter [WINSPOOL.@]
3648 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3650 FIXME("(%p): stub\n", hPrinter
);
3654 /*****************************************************************************
3655 * GetFormA [WINSPOOL.@]
3657 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3658 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3660 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3661 Level
,pForm
,cbBuf
,pcbNeeded
);
3665 /*****************************************************************************
3666 * GetFormW [WINSPOOL.@]
3668 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3669 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3671 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3672 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3676 /*****************************************************************************
3677 * SetFormA [WINSPOOL.@]
3679 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3682 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3686 /*****************************************************************************
3687 * SetFormW [WINSPOOL.@]
3689 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3692 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3696 /*****************************************************************************
3697 * ReadPrinter [WINSPOOL.@]
3699 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3700 LPDWORD pNoBytesRead
)
3702 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3706 /*****************************************************************************
3707 * ResetPrinterA [WINSPOOL.@]
3709 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3711 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3715 /*****************************************************************************
3716 * ResetPrinterW [WINSPOOL.@]
3718 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3720 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3724 /*****************************************************************************
3725 * get_filename_from_reg [internal]
3727 * Get ValueName from hkey storing result in out
3728 * when the Value in the registry has only a filename, use driverdir as prefix
3729 * outlen is space left in out
3730 * String is stored either as unicode or ascii
3734 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3735 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3737 WCHAR filename
[MAX_PATH
];
3741 LPWSTR buffer
= filename
;
3745 size
= sizeof(filename
);
3747 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3748 if (ret
== ERROR_MORE_DATA
) {
3749 TRACE("need dynamic buffer: %u\n", size
);
3750 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3752 /* No Memory is bad */
3756 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3759 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3760 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3766 /* do we have a full path ? */
3767 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3768 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3771 /* we must build the full Path */
3773 if ((out
) && (outlen
> dirlen
)) {
3774 lstrcpyW((LPWSTR
)out
, driverdir
);
3782 /* write the filename */
3783 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3784 if ((out
) && (outlen
>= size
)) {
3785 lstrcpyW((LPWSTR
)out
, ptr
);
3792 ptr
+= lstrlenW(ptr
)+1;
3793 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3796 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3798 /* write the multisz-termination */
3799 if (type
== REG_MULTI_SZ
) {
3800 size
= sizeof(WCHAR
);
3803 if (out
&& (outlen
>= size
)) {
3804 memset (out
, 0, size
);
3810 /*****************************************************************************
3811 * WINSPOOL_GetStringFromReg
3813 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3814 * String is stored as unicode.
3816 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3817 DWORD buflen
, DWORD
*needed
)
3819 DWORD sz
= buflen
, type
;
3822 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3823 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3824 WARN("Got ret = %d\n", ret
);
3828 /* add space for terminating '\0' */
3829 sz
+= sizeof(WCHAR
);
3833 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3838 /*****************************************************************************
3839 * WINSPOOL_GetDefaultDevMode
3841 * Get a default DevMode values for wineps.
3845 static void WINSPOOL_GetDefaultDevMode(
3847 DWORD buflen
, DWORD
*needed
)
3850 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3852 /* fill default DEVMODE - should be read from ppd... */
3853 ZeroMemory( &dm
, sizeof(dm
) );
3854 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3855 dm
.dmSpecVersion
= DM_SPECVERSION
;
3856 dm
.dmDriverVersion
= 1;
3857 dm
.dmSize
= sizeof(DEVMODEW
);
3858 dm
.dmDriverExtra
= 0;
3860 DM_ORIENTATION
| DM_PAPERSIZE
|
3861 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3864 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3865 DM_YRESOLUTION
| DM_TTOPTION
;
3867 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3868 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3869 dm
.u1
.s1
.dmPaperLength
= 2970;
3870 dm
.u1
.s1
.dmPaperWidth
= 2100;
3872 dm
.u1
.s1
.dmScale
= 100;
3873 dm
.u1
.s1
.dmCopies
= 1;
3874 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3875 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3878 dm
.dmYResolution
= 300; /* 300dpi */
3879 dm
.dmTTOption
= DMTT_BITMAP
;
3882 /* dm.dmLogPixels */
3883 /* dm.dmBitsPerPel */
3884 /* dm.dmPelsWidth */
3885 /* dm.dmPelsHeight */
3886 /* dm.u2.dmDisplayFlags */
3887 /* dm.dmDisplayFrequency */
3888 /* dm.dmICMMethod */
3889 /* dm.dmICMIntent */
3890 /* dm.dmMediaType */
3891 /* dm.dmDitherType */
3892 /* dm.dmReserved1 */
3893 /* dm.dmReserved2 */
3894 /* dm.dmPanningWidth */
3895 /* dm.dmPanningHeight */
3897 if(buflen
>= sizeof(DEVMODEW
))
3898 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
3899 *needed
= sizeof(DEVMODEW
);
3902 /*****************************************************************************
3903 * WINSPOOL_GetDevModeFromReg
3905 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3906 * DevMode is stored either as unicode or ascii.
3908 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3910 DWORD buflen
, DWORD
*needed
)
3912 DWORD sz
= buflen
, type
;
3915 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3916 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3917 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3918 if (sz
< sizeof(DEVMODEA
))
3920 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3923 /* ensures that dmSize is not erratically bogus if registry is invalid */
3924 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3925 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3926 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3927 if (ptr
&& (buflen
>= sz
)) {
3928 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3929 memcpy(ptr
, dmW
, sz
);
3930 HeapFree(GetProcessHeap(),0,dmW
);
3936 /*********************************************************************
3937 * WINSPOOL_GetPrinter_1
3939 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3941 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3942 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3944 DWORD size
, left
= cbBuf
;
3945 BOOL space
= (cbBuf
> 0);
3950 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3951 if(space
&& size
<= left
) {
3952 pi1
->pName
= (LPWSTR
)ptr
;
3960 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3961 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3962 if(space
&& size
<= left
) {
3963 pi1
->pDescription
= (LPWSTR
)ptr
;
3971 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3972 if(space
&& size
<= left
) {
3973 pi1
->pComment
= (LPWSTR
)ptr
;
3981 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3983 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3984 memset(pi1
, 0, sizeof(*pi1
));
3988 /*********************************************************************
3989 * WINSPOOL_GetPrinter_2
3991 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3993 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3994 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3996 DWORD size
, left
= cbBuf
;
3997 BOOL space
= (cbBuf
> 0);
4002 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4003 if(space
&& size
<= left
) {
4004 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4011 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
4012 if(space
&& size
<= left
) {
4013 pi2
->pShareName
= (LPWSTR
)ptr
;
4020 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4021 if(space
&& size
<= left
) {
4022 pi2
->pPortName
= (LPWSTR
)ptr
;
4029 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
4030 if(space
&& size
<= left
) {
4031 pi2
->pDriverName
= (LPWSTR
)ptr
;
4038 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4039 if(space
&& size
<= left
) {
4040 pi2
->pComment
= (LPWSTR
)ptr
;
4047 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
4048 if(space
&& size
<= left
) {
4049 pi2
->pLocation
= (LPWSTR
)ptr
;
4056 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
4057 if(space
&& size
<= left
) {
4058 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4067 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
4068 if(space
&& size
<= left
) {
4069 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4076 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
4077 if(space
&& size
<= left
) {
4078 pi2
->pSepFile
= (LPWSTR
)ptr
;
4085 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
4086 if(space
&& size
<= left
) {
4087 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4094 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
4095 if(space
&& size
<= left
) {
4096 pi2
->pDatatype
= (LPWSTR
)ptr
;
4103 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
4104 if(space
&& size
<= left
) {
4105 pi2
->pParameters
= (LPWSTR
)ptr
;
4113 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4114 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
4115 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
4116 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
4117 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
4120 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4121 memset(pi2
, 0, sizeof(*pi2
));
4126 /*********************************************************************
4127 * WINSPOOL_GetPrinter_4
4129 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4131 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4132 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4134 DWORD size
, left
= cbBuf
;
4135 BOOL space
= (cbBuf
> 0);
4140 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4141 if(space
&& size
<= left
) {
4142 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4150 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4153 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4154 memset(pi4
, 0, sizeof(*pi4
));
4159 /*********************************************************************
4160 * WINSPOOL_GetPrinter_5
4162 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4164 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4165 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4167 DWORD size
, left
= cbBuf
;
4168 BOOL space
= (cbBuf
> 0);
4173 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4174 if(space
&& size
<= left
) {
4175 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4182 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4183 if(space
&& size
<= left
) {
4184 pi5
->pPortName
= (LPWSTR
)ptr
;
4192 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4193 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
4194 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
4197 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4198 memset(pi5
, 0, sizeof(*pi5
));
4203 /*********************************************************************
4204 * WINSPOOL_GetPrinter_7
4206 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4208 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4209 DWORD cbBuf
, LPDWORD pcbNeeded
)
4211 DWORD size
, left
= cbBuf
;
4212 BOOL space
= (cbBuf
> 0);
4217 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
4220 size
= sizeof(pi7
->pszObjectGUID
);
4222 if (space
&& size
<= left
) {
4223 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4230 /* We do not have a Directory Service */
4231 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4234 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4235 memset(pi7
, 0, sizeof(*pi7
));
4240 /*********************************************************************
4241 * WINSPOOL_GetPrinter_9
4243 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4245 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4246 DWORD cbBuf
, LPDWORD pcbNeeded
)
4249 BOOL space
= (cbBuf
> 0);
4253 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
4254 if(space
&& size
<= cbBuf
) {
4255 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4262 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
4263 if(space
&& size
<= cbBuf
) {
4264 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4270 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4271 memset(pi9
, 0, sizeof(*pi9
));
4276 /*****************************************************************************
4277 * GetPrinterW [WINSPOOL.@]
4279 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4280 DWORD cbBuf
, LPDWORD pcbNeeded
)
4282 DWORD size
, needed
= 0, err
;
4287 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4289 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
4292 SetLastError( err
);
4299 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4301 size
= sizeof(PRINTER_INFO_2W
);
4303 ptr
= pPrinter
+ size
;
4305 memset(pPrinter
, 0, size
);
4310 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
4317 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4319 size
= sizeof(PRINTER_INFO_4W
);
4321 ptr
= pPrinter
+ size
;
4323 memset(pPrinter
, 0, size
);
4328 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
4336 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4338 size
= sizeof(PRINTER_INFO_5W
);
4340 ptr
= pPrinter
+ size
;
4342 memset(pPrinter
, 0, size
);
4348 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4356 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4358 size
= sizeof(PRINTER_INFO_6
);
4359 if (size
<= cbBuf
) {
4360 /* FIXME: We do not update the status yet */
4361 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4373 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4375 size
= sizeof(PRINTER_INFO_7W
);
4376 if (size
<= cbBuf
) {
4377 ptr
= pPrinter
+ size
;
4379 memset(pPrinter
, 0, size
);
4385 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4392 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4393 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4397 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4399 size
= sizeof(PRINTER_INFO_9W
);
4401 ptr
= pPrinter
+ size
;
4403 memset(pPrinter
, 0, size
);
4409 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4416 FIXME("Unimplemented level %d\n", Level
);
4417 SetLastError(ERROR_INVALID_LEVEL
);
4418 RegCloseKey(hkeyPrinter
);
4422 RegCloseKey(hkeyPrinter
);
4424 TRACE("returning %d needed = %d\n", ret
, needed
);
4425 if(pcbNeeded
) *pcbNeeded
= needed
;
4427 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4431 /*****************************************************************************
4432 * GetPrinterA [WINSPOOL.@]
4434 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4435 DWORD cbBuf
, LPDWORD pcbNeeded
)
4441 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4443 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4445 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4446 HeapFree(GetProcessHeap(), 0, buf
);
4451 /*****************************************************************************
4452 * WINSPOOL_EnumPrintersW
4454 * Implementation of EnumPrintersW
4456 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4457 DWORD dwLevel
, LPBYTE lpbPrinters
,
4458 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4459 LPDWORD lpdwReturned
)
4462 HKEY hkeyPrinters
, hkeyPrinter
;
4463 WCHAR PrinterName
[255];
4464 DWORD needed
= 0, number
= 0;
4465 DWORD used
, i
, left
;
4469 memset(lpbPrinters
, 0, cbBuf
);
4475 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4476 if(dwType
== PRINTER_ENUM_DEFAULT
)
4479 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4480 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4481 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4483 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4489 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4490 FIXME("dwType = %08x\n", dwType
);
4491 SetLastError(ERROR_INVALID_FLAGS
);
4495 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4497 ERR("Can't create Printers key\n");
4501 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4502 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4503 RegCloseKey(hkeyPrinters
);
4504 ERR("Can't query Printers key\n");
4507 TRACE("Found %d printers\n", number
);
4511 used
= number
* sizeof(PRINTER_INFO_1W
);
4514 used
= number
* sizeof(PRINTER_INFO_2W
);
4517 used
= number
* sizeof(PRINTER_INFO_4W
);
4520 used
= number
* sizeof(PRINTER_INFO_5W
);
4524 SetLastError(ERROR_INVALID_LEVEL
);
4525 RegCloseKey(hkeyPrinters
);
4528 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4530 for(i
= 0; i
< number
; i
++) {
4531 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4533 ERR("Can't enum key number %d\n", i
);
4534 RegCloseKey(hkeyPrinters
);
4537 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4538 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4540 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4541 RegCloseKey(hkeyPrinters
);
4546 buf
= lpbPrinters
+ used
;
4547 left
= cbBuf
- used
;
4555 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4558 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4561 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4564 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4567 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4570 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4573 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4576 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4579 ERR("Shouldn't be here!\n");
4580 RegCloseKey(hkeyPrinter
);
4581 RegCloseKey(hkeyPrinters
);
4584 RegCloseKey(hkeyPrinter
);
4586 RegCloseKey(hkeyPrinters
);
4593 memset(lpbPrinters
, 0, cbBuf
);
4594 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4598 *lpdwReturned
= number
;
4599 SetLastError(ERROR_SUCCESS
);
4604 /******************************************************************
4605 * EnumPrintersW [WINSPOOL.@]
4607 * Enumerates the available printers, print servers and print
4608 * providers, depending on the specified flags, name and level.
4612 * If level is set to 1:
4613 * Returns an array of PRINTER_INFO_1 data structures in the
4614 * lpbPrinters buffer.
4616 * If level is set to 2:
4617 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4618 * Returns an array of PRINTER_INFO_2 data structures in the
4619 * lpbPrinters buffer. Note that according to MSDN also an
4620 * OpenPrinter should be performed on every remote printer.
4622 * If level is set to 4 (officially WinNT only):
4623 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4624 * Fast: Only the registry is queried to retrieve printer names,
4625 * no connection to the driver is made.
4626 * Returns an array of PRINTER_INFO_4 data structures in the
4627 * lpbPrinters buffer.
4629 * If level is set to 5 (officially WinNT4/Win9x only):
4630 * Fast: Only the registry is queried to retrieve printer names,
4631 * no connection to the driver is made.
4632 * Returns an array of PRINTER_INFO_5 data structures in the
4633 * lpbPrinters buffer.
4635 * If level set to 3 or 6+:
4636 * returns zero (failure!)
4638 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4642 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4643 * - Only levels 2, 4 and 5 are implemented at the moment.
4644 * - 16-bit printer drivers are not enumerated.
4645 * - Returned amount of bytes used/needed does not match the real Windoze
4646 * implementation (as in this implementation, all strings are part
4647 * of the buffer, whereas Win32 keeps them somewhere else)
4648 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4651 * - In a regular Wine installation, no registry settings for printers
4652 * exist, which makes this function return an empty list.
4654 BOOL WINAPI
EnumPrintersW(
4655 DWORD dwType
, /* [in] Types of print objects to enumerate */
4656 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4657 DWORD dwLevel
, /* [in] type of printer info structure */
4658 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4659 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4660 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4661 LPDWORD lpdwReturned
/* [out] number of entries returned */
4664 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4665 lpdwNeeded
, lpdwReturned
);
4668 /******************************************************************
4669 * EnumPrintersA [WINSPOOL.@]
4674 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4675 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4678 UNICODE_STRING pNameU
;
4682 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4683 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4685 pNameW
= asciitounicode(&pNameU
, pName
);
4687 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4688 MS Office need this */
4689 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4691 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4693 RtlFreeUnicodeString(&pNameU
);
4695 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4697 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4701 /*****************************************************************************
4702 * WINSPOOL_GetDriverInfoFromReg [internal]
4704 * Enters the information from the registry into the DRIVER_INFO struct
4707 * zero if the printer driver does not exist in the registry
4708 * (only if Level > 1) otherwise nonzero
4710 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4713 const printenv_t
* env
,
4715 LPBYTE ptr
, /* DRIVER_INFO */
4716 LPBYTE pDriverStrings
, /* strings buffer */
4717 DWORD cbBuf
, /* size of string buffer */
4718 LPDWORD pcbNeeded
) /* space needed for str. */
4722 WCHAR driverdir
[MAX_PATH
];
4724 LPBYTE strPtr
= pDriverStrings
;
4725 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4727 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4728 debugstr_w(DriverName
), env
,
4729 Level
, di
, pDriverStrings
, cbBuf
);
4731 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4733 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4734 if (*pcbNeeded
<= cbBuf
)
4735 strcpyW((LPWSTR
)strPtr
, DriverName
);
4737 /* pName for level 1 has a different offset! */
4739 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4743 /* .cVersion and .pName for level > 1 */
4745 di
->cVersion
= env
->driverversion
;
4746 di
->pName
= (LPWSTR
) strPtr
;
4747 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4750 /* Reserve Space for the largest subdir and a Backslash*/
4751 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4752 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4753 /* Should never Fail */
4756 lstrcatW(driverdir
, env
->versionsubdir
);
4757 lstrcatW(driverdir
, backslashW
);
4759 /* dirlen must not include the terminating zero */
4760 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4762 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4763 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4764 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4769 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4772 if (*pcbNeeded
<= cbBuf
) {
4773 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4774 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4775 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4778 /* .pDriverPath is the Graphics rendering engine.
4779 The full Path is required to avoid a crash in some apps */
4780 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4782 if (*pcbNeeded
<= cbBuf
)
4783 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4785 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4786 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4789 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4790 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4792 if (*pcbNeeded
<= cbBuf
)
4793 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4795 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4796 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4799 /* .pConfigFile is the Driver user Interface */
4800 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4802 if (*pcbNeeded
<= cbBuf
)
4803 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4805 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4806 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4810 RegCloseKey(hkeyDriver
);
4811 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4816 RegCloseKey(hkeyDriver
);
4817 FIXME("level 5: incomplete\n");
4822 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4824 if (*pcbNeeded
<= cbBuf
)
4825 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4827 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4828 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4831 /* .pDependentFiles */
4832 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4834 if (*pcbNeeded
<= cbBuf
)
4835 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4837 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4838 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4840 else if (GetVersion() & 0x80000000) {
4841 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4842 size
= 2 * sizeof(WCHAR
);
4844 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4846 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4847 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4850 /* .pMonitorName is the optional Language Monitor */
4851 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4853 if (*pcbNeeded
<= cbBuf
)
4854 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4856 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4857 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4860 /* .pDefaultDataType */
4861 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4863 if(*pcbNeeded
<= cbBuf
)
4864 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4866 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4867 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4871 RegCloseKey(hkeyDriver
);
4872 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4876 /* .pszzPreviousNames */
4877 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4879 if(*pcbNeeded
<= cbBuf
)
4880 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4882 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4883 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4887 RegCloseKey(hkeyDriver
);
4888 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4892 /* support is missing, but not important enough for a FIXME */
4893 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4896 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
4898 if(*pcbNeeded
<= cbBuf
)
4899 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
4901 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4902 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4906 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
4908 if(*pcbNeeded
<= cbBuf
)
4909 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
4911 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4912 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4915 /* .pszHardwareID */
4916 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
4918 if(*pcbNeeded
<= cbBuf
)
4919 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
4921 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4922 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4926 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
4928 if(*pcbNeeded
<= cbBuf
)
4929 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
4931 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4932 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4936 RegCloseKey(hkeyDriver
);
4940 /* support is missing, but not important enough for a FIXME */
4941 TRACE("level 8: incomplete\n");
4943 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4944 RegCloseKey(hkeyDriver
);
4948 /*****************************************************************************
4949 * GetPrinterDriverW [WINSPOOL.@]
4951 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4952 DWORD Level
, LPBYTE pDriverInfo
,
4953 DWORD cbBuf
, LPDWORD pcbNeeded
)
4956 WCHAR DriverName
[100];
4957 DWORD ret
, type
, size
, needed
= 0;
4959 HKEY hkeyPrinter
, hkeyDrivers
;
4960 const printenv_t
* env
;
4962 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4963 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4966 ZeroMemory(pDriverInfo
, cbBuf
);
4968 if (!(name
= get_opened_printer_name(hPrinter
))) {
4969 SetLastError(ERROR_INVALID_HANDLE
);
4973 if (Level
< 1 || Level
== 7 || Level
> 8) {
4974 SetLastError(ERROR_INVALID_LEVEL
);
4978 env
= validate_envW(pEnvironment
);
4979 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4981 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
4984 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
4985 SetLastError( ret
);
4989 size
= sizeof(DriverName
);
4991 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4992 (LPBYTE
)DriverName
, &size
);
4993 RegCloseKey(hkeyPrinter
);
4994 if(ret
!= ERROR_SUCCESS
) {
4995 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4999 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5001 ERR("Can't create Drivers key\n");
5005 size
= di_sizeof
[Level
];
5006 if ((size
<= cbBuf
) && pDriverInfo
)
5007 ptr
= pDriverInfo
+ size
;
5009 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5010 env
, Level
, pDriverInfo
, ptr
,
5011 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5013 RegCloseKey(hkeyDrivers
);
5017 RegCloseKey(hkeyDrivers
);
5019 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5020 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5021 if(cbBuf
>= size
+ needed
) return TRUE
;
5022 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5026 /*****************************************************************************
5027 * GetPrinterDriverA [WINSPOOL.@]
5029 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5030 DWORD Level
, LPBYTE pDriverInfo
,
5031 DWORD cbBuf
, LPDWORD pcbNeeded
)
5034 UNICODE_STRING pEnvW
;
5040 ZeroMemory(pDriverInfo
, cbBuf
);
5041 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5044 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5045 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5048 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5050 HeapFree(GetProcessHeap(), 0, buf
);
5052 RtlFreeUnicodeString(&pEnvW
);
5056 /*****************************************************************************
5057 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5059 * Return the PATH for the Printer-Drivers (UNICODE)
5062 * pName [I] Servername (NT only) or NULL (local Computer)
5063 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5064 * Level [I] Structure-Level (must be 1)
5065 * pDriverDirectory [O] PTR to Buffer that receives the Result
5066 * cbBuf [I] Size of Buffer at pDriverDirectory
5067 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5068 * required for pDriverDirectory
5071 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5072 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5073 * if cbBuf is too small
5075 * Native Values returned in pDriverDirectory on Success:
5076 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5077 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5078 *| win9x(Windows 4.0): "%winsysdir%"
5080 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5083 *- Only NULL or "" is supported for pName
5086 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5087 DWORD Level
, LPBYTE pDriverDirectory
,
5088 DWORD cbBuf
, LPDWORD pcbNeeded
)
5090 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5091 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5093 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5096 /* (Level != 1) is ignored in win9x */
5097 SetLastError(ERROR_INVALID_LEVEL
);
5100 if (pcbNeeded
== NULL
) {
5101 /* (pcbNeeded == NULL) is ignored in win9x */
5102 SetLastError(RPC_X_NULL_REF_POINTER
);
5106 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5107 pDriverDirectory
, cbBuf
, pcbNeeded
);
5112 /*****************************************************************************
5113 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5115 * Return the PATH for the Printer-Drivers (ANSI)
5117 * See GetPrinterDriverDirectoryW.
5120 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5123 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5124 DWORD Level
, LPBYTE pDriverDirectory
,
5125 DWORD cbBuf
, LPDWORD pcbNeeded
)
5127 UNICODE_STRING nameW
, environmentW
;
5130 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5131 WCHAR
*driverDirectoryW
= NULL
;
5133 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5134 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5136 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5138 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5139 else nameW
.Buffer
= NULL
;
5140 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5141 else environmentW
.Buffer
= NULL
;
5143 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5144 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5147 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5148 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5150 *pcbNeeded
= needed
;
5151 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
5153 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5155 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5157 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5158 RtlFreeUnicodeString(&environmentW
);
5159 RtlFreeUnicodeString(&nameW
);
5164 /*****************************************************************************
5165 * AddPrinterDriverA [WINSPOOL.@]
5167 * See AddPrinterDriverW.
5170 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5172 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5173 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5176 /******************************************************************************
5177 * AddPrinterDriverW (WINSPOOL.@)
5179 * Install a Printer Driver
5182 * pName [I] Servername or NULL (local Computer)
5183 * level [I] Level for the supplied DRIVER_INFO_*W struct
5184 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5191 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5193 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5194 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5197 /*****************************************************************************
5198 * AddPrintProcessorA [WINSPOOL.@]
5200 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5201 LPSTR pPrintProcessorName
)
5203 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5204 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5208 /*****************************************************************************
5209 * AddPrintProcessorW [WINSPOOL.@]
5211 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5212 LPWSTR pPrintProcessorName
)
5214 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5215 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5219 /*****************************************************************************
5220 * AddPrintProvidorA [WINSPOOL.@]
5222 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5224 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5228 /*****************************************************************************
5229 * AddPrintProvidorW [WINSPOOL.@]
5231 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5233 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5237 /*****************************************************************************
5238 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5240 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5241 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5243 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5244 pDevModeOutput
, pDevModeInput
);
5248 /*****************************************************************************
5249 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5251 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5252 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5254 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5255 pDevModeOutput
, pDevModeInput
);
5259 /*****************************************************************************
5260 * PrinterProperties [WINSPOOL.@]
5262 * Displays a dialog to set the properties of the printer.
5265 * nonzero on success or zero on failure
5268 * implemented as stub only
5270 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5271 HANDLE hPrinter
/* [in] handle to printer object */
5273 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5274 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5278 /*****************************************************************************
5279 * EnumJobsA [WINSPOOL.@]
5282 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5283 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5286 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5287 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5289 if(pcbNeeded
) *pcbNeeded
= 0;
5290 if(pcReturned
) *pcReturned
= 0;
5295 /*****************************************************************************
5296 * EnumJobsW [WINSPOOL.@]
5299 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5300 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5303 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5304 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5306 if(pcbNeeded
) *pcbNeeded
= 0;
5307 if(pcReturned
) *pcReturned
= 0;
5311 /*****************************************************************************
5312 * WINSPOOL_EnumPrinterDrivers [internal]
5314 * Delivers information about all printer drivers installed on the
5315 * localhost or a given server
5318 * nonzero on success or zero on failure. If the buffer for the returned
5319 * information is too small the function will return an error
5322 * - only implemented for localhost, foreign hosts will return an error
5324 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5325 DWORD Level
, LPBYTE pDriverInfo
,
5327 DWORD cbBuf
, LPDWORD pcbNeeded
,
5328 LPDWORD pcFound
, DWORD data_offset
)
5332 const printenv_t
* env
;
5334 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5335 debugstr_w(pName
), debugstr_w(pEnvironment
),
5336 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5338 env
= validate_envW(pEnvironment
);
5339 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5343 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5345 ERR("Can't open Drivers key\n");
5349 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5350 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5351 RegCloseKey(hkeyDrivers
);
5352 ERR("Can't query Drivers key\n");
5355 TRACE("Found %d Drivers\n", *pcFound
);
5357 /* get size of single struct
5358 * unicode and ascii structure have the same size
5360 size
= di_sizeof
[Level
];
5362 if (data_offset
== 0)
5363 data_offset
= size
* (*pcFound
);
5364 *pcbNeeded
= data_offset
;
5366 for( i
= 0; i
< *pcFound
; i
++) {
5367 WCHAR DriverNameW
[255];
5368 PBYTE table_ptr
= NULL
;
5369 PBYTE data_ptr
= NULL
;
5372 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5374 ERR("Can't enum key number %d\n", i
);
5375 RegCloseKey(hkeyDrivers
);
5379 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5380 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5381 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5382 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5384 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5385 env
, Level
, table_ptr
, data_ptr
,
5386 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5388 RegCloseKey(hkeyDrivers
);
5392 *pcbNeeded
+= needed
;
5395 RegCloseKey(hkeyDrivers
);
5397 if(cbBuf
< *pcbNeeded
){
5398 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5405 /*****************************************************************************
5406 * EnumPrinterDriversW [WINSPOOL.@]
5408 * see function EnumPrinterDrivers for RETURNS, BUGS
5410 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5411 LPBYTE pDriverInfo
, DWORD cbBuf
,
5412 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5414 static const WCHAR allW
[] = {'a','l','l',0};
5418 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5420 SetLastError(RPC_X_NULL_REF_POINTER
);
5424 /* check for local drivers */
5425 if((pName
) && (pName
[0])) {
5426 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5427 SetLastError(ERROR_ACCESS_DENIED
);
5431 /* check input parameter */
5432 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5433 SetLastError(ERROR_INVALID_LEVEL
);
5437 if(pDriverInfo
&& cbBuf
> 0)
5438 memset( pDriverInfo
, 0, cbBuf
);
5440 /* Exception: pull all printers */
5441 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5443 DWORD i
, needed
, bufsize
= cbBuf
;
5444 DWORD total_needed
= 0;
5445 DWORD total_found
= 0;
5448 /* Precompute the overall total; we need this to know
5449 where pointers end and data begins (i.e. data_offset) */
5450 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5453 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5454 NULL
, 0, 0, &needed
, &found
, 0);
5455 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5456 total_needed
+= needed
;
5457 total_found
+= found
;
5460 data_offset
= di_sizeof
[Level
] * total_found
;
5465 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5468 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5469 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5470 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5472 *pcReturned
+= found
;
5473 *pcbNeeded
= needed
;
5474 data_offset
= needed
;
5475 total_found
+= found
;
5480 /* Normal behavior */
5481 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5482 0, cbBuf
, pcbNeeded
, &found
, 0);
5484 *pcReturned
= found
;
5489 /*****************************************************************************
5490 * EnumPrinterDriversA [WINSPOOL.@]
5492 * see function EnumPrinterDrivers for RETURNS, BUGS
5494 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5495 LPBYTE pDriverInfo
, DWORD cbBuf
,
5496 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5499 UNICODE_STRING pNameW
, pEnvironmentW
;
5500 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5504 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5506 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5507 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5509 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5510 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5512 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5514 HeapFree(GetProcessHeap(), 0, buf
);
5516 RtlFreeUnicodeString(&pNameW
);
5517 RtlFreeUnicodeString(&pEnvironmentW
);
5522 /******************************************************************************
5523 * EnumPortsA (WINSPOOL.@)
5528 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5529 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5532 LPBYTE bufferW
= NULL
;
5533 LPWSTR nameW
= NULL
;
5535 DWORD numentries
= 0;
5538 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5539 cbBuf
, pcbNeeded
, pcReturned
);
5541 /* convert servername to unicode */
5543 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5544 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5545 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5547 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5548 needed
= cbBuf
* sizeof(WCHAR
);
5549 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5550 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5552 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5553 if (pcbNeeded
) needed
= *pcbNeeded
;
5554 /* HeapReAlloc return NULL, when bufferW was NULL */
5555 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5556 HeapAlloc(GetProcessHeap(), 0, needed
);
5558 /* Try again with the large Buffer */
5559 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5561 needed
= pcbNeeded
? *pcbNeeded
: 0;
5562 numentries
= pcReturned
? *pcReturned
: 0;
5565 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5566 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5569 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5570 DWORD entrysize
= 0;
5573 LPPORT_INFO_2W pi2w
;
5574 LPPORT_INFO_2A pi2a
;
5577 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5579 /* First pass: calculate the size for all Entries */
5580 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5581 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5583 while (index
< numentries
) {
5585 needed
+= entrysize
; /* PORT_INFO_?A */
5586 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5588 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5589 NULL
, 0, NULL
, NULL
);
5591 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5592 NULL
, 0, NULL
, NULL
);
5593 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5594 NULL
, 0, NULL
, NULL
);
5596 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5597 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5598 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5601 /* check for errors and quit on failure */
5602 if (cbBuf
< needed
) {
5603 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5607 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5608 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5609 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5610 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5611 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5613 /* Second Pass: Fill the User Buffer (if we have one) */
5614 while ((index
< numentries
) && pPorts
) {
5616 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5617 pi2a
->pPortName
= ptr
;
5618 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5619 ptr
, cbBuf
, NULL
, NULL
);
5623 pi2a
->pMonitorName
= ptr
;
5624 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5625 ptr
, cbBuf
, NULL
, NULL
);
5629 pi2a
->pDescription
= ptr
;
5630 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5631 ptr
, cbBuf
, NULL
, NULL
);
5635 pi2a
->fPortType
= pi2w
->fPortType
;
5636 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5639 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5640 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5641 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5646 if (pcbNeeded
) *pcbNeeded
= needed
;
5647 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5649 HeapFree(GetProcessHeap(), 0, nameW
);
5650 HeapFree(GetProcessHeap(), 0, bufferW
);
5652 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5653 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5659 /******************************************************************************
5660 * EnumPortsW (WINSPOOL.@)
5662 * Enumerate available Ports
5665 * pName [I] Servername or NULL (local Computer)
5666 * Level [I] Structure-Level (1 or 2)
5667 * pPorts [O] PTR to Buffer that receives the Result
5668 * cbBuf [I] Size of Buffer at pPorts
5669 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5670 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5674 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5677 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5680 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5681 cbBuf
, pcbNeeded
, pcReturned
);
5683 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5685 /* Level is not checked in win9x */
5686 if (!Level
|| (Level
> 2)) {
5687 WARN("level (%d) is ignored in win9x\n", Level
);
5688 SetLastError(ERROR_INVALID_LEVEL
);
5691 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5692 SetLastError(RPC_X_NULL_REF_POINTER
);
5696 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5699 /******************************************************************************
5700 * GetDefaultPrinterW (WINSPOOL.@)
5703 * This function must read the value from data 'device' of key
5704 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5706 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5710 WCHAR
*buffer
, *ptr
;
5714 SetLastError(ERROR_INVALID_PARAMETER
);
5718 /* make the buffer big enough for the stuff from the profile/registry,
5719 * the content must fit into the local buffer to compute the correct
5720 * size even if the extern buffer is too small or not given.
5721 * (20 for ,driver,port) */
5723 len
= max(100, (insize
+ 20));
5724 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5726 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5728 SetLastError (ERROR_FILE_NOT_FOUND
);
5732 TRACE("%s\n", debugstr_w(buffer
));
5734 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5736 SetLastError(ERROR_INVALID_NAME
);
5742 *namesize
= strlenW(buffer
) + 1;
5743 if(!name
|| (*namesize
> insize
))
5745 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5749 strcpyW(name
, buffer
);
5752 HeapFree( GetProcessHeap(), 0, buffer
);
5757 /******************************************************************************
5758 * GetDefaultPrinterA (WINSPOOL.@)
5760 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5764 WCHAR
*bufferW
= NULL
;
5768 SetLastError(ERROR_INVALID_PARAMETER
);
5772 if(name
&& *namesize
) {
5774 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5777 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5782 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5786 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5789 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5792 HeapFree( GetProcessHeap(), 0, bufferW
);
5797 /******************************************************************************
5798 * SetDefaultPrinterW (WINSPOOL.204)
5800 * Set the Name of the Default Printer
5803 * pszPrinter [I] Name of the Printer or NULL
5810 * When the Parameter is NULL or points to an Empty String and
5811 * a Default Printer was already present, then this Function changes nothing.
5812 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5813 * the First enumerated local Printer is used.
5816 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5818 WCHAR default_printer
[MAX_PATH
];
5819 LPWSTR buffer
= NULL
;
5825 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5826 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5828 default_printer
[0] = '\0';
5829 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5831 /* if we have a default Printer, do nothing. */
5832 if (GetDefaultPrinterW(default_printer
, &size
))
5836 /* we have no default Printer: search local Printers and use the first */
5837 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5839 default_printer
[0] = '\0';
5840 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5841 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5843 pszPrinter
= default_printer
;
5844 TRACE("using %s\n", debugstr_w(pszPrinter
));
5849 if (pszPrinter
== NULL
) {
5850 TRACE("no local printer found\n");
5851 SetLastError(ERROR_FILE_NOT_FOUND
);
5856 /* "pszPrinter" is never empty or NULL here. */
5857 namelen
= lstrlenW(pszPrinter
);
5858 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5859 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5861 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5862 HeapFree(GetProcessHeap(), 0, buffer
);
5863 SetLastError(ERROR_FILE_NOT_FOUND
);
5867 /* read the devices entry for the printer (driver,port) to build the string for the
5868 default device entry (printer,driver,port) */
5869 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5870 buffer
[namelen
] = ',';
5871 namelen
++; /* move index to the start of the driver */
5873 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5874 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5876 TRACE("set device to %s\n", debugstr_w(buffer
));
5878 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
5879 TRACE("failed to set the device entry: %d\n", GetLastError());
5880 lres
= ERROR_INVALID_PRINTER_NAME
;
5883 /* remove the next section, when INIFileMapping is implemented */
5886 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
5887 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
5894 if (lres
!= ERROR_FILE_NOT_FOUND
)
5895 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
5897 SetLastError(ERROR_INVALID_PRINTER_NAME
);
5901 HeapFree(GetProcessHeap(), 0, buffer
);
5902 return (lres
== ERROR_SUCCESS
);
5905 /******************************************************************************
5906 * SetDefaultPrinterA (WINSPOOL.202)
5908 * See SetDefaultPrinterW.
5911 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5913 LPWSTR bufferW
= NULL
;
5916 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5918 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
5919 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5920 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
5922 res
= SetDefaultPrinterW(bufferW
);
5923 HeapFree(GetProcessHeap(), 0, bufferW
);
5927 /******************************************************************************
5928 * SetPrinterDataExA (WINSPOOL.@)
5930 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5931 LPCSTR pValueName
, DWORD Type
,
5932 LPBYTE pData
, DWORD cbData
)
5934 HKEY hkeyPrinter
, hkeySubkey
;
5937 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5938 debugstr_a(pValueName
), Type
, pData
, cbData
);
5940 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5944 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5946 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5947 RegCloseKey(hkeyPrinter
);
5950 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5951 RegCloseKey(hkeySubkey
);
5952 RegCloseKey(hkeyPrinter
);
5956 /******************************************************************************
5957 * SetPrinterDataExW (WINSPOOL.@)
5959 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5960 LPCWSTR pValueName
, DWORD Type
,
5961 LPBYTE pData
, DWORD cbData
)
5963 HKEY hkeyPrinter
, hkeySubkey
;
5966 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5967 debugstr_w(pValueName
), Type
, pData
, cbData
);
5969 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5973 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5975 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5976 RegCloseKey(hkeyPrinter
);
5979 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5980 RegCloseKey(hkeySubkey
);
5981 RegCloseKey(hkeyPrinter
);
5985 /******************************************************************************
5986 * SetPrinterDataA (WINSPOOL.@)
5988 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5989 LPBYTE pData
, DWORD cbData
)
5991 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5995 /******************************************************************************
5996 * SetPrinterDataW (WINSPOOL.@)
5998 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5999 LPBYTE pData
, DWORD cbData
)
6001 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6005 /******************************************************************************
6006 * GetPrinterDataExA (WINSPOOL.@)
6008 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6009 LPCSTR pValueName
, LPDWORD pType
,
6010 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6012 opened_printer_t
*printer
;
6013 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6016 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6017 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6019 printer
= get_opened_printer(hPrinter
);
6020 if(!printer
) return ERROR_INVALID_HANDLE
;
6022 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6023 if (ret
) return ret
;
6025 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6027 if (printer
->name
) {
6029 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6031 RegCloseKey(hkeyPrinters
);
6034 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6035 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6036 RegCloseKey(hkeyPrinter
);
6037 RegCloseKey(hkeyPrinters
);
6042 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6043 0, pType
, pData
, pcbNeeded
);
6045 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6047 RegCloseKey(hkeySubkey
);
6048 RegCloseKey(hkeyPrinter
);
6049 RegCloseKey(hkeyPrinters
);
6051 TRACE("--> %d\n", ret
);
6055 /******************************************************************************
6056 * GetPrinterDataExW (WINSPOOL.@)
6058 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6059 LPCWSTR pValueName
, LPDWORD pType
,
6060 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6062 opened_printer_t
*printer
;
6063 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6066 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6067 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6069 printer
= get_opened_printer(hPrinter
);
6070 if(!printer
) return ERROR_INVALID_HANDLE
;
6072 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6073 if (ret
) return ret
;
6075 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6077 if (printer
->name
) {
6079 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6081 RegCloseKey(hkeyPrinters
);
6084 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6085 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6086 RegCloseKey(hkeyPrinter
);
6087 RegCloseKey(hkeyPrinters
);
6092 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6093 0, pType
, pData
, pcbNeeded
);
6095 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6097 RegCloseKey(hkeySubkey
);
6098 RegCloseKey(hkeyPrinter
);
6099 RegCloseKey(hkeyPrinters
);
6101 TRACE("--> %d\n", ret
);
6105 /******************************************************************************
6106 * GetPrinterDataA (WINSPOOL.@)
6108 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6109 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6111 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6112 pData
, nSize
, pcbNeeded
);
6115 /******************************************************************************
6116 * GetPrinterDataW (WINSPOOL.@)
6118 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6119 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6121 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6122 pData
, nSize
, pcbNeeded
);
6125 /*******************************************************************************
6126 * EnumPrinterDataExW [WINSPOOL.@]
6128 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6129 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6130 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6132 HKEY hkPrinter
, hkSubKey
;
6133 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6134 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6139 PPRINTER_ENUM_VALUESW ppev
;
6141 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6143 if (pKeyName
== NULL
|| *pKeyName
== 0)
6144 return ERROR_INVALID_PARAMETER
;
6146 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6147 if (ret
!= ERROR_SUCCESS
)
6149 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6154 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6155 if (ret
!= ERROR_SUCCESS
)
6157 r
= RegCloseKey (hkPrinter
);
6158 if (r
!= ERROR_SUCCESS
)
6159 WARN ("RegCloseKey returned %i\n", r
);
6160 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6161 debugstr_w (pKeyName
), ret
);
6165 ret
= RegCloseKey (hkPrinter
);
6166 if (ret
!= ERROR_SUCCESS
)
6168 ERR ("RegCloseKey returned %i\n", ret
);
6169 r
= RegCloseKey (hkSubKey
);
6170 if (r
!= ERROR_SUCCESS
)
6171 WARN ("RegCloseKey returned %i\n", r
);
6175 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6176 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6177 if (ret
!= ERROR_SUCCESS
)
6179 r
= RegCloseKey (hkSubKey
);
6180 if (r
!= ERROR_SUCCESS
)
6181 WARN ("RegCloseKey returned %i\n", r
);
6182 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6186 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6187 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6189 if (cValues
== 0) /* empty key */
6191 r
= RegCloseKey (hkSubKey
);
6192 if (r
!= ERROR_SUCCESS
)
6193 WARN ("RegCloseKey returned %i\n", r
);
6194 *pcbEnumValues
= *pnEnumValues
= 0;
6195 return ERROR_SUCCESS
;
6198 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6200 hHeap
= GetProcessHeap ();
6203 ERR ("GetProcessHeap failed\n");
6204 r
= RegCloseKey (hkSubKey
);
6205 if (r
!= ERROR_SUCCESS
)
6206 WARN ("RegCloseKey returned %i\n", r
);
6207 return ERROR_OUTOFMEMORY
;
6210 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6211 if (lpValueName
== NULL
)
6213 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6214 r
= RegCloseKey (hkSubKey
);
6215 if (r
!= ERROR_SUCCESS
)
6216 WARN ("RegCloseKey returned %i\n", r
);
6217 return ERROR_OUTOFMEMORY
;
6220 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6221 if (lpValue
== NULL
)
6223 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6224 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6225 WARN ("HeapFree failed with code %i\n", GetLastError ());
6226 r
= RegCloseKey (hkSubKey
);
6227 if (r
!= ERROR_SUCCESS
)
6228 WARN ("RegCloseKey returned %i\n", r
);
6229 return ERROR_OUTOFMEMORY
;
6232 TRACE ("pass 1: calculating buffer required for all names and values\n");
6234 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6236 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6238 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6240 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6241 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6242 NULL
, NULL
, lpValue
, &cbValueLen
);
6243 if (ret
!= ERROR_SUCCESS
)
6245 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6246 WARN ("HeapFree failed with code %i\n", GetLastError ());
6247 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6248 WARN ("HeapFree failed with code %i\n", GetLastError ());
6249 r
= RegCloseKey (hkSubKey
);
6250 if (r
!= ERROR_SUCCESS
)
6251 WARN ("RegCloseKey returned %i\n", r
);
6252 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6256 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6257 debugstr_w (lpValueName
), dwIndex
,
6258 cbValueNameLen
+ 1, cbValueLen
);
6260 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6261 cbBufSize
+= cbValueLen
;
6264 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6266 *pcbEnumValues
= cbBufSize
;
6267 *pnEnumValues
= cValues
;
6269 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6271 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6272 WARN ("HeapFree failed with code %i\n", GetLastError ());
6273 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6274 WARN ("HeapFree failed with code %i\n", GetLastError ());
6275 r
= RegCloseKey (hkSubKey
);
6276 if (r
!= ERROR_SUCCESS
)
6277 WARN ("RegCloseKey returned %i\n", r
);
6278 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6279 return ERROR_MORE_DATA
;
6282 TRACE ("pass 2: copying all names and values to buffer\n");
6284 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6285 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6287 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6289 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6290 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6291 NULL
, &dwType
, lpValue
, &cbValueLen
);
6292 if (ret
!= ERROR_SUCCESS
)
6294 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6295 WARN ("HeapFree failed with code %i\n", GetLastError ());
6296 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6297 WARN ("HeapFree failed with code %i\n", GetLastError ());
6298 r
= RegCloseKey (hkSubKey
);
6299 if (r
!= ERROR_SUCCESS
)
6300 WARN ("RegCloseKey returned %i\n", r
);
6301 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6305 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6306 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6307 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6308 pEnumValues
+= cbValueNameLen
;
6310 /* return # of *bytes* (including trailing \0), not # of chars */
6311 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6313 ppev
[dwIndex
].dwType
= dwType
;
6315 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6316 ppev
[dwIndex
].pData
= pEnumValues
;
6317 pEnumValues
+= cbValueLen
;
6319 ppev
[dwIndex
].cbData
= cbValueLen
;
6321 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6322 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6325 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6327 ret
= GetLastError ();
6328 ERR ("HeapFree failed with code %i\n", ret
);
6329 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6330 WARN ("HeapFree failed with code %i\n", GetLastError ());
6331 r
= RegCloseKey (hkSubKey
);
6332 if (r
!= ERROR_SUCCESS
)
6333 WARN ("RegCloseKey returned %i\n", r
);
6337 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6339 ret
= GetLastError ();
6340 ERR ("HeapFree failed with code %i\n", ret
);
6341 r
= RegCloseKey (hkSubKey
);
6342 if (r
!= ERROR_SUCCESS
)
6343 WARN ("RegCloseKey returned %i\n", r
);
6347 ret
= RegCloseKey (hkSubKey
);
6348 if (ret
!= ERROR_SUCCESS
)
6350 ERR ("RegCloseKey returned %i\n", ret
);
6354 return ERROR_SUCCESS
;
6357 /*******************************************************************************
6358 * EnumPrinterDataExA [WINSPOOL.@]
6360 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6361 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6362 * what Windows 2000 SP1 does.
6365 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6366 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6367 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6371 DWORD ret
, dwIndex
, dwBufSize
;
6375 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6377 if (pKeyName
== NULL
|| *pKeyName
== 0)
6378 return ERROR_INVALID_PARAMETER
;
6380 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6383 ret
= GetLastError ();
6384 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6388 hHeap
= GetProcessHeap ();
6391 ERR ("GetProcessHeap failed\n");
6392 return ERROR_OUTOFMEMORY
;
6395 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6396 if (pKeyNameW
== NULL
)
6398 ERR ("Failed to allocate %i bytes from process heap\n",
6399 (LONG
)(len
* sizeof (WCHAR
)));
6400 return ERROR_OUTOFMEMORY
;
6403 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6405 ret
= GetLastError ();
6406 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6407 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6408 WARN ("HeapFree failed with code %i\n", GetLastError ());
6412 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6413 pcbEnumValues
, pnEnumValues
);
6414 if (ret
!= ERROR_SUCCESS
)
6416 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6417 WARN ("HeapFree failed with code %i\n", GetLastError ());
6418 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6422 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6424 ret
= GetLastError ();
6425 ERR ("HeapFree failed with code %i\n", ret
);
6429 if (*pnEnumValues
== 0) /* empty key */
6430 return ERROR_SUCCESS
;
6433 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6435 PPRINTER_ENUM_VALUESW ppev
=
6436 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6438 if (dwBufSize
< ppev
->cbValueName
)
6439 dwBufSize
= ppev
->cbValueName
;
6441 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6442 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6443 dwBufSize
= ppev
->cbData
;
6446 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6448 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6449 if (pBuffer
== NULL
)
6451 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6452 return ERROR_OUTOFMEMORY
;
6455 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6457 PPRINTER_ENUM_VALUESW ppev
=
6458 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6460 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6461 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6465 ret
= GetLastError ();
6466 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6467 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6468 WARN ("HeapFree failed with code %i\n", GetLastError ());
6472 memcpy (ppev
->pValueName
, pBuffer
, len
);
6474 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6476 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6477 ppev
->dwType
!= REG_MULTI_SZ
)
6480 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6481 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6484 ret
= GetLastError ();
6485 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6486 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6487 WARN ("HeapFree failed with code %i\n", GetLastError ());
6491 memcpy (ppev
->pData
, pBuffer
, len
);
6493 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6494 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6497 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6499 ret
= GetLastError ();
6500 ERR ("HeapFree failed with code %i\n", ret
);
6504 return ERROR_SUCCESS
;
6507 /******************************************************************************
6508 * AbortPrinter (WINSPOOL.@)
6510 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6512 FIXME("(%p), stub!\n", hPrinter
);
6516 /******************************************************************************
6517 * AddPortA (WINSPOOL.@)
6522 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6524 LPWSTR nameW
= NULL
;
6525 LPWSTR monitorW
= NULL
;
6529 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6532 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6533 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6534 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6538 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6539 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6540 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6542 res
= AddPortW(nameW
, hWnd
, monitorW
);
6543 HeapFree(GetProcessHeap(), 0, nameW
);
6544 HeapFree(GetProcessHeap(), 0, monitorW
);
6548 /******************************************************************************
6549 * AddPortW (WINSPOOL.@)
6551 * Add a Port for a specific Monitor
6554 * pName [I] Servername or NULL (local Computer)
6555 * hWnd [I] Handle to parent Window for the Dialog-Box
6556 * pMonitorName [I] Name of the Monitor that manage the Port
6563 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6565 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6567 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6569 if (!pMonitorName
) {
6570 SetLastError(RPC_X_NULL_REF_POINTER
);
6574 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6577 /******************************************************************************
6578 * AddPortExA (WINSPOOL.@)
6583 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6586 PORT_INFO_2A
* pi2A
;
6587 LPWSTR nameW
= NULL
;
6588 LPWSTR monitorW
= NULL
;
6592 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6594 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6595 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6597 if ((level
< 1) || (level
> 2)) {
6598 SetLastError(ERROR_INVALID_LEVEL
);
6603 SetLastError(ERROR_INVALID_PARAMETER
);
6608 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6609 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6610 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6614 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6615 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6616 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6619 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6621 if (pi2A
->pPortName
) {
6622 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6623 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6624 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6628 if (pi2A
->pMonitorName
) {
6629 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6630 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6631 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6634 if (pi2A
->pDescription
) {
6635 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6636 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6637 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6639 pi2W
.fPortType
= pi2A
->fPortType
;
6640 pi2W
.Reserved
= pi2A
->Reserved
;
6643 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6645 HeapFree(GetProcessHeap(), 0, nameW
);
6646 HeapFree(GetProcessHeap(), 0, monitorW
);
6647 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6648 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6649 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6654 /******************************************************************************
6655 * AddPortExW (WINSPOOL.@)
6657 * Add a Port for a specific Monitor, without presenting a user interface
6660 * pName [I] Servername or NULL (local Computer)
6661 * level [I] Structure-Level (1 or 2) for pBuffer
6662 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6663 * pMonitorName [I] Name of the Monitor that manage the Port
6670 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6674 pi2
= (PORT_INFO_2W
*) pBuffer
;
6676 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6677 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6678 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6679 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6681 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6683 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6684 SetLastError(ERROR_INVALID_PARAMETER
);
6688 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6691 /******************************************************************************
6692 * AddPrinterConnectionA (WINSPOOL.@)
6694 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6696 FIXME("%s\n", debugstr_a(pName
));
6700 /******************************************************************************
6701 * AddPrinterConnectionW (WINSPOOL.@)
6703 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6705 FIXME("%s\n", debugstr_w(pName
));
6709 /******************************************************************************
6710 * AddPrinterDriverExW (WINSPOOL.@)
6712 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6715 * pName [I] Servername or NULL (local Computer)
6716 * level [I] Level for the supplied DRIVER_INFO_*W struct
6717 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6718 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6725 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6727 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6729 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6731 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6732 SetLastError(ERROR_INVALID_LEVEL
);
6737 SetLastError(ERROR_INVALID_PARAMETER
);
6741 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6744 /******************************************************************************
6745 * AddPrinterDriverExA (WINSPOOL.@)
6747 * See AddPrinterDriverExW.
6750 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6752 DRIVER_INFO_8A
*diA
;
6754 LPWSTR nameW
= NULL
;
6759 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6761 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6762 ZeroMemory(&diW
, sizeof(diW
));
6764 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6765 SetLastError(ERROR_INVALID_LEVEL
);
6770 SetLastError(ERROR_INVALID_PARAMETER
);
6774 /* convert servername to unicode */
6776 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6777 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6778 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6782 diW
.cVersion
= diA
->cVersion
;
6785 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6786 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6787 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6790 if (diA
->pEnvironment
) {
6791 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6792 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6793 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6796 if (diA
->pDriverPath
) {
6797 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6798 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6799 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6802 if (diA
->pDataFile
) {
6803 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6804 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6805 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6808 if (diA
->pConfigFile
) {
6809 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6810 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6811 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6814 if ((Level
> 2) && diA
->pDependentFiles
) {
6815 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6816 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6817 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6818 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6821 if ((Level
> 2) && diA
->pMonitorName
) {
6822 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6823 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6824 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6827 if ((Level
> 3) && diA
->pDefaultDataType
) {
6828 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6829 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6830 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6833 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6834 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6835 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6836 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6837 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6840 if ((Level
> 5) && diA
->pszMfgName
) {
6841 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6842 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6843 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6846 if ((Level
> 5) && diA
->pszOEMUrl
) {
6847 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6848 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6849 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6852 if ((Level
> 5) && diA
->pszHardwareID
) {
6853 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6854 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6855 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6858 if ((Level
> 5) && diA
->pszProvider
) {
6859 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6860 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6861 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6865 FIXME("level %u is incomplete\n", Level
);
6868 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6869 TRACE("got %u with %u\n", res
, GetLastError());
6870 HeapFree(GetProcessHeap(), 0, nameW
);
6871 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6872 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6873 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6874 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6875 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6876 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6877 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6878 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6879 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6880 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6881 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6882 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6883 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6885 TRACE("=> %u with %u\n", res
, GetLastError());
6889 /******************************************************************************
6890 * ConfigurePortA (WINSPOOL.@)
6892 * See ConfigurePortW.
6895 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6897 LPWSTR nameW
= NULL
;
6898 LPWSTR portW
= NULL
;
6902 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6904 /* convert servername to unicode */
6906 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6907 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6908 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6911 /* convert portname to unicode */
6913 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6914 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6915 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6918 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6919 HeapFree(GetProcessHeap(), 0, nameW
);
6920 HeapFree(GetProcessHeap(), 0, portW
);
6924 /******************************************************************************
6925 * ConfigurePortW (WINSPOOL.@)
6927 * Display the Configuration-Dialog for a specific Port
6930 * pName [I] Servername or NULL (local Computer)
6931 * hWnd [I] Handle to parent Window for the Dialog-Box
6932 * pPortName [I] Name of the Port, that should be configured
6939 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6942 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6944 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6947 SetLastError(RPC_X_NULL_REF_POINTER
);
6951 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6954 /******************************************************************************
6955 * ConnectToPrinterDlg (WINSPOOL.@)
6957 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6959 FIXME("%p %x\n", hWnd
, Flags
);
6963 /******************************************************************************
6964 * DeletePrinterConnectionA (WINSPOOL.@)
6966 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6968 FIXME("%s\n", debugstr_a(pName
));
6972 /******************************************************************************
6973 * DeletePrinterConnectionW (WINSPOOL.@)
6975 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6977 FIXME("%s\n", debugstr_w(pName
));
6981 /******************************************************************************
6982 * DeletePrinterDriverExW (WINSPOOL.@)
6984 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6985 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6990 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6991 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6993 if(pName
&& pName
[0])
6995 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6996 SetLastError(ERROR_INVALID_PARAMETER
);
7002 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7003 SetLastError(ERROR_INVALID_PARAMETER
);
7007 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7011 ERR("Can't open drivers key\n");
7015 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7018 RegCloseKey(hkey_drivers
);
7023 /******************************************************************************
7024 * DeletePrinterDriverExA (WINSPOOL.@)
7026 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7027 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7029 UNICODE_STRING NameW
, EnvW
, DriverW
;
7032 asciitounicode(&NameW
, pName
);
7033 asciitounicode(&EnvW
, pEnvironment
);
7034 asciitounicode(&DriverW
, pDriverName
);
7036 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7038 RtlFreeUnicodeString(&DriverW
);
7039 RtlFreeUnicodeString(&EnvW
);
7040 RtlFreeUnicodeString(&NameW
);
7045 /******************************************************************************
7046 * DeletePrinterDataExW (WINSPOOL.@)
7048 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7051 FIXME("%p %s %s\n", hPrinter
,
7052 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7053 return ERROR_INVALID_PARAMETER
;
7056 /******************************************************************************
7057 * DeletePrinterDataExA (WINSPOOL.@)
7059 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7062 FIXME("%p %s %s\n", hPrinter
,
7063 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7064 return ERROR_INVALID_PARAMETER
;
7067 /******************************************************************************
7068 * DeletePrintProcessorA (WINSPOOL.@)
7070 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7072 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7073 debugstr_a(pPrintProcessorName
));
7077 /******************************************************************************
7078 * DeletePrintProcessorW (WINSPOOL.@)
7080 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7082 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7083 debugstr_w(pPrintProcessorName
));
7087 /******************************************************************************
7088 * DeletePrintProvidorA (WINSPOOL.@)
7090 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7092 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7093 debugstr_a(pPrintProviderName
));
7097 /******************************************************************************
7098 * DeletePrintProvidorW (WINSPOOL.@)
7100 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7102 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7103 debugstr_w(pPrintProviderName
));
7107 /******************************************************************************
7108 * EnumFormsA (WINSPOOL.@)
7110 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7111 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7113 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7114 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7118 /******************************************************************************
7119 * EnumFormsW (WINSPOOL.@)
7121 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7122 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7124 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7125 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7129 /*****************************************************************************
7130 * EnumMonitorsA [WINSPOOL.@]
7132 * See EnumMonitorsW.
7135 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7136 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7139 LPBYTE bufferW
= NULL
;
7140 LPWSTR nameW
= NULL
;
7142 DWORD numentries
= 0;
7145 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7146 cbBuf
, pcbNeeded
, pcReturned
);
7148 /* convert servername to unicode */
7150 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7151 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7152 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7154 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7155 needed
= cbBuf
* sizeof(WCHAR
);
7156 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7157 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7159 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7160 if (pcbNeeded
) needed
= *pcbNeeded
;
7161 /* HeapReAlloc return NULL, when bufferW was NULL */
7162 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7163 HeapAlloc(GetProcessHeap(), 0, needed
);
7165 /* Try again with the large Buffer */
7166 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7168 numentries
= pcReturned
? *pcReturned
: 0;
7171 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7172 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7175 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7176 DWORD entrysize
= 0;
7179 LPMONITOR_INFO_2W mi2w
;
7180 LPMONITOR_INFO_2A mi2a
;
7182 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7183 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7185 /* First pass: calculate the size for all Entries */
7186 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7187 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7189 while (index
< numentries
) {
7191 needed
+= entrysize
; /* MONITOR_INFO_?A */
7192 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7194 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7195 NULL
, 0, NULL
, NULL
);
7197 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7198 NULL
, 0, NULL
, NULL
);
7199 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7200 NULL
, 0, NULL
, NULL
);
7202 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7203 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7204 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7207 /* check for errors and quit on failure */
7208 if (cbBuf
< needed
) {
7209 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7213 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7214 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7215 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7216 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7217 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7219 /* Second Pass: Fill the User Buffer (if we have one) */
7220 while ((index
< numentries
) && pMonitors
) {
7222 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7224 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7225 ptr
, cbBuf
, NULL
, NULL
);
7229 mi2a
->pEnvironment
= ptr
;
7230 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7231 ptr
, cbBuf
, NULL
, NULL
);
7235 mi2a
->pDLLName
= ptr
;
7236 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7237 ptr
, cbBuf
, NULL
, NULL
);
7241 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7242 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7243 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7247 if (pcbNeeded
) *pcbNeeded
= needed
;
7248 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7250 HeapFree(GetProcessHeap(), 0, nameW
);
7251 HeapFree(GetProcessHeap(), 0, bufferW
);
7253 TRACE("returning %d with %d (%d byte for %d entries)\n",
7254 (res
), GetLastError(), needed
, numentries
);
7260 /*****************************************************************************
7261 * EnumMonitorsW [WINSPOOL.@]
7263 * Enumerate available Port-Monitors
7266 * pName [I] Servername or NULL (local Computer)
7267 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7268 * pMonitors [O] PTR to Buffer that receives the Result
7269 * cbBuf [I] Size of Buffer at pMonitors
7270 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7271 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7275 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7278 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7279 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7282 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7283 cbBuf
, pcbNeeded
, pcReturned
);
7285 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7287 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7288 SetLastError(RPC_X_NULL_REF_POINTER
);
7292 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7295 /******************************************************************************
7296 * SpoolerInit (WINSPOOL.@)
7298 * Initialize the Spooler
7305 * The function fails on windows, when the spooler service is not running
7308 BOOL WINAPI
SpoolerInit(void)
7311 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7315 /******************************************************************************
7316 * XcvDataW (WINSPOOL.@)
7318 * Execute commands in the Printmonitor DLL
7321 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7322 * pszDataName [i] Name of the command to execute
7323 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7324 * cbInputData [i] Size in Bytes of Buffer at pInputData
7325 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7326 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7327 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7328 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7335 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7336 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7338 * Minimal List of commands, that a Printmonitor DLL should support:
7340 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7341 *| "AddPort" : Add a Port
7342 *| "DeletePort": Delete a Port
7344 * Many Printmonitors support additional commands. Examples for localspl.dll:
7345 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7346 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7349 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7350 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7351 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7353 opened_printer_t
*printer
;
7355 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7356 pInputData
, cbInputData
, pOutputData
,
7357 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7359 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7361 printer
= get_opened_printer(hXcv
);
7362 if (!printer
|| (!printer
->backend_printer
)) {
7363 SetLastError(ERROR_INVALID_HANDLE
);
7367 if (!pcbOutputNeeded
) {
7368 SetLastError(ERROR_INVALID_PARAMETER
);
7372 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7373 SetLastError(RPC_X_NULL_REF_POINTER
);
7377 *pcbOutputNeeded
= 0;
7379 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7380 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7384 /*****************************************************************************
7385 * EnumPrinterDataA [WINSPOOL.@]
7388 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7389 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7390 DWORD cbData
, LPDWORD pcbData
)
7392 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7393 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7394 return ERROR_NO_MORE_ITEMS
;
7397 /*****************************************************************************
7398 * EnumPrinterDataW [WINSPOOL.@]
7401 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7402 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7403 DWORD cbData
, LPDWORD pcbData
)
7405 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7406 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7407 return ERROR_NO_MORE_ITEMS
;
7410 /*****************************************************************************
7411 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7414 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7415 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7416 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7418 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7419 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7420 pcbNeeded
, pcReturned
);
7424 /*****************************************************************************
7425 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7428 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7429 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7430 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7432 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7433 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7434 pcbNeeded
, pcReturned
);
7438 /*****************************************************************************
7439 * EnumPrintProcessorsA [WINSPOOL.@]
7441 * See EnumPrintProcessorsW.
7444 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7445 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7448 LPBYTE bufferW
= NULL
;
7449 LPWSTR nameW
= NULL
;
7452 DWORD numentries
= 0;
7455 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7456 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7458 /* convert names to unicode */
7460 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7461 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7462 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7465 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7466 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7467 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7470 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7471 needed
= cbBuf
* sizeof(WCHAR
);
7472 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7473 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7475 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7476 if (pcbNeeded
) needed
= *pcbNeeded
;
7477 /* HeapReAlloc return NULL, when bufferW was NULL */
7478 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7479 HeapAlloc(GetProcessHeap(), 0, needed
);
7481 /* Try again with the large Buffer */
7482 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7484 numentries
= pcReturned
? *pcReturned
: 0;
7488 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7491 PPRINTPROCESSOR_INFO_1W ppiw
;
7492 PPRINTPROCESSOR_INFO_1A ppia
;
7494 /* First pass: calculate the size for all Entries */
7495 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7496 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7498 while (index
< numentries
) {
7500 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7501 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7503 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7504 NULL
, 0, NULL
, NULL
);
7506 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7507 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7510 /* check for errors and quit on failure */
7511 if (cbBuf
< needed
) {
7512 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7517 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7518 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7519 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7520 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7521 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7523 /* Second Pass: Fill the User Buffer (if we have one) */
7524 while ((index
< numentries
) && pPPInfo
) {
7526 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7528 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7529 ptr
, cbBuf
, NULL
, NULL
);
7533 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7534 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7539 if (pcbNeeded
) *pcbNeeded
= needed
;
7540 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7542 HeapFree(GetProcessHeap(), 0, nameW
);
7543 HeapFree(GetProcessHeap(), 0, envW
);
7544 HeapFree(GetProcessHeap(), 0, bufferW
);
7546 TRACE("returning %d with %d (%d byte for %d entries)\n",
7547 (res
), GetLastError(), needed
, numentries
);
7552 /*****************************************************************************
7553 * EnumPrintProcessorsW [WINSPOOL.@]
7555 * Enumerate available Print Processors
7558 * pName [I] Servername or NULL (local Computer)
7559 * pEnvironment [I] Printing-Environment or NULL (Default)
7560 * Level [I] Structure-Level (Only 1 is allowed)
7561 * pPPInfo [O] PTR to Buffer that receives the Result
7562 * cbBuf [I] Size of Buffer at pPPInfo
7563 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7564 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7568 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7571 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7572 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7575 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7576 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7578 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7580 if (!pcbNeeded
|| !pcReturned
) {
7581 SetLastError(RPC_X_NULL_REF_POINTER
);
7585 if (!pPPInfo
&& (cbBuf
> 0)) {
7586 SetLastError(ERROR_INVALID_USER_BUFFER
);
7590 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7591 cbBuf
, pcbNeeded
, pcReturned
);
7594 /*****************************************************************************
7595 * ExtDeviceMode [WINSPOOL.@]
7598 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7599 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7602 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7603 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7604 debugstr_a(pProfile
), fMode
);
7608 /*****************************************************************************
7609 * FindClosePrinterChangeNotification [WINSPOOL.@]
7612 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7614 FIXME("Stub: %p\n", hChange
);
7618 /*****************************************************************************
7619 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7622 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7623 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7625 FIXME("Stub: %p %x %x %p\n",
7626 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7627 return INVALID_HANDLE_VALUE
;
7630 /*****************************************************************************
7631 * FindNextPrinterChangeNotification [WINSPOOL.@]
7634 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7635 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7637 FIXME("Stub: %p %p %p %p\n",
7638 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7642 /*****************************************************************************
7643 * FreePrinterNotifyInfo [WINSPOOL.@]
7646 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7648 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7652 /*****************************************************************************
7655 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7656 * ansi depending on the unicode parameter.
7658 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7668 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7671 memcpy(ptr
, str
, *size
);
7678 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7681 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7688 /*****************************************************************************
7691 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7692 LPDWORD pcbNeeded
, BOOL unicode
)
7694 DWORD size
, left
= cbBuf
;
7695 BOOL space
= (cbBuf
> 0);
7702 ji1
->JobId
= job
->job_id
;
7705 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7706 if(space
&& size
<= left
)
7708 ji1
->pDocument
= (LPWSTR
)ptr
;
7716 if (job
->printer_name
)
7718 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7719 if(space
&& size
<= left
)
7721 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7733 /*****************************************************************************
7736 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7737 LPDWORD pcbNeeded
, BOOL unicode
)
7739 DWORD size
, left
= cbBuf
;
7741 BOOL space
= (cbBuf
> 0);
7743 LPDEVMODEA dmA
= NULL
;
7750 ji2
->JobId
= job
->job_id
;
7753 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7754 if(space
&& size
<= left
)
7756 ji2
->pDocument
= (LPWSTR
)ptr
;
7764 if (job
->printer_name
)
7766 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7767 if(space
&& size
<= left
)
7769 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7782 dmA
= DEVMODEdupWtoA(job
->devmode
);
7783 devmode
= (LPDEVMODEW
) dmA
;
7784 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7788 devmode
= job
->devmode
;
7789 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7793 FIXME("Can't convert DEVMODE W to A\n");
7796 /* align DEVMODE to a DWORD boundary */
7797 shift
= (4 - (*pcbNeeded
& 3)) & 3;
7803 memcpy(ptr
, devmode
, size
-shift
);
7804 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7805 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7818 /*****************************************************************************
7821 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7822 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7825 DWORD needed
= 0, size
;
7829 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7831 EnterCriticalSection(&printer_handles_cs
);
7832 job
= get_job(hPrinter
, JobId
);
7839 size
= sizeof(JOB_INFO_1W
);
7844 memset(pJob
, 0, size
);
7848 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7853 size
= sizeof(JOB_INFO_2W
);
7858 memset(pJob
, 0, size
);
7862 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7867 size
= sizeof(JOB_INFO_3
);
7871 memset(pJob
, 0, size
);
7880 SetLastError(ERROR_INVALID_LEVEL
);
7884 *pcbNeeded
= needed
;
7886 LeaveCriticalSection(&printer_handles_cs
);
7890 /*****************************************************************************
7891 * GetJobA [WINSPOOL.@]
7894 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7895 DWORD cbBuf
, LPDWORD pcbNeeded
)
7897 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7900 /*****************************************************************************
7901 * GetJobW [WINSPOOL.@]
7904 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7905 DWORD cbBuf
, LPDWORD pcbNeeded
)
7907 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7910 /*****************************************************************************
7913 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7916 char *unixname
, *cmdA
;
7918 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7924 if(!(unixname
= wine_get_unix_file_name(filename
)))
7927 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7928 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7929 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7931 TRACE("printing with: %s\n", cmdA
);
7933 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7938 ERR("pipe() failed!\n");
7942 if ((pid
= fork()) == 0)
7948 /* reset signals that we previously set to SIG_IGN */
7949 signal(SIGPIPE
, SIG_DFL
);
7951 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7956 ERR("fork() failed!\n");
7960 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7961 write(fds
[1], buf
, no_read
);
7968 wret
= waitpid(pid
, &status
, 0);
7969 } while (wret
< 0 && errno
== EINTR
);
7972 ERR("waitpid() failed!\n");
7975 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
7977 ERR("child process failed! %d\n", status
);
7984 if(file_fd
!= -1) close(file_fd
);
7985 if(fds
[0] != -1) close(fds
[0]);
7986 if(fds
[1] != -1) close(fds
[1]);
7988 HeapFree(GetProcessHeap(), 0, cmdA
);
7989 HeapFree(GetProcessHeap(), 0, unixname
);
7996 /*****************************************************************************
7999 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8002 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8005 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8006 sprintfW(cmd
, fmtW
, printer_name
);
8008 r
= schedule_pipe(cmd
, filename
);
8010 HeapFree(GetProcessHeap(), 0, cmd
);
8014 #ifdef SONAME_LIBCUPS
8015 /*****************************************************************************
8016 * get_cups_jobs_ticket_options
8018 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8019 * The CUPS scheduler only looks for these in Print-File requests, and since
8020 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8023 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8025 FILE *fp
= fopen( file
, "r" );
8026 char buf
[257]; /* DSC max of 256 + '\0' */
8027 const char *ps_adobe
= "%!PS-Adobe-";
8028 const char *cups_job
= "%cupsJobTicket:";
8030 if (!fp
) return num_options
;
8031 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8032 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8033 while (fgets( buf
, sizeof(buf
), fp
))
8035 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8036 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8045 /*****************************************************************************
8048 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8050 #ifdef SONAME_LIBCUPS
8053 char *unixname
, *queue
, *unix_doc_title
;
8056 int num_options
= 0, i
;
8057 cups_option_t
*options
= NULL
;
8059 if(!(unixname
= wine_get_unix_file_name(filename
)))
8062 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8063 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8064 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8066 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8067 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8068 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8070 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8072 TRACE( "printing via cups with options:\n" );
8073 for (i
= 0; i
< num_options
; i
++)
8074 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8076 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8078 pcupsFreeOptions( num_options
, options
);
8080 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8081 HeapFree(GetProcessHeap(), 0, queue
);
8082 HeapFree(GetProcessHeap(), 0, unixname
);
8088 return schedule_lpr(printer_name
, filename
);
8092 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8099 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8103 if(HIWORD(wparam
) == BN_CLICKED
)
8105 if(LOWORD(wparam
) == IDOK
)
8108 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8111 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8112 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8114 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8116 WCHAR caption
[200], message
[200];
8119 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8120 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
8121 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8122 if(mb_ret
== IDCANCEL
)
8124 HeapFree(GetProcessHeap(), 0, filename
);
8128 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8129 if(hf
== INVALID_HANDLE_VALUE
)
8131 WCHAR caption
[200], message
[200];
8133 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8134 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
8135 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8136 HeapFree(GetProcessHeap(), 0, filename
);
8140 DeleteFileW(filename
);
8141 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8143 EndDialog(hwnd
, IDOK
);
8146 if(LOWORD(wparam
) == IDCANCEL
)
8148 EndDialog(hwnd
, IDCANCEL
);
8157 /*****************************************************************************
8160 static BOOL
get_filename(LPWSTR
*filename
)
8162 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8163 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8166 /*****************************************************************************
8169 static BOOL
schedule_file(LPCWSTR filename
)
8171 LPWSTR output
= NULL
;
8173 if(get_filename(&output
))
8176 TRACE("copy to %s\n", debugstr_w(output
));
8177 r
= CopyFileW(filename
, output
, FALSE
);
8178 HeapFree(GetProcessHeap(), 0, output
);
8184 /*****************************************************************************
8187 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8189 int in_fd
, out_fd
, no_read
;
8192 char *unixname
, *outputA
;
8195 if(!(unixname
= wine_get_unix_file_name(filename
)))
8198 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8199 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8200 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8202 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8203 in_fd
= open(unixname
, O_RDONLY
);
8204 if(out_fd
== -1 || in_fd
== -1)
8207 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8208 write(out_fd
, buf
, no_read
);
8212 if(in_fd
!= -1) close(in_fd
);
8213 if(out_fd
!= -1) close(out_fd
);
8214 HeapFree(GetProcessHeap(), 0, outputA
);
8215 HeapFree(GetProcessHeap(), 0, unixname
);
8219 /*****************************************************************************
8220 * ScheduleJob [WINSPOOL.@]
8223 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8225 opened_printer_t
*printer
;
8227 struct list
*cursor
, *cursor2
;
8229 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8230 EnterCriticalSection(&printer_handles_cs
);
8231 printer
= get_opened_printer(hPrinter
);
8235 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8237 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8240 if(job
->job_id
!= dwJobID
) continue;
8242 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8243 if(hf
!= INVALID_HANDLE_VALUE
)
8245 PRINTER_INFO_5W
*pi5
= NULL
;
8246 LPWSTR portname
= job
->portname
;
8250 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8251 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8255 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8256 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8257 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8258 portname
= pi5
->pPortName
;
8260 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8261 debugstr_w(portname
));
8265 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8266 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8268 DWORD type
, count
= sizeof(output
);
8269 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8272 if(output
[0] == '|')
8274 ret
= schedule_pipe(output
+ 1, job
->filename
);
8278 ret
= schedule_unixfile(output
, job
->filename
);
8280 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8282 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8284 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8286 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8288 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8290 ret
= schedule_file(job
->filename
);
8294 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8296 HeapFree(GetProcessHeap(), 0, pi5
);
8298 DeleteFileW(job
->filename
);
8300 list_remove(cursor
);
8301 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8302 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8303 HeapFree(GetProcessHeap(), 0, job
->portname
);
8304 HeapFree(GetProcessHeap(), 0, job
->filename
);
8305 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8306 HeapFree(GetProcessHeap(), 0, job
);
8310 LeaveCriticalSection(&printer_handles_cs
);
8314 /*****************************************************************************
8315 * StartDocDlgA [WINSPOOL.@]
8317 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8319 UNICODE_STRING usBuffer
;
8322 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8325 docW
.cbSize
= sizeof(docW
);
8326 if (doc
->lpszDocName
)
8328 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8329 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
8331 if (doc
->lpszOutput
)
8333 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8334 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
8336 if (doc
->lpszDatatype
)
8338 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8339 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
8341 docW
.fwType
= doc
->fwType
;
8343 retW
= StartDocDlgW(hPrinter
, &docW
);
8347 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8348 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8349 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8350 HeapFree(GetProcessHeap(), 0, retW
);
8353 HeapFree(GetProcessHeap(), 0, datatypeW
);
8354 HeapFree(GetProcessHeap(), 0, outputW
);
8355 HeapFree(GetProcessHeap(), 0, docnameW
);
8360 /*****************************************************************************
8361 * StartDocDlgW [WINSPOOL.@]
8363 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8364 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8365 * port is "FILE:". Also returns the full path if passed a relative path.
8367 * The caller should free the returned string from the process heap.
8369 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8374 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8376 PRINTER_INFO_5W
*pi5
;
8377 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8378 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8380 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8381 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8382 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8384 HeapFree(GetProcessHeap(), 0, pi5
);
8387 HeapFree(GetProcessHeap(), 0, pi5
);
8390 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8394 if (get_filename(&name
))
8396 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8398 HeapFree(GetProcessHeap(), 0, name
);
8401 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8402 GetFullPathNameW(name
, len
, ret
, NULL
);
8403 HeapFree(GetProcessHeap(), 0, name
);
8408 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8411 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8412 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8414 attr
= GetFileAttributesW(ret
);
8415 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8417 HeapFree(GetProcessHeap(), 0, ret
);