4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
48 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
49 #define GetCurrentProcess GetCurrentProcess_Mac
50 #define GetCurrentThread GetCurrentThread_Mac
51 #define LoadResource LoadResource_Mac
52 #define AnimatePalette AnimatePalette_Mac
53 #define EqualRgn EqualRgn_Mac
54 #define FillRgn FillRgn_Mac
55 #define FrameRgn FrameRgn_Mac
56 #define GetPixel GetPixel_Mac
57 #define InvertRgn InvertRgn_Mac
58 #define LineTo LineTo_Mac
59 #define OffsetRgn OffsetRgn_Mac
60 #define PaintRgn PaintRgn_Mac
61 #define Polygon Polygon_Mac
62 #define ResizePalette ResizePalette_Mac
63 #define SetRectRgn SetRectRgn_Mac
64 #define EqualRect EqualRect_Mac
65 #define FillRect FillRect_Mac
66 #define FrameRect FrameRect_Mac
67 #define GetCursor GetCursor_Mac
68 #define InvertRect InvertRect_Mac
69 #define OffsetRect OffsetRect_Mac
70 #define PtInRect PtInRect_Mac
71 #define SetCursor SetCursor_Mac
72 #define SetRect SetRect_Mac
73 #define ShowCursor ShowCursor_Mac
74 #define UnionRect UnionRect_Mac
75 #include <ApplicationServices/ApplicationServices.h>
76 #undef GetCurrentProcess
77 #undef GetCurrentThread
105 #define NONAMELESSUNION
106 #define NONAMELESSSTRUCT
107 #include "wine/library.h"
111 #include "winerror.h"
114 #include "winspool.h"
115 #include "winternl.h"
116 #include "wine/windef16.h"
117 #include "wine/unicode.h"
118 #include "wine/debug.h"
119 #include "wine/list.h"
122 #include "ddk/winsplp.h"
125 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
127 /* ############################### */
129 static CRITICAL_SECTION printer_handles_cs;
130 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
132 0, 0, &printer_handles_cs,
133 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
134 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
136 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
138 /* ############################### */
153 HANDLE backend_printer;
164 WCHAR *document_title;
174 LPCWSTR versionregpath;
175 LPCWSTR versionsubdir;
178 /* ############################### */
180 static opened_printer_t **printer_handles;
181 static UINT nb_printer_handles;
182 static LONG next_job_id = 1;
184 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
185 WORD fwCapability, LPSTR lpszOutput,
187 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
188 LPSTR lpszDevice, LPSTR lpszPort,
189 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
192 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
193 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
194 'c','o','n','t','r','o','l','\\',
195 'P','r','i','n','t','\\',
196 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
197 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
199 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
200 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
201 'C','o','n','t','r','o','l','\\',
202 'P','r','i','n','t','\\',
203 'P','r','i','n','t','e','r','s',0};
205 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
207 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
208 'M','i','c','r','o','s','o','f','t','\\',
209 'W','i','n','d','o','w','s',' ','N','T','\\',
210 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
211 'W','i','n','d','o','w','s',0};
213 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
214 'M','i','c','r','o','s','o','f','t','\\',
215 'W','i','n','d','o','w','s',' ','N','T','\\',
216 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
217 'D','e','v','i','c','e','s',0};
219 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
220 'M','i','c','r','o','s','o','f','t','\\',
221 'W','i','n','d','o','w','s',' ','N','T','\\',
222 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
223 'P','o','r','t','s',0};
225 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
226 'M','i','c','r','o','s','o','f','t','\\',
227 'W','i','n','d','o','w','s',' ','N','T','\\',
228 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
229 'P','r','i','n','t','e','r','P','o','r','t','s',0};
231 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
232 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
233 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
234 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
235 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
236 static const WCHAR subdir_x64W[] = {'x','6','4',0};
237 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
238 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
239 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
240 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
241 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
243 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
245 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
246 static const WCHAR backslashW[] = {'\\',0};
247 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
248 'i','o','n',' ','F','i','l','e',0};
249 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
250 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
251 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
252 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
253 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
254 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
255 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
256 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
257 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
258 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
259 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
260 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
261 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
262 static const WCHAR NameW[] = {'N','a','m','e',0};
263 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
264 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
265 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
266 static const WCHAR PortW[] = {'P','o','r','t',0};
267 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
268 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
269 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
270 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
271 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
272 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
273 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
274 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
275 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
276 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
277 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
278 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
279 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
280 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
281 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
282 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
283 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
284 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
285 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
286 static WCHAR rawW[] = {'R','A','W',0};
287 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
288 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
289 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
290 static const WCHAR commaW[] = {',',0};
291 static WCHAR emptyStringW[] = {0};
293 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
295 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
296 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
297 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
299 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
300 'D','o','c','u','m','e','n','t',0};
302 static const WCHAR PPD_Overrides[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
303 static const WCHAR DefaultPageSize[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
305 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
306 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
307 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
308 0, sizeof(DRIVER_INFO_8W)};
311 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
312 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
313 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
314 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
315 sizeof(PRINTER_INFO_9W)};
317 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
318 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
319 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
321 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
323 /******************************************************************
324 * validate the user-supplied printing-environment [internal]
327 * env [I] PTR to Environment-String or NULL
331 * Success: PTR to printenv_t
334 * An empty string is handled the same way as NULL.
335 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
339 static const printenv_t * validate_envW(LPCWSTR env)
341 const printenv_t *result = NULL;
344 TRACE("testing %s\n", debugstr_w(env));
347 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
349 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
351 result = all_printenv[i];
356 if (result == NULL) {
357 FIXME("unsupported Environment: %s\n", debugstr_w(env));
358 SetLastError(ERROR_INVALID_ENVIRONMENT);
360 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
364 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
366 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
372 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
373 if passed a NULL string. This returns NULLs to the result.
375 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
379 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
380 return usBufferPtr->Buffer;
382 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
386 static LPWSTR strdupW(LPCWSTR p)
392 len = (strlenW(p) + 1) * sizeof(WCHAR);
393 ret = HeapAlloc(GetProcessHeap(), 0, len);
398 static LPSTR strdupWtoA( LPCWSTR str )
403 if (!str) return NULL;
404 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
405 ret = HeapAlloc( GetProcessHeap(), 0, len );
406 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
410 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
414 if (!dm) return NULL;
415 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
416 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
420 /***********************************************************
422 * Creates an ansi copy of supplied devmode
424 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
429 if (!dmW) return NULL;
430 size = dmW->dmSize - CCHDEVICENAME -
431 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
433 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
434 if (!dmA) return NULL;
436 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
437 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
439 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
441 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
442 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
446 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
447 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
448 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
449 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
451 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
455 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
460 /******************************************************************
461 * verify, that the filename is a local file
464 static inline BOOL is_local_file(LPWSTR name)
466 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
469 /* ################################ */
471 static int multi_sz_lenA(const char *str)
473 const char *ptr = str;
477 ptr += lstrlenA(ptr) + 1;
480 return ptr - str + 1;
483 /*****************************************************************************
486 * Return DWORD associated with name from hkey.
488 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
490 DWORD sz = sizeof(DWORD), type, value = 0;
493 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
495 if (ret != ERROR_SUCCESS)
497 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
500 if (type != REG_DWORD)
502 ERR( "Got type %d\n", type );
508 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
510 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
513 /******************************************************************
515 * Get the pointer to the opened printer referred by the handle
517 static opened_printer_t *get_opened_printer(HANDLE hprn)
519 UINT_PTR idx = (UINT_PTR)hprn;
520 opened_printer_t *ret = NULL;
522 EnterCriticalSection(&printer_handles_cs);
524 if ((idx > 0) && (idx <= nb_printer_handles)) {
525 ret = printer_handles[idx - 1];
527 LeaveCriticalSection(&printer_handles_cs);
531 /******************************************************************
532 * get_opened_printer_name
533 * Get the pointer to the opened printer name referred by the handle
535 static LPCWSTR get_opened_printer_name(HANDLE hprn)
537 opened_printer_t *printer = get_opened_printer(hprn);
538 if(!printer) return NULL;
539 return printer->name;
542 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
548 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
551 err = RegOpenKeyW( printers, name, key );
552 if (err) err = ERROR_INVALID_PRINTER_NAME;
553 RegCloseKey( printers );
557 /******************************************************************
558 * WINSPOOL_GetOpenedPrinterRegKey
561 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
563 LPCWSTR name = get_opened_printer_name(hPrinter);
565 if(!name) return ERROR_INVALID_HANDLE;
566 return open_printer_reg_key( name, phkey );
570 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
573 /* If forcing, or no profile string entry for device yet, set the entry
575 * The always change entry if not WINEPS yet is discussable.
578 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
580 !strstr(qbuf,"WINEPS.DRV")
582 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
585 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
586 WriteProfileStringA("windows","device",buf);
587 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
588 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
591 HeapFree(GetProcessHeap(),0,buf);
595 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
599 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
601 di3.pName = (WCHAR*)name;
602 di3.pEnvironment = envname_x86W;
603 di3.pDriverPath = driver_nt;
605 di3.pConfigFile = driver_nt;
606 di3.pDefaultDataType = rawW;
608 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
609 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
612 di3.pEnvironment = envname_win40W;
613 di3.pDriverPath = driver_9x;
614 di3.pConfigFile = driver_9x;
615 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
616 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
621 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
625 static inline char *expand_env_string( char *str, DWORD type )
627 if (type == REG_EXPAND_SZ)
630 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
631 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
634 ExpandEnvironmentStringsA( str, tmp, needed );
635 HeapFree( GetProcessHeap(), 0, str );
642 static char *get_fallback_ppd_name( const char *printer_name )
644 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
645 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
649 const char *data_dir, *filename;
651 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
653 const char *value_name = NULL;
655 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
656 value_name = printer_name;
657 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
658 value_name = "generic";
662 ret = HeapAlloc( GetProcessHeap(), 0, needed );
663 if (!ret) return NULL;
664 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
667 if (ret) return expand_env_string( ret, type );
670 if ((data_dir = wine_get_data_dir())) filename = "/generic.ppd";
671 else if ((data_dir = wine_get_build_dir())) filename = "/dlls/wineps.drv/generic.ppd";
674 ERR( "Error getting PPD file name for printer '%s'\n", debugstr_a(printer_name) );
677 ret = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + strlen(filename) + 1 );
680 strcpy( ret, data_dir );
681 strcat( ret, filename );
687 static BOOL copy_file( const char *src, const char *dst )
689 int fds[2] = {-1, -1}, num;
693 fds[0] = open( src, O_RDONLY );
694 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
695 if (fds[0] == -1 || fds[1] == -1) goto fail;
697 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
699 if (num == -1) goto fail;
700 if (write( fds[1], buf, num ) != num) goto fail;
705 if (fds[1] != -1) close( fds[1] );
706 if (fds[0] != -1) close( fds[0] );
710 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
712 char *src = get_fallback_ppd_name( printer_name );
713 char *dst = wine_get_unix_file_name( ppd );
716 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
718 if (!src || !dst) goto fail;
720 if (symlink( src, dst ) == -1)
721 if (errno != ENOSYS || !copy_file( src, dst ))
726 HeapFree( GetProcessHeap(), 0, dst );
727 HeapFree( GetProcessHeap(), 0, src );
731 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
733 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
734 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
735 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
737 if (!ppd) return NULL;
739 strcatW( ppd, file_name );
740 strcatW( ppd, dot_ppd );
745 static WCHAR *get_ppd_dir( void )
747 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
749 WCHAR *dir, tmp_path[MAX_PATH];
752 len = GetTempPathW( sizeof(tmp_path) / sizeof(tmp_path[0]), tmp_path );
753 if (!len) return NULL;
754 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
755 if (!dir) return NULL;
757 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
758 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
759 res = CreateDirectoryW( dir, NULL );
760 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
762 HeapFree( GetProcessHeap(), 0, dir );
765 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
769 static void unlink_ppd( const WCHAR *ppd )
771 char *unix_name = wine_get_unix_file_name( ppd );
773 HeapFree( GetProcessHeap(), 0, unix_name );
776 #ifdef SONAME_LIBCUPS
778 static void *cupshandle;
781 DO_FUNC(cupsFreeDests); \
782 DO_FUNC(cupsFreeOptions); \
783 DO_FUNC(cupsGetDests); \
784 DO_FUNC(cupsGetOption); \
785 DO_FUNC(cupsGetPPD); \
786 DO_FUNC(cupsParseOptions); \
787 DO_FUNC(cupsPrintFile)
788 #define CUPS_OPT_FUNCS \
791 #define DO_FUNC(f) static typeof(f) *p##f
794 static http_status_t (*pcupsGetPPD3)(http_t *,const char *, time_t *, char *, size_t);
796 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
797 time_t *modtime, char *buffer,
802 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
804 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
806 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
809 ppd = pcupsGetPPD( name );
811 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
813 if (!ppd) return HTTP_NOT_FOUND;
815 if (rename( ppd, buffer ) == -1)
817 BOOL res = copy_file( ppd, buffer );
819 if (!res) return HTTP_NOT_FOUND;
824 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
827 http_status_t http_status;
828 char *unix_name = wine_get_unix_file_name( ppd );
830 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
832 if (!unix_name) return FALSE;
834 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
835 unix_name, strlen( unix_name ) + 1 );
837 if (http_status != HTTP_OK) unlink( unix_name );
838 HeapFree( GetProcessHeap(), 0, unix_name );
840 if (http_status == HTTP_OK) return TRUE;
842 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
843 debugstr_a(printer_name), http_status );
844 return get_fallback_ppd( printer_name, ppd );
847 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
853 value = pcupsGetOption( name, num_options, options );
854 if (!value) return NULL;
856 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
857 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
858 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
863 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
865 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
866 cups_ptype_t ret = 0;
870 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
873 HeapFree( GetProcessHeap(), 0, type );
877 static void load_cups(void)
879 cupshandle = wine_dlopen( SONAME_LIBCUPS, RTLD_NOW, NULL, 0 );
880 if (!cupshandle) return;
882 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
885 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
888 ERR("failed to load symbol %s\n", #x); \
894 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
899 static BOOL CUPS_LoadPrinters(void)
902 BOOL hadprinter = FALSE, haddefault = FALSE;
905 WCHAR *port, *ppd_dir = NULL, *ppd;
906 HKEY hkeyPrinter, hkeyPrinters;
907 WCHAR nameW[MAX_PATH];
908 HANDLE added_printer;
909 cups_ptype_t printer_type;
911 if (!cupshandle) return FALSE;
913 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
915 ERR("Can't create Printers key\n");
919 nrofdests = pcupsGetDests(&dests);
920 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
921 for (i=0;i<nrofdests;i++) {
922 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
923 printer_type = get_cups_printer_type( dests + i );
925 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
927 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
929 TRACE( "skipping scanner-only device\n" );
933 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
934 lstrcpyW(port, CUPS_Port);
935 lstrcatW(port, nameW);
937 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
938 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
939 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
941 TRACE("Printer already exists\n");
942 /* overwrite old LPR:* port */
943 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
944 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
945 /* flag that the PPD file should be checked for an update */
946 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
947 RegCloseKey(hkeyPrinter);
949 BOOL added_driver = FALSE;
951 if (!ppd_dir) ppd_dir = get_ppd_dir();
952 ppd = get_ppd_filename( ppd_dir, nameW );
953 if (get_cups_ppd( dests[i].name, ppd ))
955 added_driver = add_printer_driver( nameW, ppd );
958 HeapFree( GetProcessHeap(), 0, ppd );
961 HeapFree( GetProcessHeap(), 0, port );
965 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
966 pi2.pPrinterName = nameW;
967 pi2.pDatatype = rawW;
968 pi2.pPrintProcessor = WinPrintW;
969 pi2.pDriverName = nameW;
970 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
971 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
972 pi2.pPortName = port;
973 pi2.pParameters = emptyStringW;
974 pi2.pShareName = emptyStringW;
975 pi2.pSepFile = emptyStringW;
977 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
978 if (added_printer) ClosePrinter( added_printer );
979 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
980 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
982 HeapFree( GetProcessHeap(), 0, pi2.pComment );
983 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
985 HeapFree( GetProcessHeap(), 0, port );
988 if (dests[i].is_default) {
989 SetDefaultPrinterW(nameW);
996 RemoveDirectoryW( ppd_dir );
997 HeapFree( GetProcessHeap(), 0, ppd_dir );
1000 if (hadprinter && !haddefault) {
1001 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
1002 SetDefaultPrinterW(nameW);
1004 pcupsFreeDests(nrofdests, dests);
1005 RegCloseKey(hkeyPrinters);
1011 static char *get_queue_name( HANDLE printer, BOOL *cups )
1013 WCHAR *port, *name = NULL;
1014 DWORD err, needed, type;
1020 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1021 if (err) return NULL;
1022 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1024 port = HeapAlloc( GetProcessHeap(), 0, needed );
1025 if (!port) goto end;
1026 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1028 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1030 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1033 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1034 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1037 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1038 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1039 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1041 HeapFree( GetProcessHeap(), 0, port );
1048 static void set_ppd_overrides( HANDLE printer )
1052 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1054 PMPrintSession session = NULL;
1055 PMPageFormat format = NULL;
1057 CFStringRef paper_name;
1060 status = PMCreateSession( &session );
1061 if (status) goto end;
1063 status = PMCreatePageFormat( &format );
1064 if (status) goto end;
1066 status = PMSessionDefaultPageFormat( session, format );
1067 if (status) goto end;
1069 status = PMGetPageFormatPaper( format, &paper );
1070 if (status) goto end;
1072 status = PMPaperGetPPDPaperName( paper, &paper_name );
1073 if (status) goto end;
1076 range.length = CFStringGetLength( paper_name );
1077 size = (range.length + 1) * sizeof(WCHAR);
1079 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1080 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1081 wstr[range.length] = 0;
1084 if (format) PMRelease( format );
1085 if (session) PMRelease( session );
1088 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1089 HeapFree( GetProcessHeap(), 0, wstr );
1092 static BOOL update_driver( HANDLE printer )
1095 const WCHAR *name = get_opened_printer_name( printer );
1096 WCHAR *ppd_dir, *ppd;
1099 if (!name) return FALSE;
1100 queue_name = get_queue_name( printer, &is_cups );
1101 if (!queue_name) return FALSE;
1103 ppd_dir = get_ppd_dir();
1104 ppd = get_ppd_filename( ppd_dir, name );
1106 #ifdef SONAME_LIBCUPS
1108 ret = get_cups_ppd( queue_name, ppd );
1111 ret = get_fallback_ppd( queue_name, ppd );
1115 TRACE( "updating driver %s\n", debugstr_w( name ) );
1116 ret = add_printer_driver( name, ppd );
1119 HeapFree( GetProcessHeap(), 0, ppd_dir );
1120 HeapFree( GetProcessHeap(), 0, ppd );
1121 HeapFree( GetProcessHeap(), 0, queue_name );
1123 set_ppd_overrides( printer );
1125 /* call into the driver to update the devmode */
1126 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1131 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1133 PRINTER_INFO_2A pinfo2a;
1136 char *e,*s,*name,*prettyname,*devname;
1137 BOOL ret = FALSE, set_default = FALSE;
1138 char *port = NULL, *env_default;
1139 HKEY hkeyPrinter, hkeyPrinters = NULL;
1140 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1141 HANDLE added_printer;
1143 while (isspace(*pent)) pent++;
1144 r = strchr(pent,':');
1146 name_len = r - pent;
1148 name_len = strlen(pent);
1149 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1150 memcpy(name, pent, name_len);
1151 name[name_len] = '\0';
1157 TRACE("name=%s entry=%s\n",name, pent);
1159 if(ispunct(*name)) { /* a tc entry, not a real printer */
1160 TRACE("skipping tc entry\n");
1164 if(strstr(pent,":server")) { /* server only version so skip */
1165 TRACE("skipping server entry\n");
1169 /* Determine whether this is a postscript printer. */
1172 env_default = getenv("PRINTER");
1174 /* Get longest name, usually the one at the right for later display. */
1175 while((s=strchr(prettyname,'|'))) {
1178 while(isspace(*--e)) *e = '\0';
1179 TRACE("\t%s\n", debugstr_a(prettyname));
1180 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1181 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1184 e = prettyname + strlen(prettyname);
1185 while(isspace(*--e)) *e = '\0';
1186 TRACE("\t%s\n", debugstr_a(prettyname));
1187 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1189 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1190 * if it is too long, we use it as comment below. */
1191 devname = prettyname;
1192 if (strlen(devname)>=CCHDEVICENAME-1)
1194 if (strlen(devname)>=CCHDEVICENAME-1) {
1199 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1200 sprintf(port,"LPR:%s",name);
1202 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1204 ERR("Can't create Printers key\n");
1209 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1211 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1212 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1213 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1215 TRACE("Printer already exists\n");
1216 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1217 /* flag that the PPD file should be checked for an update */
1218 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1219 RegCloseKey(hkeyPrinter);
1221 static CHAR data_type[] = "RAW",
1222 print_proc[] = "WinPrint",
1223 comment[] = "WINEPS Printer using LPR",
1224 params[] = "<parameters?>",
1225 share_name[] = "<share name?>",
1226 sep_file[] = "<sep file?>";
1227 BOOL added_driver = FALSE;
1229 if (!ppd_dir) ppd_dir = get_ppd_dir();
1230 ppd = get_ppd_filename( ppd_dir, devnameW );
1231 if (get_fallback_ppd( devname, ppd ))
1233 added_driver = add_printer_driver( devnameW, ppd );
1236 HeapFree( GetProcessHeap(), 0, ppd );
1237 if (!added_driver) goto end;
1239 memset(&pinfo2a,0,sizeof(pinfo2a));
1240 pinfo2a.pPrinterName = devname;
1241 pinfo2a.pDatatype = data_type;
1242 pinfo2a.pPrintProcessor = print_proc;
1243 pinfo2a.pDriverName = devname;
1244 pinfo2a.pComment = comment;
1245 pinfo2a.pLocation = prettyname;
1246 pinfo2a.pPortName = port;
1247 pinfo2a.pParameters = params;
1248 pinfo2a.pShareName = share_name;
1249 pinfo2a.pSepFile = sep_file;
1251 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1252 if (added_printer) ClosePrinter( added_printer );
1253 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1254 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1257 if (isfirst || set_default)
1258 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1261 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1264 RemoveDirectoryW( ppd_dir );
1265 HeapFree( GetProcessHeap(), 0, ppd_dir );
1267 HeapFree(GetProcessHeap(), 0, port);
1268 HeapFree(GetProcessHeap(), 0, name);
1273 PRINTCAP_LoadPrinters(void) {
1274 BOOL hadprinter = FALSE;
1278 BOOL had_bash = FALSE;
1280 f = fopen("/etc/printcap","r");
1284 while(fgets(buf,sizeof(buf),f)) {
1287 end=strchr(buf,'\n');
1291 while(isspace(*start)) start++;
1292 if(*start == '#' || *start == '\0')
1295 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1296 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1297 HeapFree(GetProcessHeap(),0,pent);
1301 if (end && *--end == '\\') {
1308 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1311 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1317 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1318 HeapFree(GetProcessHeap(),0,pent);
1324 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1327 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1328 (lstrlenW(value) + 1) * sizeof(WCHAR));
1330 return ERROR_FILE_NOT_FOUND;
1333 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1335 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1336 DWORD ret = ERROR_FILE_NOT_FOUND;
1338 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1339 and we support these drivers. NT writes DEVMODEW so somehow
1340 we'll need to distinguish between these when we support NT
1345 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1346 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1347 HeapFree( GetProcessHeap(), 0, dmA );
1353 /******************************************************************
1354 * get_servername_from_name (internal)
1356 * for an external server, a copy of the serverpart from the full name is returned
1359 static LPWSTR get_servername_from_name(LPCWSTR name)
1363 WCHAR buffer[MAX_PATH];
1366 if (name == NULL) return NULL;
1367 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1369 server = strdupW(&name[2]); /* skip over both backslash */
1370 if (server == NULL) return NULL;
1372 /* strip '\' and the printername */
1373 ptr = strchrW(server, '\\');
1374 if (ptr) ptr[0] = '\0';
1376 TRACE("found %s\n", debugstr_w(server));
1378 len = sizeof(buffer)/sizeof(buffer[0]);
1379 if (GetComputerNameW(buffer, &len)) {
1380 if (lstrcmpW(buffer, server) == 0) {
1381 /* The requested Servername is our computername */
1382 HeapFree(GetProcessHeap(), 0, server);
1389 /******************************************************************
1390 * get_basename_from_name (internal)
1392 * skip over the serverpart from the full name
1395 static LPCWSTR get_basename_from_name(LPCWSTR name)
1397 if (name == NULL) return NULL;
1398 if ((name[0] == '\\') && (name[1] == '\\')) {
1399 /* skip over the servername and search for the following '\' */
1400 name = strchrW(&name[2], '\\');
1401 if ((name) && (name[1])) {
1402 /* found a separator ('\') followed by a name:
1403 skip over the separator and return the rest */
1408 /* no basename present (we found only a servername) */
1415 static void free_printer_entry( opened_printer_t *printer )
1417 /* the queue is shared, so don't free that here */
1418 HeapFree( GetProcessHeap(), 0, printer->printername );
1419 HeapFree( GetProcessHeap(), 0, printer->name );
1420 HeapFree( GetProcessHeap(), 0, printer->devmode );
1421 HeapFree( GetProcessHeap(), 0, printer );
1424 /******************************************************************
1425 * get_opened_printer_entry
1426 * Get the first place empty in the opened printer table
1429 * - pDefault is ignored
1431 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1433 UINT_PTR handle = nb_printer_handles, i;
1434 jobqueue_t *queue = NULL;
1435 opened_printer_t *printer = NULL;
1437 LPCWSTR printername;
1439 if ((backend == NULL) && !load_backend()) return NULL;
1441 servername = get_servername_from_name(name);
1443 FIXME("server %s not supported\n", debugstr_w(servername));
1444 HeapFree(GetProcessHeap(), 0, servername);
1445 SetLastError(ERROR_INVALID_PRINTER_NAME);
1449 printername = get_basename_from_name(name);
1450 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1452 /* an empty printername is invalid */
1453 if (printername && (!printername[0])) {
1454 SetLastError(ERROR_INVALID_PARAMETER);
1458 EnterCriticalSection(&printer_handles_cs);
1460 for (i = 0; i < nb_printer_handles; i++)
1462 if (!printer_handles[i])
1464 if(handle == nb_printer_handles)
1469 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1470 queue = printer_handles[i]->queue;
1474 if (handle >= nb_printer_handles)
1476 opened_printer_t **new_array;
1477 if (printer_handles)
1478 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1479 (nb_printer_handles + 16) * sizeof(*new_array) );
1481 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1482 (nb_printer_handles + 16) * sizeof(*new_array) );
1489 printer_handles = new_array;
1490 nb_printer_handles += 16;
1493 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1499 /* get a printer handle from the backend */
1500 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1505 /* clone the base name. This is NULL for the printserver */
1506 printer->printername = strdupW(printername);
1508 /* clone the full name */
1509 printer->name = strdupW(name);
1510 if (name && (!printer->name)) {
1515 if (pDefault && pDefault->pDevMode)
1516 printer->devmode = dup_devmode( pDefault->pDevMode );
1519 printer->queue = queue;
1522 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1523 if (!printer->queue) {
1527 list_init(&printer->queue->jobs);
1528 printer->queue->ref = 0;
1530 InterlockedIncrement(&printer->queue->ref);
1532 printer_handles[handle] = printer;
1535 LeaveCriticalSection(&printer_handles_cs);
1536 if (!handle && printer) {
1537 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1538 free_printer_entry( printer );
1541 return (HANDLE)handle;
1544 static void old_printer_check( BOOL delete_phase )
1546 PRINTER_INFO_5W* pi;
1547 DWORD needed, type, num, delete, i, size;
1548 const DWORD one = 1;
1552 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1553 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1555 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1556 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1557 for (i = 0; i < num; i++)
1559 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1560 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1563 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1567 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1573 size = sizeof( delete );
1574 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1578 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1579 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1581 DeletePrinter( hprn );
1582 ClosePrinter( hprn );
1584 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1588 HeapFree(GetProcessHeap(), 0, pi);
1591 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1592 'M','U','T','E','X','_','_','\0'};
1593 static HANDLE init_mutex;
1595 void WINSPOOL_LoadSystemPrinters(void)
1597 HKEY hkey, hkeyPrinters;
1598 DWORD needed, num, i;
1599 WCHAR PrinterName[256];
1602 #ifdef SONAME_LIBCUPS
1606 /* FIXME: The init code should be moved to spoolsv.exe */
1607 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1610 ERR( "Failed to create mutex\n" );
1613 if (GetLastError() == ERROR_ALREADY_EXISTS)
1615 WaitForSingleObject( init_mutex, INFINITE );
1616 ReleaseMutex( init_mutex );
1617 TRACE( "Init already done\n" );
1621 /* This ensures that all printer entries have a valid Name value. If causes
1622 problems later if they don't. If one is found to be missed we create one
1623 and set it equal to the name of the key */
1624 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1625 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1626 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1627 for(i = 0; i < num; i++) {
1628 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1629 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1630 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1631 set_reg_szW(hkey, NameW, PrinterName);
1638 RegCloseKey(hkeyPrinters);
1641 old_printer_check( FALSE );
1643 #ifdef SONAME_LIBCUPS
1644 done = CUPS_LoadPrinters();
1647 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1648 PRINTCAP_LoadPrinters();
1650 old_printer_check( TRUE );
1652 ReleaseMutex( init_mutex );
1656 /******************************************************************
1659 * Get the pointer to the specified job.
1660 * Should hold the printer_handles_cs before calling.
1662 static job_t *get_job(HANDLE hprn, DWORD JobId)
1664 opened_printer_t *printer = get_opened_printer(hprn);
1667 if(!printer) return NULL;
1668 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1670 if(job->job_id == JobId)
1676 /***********************************************************
1679 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1682 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1685 Formname = (dmA->dmSize > off_formname);
1686 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1687 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1688 dmW->dmDeviceName, CCHDEVICENAME);
1690 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1691 dmA->dmSize - CCHDEVICENAME);
1693 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1694 off_formname - CCHDEVICENAME);
1695 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1696 dmW->dmFormName, CCHFORMNAME);
1697 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1698 (off_formname + CCHFORMNAME));
1701 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1702 dmA->dmDriverExtra);
1706 /******************************************************************
1707 * convert_printerinfo_W_to_A [internal]
1710 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1711 DWORD level, DWORD outlen, DWORD numentries)
1717 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1719 len = pi_sizeof[level] * numentries;
1720 ptr = (LPSTR) out + len;
1723 /* copy the numbers of all PRINTER_INFO_* first */
1724 memcpy(out, pPrintersW, len);
1726 while (id < numentries) {
1730 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1731 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1733 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1734 if (piW->pDescription) {
1735 piA->pDescription = ptr;
1736 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1737 ptr, outlen, NULL, NULL);
1743 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1744 ptr, outlen, NULL, NULL);
1748 if (piW->pComment) {
1749 piA->pComment = ptr;
1750 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1751 ptr, outlen, NULL, NULL);
1760 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1761 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1764 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1765 if (piW->pServerName) {
1766 piA->pServerName = ptr;
1767 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1768 ptr, outlen, NULL, NULL);
1772 if (piW->pPrinterName) {
1773 piA->pPrinterName = ptr;
1774 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1775 ptr, outlen, NULL, NULL);
1779 if (piW->pShareName) {
1780 piA->pShareName = ptr;
1781 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1782 ptr, outlen, NULL, NULL);
1786 if (piW->pPortName) {
1787 piA->pPortName = ptr;
1788 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1789 ptr, outlen, NULL, NULL);
1793 if (piW->pDriverName) {
1794 piA->pDriverName = ptr;
1795 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1796 ptr, outlen, NULL, NULL);
1800 if (piW->pComment) {
1801 piA->pComment = ptr;
1802 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1803 ptr, outlen, NULL, NULL);
1807 if (piW->pLocation) {
1808 piA->pLocation = ptr;
1809 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1810 ptr, outlen, NULL, NULL);
1815 dmA = DEVMODEdupWtoA(piW->pDevMode);
1817 /* align DEVMODEA to a DWORD boundary */
1818 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1822 piA->pDevMode = (LPDEVMODEA) ptr;
1823 len = dmA->dmSize + dmA->dmDriverExtra;
1824 memcpy(ptr, dmA, len);
1825 HeapFree(GetProcessHeap(), 0, dmA);
1831 if (piW->pSepFile) {
1832 piA->pSepFile = ptr;
1833 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1834 ptr, outlen, NULL, NULL);
1838 if (piW->pPrintProcessor) {
1839 piA->pPrintProcessor = ptr;
1840 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1841 ptr, outlen, NULL, NULL);
1845 if (piW->pDatatype) {
1846 piA->pDatatype = ptr;
1847 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1848 ptr, outlen, NULL, NULL);
1852 if (piW->pParameters) {
1853 piA->pParameters = ptr;
1854 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1855 ptr, outlen, NULL, NULL);
1859 if (piW->pSecurityDescriptor) {
1860 piA->pSecurityDescriptor = NULL;
1861 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1868 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1869 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1871 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1873 if (piW->pPrinterName) {
1874 piA->pPrinterName = ptr;
1875 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1876 ptr, outlen, NULL, NULL);
1880 if (piW->pServerName) {
1881 piA->pServerName = ptr;
1882 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1883 ptr, outlen, NULL, NULL);
1892 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1893 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1895 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1897 if (piW->pPrinterName) {
1898 piA->pPrinterName = ptr;
1899 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1900 ptr, outlen, NULL, NULL);
1904 if (piW->pPortName) {
1905 piA->pPortName = ptr;
1906 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1907 ptr, outlen, NULL, NULL);
1914 case 6: /* 6A and 6W are the same structure */
1919 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1920 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1922 TRACE("(%u) #%u\n", level, id);
1923 if (piW->pszObjectGUID) {
1924 piA->pszObjectGUID = ptr;
1925 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1926 ptr, outlen, NULL, NULL);
1936 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1937 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1940 TRACE("(%u) #%u\n", level, id);
1941 dmA = DEVMODEdupWtoA(piW->pDevMode);
1943 /* align DEVMODEA to a DWORD boundary */
1944 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1948 piA->pDevMode = (LPDEVMODEA) ptr;
1949 len = dmA->dmSize + dmA->dmDriverExtra;
1950 memcpy(ptr, dmA, len);
1951 HeapFree(GetProcessHeap(), 0, dmA);
1961 FIXME("for level %u\n", level);
1963 pPrintersW += pi_sizeof[level];
1964 out += pi_sizeof[level];
1969 /******************************************************************
1970 * convert_driverinfo_W_to_A [internal]
1973 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1974 DWORD level, DWORD outlen, DWORD numentries)
1980 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1982 len = di_sizeof[level] * numentries;
1983 ptr = (LPSTR) out + len;
1986 /* copy the numbers of all PRINTER_INFO_* first */
1987 memcpy(out, pDriversW, len);
1989 #define COPY_STRING(fld) \
1992 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1993 ptr += len; outlen -= len;\
1995 #define COPY_MULTIZ_STRING(fld) \
1996 { LPWSTR p = diW->fld; if (p){ \
1999 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2000 ptr += len; outlen -= len; p += len;\
2002 while(len > 1 && outlen > 0); \
2005 while (id < numentries)
2011 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2012 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2014 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2021 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2022 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2024 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2027 COPY_STRING(pEnvironment);
2028 COPY_STRING(pDriverPath);
2029 COPY_STRING(pDataFile);
2030 COPY_STRING(pConfigFile);
2035 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2036 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2038 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2041 COPY_STRING(pEnvironment);
2042 COPY_STRING(pDriverPath);
2043 COPY_STRING(pDataFile);
2044 COPY_STRING(pConfigFile);
2045 COPY_STRING(pHelpFile);
2046 COPY_MULTIZ_STRING(pDependentFiles);
2047 COPY_STRING(pMonitorName);
2048 COPY_STRING(pDefaultDataType);
2053 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2054 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2056 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2059 COPY_STRING(pEnvironment);
2060 COPY_STRING(pDriverPath);
2061 COPY_STRING(pDataFile);
2062 COPY_STRING(pConfigFile);
2063 COPY_STRING(pHelpFile);
2064 COPY_MULTIZ_STRING(pDependentFiles);
2065 COPY_STRING(pMonitorName);
2066 COPY_STRING(pDefaultDataType);
2067 COPY_MULTIZ_STRING(pszzPreviousNames);
2072 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2073 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2075 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2078 COPY_STRING(pEnvironment);
2079 COPY_STRING(pDriverPath);
2080 COPY_STRING(pDataFile);
2081 COPY_STRING(pConfigFile);
2086 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2087 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2089 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2092 COPY_STRING(pEnvironment);
2093 COPY_STRING(pDriverPath);
2094 COPY_STRING(pDataFile);
2095 COPY_STRING(pConfigFile);
2096 COPY_STRING(pHelpFile);
2097 COPY_MULTIZ_STRING(pDependentFiles);
2098 COPY_STRING(pMonitorName);
2099 COPY_STRING(pDefaultDataType);
2100 COPY_MULTIZ_STRING(pszzPreviousNames);
2101 COPY_STRING(pszMfgName);
2102 COPY_STRING(pszOEMUrl);
2103 COPY_STRING(pszHardwareID);
2104 COPY_STRING(pszProvider);
2109 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2110 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2112 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2115 COPY_STRING(pEnvironment);
2116 COPY_STRING(pDriverPath);
2117 COPY_STRING(pDataFile);
2118 COPY_STRING(pConfigFile);
2119 COPY_STRING(pHelpFile);
2120 COPY_MULTIZ_STRING(pDependentFiles);
2121 COPY_STRING(pMonitorName);
2122 COPY_STRING(pDefaultDataType);
2123 COPY_MULTIZ_STRING(pszzPreviousNames);
2124 COPY_STRING(pszMfgName);
2125 COPY_STRING(pszOEMUrl);
2126 COPY_STRING(pszHardwareID);
2127 COPY_STRING(pszProvider);
2128 COPY_STRING(pszPrintProcessor);
2129 COPY_STRING(pszVendorSetup);
2130 COPY_MULTIZ_STRING(pszzColorProfiles);
2131 COPY_STRING(pszInfPath);
2132 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2138 FIXME("for level %u\n", level);
2141 pDriversW += di_sizeof[level];
2142 out += di_sizeof[level];
2147 #undef COPY_MULTIZ_STRING
2151 /***********************************************************
2154 static void *printer_info_AtoW( const void *data, DWORD level )
2157 UNICODE_STRING usBuffer;
2159 if (!data) return NULL;
2161 if (level < 1 || level > 9) return NULL;
2163 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2164 if (!ret) return NULL;
2166 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2172 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2173 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2175 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2176 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2177 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2178 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2179 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2180 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2181 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2182 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2183 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2184 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2185 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2186 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2193 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2194 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2196 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2201 FIXME( "Unhandled level %d\n", level );
2202 HeapFree( GetProcessHeap(), 0, ret );
2209 /***********************************************************
2212 static void free_printer_info( void *data, DWORD level )
2220 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2222 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2223 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2224 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2225 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2226 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2227 HeapFree( GetProcessHeap(), 0, piW->pComment );
2228 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2229 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2230 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2231 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2232 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2233 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2240 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2242 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2247 FIXME( "Unhandled level %d\n", level );
2250 HeapFree( GetProcessHeap(), 0, data );
2254 /******************************************************************
2255 * DeviceCapabilities [WINSPOOL.@]
2256 * DeviceCapabilitiesA [WINSPOOL.@]
2259 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2260 LPSTR pOutput, LPDEVMODEA lpdm)
2264 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2266 if (!GDI_CallDeviceCapabilities16)
2268 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2270 if (!GDI_CallDeviceCapabilities16) return -1;
2272 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2274 /* If DC_PAPERSIZE map POINT16s to POINTs */
2275 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2276 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2277 POINT *pt = (POINT *)pOutput;
2279 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2280 for(i = 0; i < ret; i++, pt++)
2285 HeapFree( GetProcessHeap(), 0, tmp );
2291 /*****************************************************************************
2292 * DeviceCapabilitiesW [WINSPOOL.@]
2294 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2297 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2298 WORD fwCapability, LPWSTR pOutput,
2299 const DEVMODEW *pDevMode)
2301 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2302 LPSTR pDeviceA = strdupWtoA(pDevice);
2303 LPSTR pPortA = strdupWtoA(pPort);
2306 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2308 if(pOutput && (fwCapability == DC_BINNAMES ||
2309 fwCapability == DC_FILEDEPENDENCIES ||
2310 fwCapability == DC_PAPERNAMES)) {
2311 /* These need A -> W translation */
2314 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2318 switch(fwCapability) {
2323 case DC_FILEDEPENDENCIES:
2327 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2328 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2330 for(i = 0; i < ret; i++)
2331 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2332 pOutput + (i * size), size);
2333 HeapFree(GetProcessHeap(), 0, pOutputA);
2335 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2336 (LPSTR)pOutput, dmA);
2338 HeapFree(GetProcessHeap(),0,pPortA);
2339 HeapFree(GetProcessHeap(),0,pDeviceA);
2340 HeapFree(GetProcessHeap(),0,dmA);
2344 /******************************************************************
2345 * DocumentPropertiesA [WINSPOOL.@]
2347 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2349 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2350 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2351 LPDEVMODEA pDevModeInput,DWORD fMode )
2353 LPSTR lpName = pDeviceName;
2354 static CHAR port[] = "LPT1:";
2357 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2358 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2361 if(!pDeviceName || !*pDeviceName) {
2362 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2364 ERR("no name from hPrinter?\n");
2365 SetLastError(ERROR_INVALID_HANDLE);
2368 lpName = strdupWtoA(lpNameW);
2371 if (!GDI_CallExtDeviceMode16)
2373 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2375 if (!GDI_CallExtDeviceMode16) {
2376 ERR("No CallExtDeviceMode16?\n");
2380 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2381 pDevModeInput, NULL, fMode);
2384 HeapFree(GetProcessHeap(),0,lpName);
2389 /*****************************************************************************
2390 * DocumentPropertiesW (WINSPOOL.@)
2392 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2394 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2396 LPDEVMODEW pDevModeOutput,
2397 LPDEVMODEW pDevModeInput, DWORD fMode)
2400 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2401 LPDEVMODEA pDevModeInputA;
2402 LPDEVMODEA pDevModeOutputA = NULL;
2405 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2406 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2408 if(pDevModeOutput) {
2409 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2410 if(ret < 0) return ret;
2411 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2413 pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2414 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2415 pDevModeInputA, fMode);
2416 if(pDevModeOutput) {
2417 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2418 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2420 if(fMode == 0 && ret > 0)
2421 ret += (CCHDEVICENAME + CCHFORMNAME);
2422 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2423 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2427 /*****************************************************************************
2428 * IsValidDevmodeA [WINSPOOL.@]
2430 * Validate a DEVMODE structure and fix errors if possible.
2433 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2435 FIXME("(%p,%ld): stub\n", pDevMode, size);
2443 /*****************************************************************************
2444 * IsValidDevmodeW [WINSPOOL.@]
2446 * Validate a DEVMODE structure and fix errors if possible.
2449 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2451 FIXME("(%p,%ld): stub\n", pDevMode, size);
2459 /******************************************************************
2460 * OpenPrinterA [WINSPOOL.@]
2465 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2466 LPPRINTER_DEFAULTSA pDefault)
2468 UNICODE_STRING lpPrinterNameW;
2469 UNICODE_STRING usBuffer;
2470 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2471 PWSTR pwstrPrinterNameW;
2474 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2476 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2479 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2480 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2481 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2482 pDefaultW = &DefaultW;
2484 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2486 RtlFreeUnicodeString(&usBuffer);
2487 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2489 RtlFreeUnicodeString(&lpPrinterNameW);
2493 /******************************************************************
2494 * OpenPrinterW [WINSPOOL.@]
2496 * Open a Printer / Printserver or a Printer-Object
2499 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2500 * phPrinter [O] The resulting Handle is stored here
2501 * pDefault [I] PTR to Default Printer Settings or NULL
2508 * lpPrinterName is one of:
2509 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2510 *| Printer: "PrinterName"
2511 *| Printer-Object: "PrinterName,Job xxx"
2512 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2513 *| XcvPort: "Servername,XcvPort PortName"
2516 *| Printer-Object not supported
2517 *| pDefaults is ignored
2520 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2523 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2526 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2527 SetLastError(ERROR_INVALID_PARAMETER);
2531 /* Get the unique handle of the printer or Printserver */
2532 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2537 DWORD deleting = 0, size = sizeof( deleting ), type;
2539 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key );
2540 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2541 WaitForSingleObject( init_mutex, INFINITE );
2542 status = get_dword_from_reg( key, StatusW );
2543 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2544 ReleaseMutex( init_mutex );
2545 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2546 update_driver( *phPrinter );
2550 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2551 return (*phPrinter != 0);
2554 /******************************************************************
2555 * AddMonitorA [WINSPOOL.@]
2560 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2562 LPWSTR nameW = NULL;
2565 LPMONITOR_INFO_2A mi2a;
2566 MONITOR_INFO_2W mi2w;
2568 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2569 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2570 debugstr_a(mi2a ? mi2a->pName : NULL),
2571 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2572 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2575 SetLastError(ERROR_INVALID_LEVEL);
2579 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2585 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2586 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2587 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2590 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2592 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2593 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2594 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2596 if (mi2a->pEnvironment) {
2597 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2598 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2599 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2601 if (mi2a->pDLLName) {
2602 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2603 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2604 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2607 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2609 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2610 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2611 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2613 HeapFree(GetProcessHeap(), 0, nameW);
2617 /******************************************************************************
2618 * AddMonitorW [WINSPOOL.@]
2620 * Install a Printmonitor
2623 * pName [I] Servername or NULL (local Computer)
2624 * Level [I] Structure-Level (Must be 2)
2625 * pMonitors [I] PTR to MONITOR_INFO_2
2632 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2635 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2637 LPMONITOR_INFO_2W mi2w;
2639 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2640 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2641 debugstr_w(mi2w ? mi2w->pName : NULL),
2642 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2643 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2645 if ((backend == NULL) && !load_backend()) return FALSE;
2648 SetLastError(ERROR_INVALID_LEVEL);
2652 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2657 return backend->fpAddMonitor(pName, Level, pMonitors);
2660 /******************************************************************
2661 * DeletePrinterDriverA [WINSPOOL.@]
2664 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2666 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2669 /******************************************************************
2670 * DeletePrinterDriverW [WINSPOOL.@]
2673 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2675 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2678 /******************************************************************
2679 * DeleteMonitorA [WINSPOOL.@]
2681 * See DeleteMonitorW.
2684 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2686 LPWSTR nameW = NULL;
2687 LPWSTR EnvironmentW = NULL;
2688 LPWSTR MonitorNameW = NULL;
2693 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2694 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2695 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2699 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2700 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2701 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2704 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2705 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2706 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2709 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2711 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2712 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2713 HeapFree(GetProcessHeap(), 0, nameW);
2717 /******************************************************************
2718 * DeleteMonitorW [WINSPOOL.@]
2720 * Delete a specific Printmonitor from a Printing-Environment
2723 * pName [I] Servername or NULL (local Computer)
2724 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2725 * pMonitorName [I] Name of the Monitor, that should be deleted
2732 * pEnvironment is ignored in Windows for the local Computer.
2735 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2738 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2739 debugstr_w(pMonitorName));
2741 if ((backend == NULL) && !load_backend()) return FALSE;
2743 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2747 /******************************************************************
2748 * DeletePortA [WINSPOOL.@]
2753 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2755 LPWSTR nameW = NULL;
2756 LPWSTR portW = NULL;
2760 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2762 /* convert servername to unicode */
2764 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2765 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2766 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2769 /* convert portname to unicode */
2771 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2772 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2773 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2776 res = DeletePortW(nameW, hWnd, portW);
2777 HeapFree(GetProcessHeap(), 0, nameW);
2778 HeapFree(GetProcessHeap(), 0, portW);
2782 /******************************************************************
2783 * DeletePortW [WINSPOOL.@]
2785 * Delete a specific Port
2788 * pName [I] Servername or NULL (local Computer)
2789 * hWnd [I] Handle to parent Window for the Dialog-Box
2790 * pPortName [I] Name of the Port, that should be deleted
2797 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2799 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2801 if ((backend == NULL) && !load_backend()) return FALSE;
2804 SetLastError(RPC_X_NULL_REF_POINTER);
2808 return backend->fpDeletePort(pName, hWnd, pPortName);
2811 /******************************************************************************
2812 * WritePrinter [WINSPOOL.@]
2814 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2816 opened_printer_t *printer;
2819 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2821 EnterCriticalSection(&printer_handles_cs);
2822 printer = get_opened_printer(hPrinter);
2825 SetLastError(ERROR_INVALID_HANDLE);
2831 SetLastError(ERROR_SPL_NO_STARTDOC);
2835 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2837 LeaveCriticalSection(&printer_handles_cs);
2841 /*****************************************************************************
2842 * AddFormA [WINSPOOL.@]
2844 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2846 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2850 /*****************************************************************************
2851 * AddFormW [WINSPOOL.@]
2853 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2855 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2859 /*****************************************************************************
2860 * AddJobA [WINSPOOL.@]
2862 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2865 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2869 SetLastError(ERROR_INVALID_LEVEL);
2873 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2876 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2877 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2878 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2879 if(*pcbNeeded > cbBuf) {
2880 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2883 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2884 addjobA->JobId = addjobW->JobId;
2885 addjobA->Path = (char *)(addjobA + 1);
2886 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2892 /*****************************************************************************
2893 * AddJobW [WINSPOOL.@]
2895 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2897 opened_printer_t *printer;
2900 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2901 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2902 WCHAR path[MAX_PATH], filename[MAX_PATH];
2904 ADDJOB_INFO_1W *addjob;
2906 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2908 EnterCriticalSection(&printer_handles_cs);
2910 printer = get_opened_printer(hPrinter);
2913 SetLastError(ERROR_INVALID_HANDLE);
2918 SetLastError(ERROR_INVALID_LEVEL);
2922 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2926 job->job_id = InterlockedIncrement(&next_job_id);
2928 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2929 if(path[len - 1] != '\\')
2931 memcpy(path + len, spool_path, sizeof(spool_path));
2932 sprintfW(filename, fmtW, path, job->job_id);
2934 len = strlenW(filename);
2935 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2936 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2937 job->portname = NULL;
2938 job->document_title = strdupW(default_doc_title);
2939 job->printer_name = strdupW(printer->name);
2940 job->devmode = dup_devmode( printer->devmode );
2941 list_add_tail(&printer->queue->jobs, &job->entry);
2943 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2944 if(*pcbNeeded <= cbBuf) {
2945 addjob = (ADDJOB_INFO_1W*)pData;
2946 addjob->JobId = job->job_id;
2947 addjob->Path = (WCHAR *)(addjob + 1);
2948 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2951 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2954 LeaveCriticalSection(&printer_handles_cs);
2958 /*****************************************************************************
2959 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2961 * Return the PATH for the Print-Processors
2963 * See GetPrintProcessorDirectoryW.
2967 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2968 DWORD level, LPBYTE Info,
2969 DWORD cbBuf, LPDWORD pcbNeeded)
2971 LPWSTR serverW = NULL;
2976 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2977 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2981 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2982 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2983 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2987 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2988 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2989 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2992 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2993 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2995 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2998 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2999 cbBuf, NULL, NULL) > 0;
3002 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3003 HeapFree(GetProcessHeap(), 0, envW);
3004 HeapFree(GetProcessHeap(), 0, serverW);
3008 /*****************************************************************************
3009 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3011 * Return the PATH for the Print-Processors
3014 * server [I] Servername (NT only) or NULL (local Computer)
3015 * env [I] Printing-Environment (see below) or NULL (Default)
3016 * level [I] Structure-Level (must be 1)
3017 * Info [O] PTR to Buffer that receives the Result
3018 * cbBuf [I] Size of Buffer at "Info"
3019 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3020 * required for the Buffer at "Info"
3023 * Success: TRUE and in pcbNeeded the Bytes used in Info
3024 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3025 * if cbBuf is too small
3027 * Native Values returned in Info on Success:
3028 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3029 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3030 *| win9x(Windows 4.0): "%winsysdir%"
3032 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3035 * Only NULL or "" is supported for server
3038 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3039 DWORD level, LPBYTE Info,
3040 DWORD cbBuf, LPDWORD pcbNeeded)
3043 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3044 Info, cbBuf, pcbNeeded);
3046 if ((backend == NULL) && !load_backend()) return FALSE;
3049 /* (Level != 1) is ignored in win9x */
3050 SetLastError(ERROR_INVALID_LEVEL);
3054 if (pcbNeeded == NULL) {
3055 /* (pcbNeeded == NULL) is ignored in win9x */
3056 SetLastError(RPC_X_NULL_REF_POINTER);
3060 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3063 /*****************************************************************************
3064 * WINSPOOL_OpenDriverReg [internal]
3066 * opens the registry for the printer drivers depending on the given input
3067 * variable pEnvironment
3070 * the opened hkey on success
3073 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3077 const printenv_t * env;
3079 TRACE("(%s)\n", debugstr_w(pEnvironment));
3081 env = validate_envW(pEnvironment);
3082 if (!env) return NULL;
3084 buffer = HeapAlloc( GetProcessHeap(), 0,
3085 (strlenW(DriversW) + strlenW(env->envname) +
3086 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3088 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3089 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3090 HeapFree(GetProcessHeap(), 0, buffer);
3095 /*****************************************************************************
3096 * set_devices_and_printerports [internal]
3098 * set the [Devices] and [PrinterPorts] entries for a printer.
3101 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3103 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3107 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3109 /* FIXME: the driver must change to "winspool" */
3110 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3112 lstrcpyW(devline, driver_nt);
3113 lstrcatW(devline, commaW);
3114 lstrcatW(devline, pi->pPortName);
3116 TRACE("using %s\n", debugstr_w(devline));
3117 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3118 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3119 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3120 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3124 lstrcatW(devline, timeout_15_45);
3125 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3126 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3127 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3128 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3131 HeapFree(GetProcessHeap(), 0, devline);
3135 /*****************************************************************************
3136 * AddPrinterW [WINSPOOL.@]
3138 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3140 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3143 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3146 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3149 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3150 SetLastError(ERROR_INVALID_PARAMETER);
3154 ERR("Level = %d, unsupported!\n", Level);
3155 SetLastError(ERROR_INVALID_LEVEL);
3159 SetLastError(ERROR_INVALID_PARAMETER);
3162 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3164 ERR("Can't create Printers key\n");
3167 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3168 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3169 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3170 RegCloseKey(hkeyPrinter);
3171 RegCloseKey(hkeyPrinters);
3174 RegCloseKey(hkeyPrinter);
3176 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3178 ERR("Can't create Drivers key\n");
3179 RegCloseKey(hkeyPrinters);
3182 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3184 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3185 RegCloseKey(hkeyPrinters);
3186 RegCloseKey(hkeyDrivers);
3187 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3190 RegCloseKey(hkeyDriver);
3191 RegCloseKey(hkeyDrivers);
3193 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3194 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3195 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3196 RegCloseKey(hkeyPrinters);
3200 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3202 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3203 SetLastError(ERROR_INVALID_PRINTER_NAME);
3204 RegCloseKey(hkeyPrinters);
3208 set_devices_and_printerports(pi);
3210 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3211 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3212 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3213 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3214 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3215 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3216 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3217 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3218 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3219 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3220 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3221 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3222 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3223 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3224 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3225 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3226 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3227 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3229 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3233 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3234 size = sizeof(DEVMODEW);
3240 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3242 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3244 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3245 HeapFree( GetProcessHeap(), 0, dm );
3250 /* set devmode to printer name */
3251 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3255 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3256 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3258 RegCloseKey(hkeyPrinter);
3259 RegCloseKey(hkeyPrinters);
3260 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3261 ERR("OpenPrinter failing\n");
3267 /*****************************************************************************
3268 * AddPrinterA [WINSPOOL.@]
3270 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3272 UNICODE_STRING pNameW;
3274 PRINTER_INFO_2W *piW;
3275 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3278 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3280 ERR("Level = %d, unsupported!\n", Level);
3281 SetLastError(ERROR_INVALID_LEVEL);
3284 pwstrNameW = asciitounicode(&pNameW,pName);
3285 piW = printer_info_AtoW( piA, Level );
3287 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3289 free_printer_info( piW, Level );
3290 RtlFreeUnicodeString(&pNameW);
3295 /*****************************************************************************
3296 * ClosePrinter [WINSPOOL.@]
3298 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3300 UINT_PTR i = (UINT_PTR)hPrinter;
3301 opened_printer_t *printer = NULL;
3304 TRACE("(%p)\n", hPrinter);
3306 EnterCriticalSection(&printer_handles_cs);
3308 if ((i > 0) && (i <= nb_printer_handles))
3309 printer = printer_handles[i - 1];
3314 struct list *cursor, *cursor2;
3316 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3318 if (printer->backend_printer) {
3319 backend->fpClosePrinter(printer->backend_printer);
3323 EndDocPrinter(hPrinter);
3325 if(InterlockedDecrement(&printer->queue->ref) == 0)
3327 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3329 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3330 ScheduleJob(hPrinter, job->job_id);
3332 HeapFree(GetProcessHeap(), 0, printer->queue);
3335 free_printer_entry( printer );
3336 printer_handles[i - 1] = NULL;
3339 LeaveCriticalSection(&printer_handles_cs);
3343 /*****************************************************************************
3344 * DeleteFormA [WINSPOOL.@]
3346 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3348 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3352 /*****************************************************************************
3353 * DeleteFormW [WINSPOOL.@]
3355 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3357 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3361 /*****************************************************************************
3362 * DeletePrinter [WINSPOOL.@]
3364 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3366 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3367 HKEY hkeyPrinters, hkey;
3368 WCHAR def[MAX_PATH];
3369 DWORD size = sizeof( def ) / sizeof( def[0] );
3372 SetLastError(ERROR_INVALID_HANDLE);
3375 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3376 RegDeleteTreeW(hkeyPrinters, lpNameW);
3377 RegCloseKey(hkeyPrinters);
3379 WriteProfileStringW(devicesW, lpNameW, NULL);
3380 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3382 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3383 RegDeleteValueW(hkey, lpNameW);
3387 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3388 RegDeleteValueW(hkey, lpNameW);
3392 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3394 WriteProfileStringW( windowsW, deviceW, NULL );
3395 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3397 RegDeleteValueW( hkey, deviceW );
3398 RegCloseKey( hkey );
3400 SetDefaultPrinterW( NULL );
3406 /*****************************************************************************
3407 * SetPrinterA [WINSPOOL.@]
3409 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3416 dataW = printer_info_AtoW( data, level );
3417 if (!dataW) return FALSE;
3420 ret = SetPrinterW( printer, level, dataW, command );
3422 if (dataW != data) free_printer_info( dataW, level );
3427 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3429 set_reg_szW( key, NameW, pi->pPrinterName );
3430 set_reg_szW( key, Share_NameW, pi->pShareName );
3431 set_reg_szW( key, PortW, pi->pPortName );
3432 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3433 set_reg_szW( key, DescriptionW, pi->pComment );
3434 set_reg_szW( key, LocationW, pi->pLocation );
3437 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3439 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3440 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3441 set_reg_szW( key, DatatypeW, pi->pDatatype );
3442 set_reg_szW( key, ParametersW, pi->pParameters );
3444 set_reg_DWORD( key, AttributesW, pi->Attributes );
3445 set_reg_DWORD( key, PriorityW, pi->Priority );
3446 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3447 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3448 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3451 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3453 if (!pi->pDevMode) return FALSE;
3455 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3459 /******************************************************************************
3460 * SetPrinterW [WINSPOOL.@]
3462 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3467 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3469 if (command != 0) FIXME( "Ignoring command %d\n", command );
3471 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3478 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3479 set_printer_2( key, pi2 );
3486 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3487 ret = set_printer_9( key, pi );
3492 FIXME( "Unimplemented level %d\n", level );
3493 SetLastError( ERROR_INVALID_LEVEL );
3500 /*****************************************************************************
3501 * SetJobA [WINSPOOL.@]
3503 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3504 LPBYTE pJob, DWORD Command)
3508 UNICODE_STRING usBuffer;
3510 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3512 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3513 are all ignored by SetJob, so we don't bother copying them */
3521 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3522 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3524 JobW = (LPBYTE)info1W;
3525 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3526 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3527 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3528 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3529 info1W->Status = info1A->Status;
3530 info1W->Priority = info1A->Priority;
3531 info1W->Position = info1A->Position;
3532 info1W->PagesPrinted = info1A->PagesPrinted;
3537 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3538 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3540 JobW = (LPBYTE)info2W;
3541 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3542 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3543 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3544 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3545 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3546 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3547 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3548 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3549 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3550 info2W->Status = info2A->Status;
3551 info2W->Priority = info2A->Priority;
3552 info2W->Position = info2A->Position;
3553 info2W->StartTime = info2A->StartTime;
3554 info2W->UntilTime = info2A->UntilTime;
3555 info2W->PagesPrinted = info2A->PagesPrinted;
3559 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3560 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3563 SetLastError(ERROR_INVALID_LEVEL);
3567 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3573 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3574 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3575 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3576 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3577 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3582 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3583 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3584 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3585 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3586 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3587 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3588 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3589 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3590 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3594 HeapFree(GetProcessHeap(), 0, JobW);
3599 /*****************************************************************************
3600 * SetJobW [WINSPOOL.@]
3602 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3603 LPBYTE pJob, DWORD Command)
3608 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3609 FIXME("Ignoring everything other than document title\n");
3611 EnterCriticalSection(&printer_handles_cs);
3612 job = get_job(hPrinter, JobId);
3622 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3623 HeapFree(GetProcessHeap(), 0, job->document_title);
3624 job->document_title = strdupW(info1->pDocument);
3629 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3630 HeapFree(GetProcessHeap(), 0, job->document_title);
3631 job->document_title = strdupW(info2->pDocument);
3632 HeapFree(GetProcessHeap(), 0, job->devmode);
3633 job->devmode = dup_devmode( info2->pDevMode );
3639 SetLastError(ERROR_INVALID_LEVEL);
3644 LeaveCriticalSection(&printer_handles_cs);
3648 /*****************************************************************************
3649 * EndDocPrinter [WINSPOOL.@]
3651 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3653 opened_printer_t *printer;
3655 TRACE("(%p)\n", hPrinter);
3657 EnterCriticalSection(&printer_handles_cs);
3659 printer = get_opened_printer(hPrinter);
3662 SetLastError(ERROR_INVALID_HANDLE);
3668 SetLastError(ERROR_SPL_NO_STARTDOC);
3672 CloseHandle(printer->doc->hf);
3673 ScheduleJob(hPrinter, printer->doc->job_id);
3674 HeapFree(GetProcessHeap(), 0, printer->doc);
3675 printer->doc = NULL;
3678 LeaveCriticalSection(&printer_handles_cs);
3682 /*****************************************************************************
3683 * EndPagePrinter [WINSPOOL.@]
3685 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3687 FIXME("(%p): stub\n", hPrinter);
3691 /*****************************************************************************
3692 * StartDocPrinterA [WINSPOOL.@]
3694 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3696 UNICODE_STRING usBuffer;
3698 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3701 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3702 or one (DOC_INFO_3) extra DWORDs */
3706 doc2W.JobId = doc2->JobId;
3709 doc2W.dwMode = doc2->dwMode;
3712 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3713 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3714 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3718 SetLastError(ERROR_INVALID_LEVEL);
3722 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3724 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3725 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3726 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3731 /*****************************************************************************
3732 * StartDocPrinterW [WINSPOOL.@]
3734 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3736 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3737 opened_printer_t *printer;
3738 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3739 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3740 JOB_INFO_1W job_info;
3741 DWORD needed, ret = 0;
3746 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3747 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3748 debugstr_w(doc->pDatatype));
3750 if(Level < 1 || Level > 3)
3752 SetLastError(ERROR_INVALID_LEVEL);
3756 EnterCriticalSection(&printer_handles_cs);
3757 printer = get_opened_printer(hPrinter);
3760 SetLastError(ERROR_INVALID_HANDLE);
3766 SetLastError(ERROR_INVALID_PRINTER_STATE);
3770 /* Even if we're printing to a file we still add a print job, we'll
3771 just ignore the spool file name */
3773 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3775 ERR("AddJob failed gle %u\n", GetLastError());
3779 /* use pOutputFile only, when it is a real filename */
3780 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3781 filename = doc->pOutputFile;
3783 filename = addjob->Path;
3785 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3786 if(hf == INVALID_HANDLE_VALUE)
3789 memset(&job_info, 0, sizeof(job_info));
3790 job_info.pDocument = doc->pDocName;
3791 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3793 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3794 printer->doc->hf = hf;
3795 ret = printer->doc->job_id = addjob->JobId;
3796 job = get_job(hPrinter, ret);
3797 job->portname = strdupW(doc->pOutputFile);
3800 LeaveCriticalSection(&printer_handles_cs);
3805 /*****************************************************************************
3806 * StartPagePrinter [WINSPOOL.@]
3808 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3810 FIXME("(%p): stub\n", hPrinter);
3814 /*****************************************************************************
3815 * GetFormA [WINSPOOL.@]
3817 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3818 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3820 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3821 Level,pForm,cbBuf,pcbNeeded);
3825 /*****************************************************************************
3826 * GetFormW [WINSPOOL.@]
3828 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3829 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3831 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3832 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3836 /*****************************************************************************
3837 * SetFormA [WINSPOOL.@]
3839 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3842 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3846 /*****************************************************************************
3847 * SetFormW [WINSPOOL.@]
3849 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3852 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3856 /*****************************************************************************
3857 * ReadPrinter [WINSPOOL.@]
3859 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3860 LPDWORD pNoBytesRead)
3862 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3866 /*****************************************************************************
3867 * ResetPrinterA [WINSPOOL.@]
3869 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3871 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3875 /*****************************************************************************
3876 * ResetPrinterW [WINSPOOL.@]
3878 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3880 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3884 /*****************************************************************************
3885 * get_filename_from_reg [internal]
3887 * Get ValueName from hkey storing result in out
3888 * when the Value in the registry has only a filename, use driverdir as prefix
3889 * outlen is space left in out
3890 * String is stored either as unicode or ascii
3894 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3895 LPBYTE out, DWORD outlen, LPDWORD needed)
3897 WCHAR filename[MAX_PATH];
3901 LPWSTR buffer = filename;
3905 size = sizeof(filename);
3907 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3908 if (ret == ERROR_MORE_DATA) {
3909 TRACE("need dynamic buffer: %u\n", size);
3910 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3912 /* No Memory is bad */
3916 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3919 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3920 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3926 /* do we have a full path ? */
3927 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3928 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3931 /* we must build the full Path */
3933 if ((out) && (outlen > dirlen)) {
3934 lstrcpyW((LPWSTR)out, driverdir);
3942 /* write the filename */
3943 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3944 if ((out) && (outlen >= size)) {
3945 lstrcpyW((LPWSTR)out, ptr);
3952 ptr += lstrlenW(ptr)+1;
3953 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3956 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3958 /* write the multisz-termination */
3959 if (type == REG_MULTI_SZ) {
3960 size = sizeof(WCHAR);
3963 if (out && (outlen >= size)) {
3964 memset (out, 0, size);
3970 /*****************************************************************************
3971 * WINSPOOL_GetStringFromReg
3973 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3974 * String is stored as unicode.
3976 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3977 DWORD buflen, DWORD *needed)
3979 DWORD sz = buflen, type;
3982 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3983 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3984 WARN("Got ret = %d\n", ret);
3988 /* add space for terminating '\0' */
3989 sz += sizeof(WCHAR);
3993 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3998 /*****************************************************************************
3999 * WINSPOOL_GetDefaultDevMode
4001 * Get a default DevMode values for wineps.
4003 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4005 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4007 if (buflen >= sizeof(DEVMODEW))
4009 DEVMODEW *dm = (DEVMODEW *)ptr;
4011 /* the driver will update registry with real values */
4012 memset(dm, 0, sizeof(*dm));
4013 dm->dmSize = sizeof(*dm);
4014 lstrcpyW(dm->dmDeviceName, winepsW);
4016 *needed = sizeof(DEVMODEW);
4019 /*****************************************************************************
4020 * WINSPOOL_GetDevModeFromReg
4022 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4023 * DevMode is stored either as unicode or ascii.
4025 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4027 DWORD buflen, DWORD *needed)
4029 DWORD sz = buflen, type;
4032 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4033 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4034 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4035 if (sz < sizeof(DEVMODEA))
4037 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4040 /* ensures that dmSize is not erratically bogus if registry is invalid */
4041 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4042 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4043 sz += (CCHDEVICENAME + CCHFORMNAME);
4044 if (ptr && (buflen >= sz)) {
4045 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4046 memcpy(ptr, dmW, sz);
4047 HeapFree(GetProcessHeap(),0,dmW);
4053 /*********************************************************************
4054 * WINSPOOL_GetPrinter_1
4056 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4058 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4059 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4061 DWORD size, left = cbBuf;
4062 BOOL space = (cbBuf > 0);
4067 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4068 if(space && size <= left) {
4069 pi1->pName = (LPWSTR)ptr;
4077 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4078 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4079 if(space && size <= left) {
4080 pi1->pDescription = (LPWSTR)ptr;
4088 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4089 if(space && size <= left) {
4090 pi1->pComment = (LPWSTR)ptr;
4098 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4100 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4101 memset(pi1, 0, sizeof(*pi1));
4105 /*********************************************************************
4106 * WINSPOOL_GetPrinter_2
4108 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4110 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4111 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4113 DWORD size, left = cbBuf;
4114 BOOL space = (cbBuf > 0);
4119 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4120 if(space && size <= left) {
4121 pi2->pPrinterName = (LPWSTR)ptr;
4128 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4129 if(space && size <= left) {
4130 pi2->pShareName = (LPWSTR)ptr;
4137 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4138 if(space && size <= left) {
4139 pi2->pPortName = (LPWSTR)ptr;
4146 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4147 if(space && size <= left) {
4148 pi2->pDriverName = (LPWSTR)ptr;
4155 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4156 if(space && size <= left) {
4157 pi2->pComment = (LPWSTR)ptr;
4164 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4165 if(space && size <= left) {
4166 pi2->pLocation = (LPWSTR)ptr;
4173 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4174 if(space && size <= left) {
4175 pi2->pDevMode = (LPDEVMODEW)ptr;
4184 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4185 if(space && size <= left) {
4186 pi2->pDevMode = (LPDEVMODEW)ptr;
4193 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4194 if(space && size <= left) {
4195 pi2->pSepFile = (LPWSTR)ptr;
4202 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4203 if(space && size <= left) {
4204 pi2->pPrintProcessor = (LPWSTR)ptr;
4211 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4212 if(space && size <= left) {
4213 pi2->pDatatype = (LPWSTR)ptr;
4220 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4221 if(space && size <= left) {
4222 pi2->pParameters = (LPWSTR)ptr;
4230 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4231 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4232 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4233 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4234 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4237 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4238 memset(pi2, 0, sizeof(*pi2));
4243 /*********************************************************************
4244 * WINSPOOL_GetPrinter_4
4246 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4248 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4249 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4251 DWORD size, left = cbBuf;
4252 BOOL space = (cbBuf > 0);
4257 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4258 if(space && size <= left) {
4259 pi4->pPrinterName = (LPWSTR)ptr;
4267 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4270 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4271 memset(pi4, 0, sizeof(*pi4));
4276 /*********************************************************************
4277 * WINSPOOL_GetPrinter_5
4279 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4281 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4282 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4284 DWORD size, left = cbBuf;
4285 BOOL space = (cbBuf > 0);
4290 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4291 if(space && size <= left) {
4292 pi5->pPrinterName = (LPWSTR)ptr;
4299 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4300 if(space && size <= left) {
4301 pi5->pPortName = (LPWSTR)ptr;
4309 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4310 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4311 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4314 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4315 memset(pi5, 0, sizeof(*pi5));
4320 /*********************************************************************
4321 * WINSPOOL_GetPrinter_7
4323 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4325 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4326 DWORD cbBuf, LPDWORD pcbNeeded)
4328 DWORD size, left = cbBuf;
4329 BOOL space = (cbBuf > 0);
4334 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4337 size = sizeof(pi7->pszObjectGUID);
4339 if (space && size <= left) {
4340 pi7->pszObjectGUID = (LPWSTR)ptr;
4347 /* We do not have a Directory Service */
4348 pi7->dwAction = DSPRINT_UNPUBLISH;
4351 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4352 memset(pi7, 0, sizeof(*pi7));
4357 /*********************************************************************
4358 * WINSPOOL_GetPrinter_9
4360 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4362 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4363 DWORD cbBuf, LPDWORD pcbNeeded)
4366 BOOL space = (cbBuf > 0);
4370 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4371 if(space && size <= cbBuf) {
4372 pi9->pDevMode = (LPDEVMODEW)buf;
4379 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4380 if(space && size <= cbBuf) {
4381 pi9->pDevMode = (LPDEVMODEW)buf;
4387 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4388 memset(pi9, 0, sizeof(*pi9));
4393 /*****************************************************************************
4394 * GetPrinterW [WINSPOOL.@]
4396 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4397 DWORD cbBuf, LPDWORD pcbNeeded)
4399 DWORD size, needed = 0, err;
4404 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4406 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4409 SetLastError( err );
4416 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4418 size = sizeof(PRINTER_INFO_2W);
4420 ptr = pPrinter + size;
4422 memset(pPrinter, 0, size);
4427 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4434 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4436 size = sizeof(PRINTER_INFO_4W);
4438 ptr = pPrinter + size;
4440 memset(pPrinter, 0, size);
4445 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4453 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4455 size = sizeof(PRINTER_INFO_5W);
4457 ptr = pPrinter + size;
4459 memset(pPrinter, 0, size);
4465 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4473 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4475 size = sizeof(PRINTER_INFO_6);
4476 if (size <= cbBuf) {
4477 /* FIXME: We do not update the status yet */
4478 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4490 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4492 size = sizeof(PRINTER_INFO_7W);
4493 if (size <= cbBuf) {
4494 ptr = pPrinter + size;
4496 memset(pPrinter, 0, size);
4502 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4509 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4510 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4514 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4516 size = sizeof(PRINTER_INFO_9W);
4518 ptr = pPrinter + size;
4520 memset(pPrinter, 0, size);
4526 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4533 FIXME("Unimplemented level %d\n", Level);
4534 SetLastError(ERROR_INVALID_LEVEL);
4535 RegCloseKey(hkeyPrinter);
4539 RegCloseKey(hkeyPrinter);
4541 TRACE("returning %d needed = %d\n", ret, needed);
4542 if(pcbNeeded) *pcbNeeded = needed;
4544 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4548 /*****************************************************************************
4549 * GetPrinterA [WINSPOOL.@]
4551 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4552 DWORD cbBuf, LPDWORD pcbNeeded)
4558 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4560 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4562 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4563 HeapFree(GetProcessHeap(), 0, buf);
4568 /*****************************************************************************
4569 * WINSPOOL_EnumPrintersW
4571 * Implementation of EnumPrintersW
4573 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4574 DWORD dwLevel, LPBYTE lpbPrinters,
4575 DWORD cbBuf, LPDWORD lpdwNeeded,
4576 LPDWORD lpdwReturned)
4579 HKEY hkeyPrinters, hkeyPrinter;
4580 WCHAR PrinterName[255];
4581 DWORD needed = 0, number = 0;
4582 DWORD used, i, left;
4586 memset(lpbPrinters, 0, cbBuf);
4592 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4593 if(dwType == PRINTER_ENUM_DEFAULT)
4596 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4597 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4598 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4600 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4606 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4607 FIXME("dwType = %08x\n", dwType);
4608 SetLastError(ERROR_INVALID_FLAGS);
4612 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4614 ERR("Can't create Printers key\n");
4618 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4619 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4620 RegCloseKey(hkeyPrinters);
4621 ERR("Can't query Printers key\n");
4624 TRACE("Found %d printers\n", number);
4628 used = number * sizeof(PRINTER_INFO_1W);
4631 used = number * sizeof(PRINTER_INFO_2W);
4634 used = number * sizeof(PRINTER_INFO_4W);
4637 used = number * sizeof(PRINTER_INFO_5W);
4641 SetLastError(ERROR_INVALID_LEVEL);
4642 RegCloseKey(hkeyPrinters);
4645 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4647 for(i = 0; i < number; i++) {
4648 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4650 ERR("Can't enum key number %d\n", i);
4651 RegCloseKey(hkeyPrinters);
4654 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4655 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4657 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4658 RegCloseKey(hkeyPrinters);
4663 buf = lpbPrinters + used;
4664 left = cbBuf - used;
4672 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4675 if(pi) pi += sizeof(PRINTER_INFO_1W);
4678 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4681 if(pi) pi += sizeof(PRINTER_INFO_2W);
4684 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4687 if(pi) pi += sizeof(PRINTER_INFO_4W);
4690 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4693 if(pi) pi += sizeof(PRINTER_INFO_5W);
4696 ERR("Shouldn't be here!\n");
4697 RegCloseKey(hkeyPrinter);
4698 RegCloseKey(hkeyPrinters);
4701 RegCloseKey(hkeyPrinter);
4703 RegCloseKey(hkeyPrinters);
4710 memset(lpbPrinters, 0, cbBuf);
4711 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4715 *lpdwReturned = number;
4716 SetLastError(ERROR_SUCCESS);
4721 /******************************************************************
4722 * EnumPrintersW [WINSPOOL.@]
4724 * Enumerates the available printers, print servers and print
4725 * providers, depending on the specified flags, name and level.
4729 * If level is set to 1:
4730 * Returns an array of PRINTER_INFO_1 data structures in the
4731 * lpbPrinters buffer.
4733 * If level is set to 2:
4734 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4735 * Returns an array of PRINTER_INFO_2 data structures in the
4736 * lpbPrinters buffer. Note that according to MSDN also an
4737 * OpenPrinter should be performed on every remote printer.
4739 * If level is set to 4 (officially WinNT only):
4740 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4741 * Fast: Only the registry is queried to retrieve printer names,
4742 * no connection to the driver is made.
4743 * Returns an array of PRINTER_INFO_4 data structures in the
4744 * lpbPrinters buffer.
4746 * If level is set to 5 (officially WinNT4/Win9x only):
4747 * Fast: Only the registry is queried to retrieve printer names,
4748 * no connection to the driver is made.
4749 * Returns an array of PRINTER_INFO_5 data structures in the
4750 * lpbPrinters buffer.
4752 * If level set to 3 or 6+:
4753 * returns zero (failure!)
4755 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4759 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4760 * - Only levels 2, 4 and 5 are implemented at the moment.
4761 * - 16-bit printer drivers are not enumerated.
4762 * - Returned amount of bytes used/needed does not match the real Windoze
4763 * implementation (as in this implementation, all strings are part
4764 * of the buffer, whereas Win32 keeps them somewhere else)
4765 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4768 * - In a regular Wine installation, no registry settings for printers
4769 * exist, which makes this function return an empty list.
4771 BOOL WINAPI EnumPrintersW(
4772 DWORD dwType, /* [in] Types of print objects to enumerate */
4773 LPWSTR lpszName, /* [in] name of objects to enumerate */
4774 DWORD dwLevel, /* [in] type of printer info structure */
4775 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4776 DWORD cbBuf, /* [in] max size of buffer in bytes */
4777 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4778 LPDWORD lpdwReturned /* [out] number of entries returned */
4781 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4782 lpdwNeeded, lpdwReturned);
4785 /******************************************************************
4786 * EnumPrintersA [WINSPOOL.@]
4791 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4792 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4795 UNICODE_STRING pNameU;
4799 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4800 pPrinters, cbBuf, pcbNeeded, pcReturned);
4802 pNameW = asciitounicode(&pNameU, pName);
4804 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4805 MS Office need this */
4806 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4808 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4810 RtlFreeUnicodeString(&pNameU);
4812 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4814 HeapFree(GetProcessHeap(), 0, pPrintersW);
4818 /*****************************************************************************
4819 * WINSPOOL_GetDriverInfoFromReg [internal]
4821 * Enters the information from the registry into the DRIVER_INFO struct
4824 * zero if the printer driver does not exist in the registry
4825 * (only if Level > 1) otherwise nonzero
4827 static BOOL WINSPOOL_GetDriverInfoFromReg(
4830 const printenv_t * env,
4832 LPBYTE ptr, /* DRIVER_INFO */
4833 LPBYTE pDriverStrings, /* strings buffer */
4834 DWORD cbBuf, /* size of string buffer */
4835 LPDWORD pcbNeeded) /* space needed for str. */
4839 WCHAR driverdir[MAX_PATH];
4841 LPBYTE strPtr = pDriverStrings;
4842 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4844 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4845 debugstr_w(DriverName), env,
4846 Level, di, pDriverStrings, cbBuf);
4848 if (di) ZeroMemory(di, di_sizeof[Level]);
4850 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4851 if (*pcbNeeded <= cbBuf)
4852 strcpyW((LPWSTR)strPtr, DriverName);
4854 /* pName for level 1 has a different offset! */
4856 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4860 /* .cVersion and .pName for level > 1 */
4862 di->cVersion = env->driverversion;
4863 di->pName = (LPWSTR) strPtr;
4864 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4867 /* Reserve Space for the largest subdir and a Backslash*/
4868 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4869 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4870 /* Should never Fail */
4873 lstrcatW(driverdir, env->versionsubdir);
4874 lstrcatW(driverdir, backslashW);
4876 /* dirlen must not include the terminating zero */
4877 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4879 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4880 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4881 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4886 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4889 if (*pcbNeeded <= cbBuf) {
4890 lstrcpyW((LPWSTR)strPtr, env->envname);
4891 if (di) di->pEnvironment = (LPWSTR)strPtr;
4892 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4895 /* .pDriverPath is the Graphics rendering engine.
4896 The full Path is required to avoid a crash in some apps */
4897 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4899 if (*pcbNeeded <= cbBuf)
4900 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4902 if (di) di->pDriverPath = (LPWSTR)strPtr;
4903 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4906 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4907 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4909 if (*pcbNeeded <= cbBuf)
4910 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4912 if (di) di->pDataFile = (LPWSTR)strPtr;
4913 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4916 /* .pConfigFile is the Driver user Interface */
4917 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4919 if (*pcbNeeded <= cbBuf)
4920 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4922 if (di) di->pConfigFile = (LPWSTR)strPtr;
4923 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4927 RegCloseKey(hkeyDriver);
4928 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4933 RegCloseKey(hkeyDriver);
4934 FIXME("level 5: incomplete\n");
4939 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4941 if (*pcbNeeded <= cbBuf)
4942 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4944 if (di) di->pHelpFile = (LPWSTR)strPtr;
4945 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4948 /* .pDependentFiles */
4949 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4951 if (*pcbNeeded <= cbBuf)
4952 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4954 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4955 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4957 else if (GetVersion() & 0x80000000) {
4958 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4959 size = 2 * sizeof(WCHAR);
4961 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4963 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4964 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4967 /* .pMonitorName is the optional Language Monitor */
4968 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4970 if (*pcbNeeded <= cbBuf)
4971 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4973 if (di) di->pMonitorName = (LPWSTR)strPtr;
4974 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4977 /* .pDefaultDataType */
4978 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4980 if(*pcbNeeded <= cbBuf)
4981 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4983 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4984 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4988 RegCloseKey(hkeyDriver);
4989 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4993 /* .pszzPreviousNames */
4994 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4996 if(*pcbNeeded <= cbBuf)
4997 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4999 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5000 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5004 RegCloseKey(hkeyDriver);
5005 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5009 /* support is missing, but not important enough for a FIXME */
5010 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5013 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5015 if(*pcbNeeded <= cbBuf)
5016 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5018 if (di) di->pszMfgName = (LPWSTR)strPtr;
5019 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5023 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5025 if(*pcbNeeded <= cbBuf)
5026 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5028 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5029 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5032 /* .pszHardwareID */
5033 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5035 if(*pcbNeeded <= cbBuf)
5036 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5038 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5039 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5043 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5045 if(*pcbNeeded <= cbBuf)
5046 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5048 if (di) di->pszProvider = (LPWSTR)strPtr;
5049 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5053 RegCloseKey(hkeyDriver);
5057 /* support is missing, but not important enough for a FIXME */
5058 TRACE("level 8: incomplete\n");
5060 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5061 RegCloseKey(hkeyDriver);
5065 /*****************************************************************************
5066 * GetPrinterDriverW [WINSPOOL.@]
5068 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5069 DWORD Level, LPBYTE pDriverInfo,
5070 DWORD cbBuf, LPDWORD pcbNeeded)
5073 WCHAR DriverName[100];
5074 DWORD ret, type, size, needed = 0;
5076 HKEY hkeyPrinter, hkeyDrivers;
5077 const printenv_t * env;
5079 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5080 Level,pDriverInfo,cbBuf, pcbNeeded);
5083 ZeroMemory(pDriverInfo, cbBuf);
5085 if (!(name = get_opened_printer_name(hPrinter))) {
5086 SetLastError(ERROR_INVALID_HANDLE);
5090 if (Level < 1 || Level == 7 || Level > 8) {
5091 SetLastError(ERROR_INVALID_LEVEL);
5095 env = validate_envW(pEnvironment);
5096 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5098 ret = open_printer_reg_key( name, &hkeyPrinter );
5101 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5102 SetLastError( ret );
5106 size = sizeof(DriverName);
5108 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5109 (LPBYTE)DriverName, &size);
5110 RegCloseKey(hkeyPrinter);
5111 if(ret != ERROR_SUCCESS) {
5112 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5116 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5118 ERR("Can't create Drivers key\n");
5122 size = di_sizeof[Level];
5123 if ((size <= cbBuf) && pDriverInfo)
5124 ptr = pDriverInfo + size;
5126 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5127 env, Level, pDriverInfo, ptr,
5128 (cbBuf < size) ? 0 : cbBuf - size,
5130 RegCloseKey(hkeyDrivers);
5134 RegCloseKey(hkeyDrivers);
5136 if(pcbNeeded) *pcbNeeded = size + needed;
5137 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5138 if(cbBuf >= size + needed) return TRUE;
5139 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5143 /*****************************************************************************
5144 * GetPrinterDriverA [WINSPOOL.@]
5146 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5147 DWORD Level, LPBYTE pDriverInfo,
5148 DWORD cbBuf, LPDWORD pcbNeeded)
5151 UNICODE_STRING pEnvW;
5157 ZeroMemory(pDriverInfo, cbBuf);
5158 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5161 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5162 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5165 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5167 HeapFree(GetProcessHeap(), 0, buf);
5169 RtlFreeUnicodeString(&pEnvW);
5173 /*****************************************************************************
5174 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5176 * Return the PATH for the Printer-Drivers (UNICODE)
5179 * pName [I] Servername (NT only) or NULL (local Computer)
5180 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5181 * Level [I] Structure-Level (must be 1)
5182 * pDriverDirectory [O] PTR to Buffer that receives the Result
5183 * cbBuf [I] Size of Buffer at pDriverDirectory
5184 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5185 * required for pDriverDirectory
5188 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5189 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5190 * if cbBuf is too small
5192 * Native Values returned in pDriverDirectory on Success:
5193 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5194 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5195 *| win9x(Windows 4.0): "%winsysdir%"
5197 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5200 *- Only NULL or "" is supported for pName
5203 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5204 DWORD Level, LPBYTE pDriverDirectory,
5205 DWORD cbBuf, LPDWORD pcbNeeded)
5207 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5208 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5210 if ((backend == NULL) && !load_backend()) return FALSE;
5213 /* (Level != 1) is ignored in win9x */
5214 SetLastError(ERROR_INVALID_LEVEL);
5217 if (pcbNeeded == NULL) {
5218 /* (pcbNeeded == NULL) is ignored in win9x */
5219 SetLastError(RPC_X_NULL_REF_POINTER);
5223 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5224 pDriverDirectory, cbBuf, pcbNeeded);
5229 /*****************************************************************************
5230 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5232 * Return the PATH for the Printer-Drivers (ANSI)
5234 * See GetPrinterDriverDirectoryW.
5237 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5240 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5241 DWORD Level, LPBYTE pDriverDirectory,
5242 DWORD cbBuf, LPDWORD pcbNeeded)
5244 UNICODE_STRING nameW, environmentW;
5247 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5248 WCHAR *driverDirectoryW = NULL;
5250 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5251 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5253 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5255 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5256 else nameW.Buffer = NULL;
5257 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5258 else environmentW.Buffer = NULL;
5260 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5261 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5264 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5265 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5267 *pcbNeeded = needed;
5268 ret = needed <= cbBuf;
5270 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5272 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5274 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5275 RtlFreeUnicodeString(&environmentW);
5276 RtlFreeUnicodeString(&nameW);
5281 /*****************************************************************************
5282 * AddPrinterDriverA [WINSPOOL.@]
5284 * See AddPrinterDriverW.
5287 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5289 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5290 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5293 /******************************************************************************
5294 * AddPrinterDriverW (WINSPOOL.@)
5296 * Install a Printer Driver
5299 * pName [I] Servername or NULL (local Computer)
5300 * level [I] Level for the supplied DRIVER_INFO_*W struct
5301 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5308 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5310 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5311 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5314 /*****************************************************************************
5315 * AddPrintProcessorA [WINSPOOL.@]
5317 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5318 LPSTR pPrintProcessorName)
5320 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5321 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5325 /*****************************************************************************
5326 * AddPrintProcessorW [WINSPOOL.@]
5328 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5329 LPWSTR pPrintProcessorName)
5331 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5332 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5336 /*****************************************************************************
5337 * AddPrintProvidorA [WINSPOOL.@]
5339 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5341 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5345 /*****************************************************************************
5346 * AddPrintProvidorW [WINSPOOL.@]
5348 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5350 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5354 /*****************************************************************************
5355 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5357 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5358 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5360 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5361 pDevModeOutput, pDevModeInput);
5365 /*****************************************************************************
5366 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5368 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5369 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5371 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5372 pDevModeOutput, pDevModeInput);
5376 /*****************************************************************************
5377 * PrinterProperties [WINSPOOL.@]
5379 * Displays a dialog to set the properties of the printer.
5382 * nonzero on success or zero on failure
5385 * implemented as stub only
5387 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5388 HANDLE hPrinter /* [in] handle to printer object */
5390 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5391 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5395 /*****************************************************************************
5396 * EnumJobsA [WINSPOOL.@]
5399 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5400 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5403 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5404 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5406 if(pcbNeeded) *pcbNeeded = 0;
5407 if(pcReturned) *pcReturned = 0;
5412 /*****************************************************************************
5413 * EnumJobsW [WINSPOOL.@]
5416 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5417 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5420 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5421 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5423 if(pcbNeeded) *pcbNeeded = 0;
5424 if(pcReturned) *pcReturned = 0;
5428 /*****************************************************************************
5429 * WINSPOOL_EnumPrinterDrivers [internal]
5431 * Delivers information about all printer drivers installed on the
5432 * localhost or a given server
5435 * nonzero on success or zero on failure. If the buffer for the returned
5436 * information is too small the function will return an error
5439 * - only implemented for localhost, foreign hosts will return an error
5441 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5442 DWORD Level, LPBYTE pDriverInfo,
5444 DWORD cbBuf, LPDWORD pcbNeeded,
5445 LPDWORD pcFound, DWORD data_offset)
5449 const printenv_t * env;
5451 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5452 debugstr_w(pName), debugstr_w(pEnvironment),
5453 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5455 env = validate_envW(pEnvironment);
5456 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5460 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5462 ERR("Can't open Drivers key\n");
5466 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5467 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5468 RegCloseKey(hkeyDrivers);
5469 ERR("Can't query Drivers key\n");
5472 TRACE("Found %d Drivers\n", *pcFound);
5474 /* get size of single struct
5475 * unicode and ascii structure have the same size
5477 size = di_sizeof[Level];
5479 if (data_offset == 0)
5480 data_offset = size * (*pcFound);
5481 *pcbNeeded = data_offset;
5483 for( i = 0; i < *pcFound; i++) {
5484 WCHAR DriverNameW[255];
5485 PBYTE table_ptr = NULL;
5486 PBYTE data_ptr = NULL;
5489 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5491 ERR("Can't enum key number %d\n", i);
5492 RegCloseKey(hkeyDrivers);
5496 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5497 table_ptr = pDriverInfo + (driver_index + i) * size;
5498 if (pDriverInfo && *pcbNeeded <= cbBuf)
5499 data_ptr = pDriverInfo + *pcbNeeded;
5501 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5502 env, Level, table_ptr, data_ptr,
5503 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5505 RegCloseKey(hkeyDrivers);
5509 *pcbNeeded += needed;
5512 RegCloseKey(hkeyDrivers);
5514 if(cbBuf < *pcbNeeded){
5515 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5522 /*****************************************************************************
5523 * EnumPrinterDriversW [WINSPOOL.@]
5525 * see function EnumPrinterDrivers for RETURNS, BUGS
5527 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5528 LPBYTE pDriverInfo, DWORD cbBuf,
5529 LPDWORD pcbNeeded, LPDWORD pcReturned)
5531 static const WCHAR allW[] = {'a','l','l',0};
5535 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5537 SetLastError(RPC_X_NULL_REF_POINTER);
5541 /* check for local drivers */
5542 if((pName) && (pName[0])) {
5543 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5544 SetLastError(ERROR_ACCESS_DENIED);
5548 /* check input parameter */
5549 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5550 SetLastError(ERROR_INVALID_LEVEL);
5554 if(pDriverInfo && cbBuf > 0)
5555 memset( pDriverInfo, 0, cbBuf);
5557 /* Exception: pull all printers */
5558 if (pEnvironment && !strcmpW(pEnvironment, allW))
5560 DWORD i, needed, bufsize = cbBuf;
5561 DWORD total_found = 0;
5564 /* Precompute the overall total; we need this to know
5565 where pointers end and data begins (i.e. data_offset) */
5566 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5569 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5570 NULL, 0, 0, &needed, &found, 0);
5571 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5572 total_found += found;
5575 data_offset = di_sizeof[Level] * total_found;
5580 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5583 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5584 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5585 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5587 *pcReturned += found;
5588 *pcbNeeded = needed;
5589 data_offset = needed;
5590 total_found += found;
5595 /* Normal behavior */
5596 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5597 0, cbBuf, pcbNeeded, &found, 0);
5599 *pcReturned = found;
5604 /*****************************************************************************
5605 * EnumPrinterDriversA [WINSPOOL.@]
5607 * see function EnumPrinterDrivers for RETURNS, BUGS
5609 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5610 LPBYTE pDriverInfo, DWORD cbBuf,
5611 LPDWORD pcbNeeded, LPDWORD pcReturned)
5614 UNICODE_STRING pNameW, pEnvironmentW;
5615 PWSTR pwstrNameW, pwstrEnvironmentW;
5619 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5621 pwstrNameW = asciitounicode(&pNameW, pName);
5622 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5624 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5625 buf, cbBuf, pcbNeeded, pcReturned);
5627 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5629 HeapFree(GetProcessHeap(), 0, buf);
5631 RtlFreeUnicodeString(&pNameW);
5632 RtlFreeUnicodeString(&pEnvironmentW);
5637 /******************************************************************************
5638 * EnumPortsA (WINSPOOL.@)
5643 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5644 LPDWORD pcbNeeded, LPDWORD pcReturned)
5647 LPBYTE bufferW = NULL;
5648 LPWSTR nameW = NULL;
5650 DWORD numentries = 0;
5653 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5654 cbBuf, pcbNeeded, pcReturned);
5656 /* convert servername to unicode */
5658 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5659 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5660 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5662 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5663 needed = cbBuf * sizeof(WCHAR);
5664 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5665 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5667 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5668 if (pcbNeeded) needed = *pcbNeeded;
5669 /* HeapReAlloc return NULL, when bufferW was NULL */
5670 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5671 HeapAlloc(GetProcessHeap(), 0, needed);
5673 /* Try again with the large Buffer */
5674 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5676 needed = pcbNeeded ? *pcbNeeded : 0;
5677 numentries = pcReturned ? *pcReturned : 0;
5680 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5681 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5684 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5685 DWORD entrysize = 0;
5688 LPPORT_INFO_2W pi2w;
5689 LPPORT_INFO_2A pi2a;
5692 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5694 /* First pass: calculate the size for all Entries */
5695 pi2w = (LPPORT_INFO_2W) bufferW;
5696 pi2a = (LPPORT_INFO_2A) pPorts;
5698 while (index < numentries) {
5700 needed += entrysize; /* PORT_INFO_?A */
5701 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5703 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5704 NULL, 0, NULL, NULL);
5706 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5707 NULL, 0, NULL, NULL);
5708 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5709 NULL, 0, NULL, NULL);
5711 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5712 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5713 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5716 /* check for errors and quit on failure */
5717 if (cbBuf < needed) {
5718 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5722 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5723 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5724 cbBuf -= len ; /* free Bytes in the user-Buffer */
5725 pi2w = (LPPORT_INFO_2W) bufferW;
5726 pi2a = (LPPORT_INFO_2A) pPorts;
5728 /* Second Pass: Fill the User Buffer (if we have one) */
5729 while ((index < numentries) && pPorts) {
5731 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5732 pi2a->pPortName = ptr;
5733 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5734 ptr, cbBuf , NULL, NULL);
5738 pi2a->pMonitorName = ptr;
5739 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5740 ptr, cbBuf, NULL, NULL);
5744 pi2a->pDescription = ptr;
5745 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5746 ptr, cbBuf, NULL, NULL);
5750 pi2a->fPortType = pi2w->fPortType;
5751 pi2a->Reserved = 0; /* documented: "must be zero" */
5754 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5755 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5756 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5761 if (pcbNeeded) *pcbNeeded = needed;
5762 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5764 HeapFree(GetProcessHeap(), 0, nameW);
5765 HeapFree(GetProcessHeap(), 0, bufferW);
5767 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5768 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5774 /******************************************************************************
5775 * EnumPortsW (WINSPOOL.@)
5777 * Enumerate available Ports
5780 * pName [I] Servername or NULL (local Computer)
5781 * Level [I] Structure-Level (1 or 2)
5782 * pPorts [O] PTR to Buffer that receives the Result
5783 * cbBuf [I] Size of Buffer at pPorts
5784 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5785 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5789 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5792 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5795 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5796 cbBuf, pcbNeeded, pcReturned);
5798 if ((backend == NULL) && !load_backend()) return FALSE;
5800 /* Level is not checked in win9x */
5801 if (!Level || (Level > 2)) {
5802 WARN("level (%d) is ignored in win9x\n", Level);
5803 SetLastError(ERROR_INVALID_LEVEL);
5806 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5807 SetLastError(RPC_X_NULL_REF_POINTER);
5811 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5814 /******************************************************************************
5815 * GetDefaultPrinterW (WINSPOOL.@)
5818 * This function must read the value from data 'device' of key
5819 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5821 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5825 WCHAR *buffer, *ptr;
5829 SetLastError(ERROR_INVALID_PARAMETER);
5833 /* make the buffer big enough for the stuff from the profile/registry,
5834 * the content must fit into the local buffer to compute the correct
5835 * size even if the extern buffer is too small or not given.
5836 * (20 for ,driver,port) */
5838 len = max(100, (insize + 20));
5839 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5841 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5843 SetLastError (ERROR_FILE_NOT_FOUND);
5847 TRACE("%s\n", debugstr_w(buffer));
5849 if ((ptr = strchrW(buffer, ',')) == NULL)
5851 SetLastError(ERROR_INVALID_NAME);
5857 *namesize = strlenW(buffer) + 1;
5858 if(!name || (*namesize > insize))
5860 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5864 strcpyW(name, buffer);
5867 HeapFree( GetProcessHeap(), 0, buffer);
5872 /******************************************************************************
5873 * GetDefaultPrinterA (WINSPOOL.@)
5875 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5879 WCHAR *bufferW = NULL;
5883 SetLastError(ERROR_INVALID_PARAMETER);
5887 if(name && *namesize) {
5889 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5892 if(!GetDefaultPrinterW( bufferW, namesize)) {
5897 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5901 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5904 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5907 HeapFree( GetProcessHeap(), 0, bufferW);
5912 /******************************************************************************
5913 * SetDefaultPrinterW (WINSPOOL.204)
5915 * Set the Name of the Default Printer
5918 * pszPrinter [I] Name of the Printer or NULL
5925 * When the Parameter is NULL or points to an Empty String and
5926 * a Default Printer was already present, then this Function changes nothing.
5927 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5928 * the First enumerated local Printer is used.
5931 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5933 WCHAR default_printer[MAX_PATH];
5934 LPWSTR buffer = NULL;
5940 TRACE("(%s)\n", debugstr_w(pszPrinter));
5941 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5943 default_printer[0] = '\0';
5944 size = sizeof(default_printer)/sizeof(WCHAR);
5946 /* if we have a default Printer, do nothing. */
5947 if (GetDefaultPrinterW(default_printer, &size))
5951 /* we have no default Printer: search local Printers and use the first */
5952 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5954 default_printer[0] = '\0';
5955 size = sizeof(default_printer)/sizeof(WCHAR);
5956 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5958 pszPrinter = default_printer;
5959 TRACE("using %s\n", debugstr_w(pszPrinter));
5964 if (pszPrinter == NULL) {
5965 TRACE("no local printer found\n");
5966 SetLastError(ERROR_FILE_NOT_FOUND);
5971 /* "pszPrinter" is never empty or NULL here. */
5972 namelen = lstrlenW(pszPrinter);
5973 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5974 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5976 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5977 HeapFree(GetProcessHeap(), 0, buffer);
5978 SetLastError(ERROR_FILE_NOT_FOUND);
5982 /* read the devices entry for the printer (driver,port) to build the string for the
5983 default device entry (printer,driver,port) */
5984 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5985 buffer[namelen] = ',';
5986 namelen++; /* move index to the start of the driver */
5988 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5989 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5991 TRACE("set device to %s\n", debugstr_w(buffer));
5993 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5994 TRACE("failed to set the device entry: %d\n", GetLastError());
5995 lres = ERROR_INVALID_PRINTER_NAME;
5998 /* remove the next section, when INIFileMapping is implemented */
6001 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6002 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6009 if (lres != ERROR_FILE_NOT_FOUND)
6010 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6012 SetLastError(ERROR_INVALID_PRINTER_NAME);
6016 HeapFree(GetProcessHeap(), 0, buffer);
6017 return (lres == ERROR_SUCCESS);
6020 /******************************************************************************
6021 * SetDefaultPrinterA (WINSPOOL.202)
6023 * See SetDefaultPrinterW.
6026 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6028 LPWSTR bufferW = NULL;
6031 TRACE("(%s)\n", debugstr_a(pszPrinter));
6033 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6034 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6035 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6037 res = SetDefaultPrinterW(bufferW);
6038 HeapFree(GetProcessHeap(), 0, bufferW);
6042 /******************************************************************************
6043 * SetPrinterDataExA (WINSPOOL.@)
6045 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6046 LPCSTR pValueName, DWORD Type,
6047 LPBYTE pData, DWORD cbData)
6049 HKEY hkeyPrinter, hkeySubkey;
6052 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6053 debugstr_a(pValueName), Type, pData, cbData);
6055 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6059 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6061 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6062 RegCloseKey(hkeyPrinter);
6065 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6066 RegCloseKey(hkeySubkey);
6067 RegCloseKey(hkeyPrinter);
6071 /******************************************************************************
6072 * SetPrinterDataExW (WINSPOOL.@)
6074 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6075 LPCWSTR pValueName, DWORD Type,
6076 LPBYTE pData, DWORD cbData)
6078 HKEY hkeyPrinter, hkeySubkey;
6081 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6082 debugstr_w(pValueName), Type, pData, cbData);
6084 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6088 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6090 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6091 RegCloseKey(hkeyPrinter);
6094 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6095 RegCloseKey(hkeySubkey);
6096 RegCloseKey(hkeyPrinter);
6100 /******************************************************************************
6101 * SetPrinterDataA (WINSPOOL.@)
6103 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6104 LPBYTE pData, DWORD cbData)
6106 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6110 /******************************************************************************
6111 * SetPrinterDataW (WINSPOOL.@)
6113 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6114 LPBYTE pData, DWORD cbData)
6116 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6120 /******************************************************************************
6121 * GetPrinterDataExA (WINSPOOL.@)
6123 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6124 LPCSTR pValueName, LPDWORD pType,
6125 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6127 opened_printer_t *printer;
6128 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6131 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6132 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6134 printer = get_opened_printer(hPrinter);
6135 if(!printer) return ERROR_INVALID_HANDLE;
6137 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6138 if (ret) return ret;
6140 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6142 if (printer->name) {
6144 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6146 RegCloseKey(hkeyPrinters);
6149 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6150 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6151 RegCloseKey(hkeyPrinter);
6152 RegCloseKey(hkeyPrinters);
6157 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6158 0, pType, pData, pcbNeeded);
6160 if (!ret && !pData) ret = ERROR_MORE_DATA;
6162 RegCloseKey(hkeySubkey);
6163 RegCloseKey(hkeyPrinter);
6164 RegCloseKey(hkeyPrinters);
6166 TRACE("--> %d\n", ret);
6170 /******************************************************************************
6171 * GetPrinterDataExW (WINSPOOL.@)
6173 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6174 LPCWSTR pValueName, LPDWORD pType,
6175 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6177 opened_printer_t *printer;
6178 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6181 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6182 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6184 printer = get_opened_printer(hPrinter);
6185 if(!printer) return ERROR_INVALID_HANDLE;
6187 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6188 if (ret) return ret;
6190 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6192 if (printer->name) {
6194 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6196 RegCloseKey(hkeyPrinters);
6199 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6200 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6201 RegCloseKey(hkeyPrinter);
6202 RegCloseKey(hkeyPrinters);
6207 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6208 0, pType, pData, pcbNeeded);
6210 if (!ret && !pData) ret = ERROR_MORE_DATA;
6212 RegCloseKey(hkeySubkey);
6213 RegCloseKey(hkeyPrinter);
6214 RegCloseKey(hkeyPrinters);
6216 TRACE("--> %d\n", ret);
6220 /******************************************************************************
6221 * GetPrinterDataA (WINSPOOL.@)
6223 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6224 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6226 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6227 pData, nSize, pcbNeeded);
6230 /******************************************************************************
6231 * GetPrinterDataW (WINSPOOL.@)
6233 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6234 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6236 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6237 pData, nSize, pcbNeeded);
6240 /*******************************************************************************
6241 * EnumPrinterDataExW [WINSPOOL.@]
6243 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6244 LPBYTE pEnumValues, DWORD cbEnumValues,
6245 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6247 HKEY hkPrinter, hkSubKey;
6248 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6249 cbValueNameLen, cbMaxValueLen, cbValueLen,
6254 PPRINTER_ENUM_VALUESW ppev;
6256 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6258 if (pKeyName == NULL || *pKeyName == 0)
6259 return ERROR_INVALID_PARAMETER;
6261 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6262 if (ret != ERROR_SUCCESS)
6264 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6269 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6270 if (ret != ERROR_SUCCESS)
6272 r = RegCloseKey (hkPrinter);
6273 if (r != ERROR_SUCCESS)
6274 WARN ("RegCloseKey returned %i\n", r);
6275 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6276 debugstr_w (pKeyName), ret);
6280 ret = RegCloseKey (hkPrinter);
6281 if (ret != ERROR_SUCCESS)
6283 ERR ("RegCloseKey returned %i\n", ret);
6284 r = RegCloseKey (hkSubKey);
6285 if (r != ERROR_SUCCESS)
6286 WARN ("RegCloseKey returned %i\n", r);
6290 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6291 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6292 if (ret != ERROR_SUCCESS)
6294 r = RegCloseKey (hkSubKey);
6295 if (r != ERROR_SUCCESS)
6296 WARN ("RegCloseKey returned %i\n", r);
6297 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6301 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6302 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6304 if (cValues == 0) /* empty key */
6306 r = RegCloseKey (hkSubKey);
6307 if (r != ERROR_SUCCESS)
6308 WARN ("RegCloseKey returned %i\n", r);
6309 *pcbEnumValues = *pnEnumValues = 0;
6310 return ERROR_SUCCESS;
6313 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6315 hHeap = GetProcessHeap ();
6318 ERR ("GetProcessHeap failed\n");
6319 r = RegCloseKey (hkSubKey);
6320 if (r != ERROR_SUCCESS)
6321 WARN ("RegCloseKey returned %i\n", r);
6322 return ERROR_OUTOFMEMORY;
6325 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6326 if (lpValueName == NULL)
6328 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6329 r = RegCloseKey (hkSubKey);
6330 if (r != ERROR_SUCCESS)
6331 WARN ("RegCloseKey returned %i\n", r);
6332 return ERROR_OUTOFMEMORY;
6335 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6336 if (lpValue == NULL)
6338 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6339 if (HeapFree (hHeap, 0, lpValueName) == 0)
6340 WARN ("HeapFree failed with code %i\n", GetLastError ());
6341 r = RegCloseKey (hkSubKey);
6342 if (r != ERROR_SUCCESS)
6343 WARN ("RegCloseKey returned %i\n", r);
6344 return ERROR_OUTOFMEMORY;
6347 TRACE ("pass 1: calculating buffer required for all names and values\n");
6349 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6351 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6353 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6355 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6356 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6357 NULL, NULL, lpValue, &cbValueLen);
6358 if (ret != ERROR_SUCCESS)
6360 if (HeapFree (hHeap, 0, lpValue) == 0)
6361 WARN ("HeapFree failed with code %i\n", GetLastError ());
6362 if (HeapFree (hHeap, 0, lpValueName) == 0)
6363 WARN ("HeapFree failed with code %i\n", GetLastError ());
6364 r = RegCloseKey (hkSubKey);
6365 if (r != ERROR_SUCCESS)
6366 WARN ("RegCloseKey returned %i\n", r);
6367 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6371 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6372 debugstr_w (lpValueName), dwIndex,
6373 cbValueNameLen + 1, cbValueLen);
6375 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6376 cbBufSize += cbValueLen;
6379 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6381 *pcbEnumValues = cbBufSize;
6382 *pnEnumValues = cValues;
6384 if (cbEnumValues < cbBufSize) /* buffer too small */
6386 if (HeapFree (hHeap, 0, lpValue) == 0)
6387 WARN ("HeapFree failed with code %i\n", GetLastError ());
6388 if (HeapFree (hHeap, 0, lpValueName) == 0)
6389 WARN ("HeapFree failed with code %i\n", GetLastError ());
6390 r = RegCloseKey (hkSubKey);
6391 if (r != ERROR_SUCCESS)
6392 WARN ("RegCloseKey returned %i\n", r);
6393 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6394 return ERROR_MORE_DATA;
6397 TRACE ("pass 2: copying all names and values to buffer\n");
6399 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6400 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6402 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6404 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6405 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6406 NULL, &dwType, lpValue, &cbValueLen);
6407 if (ret != ERROR_SUCCESS)
6409 if (HeapFree (hHeap, 0, lpValue) == 0)
6410 WARN ("HeapFree failed with code %i\n", GetLastError ());
6411 if (HeapFree (hHeap, 0, lpValueName) == 0)
6412 WARN ("HeapFree failed with code %i\n", GetLastError ());
6413 r = RegCloseKey (hkSubKey);
6414 if (r != ERROR_SUCCESS)
6415 WARN ("RegCloseKey returned %i\n", r);
6416 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6420 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6421 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6422 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6423 pEnumValues += cbValueNameLen;
6425 /* return # of *bytes* (including trailing \0), not # of chars */
6426 ppev[dwIndex].cbValueName = cbValueNameLen;
6428 ppev[dwIndex].dwType = dwType;
6430 memcpy (pEnumValues, lpValue, cbValueLen);
6431 ppev[dwIndex].pData = pEnumValues;
6432 pEnumValues += cbValueLen;
6434 ppev[dwIndex].cbData = cbValueLen;
6436 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6437 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6440 if (HeapFree (hHeap, 0, lpValue) == 0)
6442 ret = GetLastError ();
6443 ERR ("HeapFree failed with code %i\n", ret);
6444 if (HeapFree (hHeap, 0, lpValueName) == 0)
6445 WARN ("HeapFree failed with code %i\n", GetLastError ());
6446 r = RegCloseKey (hkSubKey);
6447 if (r != ERROR_SUCCESS)
6448 WARN ("RegCloseKey returned %i\n", r);
6452 if (HeapFree (hHeap, 0, lpValueName) == 0)
6454 ret = GetLastError ();
6455 ERR ("HeapFree failed with code %i\n", ret);
6456 r = RegCloseKey (hkSubKey);
6457 if (r != ERROR_SUCCESS)
6458 WARN ("RegCloseKey returned %i\n", r);
6462 ret = RegCloseKey (hkSubKey);
6463 if (ret != ERROR_SUCCESS)
6465 ERR ("RegCloseKey returned %i\n", ret);
6469 return ERROR_SUCCESS;
6472 /*******************************************************************************
6473 * EnumPrinterDataExA [WINSPOOL.@]
6475 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6476 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6477 * what Windows 2000 SP1 does.
6480 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6481 LPBYTE pEnumValues, DWORD cbEnumValues,
6482 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6486 DWORD ret, dwIndex, dwBufSize;
6490 TRACE ("%p %s\n", hPrinter, pKeyName);
6492 if (pKeyName == NULL || *pKeyName == 0)
6493 return ERROR_INVALID_PARAMETER;
6495 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6498 ret = GetLastError ();
6499 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6503 hHeap = GetProcessHeap ();
6506 ERR ("GetProcessHeap failed\n");
6507 return ERROR_OUTOFMEMORY;
6510 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6511 if (pKeyNameW == NULL)
6513 ERR ("Failed to allocate %i bytes from process heap\n",
6514 (LONG)(len * sizeof (WCHAR)));
6515 return ERROR_OUTOFMEMORY;
6518 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6520 ret = GetLastError ();
6521 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6522 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6523 WARN ("HeapFree failed with code %i\n", GetLastError ());
6527 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6528 pcbEnumValues, pnEnumValues);
6529 if (ret != ERROR_SUCCESS)
6531 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6532 WARN ("HeapFree failed with code %i\n", GetLastError ());
6533 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6537 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6539 ret = GetLastError ();
6540 ERR ("HeapFree failed with code %i\n", ret);
6544 if (*pnEnumValues == 0) /* empty key */
6545 return ERROR_SUCCESS;
6548 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6550 PPRINTER_ENUM_VALUESW ppev =
6551 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6553 if (dwBufSize < ppev->cbValueName)
6554 dwBufSize = ppev->cbValueName;
6556 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6557 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6558 dwBufSize = ppev->cbData;
6561 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6563 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6564 if (pBuffer == NULL)
6566 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6567 return ERROR_OUTOFMEMORY;
6570 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6572 PPRINTER_ENUM_VALUESW ppev =
6573 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6575 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6576 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6580 ret = GetLastError ();
6581 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6582 if (HeapFree (hHeap, 0, pBuffer) == 0)
6583 WARN ("HeapFree failed with code %i\n", GetLastError ());
6587 memcpy (ppev->pValueName, pBuffer, len);
6589 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6591 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6592 ppev->dwType != REG_MULTI_SZ)
6595 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6596 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6599 ret = GetLastError ();
6600 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6601 if (HeapFree (hHeap, 0, pBuffer) == 0)
6602 WARN ("HeapFree failed with code %i\n", GetLastError ());
6606 memcpy (ppev->pData, pBuffer, len);
6608 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6609 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6612 if (HeapFree (hHeap, 0, pBuffer) == 0)
6614 ret = GetLastError ();
6615 ERR ("HeapFree failed with code %i\n", ret);
6619 return ERROR_SUCCESS;
6622 /******************************************************************************
6623 * AbortPrinter (WINSPOOL.@)
6625 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6627 FIXME("(%p), stub!\n", hPrinter);
6631 /******************************************************************************
6632 * AddPortA (WINSPOOL.@)
6637 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6639 LPWSTR nameW = NULL;
6640 LPWSTR monitorW = NULL;
6644 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6647 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6648 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6649 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6653 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6654 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6655 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6657 res = AddPortW(nameW, hWnd, monitorW);
6658 HeapFree(GetProcessHeap(), 0, nameW);
6659 HeapFree(GetProcessHeap(), 0, monitorW);
6663 /******************************************************************************
6664 * AddPortW (WINSPOOL.@)
6666 * Add a Port for a specific Monitor
6669 * pName [I] Servername or NULL (local Computer)
6670 * hWnd [I] Handle to parent Window for the Dialog-Box
6671 * pMonitorName [I] Name of the Monitor that manage the Port
6678 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6680 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6682 if ((backend == NULL) && !load_backend()) return FALSE;
6684 if (!pMonitorName) {
6685 SetLastError(RPC_X_NULL_REF_POINTER);
6689 return backend->fpAddPort(pName, hWnd, pMonitorName);
6692 /******************************************************************************
6693 * AddPortExA (WINSPOOL.@)
6698 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6701 PORT_INFO_2A * pi2A;
6702 LPWSTR nameW = NULL;
6703 LPWSTR monitorW = NULL;
6707 pi2A = (PORT_INFO_2A *) pBuffer;
6709 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6710 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6712 if ((level < 1) || (level > 2)) {
6713 SetLastError(ERROR_INVALID_LEVEL);
6718 SetLastError(ERROR_INVALID_PARAMETER);
6723 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6724 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6725 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6729 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6730 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6731 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6734 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6736 if (pi2A->pPortName) {
6737 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6738 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6739 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6743 if (pi2A->pMonitorName) {
6744 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6745 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6746 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6749 if (pi2A->pDescription) {
6750 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6751 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6752 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6754 pi2W.fPortType = pi2A->fPortType;
6755 pi2W.Reserved = pi2A->Reserved;
6758 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6760 HeapFree(GetProcessHeap(), 0, nameW);
6761 HeapFree(GetProcessHeap(), 0, monitorW);
6762 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6763 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6764 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6769 /******************************************************************************
6770 * AddPortExW (WINSPOOL.@)
6772 * Add a Port for a specific Monitor, without presenting a user interface
6775 * pName [I] Servername or NULL (local Computer)
6776 * level [I] Structure-Level (1 or 2) for pBuffer
6777 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6778 * pMonitorName [I] Name of the Monitor that manage the Port
6785 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6789 pi2 = (PORT_INFO_2W *) pBuffer;
6791 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6792 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6793 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6794 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6796 if ((backend == NULL) && !load_backend()) return FALSE;
6798 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6799 SetLastError(ERROR_INVALID_PARAMETER);
6803 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6806 /******************************************************************************
6807 * AddPrinterConnectionA (WINSPOOL.@)
6809 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6811 FIXME("%s\n", debugstr_a(pName));
6815 /******************************************************************************
6816 * AddPrinterConnectionW (WINSPOOL.@)
6818 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6820 FIXME("%s\n", debugstr_w(pName));
6824 /******************************************************************************
6825 * AddPrinterDriverExW (WINSPOOL.@)
6827 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6830 * pName [I] Servername or NULL (local Computer)
6831 * level [I] Level for the supplied DRIVER_INFO_*W struct
6832 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6833 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6840 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6842 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6844 if ((backend == NULL) && !load_backend()) return FALSE;
6846 if (level < 2 || level == 5 || level == 7 || level > 8) {
6847 SetLastError(ERROR_INVALID_LEVEL);
6852 SetLastError(ERROR_INVALID_PARAMETER);
6856 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6859 /******************************************************************************
6860 * AddPrinterDriverExA (WINSPOOL.@)
6862 * See AddPrinterDriverExW.
6865 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6867 DRIVER_INFO_8A *diA;
6869 LPWSTR nameW = NULL;
6874 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6876 diA = (DRIVER_INFO_8A *) pDriverInfo;
6877 ZeroMemory(&diW, sizeof(diW));
6879 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6880 SetLastError(ERROR_INVALID_LEVEL);
6885 SetLastError(ERROR_INVALID_PARAMETER);
6889 /* convert servername to unicode */
6891 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6892 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6893 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6897 diW.cVersion = diA->cVersion;
6900 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6901 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6902 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6905 if (diA->pEnvironment) {
6906 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6907 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6908 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6911 if (diA->pDriverPath) {
6912 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6913 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6914 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6917 if (diA->pDataFile) {
6918 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6919 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6920 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6923 if (diA->pConfigFile) {
6924 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6925 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6926 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6929 if ((Level > 2) && diA->pDependentFiles) {
6930 lenA = multi_sz_lenA(diA->pDependentFiles);
6931 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6932 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6933 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6936 if ((Level > 2) && diA->pMonitorName) {
6937 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6938 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6939 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6942 if ((Level > 3) && diA->pDefaultDataType) {
6943 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6944 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6945 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6948 if ((Level > 3) && diA->pszzPreviousNames) {
6949 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6950 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6951 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6952 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6955 if ((Level > 5) && diA->pszMfgName) {
6956 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6957 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6958 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6961 if ((Level > 5) && diA->pszOEMUrl) {
6962 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6963 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6964 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6967 if ((Level > 5) && diA->pszHardwareID) {
6968 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6969 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6970 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6973 if ((Level > 5) && diA->pszProvider) {
6974 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6975 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6976 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6980 FIXME("level %u is incomplete\n", Level);
6983 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6984 TRACE("got %u with %u\n", res, GetLastError());
6985 HeapFree(GetProcessHeap(), 0, nameW);
6986 HeapFree(GetProcessHeap(), 0, diW.pName);
6987 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6988 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6989 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6990 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6991 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6992 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6993 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6994 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6995 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6996 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6997 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6998 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7000 TRACE("=> %u with %u\n", res, GetLastError());
7004 /******************************************************************************
7005 * ConfigurePortA (WINSPOOL.@)
7007 * See ConfigurePortW.
7010 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7012 LPWSTR nameW = NULL;
7013 LPWSTR portW = NULL;
7017 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7019 /* convert servername to unicode */
7021 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7022 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7023 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7026 /* convert portname to unicode */
7028 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7029 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7030 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7033 res = ConfigurePortW(nameW, hWnd, portW);
7034 HeapFree(GetProcessHeap(), 0, nameW);
7035 HeapFree(GetProcessHeap(), 0, portW);
7039 /******************************************************************************
7040 * ConfigurePortW (WINSPOOL.@)
7042 * Display the Configuration-Dialog for a specific Port
7045 * pName [I] Servername or NULL (local Computer)
7046 * hWnd [I] Handle to parent Window for the Dialog-Box
7047 * pPortName [I] Name of the Port, that should be configured
7054 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7057 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7059 if ((backend == NULL) && !load_backend()) return FALSE;
7062 SetLastError(RPC_X_NULL_REF_POINTER);
7066 return backend->fpConfigurePort(pName, hWnd, pPortName);
7069 /******************************************************************************
7070 * ConnectToPrinterDlg (WINSPOOL.@)
7072 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7074 FIXME("%p %x\n", hWnd, Flags);
7078 /******************************************************************************
7079 * DeletePrinterConnectionA (WINSPOOL.@)
7081 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7083 FIXME("%s\n", debugstr_a(pName));
7087 /******************************************************************************
7088 * DeletePrinterConnectionW (WINSPOOL.@)
7090 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7092 FIXME("%s\n", debugstr_w(pName));
7096 /******************************************************************************
7097 * DeletePrinterDriverExW (WINSPOOL.@)
7099 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7100 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7105 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7106 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7108 if(pName && pName[0])
7110 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7111 SetLastError(ERROR_INVALID_PARAMETER);
7117 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7118 SetLastError(ERROR_INVALID_PARAMETER);
7122 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7126 ERR("Can't open drivers key\n");
7130 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7133 RegCloseKey(hkey_drivers);
7138 /******************************************************************************
7139 * DeletePrinterDriverExA (WINSPOOL.@)
7141 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7142 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7144 UNICODE_STRING NameW, EnvW, DriverW;
7147 asciitounicode(&NameW, pName);
7148 asciitounicode(&EnvW, pEnvironment);
7149 asciitounicode(&DriverW, pDriverName);
7151 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7153 RtlFreeUnicodeString(&DriverW);
7154 RtlFreeUnicodeString(&EnvW);
7155 RtlFreeUnicodeString(&NameW);
7160 /******************************************************************************
7161 * DeletePrinterDataExW (WINSPOOL.@)
7163 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7166 FIXME("%p %s %s\n", hPrinter,
7167 debugstr_w(pKeyName), debugstr_w(pValueName));
7168 return ERROR_INVALID_PARAMETER;
7171 /******************************************************************************
7172 * DeletePrinterDataExA (WINSPOOL.@)
7174 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7177 FIXME("%p %s %s\n", hPrinter,
7178 debugstr_a(pKeyName), debugstr_a(pValueName));
7179 return ERROR_INVALID_PARAMETER;
7182 /******************************************************************************
7183 * DeletePrintProcessorA (WINSPOOL.@)
7185 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7187 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7188 debugstr_a(pPrintProcessorName));
7192 /******************************************************************************
7193 * DeletePrintProcessorW (WINSPOOL.@)
7195 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7197 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7198 debugstr_w(pPrintProcessorName));
7202 /******************************************************************************
7203 * DeletePrintProvidorA (WINSPOOL.@)
7205 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7207 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7208 debugstr_a(pPrintProviderName));
7212 /******************************************************************************
7213 * DeletePrintProvidorW (WINSPOOL.@)
7215 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7217 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7218 debugstr_w(pPrintProviderName));
7222 /******************************************************************************
7223 * EnumFormsA (WINSPOOL.@)
7225 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7226 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7228 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7229 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7233 /******************************************************************************
7234 * EnumFormsW (WINSPOOL.@)
7236 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7237 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7239 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7240 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7244 /*****************************************************************************
7245 * EnumMonitorsA [WINSPOOL.@]
7247 * See EnumMonitorsW.
7250 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7251 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7254 LPBYTE bufferW = NULL;
7255 LPWSTR nameW = NULL;
7257 DWORD numentries = 0;
7260 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7261 cbBuf, pcbNeeded, pcReturned);
7263 /* convert servername to unicode */
7265 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7266 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7267 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7269 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7270 needed = cbBuf * sizeof(WCHAR);
7271 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7272 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7274 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7275 if (pcbNeeded) needed = *pcbNeeded;
7276 /* HeapReAlloc return NULL, when bufferW was NULL */
7277 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7278 HeapAlloc(GetProcessHeap(), 0, needed);
7280 /* Try again with the large Buffer */
7281 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7283 numentries = pcReturned ? *pcReturned : 0;
7286 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7287 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7290 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7291 DWORD entrysize = 0;
7294 LPMONITOR_INFO_2W mi2w;
7295 LPMONITOR_INFO_2A mi2a;
7297 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7298 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7300 /* First pass: calculate the size for all Entries */
7301 mi2w = (LPMONITOR_INFO_2W) bufferW;
7302 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7304 while (index < numentries) {
7306 needed += entrysize; /* MONITOR_INFO_?A */
7307 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7309 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7310 NULL, 0, NULL, NULL);
7312 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7313 NULL, 0, NULL, NULL);
7314 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7315 NULL, 0, NULL, NULL);
7317 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7318 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7319 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7322 /* check for errors and quit on failure */
7323 if (cbBuf < needed) {
7324 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7328 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7329 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7330 cbBuf -= len ; /* free Bytes in the user-Buffer */
7331 mi2w = (LPMONITOR_INFO_2W) bufferW;
7332 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7334 /* Second Pass: Fill the User Buffer (if we have one) */
7335 while ((index < numentries) && pMonitors) {
7337 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7339 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7340 ptr, cbBuf , NULL, NULL);
7344 mi2a->pEnvironment = ptr;
7345 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7346 ptr, cbBuf, NULL, NULL);
7350 mi2a->pDLLName = ptr;
7351 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7352 ptr, cbBuf, NULL, NULL);
7356 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7357 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7358 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7362 if (pcbNeeded) *pcbNeeded = needed;
7363 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7365 HeapFree(GetProcessHeap(), 0, nameW);
7366 HeapFree(GetProcessHeap(), 0, bufferW);
7368 TRACE("returning %d with %d (%d byte for %d entries)\n",
7369 (res), GetLastError(), needed, numentries);
7375 /*****************************************************************************
7376 * EnumMonitorsW [WINSPOOL.@]
7378 * Enumerate available Port-Monitors
7381 * pName [I] Servername or NULL (local Computer)
7382 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7383 * pMonitors [O] PTR to Buffer that receives the Result
7384 * cbBuf [I] Size of Buffer at pMonitors
7385 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7386 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7390 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7393 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7394 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7397 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7398 cbBuf, pcbNeeded, pcReturned);
7400 if ((backend == NULL) && !load_backend()) return FALSE;
7402 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7403 SetLastError(RPC_X_NULL_REF_POINTER);
7407 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7410 /******************************************************************************
7411 * SpoolerInit (WINSPOOL.@)
7413 * Initialize the Spooler
7420 * The function fails on windows, when the spooler service is not running
7423 BOOL WINAPI SpoolerInit(void)
7426 if ((backend == NULL) && !load_backend()) return FALSE;
7430 /******************************************************************************
7431 * XcvDataW (WINSPOOL.@)
7433 * Execute commands in the Printmonitor DLL
7436 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7437 * pszDataName [i] Name of the command to execute
7438 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7439 * cbInputData [i] Size in Bytes of Buffer at pInputData
7440 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7441 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7442 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7443 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7450 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7451 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7453 * Minimal List of commands, that a Printmonitor DLL should support:
7455 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7456 *| "AddPort" : Add a Port
7457 *| "DeletePort": Delete a Port
7459 * Many Printmonitors support additional commands. Examples for localspl.dll:
7460 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7461 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7464 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7465 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7466 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7468 opened_printer_t *printer;
7470 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7471 pInputData, cbInputData, pOutputData,
7472 cbOutputData, pcbOutputNeeded, pdwStatus);
7474 if ((backend == NULL) && !load_backend()) return FALSE;
7476 printer = get_opened_printer(hXcv);
7477 if (!printer || (!printer->backend_printer)) {
7478 SetLastError(ERROR_INVALID_HANDLE);
7482 if (!pcbOutputNeeded) {
7483 SetLastError(ERROR_INVALID_PARAMETER);
7487 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7488 SetLastError(RPC_X_NULL_REF_POINTER);
7492 *pcbOutputNeeded = 0;
7494 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7495 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7499 /*****************************************************************************
7500 * EnumPrinterDataA [WINSPOOL.@]
7503 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7504 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7505 DWORD cbData, LPDWORD pcbData )
7507 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7508 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7509 return ERROR_NO_MORE_ITEMS;
7512 /*****************************************************************************
7513 * EnumPrinterDataW [WINSPOOL.@]
7516 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7517 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7518 DWORD cbData, LPDWORD pcbData )
7520 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7521 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7522 return ERROR_NO_MORE_ITEMS;
7525 /*****************************************************************************
7526 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7529 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7530 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7531 LPDWORD pcbNeeded, LPDWORD pcReturned)
7533 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7534 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7535 pcbNeeded, pcReturned);
7539 /*****************************************************************************
7540 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7543 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7544 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7545 LPDWORD pcbNeeded, LPDWORD pcReturned)
7547 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7548 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7549 pcbNeeded, pcReturned);
7553 /*****************************************************************************
7554 * EnumPrintProcessorsA [WINSPOOL.@]
7556 * See EnumPrintProcessorsW.
7559 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7560 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7563 LPBYTE bufferW = NULL;
7564 LPWSTR nameW = NULL;
7567 DWORD numentries = 0;
7570 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7571 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7573 /* convert names to unicode */
7575 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7576 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7577 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7580 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7581 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7582 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7585 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7586 needed = cbBuf * sizeof(WCHAR);
7587 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7588 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7590 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7591 if (pcbNeeded) needed = *pcbNeeded;
7592 /* HeapReAlloc return NULL, when bufferW was NULL */
7593 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7594 HeapAlloc(GetProcessHeap(), 0, needed);
7596 /* Try again with the large Buffer */
7597 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7599 numentries = pcReturned ? *pcReturned : 0;
7603 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7606 PPRINTPROCESSOR_INFO_1W ppiw;
7607 PPRINTPROCESSOR_INFO_1A ppia;
7609 /* First pass: calculate the size for all Entries */
7610 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7611 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7613 while (index < numentries) {
7615 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7616 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7618 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7619 NULL, 0, NULL, NULL);
7621 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7622 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7625 /* check for errors and quit on failure */
7626 if (cbBuf < needed) {
7627 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7632 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7633 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7634 cbBuf -= len ; /* free Bytes in the user-Buffer */
7635 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7636 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7638 /* Second Pass: Fill the User Buffer (if we have one) */
7639 while ((index < numentries) && pPPInfo) {
7641 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7643 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7644 ptr, cbBuf , NULL, NULL);
7648 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7649 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7654 if (pcbNeeded) *pcbNeeded = needed;
7655 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7657 HeapFree(GetProcessHeap(), 0, nameW);
7658 HeapFree(GetProcessHeap(), 0, envW);
7659 HeapFree(GetProcessHeap(), 0, bufferW);
7661 TRACE("returning %d with %d (%d byte for %d entries)\n",
7662 (res), GetLastError(), needed, numentries);
7667 /*****************************************************************************
7668 * EnumPrintProcessorsW [WINSPOOL.@]
7670 * Enumerate available Print Processors
7673 * pName [I] Servername or NULL (local Computer)
7674 * pEnvironment [I] Printing-Environment or NULL (Default)
7675 * Level [I] Structure-Level (Only 1 is allowed)
7676 * pPPInfo [O] PTR to Buffer that receives the Result
7677 * cbBuf [I] Size of Buffer at pPPInfo
7678 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7679 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7683 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7686 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7687 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7690 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7691 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7693 if ((backend == NULL) && !load_backend()) return FALSE;
7695 if (!pcbNeeded || !pcReturned) {
7696 SetLastError(RPC_X_NULL_REF_POINTER);
7700 if (!pPPInfo && (cbBuf > 0)) {
7701 SetLastError(ERROR_INVALID_USER_BUFFER);
7705 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7706 cbBuf, pcbNeeded, pcReturned);
7709 /*****************************************************************************
7710 * ExtDeviceMode [WINSPOOL.@]
7713 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7714 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7717 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7718 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7719 debugstr_a(pProfile), fMode);
7723 /*****************************************************************************
7724 * FindClosePrinterChangeNotification [WINSPOOL.@]
7727 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7729 FIXME("Stub: %p\n", hChange);
7733 /*****************************************************************************
7734 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7737 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7738 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7740 FIXME("Stub: %p %x %x %p\n",
7741 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7742 return INVALID_HANDLE_VALUE;
7745 /*****************************************************************************
7746 * FindNextPrinterChangeNotification [WINSPOOL.@]
7749 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7750 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7752 FIXME("Stub: %p %p %p %p\n",
7753 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7757 /*****************************************************************************
7758 * FreePrinterNotifyInfo [WINSPOOL.@]
7761 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7763 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7767 /*****************************************************************************
7770 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7771 * ansi depending on the unicode parameter.
7773 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7783 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7786 memcpy(ptr, str, *size);
7793 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7796 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7803 /*****************************************************************************
7806 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7807 LPDWORD pcbNeeded, BOOL unicode)
7809 DWORD size, left = cbBuf;
7810 BOOL space = (cbBuf > 0);
7817 ji1->JobId = job->job_id;
7820 string_to_buf(job->document_title, ptr, left, &size, unicode);
7821 if(space && size <= left)
7823 ji1->pDocument = (LPWSTR)ptr;
7831 if (job->printer_name)
7833 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7834 if(space && size <= left)
7836 ji1->pPrinterName = (LPWSTR)ptr;
7848 /*****************************************************************************
7851 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7852 LPDWORD pcbNeeded, BOOL unicode)
7854 DWORD size, left = cbBuf;
7856 BOOL space = (cbBuf > 0);
7858 LPDEVMODEA dmA = NULL;
7865 ji2->JobId = job->job_id;
7868 string_to_buf(job->document_title, ptr, left, &size, unicode);
7869 if(space && size <= left)
7871 ji2->pDocument = (LPWSTR)ptr;
7879 if (job->printer_name)
7881 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7882 if(space && size <= left)
7884 ji2->pPrinterName = (LPWSTR)ptr;
7897 dmA = DEVMODEdupWtoA(job->devmode);
7898 devmode = (LPDEVMODEW) dmA;
7899 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7903 devmode = job->devmode;
7904 size = devmode->dmSize + devmode->dmDriverExtra;
7908 FIXME("Can't convert DEVMODE W to A\n");
7911 /* align DEVMODE to a DWORD boundary */
7912 shift = (4 - (*pcbNeeded & 3)) & 3;
7918 memcpy(ptr, devmode, size-shift);
7919 ji2->pDevMode = (LPDEVMODEW)ptr;
7920 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7933 /*****************************************************************************
7936 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7937 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7940 DWORD needed = 0, size;
7944 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7946 EnterCriticalSection(&printer_handles_cs);
7947 job = get_job(hPrinter, JobId);
7954 size = sizeof(JOB_INFO_1W);
7959 memset(pJob, 0, size);
7963 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7968 size = sizeof(JOB_INFO_2W);
7973 memset(pJob, 0, size);
7977 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7982 size = sizeof(JOB_INFO_3);
7986 memset(pJob, 0, size);
7995 SetLastError(ERROR_INVALID_LEVEL);
7999 *pcbNeeded = needed;
8001 LeaveCriticalSection(&printer_handles_cs);
8005 /*****************************************************************************
8006 * GetJobA [WINSPOOL.@]
8009 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8010 DWORD cbBuf, LPDWORD pcbNeeded)
8012 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8015 /*****************************************************************************
8016 * GetJobW [WINSPOOL.@]
8019 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8020 DWORD cbBuf, LPDWORD pcbNeeded)
8022 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8025 /*****************************************************************************
8028 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8031 char *unixname, *cmdA;
8033 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8039 if(!(unixname = wine_get_unix_file_name(filename)))
8042 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8043 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8044 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8046 TRACE("printing with: %s\n", cmdA);
8048 if((file_fd = open(unixname, O_RDONLY)) == -1)
8053 ERR("pipe() failed!\n");
8057 if ((pid = fork()) == 0)
8063 /* reset signals that we previously set to SIG_IGN */
8064 signal(SIGPIPE, SIG_DFL);
8066 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8071 ERR("fork() failed!\n");
8077 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8078 write(fds[1], buf, no_read);
8085 wret = waitpid(pid, &status, 0);
8086 } while (wret < 0 && errno == EINTR);
8089 ERR("waitpid() failed!\n");
8092 if (!WIFEXITED(status) || WEXITSTATUS(status))
8094 ERR("child process failed! %d\n", status);
8101 if(file_fd != -1) close(file_fd);
8102 if(fds[0] != -1) close(fds[0]);
8103 if(fds[1] != -1) close(fds[1]);
8105 HeapFree(GetProcessHeap(), 0, cmdA);
8106 HeapFree(GetProcessHeap(), 0, unixname);
8113 /*****************************************************************************
8116 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8119 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8122 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8123 sprintfW(cmd, fmtW, printer_name);
8125 r = schedule_pipe(cmd, filename);
8127 HeapFree(GetProcessHeap(), 0, cmd);
8131 #ifdef SONAME_LIBCUPS
8132 /*****************************************************************************
8133 * get_cups_jobs_ticket_options
8135 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8136 * The CUPS scheduler only looks for these in Print-File requests, and since
8137 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8140 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8142 FILE *fp = fopen( file, "r" );
8143 char buf[257]; /* DSC max of 256 + '\0' */
8144 const char *ps_adobe = "%!PS-Adobe-";
8145 const char *cups_job = "%cupsJobTicket:";
8147 if (!fp) return num_options;
8148 if (!fgets( buf, sizeof(buf), fp )) goto end;
8149 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8150 while (fgets( buf, sizeof(buf), fp ))
8152 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8153 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8162 /*****************************************************************************
8165 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8167 #ifdef SONAME_LIBCUPS
8170 char *unixname, *queue, *unix_doc_title;
8173 int num_options = 0, i;
8174 cups_option_t *options = NULL;
8176 if(!(unixname = wine_get_unix_file_name(filename)))
8179 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8180 queue = HeapAlloc(GetProcessHeap(), 0, len);
8181 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8183 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8184 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8185 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8187 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8189 TRACE( "printing via cups with options:\n" );
8190 for (i = 0; i < num_options; i++)
8191 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8193 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8195 pcupsFreeOptions( num_options, options );
8197 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8198 HeapFree(GetProcessHeap(), 0, queue);
8199 HeapFree(GetProcessHeap(), 0, unixname);
8205 return schedule_lpr(printer_name, filename);
8209 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8216 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8220 if(HIWORD(wparam) == BN_CLICKED)
8222 if(LOWORD(wparam) == IDOK)
8225 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8228 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8229 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8231 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8233 WCHAR caption[200], message[200];
8236 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8237 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8238 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8239 if(mb_ret == IDCANCEL)
8241 HeapFree(GetProcessHeap(), 0, filename);
8245 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8246 if(hf == INVALID_HANDLE_VALUE)
8248 WCHAR caption[200], message[200];
8250 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8251 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8252 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8253 HeapFree(GetProcessHeap(), 0, filename);
8257 DeleteFileW(filename);
8258 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8260 EndDialog(hwnd, IDOK);
8263 if(LOWORD(wparam) == IDCANCEL)
8265 EndDialog(hwnd, IDCANCEL);
8274 /*****************************************************************************
8277 static BOOL get_filename(LPWSTR *filename)
8279 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8280 file_dlg_proc, (LPARAM)filename) == IDOK;
8283 /*****************************************************************************
8286 static BOOL schedule_file(LPCWSTR filename)
8288 LPWSTR output = NULL;
8290 if(get_filename(&output))
8293 TRACE("copy to %s\n", debugstr_w(output));
8294 r = CopyFileW(filename, output, FALSE);
8295 HeapFree(GetProcessHeap(), 0, output);
8301 /*****************************************************************************
8304 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8306 int in_fd, out_fd, no_read;
8309 char *unixname, *outputA;
8312 if(!(unixname = wine_get_unix_file_name(filename)))
8315 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8316 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8317 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8319 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8320 in_fd = open(unixname, O_RDONLY);
8321 if(out_fd == -1 || in_fd == -1)
8324 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8325 write(out_fd, buf, no_read);
8329 if(in_fd != -1) close(in_fd);
8330 if(out_fd != -1) close(out_fd);
8331 HeapFree(GetProcessHeap(), 0, outputA);
8332 HeapFree(GetProcessHeap(), 0, unixname);
8336 /*****************************************************************************
8337 * ScheduleJob [WINSPOOL.@]
8340 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8342 opened_printer_t *printer;
8344 struct list *cursor, *cursor2;
8346 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8347 EnterCriticalSection(&printer_handles_cs);
8348 printer = get_opened_printer(hPrinter);
8352 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8354 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8357 if(job->job_id != dwJobID) continue;
8359 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8360 if(hf != INVALID_HANDLE_VALUE)
8362 PRINTER_INFO_5W *pi5 = NULL;
8363 LPWSTR portname = job->portname;
8367 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8368 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8372 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8373 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8374 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8375 portname = pi5->pPortName;
8377 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8378 debugstr_w(portname));
8382 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8383 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8385 DWORD type, count = sizeof(output);
8386 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8389 if(output[0] == '|')
8391 ret = schedule_pipe(output + 1, job->filename);
8395 ret = schedule_unixfile(output, job->filename);
8397 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8399 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8401 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8403 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8405 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8407 ret = schedule_file(job->filename);
8411 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8413 HeapFree(GetProcessHeap(), 0, pi5);
8415 DeleteFileW(job->filename);
8417 list_remove(cursor);
8418 HeapFree(GetProcessHeap(), 0, job->document_title);
8419 HeapFree(GetProcessHeap(), 0, job->printer_name);
8420 HeapFree(GetProcessHeap(), 0, job->portname);
8421 HeapFree(GetProcessHeap(), 0, job->filename);
8422 HeapFree(GetProcessHeap(), 0, job->devmode);
8423 HeapFree(GetProcessHeap(), 0, job);
8427 LeaveCriticalSection(&printer_handles_cs);
8431 /*****************************************************************************
8432 * StartDocDlgA [WINSPOOL.@]
8434 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8436 UNICODE_STRING usBuffer;
8439 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8442 docW.cbSize = sizeof(docW);
8443 if (doc->lpszDocName)
8445 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8446 if (!(docW.lpszDocName = docnameW)) return NULL;
8448 if (doc->lpszOutput)
8450 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8451 if (!(docW.lpszOutput = outputW)) return NULL;
8453 if (doc->lpszDatatype)
8455 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8456 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8458 docW.fwType = doc->fwType;
8460 retW = StartDocDlgW(hPrinter, &docW);
8464 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8465 ret = HeapAlloc(GetProcessHeap(), 0, len);
8466 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8467 HeapFree(GetProcessHeap(), 0, retW);
8470 HeapFree(GetProcessHeap(), 0, datatypeW);
8471 HeapFree(GetProcessHeap(), 0, outputW);
8472 HeapFree(GetProcessHeap(), 0, docnameW);
8477 /*****************************************************************************
8478 * StartDocDlgW [WINSPOOL.@]
8480 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8481 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8482 * port is "FILE:". Also returns the full path if passed a relative path.
8484 * The caller should free the returned string from the process heap.
8486 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8491 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8493 PRINTER_INFO_5W *pi5;
8494 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8495 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8497 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8498 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8499 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8501 HeapFree(GetProcessHeap(), 0, pi5);
8504 HeapFree(GetProcessHeap(), 0, pi5);
8507 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8511 if (get_filename(&name))
8513 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8515 HeapFree(GetProcessHeap(), 0, name);
8518 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8519 GetFullPathNameW(name, len, ret, NULL);
8520 HeapFree(GetProcessHeap(), 0, name);
8525 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8528 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8529 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8531 attr = GetFileAttributesW(ret);
8532 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8534 HeapFree(GetProcessHeap(), 0, ret);