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 BOOL CUPS_LoadPrinters(void)
880 BOOL hadprinter = FALSE, haddefault = FALSE;
883 WCHAR *port, *ppd_dir = NULL, *ppd;
884 HKEY hkeyPrinter, hkeyPrinters;
886 WCHAR nameW[MAX_PATH];
887 HANDLE added_printer;
888 cups_ptype_t printer_type;
890 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
892 TRACE("%s\n", loaderror);
895 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
897 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE
900 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
904 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
906 ERR("Can't create Printers key\n");
910 nrofdests = pcupsGetDests(&dests);
911 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
912 for (i=0;i<nrofdests;i++) {
913 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
914 printer_type = get_cups_printer_type( dests + i );
916 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
918 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
920 TRACE( "skipping scanner-only device\n" );
924 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
925 lstrcpyW(port, CUPS_Port);
926 lstrcatW(port, nameW);
928 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
929 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
930 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
932 TRACE("Printer already exists\n");
933 /* overwrite old LPR:* port */
934 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
935 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
936 /* flag that the PPD file should be checked for an update */
937 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
938 RegCloseKey(hkeyPrinter);
940 BOOL added_driver = FALSE;
942 if (!ppd_dir) ppd_dir = get_ppd_dir();
943 ppd = get_ppd_filename( ppd_dir, nameW );
944 if (get_cups_ppd( dests[i].name, ppd ))
946 added_driver = add_printer_driver( nameW, ppd );
949 HeapFree( GetProcessHeap(), 0, ppd );
952 HeapFree( GetProcessHeap(), 0, port );
956 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
957 pi2.pPrinterName = nameW;
958 pi2.pDatatype = rawW;
959 pi2.pPrintProcessor = WinPrintW;
960 pi2.pDriverName = nameW;
961 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
962 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
963 pi2.pPortName = port;
964 pi2.pParameters = emptyStringW;
965 pi2.pShareName = emptyStringW;
966 pi2.pSepFile = emptyStringW;
968 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
969 if (added_printer) ClosePrinter( added_printer );
970 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
971 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
973 HeapFree( GetProcessHeap(), 0, pi2.pComment );
974 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
976 HeapFree( GetProcessHeap(), 0, port );
979 if (dests[i].is_default) {
980 SetDefaultPrinterW(nameW);
987 RemoveDirectoryW( ppd_dir );
988 HeapFree( GetProcessHeap(), 0, ppd_dir );
991 if (hadprinter && !haddefault) {
992 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
993 SetDefaultPrinterW(nameW);
995 pcupsFreeDests(nrofdests, dests);
996 RegCloseKey(hkeyPrinters);
1002 static char *get_queue_name( HANDLE printer, BOOL *cups )
1004 WCHAR *port, *name = NULL;
1005 DWORD err, needed, type;
1011 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1012 if (err) return NULL;
1013 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1015 port = HeapAlloc( GetProcessHeap(), 0, needed );
1016 if (!port) goto end;
1017 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1019 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1021 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1024 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1025 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1028 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1029 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1030 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1032 HeapFree( GetProcessHeap(), 0, port );
1039 static void set_ppd_overrides( HANDLE printer )
1043 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1045 PMPrintSession session = NULL;
1046 PMPageFormat format = NULL;
1048 CFStringRef paper_name;
1051 status = PMCreateSession( &session );
1052 if (status) goto end;
1054 status = PMCreatePageFormat( &format );
1055 if (status) goto end;
1057 status = PMSessionDefaultPageFormat( session, format );
1058 if (status) goto end;
1060 status = PMGetPageFormatPaper( format, &paper );
1061 if (status) goto end;
1063 status = PMPaperGetPPDPaperName( paper, &paper_name );
1064 if (status) goto end;
1067 range.length = CFStringGetLength( paper_name );
1068 size = (range.length + 1) * sizeof(WCHAR);
1070 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1071 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1072 wstr[range.length] = 0;
1075 if (format) PMRelease( format );
1076 if (session) PMRelease( session );
1079 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1080 HeapFree( GetProcessHeap(), 0, wstr );
1083 static BOOL update_driver( HANDLE printer )
1086 const WCHAR *name = get_opened_printer_name( printer );
1087 WCHAR *ppd_dir, *ppd;
1090 if (!name) return FALSE;
1091 queue_name = get_queue_name( printer, &is_cups );
1092 if (!queue_name) return FALSE;
1094 ppd_dir = get_ppd_dir();
1095 ppd = get_ppd_filename( ppd_dir, name );
1097 #ifdef SONAME_LIBCUPS
1099 ret = get_cups_ppd( queue_name, ppd );
1102 ret = get_fallback_ppd( queue_name, ppd );
1106 TRACE( "updating driver %s\n", debugstr_w( name ) );
1107 ret = add_printer_driver( name, ppd );
1110 HeapFree( GetProcessHeap(), 0, ppd_dir );
1111 HeapFree( GetProcessHeap(), 0, ppd );
1112 HeapFree( GetProcessHeap(), 0, queue_name );
1114 set_ppd_overrides( printer );
1116 /* call into the driver to update the devmode */
1117 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1122 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1124 PRINTER_INFO_2A pinfo2a;
1127 char *e,*s,*name,*prettyname,*devname;
1128 BOOL ret = FALSE, set_default = FALSE;
1129 char *port = NULL, *env_default;
1130 HKEY hkeyPrinter, hkeyPrinters = NULL;
1131 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1132 HANDLE added_printer;
1134 while (isspace(*pent)) pent++;
1135 r = strchr(pent,':');
1137 name_len = r - pent;
1139 name_len = strlen(pent);
1140 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1141 memcpy(name, pent, name_len);
1142 name[name_len] = '\0';
1148 TRACE("name=%s entry=%s\n",name, pent);
1150 if(ispunct(*name)) { /* a tc entry, not a real printer */
1151 TRACE("skipping tc entry\n");
1155 if(strstr(pent,":server")) { /* server only version so skip */
1156 TRACE("skipping server entry\n");
1160 /* Determine whether this is a postscript printer. */
1163 env_default = getenv("PRINTER");
1165 /* Get longest name, usually the one at the right for later display. */
1166 while((s=strchr(prettyname,'|'))) {
1169 while(isspace(*--e)) *e = '\0';
1170 TRACE("\t%s\n", debugstr_a(prettyname));
1171 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1172 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1175 e = prettyname + strlen(prettyname);
1176 while(isspace(*--e)) *e = '\0';
1177 TRACE("\t%s\n", debugstr_a(prettyname));
1178 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1180 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1181 * if it is too long, we use it as comment below. */
1182 devname = prettyname;
1183 if (strlen(devname)>=CCHDEVICENAME-1)
1185 if (strlen(devname)>=CCHDEVICENAME-1) {
1190 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1191 sprintf(port,"LPR:%s",name);
1193 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1195 ERR("Can't create Printers key\n");
1200 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1202 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1203 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1204 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1206 TRACE("Printer already exists\n");
1207 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1208 /* flag that the PPD file should be checked for an update */
1209 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1210 RegCloseKey(hkeyPrinter);
1212 static CHAR data_type[] = "RAW",
1213 print_proc[] = "WinPrint",
1214 comment[] = "WINEPS Printer using LPR",
1215 params[] = "<parameters?>",
1216 share_name[] = "<share name?>",
1217 sep_file[] = "<sep file?>";
1218 BOOL added_driver = FALSE;
1220 if (!ppd_dir) ppd_dir = get_ppd_dir();
1221 ppd = get_ppd_filename( ppd_dir, devnameW );
1222 if (get_fallback_ppd( devname, ppd ))
1224 added_driver = add_printer_driver( devnameW, ppd );
1227 HeapFree( GetProcessHeap(), 0, ppd );
1228 if (!added_driver) goto end;
1230 memset(&pinfo2a,0,sizeof(pinfo2a));
1231 pinfo2a.pPrinterName = devname;
1232 pinfo2a.pDatatype = data_type;
1233 pinfo2a.pPrintProcessor = print_proc;
1234 pinfo2a.pDriverName = devname;
1235 pinfo2a.pComment = comment;
1236 pinfo2a.pLocation = prettyname;
1237 pinfo2a.pPortName = port;
1238 pinfo2a.pParameters = params;
1239 pinfo2a.pShareName = share_name;
1240 pinfo2a.pSepFile = sep_file;
1242 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1243 if (added_printer) ClosePrinter( added_printer );
1244 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1245 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1248 if (isfirst || set_default)
1249 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1252 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1255 RemoveDirectoryW( ppd_dir );
1256 HeapFree( GetProcessHeap(), 0, ppd_dir );
1258 HeapFree(GetProcessHeap(), 0, port);
1259 HeapFree(GetProcessHeap(), 0, name);
1264 PRINTCAP_LoadPrinters(void) {
1265 BOOL hadprinter = FALSE;
1269 BOOL had_bash = FALSE;
1271 f = fopen("/etc/printcap","r");
1275 while(fgets(buf,sizeof(buf),f)) {
1278 end=strchr(buf,'\n');
1282 while(isspace(*start)) start++;
1283 if(*start == '#' || *start == '\0')
1286 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1287 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1288 HeapFree(GetProcessHeap(),0,pent);
1292 if (end && *--end == '\\') {
1299 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1302 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1308 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1309 HeapFree(GetProcessHeap(),0,pent);
1315 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1318 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1319 (lstrlenW(value) + 1) * sizeof(WCHAR));
1321 return ERROR_FILE_NOT_FOUND;
1324 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1326 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1327 DWORD ret = ERROR_FILE_NOT_FOUND;
1329 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1330 and we support these drivers. NT writes DEVMODEW so somehow
1331 we'll need to distinguish between these when we support NT
1336 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1337 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1338 HeapFree( GetProcessHeap(), 0, dmA );
1344 /******************************************************************
1345 * get_servername_from_name (internal)
1347 * for an external server, a copy of the serverpart from the full name is returned
1350 static LPWSTR get_servername_from_name(LPCWSTR name)
1354 WCHAR buffer[MAX_PATH];
1357 if (name == NULL) return NULL;
1358 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1360 server = strdupW(&name[2]); /* skip over both backslash */
1361 if (server == NULL) return NULL;
1363 /* strip '\' and the printername */
1364 ptr = strchrW(server, '\\');
1365 if (ptr) ptr[0] = '\0';
1367 TRACE("found %s\n", debugstr_w(server));
1369 len = sizeof(buffer)/sizeof(buffer[0]);
1370 if (GetComputerNameW(buffer, &len)) {
1371 if (lstrcmpW(buffer, server) == 0) {
1372 /* The requested Servername is our computername */
1373 HeapFree(GetProcessHeap(), 0, server);
1380 /******************************************************************
1381 * get_basename_from_name (internal)
1383 * skip over the serverpart from the full name
1386 static LPCWSTR get_basename_from_name(LPCWSTR name)
1388 if (name == NULL) return NULL;
1389 if ((name[0] == '\\') && (name[1] == '\\')) {
1390 /* skip over the servername and search for the following '\' */
1391 name = strchrW(&name[2], '\\');
1392 if ((name) && (name[1])) {
1393 /* found a separator ('\') followed by a name:
1394 skip over the separator and return the rest */
1399 /* no basename present (we found only a servername) */
1406 static void free_printer_entry( opened_printer_t *printer )
1408 /* the queue is shared, so don't free that here */
1409 HeapFree( GetProcessHeap(), 0, printer->printername );
1410 HeapFree( GetProcessHeap(), 0, printer->name );
1411 HeapFree( GetProcessHeap(), 0, printer->devmode );
1412 HeapFree( GetProcessHeap(), 0, printer );
1415 /******************************************************************
1416 * get_opened_printer_entry
1417 * Get the first place empty in the opened printer table
1420 * - pDefault is ignored
1422 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1424 UINT_PTR handle = nb_printer_handles, i;
1425 jobqueue_t *queue = NULL;
1426 opened_printer_t *printer = NULL;
1428 LPCWSTR printername;
1430 if ((backend == NULL) && !load_backend()) return NULL;
1432 servername = get_servername_from_name(name);
1434 FIXME("server %s not supported\n", debugstr_w(servername));
1435 HeapFree(GetProcessHeap(), 0, servername);
1436 SetLastError(ERROR_INVALID_PRINTER_NAME);
1440 printername = get_basename_from_name(name);
1441 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1443 /* an empty printername is invalid */
1444 if (printername && (!printername[0])) {
1445 SetLastError(ERROR_INVALID_PARAMETER);
1449 EnterCriticalSection(&printer_handles_cs);
1451 for (i = 0; i < nb_printer_handles; i++)
1453 if (!printer_handles[i])
1455 if(handle == nb_printer_handles)
1460 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1461 queue = printer_handles[i]->queue;
1465 if (handle >= nb_printer_handles)
1467 opened_printer_t **new_array;
1468 if (printer_handles)
1469 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1470 (nb_printer_handles + 16) * sizeof(*new_array) );
1472 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1473 (nb_printer_handles + 16) * sizeof(*new_array) );
1480 printer_handles = new_array;
1481 nb_printer_handles += 16;
1484 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1490 /* get a printer handle from the backend */
1491 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1496 /* clone the base name. This is NULL for the printserver */
1497 printer->printername = strdupW(printername);
1499 /* clone the full name */
1500 printer->name = strdupW(name);
1501 if (name && (!printer->name)) {
1506 if (pDefault && pDefault->pDevMode)
1507 printer->devmode = dup_devmode( pDefault->pDevMode );
1510 printer->queue = queue;
1513 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1514 if (!printer->queue) {
1518 list_init(&printer->queue->jobs);
1519 printer->queue->ref = 0;
1521 InterlockedIncrement(&printer->queue->ref);
1523 printer_handles[handle] = printer;
1526 LeaveCriticalSection(&printer_handles_cs);
1527 if (!handle && printer) {
1528 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1529 free_printer_entry( printer );
1532 return (HANDLE)handle;
1535 static void old_printer_check( BOOL delete_phase )
1537 PRINTER_INFO_5W* pi;
1538 DWORD needed, type, num, delete, i, size;
1539 const DWORD one = 1;
1543 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1544 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1546 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1547 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1548 for (i = 0; i < num; i++)
1550 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1551 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1554 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1558 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1564 size = sizeof( delete );
1565 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1569 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1570 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1572 DeletePrinter( hprn );
1573 ClosePrinter( hprn );
1575 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1579 HeapFree(GetProcessHeap(), 0, pi);
1582 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1583 'M','U','T','E','X','_','_','\0'};
1584 static HANDLE init_mutex;
1586 void WINSPOOL_LoadSystemPrinters(void)
1588 HKEY hkey, hkeyPrinters;
1589 DWORD needed, num, i;
1590 WCHAR PrinterName[256];
1593 /* FIXME: The init code should be moved to spoolsv.exe */
1594 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1597 ERR( "Failed to create mutex\n" );
1600 if (GetLastError() == ERROR_ALREADY_EXISTS)
1602 WaitForSingleObject( init_mutex, INFINITE );
1603 ReleaseMutex( init_mutex );
1604 TRACE( "Init already done\n" );
1608 /* This ensures that all printer entries have a valid Name value. If causes
1609 problems later if they don't. If one is found to be missed we create one
1610 and set it equal to the name of the key */
1611 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1612 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1613 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1614 for(i = 0; i < num; i++) {
1615 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1616 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1617 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1618 set_reg_szW(hkey, NameW, PrinterName);
1625 RegCloseKey(hkeyPrinters);
1628 old_printer_check( FALSE );
1630 #ifdef SONAME_LIBCUPS
1631 done = CUPS_LoadPrinters();
1634 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1635 PRINTCAP_LoadPrinters();
1637 old_printer_check( TRUE );
1639 ReleaseMutex( init_mutex );
1643 /******************************************************************
1646 * Get the pointer to the specified job.
1647 * Should hold the printer_handles_cs before calling.
1649 static job_t *get_job(HANDLE hprn, DWORD JobId)
1651 opened_printer_t *printer = get_opened_printer(hprn);
1654 if(!printer) return NULL;
1655 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1657 if(job->job_id == JobId)
1663 /***********************************************************
1666 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1669 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1672 Formname = (dmA->dmSize > off_formname);
1673 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1674 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1675 dmW->dmDeviceName, CCHDEVICENAME);
1677 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1678 dmA->dmSize - CCHDEVICENAME);
1680 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1681 off_formname - CCHDEVICENAME);
1682 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1683 dmW->dmFormName, CCHFORMNAME);
1684 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1685 (off_formname + CCHFORMNAME));
1688 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1689 dmA->dmDriverExtra);
1693 /******************************************************************
1694 * convert_printerinfo_W_to_A [internal]
1697 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1698 DWORD level, DWORD outlen, DWORD numentries)
1704 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1706 len = pi_sizeof[level] * numentries;
1707 ptr = (LPSTR) out + len;
1710 /* copy the numbers of all PRINTER_INFO_* first */
1711 memcpy(out, pPrintersW, len);
1713 while (id < numentries) {
1717 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1718 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1720 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1721 if (piW->pDescription) {
1722 piA->pDescription = ptr;
1723 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1724 ptr, outlen, NULL, NULL);
1730 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1731 ptr, outlen, NULL, NULL);
1735 if (piW->pComment) {
1736 piA->pComment = ptr;
1737 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1738 ptr, outlen, NULL, NULL);
1747 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1748 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1751 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1752 if (piW->pServerName) {
1753 piA->pServerName = ptr;
1754 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1755 ptr, outlen, NULL, NULL);
1759 if (piW->pPrinterName) {
1760 piA->pPrinterName = ptr;
1761 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1762 ptr, outlen, NULL, NULL);
1766 if (piW->pShareName) {
1767 piA->pShareName = ptr;
1768 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1769 ptr, outlen, NULL, NULL);
1773 if (piW->pPortName) {
1774 piA->pPortName = ptr;
1775 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1776 ptr, outlen, NULL, NULL);
1780 if (piW->pDriverName) {
1781 piA->pDriverName = ptr;
1782 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1783 ptr, outlen, NULL, NULL);
1787 if (piW->pComment) {
1788 piA->pComment = ptr;
1789 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1790 ptr, outlen, NULL, NULL);
1794 if (piW->pLocation) {
1795 piA->pLocation = ptr;
1796 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1797 ptr, outlen, NULL, NULL);
1802 dmA = DEVMODEdupWtoA(piW->pDevMode);
1804 /* align DEVMODEA to a DWORD boundary */
1805 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1809 piA->pDevMode = (LPDEVMODEA) ptr;
1810 len = dmA->dmSize + dmA->dmDriverExtra;
1811 memcpy(ptr, dmA, len);
1812 HeapFree(GetProcessHeap(), 0, dmA);
1818 if (piW->pSepFile) {
1819 piA->pSepFile = ptr;
1820 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1821 ptr, outlen, NULL, NULL);
1825 if (piW->pPrintProcessor) {
1826 piA->pPrintProcessor = ptr;
1827 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1828 ptr, outlen, NULL, NULL);
1832 if (piW->pDatatype) {
1833 piA->pDatatype = ptr;
1834 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1835 ptr, outlen, NULL, NULL);
1839 if (piW->pParameters) {
1840 piA->pParameters = ptr;
1841 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1842 ptr, outlen, NULL, NULL);
1846 if (piW->pSecurityDescriptor) {
1847 piA->pSecurityDescriptor = NULL;
1848 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1855 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1856 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1858 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1860 if (piW->pPrinterName) {
1861 piA->pPrinterName = ptr;
1862 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1863 ptr, outlen, NULL, NULL);
1867 if (piW->pServerName) {
1868 piA->pServerName = ptr;
1869 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1870 ptr, outlen, NULL, NULL);
1879 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1880 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1882 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1884 if (piW->pPrinterName) {
1885 piA->pPrinterName = ptr;
1886 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1887 ptr, outlen, NULL, NULL);
1891 if (piW->pPortName) {
1892 piA->pPortName = ptr;
1893 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1894 ptr, outlen, NULL, NULL);
1901 case 6: /* 6A and 6W are the same structure */
1906 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1907 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1909 TRACE("(%u) #%u\n", level, id);
1910 if (piW->pszObjectGUID) {
1911 piA->pszObjectGUID = ptr;
1912 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1913 ptr, outlen, NULL, NULL);
1923 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1924 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1927 TRACE("(%u) #%u\n", level, id);
1928 dmA = DEVMODEdupWtoA(piW->pDevMode);
1930 /* align DEVMODEA to a DWORD boundary */
1931 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1935 piA->pDevMode = (LPDEVMODEA) ptr;
1936 len = dmA->dmSize + dmA->dmDriverExtra;
1937 memcpy(ptr, dmA, len);
1938 HeapFree(GetProcessHeap(), 0, dmA);
1948 FIXME("for level %u\n", level);
1950 pPrintersW += pi_sizeof[level];
1951 out += pi_sizeof[level];
1956 /******************************************************************
1957 * convert_driverinfo_W_to_A [internal]
1960 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1961 DWORD level, DWORD outlen, DWORD numentries)
1967 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1969 len = di_sizeof[level] * numentries;
1970 ptr = (LPSTR) out + len;
1973 /* copy the numbers of all PRINTER_INFO_* first */
1974 memcpy(out, pDriversW, len);
1976 #define COPY_STRING(fld) \
1979 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1980 ptr += len; outlen -= len;\
1982 #define COPY_MULTIZ_STRING(fld) \
1983 { LPWSTR p = diW->fld; if (p){ \
1986 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1987 ptr += len; outlen -= len; p += len;\
1989 while(len > 1 && outlen > 0); \
1992 while (id < numentries)
1998 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1999 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2001 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2008 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2009 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2011 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2014 COPY_STRING(pEnvironment);
2015 COPY_STRING(pDriverPath);
2016 COPY_STRING(pDataFile);
2017 COPY_STRING(pConfigFile);
2022 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2023 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2025 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2028 COPY_STRING(pEnvironment);
2029 COPY_STRING(pDriverPath);
2030 COPY_STRING(pDataFile);
2031 COPY_STRING(pConfigFile);
2032 COPY_STRING(pHelpFile);
2033 COPY_MULTIZ_STRING(pDependentFiles);
2034 COPY_STRING(pMonitorName);
2035 COPY_STRING(pDefaultDataType);
2040 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2041 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2043 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2046 COPY_STRING(pEnvironment);
2047 COPY_STRING(pDriverPath);
2048 COPY_STRING(pDataFile);
2049 COPY_STRING(pConfigFile);
2050 COPY_STRING(pHelpFile);
2051 COPY_MULTIZ_STRING(pDependentFiles);
2052 COPY_STRING(pMonitorName);
2053 COPY_STRING(pDefaultDataType);
2054 COPY_MULTIZ_STRING(pszzPreviousNames);
2059 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2060 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2062 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2065 COPY_STRING(pEnvironment);
2066 COPY_STRING(pDriverPath);
2067 COPY_STRING(pDataFile);
2068 COPY_STRING(pConfigFile);
2073 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2074 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2076 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2079 COPY_STRING(pEnvironment);
2080 COPY_STRING(pDriverPath);
2081 COPY_STRING(pDataFile);
2082 COPY_STRING(pConfigFile);
2083 COPY_STRING(pHelpFile);
2084 COPY_MULTIZ_STRING(pDependentFiles);
2085 COPY_STRING(pMonitorName);
2086 COPY_STRING(pDefaultDataType);
2087 COPY_MULTIZ_STRING(pszzPreviousNames);
2088 COPY_STRING(pszMfgName);
2089 COPY_STRING(pszOEMUrl);
2090 COPY_STRING(pszHardwareID);
2091 COPY_STRING(pszProvider);
2096 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2097 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2099 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2102 COPY_STRING(pEnvironment);
2103 COPY_STRING(pDriverPath);
2104 COPY_STRING(pDataFile);
2105 COPY_STRING(pConfigFile);
2106 COPY_STRING(pHelpFile);
2107 COPY_MULTIZ_STRING(pDependentFiles);
2108 COPY_STRING(pMonitorName);
2109 COPY_STRING(pDefaultDataType);
2110 COPY_MULTIZ_STRING(pszzPreviousNames);
2111 COPY_STRING(pszMfgName);
2112 COPY_STRING(pszOEMUrl);
2113 COPY_STRING(pszHardwareID);
2114 COPY_STRING(pszProvider);
2115 COPY_STRING(pszPrintProcessor);
2116 COPY_STRING(pszVendorSetup);
2117 COPY_MULTIZ_STRING(pszzColorProfiles);
2118 COPY_STRING(pszInfPath);
2119 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2125 FIXME("for level %u\n", level);
2128 pDriversW += di_sizeof[level];
2129 out += di_sizeof[level];
2134 #undef COPY_MULTIZ_STRING
2138 /***********************************************************
2141 static void *printer_info_AtoW( const void *data, DWORD level )
2144 UNICODE_STRING usBuffer;
2146 if (!data) return NULL;
2148 if (level < 1 || level > 9) return NULL;
2150 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2151 if (!ret) return NULL;
2153 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2159 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2160 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2162 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2163 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2164 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2165 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2166 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2167 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2168 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2169 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2170 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2171 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2172 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2173 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2180 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2181 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2183 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2188 FIXME( "Unhandled level %d\n", level );
2189 HeapFree( GetProcessHeap(), 0, ret );
2196 /***********************************************************
2199 static void free_printer_info( void *data, DWORD level )
2207 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2209 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2210 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2211 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2212 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2213 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2214 HeapFree( GetProcessHeap(), 0, piW->pComment );
2215 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2216 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2217 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2218 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2219 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2220 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2227 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2229 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2234 FIXME( "Unhandled level %d\n", level );
2237 HeapFree( GetProcessHeap(), 0, data );
2241 /******************************************************************
2242 * DeviceCapabilities [WINSPOOL.@]
2243 * DeviceCapabilitiesA [WINSPOOL.@]
2246 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2247 LPSTR pOutput, LPDEVMODEA lpdm)
2251 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2253 if (!GDI_CallDeviceCapabilities16)
2255 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2257 if (!GDI_CallDeviceCapabilities16) return -1;
2259 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2261 /* If DC_PAPERSIZE map POINT16s to POINTs */
2262 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2263 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2264 POINT *pt = (POINT *)pOutput;
2266 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2267 for(i = 0; i < ret; i++, pt++)
2272 HeapFree( GetProcessHeap(), 0, tmp );
2278 /*****************************************************************************
2279 * DeviceCapabilitiesW [WINSPOOL.@]
2281 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2284 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2285 WORD fwCapability, LPWSTR pOutput,
2286 const DEVMODEW *pDevMode)
2288 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2289 LPSTR pDeviceA = strdupWtoA(pDevice);
2290 LPSTR pPortA = strdupWtoA(pPort);
2293 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2295 if(pOutput && (fwCapability == DC_BINNAMES ||
2296 fwCapability == DC_FILEDEPENDENCIES ||
2297 fwCapability == DC_PAPERNAMES)) {
2298 /* These need A -> W translation */
2301 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2305 switch(fwCapability) {
2310 case DC_FILEDEPENDENCIES:
2314 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2315 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2317 for(i = 0; i < ret; i++)
2318 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2319 pOutput + (i * size), size);
2320 HeapFree(GetProcessHeap(), 0, pOutputA);
2322 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2323 (LPSTR)pOutput, dmA);
2325 HeapFree(GetProcessHeap(),0,pPortA);
2326 HeapFree(GetProcessHeap(),0,pDeviceA);
2327 HeapFree(GetProcessHeap(),0,dmA);
2331 /******************************************************************
2332 * DocumentPropertiesA [WINSPOOL.@]
2334 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2336 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2337 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2338 LPDEVMODEA pDevModeInput,DWORD fMode )
2340 LPSTR lpName = pDeviceName;
2341 static CHAR port[] = "LPT1:";
2344 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2345 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2349 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2351 ERR("no name from hPrinter?\n");
2352 SetLastError(ERROR_INVALID_HANDLE);
2355 lpName = strdupWtoA(lpNameW);
2358 if (!GDI_CallExtDeviceMode16)
2360 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2362 if (!GDI_CallExtDeviceMode16) {
2363 ERR("No CallExtDeviceMode16?\n");
2367 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2368 pDevModeInput, NULL, fMode);
2371 HeapFree(GetProcessHeap(),0,lpName);
2376 /*****************************************************************************
2377 * DocumentPropertiesW (WINSPOOL.@)
2379 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2381 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2383 LPDEVMODEW pDevModeOutput,
2384 LPDEVMODEW pDevModeInput, DWORD fMode)
2387 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2388 LPDEVMODEA pDevModeInputA;
2389 LPDEVMODEA pDevModeOutputA = NULL;
2392 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2393 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2395 if(pDevModeOutput) {
2396 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2397 if(ret < 0) return ret;
2398 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2400 pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2401 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2402 pDevModeInputA, fMode);
2403 if(pDevModeOutput) {
2404 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2405 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2407 if(fMode == 0 && ret > 0)
2408 ret += (CCHDEVICENAME + CCHFORMNAME);
2409 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2410 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2414 /*****************************************************************************
2415 * IsValidDevmodeA [WINSPOOL.@]
2417 * Validate a DEVMODE structure and fix errors if possible.
2420 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2422 FIXME("(%p,%ld): stub\n", pDevMode, size);
2430 /*****************************************************************************
2431 * IsValidDevmodeW [WINSPOOL.@]
2433 * Validate a DEVMODE structure and fix errors if possible.
2436 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2438 FIXME("(%p,%ld): stub\n", pDevMode, size);
2446 /******************************************************************
2447 * OpenPrinterA [WINSPOOL.@]
2452 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2453 LPPRINTER_DEFAULTSA pDefault)
2455 UNICODE_STRING lpPrinterNameW;
2456 UNICODE_STRING usBuffer;
2457 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2458 PWSTR pwstrPrinterNameW;
2461 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2463 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2466 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2467 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2468 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2469 pDefaultW = &DefaultW;
2471 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2473 RtlFreeUnicodeString(&usBuffer);
2474 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2476 RtlFreeUnicodeString(&lpPrinterNameW);
2480 /******************************************************************
2481 * OpenPrinterW [WINSPOOL.@]
2483 * Open a Printer / Printserver or a Printer-Object
2486 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2487 * phPrinter [O] The resulting Handle is stored here
2488 * pDefault [I] PTR to Default Printer Settings or NULL
2495 * lpPrinterName is one of:
2496 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2497 *| Printer: "PrinterName"
2498 *| Printer-Object: "PrinterName,Job xxx"
2499 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2500 *| XcvPort: "Servername,XcvPort PortName"
2503 *| Printer-Object not supported
2504 *| pDefaults is ignored
2507 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2510 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2513 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2514 SetLastError(ERROR_INVALID_PARAMETER);
2518 /* Get the unique handle of the printer or Printserver */
2519 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2524 DWORD deleting = 0, size = sizeof( deleting ), type;
2526 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key );
2527 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2528 WaitForSingleObject( init_mutex, INFINITE );
2529 status = get_dword_from_reg( key, StatusW );
2530 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2531 ReleaseMutex( init_mutex );
2532 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2533 update_driver( *phPrinter );
2537 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2538 return (*phPrinter != 0);
2541 /******************************************************************
2542 * AddMonitorA [WINSPOOL.@]
2547 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2549 LPWSTR nameW = NULL;
2552 LPMONITOR_INFO_2A mi2a;
2553 MONITOR_INFO_2W mi2w;
2555 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2556 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2557 debugstr_a(mi2a ? mi2a->pName : NULL),
2558 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2559 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2562 SetLastError(ERROR_INVALID_LEVEL);
2566 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2572 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2573 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2574 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2577 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2579 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2580 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2581 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2583 if (mi2a->pEnvironment) {
2584 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2585 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2586 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2588 if (mi2a->pDLLName) {
2589 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2590 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2591 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2594 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2596 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2597 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2598 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2600 HeapFree(GetProcessHeap(), 0, nameW);
2604 /******************************************************************************
2605 * AddMonitorW [WINSPOOL.@]
2607 * Install a Printmonitor
2610 * pName [I] Servername or NULL (local Computer)
2611 * Level [I] Structure-Level (Must be 2)
2612 * pMonitors [I] PTR to MONITOR_INFO_2
2619 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2622 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2624 LPMONITOR_INFO_2W mi2w;
2626 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2627 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2628 debugstr_w(mi2w ? mi2w->pName : NULL),
2629 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2630 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2632 if ((backend == NULL) && !load_backend()) return FALSE;
2635 SetLastError(ERROR_INVALID_LEVEL);
2639 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2644 return backend->fpAddMonitor(pName, Level, pMonitors);
2647 /******************************************************************
2648 * DeletePrinterDriverA [WINSPOOL.@]
2651 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2653 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2656 /******************************************************************
2657 * DeletePrinterDriverW [WINSPOOL.@]
2660 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2662 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2665 /******************************************************************
2666 * DeleteMonitorA [WINSPOOL.@]
2668 * See DeleteMonitorW.
2671 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2673 LPWSTR nameW = NULL;
2674 LPWSTR EnvironmentW = NULL;
2675 LPWSTR MonitorNameW = NULL;
2680 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2681 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2682 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2686 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2687 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2688 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2691 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2692 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2693 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2696 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2698 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2699 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2700 HeapFree(GetProcessHeap(), 0, nameW);
2704 /******************************************************************
2705 * DeleteMonitorW [WINSPOOL.@]
2707 * Delete a specific Printmonitor from a Printing-Environment
2710 * pName [I] Servername or NULL (local Computer)
2711 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2712 * pMonitorName [I] Name of the Monitor, that should be deleted
2719 * pEnvironment is ignored in Windows for the local Computer.
2722 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2725 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2726 debugstr_w(pMonitorName));
2728 if ((backend == NULL) && !load_backend()) return FALSE;
2730 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2734 /******************************************************************
2735 * DeletePortA [WINSPOOL.@]
2740 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2742 LPWSTR nameW = NULL;
2743 LPWSTR portW = NULL;
2747 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2749 /* convert servername to unicode */
2751 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2752 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2753 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2756 /* convert portname to unicode */
2758 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2759 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2760 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2763 res = DeletePortW(nameW, hWnd, portW);
2764 HeapFree(GetProcessHeap(), 0, nameW);
2765 HeapFree(GetProcessHeap(), 0, portW);
2769 /******************************************************************
2770 * DeletePortW [WINSPOOL.@]
2772 * Delete a specific Port
2775 * pName [I] Servername or NULL (local Computer)
2776 * hWnd [I] Handle to parent Window for the Dialog-Box
2777 * pPortName [I] Name of the Port, that should be deleted
2784 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2786 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2788 if ((backend == NULL) && !load_backend()) return FALSE;
2791 SetLastError(RPC_X_NULL_REF_POINTER);
2795 return backend->fpDeletePort(pName, hWnd, pPortName);
2798 /******************************************************************************
2799 * WritePrinter [WINSPOOL.@]
2801 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2803 opened_printer_t *printer;
2806 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2808 EnterCriticalSection(&printer_handles_cs);
2809 printer = get_opened_printer(hPrinter);
2812 SetLastError(ERROR_INVALID_HANDLE);
2818 SetLastError(ERROR_SPL_NO_STARTDOC);
2822 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2824 LeaveCriticalSection(&printer_handles_cs);
2828 /*****************************************************************************
2829 * AddFormA [WINSPOOL.@]
2831 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2833 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2837 /*****************************************************************************
2838 * AddFormW [WINSPOOL.@]
2840 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2842 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2846 /*****************************************************************************
2847 * AddJobA [WINSPOOL.@]
2849 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2852 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2856 SetLastError(ERROR_INVALID_LEVEL);
2860 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2863 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2864 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2865 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2866 if(*pcbNeeded > cbBuf) {
2867 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2870 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2871 addjobA->JobId = addjobW->JobId;
2872 addjobA->Path = (char *)(addjobA + 1);
2873 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2879 /*****************************************************************************
2880 * AddJobW [WINSPOOL.@]
2882 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2884 opened_printer_t *printer;
2887 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2888 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2889 WCHAR path[MAX_PATH], filename[MAX_PATH];
2891 ADDJOB_INFO_1W *addjob;
2893 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2895 EnterCriticalSection(&printer_handles_cs);
2897 printer = get_opened_printer(hPrinter);
2900 SetLastError(ERROR_INVALID_HANDLE);
2905 SetLastError(ERROR_INVALID_LEVEL);
2909 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2913 job->job_id = InterlockedIncrement(&next_job_id);
2915 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2916 if(path[len - 1] != '\\')
2918 memcpy(path + len, spool_path, sizeof(spool_path));
2919 sprintfW(filename, fmtW, path, job->job_id);
2921 len = strlenW(filename);
2922 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2923 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2924 job->portname = NULL;
2925 job->document_title = strdupW(default_doc_title);
2926 job->printer_name = strdupW(printer->name);
2927 job->devmode = dup_devmode( printer->devmode );
2928 list_add_tail(&printer->queue->jobs, &job->entry);
2930 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2931 if(*pcbNeeded <= cbBuf) {
2932 addjob = (ADDJOB_INFO_1W*)pData;
2933 addjob->JobId = job->job_id;
2934 addjob->Path = (WCHAR *)(addjob + 1);
2935 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2938 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2941 LeaveCriticalSection(&printer_handles_cs);
2945 /*****************************************************************************
2946 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2948 * Return the PATH for the Print-Processors
2950 * See GetPrintProcessorDirectoryW.
2954 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2955 DWORD level, LPBYTE Info,
2956 DWORD cbBuf, LPDWORD pcbNeeded)
2958 LPWSTR serverW = NULL;
2963 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2964 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2968 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2969 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2970 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2974 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2975 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2976 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2979 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2980 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2982 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2985 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2986 cbBuf, NULL, NULL) > 0;
2989 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2990 HeapFree(GetProcessHeap(), 0, envW);
2991 HeapFree(GetProcessHeap(), 0, serverW);
2995 /*****************************************************************************
2996 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2998 * Return the PATH for the Print-Processors
3001 * server [I] Servername (NT only) or NULL (local Computer)
3002 * env [I] Printing-Environment (see below) or NULL (Default)
3003 * level [I] Structure-Level (must be 1)
3004 * Info [O] PTR to Buffer that receives the Result
3005 * cbBuf [I] Size of Buffer at "Info"
3006 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3007 * required for the Buffer at "Info"
3010 * Success: TRUE and in pcbNeeded the Bytes used in Info
3011 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3012 * if cbBuf is too small
3014 * Native Values returned in Info on Success:
3015 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3016 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3017 *| win9x(Windows 4.0): "%winsysdir%"
3019 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3022 * Only NULL or "" is supported for server
3025 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3026 DWORD level, LPBYTE Info,
3027 DWORD cbBuf, LPDWORD pcbNeeded)
3030 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3031 Info, cbBuf, pcbNeeded);
3033 if ((backend == NULL) && !load_backend()) return FALSE;
3036 /* (Level != 1) is ignored in win9x */
3037 SetLastError(ERROR_INVALID_LEVEL);
3041 if (pcbNeeded == NULL) {
3042 /* (pcbNeeded == NULL) is ignored in win9x */
3043 SetLastError(RPC_X_NULL_REF_POINTER);
3047 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3050 /*****************************************************************************
3051 * WINSPOOL_OpenDriverReg [internal]
3053 * opens the registry for the printer drivers depending on the given input
3054 * variable pEnvironment
3057 * the opened hkey on success
3060 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3064 const printenv_t * env;
3066 TRACE("(%s)\n", debugstr_w(pEnvironment));
3068 env = validate_envW(pEnvironment);
3069 if (!env) return NULL;
3071 buffer = HeapAlloc( GetProcessHeap(), 0,
3072 (strlenW(DriversW) + strlenW(env->envname) +
3073 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3075 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3076 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3077 HeapFree(GetProcessHeap(), 0, buffer);
3082 /*****************************************************************************
3083 * set_devices_and_printerports [internal]
3085 * set the [Devices] and [PrinterPorts] entries for a printer.
3088 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3090 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3094 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3096 /* FIXME: the driver must change to "winspool" */
3097 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3099 lstrcpyW(devline, driver_nt);
3100 lstrcatW(devline, commaW);
3101 lstrcatW(devline, pi->pPortName);
3103 TRACE("using %s\n", debugstr_w(devline));
3104 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3105 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3106 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3107 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3111 lstrcatW(devline, timeout_15_45);
3112 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3113 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3114 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3115 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3118 HeapFree(GetProcessHeap(), 0, devline);
3122 /*****************************************************************************
3123 * AddPrinterW [WINSPOOL.@]
3125 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3127 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3130 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3133 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3136 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3137 SetLastError(ERROR_INVALID_PARAMETER);
3141 ERR("Level = %d, unsupported!\n", Level);
3142 SetLastError(ERROR_INVALID_LEVEL);
3146 SetLastError(ERROR_INVALID_PARAMETER);
3149 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3151 ERR("Can't create Printers key\n");
3154 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3155 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3156 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3157 RegCloseKey(hkeyPrinter);
3158 RegCloseKey(hkeyPrinters);
3161 RegCloseKey(hkeyPrinter);
3163 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3165 ERR("Can't create Drivers key\n");
3166 RegCloseKey(hkeyPrinters);
3169 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3171 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3172 RegCloseKey(hkeyPrinters);
3173 RegCloseKey(hkeyDrivers);
3174 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3177 RegCloseKey(hkeyDriver);
3178 RegCloseKey(hkeyDrivers);
3180 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3181 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3182 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3183 RegCloseKey(hkeyPrinters);
3187 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3189 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3190 SetLastError(ERROR_INVALID_PRINTER_NAME);
3191 RegCloseKey(hkeyPrinters);
3195 set_devices_and_printerports(pi);
3197 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3198 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3199 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3200 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3201 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3202 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3203 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3204 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3205 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3206 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3207 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3208 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3209 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3210 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3211 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3212 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3213 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3214 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3216 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3220 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3221 size = sizeof(DEVMODEW);
3227 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3229 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3231 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3232 HeapFree( GetProcessHeap(), 0, dm );
3237 /* set devmode to printer name */
3238 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3242 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3243 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3245 RegCloseKey(hkeyPrinter);
3246 RegCloseKey(hkeyPrinters);
3247 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3248 ERR("OpenPrinter failing\n");
3254 /*****************************************************************************
3255 * AddPrinterA [WINSPOOL.@]
3257 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3259 UNICODE_STRING pNameW;
3261 PRINTER_INFO_2W *piW;
3262 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3265 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3267 ERR("Level = %d, unsupported!\n", Level);
3268 SetLastError(ERROR_INVALID_LEVEL);
3271 pwstrNameW = asciitounicode(&pNameW,pName);
3272 piW = printer_info_AtoW( piA, Level );
3274 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3276 free_printer_info( piW, Level );
3277 RtlFreeUnicodeString(&pNameW);
3282 /*****************************************************************************
3283 * ClosePrinter [WINSPOOL.@]
3285 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3287 UINT_PTR i = (UINT_PTR)hPrinter;
3288 opened_printer_t *printer = NULL;
3291 TRACE("(%p)\n", hPrinter);
3293 EnterCriticalSection(&printer_handles_cs);
3295 if ((i > 0) && (i <= nb_printer_handles))
3296 printer = printer_handles[i - 1];
3301 struct list *cursor, *cursor2;
3303 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3305 if (printer->backend_printer) {
3306 backend->fpClosePrinter(printer->backend_printer);
3310 EndDocPrinter(hPrinter);
3312 if(InterlockedDecrement(&printer->queue->ref) == 0)
3314 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3316 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3317 ScheduleJob(hPrinter, job->job_id);
3319 HeapFree(GetProcessHeap(), 0, printer->queue);
3322 free_printer_entry( printer );
3323 printer_handles[i - 1] = NULL;
3326 LeaveCriticalSection(&printer_handles_cs);
3330 /*****************************************************************************
3331 * DeleteFormA [WINSPOOL.@]
3333 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3335 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3339 /*****************************************************************************
3340 * DeleteFormW [WINSPOOL.@]
3342 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3344 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3348 /*****************************************************************************
3349 * DeletePrinter [WINSPOOL.@]
3351 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3353 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3354 HKEY hkeyPrinters, hkey;
3355 WCHAR def[MAX_PATH];
3356 DWORD size = sizeof( def ) / sizeof( def[0] );
3359 SetLastError(ERROR_INVALID_HANDLE);
3362 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3363 RegDeleteTreeW(hkeyPrinters, lpNameW);
3364 RegCloseKey(hkeyPrinters);
3366 WriteProfileStringW(devicesW, lpNameW, NULL);
3367 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3369 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3370 RegDeleteValueW(hkey, lpNameW);
3374 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3375 RegDeleteValueW(hkey, lpNameW);
3379 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3381 WriteProfileStringW( windowsW, deviceW, NULL );
3382 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3384 RegDeleteValueW( hkey, deviceW );
3385 RegCloseKey( hkey );
3387 SetDefaultPrinterW( NULL );
3393 /*****************************************************************************
3394 * SetPrinterA [WINSPOOL.@]
3396 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3403 dataW = printer_info_AtoW( data, level );
3404 if (!dataW) return FALSE;
3407 ret = SetPrinterW( printer, level, dataW, command );
3409 if (dataW != data) free_printer_info( dataW, level );
3414 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3416 set_reg_szW( key, NameW, pi->pPrinterName );
3417 set_reg_szW( key, Share_NameW, pi->pShareName );
3418 set_reg_szW( key, PortW, pi->pPortName );
3419 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3420 set_reg_szW( key, DescriptionW, pi->pComment );
3421 set_reg_szW( key, LocationW, pi->pLocation );
3424 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3426 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3427 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3428 set_reg_szW( key, DatatypeW, pi->pDatatype );
3429 set_reg_szW( key, ParametersW, pi->pParameters );
3431 set_reg_DWORD( key, AttributesW, pi->Attributes );
3432 set_reg_DWORD( key, PriorityW, pi->Priority );
3433 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3434 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3435 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3438 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3440 if (!pi->pDevMode) return FALSE;
3442 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3446 /******************************************************************************
3447 * SetPrinterW [WINSPOOL.@]
3449 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3454 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3456 if (command != 0) FIXME( "Ignoring command %d\n", command );
3458 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3465 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3466 set_printer_2( key, pi2 );
3473 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3474 ret = set_printer_9( key, pi );
3479 FIXME( "Unimplemented level %d\n", level );
3480 SetLastError( ERROR_INVALID_LEVEL );
3487 /*****************************************************************************
3488 * SetJobA [WINSPOOL.@]
3490 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3491 LPBYTE pJob, DWORD Command)
3495 UNICODE_STRING usBuffer;
3497 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3499 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3500 are all ignored by SetJob, so we don't bother copying them */
3508 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3509 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3511 JobW = (LPBYTE)info1W;
3512 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3513 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3514 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3515 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3516 info1W->Status = info1A->Status;
3517 info1W->Priority = info1A->Priority;
3518 info1W->Position = info1A->Position;
3519 info1W->PagesPrinted = info1A->PagesPrinted;
3524 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3525 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3527 JobW = (LPBYTE)info2W;
3528 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3529 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3530 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3531 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3532 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3533 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3534 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3535 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3536 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3537 info2W->Status = info2A->Status;
3538 info2W->Priority = info2A->Priority;
3539 info2W->Position = info2A->Position;
3540 info2W->StartTime = info2A->StartTime;
3541 info2W->UntilTime = info2A->UntilTime;
3542 info2W->PagesPrinted = info2A->PagesPrinted;
3546 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3547 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3550 SetLastError(ERROR_INVALID_LEVEL);
3554 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3560 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3561 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3562 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3563 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3564 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3569 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3570 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3571 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3572 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3573 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3574 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3575 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3576 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3577 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3581 HeapFree(GetProcessHeap(), 0, JobW);
3586 /*****************************************************************************
3587 * SetJobW [WINSPOOL.@]
3589 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3590 LPBYTE pJob, DWORD Command)
3595 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3596 FIXME("Ignoring everything other than document title\n");
3598 EnterCriticalSection(&printer_handles_cs);
3599 job = get_job(hPrinter, JobId);
3609 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3610 HeapFree(GetProcessHeap(), 0, job->document_title);
3611 job->document_title = strdupW(info1->pDocument);
3616 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3617 HeapFree(GetProcessHeap(), 0, job->document_title);
3618 job->document_title = strdupW(info2->pDocument);
3619 HeapFree(GetProcessHeap(), 0, job->devmode);
3620 job->devmode = dup_devmode( info2->pDevMode );
3626 SetLastError(ERROR_INVALID_LEVEL);
3631 LeaveCriticalSection(&printer_handles_cs);
3635 /*****************************************************************************
3636 * EndDocPrinter [WINSPOOL.@]
3638 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3640 opened_printer_t *printer;
3642 TRACE("(%p)\n", hPrinter);
3644 EnterCriticalSection(&printer_handles_cs);
3646 printer = get_opened_printer(hPrinter);
3649 SetLastError(ERROR_INVALID_HANDLE);
3655 SetLastError(ERROR_SPL_NO_STARTDOC);
3659 CloseHandle(printer->doc->hf);
3660 ScheduleJob(hPrinter, printer->doc->job_id);
3661 HeapFree(GetProcessHeap(), 0, printer->doc);
3662 printer->doc = NULL;
3665 LeaveCriticalSection(&printer_handles_cs);
3669 /*****************************************************************************
3670 * EndPagePrinter [WINSPOOL.@]
3672 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3674 FIXME("(%p): stub\n", hPrinter);
3678 /*****************************************************************************
3679 * StartDocPrinterA [WINSPOOL.@]
3681 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3683 UNICODE_STRING usBuffer;
3685 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3688 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3689 or one (DOC_INFO_3) extra DWORDs */
3693 doc2W.JobId = doc2->JobId;
3696 doc2W.dwMode = doc2->dwMode;
3699 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3700 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3701 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3705 SetLastError(ERROR_INVALID_LEVEL);
3709 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3711 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3712 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3713 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3718 /*****************************************************************************
3719 * StartDocPrinterW [WINSPOOL.@]
3721 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3723 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3724 opened_printer_t *printer;
3725 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3726 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3727 JOB_INFO_1W job_info;
3728 DWORD needed, ret = 0;
3733 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3734 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3735 debugstr_w(doc->pDatatype));
3737 if(Level < 1 || Level > 3)
3739 SetLastError(ERROR_INVALID_LEVEL);
3743 EnterCriticalSection(&printer_handles_cs);
3744 printer = get_opened_printer(hPrinter);
3747 SetLastError(ERROR_INVALID_HANDLE);
3753 SetLastError(ERROR_INVALID_PRINTER_STATE);
3757 /* Even if we're printing to a file we still add a print job, we'll
3758 just ignore the spool file name */
3760 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3762 ERR("AddJob failed gle %u\n", GetLastError());
3766 /* use pOutputFile only, when it is a real filename */
3767 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3768 filename = doc->pOutputFile;
3770 filename = addjob->Path;
3772 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3773 if(hf == INVALID_HANDLE_VALUE)
3776 memset(&job_info, 0, sizeof(job_info));
3777 job_info.pDocument = doc->pDocName;
3778 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3780 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3781 printer->doc->hf = hf;
3782 ret = printer->doc->job_id = addjob->JobId;
3783 job = get_job(hPrinter, ret);
3784 job->portname = strdupW(doc->pOutputFile);
3787 LeaveCriticalSection(&printer_handles_cs);
3792 /*****************************************************************************
3793 * StartPagePrinter [WINSPOOL.@]
3795 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3797 FIXME("(%p): stub\n", hPrinter);
3801 /*****************************************************************************
3802 * GetFormA [WINSPOOL.@]
3804 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3805 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3807 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3808 Level,pForm,cbBuf,pcbNeeded);
3812 /*****************************************************************************
3813 * GetFormW [WINSPOOL.@]
3815 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3816 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3818 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3819 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3823 /*****************************************************************************
3824 * SetFormA [WINSPOOL.@]
3826 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3829 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3833 /*****************************************************************************
3834 * SetFormW [WINSPOOL.@]
3836 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3839 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3843 /*****************************************************************************
3844 * ReadPrinter [WINSPOOL.@]
3846 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3847 LPDWORD pNoBytesRead)
3849 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3853 /*****************************************************************************
3854 * ResetPrinterA [WINSPOOL.@]
3856 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3858 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3862 /*****************************************************************************
3863 * ResetPrinterW [WINSPOOL.@]
3865 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3867 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3871 /*****************************************************************************
3872 * get_filename_from_reg [internal]
3874 * Get ValueName from hkey storing result in out
3875 * when the Value in the registry has only a filename, use driverdir as prefix
3876 * outlen is space left in out
3877 * String is stored either as unicode or ascii
3881 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3882 LPBYTE out, DWORD outlen, LPDWORD needed)
3884 WCHAR filename[MAX_PATH];
3888 LPWSTR buffer = filename;
3892 size = sizeof(filename);
3894 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3895 if (ret == ERROR_MORE_DATA) {
3896 TRACE("need dynamic buffer: %u\n", size);
3897 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3899 /* No Memory is bad */
3903 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3906 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3907 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3913 /* do we have a full path ? */
3914 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3915 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3918 /* we must build the full Path */
3920 if ((out) && (outlen > dirlen)) {
3921 lstrcpyW((LPWSTR)out, driverdir);
3929 /* write the filename */
3930 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3931 if ((out) && (outlen >= size)) {
3932 lstrcpyW((LPWSTR)out, ptr);
3939 ptr += lstrlenW(ptr)+1;
3940 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3943 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3945 /* write the multisz-termination */
3946 if (type == REG_MULTI_SZ) {
3947 size = sizeof(WCHAR);
3950 if (out && (outlen >= size)) {
3951 memset (out, 0, size);
3957 /*****************************************************************************
3958 * WINSPOOL_GetStringFromReg
3960 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3961 * String is stored as unicode.
3963 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3964 DWORD buflen, DWORD *needed)
3966 DWORD sz = buflen, type;
3969 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3970 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3971 WARN("Got ret = %d\n", ret);
3975 /* add space for terminating '\0' */
3976 sz += sizeof(WCHAR);
3980 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3985 /*****************************************************************************
3986 * WINSPOOL_GetDefaultDevMode
3988 * Get a default DevMode values for wineps.
3990 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
3992 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
3994 if (buflen >= sizeof(DEVMODEW))
3996 DEVMODEW *dm = (DEVMODEW *)ptr;
3998 /* the driver will update registry with real values */
3999 memset(dm, 0, sizeof(*dm));
4000 dm->dmSize = sizeof(*dm);
4001 lstrcpyW(dm->dmDeviceName, winepsW);
4003 *needed = sizeof(DEVMODEW);
4006 /*****************************************************************************
4007 * WINSPOOL_GetDevModeFromReg
4009 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4010 * DevMode is stored either as unicode or ascii.
4012 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4014 DWORD buflen, DWORD *needed)
4016 DWORD sz = buflen, type;
4019 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4020 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4021 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4022 if (sz < sizeof(DEVMODEA))
4024 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4027 /* ensures that dmSize is not erratically bogus if registry is invalid */
4028 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4029 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4030 sz += (CCHDEVICENAME + CCHFORMNAME);
4031 if (ptr && (buflen >= sz)) {
4032 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4033 memcpy(ptr, dmW, sz);
4034 HeapFree(GetProcessHeap(),0,dmW);
4040 /*********************************************************************
4041 * WINSPOOL_GetPrinter_1
4043 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4045 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4046 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4048 DWORD size, left = cbBuf;
4049 BOOL space = (cbBuf > 0);
4054 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4055 if(space && size <= left) {
4056 pi1->pName = (LPWSTR)ptr;
4064 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4065 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4066 if(space && size <= left) {
4067 pi1->pDescription = (LPWSTR)ptr;
4075 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4076 if(space && size <= left) {
4077 pi1->pComment = (LPWSTR)ptr;
4085 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4087 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4088 memset(pi1, 0, sizeof(*pi1));
4092 /*********************************************************************
4093 * WINSPOOL_GetPrinter_2
4095 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4097 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4098 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4100 DWORD size, left = cbBuf;
4101 BOOL space = (cbBuf > 0);
4106 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4107 if(space && size <= left) {
4108 pi2->pPrinterName = (LPWSTR)ptr;
4115 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4116 if(space && size <= left) {
4117 pi2->pShareName = (LPWSTR)ptr;
4124 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4125 if(space && size <= left) {
4126 pi2->pPortName = (LPWSTR)ptr;
4133 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4134 if(space && size <= left) {
4135 pi2->pDriverName = (LPWSTR)ptr;
4142 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4143 if(space && size <= left) {
4144 pi2->pComment = (LPWSTR)ptr;
4151 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4152 if(space && size <= left) {
4153 pi2->pLocation = (LPWSTR)ptr;
4160 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4161 if(space && size <= left) {
4162 pi2->pDevMode = (LPDEVMODEW)ptr;
4171 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4172 if(space && size <= left) {
4173 pi2->pDevMode = (LPDEVMODEW)ptr;
4180 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4181 if(space && size <= left) {
4182 pi2->pSepFile = (LPWSTR)ptr;
4189 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4190 if(space && size <= left) {
4191 pi2->pPrintProcessor = (LPWSTR)ptr;
4198 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4199 if(space && size <= left) {
4200 pi2->pDatatype = (LPWSTR)ptr;
4207 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4208 if(space && size <= left) {
4209 pi2->pParameters = (LPWSTR)ptr;
4217 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4218 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4219 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4220 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4221 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4224 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4225 memset(pi2, 0, sizeof(*pi2));
4230 /*********************************************************************
4231 * WINSPOOL_GetPrinter_4
4233 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4235 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4236 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4238 DWORD size, left = cbBuf;
4239 BOOL space = (cbBuf > 0);
4244 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4245 if(space && size <= left) {
4246 pi4->pPrinterName = (LPWSTR)ptr;
4254 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4257 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4258 memset(pi4, 0, sizeof(*pi4));
4263 /*********************************************************************
4264 * WINSPOOL_GetPrinter_5
4266 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4268 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4269 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4271 DWORD size, left = cbBuf;
4272 BOOL space = (cbBuf > 0);
4277 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4278 if(space && size <= left) {
4279 pi5->pPrinterName = (LPWSTR)ptr;
4286 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4287 if(space && size <= left) {
4288 pi5->pPortName = (LPWSTR)ptr;
4296 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4297 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4298 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4301 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4302 memset(pi5, 0, sizeof(*pi5));
4307 /*********************************************************************
4308 * WINSPOOL_GetPrinter_7
4310 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4312 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4313 DWORD cbBuf, LPDWORD pcbNeeded)
4315 DWORD size, left = cbBuf;
4316 BOOL space = (cbBuf > 0);
4321 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4324 size = sizeof(pi7->pszObjectGUID);
4326 if (space && size <= left) {
4327 pi7->pszObjectGUID = (LPWSTR)ptr;
4334 /* We do not have a Directory Service */
4335 pi7->dwAction = DSPRINT_UNPUBLISH;
4338 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4339 memset(pi7, 0, sizeof(*pi7));
4344 /*********************************************************************
4345 * WINSPOOL_GetPrinter_9
4347 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4349 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4350 DWORD cbBuf, LPDWORD pcbNeeded)
4353 BOOL space = (cbBuf > 0);
4357 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4358 if(space && size <= cbBuf) {
4359 pi9->pDevMode = (LPDEVMODEW)buf;
4366 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4367 if(space && size <= cbBuf) {
4368 pi9->pDevMode = (LPDEVMODEW)buf;
4374 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4375 memset(pi9, 0, sizeof(*pi9));
4380 /*****************************************************************************
4381 * GetPrinterW [WINSPOOL.@]
4383 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4384 DWORD cbBuf, LPDWORD pcbNeeded)
4386 DWORD size, needed = 0, err;
4391 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4393 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4396 SetLastError( err );
4403 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4405 size = sizeof(PRINTER_INFO_2W);
4407 ptr = pPrinter + size;
4409 memset(pPrinter, 0, size);
4414 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4421 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4423 size = sizeof(PRINTER_INFO_4W);
4425 ptr = pPrinter + size;
4427 memset(pPrinter, 0, size);
4432 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4440 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4442 size = sizeof(PRINTER_INFO_5W);
4444 ptr = pPrinter + size;
4446 memset(pPrinter, 0, size);
4452 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4460 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4462 size = sizeof(PRINTER_INFO_6);
4463 if (size <= cbBuf) {
4464 /* FIXME: We do not update the status yet */
4465 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4477 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4479 size = sizeof(PRINTER_INFO_7W);
4480 if (size <= cbBuf) {
4481 ptr = pPrinter + size;
4483 memset(pPrinter, 0, size);
4489 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4496 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4497 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4501 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4503 size = sizeof(PRINTER_INFO_9W);
4505 ptr = pPrinter + size;
4507 memset(pPrinter, 0, size);
4513 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4520 FIXME("Unimplemented level %d\n", Level);
4521 SetLastError(ERROR_INVALID_LEVEL);
4522 RegCloseKey(hkeyPrinter);
4526 RegCloseKey(hkeyPrinter);
4528 TRACE("returning %d needed = %d\n", ret, needed);
4529 if(pcbNeeded) *pcbNeeded = needed;
4531 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4535 /*****************************************************************************
4536 * GetPrinterA [WINSPOOL.@]
4538 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4539 DWORD cbBuf, LPDWORD pcbNeeded)
4545 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4547 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4549 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4550 HeapFree(GetProcessHeap(), 0, buf);
4555 /*****************************************************************************
4556 * WINSPOOL_EnumPrintersW
4558 * Implementation of EnumPrintersW
4560 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4561 DWORD dwLevel, LPBYTE lpbPrinters,
4562 DWORD cbBuf, LPDWORD lpdwNeeded,
4563 LPDWORD lpdwReturned)
4566 HKEY hkeyPrinters, hkeyPrinter;
4567 WCHAR PrinterName[255];
4568 DWORD needed = 0, number = 0;
4569 DWORD used, i, left;
4573 memset(lpbPrinters, 0, cbBuf);
4579 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4580 if(dwType == PRINTER_ENUM_DEFAULT)
4583 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4584 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4585 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4587 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4593 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4594 FIXME("dwType = %08x\n", dwType);
4595 SetLastError(ERROR_INVALID_FLAGS);
4599 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4601 ERR("Can't create Printers key\n");
4605 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4606 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4607 RegCloseKey(hkeyPrinters);
4608 ERR("Can't query Printers key\n");
4611 TRACE("Found %d printers\n", number);
4615 used = number * sizeof(PRINTER_INFO_1W);
4618 used = number * sizeof(PRINTER_INFO_2W);
4621 used = number * sizeof(PRINTER_INFO_4W);
4624 used = number * sizeof(PRINTER_INFO_5W);
4628 SetLastError(ERROR_INVALID_LEVEL);
4629 RegCloseKey(hkeyPrinters);
4632 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4634 for(i = 0; i < number; i++) {
4635 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4637 ERR("Can't enum key number %d\n", i);
4638 RegCloseKey(hkeyPrinters);
4641 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4642 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4644 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4645 RegCloseKey(hkeyPrinters);
4650 buf = lpbPrinters + used;
4651 left = cbBuf - used;
4659 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4662 if(pi) pi += sizeof(PRINTER_INFO_1W);
4665 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4668 if(pi) pi += sizeof(PRINTER_INFO_2W);
4671 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4674 if(pi) pi += sizeof(PRINTER_INFO_4W);
4677 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4680 if(pi) pi += sizeof(PRINTER_INFO_5W);
4683 ERR("Shouldn't be here!\n");
4684 RegCloseKey(hkeyPrinter);
4685 RegCloseKey(hkeyPrinters);
4688 RegCloseKey(hkeyPrinter);
4690 RegCloseKey(hkeyPrinters);
4697 memset(lpbPrinters, 0, cbBuf);
4698 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4702 *lpdwReturned = number;
4703 SetLastError(ERROR_SUCCESS);
4708 /******************************************************************
4709 * EnumPrintersW [WINSPOOL.@]
4711 * Enumerates the available printers, print servers and print
4712 * providers, depending on the specified flags, name and level.
4716 * If level is set to 1:
4717 * Returns an array of PRINTER_INFO_1 data structures in the
4718 * lpbPrinters buffer.
4720 * If level is set to 2:
4721 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4722 * Returns an array of PRINTER_INFO_2 data structures in the
4723 * lpbPrinters buffer. Note that according to MSDN also an
4724 * OpenPrinter should be performed on every remote printer.
4726 * If level is set to 4 (officially WinNT only):
4727 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4728 * Fast: Only the registry is queried to retrieve printer names,
4729 * no connection to the driver is made.
4730 * Returns an array of PRINTER_INFO_4 data structures in the
4731 * lpbPrinters buffer.
4733 * If level is set to 5 (officially WinNT4/Win9x only):
4734 * Fast: Only the registry is queried to retrieve printer names,
4735 * no connection to the driver is made.
4736 * Returns an array of PRINTER_INFO_5 data structures in the
4737 * lpbPrinters buffer.
4739 * If level set to 3 or 6+:
4740 * returns zero (failure!)
4742 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4746 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4747 * - Only levels 2, 4 and 5 are implemented at the moment.
4748 * - 16-bit printer drivers are not enumerated.
4749 * - Returned amount of bytes used/needed does not match the real Windoze
4750 * implementation (as in this implementation, all strings are part
4751 * of the buffer, whereas Win32 keeps them somewhere else)
4752 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4755 * - In a regular Wine installation, no registry settings for printers
4756 * exist, which makes this function return an empty list.
4758 BOOL WINAPI EnumPrintersW(
4759 DWORD dwType, /* [in] Types of print objects to enumerate */
4760 LPWSTR lpszName, /* [in] name of objects to enumerate */
4761 DWORD dwLevel, /* [in] type of printer info structure */
4762 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4763 DWORD cbBuf, /* [in] max size of buffer in bytes */
4764 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4765 LPDWORD lpdwReturned /* [out] number of entries returned */
4768 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4769 lpdwNeeded, lpdwReturned);
4772 /******************************************************************
4773 * EnumPrintersA [WINSPOOL.@]
4778 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4779 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4782 UNICODE_STRING pNameU;
4786 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4787 pPrinters, cbBuf, pcbNeeded, pcReturned);
4789 pNameW = asciitounicode(&pNameU, pName);
4791 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4792 MS Office need this */
4793 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4795 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4797 RtlFreeUnicodeString(&pNameU);
4799 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4801 HeapFree(GetProcessHeap(), 0, pPrintersW);
4805 /*****************************************************************************
4806 * WINSPOOL_GetDriverInfoFromReg [internal]
4808 * Enters the information from the registry into the DRIVER_INFO struct
4811 * zero if the printer driver does not exist in the registry
4812 * (only if Level > 1) otherwise nonzero
4814 static BOOL WINSPOOL_GetDriverInfoFromReg(
4817 const printenv_t * env,
4819 LPBYTE ptr, /* DRIVER_INFO */
4820 LPBYTE pDriverStrings, /* strings buffer */
4821 DWORD cbBuf, /* size of string buffer */
4822 LPDWORD pcbNeeded) /* space needed for str. */
4826 WCHAR driverdir[MAX_PATH];
4828 LPBYTE strPtr = pDriverStrings;
4829 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4831 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4832 debugstr_w(DriverName), env,
4833 Level, di, pDriverStrings, cbBuf);
4835 if (di) ZeroMemory(di, di_sizeof[Level]);
4837 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4838 if (*pcbNeeded <= cbBuf)
4839 strcpyW((LPWSTR)strPtr, DriverName);
4841 /* pName for level 1 has a different offset! */
4843 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4847 /* .cVersion and .pName for level > 1 */
4849 di->cVersion = env->driverversion;
4850 di->pName = (LPWSTR) strPtr;
4851 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4854 /* Reserve Space for the largest subdir and a Backslash*/
4855 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4856 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4857 /* Should never Fail */
4860 lstrcatW(driverdir, env->versionsubdir);
4861 lstrcatW(driverdir, backslashW);
4863 /* dirlen must not include the terminating zero */
4864 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4866 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4867 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4868 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4873 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4876 if (*pcbNeeded <= cbBuf) {
4877 lstrcpyW((LPWSTR)strPtr, env->envname);
4878 if (di) di->pEnvironment = (LPWSTR)strPtr;
4879 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4882 /* .pDriverPath is the Graphics rendering engine.
4883 The full Path is required to avoid a crash in some apps */
4884 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4886 if (*pcbNeeded <= cbBuf)
4887 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4889 if (di) di->pDriverPath = (LPWSTR)strPtr;
4890 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4893 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4894 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4896 if (*pcbNeeded <= cbBuf)
4897 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4899 if (di) di->pDataFile = (LPWSTR)strPtr;
4900 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4903 /* .pConfigFile is the Driver user Interface */
4904 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4906 if (*pcbNeeded <= cbBuf)
4907 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4909 if (di) di->pConfigFile = (LPWSTR)strPtr;
4910 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4914 RegCloseKey(hkeyDriver);
4915 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4920 RegCloseKey(hkeyDriver);
4921 FIXME("level 5: incomplete\n");
4926 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4928 if (*pcbNeeded <= cbBuf)
4929 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4931 if (di) di->pHelpFile = (LPWSTR)strPtr;
4932 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4935 /* .pDependentFiles */
4936 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4938 if (*pcbNeeded <= cbBuf)
4939 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4941 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4942 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4944 else if (GetVersion() & 0x80000000) {
4945 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4946 size = 2 * sizeof(WCHAR);
4948 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4950 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4951 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4954 /* .pMonitorName is the optional Language Monitor */
4955 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4957 if (*pcbNeeded <= cbBuf)
4958 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4960 if (di) di->pMonitorName = (LPWSTR)strPtr;
4961 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4964 /* .pDefaultDataType */
4965 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4967 if(*pcbNeeded <= cbBuf)
4968 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4970 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4971 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4975 RegCloseKey(hkeyDriver);
4976 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4980 /* .pszzPreviousNames */
4981 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4983 if(*pcbNeeded <= cbBuf)
4984 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4986 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4987 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4991 RegCloseKey(hkeyDriver);
4992 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4996 /* support is missing, but not important enough for a FIXME */
4997 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5000 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5002 if(*pcbNeeded <= cbBuf)
5003 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5005 if (di) di->pszMfgName = (LPWSTR)strPtr;
5006 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5010 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5012 if(*pcbNeeded <= cbBuf)
5013 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5015 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5016 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5019 /* .pszHardwareID */
5020 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5022 if(*pcbNeeded <= cbBuf)
5023 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5025 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5026 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5030 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5032 if(*pcbNeeded <= cbBuf)
5033 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5035 if (di) di->pszProvider = (LPWSTR)strPtr;
5036 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5040 RegCloseKey(hkeyDriver);
5044 /* support is missing, but not important enough for a FIXME */
5045 TRACE("level 8: incomplete\n");
5047 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5048 RegCloseKey(hkeyDriver);
5052 /*****************************************************************************
5053 * GetPrinterDriverW [WINSPOOL.@]
5055 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5056 DWORD Level, LPBYTE pDriverInfo,
5057 DWORD cbBuf, LPDWORD pcbNeeded)
5060 WCHAR DriverName[100];
5061 DWORD ret, type, size, needed = 0;
5063 HKEY hkeyPrinter, hkeyDrivers;
5064 const printenv_t * env;
5066 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5067 Level,pDriverInfo,cbBuf, pcbNeeded);
5070 ZeroMemory(pDriverInfo, cbBuf);
5072 if (!(name = get_opened_printer_name(hPrinter))) {
5073 SetLastError(ERROR_INVALID_HANDLE);
5077 if (Level < 1 || Level == 7 || Level > 8) {
5078 SetLastError(ERROR_INVALID_LEVEL);
5082 env = validate_envW(pEnvironment);
5083 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5085 ret = open_printer_reg_key( name, &hkeyPrinter );
5088 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5089 SetLastError( ret );
5093 size = sizeof(DriverName);
5095 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5096 (LPBYTE)DriverName, &size);
5097 RegCloseKey(hkeyPrinter);
5098 if(ret != ERROR_SUCCESS) {
5099 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5103 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5105 ERR("Can't create Drivers key\n");
5109 size = di_sizeof[Level];
5110 if ((size <= cbBuf) && pDriverInfo)
5111 ptr = pDriverInfo + size;
5113 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5114 env, Level, pDriverInfo, ptr,
5115 (cbBuf < size) ? 0 : cbBuf - size,
5117 RegCloseKey(hkeyDrivers);
5121 RegCloseKey(hkeyDrivers);
5123 if(pcbNeeded) *pcbNeeded = size + needed;
5124 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5125 if(cbBuf >= size + needed) return TRUE;
5126 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5130 /*****************************************************************************
5131 * GetPrinterDriverA [WINSPOOL.@]
5133 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5134 DWORD Level, LPBYTE pDriverInfo,
5135 DWORD cbBuf, LPDWORD pcbNeeded)
5138 UNICODE_STRING pEnvW;
5144 ZeroMemory(pDriverInfo, cbBuf);
5145 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5148 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5149 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5152 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5154 HeapFree(GetProcessHeap(), 0, buf);
5156 RtlFreeUnicodeString(&pEnvW);
5160 /*****************************************************************************
5161 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5163 * Return the PATH for the Printer-Drivers (UNICODE)
5166 * pName [I] Servername (NT only) or NULL (local Computer)
5167 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5168 * Level [I] Structure-Level (must be 1)
5169 * pDriverDirectory [O] PTR to Buffer that receives the Result
5170 * cbBuf [I] Size of Buffer at pDriverDirectory
5171 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5172 * required for pDriverDirectory
5175 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5176 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5177 * if cbBuf is too small
5179 * Native Values returned in pDriverDirectory on Success:
5180 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5181 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5182 *| win9x(Windows 4.0): "%winsysdir%"
5184 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5187 *- Only NULL or "" is supported for pName
5190 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5191 DWORD Level, LPBYTE pDriverDirectory,
5192 DWORD cbBuf, LPDWORD pcbNeeded)
5194 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5195 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5197 if ((backend == NULL) && !load_backend()) return FALSE;
5200 /* (Level != 1) is ignored in win9x */
5201 SetLastError(ERROR_INVALID_LEVEL);
5204 if (pcbNeeded == NULL) {
5205 /* (pcbNeeded == NULL) is ignored in win9x */
5206 SetLastError(RPC_X_NULL_REF_POINTER);
5210 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5211 pDriverDirectory, cbBuf, pcbNeeded);
5216 /*****************************************************************************
5217 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5219 * Return the PATH for the Printer-Drivers (ANSI)
5221 * See GetPrinterDriverDirectoryW.
5224 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5227 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5228 DWORD Level, LPBYTE pDriverDirectory,
5229 DWORD cbBuf, LPDWORD pcbNeeded)
5231 UNICODE_STRING nameW, environmentW;
5234 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5235 WCHAR *driverDirectoryW = NULL;
5237 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5238 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5240 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5242 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5243 else nameW.Buffer = NULL;
5244 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5245 else environmentW.Buffer = NULL;
5247 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5248 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5251 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5252 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5254 *pcbNeeded = needed;
5255 ret = needed <= cbBuf;
5257 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5259 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5261 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5262 RtlFreeUnicodeString(&environmentW);
5263 RtlFreeUnicodeString(&nameW);
5268 /*****************************************************************************
5269 * AddPrinterDriverA [WINSPOOL.@]
5271 * See AddPrinterDriverW.
5274 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5276 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5277 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5280 /******************************************************************************
5281 * AddPrinterDriverW (WINSPOOL.@)
5283 * Install a Printer Driver
5286 * pName [I] Servername or NULL (local Computer)
5287 * level [I] Level for the supplied DRIVER_INFO_*W struct
5288 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5295 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5297 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5298 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5301 /*****************************************************************************
5302 * AddPrintProcessorA [WINSPOOL.@]
5304 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5305 LPSTR pPrintProcessorName)
5307 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5308 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5312 /*****************************************************************************
5313 * AddPrintProcessorW [WINSPOOL.@]
5315 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5316 LPWSTR pPrintProcessorName)
5318 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5319 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5323 /*****************************************************************************
5324 * AddPrintProvidorA [WINSPOOL.@]
5326 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5328 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5332 /*****************************************************************************
5333 * AddPrintProvidorW [WINSPOOL.@]
5335 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5337 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5341 /*****************************************************************************
5342 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5344 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5345 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5347 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5348 pDevModeOutput, pDevModeInput);
5352 /*****************************************************************************
5353 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5355 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5356 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5358 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5359 pDevModeOutput, pDevModeInput);
5363 /*****************************************************************************
5364 * PrinterProperties [WINSPOOL.@]
5366 * Displays a dialog to set the properties of the printer.
5369 * nonzero on success or zero on failure
5372 * implemented as stub only
5374 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5375 HANDLE hPrinter /* [in] handle to printer object */
5377 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5378 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5382 /*****************************************************************************
5383 * EnumJobsA [WINSPOOL.@]
5386 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5387 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5390 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5391 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5393 if(pcbNeeded) *pcbNeeded = 0;
5394 if(pcReturned) *pcReturned = 0;
5399 /*****************************************************************************
5400 * EnumJobsW [WINSPOOL.@]
5403 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5404 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5407 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5408 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5410 if(pcbNeeded) *pcbNeeded = 0;
5411 if(pcReturned) *pcReturned = 0;
5415 /*****************************************************************************
5416 * WINSPOOL_EnumPrinterDrivers [internal]
5418 * Delivers information about all printer drivers installed on the
5419 * localhost or a given server
5422 * nonzero on success or zero on failure. If the buffer for the returned
5423 * information is too small the function will return an error
5426 * - only implemented for localhost, foreign hosts will return an error
5428 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5429 DWORD Level, LPBYTE pDriverInfo,
5431 DWORD cbBuf, LPDWORD pcbNeeded,
5432 LPDWORD pcFound, DWORD data_offset)
5436 const printenv_t * env;
5438 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5439 debugstr_w(pName), debugstr_w(pEnvironment),
5440 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5442 env = validate_envW(pEnvironment);
5443 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5447 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5449 ERR("Can't open Drivers key\n");
5453 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5454 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5455 RegCloseKey(hkeyDrivers);
5456 ERR("Can't query Drivers key\n");
5459 TRACE("Found %d Drivers\n", *pcFound);
5461 /* get size of single struct
5462 * unicode and ascii structure have the same size
5464 size = di_sizeof[Level];
5466 if (data_offset == 0)
5467 data_offset = size * (*pcFound);
5468 *pcbNeeded = data_offset;
5470 for( i = 0; i < *pcFound; i++) {
5471 WCHAR DriverNameW[255];
5472 PBYTE table_ptr = NULL;
5473 PBYTE data_ptr = NULL;
5476 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5478 ERR("Can't enum key number %d\n", i);
5479 RegCloseKey(hkeyDrivers);
5483 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5484 table_ptr = pDriverInfo + (driver_index + i) * size;
5485 if (pDriverInfo && *pcbNeeded <= cbBuf)
5486 data_ptr = pDriverInfo + *pcbNeeded;
5488 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5489 env, Level, table_ptr, data_ptr,
5490 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5492 RegCloseKey(hkeyDrivers);
5496 *pcbNeeded += needed;
5499 RegCloseKey(hkeyDrivers);
5501 if(cbBuf < *pcbNeeded){
5502 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5509 /*****************************************************************************
5510 * EnumPrinterDriversW [WINSPOOL.@]
5512 * see function EnumPrinterDrivers for RETURNS, BUGS
5514 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5515 LPBYTE pDriverInfo, DWORD cbBuf,
5516 LPDWORD pcbNeeded, LPDWORD pcReturned)
5518 static const WCHAR allW[] = {'a','l','l',0};
5522 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5524 SetLastError(RPC_X_NULL_REF_POINTER);
5528 /* check for local drivers */
5529 if((pName) && (pName[0])) {
5530 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5531 SetLastError(ERROR_ACCESS_DENIED);
5535 /* check input parameter */
5536 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5537 SetLastError(ERROR_INVALID_LEVEL);
5541 if(pDriverInfo && cbBuf > 0)
5542 memset( pDriverInfo, 0, cbBuf);
5544 /* Exception: pull all printers */
5545 if (pEnvironment && !strcmpW(pEnvironment, allW))
5547 DWORD i, needed, bufsize = cbBuf;
5548 DWORD total_found = 0;
5551 /* Precompute the overall total; we need this to know
5552 where pointers end and data begins (i.e. data_offset) */
5553 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5556 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5557 NULL, 0, 0, &needed, &found, 0);
5558 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5559 total_found += found;
5562 data_offset = di_sizeof[Level] * total_found;
5567 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5570 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5571 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5572 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5574 *pcReturned += found;
5575 *pcbNeeded = needed;
5576 data_offset = needed;
5577 total_found += found;
5582 /* Normal behavior */
5583 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5584 0, cbBuf, pcbNeeded, &found, 0);
5586 *pcReturned = found;
5591 /*****************************************************************************
5592 * EnumPrinterDriversA [WINSPOOL.@]
5594 * see function EnumPrinterDrivers for RETURNS, BUGS
5596 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5597 LPBYTE pDriverInfo, DWORD cbBuf,
5598 LPDWORD pcbNeeded, LPDWORD pcReturned)
5601 UNICODE_STRING pNameW, pEnvironmentW;
5602 PWSTR pwstrNameW, pwstrEnvironmentW;
5606 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5608 pwstrNameW = asciitounicode(&pNameW, pName);
5609 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5611 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5612 buf, cbBuf, pcbNeeded, pcReturned);
5614 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5616 HeapFree(GetProcessHeap(), 0, buf);
5618 RtlFreeUnicodeString(&pNameW);
5619 RtlFreeUnicodeString(&pEnvironmentW);
5624 /******************************************************************************
5625 * EnumPortsA (WINSPOOL.@)
5630 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5631 LPDWORD pcbNeeded, LPDWORD pcReturned)
5634 LPBYTE bufferW = NULL;
5635 LPWSTR nameW = NULL;
5637 DWORD numentries = 0;
5640 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5641 cbBuf, pcbNeeded, pcReturned);
5643 /* convert servername to unicode */
5645 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5646 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5647 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5649 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5650 needed = cbBuf * sizeof(WCHAR);
5651 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5652 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5654 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5655 if (pcbNeeded) needed = *pcbNeeded;
5656 /* HeapReAlloc return NULL, when bufferW was NULL */
5657 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5658 HeapAlloc(GetProcessHeap(), 0, needed);
5660 /* Try again with the large Buffer */
5661 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5663 needed = pcbNeeded ? *pcbNeeded : 0;
5664 numentries = pcReturned ? *pcReturned : 0;
5667 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5668 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5671 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5672 DWORD entrysize = 0;
5675 LPPORT_INFO_2W pi2w;
5676 LPPORT_INFO_2A pi2a;
5679 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5681 /* First pass: calculate the size for all Entries */
5682 pi2w = (LPPORT_INFO_2W) bufferW;
5683 pi2a = (LPPORT_INFO_2A) pPorts;
5685 while (index < numentries) {
5687 needed += entrysize; /* PORT_INFO_?A */
5688 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5690 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5691 NULL, 0, NULL, NULL);
5693 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5694 NULL, 0, NULL, NULL);
5695 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5696 NULL, 0, NULL, NULL);
5698 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5699 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5700 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5703 /* check for errors and quit on failure */
5704 if (cbBuf < needed) {
5705 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5709 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5710 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5711 cbBuf -= len ; /* free Bytes in the user-Buffer */
5712 pi2w = (LPPORT_INFO_2W) bufferW;
5713 pi2a = (LPPORT_INFO_2A) pPorts;
5715 /* Second Pass: Fill the User Buffer (if we have one) */
5716 while ((index < numentries) && pPorts) {
5718 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5719 pi2a->pPortName = ptr;
5720 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5721 ptr, cbBuf , NULL, NULL);
5725 pi2a->pMonitorName = ptr;
5726 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5727 ptr, cbBuf, NULL, NULL);
5731 pi2a->pDescription = ptr;
5732 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5733 ptr, cbBuf, NULL, NULL);
5737 pi2a->fPortType = pi2w->fPortType;
5738 pi2a->Reserved = 0; /* documented: "must be zero" */
5741 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5742 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5743 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5748 if (pcbNeeded) *pcbNeeded = needed;
5749 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5751 HeapFree(GetProcessHeap(), 0, nameW);
5752 HeapFree(GetProcessHeap(), 0, bufferW);
5754 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5755 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5761 /******************************************************************************
5762 * EnumPortsW (WINSPOOL.@)
5764 * Enumerate available Ports
5767 * pName [I] Servername or NULL (local Computer)
5768 * Level [I] Structure-Level (1 or 2)
5769 * pPorts [O] PTR to Buffer that receives the Result
5770 * cbBuf [I] Size of Buffer at pPorts
5771 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5772 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5776 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5779 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5782 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5783 cbBuf, pcbNeeded, pcReturned);
5785 if ((backend == NULL) && !load_backend()) return FALSE;
5787 /* Level is not checked in win9x */
5788 if (!Level || (Level > 2)) {
5789 WARN("level (%d) is ignored in win9x\n", Level);
5790 SetLastError(ERROR_INVALID_LEVEL);
5793 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5794 SetLastError(RPC_X_NULL_REF_POINTER);
5798 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5801 /******************************************************************************
5802 * GetDefaultPrinterW (WINSPOOL.@)
5805 * This function must read the value from data 'device' of key
5806 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5808 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5812 WCHAR *buffer, *ptr;
5816 SetLastError(ERROR_INVALID_PARAMETER);
5820 /* make the buffer big enough for the stuff from the profile/registry,
5821 * the content must fit into the local buffer to compute the correct
5822 * size even if the extern buffer is too small or not given.
5823 * (20 for ,driver,port) */
5825 len = max(100, (insize + 20));
5826 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5828 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5830 SetLastError (ERROR_FILE_NOT_FOUND);
5834 TRACE("%s\n", debugstr_w(buffer));
5836 if ((ptr = strchrW(buffer, ',')) == NULL)
5838 SetLastError(ERROR_INVALID_NAME);
5844 *namesize = strlenW(buffer) + 1;
5845 if(!name || (*namesize > insize))
5847 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5851 strcpyW(name, buffer);
5854 HeapFree( GetProcessHeap(), 0, buffer);
5859 /******************************************************************************
5860 * GetDefaultPrinterA (WINSPOOL.@)
5862 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5866 WCHAR *bufferW = NULL;
5870 SetLastError(ERROR_INVALID_PARAMETER);
5874 if(name && *namesize) {
5876 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5879 if(!GetDefaultPrinterW( bufferW, namesize)) {
5884 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5888 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5891 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5894 HeapFree( GetProcessHeap(), 0, bufferW);
5899 /******************************************************************************
5900 * SetDefaultPrinterW (WINSPOOL.204)
5902 * Set the Name of the Default Printer
5905 * pszPrinter [I] Name of the Printer or NULL
5912 * When the Parameter is NULL or points to an Empty String and
5913 * a Default Printer was already present, then this Function changes nothing.
5914 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5915 * the First enumerated local Printer is used.
5918 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5920 WCHAR default_printer[MAX_PATH];
5921 LPWSTR buffer = NULL;
5927 TRACE("(%s)\n", debugstr_w(pszPrinter));
5928 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5930 default_printer[0] = '\0';
5931 size = sizeof(default_printer)/sizeof(WCHAR);
5933 /* if we have a default Printer, do nothing. */
5934 if (GetDefaultPrinterW(default_printer, &size))
5938 /* we have no default Printer: search local Printers and use the first */
5939 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5941 default_printer[0] = '\0';
5942 size = sizeof(default_printer)/sizeof(WCHAR);
5943 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5945 pszPrinter = default_printer;
5946 TRACE("using %s\n", debugstr_w(pszPrinter));
5951 if (pszPrinter == NULL) {
5952 TRACE("no local printer found\n");
5953 SetLastError(ERROR_FILE_NOT_FOUND);
5958 /* "pszPrinter" is never empty or NULL here. */
5959 namelen = lstrlenW(pszPrinter);
5960 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5961 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5963 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5964 HeapFree(GetProcessHeap(), 0, buffer);
5965 SetLastError(ERROR_FILE_NOT_FOUND);
5969 /* read the devices entry for the printer (driver,port) to build the string for the
5970 default device entry (printer,driver,port) */
5971 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5972 buffer[namelen] = ',';
5973 namelen++; /* move index to the start of the driver */
5975 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5976 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5978 TRACE("set device to %s\n", debugstr_w(buffer));
5980 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5981 TRACE("failed to set the device entry: %d\n", GetLastError());
5982 lres = ERROR_INVALID_PRINTER_NAME;
5985 /* remove the next section, when INIFileMapping is implemented */
5988 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5989 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5996 if (lres != ERROR_FILE_NOT_FOUND)
5997 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5999 SetLastError(ERROR_INVALID_PRINTER_NAME);
6003 HeapFree(GetProcessHeap(), 0, buffer);
6004 return (lres == ERROR_SUCCESS);
6007 /******************************************************************************
6008 * SetDefaultPrinterA (WINSPOOL.202)
6010 * See SetDefaultPrinterW.
6013 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6015 LPWSTR bufferW = NULL;
6018 TRACE("(%s)\n", debugstr_a(pszPrinter));
6020 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6021 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6022 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6024 res = SetDefaultPrinterW(bufferW);
6025 HeapFree(GetProcessHeap(), 0, bufferW);
6029 /******************************************************************************
6030 * SetPrinterDataExA (WINSPOOL.@)
6032 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6033 LPCSTR pValueName, DWORD Type,
6034 LPBYTE pData, DWORD cbData)
6036 HKEY hkeyPrinter, hkeySubkey;
6039 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6040 debugstr_a(pValueName), Type, pData, cbData);
6042 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6046 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6048 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6049 RegCloseKey(hkeyPrinter);
6052 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6053 RegCloseKey(hkeySubkey);
6054 RegCloseKey(hkeyPrinter);
6058 /******************************************************************************
6059 * SetPrinterDataExW (WINSPOOL.@)
6061 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6062 LPCWSTR pValueName, DWORD Type,
6063 LPBYTE pData, DWORD cbData)
6065 HKEY hkeyPrinter, hkeySubkey;
6068 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6069 debugstr_w(pValueName), Type, pData, cbData);
6071 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6075 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6077 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6078 RegCloseKey(hkeyPrinter);
6081 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6082 RegCloseKey(hkeySubkey);
6083 RegCloseKey(hkeyPrinter);
6087 /******************************************************************************
6088 * SetPrinterDataA (WINSPOOL.@)
6090 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6091 LPBYTE pData, DWORD cbData)
6093 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6097 /******************************************************************************
6098 * SetPrinterDataW (WINSPOOL.@)
6100 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6101 LPBYTE pData, DWORD cbData)
6103 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6107 /******************************************************************************
6108 * GetPrinterDataExA (WINSPOOL.@)
6110 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6111 LPCSTR pValueName, LPDWORD pType,
6112 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6114 opened_printer_t *printer;
6115 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6118 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6119 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6121 printer = get_opened_printer(hPrinter);
6122 if(!printer) return ERROR_INVALID_HANDLE;
6124 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6125 if (ret) return ret;
6127 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6129 if (printer->name) {
6131 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6133 RegCloseKey(hkeyPrinters);
6136 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6137 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6138 RegCloseKey(hkeyPrinter);
6139 RegCloseKey(hkeyPrinters);
6144 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6145 0, pType, pData, pcbNeeded);
6147 if (!ret && !pData) ret = ERROR_MORE_DATA;
6149 RegCloseKey(hkeySubkey);
6150 RegCloseKey(hkeyPrinter);
6151 RegCloseKey(hkeyPrinters);
6153 TRACE("--> %d\n", ret);
6157 /******************************************************************************
6158 * GetPrinterDataExW (WINSPOOL.@)
6160 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6161 LPCWSTR pValueName, LPDWORD pType,
6162 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6164 opened_printer_t *printer;
6165 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6168 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6169 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6171 printer = get_opened_printer(hPrinter);
6172 if(!printer) return ERROR_INVALID_HANDLE;
6174 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6175 if (ret) return ret;
6177 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6179 if (printer->name) {
6181 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6183 RegCloseKey(hkeyPrinters);
6186 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6187 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6188 RegCloseKey(hkeyPrinter);
6189 RegCloseKey(hkeyPrinters);
6194 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6195 0, pType, pData, pcbNeeded);
6197 if (!ret && !pData) ret = ERROR_MORE_DATA;
6199 RegCloseKey(hkeySubkey);
6200 RegCloseKey(hkeyPrinter);
6201 RegCloseKey(hkeyPrinters);
6203 TRACE("--> %d\n", ret);
6207 /******************************************************************************
6208 * GetPrinterDataA (WINSPOOL.@)
6210 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6211 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6213 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6214 pData, nSize, pcbNeeded);
6217 /******************************************************************************
6218 * GetPrinterDataW (WINSPOOL.@)
6220 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6221 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6223 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6224 pData, nSize, pcbNeeded);
6227 /*******************************************************************************
6228 * EnumPrinterDataExW [WINSPOOL.@]
6230 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6231 LPBYTE pEnumValues, DWORD cbEnumValues,
6232 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6234 HKEY hkPrinter, hkSubKey;
6235 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6236 cbValueNameLen, cbMaxValueLen, cbValueLen,
6241 PPRINTER_ENUM_VALUESW ppev;
6243 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6245 if (pKeyName == NULL || *pKeyName == 0)
6246 return ERROR_INVALID_PARAMETER;
6248 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6249 if (ret != ERROR_SUCCESS)
6251 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6256 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6257 if (ret != ERROR_SUCCESS)
6259 r = RegCloseKey (hkPrinter);
6260 if (r != ERROR_SUCCESS)
6261 WARN ("RegCloseKey returned %i\n", r);
6262 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6263 debugstr_w (pKeyName), ret);
6267 ret = RegCloseKey (hkPrinter);
6268 if (ret != ERROR_SUCCESS)
6270 ERR ("RegCloseKey returned %i\n", ret);
6271 r = RegCloseKey (hkSubKey);
6272 if (r != ERROR_SUCCESS)
6273 WARN ("RegCloseKey returned %i\n", r);
6277 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6278 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6279 if (ret != ERROR_SUCCESS)
6281 r = RegCloseKey (hkSubKey);
6282 if (r != ERROR_SUCCESS)
6283 WARN ("RegCloseKey returned %i\n", r);
6284 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6288 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6289 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6291 if (cValues == 0) /* empty key */
6293 r = RegCloseKey (hkSubKey);
6294 if (r != ERROR_SUCCESS)
6295 WARN ("RegCloseKey returned %i\n", r);
6296 *pcbEnumValues = *pnEnumValues = 0;
6297 return ERROR_SUCCESS;
6300 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6302 hHeap = GetProcessHeap ();
6305 ERR ("GetProcessHeap failed\n");
6306 r = RegCloseKey (hkSubKey);
6307 if (r != ERROR_SUCCESS)
6308 WARN ("RegCloseKey returned %i\n", r);
6309 return ERROR_OUTOFMEMORY;
6312 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6313 if (lpValueName == NULL)
6315 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6316 r = RegCloseKey (hkSubKey);
6317 if (r != ERROR_SUCCESS)
6318 WARN ("RegCloseKey returned %i\n", r);
6319 return ERROR_OUTOFMEMORY;
6322 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6323 if (lpValue == NULL)
6325 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6326 if (HeapFree (hHeap, 0, lpValueName) == 0)
6327 WARN ("HeapFree failed with code %i\n", GetLastError ());
6328 r = RegCloseKey (hkSubKey);
6329 if (r != ERROR_SUCCESS)
6330 WARN ("RegCloseKey returned %i\n", r);
6331 return ERROR_OUTOFMEMORY;
6334 TRACE ("pass 1: calculating buffer required for all names and values\n");
6336 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6338 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6340 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6342 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6343 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6344 NULL, NULL, lpValue, &cbValueLen);
6345 if (ret != ERROR_SUCCESS)
6347 if (HeapFree (hHeap, 0, lpValue) == 0)
6348 WARN ("HeapFree failed with code %i\n", GetLastError ());
6349 if (HeapFree (hHeap, 0, lpValueName) == 0)
6350 WARN ("HeapFree failed with code %i\n", GetLastError ());
6351 r = RegCloseKey (hkSubKey);
6352 if (r != ERROR_SUCCESS)
6353 WARN ("RegCloseKey returned %i\n", r);
6354 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6358 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6359 debugstr_w (lpValueName), dwIndex,
6360 cbValueNameLen + 1, cbValueLen);
6362 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6363 cbBufSize += cbValueLen;
6366 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6368 *pcbEnumValues = cbBufSize;
6369 *pnEnumValues = cValues;
6371 if (cbEnumValues < cbBufSize) /* buffer too small */
6373 if (HeapFree (hHeap, 0, lpValue) == 0)
6374 WARN ("HeapFree failed with code %i\n", GetLastError ());
6375 if (HeapFree (hHeap, 0, lpValueName) == 0)
6376 WARN ("HeapFree failed with code %i\n", GetLastError ());
6377 r = RegCloseKey (hkSubKey);
6378 if (r != ERROR_SUCCESS)
6379 WARN ("RegCloseKey returned %i\n", r);
6380 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6381 return ERROR_MORE_DATA;
6384 TRACE ("pass 2: copying all names and values to buffer\n");
6386 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6387 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6389 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6391 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6392 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6393 NULL, &dwType, lpValue, &cbValueLen);
6394 if (ret != ERROR_SUCCESS)
6396 if (HeapFree (hHeap, 0, lpValue) == 0)
6397 WARN ("HeapFree failed with code %i\n", GetLastError ());
6398 if (HeapFree (hHeap, 0, lpValueName) == 0)
6399 WARN ("HeapFree failed with code %i\n", GetLastError ());
6400 r = RegCloseKey (hkSubKey);
6401 if (r != ERROR_SUCCESS)
6402 WARN ("RegCloseKey returned %i\n", r);
6403 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6407 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6408 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6409 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6410 pEnumValues += cbValueNameLen;
6412 /* return # of *bytes* (including trailing \0), not # of chars */
6413 ppev[dwIndex].cbValueName = cbValueNameLen;
6415 ppev[dwIndex].dwType = dwType;
6417 memcpy (pEnumValues, lpValue, cbValueLen);
6418 ppev[dwIndex].pData = pEnumValues;
6419 pEnumValues += cbValueLen;
6421 ppev[dwIndex].cbData = cbValueLen;
6423 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6424 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6427 if (HeapFree (hHeap, 0, lpValue) == 0)
6429 ret = GetLastError ();
6430 ERR ("HeapFree failed with code %i\n", ret);
6431 if (HeapFree (hHeap, 0, lpValueName) == 0)
6432 WARN ("HeapFree failed with code %i\n", GetLastError ());
6433 r = RegCloseKey (hkSubKey);
6434 if (r != ERROR_SUCCESS)
6435 WARN ("RegCloseKey returned %i\n", r);
6439 if (HeapFree (hHeap, 0, lpValueName) == 0)
6441 ret = GetLastError ();
6442 ERR ("HeapFree failed with code %i\n", ret);
6443 r = RegCloseKey (hkSubKey);
6444 if (r != ERROR_SUCCESS)
6445 WARN ("RegCloseKey returned %i\n", r);
6449 ret = RegCloseKey (hkSubKey);
6450 if (ret != ERROR_SUCCESS)
6452 ERR ("RegCloseKey returned %i\n", ret);
6456 return ERROR_SUCCESS;
6459 /*******************************************************************************
6460 * EnumPrinterDataExA [WINSPOOL.@]
6462 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6463 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6464 * what Windows 2000 SP1 does.
6467 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6468 LPBYTE pEnumValues, DWORD cbEnumValues,
6469 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6473 DWORD ret, dwIndex, dwBufSize;
6477 TRACE ("%p %s\n", hPrinter, pKeyName);
6479 if (pKeyName == NULL || *pKeyName == 0)
6480 return ERROR_INVALID_PARAMETER;
6482 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6485 ret = GetLastError ();
6486 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6490 hHeap = GetProcessHeap ();
6493 ERR ("GetProcessHeap failed\n");
6494 return ERROR_OUTOFMEMORY;
6497 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6498 if (pKeyNameW == NULL)
6500 ERR ("Failed to allocate %i bytes from process heap\n",
6501 (LONG)(len * sizeof (WCHAR)));
6502 return ERROR_OUTOFMEMORY;
6505 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6507 ret = GetLastError ();
6508 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6509 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6510 WARN ("HeapFree failed with code %i\n", GetLastError ());
6514 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6515 pcbEnumValues, pnEnumValues);
6516 if (ret != ERROR_SUCCESS)
6518 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6519 WARN ("HeapFree failed with code %i\n", GetLastError ());
6520 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6524 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6526 ret = GetLastError ();
6527 ERR ("HeapFree failed with code %i\n", ret);
6531 if (*pnEnumValues == 0) /* empty key */
6532 return ERROR_SUCCESS;
6535 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6537 PPRINTER_ENUM_VALUESW ppev =
6538 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6540 if (dwBufSize < ppev->cbValueName)
6541 dwBufSize = ppev->cbValueName;
6543 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6544 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6545 dwBufSize = ppev->cbData;
6548 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6550 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6551 if (pBuffer == NULL)
6553 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6554 return ERROR_OUTOFMEMORY;
6557 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6559 PPRINTER_ENUM_VALUESW ppev =
6560 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6562 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6563 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6567 ret = GetLastError ();
6568 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6569 if (HeapFree (hHeap, 0, pBuffer) == 0)
6570 WARN ("HeapFree failed with code %i\n", GetLastError ());
6574 memcpy (ppev->pValueName, pBuffer, len);
6576 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6578 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6579 ppev->dwType != REG_MULTI_SZ)
6582 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6583 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6586 ret = GetLastError ();
6587 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6588 if (HeapFree (hHeap, 0, pBuffer) == 0)
6589 WARN ("HeapFree failed with code %i\n", GetLastError ());
6593 memcpy (ppev->pData, pBuffer, len);
6595 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6596 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6599 if (HeapFree (hHeap, 0, pBuffer) == 0)
6601 ret = GetLastError ();
6602 ERR ("HeapFree failed with code %i\n", ret);
6606 return ERROR_SUCCESS;
6609 /******************************************************************************
6610 * AbortPrinter (WINSPOOL.@)
6612 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6614 FIXME("(%p), stub!\n", hPrinter);
6618 /******************************************************************************
6619 * AddPortA (WINSPOOL.@)
6624 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6626 LPWSTR nameW = NULL;
6627 LPWSTR monitorW = NULL;
6631 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6634 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6635 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6636 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6640 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6641 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6642 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6644 res = AddPortW(nameW, hWnd, monitorW);
6645 HeapFree(GetProcessHeap(), 0, nameW);
6646 HeapFree(GetProcessHeap(), 0, monitorW);
6650 /******************************************************************************
6651 * AddPortW (WINSPOOL.@)
6653 * Add a Port for a specific Monitor
6656 * pName [I] Servername or NULL (local Computer)
6657 * hWnd [I] Handle to parent Window for the Dialog-Box
6658 * pMonitorName [I] Name of the Monitor that manage the Port
6665 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6667 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6669 if ((backend == NULL) && !load_backend()) return FALSE;
6671 if (!pMonitorName) {
6672 SetLastError(RPC_X_NULL_REF_POINTER);
6676 return backend->fpAddPort(pName, hWnd, pMonitorName);
6679 /******************************************************************************
6680 * AddPortExA (WINSPOOL.@)
6685 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6688 PORT_INFO_2A * pi2A;
6689 LPWSTR nameW = NULL;
6690 LPWSTR monitorW = NULL;
6694 pi2A = (PORT_INFO_2A *) pBuffer;
6696 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6697 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6699 if ((level < 1) || (level > 2)) {
6700 SetLastError(ERROR_INVALID_LEVEL);
6705 SetLastError(ERROR_INVALID_PARAMETER);
6710 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6711 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6712 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6716 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6717 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6718 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6721 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6723 if (pi2A->pPortName) {
6724 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6725 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6726 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6730 if (pi2A->pMonitorName) {
6731 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6732 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6733 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6736 if (pi2A->pDescription) {
6737 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6738 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6739 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6741 pi2W.fPortType = pi2A->fPortType;
6742 pi2W.Reserved = pi2A->Reserved;
6745 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6747 HeapFree(GetProcessHeap(), 0, nameW);
6748 HeapFree(GetProcessHeap(), 0, monitorW);
6749 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6750 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6751 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6756 /******************************************************************************
6757 * AddPortExW (WINSPOOL.@)
6759 * Add a Port for a specific Monitor, without presenting a user interface
6762 * pName [I] Servername or NULL (local Computer)
6763 * level [I] Structure-Level (1 or 2) for pBuffer
6764 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6765 * pMonitorName [I] Name of the Monitor that manage the Port
6772 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6776 pi2 = (PORT_INFO_2W *) pBuffer;
6778 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6779 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6780 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6781 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6783 if ((backend == NULL) && !load_backend()) return FALSE;
6785 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6786 SetLastError(ERROR_INVALID_PARAMETER);
6790 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6793 /******************************************************************************
6794 * AddPrinterConnectionA (WINSPOOL.@)
6796 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6798 FIXME("%s\n", debugstr_a(pName));
6802 /******************************************************************************
6803 * AddPrinterConnectionW (WINSPOOL.@)
6805 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6807 FIXME("%s\n", debugstr_w(pName));
6811 /******************************************************************************
6812 * AddPrinterDriverExW (WINSPOOL.@)
6814 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6817 * pName [I] Servername or NULL (local Computer)
6818 * level [I] Level for the supplied DRIVER_INFO_*W struct
6819 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6820 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6827 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6829 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6831 if ((backend == NULL) && !load_backend()) return FALSE;
6833 if (level < 2 || level == 5 || level == 7 || level > 8) {
6834 SetLastError(ERROR_INVALID_LEVEL);
6839 SetLastError(ERROR_INVALID_PARAMETER);
6843 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6846 /******************************************************************************
6847 * AddPrinterDriverExA (WINSPOOL.@)
6849 * See AddPrinterDriverExW.
6852 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6854 DRIVER_INFO_8A *diA;
6856 LPWSTR nameW = NULL;
6861 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6863 diA = (DRIVER_INFO_8A *) pDriverInfo;
6864 ZeroMemory(&diW, sizeof(diW));
6866 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6867 SetLastError(ERROR_INVALID_LEVEL);
6872 SetLastError(ERROR_INVALID_PARAMETER);
6876 /* convert servername to unicode */
6878 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6879 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6880 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6884 diW.cVersion = diA->cVersion;
6887 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6888 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6889 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6892 if (diA->pEnvironment) {
6893 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6894 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6895 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6898 if (diA->pDriverPath) {
6899 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6900 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6901 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6904 if (diA->pDataFile) {
6905 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6906 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6907 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6910 if (diA->pConfigFile) {
6911 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6912 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6913 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6916 if ((Level > 2) && diA->pDependentFiles) {
6917 lenA = multi_sz_lenA(diA->pDependentFiles);
6918 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6919 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6920 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6923 if ((Level > 2) && diA->pMonitorName) {
6924 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6925 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6926 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6929 if ((Level > 3) && diA->pDefaultDataType) {
6930 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6931 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6932 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6935 if ((Level > 3) && diA->pszzPreviousNames) {
6936 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6937 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6938 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6939 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6942 if ((Level > 5) && diA->pszMfgName) {
6943 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6944 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6945 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6948 if ((Level > 5) && diA->pszOEMUrl) {
6949 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6950 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6951 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6954 if ((Level > 5) && diA->pszHardwareID) {
6955 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6956 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6957 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6960 if ((Level > 5) && diA->pszProvider) {
6961 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6962 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6963 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6967 FIXME("level %u is incomplete\n", Level);
6970 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6971 TRACE("got %u with %u\n", res, GetLastError());
6972 HeapFree(GetProcessHeap(), 0, nameW);
6973 HeapFree(GetProcessHeap(), 0, diW.pName);
6974 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6975 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6976 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6977 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6978 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6979 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6980 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6981 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6982 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6983 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6984 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6985 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6987 TRACE("=> %u with %u\n", res, GetLastError());
6991 /******************************************************************************
6992 * ConfigurePortA (WINSPOOL.@)
6994 * See ConfigurePortW.
6997 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6999 LPWSTR nameW = NULL;
7000 LPWSTR portW = NULL;
7004 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7006 /* convert servername to unicode */
7008 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7009 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7010 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7013 /* convert portname to unicode */
7015 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7016 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7017 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7020 res = ConfigurePortW(nameW, hWnd, portW);
7021 HeapFree(GetProcessHeap(), 0, nameW);
7022 HeapFree(GetProcessHeap(), 0, portW);
7026 /******************************************************************************
7027 * ConfigurePortW (WINSPOOL.@)
7029 * Display the Configuration-Dialog for a specific Port
7032 * pName [I] Servername or NULL (local Computer)
7033 * hWnd [I] Handle to parent Window for the Dialog-Box
7034 * pPortName [I] Name of the Port, that should be configured
7041 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7044 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7046 if ((backend == NULL) && !load_backend()) return FALSE;
7049 SetLastError(RPC_X_NULL_REF_POINTER);
7053 return backend->fpConfigurePort(pName, hWnd, pPortName);
7056 /******************************************************************************
7057 * ConnectToPrinterDlg (WINSPOOL.@)
7059 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7061 FIXME("%p %x\n", hWnd, Flags);
7065 /******************************************************************************
7066 * DeletePrinterConnectionA (WINSPOOL.@)
7068 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7070 FIXME("%s\n", debugstr_a(pName));
7074 /******************************************************************************
7075 * DeletePrinterConnectionW (WINSPOOL.@)
7077 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7079 FIXME("%s\n", debugstr_w(pName));
7083 /******************************************************************************
7084 * DeletePrinterDriverExW (WINSPOOL.@)
7086 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7087 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7092 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7093 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7095 if(pName && pName[0])
7097 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7098 SetLastError(ERROR_INVALID_PARAMETER);
7104 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7105 SetLastError(ERROR_INVALID_PARAMETER);
7109 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7113 ERR("Can't open drivers key\n");
7117 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7120 RegCloseKey(hkey_drivers);
7125 /******************************************************************************
7126 * DeletePrinterDriverExA (WINSPOOL.@)
7128 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7129 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7131 UNICODE_STRING NameW, EnvW, DriverW;
7134 asciitounicode(&NameW, pName);
7135 asciitounicode(&EnvW, pEnvironment);
7136 asciitounicode(&DriverW, pDriverName);
7138 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7140 RtlFreeUnicodeString(&DriverW);
7141 RtlFreeUnicodeString(&EnvW);
7142 RtlFreeUnicodeString(&NameW);
7147 /******************************************************************************
7148 * DeletePrinterDataExW (WINSPOOL.@)
7150 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7153 FIXME("%p %s %s\n", hPrinter,
7154 debugstr_w(pKeyName), debugstr_w(pValueName));
7155 return ERROR_INVALID_PARAMETER;
7158 /******************************************************************************
7159 * DeletePrinterDataExA (WINSPOOL.@)
7161 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7164 FIXME("%p %s %s\n", hPrinter,
7165 debugstr_a(pKeyName), debugstr_a(pValueName));
7166 return ERROR_INVALID_PARAMETER;
7169 /******************************************************************************
7170 * DeletePrintProcessorA (WINSPOOL.@)
7172 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7174 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7175 debugstr_a(pPrintProcessorName));
7179 /******************************************************************************
7180 * DeletePrintProcessorW (WINSPOOL.@)
7182 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7184 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7185 debugstr_w(pPrintProcessorName));
7189 /******************************************************************************
7190 * DeletePrintProvidorA (WINSPOOL.@)
7192 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7194 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7195 debugstr_a(pPrintProviderName));
7199 /******************************************************************************
7200 * DeletePrintProvidorW (WINSPOOL.@)
7202 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7204 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7205 debugstr_w(pPrintProviderName));
7209 /******************************************************************************
7210 * EnumFormsA (WINSPOOL.@)
7212 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7213 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7215 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7216 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7220 /******************************************************************************
7221 * EnumFormsW (WINSPOOL.@)
7223 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7224 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7226 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7227 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7231 /*****************************************************************************
7232 * EnumMonitorsA [WINSPOOL.@]
7234 * See EnumMonitorsW.
7237 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7238 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7241 LPBYTE bufferW = NULL;
7242 LPWSTR nameW = NULL;
7244 DWORD numentries = 0;
7247 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7248 cbBuf, pcbNeeded, pcReturned);
7250 /* convert servername to unicode */
7252 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7253 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7254 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7256 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7257 needed = cbBuf * sizeof(WCHAR);
7258 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7259 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7261 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7262 if (pcbNeeded) needed = *pcbNeeded;
7263 /* HeapReAlloc return NULL, when bufferW was NULL */
7264 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7265 HeapAlloc(GetProcessHeap(), 0, needed);
7267 /* Try again with the large Buffer */
7268 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7270 numentries = pcReturned ? *pcReturned : 0;
7273 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7274 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7277 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7278 DWORD entrysize = 0;
7281 LPMONITOR_INFO_2W mi2w;
7282 LPMONITOR_INFO_2A mi2a;
7284 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7285 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7287 /* First pass: calculate the size for all Entries */
7288 mi2w = (LPMONITOR_INFO_2W) bufferW;
7289 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7291 while (index < numentries) {
7293 needed += entrysize; /* MONITOR_INFO_?A */
7294 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7296 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7297 NULL, 0, NULL, NULL);
7299 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7300 NULL, 0, NULL, NULL);
7301 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7302 NULL, 0, NULL, NULL);
7304 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7305 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7306 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7309 /* check for errors and quit on failure */
7310 if (cbBuf < needed) {
7311 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7315 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7316 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7317 cbBuf -= len ; /* free Bytes in the user-Buffer */
7318 mi2w = (LPMONITOR_INFO_2W) bufferW;
7319 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7321 /* Second Pass: Fill the User Buffer (if we have one) */
7322 while ((index < numentries) && pMonitors) {
7324 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7326 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7327 ptr, cbBuf , NULL, NULL);
7331 mi2a->pEnvironment = ptr;
7332 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7333 ptr, cbBuf, NULL, NULL);
7337 mi2a->pDLLName = ptr;
7338 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7339 ptr, cbBuf, NULL, NULL);
7343 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7344 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7345 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7349 if (pcbNeeded) *pcbNeeded = needed;
7350 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7352 HeapFree(GetProcessHeap(), 0, nameW);
7353 HeapFree(GetProcessHeap(), 0, bufferW);
7355 TRACE("returning %d with %d (%d byte for %d entries)\n",
7356 (res), GetLastError(), needed, numentries);
7362 /*****************************************************************************
7363 * EnumMonitorsW [WINSPOOL.@]
7365 * Enumerate available Port-Monitors
7368 * pName [I] Servername or NULL (local Computer)
7369 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7370 * pMonitors [O] PTR to Buffer that receives the Result
7371 * cbBuf [I] Size of Buffer at pMonitors
7372 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7373 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7377 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7380 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7381 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7384 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7385 cbBuf, pcbNeeded, pcReturned);
7387 if ((backend == NULL) && !load_backend()) return FALSE;
7389 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7390 SetLastError(RPC_X_NULL_REF_POINTER);
7394 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7397 /******************************************************************************
7398 * SpoolerInit (WINSPOOL.@)
7400 * Initialize the Spooler
7407 * The function fails on windows, when the spooler service is not running
7410 BOOL WINAPI SpoolerInit(void)
7413 if ((backend == NULL) && !load_backend()) return FALSE;
7417 /******************************************************************************
7418 * XcvDataW (WINSPOOL.@)
7420 * Execute commands in the Printmonitor DLL
7423 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7424 * pszDataName [i] Name of the command to execute
7425 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7426 * cbInputData [i] Size in Bytes of Buffer at pInputData
7427 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7428 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7429 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7430 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7437 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7438 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7440 * Minimal List of commands, that a Printmonitor DLL should support:
7442 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7443 *| "AddPort" : Add a Port
7444 *| "DeletePort": Delete a Port
7446 * Many Printmonitors support additional commands. Examples for localspl.dll:
7447 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7448 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7451 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7452 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7453 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7455 opened_printer_t *printer;
7457 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7458 pInputData, cbInputData, pOutputData,
7459 cbOutputData, pcbOutputNeeded, pdwStatus);
7461 if ((backend == NULL) && !load_backend()) return FALSE;
7463 printer = get_opened_printer(hXcv);
7464 if (!printer || (!printer->backend_printer)) {
7465 SetLastError(ERROR_INVALID_HANDLE);
7469 if (!pcbOutputNeeded) {
7470 SetLastError(ERROR_INVALID_PARAMETER);
7474 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7475 SetLastError(RPC_X_NULL_REF_POINTER);
7479 *pcbOutputNeeded = 0;
7481 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7482 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7486 /*****************************************************************************
7487 * EnumPrinterDataA [WINSPOOL.@]
7490 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7491 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7492 DWORD cbData, LPDWORD pcbData )
7494 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7495 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7496 return ERROR_NO_MORE_ITEMS;
7499 /*****************************************************************************
7500 * EnumPrinterDataW [WINSPOOL.@]
7503 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR 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 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7516 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7517 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7518 LPDWORD pcbNeeded, LPDWORD pcReturned)
7520 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7521 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7522 pcbNeeded, pcReturned);
7526 /*****************************************************************************
7527 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7530 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7531 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7532 LPDWORD pcbNeeded, LPDWORD pcReturned)
7534 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7535 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7536 pcbNeeded, pcReturned);
7540 /*****************************************************************************
7541 * EnumPrintProcessorsA [WINSPOOL.@]
7543 * See EnumPrintProcessorsW.
7546 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7547 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7550 LPBYTE bufferW = NULL;
7551 LPWSTR nameW = NULL;
7554 DWORD numentries = 0;
7557 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7558 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7560 /* convert names to unicode */
7562 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7563 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7564 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7567 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7568 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7569 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7572 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7573 needed = cbBuf * sizeof(WCHAR);
7574 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7575 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7577 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7578 if (pcbNeeded) needed = *pcbNeeded;
7579 /* HeapReAlloc return NULL, when bufferW was NULL */
7580 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7581 HeapAlloc(GetProcessHeap(), 0, needed);
7583 /* Try again with the large Buffer */
7584 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7586 numentries = pcReturned ? *pcReturned : 0;
7590 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7593 PPRINTPROCESSOR_INFO_1W ppiw;
7594 PPRINTPROCESSOR_INFO_1A ppia;
7596 /* First pass: calculate the size for all Entries */
7597 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7598 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7600 while (index < numentries) {
7602 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7603 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7605 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7606 NULL, 0, NULL, NULL);
7608 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7609 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7612 /* check for errors and quit on failure */
7613 if (cbBuf < needed) {
7614 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7619 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7620 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7621 cbBuf -= len ; /* free Bytes in the user-Buffer */
7622 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7623 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7625 /* Second Pass: Fill the User Buffer (if we have one) */
7626 while ((index < numentries) && pPPInfo) {
7628 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7630 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7631 ptr, cbBuf , NULL, NULL);
7635 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7636 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7641 if (pcbNeeded) *pcbNeeded = needed;
7642 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7644 HeapFree(GetProcessHeap(), 0, nameW);
7645 HeapFree(GetProcessHeap(), 0, envW);
7646 HeapFree(GetProcessHeap(), 0, bufferW);
7648 TRACE("returning %d with %d (%d byte for %d entries)\n",
7649 (res), GetLastError(), needed, numentries);
7654 /*****************************************************************************
7655 * EnumPrintProcessorsW [WINSPOOL.@]
7657 * Enumerate available Print Processors
7660 * pName [I] Servername or NULL (local Computer)
7661 * pEnvironment [I] Printing-Environment or NULL (Default)
7662 * Level [I] Structure-Level (Only 1 is allowed)
7663 * pPPInfo [O] PTR to Buffer that receives the Result
7664 * cbBuf [I] Size of Buffer at pPPInfo
7665 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7666 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7670 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7673 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7674 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7677 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7678 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7680 if ((backend == NULL) && !load_backend()) return FALSE;
7682 if (!pcbNeeded || !pcReturned) {
7683 SetLastError(RPC_X_NULL_REF_POINTER);
7687 if (!pPPInfo && (cbBuf > 0)) {
7688 SetLastError(ERROR_INVALID_USER_BUFFER);
7692 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7693 cbBuf, pcbNeeded, pcReturned);
7696 /*****************************************************************************
7697 * ExtDeviceMode [WINSPOOL.@]
7700 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7701 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7704 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7705 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7706 debugstr_a(pProfile), fMode);
7710 /*****************************************************************************
7711 * FindClosePrinterChangeNotification [WINSPOOL.@]
7714 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7716 FIXME("Stub: %p\n", hChange);
7720 /*****************************************************************************
7721 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7724 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7725 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7727 FIXME("Stub: %p %x %x %p\n",
7728 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7729 return INVALID_HANDLE_VALUE;
7732 /*****************************************************************************
7733 * FindNextPrinterChangeNotification [WINSPOOL.@]
7736 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7737 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7739 FIXME("Stub: %p %p %p %p\n",
7740 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7744 /*****************************************************************************
7745 * FreePrinterNotifyInfo [WINSPOOL.@]
7748 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7750 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7754 /*****************************************************************************
7757 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7758 * ansi depending on the unicode parameter.
7760 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7770 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7773 memcpy(ptr, str, *size);
7780 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7783 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7790 /*****************************************************************************
7793 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7794 LPDWORD pcbNeeded, BOOL unicode)
7796 DWORD size, left = cbBuf;
7797 BOOL space = (cbBuf > 0);
7804 ji1->JobId = job->job_id;
7807 string_to_buf(job->document_title, ptr, left, &size, unicode);
7808 if(space && size <= left)
7810 ji1->pDocument = (LPWSTR)ptr;
7818 if (job->printer_name)
7820 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7821 if(space && size <= left)
7823 ji1->pPrinterName = (LPWSTR)ptr;
7835 /*****************************************************************************
7838 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7839 LPDWORD pcbNeeded, BOOL unicode)
7841 DWORD size, left = cbBuf;
7843 BOOL space = (cbBuf > 0);
7845 LPDEVMODEA dmA = NULL;
7852 ji2->JobId = job->job_id;
7855 string_to_buf(job->document_title, ptr, left, &size, unicode);
7856 if(space && size <= left)
7858 ji2->pDocument = (LPWSTR)ptr;
7866 if (job->printer_name)
7868 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7869 if(space && size <= left)
7871 ji2->pPrinterName = (LPWSTR)ptr;
7884 dmA = DEVMODEdupWtoA(job->devmode);
7885 devmode = (LPDEVMODEW) dmA;
7886 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7890 devmode = job->devmode;
7891 size = devmode->dmSize + devmode->dmDriverExtra;
7895 FIXME("Can't convert DEVMODE W to A\n");
7898 /* align DEVMODE to a DWORD boundary */
7899 shift = (4 - (*pcbNeeded & 3)) & 3;
7905 memcpy(ptr, devmode, size-shift);
7906 ji2->pDevMode = (LPDEVMODEW)ptr;
7907 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7920 /*****************************************************************************
7923 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7924 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7927 DWORD needed = 0, size;
7931 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7933 EnterCriticalSection(&printer_handles_cs);
7934 job = get_job(hPrinter, JobId);
7941 size = sizeof(JOB_INFO_1W);
7946 memset(pJob, 0, size);
7950 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7955 size = sizeof(JOB_INFO_2W);
7960 memset(pJob, 0, size);
7964 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7969 size = sizeof(JOB_INFO_3);
7973 memset(pJob, 0, size);
7982 SetLastError(ERROR_INVALID_LEVEL);
7986 *pcbNeeded = needed;
7988 LeaveCriticalSection(&printer_handles_cs);
7992 /*****************************************************************************
7993 * GetJobA [WINSPOOL.@]
7996 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7997 DWORD cbBuf, LPDWORD pcbNeeded)
7999 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8002 /*****************************************************************************
8003 * GetJobW [WINSPOOL.@]
8006 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8007 DWORD cbBuf, LPDWORD pcbNeeded)
8009 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8012 /*****************************************************************************
8015 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8018 char *unixname, *cmdA;
8020 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8026 if(!(unixname = wine_get_unix_file_name(filename)))
8029 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8030 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8031 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8033 TRACE("printing with: %s\n", cmdA);
8035 if((file_fd = open(unixname, O_RDONLY)) == -1)
8040 ERR("pipe() failed!\n");
8044 if ((pid = fork()) == 0)
8050 /* reset signals that we previously set to SIG_IGN */
8051 signal(SIGPIPE, SIG_DFL);
8053 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8058 ERR("fork() failed!\n");
8064 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8065 write(fds[1], buf, no_read);
8072 wret = waitpid(pid, &status, 0);
8073 } while (wret < 0 && errno == EINTR);
8076 ERR("waitpid() failed!\n");
8079 if (!WIFEXITED(status) || WEXITSTATUS(status))
8081 ERR("child process failed! %d\n", status);
8088 if(file_fd != -1) close(file_fd);
8089 if(fds[0] != -1) close(fds[0]);
8090 if(fds[1] != -1) close(fds[1]);
8092 HeapFree(GetProcessHeap(), 0, cmdA);
8093 HeapFree(GetProcessHeap(), 0, unixname);
8100 /*****************************************************************************
8103 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8106 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8109 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8110 sprintfW(cmd, fmtW, printer_name);
8112 r = schedule_pipe(cmd, filename);
8114 HeapFree(GetProcessHeap(), 0, cmd);
8118 #ifdef SONAME_LIBCUPS
8119 /*****************************************************************************
8120 * get_cups_jobs_ticket_options
8122 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8123 * The CUPS scheduler only looks for these in Print-File requests, and since
8124 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8127 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8129 FILE *fp = fopen( file, "r" );
8130 char buf[257]; /* DSC max of 256 + '\0' */
8131 const char *ps_adobe = "%!PS-Adobe-";
8132 const char *cups_job = "%cupsJobTicket:";
8134 if (!fp) return num_options;
8135 if (!fgets( buf, sizeof(buf), fp )) goto end;
8136 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8137 while (fgets( buf, sizeof(buf), fp ))
8139 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8140 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8149 /*****************************************************************************
8152 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8154 #ifdef SONAME_LIBCUPS
8157 char *unixname, *queue, *unix_doc_title;
8160 int num_options = 0, i;
8161 cups_option_t *options = NULL;
8163 if(!(unixname = wine_get_unix_file_name(filename)))
8166 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8167 queue = HeapAlloc(GetProcessHeap(), 0, len);
8168 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8170 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8171 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8172 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8174 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8176 TRACE( "printing via cups with options:\n" );
8177 for (i = 0; i < num_options; i++)
8178 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8180 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8182 pcupsFreeOptions( num_options, options );
8184 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8185 HeapFree(GetProcessHeap(), 0, queue);
8186 HeapFree(GetProcessHeap(), 0, unixname);
8192 return schedule_lpr(printer_name, filename);
8196 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8203 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8207 if(HIWORD(wparam) == BN_CLICKED)
8209 if(LOWORD(wparam) == IDOK)
8212 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8215 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8216 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8218 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8220 WCHAR caption[200], message[200];
8223 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8224 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8225 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8226 if(mb_ret == IDCANCEL)
8228 HeapFree(GetProcessHeap(), 0, filename);
8232 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8233 if(hf == INVALID_HANDLE_VALUE)
8235 WCHAR caption[200], message[200];
8237 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8238 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8239 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8240 HeapFree(GetProcessHeap(), 0, filename);
8244 DeleteFileW(filename);
8245 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8247 EndDialog(hwnd, IDOK);
8250 if(LOWORD(wparam) == IDCANCEL)
8252 EndDialog(hwnd, IDCANCEL);
8261 /*****************************************************************************
8264 static BOOL get_filename(LPWSTR *filename)
8266 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8267 file_dlg_proc, (LPARAM)filename) == IDOK;
8270 /*****************************************************************************
8273 static BOOL schedule_file(LPCWSTR filename)
8275 LPWSTR output = NULL;
8277 if(get_filename(&output))
8280 TRACE("copy to %s\n", debugstr_w(output));
8281 r = CopyFileW(filename, output, FALSE);
8282 HeapFree(GetProcessHeap(), 0, output);
8288 /*****************************************************************************
8291 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8293 int in_fd, out_fd, no_read;
8296 char *unixname, *outputA;
8299 if(!(unixname = wine_get_unix_file_name(filename)))
8302 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8303 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8304 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8306 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8307 in_fd = open(unixname, O_RDONLY);
8308 if(out_fd == -1 || in_fd == -1)
8311 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8312 write(out_fd, buf, no_read);
8316 if(in_fd != -1) close(in_fd);
8317 if(out_fd != -1) close(out_fd);
8318 HeapFree(GetProcessHeap(), 0, outputA);
8319 HeapFree(GetProcessHeap(), 0, unixname);
8323 /*****************************************************************************
8324 * ScheduleJob [WINSPOOL.@]
8327 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8329 opened_printer_t *printer;
8331 struct list *cursor, *cursor2;
8333 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8334 EnterCriticalSection(&printer_handles_cs);
8335 printer = get_opened_printer(hPrinter);
8339 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8341 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8344 if(job->job_id != dwJobID) continue;
8346 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8347 if(hf != INVALID_HANDLE_VALUE)
8349 PRINTER_INFO_5W *pi5 = NULL;
8350 LPWSTR portname = job->portname;
8354 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8355 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8359 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8360 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8361 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8362 portname = pi5->pPortName;
8364 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8365 debugstr_w(portname));
8369 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8370 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8372 DWORD type, count = sizeof(output);
8373 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8376 if(output[0] == '|')
8378 ret = schedule_pipe(output + 1, job->filename);
8382 ret = schedule_unixfile(output, job->filename);
8384 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8386 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8388 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8390 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8392 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8394 ret = schedule_file(job->filename);
8398 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8400 HeapFree(GetProcessHeap(), 0, pi5);
8402 DeleteFileW(job->filename);
8404 list_remove(cursor);
8405 HeapFree(GetProcessHeap(), 0, job->document_title);
8406 HeapFree(GetProcessHeap(), 0, job->printer_name);
8407 HeapFree(GetProcessHeap(), 0, job->portname);
8408 HeapFree(GetProcessHeap(), 0, job->filename);
8409 HeapFree(GetProcessHeap(), 0, job->devmode);
8410 HeapFree(GetProcessHeap(), 0, job);
8414 LeaveCriticalSection(&printer_handles_cs);
8418 /*****************************************************************************
8419 * StartDocDlgA [WINSPOOL.@]
8421 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8423 UNICODE_STRING usBuffer;
8426 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8429 docW.cbSize = sizeof(docW);
8430 if (doc->lpszDocName)
8432 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8433 if (!(docW.lpszDocName = docnameW)) return NULL;
8435 if (doc->lpszOutput)
8437 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8438 if (!(docW.lpszOutput = outputW)) return NULL;
8440 if (doc->lpszDatatype)
8442 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8443 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8445 docW.fwType = doc->fwType;
8447 retW = StartDocDlgW(hPrinter, &docW);
8451 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8452 ret = HeapAlloc(GetProcessHeap(), 0, len);
8453 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8454 HeapFree(GetProcessHeap(), 0, retW);
8457 HeapFree(GetProcessHeap(), 0, datatypeW);
8458 HeapFree(GetProcessHeap(), 0, outputW);
8459 HeapFree(GetProcessHeap(), 0, docnameW);
8464 /*****************************************************************************
8465 * StartDocDlgW [WINSPOOL.@]
8467 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8468 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8469 * port is "FILE:". Also returns the full path if passed a relative path.
8471 * The caller should free the returned string from the process heap.
8473 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8478 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8480 PRINTER_INFO_5W *pi5;
8481 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8482 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8484 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8485 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8486 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8488 HeapFree(GetProcessHeap(), 0, pi5);
8491 HeapFree(GetProcessHeap(), 0, pi5);
8494 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8498 if (get_filename(&name))
8500 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8502 HeapFree(GetProcessHeap(), 0, name);
8505 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8506 GetFullPathNameW(name, len, ret, NULL);
8507 HeapFree(GetProcessHeap(), 0, name);
8512 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8515 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8516 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8518 attr = GetFileAttributesW(ret);
8519 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8521 HeapFree(GetProcessHeap(), 0, ret);