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.
3992 static void WINSPOOL_GetDefaultDevMode(
3994 DWORD buflen, DWORD *needed)
3997 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3999 /* fill default DEVMODE - should be read from ppd... */
4000 ZeroMemory( &dm, sizeof(dm) );
4001 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
4002 dm.dmSpecVersion = DM_SPECVERSION;
4003 dm.dmDriverVersion = 1;
4004 dm.dmSize = sizeof(DEVMODEW);
4005 dm.dmDriverExtra = 0;
4007 DM_ORIENTATION | DM_PAPERSIZE |
4008 DM_PAPERLENGTH | DM_PAPERWIDTH |
4011 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
4012 DM_YRESOLUTION | DM_TTOPTION;
4014 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
4015 dm.u1.s1.dmPaperSize = DMPAPER_A4;
4016 dm.u1.s1.dmPaperLength = 2970;
4017 dm.u1.s1.dmPaperWidth = 2100;
4019 dm.u1.s1.dmScale = 100;
4020 dm.u1.s1.dmCopies = 1;
4021 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
4022 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
4025 dm.dmYResolution = 300; /* 300dpi */
4026 dm.dmTTOption = DMTT_BITMAP;
4029 /* dm.dmLogPixels */
4030 /* dm.dmBitsPerPel */
4031 /* dm.dmPelsWidth */
4032 /* dm.dmPelsHeight */
4033 /* dm.u2.dmDisplayFlags */
4034 /* dm.dmDisplayFrequency */
4035 /* dm.dmICMMethod */
4036 /* dm.dmICMIntent */
4037 /* dm.dmMediaType */
4038 /* dm.dmDitherType */
4039 /* dm.dmReserved1 */
4040 /* dm.dmReserved2 */
4041 /* dm.dmPanningWidth */
4042 /* dm.dmPanningHeight */
4044 if(buflen >= sizeof(DEVMODEW))
4045 memcpy(ptr, &dm, sizeof(DEVMODEW));
4046 *needed = sizeof(DEVMODEW);
4049 /*****************************************************************************
4050 * WINSPOOL_GetDevModeFromReg
4052 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4053 * DevMode is stored either as unicode or ascii.
4055 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4057 DWORD buflen, DWORD *needed)
4059 DWORD sz = buflen, type;
4062 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4063 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4064 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4065 if (sz < sizeof(DEVMODEA))
4067 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4070 /* ensures that dmSize is not erratically bogus if registry is invalid */
4071 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4072 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4073 sz += (CCHDEVICENAME + CCHFORMNAME);
4074 if (ptr && (buflen >= sz)) {
4075 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4076 memcpy(ptr, dmW, sz);
4077 HeapFree(GetProcessHeap(),0,dmW);
4083 /*********************************************************************
4084 * WINSPOOL_GetPrinter_1
4086 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4088 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4089 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4091 DWORD size, left = cbBuf;
4092 BOOL space = (cbBuf > 0);
4097 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4098 if(space && size <= left) {
4099 pi1->pName = (LPWSTR)ptr;
4107 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4108 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4109 if(space && size <= left) {
4110 pi1->pDescription = (LPWSTR)ptr;
4118 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4119 if(space && size <= left) {
4120 pi1->pComment = (LPWSTR)ptr;
4128 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4130 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4131 memset(pi1, 0, sizeof(*pi1));
4135 /*********************************************************************
4136 * WINSPOOL_GetPrinter_2
4138 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4140 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4141 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4143 DWORD size, left = cbBuf;
4144 BOOL space = (cbBuf > 0);
4149 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4150 if(space && size <= left) {
4151 pi2->pPrinterName = (LPWSTR)ptr;
4158 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4159 if(space && size <= left) {
4160 pi2->pShareName = (LPWSTR)ptr;
4167 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4168 if(space && size <= left) {
4169 pi2->pPortName = (LPWSTR)ptr;
4176 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4177 if(space && size <= left) {
4178 pi2->pDriverName = (LPWSTR)ptr;
4185 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4186 if(space && size <= left) {
4187 pi2->pComment = (LPWSTR)ptr;
4194 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4195 if(space && size <= left) {
4196 pi2->pLocation = (LPWSTR)ptr;
4203 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4204 if(space && size <= left) {
4205 pi2->pDevMode = (LPDEVMODEW)ptr;
4214 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4215 if(space && size <= left) {
4216 pi2->pDevMode = (LPDEVMODEW)ptr;
4223 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4224 if(space && size <= left) {
4225 pi2->pSepFile = (LPWSTR)ptr;
4232 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4233 if(space && size <= left) {
4234 pi2->pPrintProcessor = (LPWSTR)ptr;
4241 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4242 if(space && size <= left) {
4243 pi2->pDatatype = (LPWSTR)ptr;
4250 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4251 if(space && size <= left) {
4252 pi2->pParameters = (LPWSTR)ptr;
4260 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4261 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4262 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4263 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4264 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4267 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4268 memset(pi2, 0, sizeof(*pi2));
4273 /*********************************************************************
4274 * WINSPOOL_GetPrinter_4
4276 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4278 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4279 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4281 DWORD size, left = cbBuf;
4282 BOOL space = (cbBuf > 0);
4287 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4288 if(space && size <= left) {
4289 pi4->pPrinterName = (LPWSTR)ptr;
4297 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4300 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4301 memset(pi4, 0, sizeof(*pi4));
4306 /*********************************************************************
4307 * WINSPOOL_GetPrinter_5
4309 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4311 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4312 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4314 DWORD size, left = cbBuf;
4315 BOOL space = (cbBuf > 0);
4320 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4321 if(space && size <= left) {
4322 pi5->pPrinterName = (LPWSTR)ptr;
4329 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4330 if(space && size <= left) {
4331 pi5->pPortName = (LPWSTR)ptr;
4339 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4340 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4341 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4344 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4345 memset(pi5, 0, sizeof(*pi5));
4350 /*********************************************************************
4351 * WINSPOOL_GetPrinter_7
4353 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4355 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4356 DWORD cbBuf, LPDWORD pcbNeeded)
4358 DWORD size, left = cbBuf;
4359 BOOL space = (cbBuf > 0);
4364 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4367 size = sizeof(pi7->pszObjectGUID);
4369 if (space && size <= left) {
4370 pi7->pszObjectGUID = (LPWSTR)ptr;
4377 /* We do not have a Directory Service */
4378 pi7->dwAction = DSPRINT_UNPUBLISH;
4381 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4382 memset(pi7, 0, sizeof(*pi7));
4387 /*********************************************************************
4388 * WINSPOOL_GetPrinter_9
4390 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4392 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4393 DWORD cbBuf, LPDWORD pcbNeeded)
4396 BOOL space = (cbBuf > 0);
4400 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4401 if(space && size <= cbBuf) {
4402 pi9->pDevMode = (LPDEVMODEW)buf;
4409 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4410 if(space && size <= cbBuf) {
4411 pi9->pDevMode = (LPDEVMODEW)buf;
4417 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4418 memset(pi9, 0, sizeof(*pi9));
4423 /*****************************************************************************
4424 * GetPrinterW [WINSPOOL.@]
4426 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4427 DWORD cbBuf, LPDWORD pcbNeeded)
4429 DWORD size, needed = 0, err;
4434 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4436 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4439 SetLastError( err );
4446 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4448 size = sizeof(PRINTER_INFO_2W);
4450 ptr = pPrinter + size;
4452 memset(pPrinter, 0, size);
4457 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4464 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4466 size = sizeof(PRINTER_INFO_4W);
4468 ptr = pPrinter + size;
4470 memset(pPrinter, 0, size);
4475 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4483 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4485 size = sizeof(PRINTER_INFO_5W);
4487 ptr = pPrinter + size;
4489 memset(pPrinter, 0, size);
4495 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4503 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4505 size = sizeof(PRINTER_INFO_6);
4506 if (size <= cbBuf) {
4507 /* FIXME: We do not update the status yet */
4508 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4520 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4522 size = sizeof(PRINTER_INFO_7W);
4523 if (size <= cbBuf) {
4524 ptr = pPrinter + size;
4526 memset(pPrinter, 0, size);
4532 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4539 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4540 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4544 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4546 size = sizeof(PRINTER_INFO_9W);
4548 ptr = pPrinter + size;
4550 memset(pPrinter, 0, size);
4556 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4563 FIXME("Unimplemented level %d\n", Level);
4564 SetLastError(ERROR_INVALID_LEVEL);
4565 RegCloseKey(hkeyPrinter);
4569 RegCloseKey(hkeyPrinter);
4571 TRACE("returning %d needed = %d\n", ret, needed);
4572 if(pcbNeeded) *pcbNeeded = needed;
4574 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4578 /*****************************************************************************
4579 * GetPrinterA [WINSPOOL.@]
4581 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4582 DWORD cbBuf, LPDWORD pcbNeeded)
4588 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4590 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4592 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4593 HeapFree(GetProcessHeap(), 0, buf);
4598 /*****************************************************************************
4599 * WINSPOOL_EnumPrintersW
4601 * Implementation of EnumPrintersW
4603 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4604 DWORD dwLevel, LPBYTE lpbPrinters,
4605 DWORD cbBuf, LPDWORD lpdwNeeded,
4606 LPDWORD lpdwReturned)
4609 HKEY hkeyPrinters, hkeyPrinter;
4610 WCHAR PrinterName[255];
4611 DWORD needed = 0, number = 0;
4612 DWORD used, i, left;
4616 memset(lpbPrinters, 0, cbBuf);
4622 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4623 if(dwType == PRINTER_ENUM_DEFAULT)
4626 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4627 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4628 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4630 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4636 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4637 FIXME("dwType = %08x\n", dwType);
4638 SetLastError(ERROR_INVALID_FLAGS);
4642 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4644 ERR("Can't create Printers key\n");
4648 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4649 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4650 RegCloseKey(hkeyPrinters);
4651 ERR("Can't query Printers key\n");
4654 TRACE("Found %d printers\n", number);
4658 used = number * sizeof(PRINTER_INFO_1W);
4661 used = number * sizeof(PRINTER_INFO_2W);
4664 used = number * sizeof(PRINTER_INFO_4W);
4667 used = number * sizeof(PRINTER_INFO_5W);
4671 SetLastError(ERROR_INVALID_LEVEL);
4672 RegCloseKey(hkeyPrinters);
4675 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4677 for(i = 0; i < number; i++) {
4678 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4680 ERR("Can't enum key number %d\n", i);
4681 RegCloseKey(hkeyPrinters);
4684 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4685 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4687 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4688 RegCloseKey(hkeyPrinters);
4693 buf = lpbPrinters + used;
4694 left = cbBuf - used;
4702 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4705 if(pi) pi += sizeof(PRINTER_INFO_1W);
4708 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4711 if(pi) pi += sizeof(PRINTER_INFO_2W);
4714 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4717 if(pi) pi += sizeof(PRINTER_INFO_4W);
4720 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4723 if(pi) pi += sizeof(PRINTER_INFO_5W);
4726 ERR("Shouldn't be here!\n");
4727 RegCloseKey(hkeyPrinter);
4728 RegCloseKey(hkeyPrinters);
4731 RegCloseKey(hkeyPrinter);
4733 RegCloseKey(hkeyPrinters);
4740 memset(lpbPrinters, 0, cbBuf);
4741 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4745 *lpdwReturned = number;
4746 SetLastError(ERROR_SUCCESS);
4751 /******************************************************************
4752 * EnumPrintersW [WINSPOOL.@]
4754 * Enumerates the available printers, print servers and print
4755 * providers, depending on the specified flags, name and level.
4759 * If level is set to 1:
4760 * Returns an array of PRINTER_INFO_1 data structures in the
4761 * lpbPrinters buffer.
4763 * If level is set to 2:
4764 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4765 * Returns an array of PRINTER_INFO_2 data structures in the
4766 * lpbPrinters buffer. Note that according to MSDN also an
4767 * OpenPrinter should be performed on every remote printer.
4769 * If level is set to 4 (officially WinNT only):
4770 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4771 * Fast: Only the registry is queried to retrieve printer names,
4772 * no connection to the driver is made.
4773 * Returns an array of PRINTER_INFO_4 data structures in the
4774 * lpbPrinters buffer.
4776 * If level is set to 5 (officially WinNT4/Win9x only):
4777 * Fast: Only the registry is queried to retrieve printer names,
4778 * no connection to the driver is made.
4779 * Returns an array of PRINTER_INFO_5 data structures in the
4780 * lpbPrinters buffer.
4782 * If level set to 3 or 6+:
4783 * returns zero (failure!)
4785 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4789 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4790 * - Only levels 2, 4 and 5 are implemented at the moment.
4791 * - 16-bit printer drivers are not enumerated.
4792 * - Returned amount of bytes used/needed does not match the real Windoze
4793 * implementation (as in this implementation, all strings are part
4794 * of the buffer, whereas Win32 keeps them somewhere else)
4795 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4798 * - In a regular Wine installation, no registry settings for printers
4799 * exist, which makes this function return an empty list.
4801 BOOL WINAPI EnumPrintersW(
4802 DWORD dwType, /* [in] Types of print objects to enumerate */
4803 LPWSTR lpszName, /* [in] name of objects to enumerate */
4804 DWORD dwLevel, /* [in] type of printer info structure */
4805 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4806 DWORD cbBuf, /* [in] max size of buffer in bytes */
4807 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4808 LPDWORD lpdwReturned /* [out] number of entries returned */
4811 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4812 lpdwNeeded, lpdwReturned);
4815 /******************************************************************
4816 * EnumPrintersA [WINSPOOL.@]
4821 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4822 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4825 UNICODE_STRING pNameU;
4829 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4830 pPrinters, cbBuf, pcbNeeded, pcReturned);
4832 pNameW = asciitounicode(&pNameU, pName);
4834 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4835 MS Office need this */
4836 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4838 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4840 RtlFreeUnicodeString(&pNameU);
4842 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4844 HeapFree(GetProcessHeap(), 0, pPrintersW);
4848 /*****************************************************************************
4849 * WINSPOOL_GetDriverInfoFromReg [internal]
4851 * Enters the information from the registry into the DRIVER_INFO struct
4854 * zero if the printer driver does not exist in the registry
4855 * (only if Level > 1) otherwise nonzero
4857 static BOOL WINSPOOL_GetDriverInfoFromReg(
4860 const printenv_t * env,
4862 LPBYTE ptr, /* DRIVER_INFO */
4863 LPBYTE pDriverStrings, /* strings buffer */
4864 DWORD cbBuf, /* size of string buffer */
4865 LPDWORD pcbNeeded) /* space needed for str. */
4869 WCHAR driverdir[MAX_PATH];
4871 LPBYTE strPtr = pDriverStrings;
4872 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4874 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4875 debugstr_w(DriverName), env,
4876 Level, di, pDriverStrings, cbBuf);
4878 if (di) ZeroMemory(di, di_sizeof[Level]);
4880 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4881 if (*pcbNeeded <= cbBuf)
4882 strcpyW((LPWSTR)strPtr, DriverName);
4884 /* pName for level 1 has a different offset! */
4886 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4890 /* .cVersion and .pName for level > 1 */
4892 di->cVersion = env->driverversion;
4893 di->pName = (LPWSTR) strPtr;
4894 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4897 /* Reserve Space for the largest subdir and a Backslash*/
4898 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4899 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4900 /* Should never Fail */
4903 lstrcatW(driverdir, env->versionsubdir);
4904 lstrcatW(driverdir, backslashW);
4906 /* dirlen must not include the terminating zero */
4907 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4909 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4910 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4911 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4916 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4919 if (*pcbNeeded <= cbBuf) {
4920 lstrcpyW((LPWSTR)strPtr, env->envname);
4921 if (di) di->pEnvironment = (LPWSTR)strPtr;
4922 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4925 /* .pDriverPath is the Graphics rendering engine.
4926 The full Path is required to avoid a crash in some apps */
4927 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4929 if (*pcbNeeded <= cbBuf)
4930 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4932 if (di) di->pDriverPath = (LPWSTR)strPtr;
4933 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4936 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4937 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4939 if (*pcbNeeded <= cbBuf)
4940 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4942 if (di) di->pDataFile = (LPWSTR)strPtr;
4943 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4946 /* .pConfigFile is the Driver user Interface */
4947 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4949 if (*pcbNeeded <= cbBuf)
4950 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4952 if (di) di->pConfigFile = (LPWSTR)strPtr;
4953 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4957 RegCloseKey(hkeyDriver);
4958 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4963 RegCloseKey(hkeyDriver);
4964 FIXME("level 5: incomplete\n");
4969 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4971 if (*pcbNeeded <= cbBuf)
4972 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4974 if (di) di->pHelpFile = (LPWSTR)strPtr;
4975 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4978 /* .pDependentFiles */
4979 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4981 if (*pcbNeeded <= cbBuf)
4982 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4984 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4985 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4987 else if (GetVersion() & 0x80000000) {
4988 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4989 size = 2 * sizeof(WCHAR);
4991 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4993 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4994 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4997 /* .pMonitorName is the optional Language Monitor */
4998 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
5000 if (*pcbNeeded <= cbBuf)
5001 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
5003 if (di) di->pMonitorName = (LPWSTR)strPtr;
5004 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5007 /* .pDefaultDataType */
5008 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
5010 if(*pcbNeeded <= cbBuf)
5011 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
5013 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
5014 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5018 RegCloseKey(hkeyDriver);
5019 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5023 /* .pszzPreviousNames */
5024 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5026 if(*pcbNeeded <= cbBuf)
5027 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5029 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5030 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5034 RegCloseKey(hkeyDriver);
5035 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5039 /* support is missing, but not important enough for a FIXME */
5040 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5043 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5045 if(*pcbNeeded <= cbBuf)
5046 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5048 if (di) di->pszMfgName = (LPWSTR)strPtr;
5049 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5053 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5055 if(*pcbNeeded <= cbBuf)
5056 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5058 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5059 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5062 /* .pszHardwareID */
5063 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5065 if(*pcbNeeded <= cbBuf)
5066 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5068 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5069 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5073 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5075 if(*pcbNeeded <= cbBuf)
5076 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5078 if (di) di->pszProvider = (LPWSTR)strPtr;
5079 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5083 RegCloseKey(hkeyDriver);
5087 /* support is missing, but not important enough for a FIXME */
5088 TRACE("level 8: incomplete\n");
5090 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5091 RegCloseKey(hkeyDriver);
5095 /*****************************************************************************
5096 * GetPrinterDriverW [WINSPOOL.@]
5098 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5099 DWORD Level, LPBYTE pDriverInfo,
5100 DWORD cbBuf, LPDWORD pcbNeeded)
5103 WCHAR DriverName[100];
5104 DWORD ret, type, size, needed = 0;
5106 HKEY hkeyPrinter, hkeyDrivers;
5107 const printenv_t * env;
5109 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5110 Level,pDriverInfo,cbBuf, pcbNeeded);
5113 ZeroMemory(pDriverInfo, cbBuf);
5115 if (!(name = get_opened_printer_name(hPrinter))) {
5116 SetLastError(ERROR_INVALID_HANDLE);
5120 if (Level < 1 || Level == 7 || Level > 8) {
5121 SetLastError(ERROR_INVALID_LEVEL);
5125 env = validate_envW(pEnvironment);
5126 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5128 ret = open_printer_reg_key( name, &hkeyPrinter );
5131 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5132 SetLastError( ret );
5136 size = sizeof(DriverName);
5138 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5139 (LPBYTE)DriverName, &size);
5140 RegCloseKey(hkeyPrinter);
5141 if(ret != ERROR_SUCCESS) {
5142 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5146 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5148 ERR("Can't create Drivers key\n");
5152 size = di_sizeof[Level];
5153 if ((size <= cbBuf) && pDriverInfo)
5154 ptr = pDriverInfo + size;
5156 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5157 env, Level, pDriverInfo, ptr,
5158 (cbBuf < size) ? 0 : cbBuf - size,
5160 RegCloseKey(hkeyDrivers);
5164 RegCloseKey(hkeyDrivers);
5166 if(pcbNeeded) *pcbNeeded = size + needed;
5167 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5168 if(cbBuf >= size + needed) return TRUE;
5169 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5173 /*****************************************************************************
5174 * GetPrinterDriverA [WINSPOOL.@]
5176 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5177 DWORD Level, LPBYTE pDriverInfo,
5178 DWORD cbBuf, LPDWORD pcbNeeded)
5181 UNICODE_STRING pEnvW;
5187 ZeroMemory(pDriverInfo, cbBuf);
5188 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5191 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5192 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5195 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5197 HeapFree(GetProcessHeap(), 0, buf);
5199 RtlFreeUnicodeString(&pEnvW);
5203 /*****************************************************************************
5204 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5206 * Return the PATH for the Printer-Drivers (UNICODE)
5209 * pName [I] Servername (NT only) or NULL (local Computer)
5210 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5211 * Level [I] Structure-Level (must be 1)
5212 * pDriverDirectory [O] PTR to Buffer that receives the Result
5213 * cbBuf [I] Size of Buffer at pDriverDirectory
5214 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5215 * required for pDriverDirectory
5218 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5219 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5220 * if cbBuf is too small
5222 * Native Values returned in pDriverDirectory on Success:
5223 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5224 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5225 *| win9x(Windows 4.0): "%winsysdir%"
5227 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5230 *- Only NULL or "" is supported for pName
5233 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5234 DWORD Level, LPBYTE pDriverDirectory,
5235 DWORD cbBuf, LPDWORD pcbNeeded)
5237 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5238 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5240 if ((backend == NULL) && !load_backend()) return FALSE;
5243 /* (Level != 1) is ignored in win9x */
5244 SetLastError(ERROR_INVALID_LEVEL);
5247 if (pcbNeeded == NULL) {
5248 /* (pcbNeeded == NULL) is ignored in win9x */
5249 SetLastError(RPC_X_NULL_REF_POINTER);
5253 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5254 pDriverDirectory, cbBuf, pcbNeeded);
5259 /*****************************************************************************
5260 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5262 * Return the PATH for the Printer-Drivers (ANSI)
5264 * See GetPrinterDriverDirectoryW.
5267 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5270 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5271 DWORD Level, LPBYTE pDriverDirectory,
5272 DWORD cbBuf, LPDWORD pcbNeeded)
5274 UNICODE_STRING nameW, environmentW;
5277 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5278 WCHAR *driverDirectoryW = NULL;
5280 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5281 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5283 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5285 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5286 else nameW.Buffer = NULL;
5287 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5288 else environmentW.Buffer = NULL;
5290 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5291 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5294 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5295 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5297 *pcbNeeded = needed;
5298 ret = needed <= cbBuf;
5300 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5302 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5304 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5305 RtlFreeUnicodeString(&environmentW);
5306 RtlFreeUnicodeString(&nameW);
5311 /*****************************************************************************
5312 * AddPrinterDriverA [WINSPOOL.@]
5314 * See AddPrinterDriverW.
5317 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5319 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5320 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5323 /******************************************************************************
5324 * AddPrinterDriverW (WINSPOOL.@)
5326 * Install a Printer Driver
5329 * pName [I] Servername or NULL (local Computer)
5330 * level [I] Level for the supplied DRIVER_INFO_*W struct
5331 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5338 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5340 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5341 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5344 /*****************************************************************************
5345 * AddPrintProcessorA [WINSPOOL.@]
5347 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5348 LPSTR pPrintProcessorName)
5350 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5351 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5355 /*****************************************************************************
5356 * AddPrintProcessorW [WINSPOOL.@]
5358 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5359 LPWSTR pPrintProcessorName)
5361 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5362 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5366 /*****************************************************************************
5367 * AddPrintProvidorA [WINSPOOL.@]
5369 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5371 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5375 /*****************************************************************************
5376 * AddPrintProvidorW [WINSPOOL.@]
5378 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5380 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5384 /*****************************************************************************
5385 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5387 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5388 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5390 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5391 pDevModeOutput, pDevModeInput);
5395 /*****************************************************************************
5396 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5398 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5399 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5401 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5402 pDevModeOutput, pDevModeInput);
5406 /*****************************************************************************
5407 * PrinterProperties [WINSPOOL.@]
5409 * Displays a dialog to set the properties of the printer.
5412 * nonzero on success or zero on failure
5415 * implemented as stub only
5417 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5418 HANDLE hPrinter /* [in] handle to printer object */
5420 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5421 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5425 /*****************************************************************************
5426 * EnumJobsA [WINSPOOL.@]
5429 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5430 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5433 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5434 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5436 if(pcbNeeded) *pcbNeeded = 0;
5437 if(pcReturned) *pcReturned = 0;
5442 /*****************************************************************************
5443 * EnumJobsW [WINSPOOL.@]
5446 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5447 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5450 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5451 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5453 if(pcbNeeded) *pcbNeeded = 0;
5454 if(pcReturned) *pcReturned = 0;
5458 /*****************************************************************************
5459 * WINSPOOL_EnumPrinterDrivers [internal]
5461 * Delivers information about all printer drivers installed on the
5462 * localhost or a given server
5465 * nonzero on success or zero on failure. If the buffer for the returned
5466 * information is too small the function will return an error
5469 * - only implemented for localhost, foreign hosts will return an error
5471 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5472 DWORD Level, LPBYTE pDriverInfo,
5474 DWORD cbBuf, LPDWORD pcbNeeded,
5475 LPDWORD pcFound, DWORD data_offset)
5479 const printenv_t * env;
5481 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5482 debugstr_w(pName), debugstr_w(pEnvironment),
5483 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5485 env = validate_envW(pEnvironment);
5486 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5490 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5492 ERR("Can't open Drivers key\n");
5496 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5497 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5498 RegCloseKey(hkeyDrivers);
5499 ERR("Can't query Drivers key\n");
5502 TRACE("Found %d Drivers\n", *pcFound);
5504 /* get size of single struct
5505 * unicode and ascii structure have the same size
5507 size = di_sizeof[Level];
5509 if (data_offset == 0)
5510 data_offset = size * (*pcFound);
5511 *pcbNeeded = data_offset;
5513 for( i = 0; i < *pcFound; i++) {
5514 WCHAR DriverNameW[255];
5515 PBYTE table_ptr = NULL;
5516 PBYTE data_ptr = NULL;
5519 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5521 ERR("Can't enum key number %d\n", i);
5522 RegCloseKey(hkeyDrivers);
5526 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5527 table_ptr = pDriverInfo + (driver_index + i) * size;
5528 if (pDriverInfo && *pcbNeeded <= cbBuf)
5529 data_ptr = pDriverInfo + *pcbNeeded;
5531 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5532 env, Level, table_ptr, data_ptr,
5533 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5535 RegCloseKey(hkeyDrivers);
5539 *pcbNeeded += needed;
5542 RegCloseKey(hkeyDrivers);
5544 if(cbBuf < *pcbNeeded){
5545 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5552 /*****************************************************************************
5553 * EnumPrinterDriversW [WINSPOOL.@]
5555 * see function EnumPrinterDrivers for RETURNS, BUGS
5557 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5558 LPBYTE pDriverInfo, DWORD cbBuf,
5559 LPDWORD pcbNeeded, LPDWORD pcReturned)
5561 static const WCHAR allW[] = {'a','l','l',0};
5565 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5567 SetLastError(RPC_X_NULL_REF_POINTER);
5571 /* check for local drivers */
5572 if((pName) && (pName[0])) {
5573 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5574 SetLastError(ERROR_ACCESS_DENIED);
5578 /* check input parameter */
5579 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5580 SetLastError(ERROR_INVALID_LEVEL);
5584 if(pDriverInfo && cbBuf > 0)
5585 memset( pDriverInfo, 0, cbBuf);
5587 /* Exception: pull all printers */
5588 if (pEnvironment && !strcmpW(pEnvironment, allW))
5590 DWORD i, needed, bufsize = cbBuf;
5591 DWORD total_found = 0;
5594 /* Precompute the overall total; we need this to know
5595 where pointers end and data begins (i.e. data_offset) */
5596 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5599 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5600 NULL, 0, 0, &needed, &found, 0);
5601 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5602 total_found += found;
5605 data_offset = di_sizeof[Level] * total_found;
5610 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5613 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5614 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5615 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5617 *pcReturned += found;
5618 *pcbNeeded = needed;
5619 data_offset = needed;
5620 total_found += found;
5625 /* Normal behavior */
5626 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5627 0, cbBuf, pcbNeeded, &found, 0);
5629 *pcReturned = found;
5634 /*****************************************************************************
5635 * EnumPrinterDriversA [WINSPOOL.@]
5637 * see function EnumPrinterDrivers for RETURNS, BUGS
5639 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5640 LPBYTE pDriverInfo, DWORD cbBuf,
5641 LPDWORD pcbNeeded, LPDWORD pcReturned)
5644 UNICODE_STRING pNameW, pEnvironmentW;
5645 PWSTR pwstrNameW, pwstrEnvironmentW;
5649 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5651 pwstrNameW = asciitounicode(&pNameW, pName);
5652 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5654 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5655 buf, cbBuf, pcbNeeded, pcReturned);
5657 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5659 HeapFree(GetProcessHeap(), 0, buf);
5661 RtlFreeUnicodeString(&pNameW);
5662 RtlFreeUnicodeString(&pEnvironmentW);
5667 /******************************************************************************
5668 * EnumPortsA (WINSPOOL.@)
5673 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5674 LPDWORD pcbNeeded, LPDWORD pcReturned)
5677 LPBYTE bufferW = NULL;
5678 LPWSTR nameW = NULL;
5680 DWORD numentries = 0;
5683 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5684 cbBuf, pcbNeeded, pcReturned);
5686 /* convert servername to unicode */
5688 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5689 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5690 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5692 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5693 needed = cbBuf * sizeof(WCHAR);
5694 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5695 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5697 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5698 if (pcbNeeded) needed = *pcbNeeded;
5699 /* HeapReAlloc return NULL, when bufferW was NULL */
5700 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5701 HeapAlloc(GetProcessHeap(), 0, needed);
5703 /* Try again with the large Buffer */
5704 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5706 needed = pcbNeeded ? *pcbNeeded : 0;
5707 numentries = pcReturned ? *pcReturned : 0;
5710 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5711 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5714 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5715 DWORD entrysize = 0;
5718 LPPORT_INFO_2W pi2w;
5719 LPPORT_INFO_2A pi2a;
5722 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5724 /* First pass: calculate the size for all Entries */
5725 pi2w = (LPPORT_INFO_2W) bufferW;
5726 pi2a = (LPPORT_INFO_2A) pPorts;
5728 while (index < numentries) {
5730 needed += entrysize; /* PORT_INFO_?A */
5731 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5733 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5734 NULL, 0, NULL, NULL);
5736 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5737 NULL, 0, NULL, NULL);
5738 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5739 NULL, 0, NULL, NULL);
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);
5746 /* check for errors and quit on failure */
5747 if (cbBuf < needed) {
5748 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5752 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5753 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5754 cbBuf -= len ; /* free Bytes in the user-Buffer */
5755 pi2w = (LPPORT_INFO_2W) bufferW;
5756 pi2a = (LPPORT_INFO_2A) pPorts;
5758 /* Second Pass: Fill the User Buffer (if we have one) */
5759 while ((index < numentries) && pPorts) {
5761 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5762 pi2a->pPortName = ptr;
5763 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5764 ptr, cbBuf , NULL, NULL);
5768 pi2a->pMonitorName = ptr;
5769 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5770 ptr, cbBuf, NULL, NULL);
5774 pi2a->pDescription = ptr;
5775 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5776 ptr, cbBuf, NULL, NULL);
5780 pi2a->fPortType = pi2w->fPortType;
5781 pi2a->Reserved = 0; /* documented: "must be zero" */
5784 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5785 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5786 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5791 if (pcbNeeded) *pcbNeeded = needed;
5792 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5794 HeapFree(GetProcessHeap(), 0, nameW);
5795 HeapFree(GetProcessHeap(), 0, bufferW);
5797 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5798 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5804 /******************************************************************************
5805 * EnumPortsW (WINSPOOL.@)
5807 * Enumerate available Ports
5810 * pName [I] Servername or NULL (local Computer)
5811 * Level [I] Structure-Level (1 or 2)
5812 * pPorts [O] PTR to Buffer that receives the Result
5813 * cbBuf [I] Size of Buffer at pPorts
5814 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5815 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5819 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5822 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5825 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5826 cbBuf, pcbNeeded, pcReturned);
5828 if ((backend == NULL) && !load_backend()) return FALSE;
5830 /* Level is not checked in win9x */
5831 if (!Level || (Level > 2)) {
5832 WARN("level (%d) is ignored in win9x\n", Level);
5833 SetLastError(ERROR_INVALID_LEVEL);
5836 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5837 SetLastError(RPC_X_NULL_REF_POINTER);
5841 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5844 /******************************************************************************
5845 * GetDefaultPrinterW (WINSPOOL.@)
5848 * This function must read the value from data 'device' of key
5849 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5851 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5855 WCHAR *buffer, *ptr;
5859 SetLastError(ERROR_INVALID_PARAMETER);
5863 /* make the buffer big enough for the stuff from the profile/registry,
5864 * the content must fit into the local buffer to compute the correct
5865 * size even if the extern buffer is too small or not given.
5866 * (20 for ,driver,port) */
5868 len = max(100, (insize + 20));
5869 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5871 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5873 SetLastError (ERROR_FILE_NOT_FOUND);
5877 TRACE("%s\n", debugstr_w(buffer));
5879 if ((ptr = strchrW(buffer, ',')) == NULL)
5881 SetLastError(ERROR_INVALID_NAME);
5887 *namesize = strlenW(buffer) + 1;
5888 if(!name || (*namesize > insize))
5890 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5894 strcpyW(name, buffer);
5897 HeapFree( GetProcessHeap(), 0, buffer);
5902 /******************************************************************************
5903 * GetDefaultPrinterA (WINSPOOL.@)
5905 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5909 WCHAR *bufferW = NULL;
5913 SetLastError(ERROR_INVALID_PARAMETER);
5917 if(name && *namesize) {
5919 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5922 if(!GetDefaultPrinterW( bufferW, namesize)) {
5927 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5931 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5934 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5937 HeapFree( GetProcessHeap(), 0, bufferW);
5942 /******************************************************************************
5943 * SetDefaultPrinterW (WINSPOOL.204)
5945 * Set the Name of the Default Printer
5948 * pszPrinter [I] Name of the Printer or NULL
5955 * When the Parameter is NULL or points to an Empty String and
5956 * a Default Printer was already present, then this Function changes nothing.
5957 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5958 * the First enumerated local Printer is used.
5961 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5963 WCHAR default_printer[MAX_PATH];
5964 LPWSTR buffer = NULL;
5970 TRACE("(%s)\n", debugstr_w(pszPrinter));
5971 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5973 default_printer[0] = '\0';
5974 size = sizeof(default_printer)/sizeof(WCHAR);
5976 /* if we have a default Printer, do nothing. */
5977 if (GetDefaultPrinterW(default_printer, &size))
5981 /* we have no default Printer: search local Printers and use the first */
5982 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5984 default_printer[0] = '\0';
5985 size = sizeof(default_printer)/sizeof(WCHAR);
5986 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5988 pszPrinter = default_printer;
5989 TRACE("using %s\n", debugstr_w(pszPrinter));
5994 if (pszPrinter == NULL) {
5995 TRACE("no local printer found\n");
5996 SetLastError(ERROR_FILE_NOT_FOUND);
6001 /* "pszPrinter" is never empty or NULL here. */
6002 namelen = lstrlenW(pszPrinter);
6003 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
6004 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
6006 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
6007 HeapFree(GetProcessHeap(), 0, buffer);
6008 SetLastError(ERROR_FILE_NOT_FOUND);
6012 /* read the devices entry for the printer (driver,port) to build the string for the
6013 default device entry (printer,driver,port) */
6014 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
6015 buffer[namelen] = ',';
6016 namelen++; /* move index to the start of the driver */
6018 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6019 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6021 TRACE("set device to %s\n", debugstr_w(buffer));
6023 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
6024 TRACE("failed to set the device entry: %d\n", GetLastError());
6025 lres = ERROR_INVALID_PRINTER_NAME;
6028 /* remove the next section, when INIFileMapping is implemented */
6031 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6032 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6039 if (lres != ERROR_FILE_NOT_FOUND)
6040 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6042 SetLastError(ERROR_INVALID_PRINTER_NAME);
6046 HeapFree(GetProcessHeap(), 0, buffer);
6047 return (lres == ERROR_SUCCESS);
6050 /******************************************************************************
6051 * SetDefaultPrinterA (WINSPOOL.202)
6053 * See SetDefaultPrinterW.
6056 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6058 LPWSTR bufferW = NULL;
6061 TRACE("(%s)\n", debugstr_a(pszPrinter));
6063 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6064 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6065 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6067 res = SetDefaultPrinterW(bufferW);
6068 HeapFree(GetProcessHeap(), 0, bufferW);
6072 /******************************************************************************
6073 * SetPrinterDataExA (WINSPOOL.@)
6075 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6076 LPCSTR pValueName, DWORD Type,
6077 LPBYTE pData, DWORD cbData)
6079 HKEY hkeyPrinter, hkeySubkey;
6082 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6083 debugstr_a(pValueName), Type, pData, cbData);
6085 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6089 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6091 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6092 RegCloseKey(hkeyPrinter);
6095 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6096 RegCloseKey(hkeySubkey);
6097 RegCloseKey(hkeyPrinter);
6101 /******************************************************************************
6102 * SetPrinterDataExW (WINSPOOL.@)
6104 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6105 LPCWSTR pValueName, DWORD Type,
6106 LPBYTE pData, DWORD cbData)
6108 HKEY hkeyPrinter, hkeySubkey;
6111 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6112 debugstr_w(pValueName), Type, pData, cbData);
6114 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6118 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6120 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6121 RegCloseKey(hkeyPrinter);
6124 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6125 RegCloseKey(hkeySubkey);
6126 RegCloseKey(hkeyPrinter);
6130 /******************************************************************************
6131 * SetPrinterDataA (WINSPOOL.@)
6133 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6134 LPBYTE pData, DWORD cbData)
6136 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6140 /******************************************************************************
6141 * SetPrinterDataW (WINSPOOL.@)
6143 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6144 LPBYTE pData, DWORD cbData)
6146 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6150 /******************************************************************************
6151 * GetPrinterDataExA (WINSPOOL.@)
6153 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6154 LPCSTR pValueName, LPDWORD pType,
6155 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6157 opened_printer_t *printer;
6158 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6161 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6162 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6164 printer = get_opened_printer(hPrinter);
6165 if(!printer) return ERROR_INVALID_HANDLE;
6167 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6168 if (ret) return ret;
6170 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6172 if (printer->name) {
6174 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6176 RegCloseKey(hkeyPrinters);
6179 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6180 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6181 RegCloseKey(hkeyPrinter);
6182 RegCloseKey(hkeyPrinters);
6187 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6188 0, pType, pData, pcbNeeded);
6190 if (!ret && !pData) ret = ERROR_MORE_DATA;
6192 RegCloseKey(hkeySubkey);
6193 RegCloseKey(hkeyPrinter);
6194 RegCloseKey(hkeyPrinters);
6196 TRACE("--> %d\n", ret);
6200 /******************************************************************************
6201 * GetPrinterDataExW (WINSPOOL.@)
6203 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6204 LPCWSTR pValueName, LPDWORD pType,
6205 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6207 opened_printer_t *printer;
6208 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6211 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6212 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6214 printer = get_opened_printer(hPrinter);
6215 if(!printer) return ERROR_INVALID_HANDLE;
6217 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6218 if (ret) return ret;
6220 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6222 if (printer->name) {
6224 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6226 RegCloseKey(hkeyPrinters);
6229 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6230 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6231 RegCloseKey(hkeyPrinter);
6232 RegCloseKey(hkeyPrinters);
6237 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6238 0, pType, pData, pcbNeeded);
6240 if (!ret && !pData) ret = ERROR_MORE_DATA;
6242 RegCloseKey(hkeySubkey);
6243 RegCloseKey(hkeyPrinter);
6244 RegCloseKey(hkeyPrinters);
6246 TRACE("--> %d\n", ret);
6250 /******************************************************************************
6251 * GetPrinterDataA (WINSPOOL.@)
6253 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6254 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6256 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6257 pData, nSize, pcbNeeded);
6260 /******************************************************************************
6261 * GetPrinterDataW (WINSPOOL.@)
6263 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6264 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6266 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6267 pData, nSize, pcbNeeded);
6270 /*******************************************************************************
6271 * EnumPrinterDataExW [WINSPOOL.@]
6273 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6274 LPBYTE pEnumValues, DWORD cbEnumValues,
6275 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6277 HKEY hkPrinter, hkSubKey;
6278 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6279 cbValueNameLen, cbMaxValueLen, cbValueLen,
6284 PPRINTER_ENUM_VALUESW ppev;
6286 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6288 if (pKeyName == NULL || *pKeyName == 0)
6289 return ERROR_INVALID_PARAMETER;
6291 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6292 if (ret != ERROR_SUCCESS)
6294 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6299 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6300 if (ret != ERROR_SUCCESS)
6302 r = RegCloseKey (hkPrinter);
6303 if (r != ERROR_SUCCESS)
6304 WARN ("RegCloseKey returned %i\n", r);
6305 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6306 debugstr_w (pKeyName), ret);
6310 ret = RegCloseKey (hkPrinter);
6311 if (ret != ERROR_SUCCESS)
6313 ERR ("RegCloseKey returned %i\n", ret);
6314 r = RegCloseKey (hkSubKey);
6315 if (r != ERROR_SUCCESS)
6316 WARN ("RegCloseKey returned %i\n", r);
6320 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6321 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6322 if (ret != ERROR_SUCCESS)
6324 r = RegCloseKey (hkSubKey);
6325 if (r != ERROR_SUCCESS)
6326 WARN ("RegCloseKey returned %i\n", r);
6327 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6331 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6332 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6334 if (cValues == 0) /* empty key */
6336 r = RegCloseKey (hkSubKey);
6337 if (r != ERROR_SUCCESS)
6338 WARN ("RegCloseKey returned %i\n", r);
6339 *pcbEnumValues = *pnEnumValues = 0;
6340 return ERROR_SUCCESS;
6343 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6345 hHeap = GetProcessHeap ();
6348 ERR ("GetProcessHeap failed\n");
6349 r = RegCloseKey (hkSubKey);
6350 if (r != ERROR_SUCCESS)
6351 WARN ("RegCloseKey returned %i\n", r);
6352 return ERROR_OUTOFMEMORY;
6355 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6356 if (lpValueName == NULL)
6358 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6359 r = RegCloseKey (hkSubKey);
6360 if (r != ERROR_SUCCESS)
6361 WARN ("RegCloseKey returned %i\n", r);
6362 return ERROR_OUTOFMEMORY;
6365 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6366 if (lpValue == NULL)
6368 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6369 if (HeapFree (hHeap, 0, lpValueName) == 0)
6370 WARN ("HeapFree failed with code %i\n", GetLastError ());
6371 r = RegCloseKey (hkSubKey);
6372 if (r != ERROR_SUCCESS)
6373 WARN ("RegCloseKey returned %i\n", r);
6374 return ERROR_OUTOFMEMORY;
6377 TRACE ("pass 1: calculating buffer required for all names and values\n");
6379 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6381 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6383 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6385 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6386 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6387 NULL, NULL, lpValue, &cbValueLen);
6388 if (ret != ERROR_SUCCESS)
6390 if (HeapFree (hHeap, 0, lpValue) == 0)
6391 WARN ("HeapFree failed with code %i\n", GetLastError ());
6392 if (HeapFree (hHeap, 0, lpValueName) == 0)
6393 WARN ("HeapFree failed with code %i\n", GetLastError ());
6394 r = RegCloseKey (hkSubKey);
6395 if (r != ERROR_SUCCESS)
6396 WARN ("RegCloseKey returned %i\n", r);
6397 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6401 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6402 debugstr_w (lpValueName), dwIndex,
6403 cbValueNameLen + 1, cbValueLen);
6405 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6406 cbBufSize += cbValueLen;
6409 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6411 *pcbEnumValues = cbBufSize;
6412 *pnEnumValues = cValues;
6414 if (cbEnumValues < cbBufSize) /* buffer too small */
6416 if (HeapFree (hHeap, 0, lpValue) == 0)
6417 WARN ("HeapFree failed with code %i\n", GetLastError ());
6418 if (HeapFree (hHeap, 0, lpValueName) == 0)
6419 WARN ("HeapFree failed with code %i\n", GetLastError ());
6420 r = RegCloseKey (hkSubKey);
6421 if (r != ERROR_SUCCESS)
6422 WARN ("RegCloseKey returned %i\n", r);
6423 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6424 return ERROR_MORE_DATA;
6427 TRACE ("pass 2: copying all names and values to buffer\n");
6429 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6430 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6432 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6434 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6435 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6436 NULL, &dwType, lpValue, &cbValueLen);
6437 if (ret != ERROR_SUCCESS)
6439 if (HeapFree (hHeap, 0, lpValue) == 0)
6440 WARN ("HeapFree failed with code %i\n", GetLastError ());
6441 if (HeapFree (hHeap, 0, lpValueName) == 0)
6442 WARN ("HeapFree failed with code %i\n", GetLastError ());
6443 r = RegCloseKey (hkSubKey);
6444 if (r != ERROR_SUCCESS)
6445 WARN ("RegCloseKey returned %i\n", r);
6446 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6450 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6451 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6452 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6453 pEnumValues += cbValueNameLen;
6455 /* return # of *bytes* (including trailing \0), not # of chars */
6456 ppev[dwIndex].cbValueName = cbValueNameLen;
6458 ppev[dwIndex].dwType = dwType;
6460 memcpy (pEnumValues, lpValue, cbValueLen);
6461 ppev[dwIndex].pData = pEnumValues;
6462 pEnumValues += cbValueLen;
6464 ppev[dwIndex].cbData = cbValueLen;
6466 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6467 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6470 if (HeapFree (hHeap, 0, lpValue) == 0)
6472 ret = GetLastError ();
6473 ERR ("HeapFree failed with code %i\n", ret);
6474 if (HeapFree (hHeap, 0, lpValueName) == 0)
6475 WARN ("HeapFree failed with code %i\n", GetLastError ());
6476 r = RegCloseKey (hkSubKey);
6477 if (r != ERROR_SUCCESS)
6478 WARN ("RegCloseKey returned %i\n", r);
6482 if (HeapFree (hHeap, 0, lpValueName) == 0)
6484 ret = GetLastError ();
6485 ERR ("HeapFree failed with code %i\n", ret);
6486 r = RegCloseKey (hkSubKey);
6487 if (r != ERROR_SUCCESS)
6488 WARN ("RegCloseKey returned %i\n", r);
6492 ret = RegCloseKey (hkSubKey);
6493 if (ret != ERROR_SUCCESS)
6495 ERR ("RegCloseKey returned %i\n", ret);
6499 return ERROR_SUCCESS;
6502 /*******************************************************************************
6503 * EnumPrinterDataExA [WINSPOOL.@]
6505 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6506 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6507 * what Windows 2000 SP1 does.
6510 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6511 LPBYTE pEnumValues, DWORD cbEnumValues,
6512 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6516 DWORD ret, dwIndex, dwBufSize;
6520 TRACE ("%p %s\n", hPrinter, pKeyName);
6522 if (pKeyName == NULL || *pKeyName == 0)
6523 return ERROR_INVALID_PARAMETER;
6525 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6528 ret = GetLastError ();
6529 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6533 hHeap = GetProcessHeap ();
6536 ERR ("GetProcessHeap failed\n");
6537 return ERROR_OUTOFMEMORY;
6540 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6541 if (pKeyNameW == NULL)
6543 ERR ("Failed to allocate %i bytes from process heap\n",
6544 (LONG)(len * sizeof (WCHAR)));
6545 return ERROR_OUTOFMEMORY;
6548 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6550 ret = GetLastError ();
6551 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6552 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6553 WARN ("HeapFree failed with code %i\n", GetLastError ());
6557 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6558 pcbEnumValues, pnEnumValues);
6559 if (ret != ERROR_SUCCESS)
6561 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6562 WARN ("HeapFree failed with code %i\n", GetLastError ());
6563 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6567 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6569 ret = GetLastError ();
6570 ERR ("HeapFree failed with code %i\n", ret);
6574 if (*pnEnumValues == 0) /* empty key */
6575 return ERROR_SUCCESS;
6578 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6580 PPRINTER_ENUM_VALUESW ppev =
6581 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6583 if (dwBufSize < ppev->cbValueName)
6584 dwBufSize = ppev->cbValueName;
6586 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6587 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6588 dwBufSize = ppev->cbData;
6591 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6593 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6594 if (pBuffer == NULL)
6596 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6597 return ERROR_OUTOFMEMORY;
6600 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6602 PPRINTER_ENUM_VALUESW ppev =
6603 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6605 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6606 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6610 ret = GetLastError ();
6611 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6612 if (HeapFree (hHeap, 0, pBuffer) == 0)
6613 WARN ("HeapFree failed with code %i\n", GetLastError ());
6617 memcpy (ppev->pValueName, pBuffer, len);
6619 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6621 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6622 ppev->dwType != REG_MULTI_SZ)
6625 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6626 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6629 ret = GetLastError ();
6630 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6631 if (HeapFree (hHeap, 0, pBuffer) == 0)
6632 WARN ("HeapFree failed with code %i\n", GetLastError ());
6636 memcpy (ppev->pData, pBuffer, len);
6638 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6639 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6642 if (HeapFree (hHeap, 0, pBuffer) == 0)
6644 ret = GetLastError ();
6645 ERR ("HeapFree failed with code %i\n", ret);
6649 return ERROR_SUCCESS;
6652 /******************************************************************************
6653 * AbortPrinter (WINSPOOL.@)
6655 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6657 FIXME("(%p), stub!\n", hPrinter);
6661 /******************************************************************************
6662 * AddPortA (WINSPOOL.@)
6667 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6669 LPWSTR nameW = NULL;
6670 LPWSTR monitorW = NULL;
6674 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6677 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6678 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6679 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6683 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6684 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6685 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6687 res = AddPortW(nameW, hWnd, monitorW);
6688 HeapFree(GetProcessHeap(), 0, nameW);
6689 HeapFree(GetProcessHeap(), 0, monitorW);
6693 /******************************************************************************
6694 * AddPortW (WINSPOOL.@)
6696 * Add a Port for a specific Monitor
6699 * pName [I] Servername or NULL (local Computer)
6700 * hWnd [I] Handle to parent Window for the Dialog-Box
6701 * pMonitorName [I] Name of the Monitor that manage the Port
6708 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6710 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6712 if ((backend == NULL) && !load_backend()) return FALSE;
6714 if (!pMonitorName) {
6715 SetLastError(RPC_X_NULL_REF_POINTER);
6719 return backend->fpAddPort(pName, hWnd, pMonitorName);
6722 /******************************************************************************
6723 * AddPortExA (WINSPOOL.@)
6728 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6731 PORT_INFO_2A * pi2A;
6732 LPWSTR nameW = NULL;
6733 LPWSTR monitorW = NULL;
6737 pi2A = (PORT_INFO_2A *) pBuffer;
6739 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6740 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6742 if ((level < 1) || (level > 2)) {
6743 SetLastError(ERROR_INVALID_LEVEL);
6748 SetLastError(ERROR_INVALID_PARAMETER);
6753 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6754 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6755 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6759 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6760 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6761 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6764 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6766 if (pi2A->pPortName) {
6767 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6768 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6769 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6773 if (pi2A->pMonitorName) {
6774 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6775 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6776 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6779 if (pi2A->pDescription) {
6780 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6781 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6782 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6784 pi2W.fPortType = pi2A->fPortType;
6785 pi2W.Reserved = pi2A->Reserved;
6788 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6790 HeapFree(GetProcessHeap(), 0, nameW);
6791 HeapFree(GetProcessHeap(), 0, monitorW);
6792 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6793 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6794 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6799 /******************************************************************************
6800 * AddPortExW (WINSPOOL.@)
6802 * Add a Port for a specific Monitor, without presenting a user interface
6805 * pName [I] Servername or NULL (local Computer)
6806 * level [I] Structure-Level (1 or 2) for pBuffer
6807 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6808 * pMonitorName [I] Name of the Monitor that manage the Port
6815 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6819 pi2 = (PORT_INFO_2W *) pBuffer;
6821 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6822 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6823 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6824 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6826 if ((backend == NULL) && !load_backend()) return FALSE;
6828 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6829 SetLastError(ERROR_INVALID_PARAMETER);
6833 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6836 /******************************************************************************
6837 * AddPrinterConnectionA (WINSPOOL.@)
6839 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6841 FIXME("%s\n", debugstr_a(pName));
6845 /******************************************************************************
6846 * AddPrinterConnectionW (WINSPOOL.@)
6848 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6850 FIXME("%s\n", debugstr_w(pName));
6854 /******************************************************************************
6855 * AddPrinterDriverExW (WINSPOOL.@)
6857 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6860 * pName [I] Servername or NULL (local Computer)
6861 * level [I] Level for the supplied DRIVER_INFO_*W struct
6862 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6863 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6870 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6872 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6874 if ((backend == NULL) && !load_backend()) return FALSE;
6876 if (level < 2 || level == 5 || level == 7 || level > 8) {
6877 SetLastError(ERROR_INVALID_LEVEL);
6882 SetLastError(ERROR_INVALID_PARAMETER);
6886 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6889 /******************************************************************************
6890 * AddPrinterDriverExA (WINSPOOL.@)
6892 * See AddPrinterDriverExW.
6895 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6897 DRIVER_INFO_8A *diA;
6899 LPWSTR nameW = NULL;
6904 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6906 diA = (DRIVER_INFO_8A *) pDriverInfo;
6907 ZeroMemory(&diW, sizeof(diW));
6909 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6910 SetLastError(ERROR_INVALID_LEVEL);
6915 SetLastError(ERROR_INVALID_PARAMETER);
6919 /* convert servername to unicode */
6921 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6922 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6923 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6927 diW.cVersion = diA->cVersion;
6930 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6931 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6932 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6935 if (diA->pEnvironment) {
6936 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6937 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6938 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6941 if (diA->pDriverPath) {
6942 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6943 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6944 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6947 if (diA->pDataFile) {
6948 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6949 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6950 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6953 if (diA->pConfigFile) {
6954 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6955 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6956 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6959 if ((Level > 2) && diA->pDependentFiles) {
6960 lenA = multi_sz_lenA(diA->pDependentFiles);
6961 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6962 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6963 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6966 if ((Level > 2) && diA->pMonitorName) {
6967 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6968 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6969 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6972 if ((Level > 3) && diA->pDefaultDataType) {
6973 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6974 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6975 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6978 if ((Level > 3) && diA->pszzPreviousNames) {
6979 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6980 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6981 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6982 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6985 if ((Level > 5) && diA->pszMfgName) {
6986 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6987 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6988 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6991 if ((Level > 5) && diA->pszOEMUrl) {
6992 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6993 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6994 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6997 if ((Level > 5) && diA->pszHardwareID) {
6998 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6999 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7000 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
7003 if ((Level > 5) && diA->pszProvider) {
7004 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
7005 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7006 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
7010 FIXME("level %u is incomplete\n", Level);
7013 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
7014 TRACE("got %u with %u\n", res, GetLastError());
7015 HeapFree(GetProcessHeap(), 0, nameW);
7016 HeapFree(GetProcessHeap(), 0, diW.pName);
7017 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
7018 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7019 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7020 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7021 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7022 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7023 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7024 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7025 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7026 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7027 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7028 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7030 TRACE("=> %u with %u\n", res, GetLastError());
7034 /******************************************************************************
7035 * ConfigurePortA (WINSPOOL.@)
7037 * See ConfigurePortW.
7040 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7042 LPWSTR nameW = NULL;
7043 LPWSTR portW = NULL;
7047 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7049 /* convert servername to unicode */
7051 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7052 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7053 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7056 /* convert portname to unicode */
7058 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7059 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7060 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7063 res = ConfigurePortW(nameW, hWnd, portW);
7064 HeapFree(GetProcessHeap(), 0, nameW);
7065 HeapFree(GetProcessHeap(), 0, portW);
7069 /******************************************************************************
7070 * ConfigurePortW (WINSPOOL.@)
7072 * Display the Configuration-Dialog for a specific Port
7075 * pName [I] Servername or NULL (local Computer)
7076 * hWnd [I] Handle to parent Window for the Dialog-Box
7077 * pPortName [I] Name of the Port, that should be configured
7084 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7087 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7089 if ((backend == NULL) && !load_backend()) return FALSE;
7092 SetLastError(RPC_X_NULL_REF_POINTER);
7096 return backend->fpConfigurePort(pName, hWnd, pPortName);
7099 /******************************************************************************
7100 * ConnectToPrinterDlg (WINSPOOL.@)
7102 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7104 FIXME("%p %x\n", hWnd, Flags);
7108 /******************************************************************************
7109 * DeletePrinterConnectionA (WINSPOOL.@)
7111 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7113 FIXME("%s\n", debugstr_a(pName));
7117 /******************************************************************************
7118 * DeletePrinterConnectionW (WINSPOOL.@)
7120 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7122 FIXME("%s\n", debugstr_w(pName));
7126 /******************************************************************************
7127 * DeletePrinterDriverExW (WINSPOOL.@)
7129 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7130 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7135 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7136 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7138 if(pName && pName[0])
7140 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7141 SetLastError(ERROR_INVALID_PARAMETER);
7147 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7148 SetLastError(ERROR_INVALID_PARAMETER);
7152 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7156 ERR("Can't open drivers key\n");
7160 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7163 RegCloseKey(hkey_drivers);
7168 /******************************************************************************
7169 * DeletePrinterDriverExA (WINSPOOL.@)
7171 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7172 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7174 UNICODE_STRING NameW, EnvW, DriverW;
7177 asciitounicode(&NameW, pName);
7178 asciitounicode(&EnvW, pEnvironment);
7179 asciitounicode(&DriverW, pDriverName);
7181 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7183 RtlFreeUnicodeString(&DriverW);
7184 RtlFreeUnicodeString(&EnvW);
7185 RtlFreeUnicodeString(&NameW);
7190 /******************************************************************************
7191 * DeletePrinterDataExW (WINSPOOL.@)
7193 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7196 FIXME("%p %s %s\n", hPrinter,
7197 debugstr_w(pKeyName), debugstr_w(pValueName));
7198 return ERROR_INVALID_PARAMETER;
7201 /******************************************************************************
7202 * DeletePrinterDataExA (WINSPOOL.@)
7204 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7207 FIXME("%p %s %s\n", hPrinter,
7208 debugstr_a(pKeyName), debugstr_a(pValueName));
7209 return ERROR_INVALID_PARAMETER;
7212 /******************************************************************************
7213 * DeletePrintProcessorA (WINSPOOL.@)
7215 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7217 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7218 debugstr_a(pPrintProcessorName));
7222 /******************************************************************************
7223 * DeletePrintProcessorW (WINSPOOL.@)
7225 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7227 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7228 debugstr_w(pPrintProcessorName));
7232 /******************************************************************************
7233 * DeletePrintProvidorA (WINSPOOL.@)
7235 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7237 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7238 debugstr_a(pPrintProviderName));
7242 /******************************************************************************
7243 * DeletePrintProvidorW (WINSPOOL.@)
7245 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7247 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7248 debugstr_w(pPrintProviderName));
7252 /******************************************************************************
7253 * EnumFormsA (WINSPOOL.@)
7255 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7256 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7258 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7259 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7263 /******************************************************************************
7264 * EnumFormsW (WINSPOOL.@)
7266 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7267 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7269 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7270 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7274 /*****************************************************************************
7275 * EnumMonitorsA [WINSPOOL.@]
7277 * See EnumMonitorsW.
7280 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7281 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7284 LPBYTE bufferW = NULL;
7285 LPWSTR nameW = NULL;
7287 DWORD numentries = 0;
7290 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7291 cbBuf, pcbNeeded, pcReturned);
7293 /* convert servername to unicode */
7295 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7296 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7297 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7299 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7300 needed = cbBuf * sizeof(WCHAR);
7301 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7302 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7304 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7305 if (pcbNeeded) needed = *pcbNeeded;
7306 /* HeapReAlloc return NULL, when bufferW was NULL */
7307 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7308 HeapAlloc(GetProcessHeap(), 0, needed);
7310 /* Try again with the large Buffer */
7311 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7313 numentries = pcReturned ? *pcReturned : 0;
7316 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7317 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7320 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7321 DWORD entrysize = 0;
7324 LPMONITOR_INFO_2W mi2w;
7325 LPMONITOR_INFO_2A mi2a;
7327 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7328 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7330 /* First pass: calculate the size for all Entries */
7331 mi2w = (LPMONITOR_INFO_2W) bufferW;
7332 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7334 while (index < numentries) {
7336 needed += entrysize; /* MONITOR_INFO_?A */
7337 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7339 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7340 NULL, 0, NULL, NULL);
7342 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7343 NULL, 0, NULL, NULL);
7344 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7345 NULL, 0, NULL, NULL);
7347 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7348 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7349 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7352 /* check for errors and quit on failure */
7353 if (cbBuf < needed) {
7354 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7358 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7359 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7360 cbBuf -= len ; /* free Bytes in the user-Buffer */
7361 mi2w = (LPMONITOR_INFO_2W) bufferW;
7362 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7364 /* Second Pass: Fill the User Buffer (if we have one) */
7365 while ((index < numentries) && pMonitors) {
7367 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7369 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7370 ptr, cbBuf , NULL, NULL);
7374 mi2a->pEnvironment = ptr;
7375 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7376 ptr, cbBuf, NULL, NULL);
7380 mi2a->pDLLName = ptr;
7381 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7382 ptr, cbBuf, NULL, NULL);
7386 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7387 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7388 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7392 if (pcbNeeded) *pcbNeeded = needed;
7393 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7395 HeapFree(GetProcessHeap(), 0, nameW);
7396 HeapFree(GetProcessHeap(), 0, bufferW);
7398 TRACE("returning %d with %d (%d byte for %d entries)\n",
7399 (res), GetLastError(), needed, numentries);
7405 /*****************************************************************************
7406 * EnumMonitorsW [WINSPOOL.@]
7408 * Enumerate available Port-Monitors
7411 * pName [I] Servername or NULL (local Computer)
7412 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7413 * pMonitors [O] PTR to Buffer that receives the Result
7414 * cbBuf [I] Size of Buffer at pMonitors
7415 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7416 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7420 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7423 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7424 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7427 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7428 cbBuf, pcbNeeded, pcReturned);
7430 if ((backend == NULL) && !load_backend()) return FALSE;
7432 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7433 SetLastError(RPC_X_NULL_REF_POINTER);
7437 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7440 /******************************************************************************
7441 * SpoolerInit (WINSPOOL.@)
7443 * Initialize the Spooler
7450 * The function fails on windows, when the spooler service is not running
7453 BOOL WINAPI SpoolerInit(void)
7456 if ((backend == NULL) && !load_backend()) return FALSE;
7460 /******************************************************************************
7461 * XcvDataW (WINSPOOL.@)
7463 * Execute commands in the Printmonitor DLL
7466 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7467 * pszDataName [i] Name of the command to execute
7468 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7469 * cbInputData [i] Size in Bytes of Buffer at pInputData
7470 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7471 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7472 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7473 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7480 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7481 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7483 * Minimal List of commands, that a Printmonitor DLL should support:
7485 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7486 *| "AddPort" : Add a Port
7487 *| "DeletePort": Delete a Port
7489 * Many Printmonitors support additional commands. Examples for localspl.dll:
7490 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7491 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7494 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7495 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7496 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7498 opened_printer_t *printer;
7500 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7501 pInputData, cbInputData, pOutputData,
7502 cbOutputData, pcbOutputNeeded, pdwStatus);
7504 if ((backend == NULL) && !load_backend()) return FALSE;
7506 printer = get_opened_printer(hXcv);
7507 if (!printer || (!printer->backend_printer)) {
7508 SetLastError(ERROR_INVALID_HANDLE);
7512 if (!pcbOutputNeeded) {
7513 SetLastError(ERROR_INVALID_PARAMETER);
7517 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7518 SetLastError(RPC_X_NULL_REF_POINTER);
7522 *pcbOutputNeeded = 0;
7524 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7525 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7529 /*****************************************************************************
7530 * EnumPrinterDataA [WINSPOOL.@]
7533 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7534 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7535 DWORD cbData, LPDWORD pcbData )
7537 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7538 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7539 return ERROR_NO_MORE_ITEMS;
7542 /*****************************************************************************
7543 * EnumPrinterDataW [WINSPOOL.@]
7546 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7547 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7548 DWORD cbData, LPDWORD pcbData )
7550 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7551 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7552 return ERROR_NO_MORE_ITEMS;
7555 /*****************************************************************************
7556 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7559 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7560 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7561 LPDWORD pcbNeeded, LPDWORD pcReturned)
7563 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7564 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7565 pcbNeeded, pcReturned);
7569 /*****************************************************************************
7570 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7573 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7574 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7575 LPDWORD pcbNeeded, LPDWORD pcReturned)
7577 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7578 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7579 pcbNeeded, pcReturned);
7583 /*****************************************************************************
7584 * EnumPrintProcessorsA [WINSPOOL.@]
7586 * See EnumPrintProcessorsW.
7589 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7590 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7593 LPBYTE bufferW = NULL;
7594 LPWSTR nameW = NULL;
7597 DWORD numentries = 0;
7600 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7601 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7603 /* convert names to unicode */
7605 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7606 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7607 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7610 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7611 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7612 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7615 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7616 needed = cbBuf * sizeof(WCHAR);
7617 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7618 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7620 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7621 if (pcbNeeded) needed = *pcbNeeded;
7622 /* HeapReAlloc return NULL, when bufferW was NULL */
7623 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7624 HeapAlloc(GetProcessHeap(), 0, needed);
7626 /* Try again with the large Buffer */
7627 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7629 numentries = pcReturned ? *pcReturned : 0;
7633 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7636 PPRINTPROCESSOR_INFO_1W ppiw;
7637 PPRINTPROCESSOR_INFO_1A ppia;
7639 /* First pass: calculate the size for all Entries */
7640 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7641 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7643 while (index < numentries) {
7645 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7646 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7648 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7649 NULL, 0, NULL, NULL);
7651 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7652 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7655 /* check for errors and quit on failure */
7656 if (cbBuf < needed) {
7657 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7662 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7663 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7664 cbBuf -= len ; /* free Bytes in the user-Buffer */
7665 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7666 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7668 /* Second Pass: Fill the User Buffer (if we have one) */
7669 while ((index < numentries) && pPPInfo) {
7671 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7673 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7674 ptr, cbBuf , NULL, NULL);
7678 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7679 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7684 if (pcbNeeded) *pcbNeeded = needed;
7685 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7687 HeapFree(GetProcessHeap(), 0, nameW);
7688 HeapFree(GetProcessHeap(), 0, envW);
7689 HeapFree(GetProcessHeap(), 0, bufferW);
7691 TRACE("returning %d with %d (%d byte for %d entries)\n",
7692 (res), GetLastError(), needed, numentries);
7697 /*****************************************************************************
7698 * EnumPrintProcessorsW [WINSPOOL.@]
7700 * Enumerate available Print Processors
7703 * pName [I] Servername or NULL (local Computer)
7704 * pEnvironment [I] Printing-Environment or NULL (Default)
7705 * Level [I] Structure-Level (Only 1 is allowed)
7706 * pPPInfo [O] PTR to Buffer that receives the Result
7707 * cbBuf [I] Size of Buffer at pPPInfo
7708 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7709 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7713 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7716 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7717 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7720 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7721 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7723 if ((backend == NULL) && !load_backend()) return FALSE;
7725 if (!pcbNeeded || !pcReturned) {
7726 SetLastError(RPC_X_NULL_REF_POINTER);
7730 if (!pPPInfo && (cbBuf > 0)) {
7731 SetLastError(ERROR_INVALID_USER_BUFFER);
7735 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7736 cbBuf, pcbNeeded, pcReturned);
7739 /*****************************************************************************
7740 * ExtDeviceMode [WINSPOOL.@]
7743 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7744 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7747 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7748 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7749 debugstr_a(pProfile), fMode);
7753 /*****************************************************************************
7754 * FindClosePrinterChangeNotification [WINSPOOL.@]
7757 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7759 FIXME("Stub: %p\n", hChange);
7763 /*****************************************************************************
7764 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7767 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7768 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7770 FIXME("Stub: %p %x %x %p\n",
7771 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7772 return INVALID_HANDLE_VALUE;
7775 /*****************************************************************************
7776 * FindNextPrinterChangeNotification [WINSPOOL.@]
7779 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7780 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7782 FIXME("Stub: %p %p %p %p\n",
7783 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7787 /*****************************************************************************
7788 * FreePrinterNotifyInfo [WINSPOOL.@]
7791 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7793 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7797 /*****************************************************************************
7800 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7801 * ansi depending on the unicode parameter.
7803 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7813 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7816 memcpy(ptr, str, *size);
7823 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7826 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7833 /*****************************************************************************
7836 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7837 LPDWORD pcbNeeded, BOOL unicode)
7839 DWORD size, left = cbBuf;
7840 BOOL space = (cbBuf > 0);
7847 ji1->JobId = job->job_id;
7850 string_to_buf(job->document_title, ptr, left, &size, unicode);
7851 if(space && size <= left)
7853 ji1->pDocument = (LPWSTR)ptr;
7861 if (job->printer_name)
7863 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7864 if(space && size <= left)
7866 ji1->pPrinterName = (LPWSTR)ptr;
7878 /*****************************************************************************
7881 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7882 LPDWORD pcbNeeded, BOOL unicode)
7884 DWORD size, left = cbBuf;
7886 BOOL space = (cbBuf > 0);
7888 LPDEVMODEA dmA = NULL;
7895 ji2->JobId = job->job_id;
7898 string_to_buf(job->document_title, ptr, left, &size, unicode);
7899 if(space && size <= left)
7901 ji2->pDocument = (LPWSTR)ptr;
7909 if (job->printer_name)
7911 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7912 if(space && size <= left)
7914 ji2->pPrinterName = (LPWSTR)ptr;
7927 dmA = DEVMODEdupWtoA(job->devmode);
7928 devmode = (LPDEVMODEW) dmA;
7929 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7933 devmode = job->devmode;
7934 size = devmode->dmSize + devmode->dmDriverExtra;
7938 FIXME("Can't convert DEVMODE W to A\n");
7941 /* align DEVMODE to a DWORD boundary */
7942 shift = (4 - (*pcbNeeded & 3)) & 3;
7948 memcpy(ptr, devmode, size-shift);
7949 ji2->pDevMode = (LPDEVMODEW)ptr;
7950 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7963 /*****************************************************************************
7966 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7967 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7970 DWORD needed = 0, size;
7974 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7976 EnterCriticalSection(&printer_handles_cs);
7977 job = get_job(hPrinter, JobId);
7984 size = sizeof(JOB_INFO_1W);
7989 memset(pJob, 0, size);
7993 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7998 size = sizeof(JOB_INFO_2W);
8003 memset(pJob, 0, size);
8007 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
8012 size = sizeof(JOB_INFO_3);
8016 memset(pJob, 0, size);
8025 SetLastError(ERROR_INVALID_LEVEL);
8029 *pcbNeeded = needed;
8031 LeaveCriticalSection(&printer_handles_cs);
8035 /*****************************************************************************
8036 * GetJobA [WINSPOOL.@]
8039 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8040 DWORD cbBuf, LPDWORD pcbNeeded)
8042 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8045 /*****************************************************************************
8046 * GetJobW [WINSPOOL.@]
8049 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8050 DWORD cbBuf, LPDWORD pcbNeeded)
8052 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8055 /*****************************************************************************
8058 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8061 char *unixname, *cmdA;
8063 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8069 if(!(unixname = wine_get_unix_file_name(filename)))
8072 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8073 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8074 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8076 TRACE("printing with: %s\n", cmdA);
8078 if((file_fd = open(unixname, O_RDONLY)) == -1)
8083 ERR("pipe() failed!\n");
8087 if ((pid = fork()) == 0)
8093 /* reset signals that we previously set to SIG_IGN */
8094 signal(SIGPIPE, SIG_DFL);
8096 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8101 ERR("fork() failed!\n");
8107 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8108 write(fds[1], buf, no_read);
8115 wret = waitpid(pid, &status, 0);
8116 } while (wret < 0 && errno == EINTR);
8119 ERR("waitpid() failed!\n");
8122 if (!WIFEXITED(status) || WEXITSTATUS(status))
8124 ERR("child process failed! %d\n", status);
8131 if(file_fd != -1) close(file_fd);
8132 if(fds[0] != -1) close(fds[0]);
8133 if(fds[1] != -1) close(fds[1]);
8135 HeapFree(GetProcessHeap(), 0, cmdA);
8136 HeapFree(GetProcessHeap(), 0, unixname);
8143 /*****************************************************************************
8146 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8149 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8152 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8153 sprintfW(cmd, fmtW, printer_name);
8155 r = schedule_pipe(cmd, filename);
8157 HeapFree(GetProcessHeap(), 0, cmd);
8161 #ifdef SONAME_LIBCUPS
8162 /*****************************************************************************
8163 * get_cups_jobs_ticket_options
8165 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8166 * The CUPS scheduler only looks for these in Print-File requests, and since
8167 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8170 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8172 FILE *fp = fopen( file, "r" );
8173 char buf[257]; /* DSC max of 256 + '\0' */
8174 const char *ps_adobe = "%!PS-Adobe-";
8175 const char *cups_job = "%cupsJobTicket:";
8177 if (!fp) return num_options;
8178 if (!fgets( buf, sizeof(buf), fp )) goto end;
8179 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8180 while (fgets( buf, sizeof(buf), fp ))
8182 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8183 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8192 /*****************************************************************************
8195 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8197 #ifdef SONAME_LIBCUPS
8200 char *unixname, *queue, *unix_doc_title;
8203 int num_options = 0, i;
8204 cups_option_t *options = NULL;
8206 if(!(unixname = wine_get_unix_file_name(filename)))
8209 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8210 queue = HeapAlloc(GetProcessHeap(), 0, len);
8211 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8213 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8214 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8215 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8217 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8219 TRACE( "printing via cups with options:\n" );
8220 for (i = 0; i < num_options; i++)
8221 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8223 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8225 pcupsFreeOptions( num_options, options );
8227 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8228 HeapFree(GetProcessHeap(), 0, queue);
8229 HeapFree(GetProcessHeap(), 0, unixname);
8235 return schedule_lpr(printer_name, filename);
8239 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8246 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8250 if(HIWORD(wparam) == BN_CLICKED)
8252 if(LOWORD(wparam) == IDOK)
8255 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8258 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8259 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8261 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8263 WCHAR caption[200], message[200];
8266 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8267 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8268 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8269 if(mb_ret == IDCANCEL)
8271 HeapFree(GetProcessHeap(), 0, filename);
8275 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8276 if(hf == INVALID_HANDLE_VALUE)
8278 WCHAR caption[200], message[200];
8280 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8281 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8282 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8283 HeapFree(GetProcessHeap(), 0, filename);
8287 DeleteFileW(filename);
8288 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8290 EndDialog(hwnd, IDOK);
8293 if(LOWORD(wparam) == IDCANCEL)
8295 EndDialog(hwnd, IDCANCEL);
8304 /*****************************************************************************
8307 static BOOL get_filename(LPWSTR *filename)
8309 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8310 file_dlg_proc, (LPARAM)filename) == IDOK;
8313 /*****************************************************************************
8316 static BOOL schedule_file(LPCWSTR filename)
8318 LPWSTR output = NULL;
8320 if(get_filename(&output))
8323 TRACE("copy to %s\n", debugstr_w(output));
8324 r = CopyFileW(filename, output, FALSE);
8325 HeapFree(GetProcessHeap(), 0, output);
8331 /*****************************************************************************
8334 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8336 int in_fd, out_fd, no_read;
8339 char *unixname, *outputA;
8342 if(!(unixname = wine_get_unix_file_name(filename)))
8345 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8346 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8347 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8349 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8350 in_fd = open(unixname, O_RDONLY);
8351 if(out_fd == -1 || in_fd == -1)
8354 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8355 write(out_fd, buf, no_read);
8359 if(in_fd != -1) close(in_fd);
8360 if(out_fd != -1) close(out_fd);
8361 HeapFree(GetProcessHeap(), 0, outputA);
8362 HeapFree(GetProcessHeap(), 0, unixname);
8366 /*****************************************************************************
8367 * ScheduleJob [WINSPOOL.@]
8370 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8372 opened_printer_t *printer;
8374 struct list *cursor, *cursor2;
8376 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8377 EnterCriticalSection(&printer_handles_cs);
8378 printer = get_opened_printer(hPrinter);
8382 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8384 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8387 if(job->job_id != dwJobID) continue;
8389 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8390 if(hf != INVALID_HANDLE_VALUE)
8392 PRINTER_INFO_5W *pi5 = NULL;
8393 LPWSTR portname = job->portname;
8397 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8398 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8402 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8403 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8404 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8405 portname = pi5->pPortName;
8407 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8408 debugstr_w(portname));
8412 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8413 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8415 DWORD type, count = sizeof(output);
8416 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8419 if(output[0] == '|')
8421 ret = schedule_pipe(output + 1, job->filename);
8425 ret = schedule_unixfile(output, job->filename);
8427 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8429 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8431 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8433 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8435 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8437 ret = schedule_file(job->filename);
8441 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8443 HeapFree(GetProcessHeap(), 0, pi5);
8445 DeleteFileW(job->filename);
8447 list_remove(cursor);
8448 HeapFree(GetProcessHeap(), 0, job->document_title);
8449 HeapFree(GetProcessHeap(), 0, job->printer_name);
8450 HeapFree(GetProcessHeap(), 0, job->portname);
8451 HeapFree(GetProcessHeap(), 0, job->filename);
8452 HeapFree(GetProcessHeap(), 0, job->devmode);
8453 HeapFree(GetProcessHeap(), 0, job);
8457 LeaveCriticalSection(&printer_handles_cs);
8461 /*****************************************************************************
8462 * StartDocDlgA [WINSPOOL.@]
8464 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8466 UNICODE_STRING usBuffer;
8469 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8472 docW.cbSize = sizeof(docW);
8473 if (doc->lpszDocName)
8475 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8476 if (!(docW.lpszDocName = docnameW)) return NULL;
8478 if (doc->lpszOutput)
8480 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8481 if (!(docW.lpszOutput = outputW)) return NULL;
8483 if (doc->lpszDatatype)
8485 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8486 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8488 docW.fwType = doc->fwType;
8490 retW = StartDocDlgW(hPrinter, &docW);
8494 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8495 ret = HeapAlloc(GetProcessHeap(), 0, len);
8496 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8497 HeapFree(GetProcessHeap(), 0, retW);
8500 HeapFree(GetProcessHeap(), 0, datatypeW);
8501 HeapFree(GetProcessHeap(), 0, outputW);
8502 HeapFree(GetProcessHeap(), 0, docnameW);
8507 /*****************************************************************************
8508 * StartDocDlgW [WINSPOOL.@]
8510 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8511 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8512 * port is "FILE:". Also returns the full path if passed a relative path.
8514 * The caller should free the returned string from the process heap.
8516 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8521 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8523 PRINTER_INFO_5W *pi5;
8524 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8525 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8527 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8528 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8529 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8531 HeapFree(GetProcessHeap(), 0, pi5);
8534 HeapFree(GetProcessHeap(), 0, pi5);
8537 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8541 if (get_filename(&name))
8543 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8545 HeapFree(GetProcessHeap(), 0, name);
8548 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8549 GetFullPathNameW(name, len, ret, NULL);
8550 HeapFree(GetProcessHeap(), 0, name);
8555 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8558 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8559 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8561 attr = GetFileAttributesW(ret);
8562 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8564 HeapFree(GetProcessHeap(), 0, ret);